From 5fcd868991011bd5aa70cddc94c80106c3bd938c Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 30 Dec 2021 20:46:26 +0100 Subject: [PATCH] Start refactoring property views --- src/commands/view/SelectComponent.js | 88 ++----- src/domain_abstract/ui/InputNumber.js | 4 +- src/style_manager/index.js | 3 +- src/style_manager/model/Property.js | 2 +- src/style_manager/view/PropertyNumberView.js | 3 +- src/style_manager/view/PropertyView.js | 249 +++++++++---------- src/style_manager/view/SectorsView.js | 8 +- 7 files changed, 158 insertions(+), 199 deletions(-) diff --git a/src/commands/view/SelectComponent.js b/src/commands/view/SelectComponent.js index 46ee3f195..b1bc84803 100644 --- a/src/commands/view/SelectComponent.js +++ b/src/commands/view/SelectComponent.js @@ -1,13 +1,6 @@ import Backbone from 'backbone'; import { bindAll, isElement, isUndefined, debounce } from 'underscore'; -import { - on, - off, - getUnitFromValue, - isTaggableNode, - getViewEl, - hasWin -} from 'utils/mixins'; +import { on, off, getUnitFromValue, isTaggableNode, getViewEl, hasWin } from 'utils/mixins'; import { isVisible, isDoc } from 'utils/dom'; import ToolbarView from 'dom_components/view/ToolbarView'; import Toolbar from 'dom_components/model/Toolbar'; @@ -36,15 +29,7 @@ let showOffsets; */ export default { init(o) { - bindAll( - this, - 'onHover', - 'onOut', - 'onClick', - 'onFrameScroll', - 'onFrameUpdated', - 'onContainerChange' - ); + bindAll(this, 'onHover', 'onOut', 'onClick', 'onFrameScroll', 'onFrameUpdated', 'onContainerChange'); }, enable() { @@ -92,7 +77,7 @@ export default { em[method]('component:toggled component:update', this.onSelect, this); em[method]('change:componentHovered', this.onHovered, this); em[method]( - 'component:resize component:styleUpdate component:input', + 'component:resize styleable:change component:input', // component:styleUpdate this.updateGlobalPos, this ); @@ -177,7 +162,7 @@ export default { * @param {Object} el * @private * */ - onSelect: debounce(function() { + onSelect: debounce(function () { const { em } = this; const component = em.getSelected(); const currentFrame = em.get('currentFrame') || {}; @@ -242,7 +227,7 @@ export default { view: opts.view, force: 1, top: 0, - left: 0 + left: 0, }); }, @@ -253,7 +238,7 @@ export default { */ hideElementOffset(view) { this.editor.stopCommand('show-offset', { - view + view, }); }, @@ -266,7 +251,7 @@ export default { this.editor.runCommand('show-offset', { el, elPos: pos, - state: 'Fixed' + state: 'Fixed', }); }, @@ -347,9 +332,7 @@ export default { const ppfx = config.pStylePrefix || ''; const clsBadge = `${ppfx}badge`; const customeLabel = config.customBadgeLabel; - const badgeLabel = `${ - icon ? `
${icon}
` : '' - } + const badgeLabel = `${icon ? `
${icon}
` : ''}
${model.getName()}
`; badge.innerHTML = customeLabel ? customeLabel(model) : badgeLabel; } @@ -359,7 +342,7 @@ export default { bStyle.display = 'block'; const targetToElem = canvas.getTargetToElementFixed(el, badge, { - pos: pos + pos: pos, }); const top = targetToElem.top; //opts.topOff - badgeH < 0 ? -opts.topOff : posTop; @@ -390,8 +373,7 @@ export default { const config = em ? em.get('Config') : ''; const pfx = config.stylePrefix || ''; const resizeClass = `${pfx}resizing`; - const model = - !isElement(elem) && isTaggableNode(elem) ? elem : em.getSelected(); + const model = !isElement(elem) && isTaggableNode(elem) ? elem : em.getSelected(); const resizable = model && model.get('resizable'); let options = {}; let modelToStyle; @@ -402,10 +384,7 @@ export default { docs.forEach(doc => { const body = doc.body; const cls = body.className || ''; - body.className = (method == 'add' - ? `${cls} ${resizeClass}` - : cls.replace(resizeClass, '') - ).trim(); + body.className = (method == 'add' ? `${cls} ${resizeClass}` : cls.replace(resizeClass, '')).trim(); }); }; @@ -415,13 +394,7 @@ export default { // Here the resizer is updated with the current element height and width onStart(e, opts = {}) { const { el, config, resizer } = opts; - const { - keyHeight, - keyWidth, - currentUnit, - keepAutoHeight, - keepAutoWidth - } = config; + const { keyHeight, keyWidth, currentUnit, keepAutoHeight, keepAutoWidth } = config; toggleBodyClass('add', e, opts); modelToStyle = em.get('StyleManager').getModelToStyle(model); canvas.toggleFramesEvents(); @@ -468,14 +441,7 @@ export default { } const { store, selectedHandler, config } = options; - const { - keyHeight, - keyWidth, - autoHeight, - autoWidth, - unitWidth, - unitHeight - } = config; + const { keyHeight, keyWidth, autoHeight, autoWidth, unitWidth, unitHeight } = config; const onlyHeight = ['tc', 'bc'].indexOf(selectedHandler) >= 0; const onlyWidth = ['cl', 'cr'].indexOf(selectedHandler) >= 0; const style = {}; @@ -495,7 +461,7 @@ export default { const updateEvent = `update:component:style`; const eventToListen = `${updateEvent}:${keyHeight} ${updateEvent}:${keyWidth}`; em && em.trigger(eventToListen, null, null, { noEmit: 1 }); - } + }, }; if (typeof resizable == 'object') { @@ -529,7 +495,7 @@ export default { const toolbarView = new ToolbarView({ collection: this.toolbar, editor: this.editor, - em + em, }); toolbarEl.appendChild(toolbarView.render().el); } @@ -628,7 +594,7 @@ export default { ...badgeOpts, view, topOff, - leftOff + leftOff, }); style.top = topOff + unit; @@ -642,18 +608,18 @@ export default { top: topOff, left: leftOff, width: pos.width, - height: pos.height + height: pos.height, }); }, - _upToolbar: debounce(function() { + _upToolbar: debounce(function () { this.updateToolsGlobal({ force: 1 }); }), _trgToolUp(type, opts = {}) { this.em.trigger('canvas:tools:update', { type, - ...opts + ...opts, }); }, @@ -677,11 +643,7 @@ export default { const unit = 'px'; const toolsEl = this.toggleToolsEl(1); const { style } = toolsEl; - const targetToElem = canvas.getTargetToElementFixed( - el, - canvas.getToolbarEl(), - { pos } - ); + const targetToElem = canvas.getTargetToElementFixed(el, canvas.getToolbarEl(), { pos }); const topOff = targetToElem.canvasOffsetTop; const leftOff = targetToElem.canvasOffsetLeft; style.top = topOff + unit; @@ -696,18 +658,18 @@ export default { top: topOff, left: leftOff, width: pos.width, - height: pos.height + height: pos.height, }); }, /** * Update attached elements, eg. component toolbar */ - updateAttached: debounce(function() { + updateAttached: debounce(function () { this.updateGlobalPos(); }), - onContainerChange: debounce(function() { + onContainerChange: debounce(function () { this.em.refreshCanvas(); }, 150), @@ -738,7 +700,7 @@ export default { model && model.set({ status: '', - state: '' + state: '', }); }, @@ -764,5 +726,5 @@ export default { !opts.preserveSelected && em.setSelected(null); this.toggleToolsEl(); editor && editor.stopCommand('resize'); - } + }, }; diff --git a/src/domain_abstract/ui/InputNumber.js b/src/domain_abstract/ui/InputNumber.js index b3a7a8c91..de61e27d3 100644 --- a/src/domain_abstract/ui/InputNumber.js +++ b/src/domain_abstract/ui/InputNumber.js @@ -124,7 +124,7 @@ export default Input.extend({ const units = model.get('units') || []; if (units.length) { - const options = []; + const options = ['']; units.forEach(unit => { const selected = unit == model.get('unit') ? 'selected' : ''; @@ -255,6 +255,8 @@ export default Input.extend({ if (opt.deepCheck) { var fixed = model.get('fixedValues') || []; + if (val === '') unit = ''; + if (val) { // If the value is one of the fixed values I leave it as it is var regFixed = new RegExp('^' + fixed.join('|'), 'g'); diff --git a/src/style_manager/index.js b/src/style_manager/index.js index e13acea89..ae79ed9dc 100644 --- a/src/style_manager/index.js +++ b/src/style_manager/index.js @@ -629,7 +629,8 @@ export default () => { __upProps(opts) { const lastTarget = this.getLastSelected(); - if (!lastTarget || !this.getConfig().custom) return; + // if (!lastTarget || !this.getConfig().custom) return; + if (!lastTarget) return; const lastTargetParents = this.getSelectedParents(); const style = lastTarget.getStyle(); diff --git a/src/style_manager/model/Property.js b/src/style_manager/model/Property.js index c27e60931..8c58ffe79 100644 --- a/src/style_manager/model/Property.js +++ b/src/style_manager/model/Property.js @@ -32,7 +32,7 @@ export default class Property extends Model { } __upTargets(p, opts = {}) { - if (!this.__hasCustom()) return; + // if (!this.__hasCustom()) return; const { em } = this; const sm = em.get('StyleManager'); const name = this.getName(); diff --git a/src/style_manager/view/PropertyNumberView.js b/src/style_manager/view/PropertyNumberView.js index d4f9faa42..9cef28277 100644 --- a/src/style_manager/view/PropertyNumberView.js +++ b/src/style_manager/view/PropertyNumberView.js @@ -10,8 +10,7 @@ export default PropertyView.extend({ init() { const model = this.model; - this.listenTo(model, 'change:unit', this.modelValueChanged); - this.listenTo(model, 'el:change', this.elementUpdated); + this.listenTo(model, 'change:unit', this.onValueChange); this.listenTo(model, 'change:units', this.render); }, diff --git a/src/style_manager/view/PropertyView.js b/src/style_manager/view/PropertyView.js index 0a0f20be9..138d52fd6 100644 --- a/src/style_manager/view/PropertyView.js +++ b/src/style_manager/view/PropertyView.js @@ -39,7 +39,7 @@ export default Backbone.View.extend({ events: { change: 'inputValueChanged', - [`click [${clearProp}]`]: 'clear' + [`click [${clearProp}]`]: 'clear', }, initialize(o = {}) { @@ -68,36 +68,28 @@ export default Backbone.View.extend({ } if (em) { - this.listenTo( - em, - `update:component:style:${this.property}`, - this.targetUpdated - ); + this.listenTo(em, `update:component:style:${this.property}`, this.targetUpdated); //this.listenTo(em, `styleable:change:${this.property}`, this.targetUpdated); // Listening to changes of properties in this.requires, so that styleable // changes based on other properties are propagated const requires = model.get('requires') || {}; Object.keys(requires).forEach(property => { - this.listenTo( - em, - `component:styleUpdate:${property}`, - this.targetUpdated - ); + this.listenTo(em, `component:styleUpdate:${property}`, this.targetUpdated); }); } - this.listenTo(this.propTarget, 'update', this.targetUpdated); + // this.listenTo(this.propTarget, 'update', this.targetUpdated); this.listenTo(model, 'destroy remove', this.remove); - this.listenTo(model, 'change:value', this.modelValueChanged); + // this.listenTo(model, 'change:value', this.modelValueChanged); this.listenTo(model, 'targetUpdated', this.targetUpdated); this.listenTo(model, 'change:visible', this.updateVisibility); - this.listenTo(model, 'change:status', this.updateStatus); - this.listenTo( - model, - 'change:name change:className change:full', - this.render - ); + // this.listenTo(model, 'change:status', this.updateStatus); + this.listenTo(model, 'change:name change:className change:full', this.render); + + // this.listenTo(this.propTarget, 'update', this.onValueChange); + this.onValueChange = debounce(this.onValueChange.bind(this)); + this.listenTo(model, 'change:value', this.onValueChange); const init = this.init && this.init.bind(this); init && init(); @@ -105,9 +97,7 @@ export default Backbone.View.extend({ remove() { Backbone.View.prototype.remove.apply(this, arguments); - ['em', 'target', 'input', '$input', 'propTarget', 'sector'].forEach( - i => (this[i] = {}) - ); + ['em', 'target', 'input', '$input', 'propTarget', 'sector'].forEach(i => (this[i] = {})); this.__destroyFn(this._getClbOpts()); }, @@ -118,8 +108,8 @@ export default Backbone.View.extend({ */ updateStatus() { const { model } = this; - const status = model.get('status'); - const parent = model.parent; + // const status = model.get('status'); + // const parent = model.parent; const pfx = this.pfx; const ppfx = this.ppfx; const config = this.config; @@ -131,18 +121,25 @@ export default Backbone.View.extend({ labelEl.removeClass(`${updatedCls} ${computedCls}`); clearStyle.display = 'none'; - switch (status) { - case 'updated': - !parent && labelEl.addClass(updatedCls); - - if (config.clearProperties) { - clearStyle.display = 'inline'; - } - break; - case 'computed': - labelEl.addClass(computedCls); - break; + if (model.hasValue({ noParent: true })) { + labelEl.addClass(updatedCls); + config.clearProperties && (clearStyle.display = ''); + } else if (model.hasValue()) { + labelEl.addClass(computedCls); } + + // switch (status) { + // case 'updated': + // !parent && labelEl.addClass(updatedCls); + + // if (config.clearProperties) { + // clearStyle.display = 'inline'; + // } + // break; + // case 'computed': + // labelEl.addClass(computedCls); + // break; + // } }, /** @@ -150,10 +147,11 @@ export default Backbone.View.extend({ */ clear(ev) { ev && ev.stopPropagation(); - this.model.clearValue(); - this.__unset(); - // Skip one stack with setTimeout to avoid inconsistencies (eg. visible on padding composite clear) - setTimeout(() => this.targetUpdated()); + this.model.clear(); + // this.model.clearValue(); + // this.__unset(); + // // Skip one stack with setTimeout to avoid inconsistencies (eg. visible on padding composite clear) + // setTimeout(() => this.targetUpdated()); }, /** @@ -207,9 +205,11 @@ export default Backbone.View.extend({ */ inputValueChanged(ev) { ev && ev.stopPropagation(); + // Skip the default update in case a custom emit method is defined if (this.emit) return; - this.model.setValueFromInput(this.getInputValue()); - this.elementUpdated(); + this.model.upValue(ev.target.value); + // this.model.setValueFromInput(this.getInputValue()); + // this.elementUpdated(); }, /** @@ -225,7 +225,7 @@ export default Backbone.View.extend({ parent && value == 'updated' && parent.set('status', value); }, - emitUpdateTarget: debounce(function() { + emitUpdateTarget: debounce(function () { const em = this.config.em; em && em.trigger('styleManager:update:target', this.getFirstTarget()); }), @@ -244,11 +244,7 @@ export default Backbone.View.extend({ if (config.highlightChanged) { status = 'updated'; } - } else if ( - computedValue && - config.showComputed && - computedValue != defaultValue - ) { + } else if (computedValue && config.showComputed && computedValue != defaultValue) { value = computedValue; if (config.highlightComputed) { @@ -264,7 +260,7 @@ export default Backbone.View.extend({ status, targetValue, defaultValue, - computedValue + computedValue, }; }, @@ -273,36 +269,30 @@ export default Backbone.View.extend({ * */ targetUpdated(mod, val, opts = {}) { // Skip properties rendered in Stack Layers - if (this.config.fromLayer) return; - - this.emitUpdateTarget(); - - if (!this.checkVisibility()) { - return; - } - - const config = this.config; - const em = config.em; - const { model } = this; - const property = model.get('property'); - const { status, value, ...targetData } = this._getTargetData(); - const data = { - status, - value, - ...targetData - }; - - this.setStatus(status); - model.setValue(value, 0, { fromTarget: 1, ...opts }); - this.__update(value); - - if (em) { - em.trigger('styleManager:change', this, property, value, data); - em.trigger(`styleManager:change:${property}`, this, value, data); - this._emitUpdate(data); - } - - return data; + // if (this.config.fromLayer) return; + // this.emitUpdateTarget(); + // if (!this.checkVisibility()) { + // return; + // } + // const config = this.config; + // const em = config.em; + // const { model } = this; + // const property = model.get('property'); + // const { status, value, ...targetData } = this._getTargetData(); + // const data = { + // status, + // value, + // ...targetData + // }; + // this.setStatus(status); + // model.setValue(value, 0, { fromTarget: 1, ...opts }); + // this.__update(value); + // if (em) { + // em.trigger('styleManager:change', this, property, value, data); + // em.trigger(`styleManager:change:${property}`, this, value, data); + // this._emitUpdate(data); + // } + // return data; }, _emitUpdate(addData = {}) { @@ -326,7 +316,7 @@ export default Backbone.View.extend({ value: model.getFullValue(), property: model, id: model.get('id'), - name: model.get('property') + name: model.get('property'), }; }, @@ -412,6 +402,13 @@ export default Backbone.View.extend({ return input ? input.value : ''; }, + onValueChange(m, val, opt = {}) { + const value = this.model.getFullValue(); + this.setValue(value); + this.updateStatus(); + console.log('onValueChange', this.model.getName(), { value }, opt); + }, + /** * Triggers when the `value` of the model changes, so the target and * the input element should be updated @@ -420,31 +417,28 @@ export default Backbone.View.extend({ * @param {Object} opt Options * */ modelValueChanged(e, val, opt = {}) { - const { model } = this; - const value = model.getFullValue(); - - // Avoid element update if the change comes from it - if (!opt.fromInput) { - this.setValue(value); - } - - // Avoid target update if the changes comes from it - if (!opt.fromTarget) { - this.getTargets().forEach(target => this.__updateTarget(target, opt)); - - // Update the editor and selected components about the change - const { em } = this.config; - if (!em) return; - const prop = model.get('property'); - const updated = { [prop]: value }; - em.getSelectedAll().forEach(component => { - !opt.noEmit && em.trigger('component:update', component, updated, opt); - em.trigger(evStyleUp, component, prop, opt); - em.trigger(`${evStyleUp}:${prop}`, component, value, opt); - component.trigger(`change:style`, component, updated, opt); - component.trigger(`change:style:${prop}`, component, value, opt); - }); - } + // const { model } = this; + // const value = model.getFullValue(); + // // Avoid element update if the change comes from it + // if (!opt.fromInput) { + // this.setValue(value); + // } + // // Avoid target update if the changes comes from it + // if (!opt.fromTarget) { + // this.getTargets().forEach(target => this.__updateTarget(target, opt)); + // // Update the editor and selected components about the change + // const { em } = this.config; + // if (!em) return; + // const prop = model.get('property'); + // const updated = { [prop]: value }; + // em.getSelectedAll().forEach(component => { + // !opt.noEmit && em.trigger('component:update', component, updated, opt); + // em.trigger(evStyleUp, component, prop, opt); + // em.trigger(`${evStyleUp}:${prop}`, component, value, opt); + // component.trigger(`change:style`, component, updated, opt); + // component.trigger(`change:style:${prop}`, component, value, opt); + // }); + // } }, __updateTarget(target, opt = {}) { @@ -534,10 +528,7 @@ export default Backbone.View.extend({ // Check if the property is available only if requested if (toRequire) { - stylable = - !target || - (stylableReq && - (stylableReq.indexOf(id) >= 0 || stylableReq.indexOf(property) >= 0)); + stylable = !target || (stylableReq && (stylableReq.indexOf(id) >= 0 || stylableReq.indexOf(property) >= 0)); } // Check if the property is available based on other property's values @@ -560,8 +551,7 @@ export default Backbone.View.extend({ if (parentEl) { const styles = window.getComputedStyle(parentEl); each(requiresParent, (values, property) => { - stylable = - stylable && styles[property] && includes(values, styles[property]); + stylable = stylable && styles[property] && includes(values, styles[property]); }); } else { stylable = false; @@ -605,11 +595,11 @@ export default Backbone.View.extend({ * @param {String} value The value from the model * */ setValue(value) { - const model = this.model; - let val = isUndefined(value) ? model.getDefaultValue() : value; - if (this.update) return this.__update(val); + const { model } = this; + const result = isUndefined(value) ? model.getDefaultValue() : value; + if (this.update) return this.__update(result); const input = this.getInputEl(); - input && (input.value = val); + input && (input.value = result); }, getInputEl() { @@ -633,8 +623,8 @@ export default Backbone.View.extend({ }, /** - * Clean input - * */ + * @deprecated + */ cleanValue() { this.setValue(''); }, @@ -655,7 +645,7 @@ export default Backbone.View.extend({ update && update({ ...this._getClbOpts(), - value + value, }); }, @@ -664,10 +654,10 @@ export default Backbone.View.extend({ emit && emit(this._getClbOpts(), ...args); }, - __updateStyle(value, { complete, ...opts } = {}) { + __updateStyle(value, { complete, partial, ...opts } = {}) { const { em, model } = this; const prop = model.get('property'); - const final = complete !== false; + const final = complete !== false && partial !== true; if (isObject(value)) { this.getTargets().forEach(target => { @@ -675,7 +665,7 @@ export default Backbone.View.extend({ em && em.trigger(evStyleUp, target, prop, opts); }); } else { - model.setValueFromInput(value, complete, opts); + model.setValueFromInput(value, final, opts); } final && this.elementUpdated(); @@ -698,7 +688,7 @@ export default Backbone.View.extend({ target: this.getFirstTarget(), // Used to update custom UI computed, parentRules, // All parent rules - parentRule // First parent rule containing the same property + parentRule, // First parent rule containing the same property }; }, @@ -706,27 +696,26 @@ export default Backbone.View.extend({ this.clearCached(); const { pfx, model, el, $el } = this; const property = model.get('property'); + const type = model.get('type'); const full = model.get('full'); const cls = model.get('className') || ''; const className = `${pfx}property`; + // Support old integer classname + const clsType = type === 'number' ? `${pfx}${type} ${pfx}integer` : `${pfx}${type}`; 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.find('[data-sm-fields]').append(this.createdEl || this.templateInput(model)); - el.className = `${className} ${pfx}${model.get( - 'type' - )} ${className}__${property} ${cls}`.trim(); + el.className = `${className} ${clsType} ${className}__${property} ${cls}`.trim(); el.className += full ? ` ${className}--full` : ''; - this.updateStatus(); + // this.updateStatus(); const onRender = this.onRender && this.onRender.bind(this); onRender && onRender(); - this.setValue(model.get('value'), { fromTarget: 1 }); - } + // this.setValue(model.get('value'), { fromTarget: 1 }); + }, }); diff --git a/src/style_manager/view/SectorsView.js b/src/style_manager/view/SectorsView.js index 973f05e51..fcf39a4be 100644 --- a/src/style_manager/view/SectorsView.js +++ b/src/style_manager/view/SectorsView.js @@ -1,5 +1,5 @@ import Backbone from 'backbone'; -import { extend, isString, isArray } from 'underscore'; +import { extend, isString, isArray, debounce } from 'underscore'; import { isTaggableNode } from 'utils/mixins'; import { appendAtIndex } from 'utils/dom'; import SectorView from './SectorView'; @@ -30,8 +30,14 @@ export default Backbone.View.extend({ this.listenTo(coll, 'add', this.addTo); this.listenTo(coll, 'reset', this.render); this.listenTo(em, module.events.target, this.targetUpdated); + // Check local/parent value on input change + this.listenTo(em, 'styleable:change', this.emitUpdate); }, + emitUpdate: debounce(function () { + this.propTarget.trigger('update'); + }), + remove() { Backbone.View.prototype.remove.apply(this, arguments); ['target', 'config', 'propTarget'].forEach(i => (this[i] = {}));