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 { Model, ObjectAny, ObjectHash, SetOptions } from '../../common';
import ParserHtml from '../../parser/model/ParserHtml'; import ParserHtml from '../../parser/model/ParserHtml';
import Selectors from '../../selector_manager/model/Selectors'; 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 EditorModel from '../../editor/model/Editor';
import StyleDataVariable from '../../data_sources/model/StyleDataVariable'; import StyleDataVariable from '../../data_sources/model/StyleDataVariable';
import { DataSourcesEvents, DataVariableListener } from '../../data_sources/types';
import { DataVariableType } from '../../data_sources/model/DataVariable'; import { DataVariableType } from '../../data_sources/model/DataVariable';
import DataVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
export type StyleProps = Record< export type StyleProps = Record<
string, string,
@ -34,10 +34,10 @@ export const getLastStyleValue = (value: string | string[]) => {
export default class StyleableModel<T extends ObjectHash = any> extends Model<T> { export default class StyleableModel<T extends ObjectHash = any> extends Model<T> {
em?: EditorModel; 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 * @param {string} str
* @returns * @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 * Trigger style change event with a new object instance
* pass a new object instance
* @param {Object} prop * @param {Object} prop
* @return {Object} * @return {Object}
*/ */
@ -97,13 +96,14 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
// Remove empty style properties // Remove empty style properties
if (newStyle[key] === '') { if (newStyle[key] === '') {
delete newStyle[key]; delete newStyle[key];
return; return;
} }
const styleValue = newStyle[key]; const styleValue = newStyle[key];
if (typeof styleValue === 'object' && styleValue.type === DataVariableType) { 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) { if (em) {
em.trigger('styleable:change', this, pr, opts); em.trigger('styleable:change', this, pr, opts);
em.trigger(`styleable:change:${pr}`, 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; return newStyle;
} }
listenToDataVariable(dataVar: StyleDataVariable, styleProp: string) { /**
const { em } = this; * Manage DataVariableListenerManager for a style property
const { path } = dataVar.attributes; */
const normPath = stringToPath(path || '').join('.'); manageDataVariableListener(dataVar: StyleDataVariable, styleProp: string) {
const dataListeners: DataVariableListener[] = []; if (this.dataVariableListeners[styleProp]) {
const prevListeners = this.dataListeners || []; this.dataVariableListeners[styleProp].listenToDataVariable();
} else {
prevListeners.forEach((ls) => this.stopListening(ls.obj, ls.event, this.updateStyleProp)); this.dataVariableListeners[styleProp] = new DataVariableListenerManager({
model: this,
dataListeners.push({ obj: dataVar, event: 'change:value' }); em: this.em!,
dataListeners.push({ obj: em, event: `${DataSourcesEvents.path}:${normPath}` }); dataVariable: dataVar,
updateValueFromDataVariable: (newValue: string) => this.updateStyleProp(styleProp, newValue),
dataListeners.forEach((ls) => });
this.listenTo(ls.obj, ls.event, () => { }
const newValue = dataVar.getDataValue();
this.updateStyleProp(styleProp, newValue);
}),
);
this.dataListeners = dataListeners;
} }
/**
* Update a specific style property
*/
updateStyleProp(prop: string, value: string) { updateStyleProp(prop: string, value: string) {
const style = this.getStyle(); const style = this.getStyle();
style[prop] = value; style[prop] = value;
@ -162,6 +155,9 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
this.trigger(`change:style:${prop}`); this.trigger(`change:style:${prop}`);
} }
/**
* Resolve data variables to their actual values
*/
resolveDataVariables(style: StyleProps): StyleProps { resolveDataVariables(style: StyleProps): StyleProps {
const resolvedStyle = { ...style }; const resolvedStyle = { ...style };
keys(resolvedStyle).forEach((key) => { 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 Category from '../../abstract/ModuleCategory';
import { LocaleOptions, Model, SetOptions } from '../../common'; import { LocaleOptions, Model, SetOptions } 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';
import { isDef, stringToPath } from '../../utils/mixins'; import { isDef } from '../../utils/mixins';
import TraitsEvents, { TraitGetValueOptions, TraitOption, TraitProperties, TraitSetValueOptions } from '../types'; import TraitsEvents, { TraitGetValueOptions, TraitOption, TraitProperties, TraitSetValueOptions } from '../types';
import TraitView from '../view/TraitView'; import TraitView from '../view/TraitView';
import Traits from './Traits'; 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 TraitDataVariable from '../../data_sources/model/TraitDataVariable';
import { DataVariableType } from '../../data_sources/model/DataVariable'; import { DataVariableType } from '../../data_sources/model/DataVariable';
import DataVariableListenerManager from '../../data_sources/model/DataVariableListenerManager';
/** /**
* @property {String} id Trait id, eg. `my-trait-id`. * @property {String} id Trait id, eg. `my-trait-id`.
@ -31,6 +32,7 @@ export default class Trait extends Model<TraitProperties> {
el?: HTMLElement; el?: HTMLElement;
dataListeners: DataVariableListener[] = []; dataListeners: DataVariableListener[] = [];
dataVariable?: TraitDataVariable; dataVariable?: TraitDataVariable;
dataVariableListener?: DataVariableListenerManager;
defaults() { defaults() {
return { return {
@ -66,7 +68,12 @@ export default class Trait extends Model<TraitProperties> {
const dv = this.dataVariable.getDataValue(); const dv = this.dataVariable.getDataValue();
this.set({ value: dv }); 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) { updateValueFromDataVariable(value: string) {
this.setTargetValue(value); this.setTargetValue(value);
this.trigger('change:value'); this.trigger('change:value');

Loading…
Cancel
Save