From 36c00413a0b40cb4d7b646515c964fcd650da6c2 Mon Sep 17 00:00:00 2001 From: Nicolas Bayet Date: Thu, 28 May 2020 11:07:20 +0200 Subject: [PATCH 1/3] [DOC] Modifiers --- documentation/core/Modifiers.md | 20 ++++++++++++++++++++ packages/core/src/Modifier.ts | 14 ++++++++++++++ packages/core/src/Modifiers.ts | 9 ++++++--- packages/plugin-inline/src/Format.ts | 26 ++++++++++++++++++++++++++ packages/plugin-inline/src/Inline.ts | 5 ++++- 5 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 documentation/core/Modifiers.md diff --git a/documentation/core/Modifiers.md b/documentation/core/Modifiers.md new file mode 100644 index 000000000..c0080bcce --- /dev/null +++ b/documentation/core/Modifiers.md @@ -0,0 +1,20 @@ +# Modifiers +A modifier is: ... + +The main modifiers are `Attribute` and `Format`. + +## Attributes +When parsing and rendering a document, we need to save the attributes that a +DOM node has and save it in our VNode. + +Attributes exists to: +- retrieve HTML attributes that a DOM node has originally +- render the HTML attributes that a VNode has + +## Format +The DOM inline nodes (e.g. span, strong, em, b, a, ...) in HTML are difficult to +manipulate. We therefore we transform them into a Format modifiers that we +attach to a VNode through the "modifiers" properties. + +Format themselve have modifiers. For instance, a HTML strong tag migh have +attributes (styles, classes, ...). diff --git a/packages/core/src/Modifier.ts b/packages/core/src/Modifier.ts index 5aa0c69ce..8497b43ed 100644 --- a/packages/core/src/Modifier.ts +++ b/packages/core/src/Modifier.ts @@ -8,9 +8,15 @@ export interface Modifier { constructor: ModifierConstructor & this; } export class Modifier { + /** + * The name of the this Modifier. + */ get name(): string { return ''; } + /** + * Return the string representation of this Modifier. + */ toString(): string { return this.name; } @@ -22,9 +28,17 @@ export class Modifier { applyTo(node: VNode): void { node.modifiers.prepend(this); } + /** + * Compare two modifiers. + * + * Meant to be overridden if necessary. + */ isSameAs(otherModifier: Modifier): boolean { return this === otherModifier; } + /** + * Clone this modifier. + */ clone(): this { return new this.constructor(); } diff --git a/packages/core/src/Modifiers.ts b/packages/core/src/Modifiers.ts index f9a5c6e55..89ca239a3 100644 --- a/packages/core/src/Modifiers.ts +++ b/packages/core/src/Modifiers.ts @@ -1,6 +1,12 @@ import { Modifier } from './Modifier'; import { Constructor, isConstructor } from '../../utils/src/utils'; +/** + * When parsing dom elements, modifiers can be DOM inline nodes (a, b, strong). + * + * The order of modifiers are important because it impact the way they will + * be rendered. + */ export class Modifiers { private _contents: Modifier[]; constructor(...modifiers: Array>) { @@ -86,7 +92,6 @@ export class Modifiers { * for `this._contents`. * * @see Array.find - * @param modifier */ find(callback: (modifier: T) => boolean): T; find(modifier: T | Constructor): T; @@ -110,8 +115,6 @@ export class Modifiers { * modifier class or create one, append it and return it. * If the modifier passed is a modifier instance, return it if it was * present in the array. - * - * @param modifier */ get(modifier: T | Constructor): T { let found = this.find(modifier); diff --git a/packages/plugin-inline/src/Format.ts b/packages/plugin-inline/src/Format.ts index 88eeadc7a..ddb8ce13a 100644 --- a/packages/plugin-inline/src/Format.ts +++ b/packages/plugin-inline/src/Format.ts @@ -2,16 +2,31 @@ import { Modifier } from '../../core/src/Modifier'; import { Modifiers } from '../../core/src/Modifiers'; import { Attributes } from '../../plugin-xml/src/Attributes'; +/** + * A Format might represent DOM inline nodes (a, b, strong) that were parsed or + * the DOM inline node (a, b, strong) that we might render. + */ export class Format extends Modifier { htmlTag: string; // TODO: remove this reference to DOM. + /** + * The modifiers for a format is `Attribute`. + * Used to be rendered. + */ modifiers = new Modifiers(); + constructor(htmlTag?: string) { super(); this.htmlTag = htmlTag; } + /** + * @override + */ get name(): string { return this.htmlTag.toLowerCase(); } + /** + * @override + */ toString(): string { const nonEmptyAttributes = this.modifiers.filter( modifier => !(modifier instanceof Attributes) || !!modifier.length, @@ -31,6 +46,11 @@ export class Format extends Modifier { // Public //-------------------------------------------------------------------------- + /** + * Render the current format into a dom Node. + * + * Meant to be used with `FormatDomRenderer`. + */ render(): Element { const domNode = document.createElement(this.htmlTag); const attributes = this.modifiers.find(Attributes); @@ -51,12 +71,18 @@ export class Format extends Modifier { } return domNode; } + /** + * @override + */ clone(): this { const clone = new this.constructor(); clone.htmlTag = this.htmlTag; clone.modifiers = this.modifiers.clone(); return clone; } + /** + * @override + */ isSameAs(otherFormat: Format): boolean { const aModifiers = this.modifiers; const bModifiers = otherFormat?.modifiers; diff --git a/packages/plugin-inline/src/Inline.ts b/packages/plugin-inline/src/Inline.ts index 95c963933..710fb5749 100644 --- a/packages/plugin-inline/src/Inline.ts +++ b/packages/plugin-inline/src/Inline.ts @@ -71,7 +71,10 @@ export class Inline extends JWPlugin< for (const inline of selectedInlines) { const format = inline.modifiers.find(FormatClass); // Apply the attributes of the format we're about to remove - // to the inline itself. + // to the inline itself in order to keep information of the + // Format. + // For instance, if the Format has a style attribute we need + // to keep that information to render it later. const attributes = inline.modifiers.get(Attributes); const matchingFormatAttributes = format.modifiers.find(Attributes); if (matchingFormatAttributes) { From 68dcada9d396945a28ec7b356b3bfa45cd0093dc Mon Sep 17 00:00:00 2001 From: Nicolas Bayet Date: Thu, 28 May 2020 13:14:25 +0200 Subject: [PATCH 2/3] [RENAME] InsertTextParams formats -> modifiers --- packages/plugin-char/src/Char.ts | 2 +- packages/plugin-link/src/Link.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-char/src/Char.ts b/packages/plugin-char/src/Char.ts index 4815bd0a6..ced2de4b5 100644 --- a/packages/plugin-char/src/Char.ts +++ b/packages/plugin-char/src/Char.ts @@ -13,7 +13,7 @@ import { Attributes } from '../../plugin-xml/src/Attributes'; export interface InsertTextParams extends CommandParams { text: string; - formats?: Modifiers; + modifiers?: Modifiers; } export class Char extends JWPlugin { diff --git a/packages/plugin-link/src/Link.ts b/packages/plugin-link/src/Link.ts index 0ad60089f..05aa81373 100644 --- a/packages/plugin-link/src/Link.ts +++ b/packages/plugin-link/src/Link.ts @@ -85,7 +85,7 @@ export class Link extends JWPlugin const link = new LinkFormat(params.url); return this.editor.execCommand('insertText', { text: params.label || link.url, - formats: new Modifiers(link), + modifiers: new Modifiers(link), }); } unlink(params: LinkParams): void { From 699e83491cf606efff2aa26d7deebec7c4a39328 Mon Sep 17 00:00:00 2001 From: Nicolas Bayet Date: Wed, 27 May 2020 17:21:43 +0200 Subject: [PATCH 3/3] [IMP] Link: add type information --- packages/plugin-link/src/Link.ts | 2 +- packages/plugin-link/src/components/LinkComponent.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/plugin-link/src/Link.ts b/packages/plugin-link/src/Link.ts index 05aa81373..84646de45 100644 --- a/packages/plugin-link/src/Link.ts +++ b/packages/plugin-link/src/Link.ts @@ -78,7 +78,7 @@ export class Link extends JWPlugin await layout.remove('link'); await layout.add('link'); - return this.editor.execCommand('show', { componentID: 'link' }); + return this.editor.execCommand('show', { componentID: 'link' }); } // Otherwise create a link and insert it. diff --git a/packages/plugin-link/src/components/LinkComponent.ts b/packages/plugin-link/src/components/LinkComponent.ts index c66c1300e..8f4b8c67c 100644 --- a/packages/plugin-link/src/components/LinkComponent.ts +++ b/packages/plugin-link/src/components/LinkComponent.ts @@ -1,7 +1,7 @@ import { OwlComponent } from '../../../plugin-owl/src/ui/OwlComponent'; import { InlineNode } from '../../../plugin-inline/src/InlineNode'; import { LinkFormat } from '../LinkFormat'; -import { LinkParams } from '../Link'; +import { Link } from '../Link'; import { Layout } from '../../../plugin-layout/src/Layout'; import { useState } from '@odoo/owl'; @@ -18,10 +18,10 @@ export class LinkComponent extends OwlComponent { //-------------------------------------------------------------------------- async saveLink(): Promise { - await this.env.editor.execCommand('link', { + await this.env.editor.execCommand('link', { url: this.state.url, label: this.state.label, - } as LinkParams); + }); this.env.editor.plugins.get(Layout).remove('link'); this.destroy(); }