diff --git a/packages/core/src/Modifiers.ts b/packages/core/src/Modifiers.ts index bb928fa26..f54c36da0 100644 --- a/packages/core/src/Modifiers.ts +++ b/packages/core/src/Modifiers.ts @@ -109,6 +109,12 @@ export class Modifiers { } return found; } + /** + * Return all the modifiers instances that are hold by `this`. + */ + getContent(): Modifier[] { + return this._contents; + } /** * Return all modifiers in the array that are an instance of the given * modifier class, if any. @@ -198,6 +204,20 @@ export class Modifiers { return true; } } + /** + * Replace the modifiers that have the same constructor. Otherwise append + * them. + */ + replaceOrAppend(modifiers: Modifiers): void { + for (const modifier of modifiers.getContent()) { + const foundModifier = this.find(modifier.constructor); + if (foundModifier) { + this.replace(foundModifier, modifier); + } else { + this.append(modifier.clone()); + } + } + } /** * Remove the first modifier in the array that is an instance of the given * modifier class or that matches the particular instance passed. diff --git a/packages/core/test/modifiers.test.ts b/packages/core/test/modifiers.test.ts new file mode 100644 index 000000000..9c7ae114f --- /dev/null +++ b/packages/core/test/modifiers.test.ts @@ -0,0 +1,41 @@ +import { Modifiers } from '../src/Modifiers'; +import { Modifier } from '../src/Modifier'; +import { expect } from 'chai'; + +function id(x: T): T { + return x; +} +describe('core', () => { + describe('Modifiers', () => { + describe('prepend()', () => { + it('should prepend multiples modifier in proper order', () => { + const modifiers = new Modifiers(); + const m1 = new Modifier(); + const m2 = new Modifier(); + const m3 = new Modifier(); + const m4 = new Modifier(); + modifiers.prepend(m1, m2, m3, m4); + const modifiersMap = modifiers.map(id); + expect(modifiersMap[0]).to.equal(m1); + expect(modifiersMap[1]).to.equal(m2); + expect(modifiersMap[2]).to.equal(m3); + expect(modifiersMap[3]).to.equal(m4); + }); + }); + describe('replaceOrAppend()', () => { + it('', () => { + class Modifier1 extends Modifier {} + class Modifier2 extends Modifier {} + const m1a = new Modifier1(); + const m1b = new Modifier1(); + const m2 = new Modifier2(); + const modifiers1 = new Modifiers(m1a, m2); + modifiers1.replaceOrAppend(new Modifiers(m1b)); + const allModifiers = modifiers1.getContent(); + expect(allModifiers.length).to.eql(2); + expect(allModifiers[0]).to.eql(m1b); + expect(allModifiers[1]).to.eql(m2); + }); + }); + }); +}); diff --git a/packages/plugin-char/src/Char.ts b/packages/plugin-char/src/Char.ts index 9dde0c6fd..7b5ff8bde 100644 --- a/packages/plugin-char/src/Char.ts +++ b/packages/plugin-char/src/Char.ts @@ -59,7 +59,7 @@ export class Char extends JWPlugin const inline = this.editor.plugins.get(Inline); const modifiers = inline.getCurrentModifiers(range); if (params.formats) { - modifiers.append(...params.formats.map(format => format.clone())); + modifiers.replaceOrAppend(params.formats); } const style = inline.getCurrentStyle(range); // Remove the contents of the range if needed. diff --git a/packages/plugin-link/src/LinkFormat.ts b/packages/plugin-link/src/LinkFormat.ts index 3006701d2..dcdec0861 100644 --- a/packages/plugin-link/src/LinkFormat.ts +++ b/packages/plugin-link/src/LinkFormat.ts @@ -17,4 +17,13 @@ export class LinkFormat extends Format { element.setAttribute('href', this.url); return element; } + + /** + * @override + */ + clone(): this { + const clone = super.clone(); + clone.url = this.url; + return clone; + } } diff --git a/packages/plugin-link/test/LinkFormat.test.ts b/packages/plugin-link/test/LinkFormat.test.ts new file mode 100644 index 000000000..4eac63974 --- /dev/null +++ b/packages/plugin-link/test/LinkFormat.test.ts @@ -0,0 +1,12 @@ +import { LinkFormat } from '../src/LinkFormat'; +import { expect } from 'chai'; +describe('Link', () => { + describe('LinkFormat', () => { + describe('clone()', () => { + it('should clone the link with proper url', () => { + const format = new LinkFormat('/url'); + expect(format.clone().url).to.eql('/url'); + }); + }); + }); +});