Browse Source

Refactor Traits Collection (#4983)

* Refactor Traits Collection

* Fix css prefix

* Fix trait undo and add test for it

---------

Co-authored-by: Artur Arseniev <artur.catch@hotmail.it>
pull/5196/head
Alex Ritter 3 years ago
committed by GitHub
parent
commit
047dc35412
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      .editorconfig
  2. 7
      src/trait_manager/index.ts
  3. 13
      src/trait_manager/model/Trait.ts
  4. 54
      src/trait_manager/model/TraitFactory.ts
  5. 43
      src/trait_manager/model/Traits.ts
  6. 2
      src/trait_manager/view/TraitView.ts
  7. 6
      src/trait_manager/view/TraitsView.ts
  8. 32
      test/specs/trait_manager/model/TraitsModel.ts
  9. 37
      test/specs/trait_manager/view/TraitsView.ts

8
.editorconfig

@ -8,3 +8,11 @@ insert_final_newline = true
charset = utf-8 charset = utf-8
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
quote_type = single
[*.ts]
charset = utf-8
indent_style = space
indent_size = 2
quote_type = single
max_line_length = 120

7
src/trait_manager/index.ts

@ -16,7 +16,7 @@ export const evAll = 'trait';
export const evPfx = `${evAll}:`; export const evPfx = `${evAll}:`;
export const evCustom = `${evPfx}custom`; export const evCustom = `${evPfx}custom`;
const typesDef = { const typesDef: { [id: string]: { new (o: any): TraitView } } = {
text: TraitView, text: TraitView,
number: TraitNumberView, number: TraitNumberView,
select: TraitSelectView, select: TraitSelectView,
@ -62,12 +62,9 @@ export default class TraitManager extends Module<TraitManagerConfig & { pStylePr
*/ */
constructor(em: EditorModel) { constructor(em: EditorModel) {
super(em, 'TraitManager', defaults); super(em, 'TraitManager', defaults);
const c = this.config;
const model = new Model(); const model = new Model();
this.model = model; this.model = model;
const ppfx = c.pStylePrefix; this.types = typesDef;
this.types = { ...typesDef };
ppfx && (c.stylePrefix = `${ppfx}${c.stylePrefix}`);
const upAll = debounce(() => this.__upSel(), 0); const upAll = debounce(() => this.__upSel(), 0);
model.listenTo(em, 'component:toggled', upAll); model.listenTo(em, 'component:toggled', upAll);

13
src/trait_manager/model/Trait.ts

@ -66,7 +66,7 @@ export interface TraitProperties {
*/ */
export default class Trait extends Model<TraitProperties> { export default class Trait extends Model<TraitProperties> {
target!: Component; target!: Component;
em?: EditorModel; em: EditorModel;
view?: TraitView; view?: TraitView;
el?: HTMLElement; el?: HTMLElement;
@ -85,12 +85,19 @@ export default class Trait extends Model<TraitProperties> {
}; };
} }
constructor(prop: TraitProperties) { constructor(prop: TraitProperties, em: EditorModel) {
super(prop); super(prop);
const { target, name, changeProp, value: initValue } = this.attributes; const { target, name } = this.attributes;
!this.get('id') && this.set('id', name); !this.get('id') && this.set('id', name);
if (target) {
this.setTarget(target);
}
this.em = em;
}
setTarget(target: Component) {
if (target) { if (target) {
const { name, changeProp, value: initValue } = this.attributes;
this.target = target; this.target = target;
this.unset('target'); this.unset('target');
const targetEvent = changeProp ? `change:${name}` : `change:attributes:${name}`; const targetEvent = changeProp ? `change:${name}` : `change:attributes:${name}`;

54
src/trait_manager/model/TraitFactory.ts

@ -1,35 +1,35 @@
import { TraitManagerConfig } from '../config/config'; import { TraitManagerConfig } from '../config/config';
import { TraitProperties } from './Trait'; import { isString } from 'underscore';
import Trait, { TraitProperties } from './Trait';
import EditorModel from '../../editor/model/Editor';
export default class TraitFactory {
config: Partial<TraitManagerConfig>;
constructor(config: Partial<TraitManagerConfig> = {}) {
this.config = config;
}
export default (config: Partial<TraitManagerConfig> = {}) => ({
/** /**
* Build props object by their name * Build props object by their name
* @param {Array<string>|string} props Array of properties name
* @return {Array<Object>}
*/ */
build(props: string | string[]) { build(prop: string | TraitProperties, em: EditorModel): Trait {
const objs = []; return isString(prop) ? this.buildFromString(prop, em) : new Trait(prop, em);
}
if (typeof props === 'string') props = [props];
for (let i = 0; i < props.length; i++) { private buildFromString(name: string, em: EditorModel): Trait {
const prop = props[i]; const obj: TraitProperties = {
const obj: TraitProperties = { name: name,
name: prop, type: 'text',
type: 'text', };
};
switch (prop) { switch (name) {
case 'target': case 'target':
obj.type = 'select'; obj.type = 'select';
obj.default = false; obj.default = false;
obj.options = config.optionsTarget; obj.options = this.config.optionsTarget;
break; break;
}
objs.push(obj);
} }
return new Trait(obj, em);
return objs; }
}, }
});

43
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 { AddOptions, Collection } from '../../common';
import Component from '../../dom_components/model/Component'; import Component from '../../dom_components/model/Component';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
@ -8,12 +8,16 @@ import TraitFactory from './TraitFactory';
export default class Traits extends Collection<Trait> { export default class Traits extends Collection<Trait> {
em: EditorModel; em: EditorModel;
target!: Component; target!: Component;
tf: TraitFactory;
constructor(coll: TraitProperties[], options: { em: EditorModel }) { constructor(coll: TraitProperties[], options: { em: EditorModel }) {
super(coll); super(coll);
this.em = options.em; this.em = options.em;
this.listenTo(this, 'add', this.handleAdd); this.listenTo(this, 'add', this.handleAdd);
this.listenTo(this, 'reset', this.handleReset); 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[] } = {}) { handleReset(coll: TraitProperties[], { previousModels = [] }: { previousModels?: Trait[] } = {}) {
@ -31,32 +35,29 @@ export default class Traits extends Collection<Trait> {
setTarget(target: Component) { setTarget(target: Component) {
this.target = target; this.target = target;
this.models.forEach(trait => trait.setTarget(target));
} }
/** @ts-ignore */ add(model: string | TraitProperties | Trait, options?: AddOptions): Trait;
add(models: string | Trait | TraitProperties | (string | Trait | TraitProperties)[], opt?: AddOptions) { add(models: Array<string | TraitProperties | Trait>, options?: AddOptions): Trait[];
const em = this.em; add(models: unknown, opt?: AddOptions): any {
if (models == undefined) {
// Use TraitFactory if necessary return undefined;
if (isString(models) || isArray(models)) { }
const tm = em && em.get! && em.Traits; const { target, em } = this;
const tmOpts = tm && tm.getConfig();
const tf = TraitFactory(tmOpts);
if (isString(models)) {
models = [models];
}
if (isArray(models)) {
var traits: Trait[] = [];
for (var i = 0, len = models.length; i < len; i++) { for (var i = 0, len = models.length; i < len; i++) {
const str = models[i]; const trait = models[i];
const model = isString(str) ? tf.build(str)[0] : str; traits[i] = trait instanceof Trait ? trait : this.tf.build(trait, em);
model.target = this.target; traits[i].setTarget(target);
models[i] = model as Trait;
} }
return super.add(traits, opt);
} }
const trait = models instanceof Trait ? models : this.tf.build(models as any, em);
trait.setTarget(target);
return Collection.prototype.add.apply(this, [models as Trait[], opt]); return super.add(trait, opt);
} }
} }
Traits.prototype.model = Trait;

2
src/trait_manager/view/TraitView.ts

@ -48,8 +48,8 @@ export default class TraitView extends View<Trait> {
const { type } = model.attributes; const { type } = model.attributes;
this.config = config; this.config = config;
this.em = config.em; this.em = config.em;
this.pfx = config.stylePrefix || '';
this.ppfx = config.pStylePrefix || ''; this.ppfx = config.pStylePrefix || '';
this.pfx = this.ppfx + config.stylePrefix || '';
this.target = target; this.target = target;
const { ppfx } = this; const { ppfx } = this;
this.clsField = `${ppfx}field ${ppfx}field-${type}`; this.clsField = `${ppfx}field ${ppfx}field-${type}`;

6
src/trait_manager/view/TraitsView.ts

@ -12,13 +12,13 @@ export default class TraitsView extends DomainViews {
super(o); super(o);
this.itemsView = itemsView; this.itemsView = itemsView;
const config = o.config || {}; const config = o.config || {};
const pfx = config.stylePrefix || '';
const em = o.editor; const em = o.editor;
this.config = config; this.config = config;
this.em = em; this.em = em;
this.pfx = pfx;
this.ppfx = config.pStylePrefix || ''; 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.listenTo(em, 'component:toggled', this.updatedCollection);
this.updatedCollection(); this.updatedCollection();
} }

32
test/specs/trait_manager/model/TraitsModel.ts

@ -1,17 +1,25 @@
import Trait from '../../../../src/trait_manager/model/Trait'; 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 Component from '../../../../src/dom_components/model/Component';
import Editor from '../../../../src/editor';
import EditorModel from '../../../../src/editor/model/Editor';
describe('TraitModels', () => { describe('TraitModels', () => {
var trait: Trait; var trait: Trait;
var target: Component; var target: Component;
var modelName = 'title'; var modelName = 'title';
var em: EditorModel;
beforeEach(() => { beforeEach(() => {
target = new Component(); em = new Editor().getModel();
trait = new Trait({ target = new Component({}, { em });
name: modelName, trait = new Trait(
target, {
}); name: modelName,
target,
},
em
);
}); });
afterEach(() => {}); afterEach(() => {});
@ -19,4 +27,18 @@ describe('TraitModels', () => {
test('Object exists', () => { test('Object exists', () => {
expect(trait).toBeTruthy(); 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;
});
}); });

37
test/specs/trait_manager/view/TraitsView.ts

@ -1,19 +1,26 @@
import Trait from '../../../../src/trait_manager/model/Trait'; import Trait from '../../../../src/trait_manager/model/Trait';
import TraitView from '../../../../src/trait_manager/view/TraitView'; import TraitView from '../../../../src/trait_manager/view/TraitView';
import Component from '../../../../src/dom_components/model/Component'; import Component from '../../../../src/dom_components/model/Component';
import EditorModel from '../../../../src/editor/model/Editor';
import Editor from '../../../../src/editor';
describe('TraitView', () => { describe('TraitView', () => {
var obj: TraitView; var obj: TraitView;
var trait: Trait; var trait: Trait;
var modelName = 'title'; var modelName = 'title';
var target: Component; var target: Component;
var em: EditorModel;
beforeEach(() => { beforeEach(() => {
em = new Editor().getModel();
target = new Component(); target = new Component();
trait = new Trait({ trait = new Trait(
name: modelName, {
target, name: modelName,
}); target,
},
em
);
obj = new TraitView({ obj = new TraitView({
model: trait, model: trait,
}); });
@ -34,14 +41,20 @@ describe('TraitView', () => {
test('Updates on different models do not alter other targets', () => { test('Updates on different models do not alter other targets', () => {
var target1 = new Component(); var target1 = new Component();
var target2 = new Component(); var target2 = new Component();
var trait1 = new Trait({ var trait1 = new Trait(
name: modelName, {
target: target1, name: modelName,
}); target: target1,
var trait2 = new Trait({ },
name: modelName, em
target: target2, );
}); var trait2 = new Trait(
{
name: modelName,
target: target2,
},
em
);
var obj1 = new TraitView({ model: trait1 }); var obj1 = new TraitView({ model: trait1 });
var obj2 = new TraitView({ model: trait2 }); var obj2 = new TraitView({ model: trait2 });

Loading…
Cancel
Save