From 260b210801935d0f7c64a47a081c02d2d25a2d7c Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sun, 30 Aug 2020 22:09:43 +0200 Subject: [PATCH] Add new API for extending Style Manager properties --- .../model/TypeableCollection.js | 5 ++ src/style_manager/index.js | 9 ++- src/style_manager/model/Properties.js | 2 + src/style_manager/view/PropertyView.js | 79 +++++++++++++++---- src/utils/mixins.js | 3 + 5 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/domain_abstract/model/TypeableCollection.js b/src/domain_abstract/model/TypeableCollection.js index faf6affdc..40b43ee13 100644 --- a/src/domain_abstract/model/TypeableCollection.js +++ b/src/domain_abstract/model/TypeableCollection.js @@ -124,6 +124,11 @@ export default { ? view : ViewInst.extend(view || {}); + // New API + if (this.extendViewApi && !definition.model && !definition.view) { + view = view.extend(definition); + } + if (type) { type.model = model; type.view = view; diff --git a/src/style_manager/index.js b/src/style_manager/index.js index 3b7fe8675..257d964f1 100644 --- a/src/style_manager/index.js +++ b/src/style_manager/index.js @@ -204,7 +204,7 @@ export default () => { /** * Get property by its CSS name and sector id * @param {string} sectorId Sector id - * @param {string} name CSS property name, eg. 'min-height' + * @param {string} name CSS property name (or id), eg. 'min-height' * @return {Property|null} * @example * var property = styleManager.getProperty('mySector','min-height'); @@ -214,8 +214,11 @@ export default () => { let prop = null; if (sector) { - prop = sector.get('properties').where({ property: name }); - prop = prop.length == 1 ? prop[0] : prop; + prop = sector + .get('properties') + .filter( + prop => prop.get('property') === name || prop.get('id') === name + )[0]; } return prop; diff --git a/src/style_manager/model/Properties.js b/src/style_manager/model/Properties.js index a865439ec..b2fbda89b 100644 --- a/src/style_manager/model/Properties.js +++ b/src/style_manager/model/Properties.js @@ -18,6 +18,8 @@ import PropertyIntegerView from './../view/PropertyIntegerView'; import PropertyView from './../view/PropertyView'; export default Backbone.Collection.extend(TypeableCollection).extend({ + extendViewApi: 1, + types: [ { id: 'stack', diff --git a/src/style_manager/view/PropertyView.js b/src/style_manager/view/PropertyView.js index a59e9e24e..9d3b9ed60 100644 --- a/src/style_manager/view/PropertyView.js +++ b/src/style_manager/view/PropertyView.js @@ -1,20 +1,16 @@ import Backbone from 'backbone'; import { bindAll, isArray, isUndefined, debounce } from 'underscore'; -import { camelCase } from 'utils/mixins'; +import { camelCase, isObject } from 'utils/mixins'; import { includes, each } from 'underscore'; const clearProp = 'data-clear-style'; export default Backbone.View.extend({ - template(model) { - const pfx = this.pfx; + template() { + const { pfx, ppfx } = this; return ` -
- ${this.templateLabel(model)} -
-
- ${this.templateInput(model)} -
+
+
`; }, @@ -46,7 +42,7 @@ export default Backbone.View.extend({ }, initialize(o = {}) { - bindAll(this, 'targetUpdated'); + bindAll(this, 'targetUpdated', '__change', '__updateStyle'); this.config = o.config || {}; const em = this.config.em; this.em = em; @@ -63,6 +59,7 @@ export default Backbone.View.extend({ const pfx = this.pfx; this.inputHolderId = '#' + pfx + 'input-holder'; this.sector = model.collection && model.collection.sector; + this.__destroyFn = this.destroy ? this.destroy.bind(this) : () => {}; model.view = this; if (!model.get('value')) { @@ -100,6 +97,11 @@ export default Backbone.View.extend({ init && init(); }, + remove() { + Backbone.View.prototype.remove.apply(this, arguments); + this.__destroyFn(this._getClbOpts()); + }, + /** * Triggers when the status changes. The status indicates if the value of * the proprerty is changed or inherited @@ -191,6 +193,7 @@ export default Backbone.View.extend({ */ inputValueChanged(ev) { ev && ev.stopPropagation(); + if (this.emit) return; this.model.setValueFromInput(this.getInputValue()); this.elementUpdated(); }, @@ -588,6 +591,7 @@ export default Backbone.View.extend({ setValue(value) { const model = this.model; let val = isUndefined(value) ? model.getDefaultValue() : value; + if (this.update) return this.__update(val); const input = this.getInputEl(); input && (input.value = val); }, @@ -625,16 +629,63 @@ export default Backbone.View.extend({ this.$input = null; }, + __update(value) { + const update = this.update && this.update.bind(this); + update && + update({ + ...this._getClbOpts(), + value + }); + }, + + __change(...args) { + const emit = this.emit && this.emit.bind(this); + emit && emit(this._getClbOpts(), ...args); + }, + + __updateStyle(value, { complete, ...opts } = {}) { + const final = complete !== false; + + if (isObject(value)) { + this.getTargets().forEach(target => + target.addStyle(value, { avoidStore: !final }) + ); + } else { + this.model.setValueFromInput(value, complete, opts); + } + + final && this.elementUpdated(); + }, + + _getClbOpts() { + const { model, el } = this; + return { + el, + props: model.attributes, + setProps: (...args) => model.set(...args), + change: this.__change, + updateStyle: this.__updateStyle, + targets: this.getTargets() + }; + }, + render() { this.clearCached(); - const pfx = this.pfx; - const model = this.model; - const el = this.el; + const { pfx, model, el, $el } = this; const property = model.get('property'); const full = model.get('full'); const cls = model.get('className') || ''; const className = `${pfx}property`; - el.innerHTML = this.template(model); + + this.createdEl && this.__destroyFn(this._getClbOpts()); + $el.empty().append(this.template(model)); + $el.find('[data-sm-label]').append(this.templateLabel(model)); + const create = this.create && this.create.bind(this); + this.createdEl = create && create(this._getClbOpts()); + $el + .find('[data-sm-fields]') + .append(this.createdEl || this.templateInput(model)); + el.className = `${className} ${pfx}${model.get( 'type' )} ${className}__${property} ${cls}`.trim(); diff --git a/src/utils/mixins.js b/src/utils/mixins.js index bde2e5c7e..9f44d76c4 100644 --- a/src/utils/mixins.js +++ b/src/utils/mixins.js @@ -210,6 +210,8 @@ const getPointerEvent = ev => const getKeyCode = ev => ev.which || ev.keyCode; const getKeyChar = ev => String.fromCharCode(getKeyCode(ev)); const isEscKey = ev => getKeyCode(ev) === 27; +const isObject = val => + val !== null && !Array.isArray(val) && typeof val === 'object'; const capitalize = str => str && str.charAt(0).toUpperCase() + str.substring(1); const isComponent = obj => obj && obj.toHTML; @@ -242,6 +244,7 @@ export { getViewEl, setViewEl, appendStyles, + isObject, isComponent, isRule };