From 1781a817e35e0a1f9f98ac8a16faeec829734969 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 17 Mar 2023 19:41:19 +0100 Subject: [PATCH 1/3] Refactor Traits Collection --- .editorconfig | 8 ++++ src/trait_manager/index.ts | 7 +--- src/trait_manager/model/TraitFactory.ts | 53 ++++++++++++------------- src/trait_manager/model/Traits.ts | 41 ++++++++++--------- 4 files changed, 56 insertions(+), 53 deletions(-) diff --git a/.editorconfig b/.editorconfig index 99745b0035..8b10eb01af 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,11 @@ insert_final_newline = true charset = utf-8 indent_style = space indent_size = 2 +quote_type = single + +[*.ts] +charset = utf-8 +indent_style = space +indent_size = 2 +quote_type = single +max_line_length = 120 \ No newline at end of file diff --git a/src/trait_manager/index.ts b/src/trait_manager/index.ts index 8d1ce8c3e9..f1c1036a35 100644 --- a/src/trait_manager/index.ts +++ b/src/trait_manager/index.ts @@ -16,7 +16,7 @@ export const evAll = 'trait'; export const evPfx = `${evAll}:`; export const evCustom = `${evPfx}custom`; -const typesDef = { +const typesDef: { [id: string]: { new (o: any): TraitView } } = { text: TraitView, number: TraitNumberView, select: TraitSelectView, @@ -62,12 +62,9 @@ export default class TraitManager extends Module this.__upSel(), 0); model.listenTo(em, 'component:toggled', upAll); diff --git a/src/trait_manager/model/TraitFactory.ts b/src/trait_manager/model/TraitFactory.ts index 0680ea2afc..2fbe6ca4dd 100644 --- a/src/trait_manager/model/TraitFactory.ts +++ b/src/trait_manager/model/TraitFactory.ts @@ -1,35 +1,34 @@ import { TraitManagerConfig } from '../config/config'; -import { TraitProperties } from './Trait'; +import { isString } from 'underscore'; +import Trait, { TraitProperties } from './Trait'; + +export default class TraitFactory { + config: Partial; + + constructor(config: Partial = {}) { + this.config = config; + } -export default (config: Partial = {}) => ({ /** * Build props object by their name - * @param {Array|string} props Array of properties name - * @return {Array} */ - build(props: string | string[]) { - const objs = []; - - if (typeof props === 'string') props = [props]; + build(prop: string | TraitProperties): Trait { + return isString(prop) ? this.buildFromString(prop) : new Trait(prop); + } - for (let i = 0; i < props.length; i++) { - const prop = props[i]; - const obj: TraitProperties = { - name: prop, - type: 'text', - }; + private buildFromString(name: string): Trait { + const obj: TraitProperties = { + name: name, + type: 'text', + }; - switch (prop) { - case 'target': - obj.type = 'select'; - obj.default = false; - obj.options = config.optionsTarget; - break; - } - - objs.push(obj); + switch (name) { + case 'target': + obj.type = 'select'; + obj.default = false; + obj.options = this.config.optionsTarget; + break; } - - return objs; - }, -}); + return new Trait(obj); + } +} diff --git a/src/trait_manager/model/Traits.ts b/src/trait_manager/model/Traits.ts index 94f543fa36..c9e9993d61 100644 --- a/src/trait_manager/model/Traits.ts +++ b/src/trait_manager/model/Traits.ts @@ -1,4 +1,4 @@ -import { isString, isArray } from 'underscore'; +import { isArray } from 'underscore'; import { AddOptions, Collection } from '../../common'; import Component from '../../dom_components/model/Component'; import EditorModel from '../../editor/model/Editor'; @@ -8,12 +8,16 @@ import TraitFactory from './TraitFactory'; export default class Traits extends Collection { em: EditorModel; target!: Component; + tf: TraitFactory; constructor(coll: TraitProperties[], options: { em: EditorModel }) { super(coll); this.em = options.em; this.listenTo(this, 'add', this.handleAdd); this.listenTo(this, 'reset', this.handleReset); + const tm = this.em?.Traits; + const tmOpts = tm?.getConfig(); + this.tf = new TraitFactory(tmOpts); } handleReset(coll: TraitProperties[], { previousModels = [] }: { previousModels?: Trait[] } = {}) { @@ -33,30 +37,25 @@ export default class Traits extends Collection { this.target = target; } - /** @ts-ignore */ - add(models: string | Trait | TraitProperties | (string | Trait | TraitProperties)[], opt?: AddOptions) { - const em = this.em; - - // Use TraitFactory if necessary - if (isString(models) || isArray(models)) { - const tm = em && em.get! && em.Traits; - const tmOpts = tm && tm.getConfig(); - const tf = TraitFactory(tmOpts); - - if (isString(models)) { - models = [models]; - } + add(model: string | TraitProperties | Trait, options?: AddOptions): Trait; + add(models: Array, options?: AddOptions): Trait[]; + add(models: unknown, opt?: AddOptions): any { + if (models == undefined) { + return undefined; + } + if (isArray(models)) { + var traits: Trait[] = []; for (var i = 0, len = models.length; i < len; i++) { - const str = models[i]; - const model = isString(str) ? tf.build(str)[0] : str; - model.target = this.target; - models[i] = model as Trait; + const trait = models[i]; + traits[i] = trait instanceof Trait ? trait : this.tf.build(trait); + traits[i].target = this.target; } + return super.add(traits, opt); } + const trait = models instanceof Trait ? models : this.tf.build(models as any); + trait.target = this.target; - return Collection.prototype.add.apply(this, [models as Trait[], opt]); + return super.add(trait, opt); } } - -Traits.prototype.model = Trait; From cc28ed6c79211b7636f0566acef2a85c5f621dcd Mon Sep 17 00:00:00 2001 From: Alex Ritter Date: Fri, 24 Mar 2023 14:12:11 +0100 Subject: [PATCH 2/3] Fix css prefix --- src/trait_manager/view/TraitView.ts | 2 +- src/trait_manager/view/TraitsView.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/trait_manager/view/TraitView.ts b/src/trait_manager/view/TraitView.ts index 8f7654b45e..7a0986ff47 100644 --- a/src/trait_manager/view/TraitView.ts +++ b/src/trait_manager/view/TraitView.ts @@ -48,8 +48,8 @@ export default class TraitView extends View { const { type } = model.attributes; this.config = config; this.em = config.em; - this.pfx = config.stylePrefix || ''; this.ppfx = config.pStylePrefix || ''; + this.pfx = this.ppfx + config.stylePrefix || ''; this.target = target; const { ppfx } = this; this.clsField = `${ppfx}field ${ppfx}field-${type}`; diff --git a/src/trait_manager/view/TraitsView.ts b/src/trait_manager/view/TraitsView.ts index fd2616b9a9..05c3981075 100644 --- a/src/trait_manager/view/TraitsView.ts +++ b/src/trait_manager/view/TraitsView.ts @@ -12,13 +12,13 @@ export default class TraitsView extends DomainViews { super(o); this.itemsView = itemsView; const config = o.config || {}; - const pfx = config.stylePrefix || ''; + const em = o.editor; this.config = config; this.em = em; - this.pfx = pfx; this.ppfx = config.pStylePrefix || ''; - this.className = `${pfx}traits`; + this.pfx = this.ppfx + config.stylePrefix || ''; + this.className = `${this.pfx}traits`; this.listenTo(em, 'component:toggled', this.updatedCollection); this.updatedCollection(); } From 0981a9aaab5bc1b30dec9fba16756bc18da5d50a Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 1 Jun 2023 20:43:19 +0200 Subject: [PATCH 3/3] Fix trait undo and add test for it --- src/trait_manager/model/Trait.ts | 13 +++++-- src/trait_manager/model/TraitFactory.ts | 9 +++-- src/trait_manager/model/Traits.ts | 10 +++-- test/specs/trait_manager/model/TraitsModel.ts | 32 +++++++++++++--- test/specs/trait_manager/view/TraitsView.ts | 37 +++++++++++++------ 5 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/trait_manager/model/Trait.ts b/src/trait_manager/model/Trait.ts index 8ce57da622..195a0bf5a9 100644 --- a/src/trait_manager/model/Trait.ts +++ b/src/trait_manager/model/Trait.ts @@ -64,7 +64,7 @@ export interface TraitProperties { */ export default class Trait extends Model { target!: Component; - em?: EditorModel; + em: EditorModel; view?: TraitView; el?: HTMLElement; @@ -83,12 +83,19 @@ export default class Trait extends Model { }; } - constructor(prop: TraitProperties) { + constructor(prop: TraitProperties, em: EditorModel) { super(prop); - const { target, name, changeProp, value: initValue } = this.attributes; + const { target, name } = this.attributes; !this.get('id') && this.set('id', name); + if (target) { + this.setTarget(target); + } + this.em = em; + } + setTarget(target: Component) { if (target) { + const { name, changeProp, value: initValue } = this.attributes; this.target = target; this.unset('target'); const targetEvent = changeProp ? `change:${name}` : `change:attributes:${name}`; diff --git a/src/trait_manager/model/TraitFactory.ts b/src/trait_manager/model/TraitFactory.ts index 2fbe6ca4dd..8653acb05e 100644 --- a/src/trait_manager/model/TraitFactory.ts +++ b/src/trait_manager/model/TraitFactory.ts @@ -1,6 +1,7 @@ import { TraitManagerConfig } from '../config/config'; import { isString } from 'underscore'; import Trait, { TraitProperties } from './Trait'; +import EditorModel from '../../editor/model/Editor'; export default class TraitFactory { config: Partial; @@ -12,11 +13,11 @@ export default class TraitFactory { /** * Build props object by their name */ - build(prop: string | TraitProperties): Trait { - return isString(prop) ? this.buildFromString(prop) : new Trait(prop); + build(prop: string | TraitProperties, em: EditorModel): Trait { + return isString(prop) ? this.buildFromString(prop, em) : new Trait(prop, em); } - private buildFromString(name: string): Trait { + private buildFromString(name: string, em: EditorModel): Trait { const obj: TraitProperties = { name: name, type: 'text', @@ -29,6 +30,6 @@ export default class TraitFactory { obj.options = this.config.optionsTarget; break; } - return new Trait(obj); + return new Trait(obj, em); } } diff --git a/src/trait_manager/model/Traits.ts b/src/trait_manager/model/Traits.ts index c9e9993d61..302e474a10 100644 --- a/src/trait_manager/model/Traits.ts +++ b/src/trait_manager/model/Traits.ts @@ -35,6 +35,7 @@ export default class Traits extends Collection { setTarget(target: Component) { this.target = target; + this.models.forEach(trait => trait.setTarget(target)); } add(model: string | TraitProperties | Trait, options?: AddOptions): Trait; @@ -43,18 +44,19 @@ export default class Traits extends Collection { if (models == undefined) { return undefined; } + const { target, em } = this; if (isArray(models)) { var traits: Trait[] = []; for (var i = 0, len = models.length; i < len; i++) { const trait = models[i]; - traits[i] = trait instanceof Trait ? trait : this.tf.build(trait); - traits[i].target = this.target; + traits[i] = trait instanceof Trait ? trait : this.tf.build(trait, em); + traits[i].setTarget(target); } return super.add(traits, opt); } - const trait = models instanceof Trait ? models : this.tf.build(models as any); - trait.target = this.target; + const trait = models instanceof Trait ? models : this.tf.build(models as any, em); + trait.setTarget(target); return super.add(trait, opt); } diff --git a/test/specs/trait_manager/model/TraitsModel.ts b/test/specs/trait_manager/model/TraitsModel.ts index dc19460a56..7a6b5ad9b1 100644 --- a/test/specs/trait_manager/model/TraitsModel.ts +++ b/test/specs/trait_manager/model/TraitsModel.ts @@ -1,17 +1,25 @@ import Trait from '../../../../src/trait_manager/model/Trait'; +import Traits from '../../../../src/trait_manager/model/Traits'; import Component from '../../../../src/dom_components/model/Component'; +import Editor from '../../../../src/editor'; +import EditorModel from '../../../../src/editor/model/Editor'; describe('TraitModels', () => { var trait: Trait; var target: Component; var modelName = 'title'; + var em: EditorModel; beforeEach(() => { - target = new Component(); - trait = new Trait({ - name: modelName, - target, - }); + em = new Editor().getModel(); + target = new Component({}, { em }); + trait = new Trait( + { + name: modelName, + target, + }, + em + ); }); afterEach(() => {}); @@ -19,4 +27,18 @@ describe('TraitModels', () => { test('Object exists', () => { expect(trait).toBeTruthy(); }); + test('Traits undo property', () => { + em.loadOnStart(); + const wrapper = em.Components.getWrapper(); + wrapper!.append(target); + const traits = new Traits([], { em }); + traits.add(modelName); + traits.setTarget(target); + const trait = traits.models[0]; + trait.setTargetValue('TitleValue'); + + expect(target.getAttributes()[modelName]).toBe('TitleValue'); + em.UndoManager.undo(); + expect(target.getAttributes()[modelName]).toBeUndefined; + }); }); diff --git a/test/specs/trait_manager/view/TraitsView.ts b/test/specs/trait_manager/view/TraitsView.ts index 3931a477c8..35bf45e528 100644 --- a/test/specs/trait_manager/view/TraitsView.ts +++ b/test/specs/trait_manager/view/TraitsView.ts @@ -1,19 +1,26 @@ import Trait from '../../../../src/trait_manager/model/Trait'; import TraitView from '../../../../src/trait_manager/view/TraitView'; import Component from '../../../../src/dom_components/model/Component'; +import EditorModel from '../../../../src/editor/model/Editor'; +import Editor from '../../../../src/editor'; describe('TraitView', () => { var obj: TraitView; var trait: Trait; var modelName = 'title'; var target: Component; + var em: EditorModel; beforeEach(() => { + em = new Editor().getModel(); target = new Component(); - trait = new Trait({ - name: modelName, - target, - }); + trait = new Trait( + { + name: modelName, + target, + }, + em + ); obj = new TraitView({ model: trait, }); @@ -34,14 +41,20 @@ describe('TraitView', () => { test('Updates on different models do not alter other targets', () => { var target1 = new Component(); var target2 = new Component(); - var trait1 = new Trait({ - name: modelName, - target: target1, - }); - var trait2 = new Trait({ - name: modelName, - target: target2, - }); + var trait1 = new Trait( + { + name: modelName, + target: target1, + }, + em + ); + var trait2 = new Trait( + { + name: modelName, + target: target2, + }, + em + ); var obj1 = new TraitView({ model: trait1 }); var obj2 = new TraitView({ model: trait2 });