This commit is contained in:
Aitor Moreno
2025-04-23 07:37:17 +02:00
parent 53dcd94f0d
commit c91ed5b580
2 changed files with 31 additions and 48 deletions

View File

@@ -21,7 +21,7 @@ const DEFAULT_LINE_HEIGHT = "1.2";
export function mergeStyleDeclarations(target, source) { export function mergeStyleDeclarations(target, source) {
// This is better but it doesn't work in JSDOM // This is better but it doesn't work in JSDOM
// for (const styleName of source) { // for (const styleName of source) {
for (let index = 0; index < source.length; index++) { for (let index = 0; index < source.length; ++index) {
const styleName = source.item(index); const styleName = source.item(index);
const styleValue = source.getPropertyValue(styleName); const styleValue = source.getPropertyValue(styleName);
target.setProperty(styleName, styleValue); target.setProperty(styleName, styleValue);
@@ -36,7 +36,7 @@ export function mergeStyleDeclarations(target, source) {
* @returns {CSSStyleDeclaration} * @returns {CSSStyleDeclaration}
*/ */
function resetStyleDeclaration(styleDeclaration) { function resetStyleDeclaration(styleDeclaration) {
for (let index = 0; index < styleDeclaration.length; index++) { for (let index = 0; index < styleDeclaration.length; ++index) {
const styleName = styleDeclaration.item(index); const styleName = styleDeclaration.item(index);
styleDeclaration.removeProperty(styleName); styleDeclaration.removeProperty(styleName);
} }
@@ -121,6 +121,19 @@ export function getComputedStyle(element) {
return inertElement.style; return inertElement.style;
} }
/**
* Returns a property value
*
* @param {CSSStyleDeclaration} styleDeclaration
* @param {string} propertyName
* @returns {string|undefined}
*/
function getPropertyValue(styleDeclaration, propertyName) {
if (Array.from(styleDeclaration).includes(propertyName)) {
return styleDeclaration.getPropertyValue(propertyName)
}
}
/** /**
* Normalizes style declaration. * Normalizes style declaration.
* *
@@ -140,34 +153,39 @@ export function normalizeStyles(node, styleDefaults = getStyleDefaultsDeclaratio
// If there's a color property, we should convert it to // If there's a color property, we should convert it to
// a --fills CSS variable property. // a --fills CSS variable property.
const fills = styleDeclaration.getPropertyValue("--fills"); const fills = getPropertyValue(styleDeclaration, "--fills");
const color = styleDeclaration.getPropertyValue("color"); const color = getPropertyValue(styleDeclaration, "color");
if (color && !fills) { if (color && !fills) {
styleDeclaration.removeProperty("color"); styleDeclaration.removeProperty("color");
styleDeclaration.setProperty("--fills", getFills(color)); styleDeclaration.setProperty("--fills", getFills(color));
} else { } else if (fills) {
styleDeclaration.setProperty("--fills", fills); styleDeclaration.setProperty("--fills", fills);
} else {
styleDeclaration.setProperty(
"--fills",
JSON.stringify([["^ ","~:fill-color","#000000","~:fill-opacity",1]]),
);
} }
// If there's a font-family property and not a --font-id, then // If there's a font-family property and not a --font-id, then
// we remove the font-family because it will not work. // we remove the font-family because it will not work.
const fontFamily = styleDeclaration.getPropertyValue("font-family"); const fontFamily = getPropertyValue(styleDeclaration, "font-family");
const fontId = styleDeclaration.getPropertyValue("--font-id"); const fontId = getPropertyValue(styleDeclaration, "--font-id");
if (fontFamily && !fontId) { if (fontFamily && !fontId) {
styleDeclaration.removeProperty("font-family"); styleDeclaration.removeProperty("font-family");
} }
const fontSize = styleDeclaration.getPropertyValue("font-size"); const fontSize = getPropertyValue(styleDeclaration, "font-size");
if (!fontSize || fontSize === "0px") { if (!fontSize || fontSize === "0px") {
styleDeclaration.setProperty("font-size", DEFAULT_FONT_SIZE); styleDeclaration.setProperty("font-size", DEFAULT_FONT_SIZE);
} }
const lineHeight = styleDeclaration.getPropertyValue("line-height"); const lineHeight = getPropertyValue(styleDeclaration, "line-height");
if (!lineHeight || lineHeight === "" || !lineHeight.endsWith("px")) { if (!lineHeight || lineHeight === "" || !lineHeight.endsWith("px")) {
// TODO: Podríamos convertir unidades en decimales. // TODO: Podríamos convertir unidades en decimales.
styleDeclaration.setProperty("line-height", DEFAULT_LINE_HEIGHT); styleDeclaration.setProperty("line-height", DEFAULT_LINE_HEIGHT);
} else if (lineHeight.endsWith("px")) { } else if (lineHeight.endsWith("px")) {
const fontSize = styleDeclaration.getPropertyValue("font-size"); const fontSize = getPropertyValue(styleDeclaration, "font-size");
styleDeclaration.setProperty( styleDeclaration.setProperty(
"line-height", "line-height",
parseFloat(lineHeight) / parseFloat(fontSize), parseFloat(lineHeight) / parseFloat(fontSize),

View File

@@ -46,6 +46,7 @@ import CommandMutations from "../commands/CommandMutations.js";
import { isRoot, setRootStyles } from "../content/dom/Root.js"; import { isRoot, setRootStyles } from "../content/dom/Root.js";
import { SelectionDirection } from "./SelectionDirection.js"; import { SelectionDirection } from "./SelectionDirection.js";
import SafeGuard from "./SafeGuard.js"; import SafeGuard from "./SafeGuard.js";
import { mergeStyleDeclarations } from '../content/dom/Style.js';
/** /**
* Supported options for the SelectionController. * Supported options for the SelectionController.
@@ -56,39 +57,7 @@ import SafeGuard from "./SafeGuard.js";
/** /**
* SelectionController uses the same concepts used by the Selection API but extending it to support * SelectionController uses the same concepts used by the Selection API but extending it to support
* our own internal model based on paragraphs (in drafconst textEditorMock = TextEditorMock.createTextEditorMockWithParagraphs([ * our own internal model based on paragraphs (in draft.js they were called blocks) and inlines.
createParagraph([createInline(new Text("Hello, "))]),
createEmptyParagraph(),
createParagraph([createInline(new Text("World!"))]),
]);
const root = textEditorMock.root;
const selection = document.getSelection();
const selectionController = new SelectionController(
textEditorMock,
selection
);
focus(
selection,
textEditorMock,
root.childNodes.item(2).firstChild.firstChild,
0
);
selectionController.mergeBackwardParagraph();
expect(textEditorMock.root).toBeInstanceOf(HTMLDivElement);
expect(textEditorMock.root.children.length).toBe(2);
expect(textEditorMock.root.dataset.itype).toBe("root");
expect(textEditorMock.root.firstChild).toBeInstanceOf(HTMLDivElement);
expect(textEditorMock.root.firstChild.dataset.itype).toBe("paragraph");
expect(textEditorMock.root.firstChild.firstChild).toBeInstanceOf(
HTMLSpanElement
);
expect(textEditorMock.root.firstChild.firstChild.dataset.itype).toBe(
"inline"
);
expect(textEditorMock.root.textContent).toBe("Hello, World!");
expect(textEditorMock.root.firstChild.textContent).toBe("Hello, ");
expect(textEditorMock.root.lastChild.textContent).toBe("World!");
t.js they were called blocks) and inlines.
*/ */
export class SelectionController extends EventTarget { export class SelectionController extends EventTarget {
/** /**
@@ -253,11 +222,7 @@ export class SelectionController extends EventTarget {
* @param {HTMLElement} element * @param {HTMLElement} element
*/ */
#applyStylesToCurrentStyle(element) { #applyStylesToCurrentStyle(element) {
for (let index = 0; index < element.style.length; index++) { mergeStyleDeclarations(this.#currentStyle, element.style);
const styleName = element.style.item(index);
const styleValue = element.style.getPropertyValue(styleName);
this.#currentStyle.setProperty(styleName, styleValue);
}
} }
/** /**