Browse Source

feat: reuse data listeners for style and traits

feature/data-sources
danstarns 2 years ago
parent
commit
843492fbc7
  1. 60
      src/data_sources/model/DataVariableListenerManager.ts
  2. 60
      src/domain_abstract/model/StyleableModel.ts
  3. 45
      src/trait_manager/model/Trait.ts

60
src/data_sources/model/DataVariableListenerManager.ts

@ -0,0 +1,60 @@
import { DataSourcesEvents, DataVariableListener } from '../../data_sources/types';
import { stringToPath } from '../../utils/mixins';
import { Model } from '../../common';
import EditorModel from '../../editor/model/Editor';
import DataVariable from './DataVariable';
export interface DataVariableListenerManagerOptions {
model: Model;
em: EditorModel;
dataVariable: DataVariable;
updateValueFromDataVariable: (value: any) => void;
}
export default class DataVariableListenerManager {
private dataListeners: DataVariableListener[] = [];
private em: EditorModel;
private model: Model;
private dataVariable: DataVariable;
private updateValueFromDataVariable: (value: any) => void;
constructor(options: DataVariableListenerManagerOptions) {
this.em = options.em;
this.model = options.model;
this.dataVariable = options.dataVariable;
this.updateValueFromDataVariable = options.updateValueFromDataVariable;
this.listenToDataVariable();
}
listenToDataVariable() {
const { em, dataVariable, model, updateValueFromDataVariable } = this;
const { path } = dataVariable.attributes;
const normPath = stringToPath(path || '').join('.');
const prevListeners = this.dataListeners || [];
const [ds, dr] = this.em.DataSources.fromPath(path);
prevListeners.forEach((ls) => model.stopListening(ls.obj, ls.event, updateValueFromDataVariable));
const dataListeners: DataVariableListener[] = [];
ds && dataListeners.push({ obj: ds.records, event: 'add remove reset' });
dr && dataListeners.push({ obj: dr, event: 'change' });
dataListeners.push({ obj: dataVariable, event: 'change:value' });
dataListeners.push({ obj: em, event: `${DataSourcesEvents.path}:${normPath}` });
dataListeners.push(
{ obj: dataVariable, event: 'change:path change:value' },
{ obj: em.DataSources.all, event: 'add remove reset' },
{ obj: em, event: `${DataSourcesEvents.path}:${normPath}` },
);
dataListeners.forEach((ls) =>
model.listenTo(ls.obj, ls.event, () => {
const value = dataVariable.getDataValue();
updateValueFromDataVariable(value);
}),
);
this.dataListeners = dataListeners;
}
}

60
src/domain_abstract/model/StyleableModel.ts

