mirror of
https://github.com/ankitects/anki.git
synced 2025-09-23 08:22:24 -04:00
Preserve background-color when pasting external content in light mode
Closes #1964
This commit is contained in:
parent
92171e25e6
commit
0809812c1d
2 changed files with 71 additions and 53 deletions
|
@ -9,4 +9,35 @@ describe("filterHTML", () => {
|
|||
expect(filterHTML("", true, false)).toBe("");
|
||||
expect(filterHTML("", false, false)).toBe("");
|
||||
});
|
||||
test("internal filtering", () => {
|
||||
// font-size is filtered, weight is not
|
||||
expect(
|
||||
filterHTML(
|
||||
'<div style="font-weight: bold; font-size: 10px;"></div>',
|
||||
true,
|
||||
true,
|
||||
),
|
||||
).toBe('<div style="font-weight: bold;"></div>');
|
||||
});
|
||||
test("background color", () => {
|
||||
// transparent is stripped, other colors are not
|
||||
expect(
|
||||
filterHTML(
|
||||
'<span style="background-color: transparent;"></span>',
|
||||
false,
|
||||
true,
|
||||
),
|
||||
).toBe('<span style=""></span>');
|
||||
expect(
|
||||
filterHTML('<span style="background-color: blue;"></span>', false, true),
|
||||
).toBe('<span style="background-color: blue;"></span>');
|
||||
// except if extended mode is off
|
||||
expect(
|
||||
filterHTML('<span style="background-color: blue;">x</span>', false, false),
|
||||
).toBe("x");
|
||||
// or if it's an internal paste
|
||||
expect(
|
||||
filterHTML('<span style="background-color: blue;"></span>', true, true),
|
||||
).toBe('<span style=""></span>');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,63 +1,50 @@
|
|||
// Copyright: Ankitects Pty Ltd and contributors
|
||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
interface AllowPropertiesBlockValues {
|
||||
[property: string]: string[];
|
||||
}
|
||||
|
||||
type BlockProperties = string[];
|
||||
|
||||
/// Keep property if true.
|
||||
type StylingPredicate = (property: string, value: string) => boolean;
|
||||
|
||||
const stylingNightMode: AllowPropertiesBlockValues = {
|
||||
"font-weight": [],
|
||||
"font-style": [],
|
||||
"text-decoration-line": [],
|
||||
};
|
||||
const keep = (_key: string, _value: string) => true;
|
||||
const discard = (_key: string, _value: string) => false;
|
||||
|
||||
const stylingLightMode: AllowPropertiesBlockValues = {
|
||||
color: [],
|
||||
"background-color": ["transparent"],
|
||||
...stylingNightMode,
|
||||
};
|
||||
|
||||
const stylingInternal: BlockProperties = [
|
||||
"background-color",
|
||||
"font-size",
|
||||
"font-family",
|
||||
"width",
|
||||
"height",
|
||||
"max-width",
|
||||
"max-height",
|
||||
];
|
||||
|
||||
const allowPropertiesBlockValues =
|
||||
(allowBlock: AllowPropertiesBlockValues): StylingPredicate =>
|
||||
(property: string, value: string): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(allowBlock, property) &&
|
||||
!allowBlock[property].includes(value);
|
||||
|
||||
const blockProperties =
|
||||
(block: BlockProperties): StylingPredicate =>
|
||||
(property: string): boolean =>
|
||||
!block.includes(property);
|
||||
|
||||
const filterStyling =
|
||||
(predicate: (property: string, value: string) => boolean) =>
|
||||
(element: HTMLElement): void => {
|
||||
for (const property of [...element.style]) {
|
||||
const value = element.style.getPropertyValue(property);
|
||||
|
||||
if (!predicate(property, value)) {
|
||||
element.style.removeProperty(property);
|
||||
/// Return a function that filters out certain styles.
|
||||
/// - If the style is listed in `exceptions`, the provided predicate is used.
|
||||
/// - If the style is not listed, the default predicate is used instead.
|
||||
function filterStyling(
|
||||
defaultPredicate: StylingPredicate,
|
||||
exceptions: Record<string, StylingPredicate>,
|
||||
): (element: HTMLElement) => void {
|
||||
return (element: HTMLElement): void => {
|
||||
// jsdom does not support @@iterator, so manually iterate
|
||||
for (let i = 0; i < element.style.length; i++) {
|
||||
const key = element.style.item(i);
|
||||
const value = element.style.getPropertyValue(key);
|
||||
const predicate = exceptions[key] ?? defaultPredicate;
|
||||
if (!predicate(key, value)) {
|
||||
element.style.removeProperty(key);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const filterStylingNightMode = filterStyling(
|
||||
allowPropertiesBlockValues(stylingNightMode),
|
||||
);
|
||||
export const filterStylingLightMode = filterStyling(
|
||||
allowPropertiesBlockValues(stylingLightMode),
|
||||
);
|
||||
export const filterStylingInternal = filterStyling(blockProperties(stylingInternal));
|
||||
const nightModeExceptions = {
|
||||
"font-weight": keep,
|
||||
"font-style": keep,
|
||||
"text-decoration-line": keep,
|
||||
};
|
||||
|
||||
export const filterStylingNightMode = filterStyling(discard, nightModeExceptions);
|
||||
export const filterStylingLightMode = filterStyling(discard, {
|
||||
color: keep,
|
||||
"background-color": (_key: string, value: string) => value != "transparent",
|
||||
...nightModeExceptions,
|
||||
});
|
||||
export const filterStylingInternal = filterStyling(keep, {
|
||||
"background-color": discard,
|
||||
"font-size": discard,
|
||||
"font-family": discard,
|
||||
width: discard,
|
||||
height: discard,
|
||||
"max-width": discard,
|
||||
"max-height": discard,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue