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
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

7
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<TraitManagerConfig & { pStylePr
*/
constructor(em: EditorModel) {
super(em, 'TraitManager', defaults);
const c = this.config;
const model = new Model();
this.model = model;
const ppfx = c.pStylePrefix;
this.types = { ...typesDef };
ppfx && (c.stylePrefix = `${ppfx}${c.stylePrefix}`);
this.types = typesDef;
const upAll = debounce(() => this.__upSel(), 0);
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> {
target!: Component;
em?: EditorModel;
em: EditorModel;
view?: TraitView;
el?: HTMLElement;
@ -85,12 +85,19 @@ export default class Trait extends Model<TraitProperties> {
};
}
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}`;

54
src/trait_manager/model/TraitFactory.ts

@ -1,35 +1,35 @@
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
* @param {Array<string>|string} props Array of properties name
* @return {Array<Object>}
*/
build(props: string | string[]) {
const objs = [];
if (typeof props === 'string') props = [props];
build(prop: string | TraitProperties, em: EditorModel): Trait {
return isString(prop) ? this.buildFromString(prop, em) : new Trait(prop, em);
}
for (let i = 0; i < props.length; i++) {
const prop = props[i];
const obj: TraitProperties = {
name: prop,
type: 'text',
};
private buildFromString(name: string, em: EditorModel): 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, em);
}
}

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 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<Trait> {
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[] } = {}) {
@ -31,32 +35,29 @@ export default class Traits extends Collection<Trait> {
setTarget(target: Component) {
this.target = target;
this.models.forEach(trait => trait.setTarget(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<string | TraitProperties | Trait>, options?: AddOptions): Trait[];
add(models: unknown, opt?: AddOptions): any {
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 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, em);
traits[i].setTarget(target);
}
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;
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}`;

6
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();
}

32
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;
});
});

37
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 });

Loading…
Cancel
Save