@ -2,11 +2,11 @@ import { isArray, isString, keys } from 'underscore';
import { Model, ObjectAny, ObjectHash, SetOptions } from '../../common';
import ParserHtml from '../../parser/model/ParserHtml';
import Selectors from '../../selector_manager/model/Selectors';
import { shallowDiff, stringToPath } from '../../utils/mixins';
import { shallowDiff } from '../../utils/mixins';
import EditorModel from '../../editor/model/Editor';
import StyleDataVariable from '../../data_sources/model/StyleDataVariable';
import { DataSourcesEvents, DataVariableListener } from '../../data_sources/types';
import { DataVariableType } from '../../data_sources/model/DataVariable';
import DataVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
export type StyleProps = Record<
string,
@ -34,10 +34,10 @@ export const getLastStyleValue = (value: string | string[]) => {
export default class StyleableModel<T extends ObjectHash = any> extends Model<T> {
em?: EditorModel;
dataListeners: DataVariableListener[] = [];
dataVariableListeners: Record<string, DataVariableListenerManager> = {};
/**
* Forward style string to `parseStyle` to be parse to an object
* Parse style string to an object
* @param {string} str
* @returns
*/
@ -46,8 +46,7 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
}
/**
* To trigger the style change event on models I have to
* pass a new object instance
* Trigger style change event with a new object instance
* @param {Object} prop
* @return {Object}
*/
@ -97,13 +96,14 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
// Remove empty style properties
if (newStyle[key] === '') {
delete newStyle[key];
return;
}
const styleValue = newStyle[key];
if (typeof styleValue === 'object' && styleValue.type === DataVariableType) {
newStyle[key] = new StyleDataVariable(styleValue, { em: this.em });
const styleDataVariable = new StyleDataVariable(styleValue, { em: this.em });
newStyle[key] = styleDataVariable;
this.manageDataVariableListener(styleDataVariable, key);
}
});
@ -123,38 +123,31 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
if (em) {
em.trigger('styleable:change', this, pr, opts);
em.trigger(`styleable:change:${pr}`, this, pr, opts);
const styleValue = newStyle[pr];
if (styleValue instanceof StyleDataVariable) {
this.listenToDataVariable(styleValue, pr);
}
}
});
return newStyle;
}
listenToDataVariable(dataVar: StyleDataVariable, styleProp: string) {
const { em } = this;
const { path } = dataVar.attributes;
const normPath = stringToPath(path || '').join('.');
const dataListeners: DataVariableListener[] = [];
const prevListeners = this.dataListeners || [];
prevListeners.forEach((ls) => this.stopListening(ls.obj, ls.event, this.updateStyleProp));
dataListeners.push({ obj: dataVar, event: 'change:value' });
dataListeners.push({ obj: em, event: `${DataSourcesEvents.path}:${normPath}` });
dataListeners.forEach((ls) =>
this.listenTo(ls.obj, ls.event, () => {
const newValue = dataVar.getDataValue();
this.updateStyleProp(styleProp, newValue);
}),
);
this.dataListeners = dataListeners;
/**
* Manage DataVariableListenerManager for a style property
*/
manageDataVariableListener(dataVar: StyleDataVariable, styleProp: string) {
if (this.dataVariableListeners[styleProp]) {
this.dataVariableListeners[styleProp].listenToDataVariable();
} else {
this.dataVariableListeners[styleProp] = new DataVariableListenerManager({
model: this,
em: this.em!,
dataVariable: dataVar,
updateValueFromDataVariable: (newValue: string) => this.updateStyleProp(styleProp, newValue),
});
}
}
/**
* Update a specific style property
*/
updateStyleProp(prop: string, value: string) {
const style = this.getStyle();
style[prop] = value;
@ -162,6 +155,9 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
this.trigger(`change:style:${prop}`);
}
/**
* Resolve data variables to their actual values
*/
resolveDataVariables(style: StyleProps): StyleProps {
const resolvedStyle = { ...style };
keys(resolvedStyle).forEach((key) => {

45
src/trait_manager/model/Trait.ts

@ -1,15 +1,16 @@
import { isString, isUndefined, keys } from 'underscore';
import { isString, isUndefined } from 'underscore';
import Category from '../../abstract/ModuleCategory';
import { LocaleOptions, Model, SetOptions } from '../../common';
import Component from '../../dom_components/model/Component';
import EditorModel from '../../editor/model/Editor';
import { isDef, stringToPath } from '../../utils/mixins';
import { isDef } from '../../utils/mixins';
import TraitsEvents, { TraitGetValueOptions, TraitOption, TraitProperties, TraitSetValueOptions } from '../types';
import TraitView from '../view/TraitView';
import Traits from './Traits';
import { DataSourcesEvents, DataVariableListener } from '../../data_sources/types';
import { DataVariableListener } from '../../data_sources/types';
import TraitDataVariable from '../../data_sources/model/TraitDataVariable';
import { DataVariableType } from '../../data_sources/model/DataVariable';
import DataVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
/**
* @property {String} id Trait id, eg. `my-trait-id`.
@ -31,6 +32,7 @@ export default class Trait extends Model<TraitProperties> {
el?: HTMLElement;
dataListeners: DataVariableListener[] = [];
dataVariable?: TraitDataVariable;
dataVariableListener?: DataVariableListenerManager;
defaults() {
return {
@ -66,7 +68,12 @@ export default class Trait extends Model<TraitProperties> {
const dv = this.dataVariable.getDataValue();
this.set({ value: dv });
this.listenToDataVariable(this.dataVariable);
this.dataVariableListener = new DataVariableListenerManager({
model: this,
em: this.em,
dataVariable: this.dataVariable,
updateValueFromDataVariable: this.updateValueFromDataVariable.bind(this),
});
}
}
@ -102,36 +109,6 @@ export default class Trait extends Model<TraitProperties> {
}
}
listenToDataVariable(dataVar: TraitDataVariable) {
const { em } = this;
const { path } = dataVar.attributes;
const normPath = stringToPath(path || '').join('.');
const dataListeners: DataVariableListener[] = [];
const prevListeners = this.dataListeners || [];
const [ds, dr] = this.em.DataSources.fromPath(path);
prevListeners.forEach((ls) => this.stopListening(ls.obj, ls.event, this.updateValueFromDataVariable));
ds && dataListeners.push({ obj: ds.records, event: 'add remove reset' });
dr && dataListeners.push({ obj: dr, event: 'change' });
dataListeners.push({ obj: dataVar, event: 'change:value' });
dataListeners.push({ obj: em, event: `${DataSourcesEvents.path}:${normPath}` });
dataListeners.push(
{ obj: dataVar, event: 'change:path change:value' },
{ obj: em.DataSources.all, event: 'add remove reset' },
{ obj: em, event: `${DataSourcesEvents.path}:${normPath}` },
);
dataListeners.forEach((ls) =>
this.listenTo(ls.obj, ls.event, () => {
const dr = dataVar.getDataValue();
this.updateValueFromDataVariable(dr);
}),
);
this.dataListeners = dataListeners;
}
updateValueFromDataVariable(value: string) {
this.setTargetValue(value);
this.trigger('change:value');

Loading…
Cancel
Save