diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 1f6834449..07092e215 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -1,4 +1,5 @@ -import { isUndefined, isArray, isEmpty, has, clone } from 'underscore'; +import { isUndefined, isArray, isEmpty, has, clone, isString, keys } from 'underscore'; +import { shallowDiff } from 'utils/mixins'; import Styleable from 'domain_abstract/model/Styleable'; const Backbone = require('backbone'); @@ -208,10 +209,13 @@ module.exports = Backbone.Model.extend(Styleable).extend({ const em = this.em; if (em && em.getConfig('avoidInlineStyle')) { - prop = Styleable.setStyle.call(this, prop, {silent: 1, avoidStore: 1}); + prop = isString(prop) ? this.parseStyle(prop) : prop; const state = this.get('state'); const cc = em.get('CssComposer'); + const propOrig = this.getStyle(); this.rule = cc.setIdRule(this.getId(), prop, { ...opts, state }); + const diff = shallowDiff(propOrig, prop); + keys(diff).forEach(pr => this.trigger(`change:style:${pr}`)); } else { prop = Styleable.setStyle.apply(this, arguments); } diff --git a/src/domain_abstract/model/Styleable.js b/src/domain_abstract/model/Styleable.js index 1a04ec388..a0d379a8b 100644 --- a/src/domain_abstract/model/Styleable.js +++ b/src/domain_abstract/model/Styleable.js @@ -1,4 +1,5 @@ -import { isString, isArray } from 'underscore'; +import { isString, isArray, keys } from 'underscore'; +import { shallowDiff } from 'utils/mixins'; import ParserHtml from 'parser/model/ParserHtml'; const parseStyle = ParserHtml().parseStyle; @@ -37,13 +38,13 @@ export default { prop = parseStyle(prop); } - this.set('style', { ...prop }, opts); + const propOrig = this.getStyle(); + const propNew = { ...prop }; + this.set('style', propNew, opts); + const diff = shallowDiff(propOrig, propNew); + keys(diff).forEach(pr => this.trigger(`change:style:${pr}`)); - for (let pr in prop) { - this.trigger(`change:style:${pr}`); - } - - return prop; + return propNew; }, diff --git a/src/navigator/view/ItemView.js b/src/navigator/view/ItemView.js index 8fff579c8..c88213316 100644 --- a/src/navigator/view/ItemView.js +++ b/src/navigator/view/ItemView.js @@ -54,6 +54,7 @@ module.exports = Backbone.View.extend({ this.listenTo(model, 'destroy remove', this.remove); this.listenTo(model, 'change:status', this.updateStatus); this.listenTo(model, 'change:open', this.updateOpening); + this.listenTo(model, 'change:style:display', this.updateVisibility); this.className = `${pfx}item no-select`; this.editBtnCls = `${pfx}nav-item-edit`; this.inputNameCls = `${ppfx}nav-comp-name`; @@ -63,6 +64,50 @@ module.exports = Backbone.View.extend({ this.$el.data('collection', components); }, + + getVisibilityEl () { + if (!this.eyeEl) { + this.eyeEl = this.$el.children(`#${this.pfx}btn-eye`); + } + + return this.eyeEl; + }, + + + updateVisibility() { + const pfx = this.pfx; + const model = this.model; + const hClass = `${pfx}hide`; + const hideIcon = 'fa-eye-slash'; + const hidden = model.getStyle().display == 'none'; + const method = hidden ? 'addClass' : 'removeClass'; + this.$el[method](hClass); + this.getVisibilityEl()[method](hideIcon); + }, + + + /** + * Toggle visibility + * @param Event + * + * @return void + * */ + toggleVisibility(e) { + e && e.stopPropagation(); + const model = this.model; + const style = model.getStyle(); + const hidden = style.display == 'none'; + + if (hidden) { + delete style.display; + } else { + style.display = 'none'; + } + + model.setStyle(style); + }, + + /** * Handle the edit of the component name */ @@ -73,6 +118,7 @@ module.exports = Backbone.View.extend({ inputName.focus(); }, + /** * Handle with the end of editing of the component name */ @@ -178,34 +224,6 @@ module.exports = Backbone.View.extend({ ComponentView.prototype.updateStatus.apply(this, arguments); }, - /** - * Toggle visibility - * @param Event - * - * @return void - * */ - toggleVisibility(e) { - e && e.stopPropagation(); - const pfx = this.pfx; - const model = this.model; - const hClass = `${pfx}hide`; - const style = model.getStyle(); - const hideIcon = 'fa-eye-slash'; - const $el = this.$el; - !this.$eye && (this.$eye = $el.children(`#${pfx}btn-eye`)); - - if (this.isVisible()) { - $el.addClass(hClass); - this.$eye.addClass(hideIcon); - style.display = 'none'; - } else { - $el.removeClass(hClass); - this.$eye.removeClass(hideIcon); - delete style.display; - } - - model.setStyle(style); - }, /** * Check if component is visible @@ -319,6 +337,7 @@ module.exports = Backbone.View.extend({ el.attr('class', _.result(this, 'className')); this.updateOpening(); this.updateStatus(); + this.updateVisibility(); return this; }, diff --git a/src/utils/mixins.js b/src/utils/mixins.js index 714e41e8c..f612f4795 100644 --- a/src/utils/mixins.js +++ b/src/utils/mixins.js @@ -1,6 +1,50 @@ +import { omit, keys, isUndefined } from 'underscore'; + const elProt = window.Element.prototype; const matches = elProt.matches || elProt.webkitMatchesSelector || elProt.mozMatchesSelector || elProt.msMatchesSelector; +/** + * Returns shallow diff between 2 objects + * @param {Object} objOrig + * @param {Objec} objNew + * @return {Object} + * @example + * var a = {foo: 'bar', baz: 1, faz: 'sop'}; + * var b = {foo: 'bar', baz: 2, bar: ''}; + * shallowDiff(a, b); + * // -> {baz: 2, faz: null, bar: ''}; + */ +const shallowDiff = (objOrig, objNew) => { + const result = {}; + const keysNew = keys(objNew); + + for (let prop in objOrig) { + if (objOrig.hasOwnProperty(prop)) { + const origValue = objOrig[prop]; + const newValue = objNew[prop]; + + if (keysNew.indexOf(prop) >= 0) { + if (origValue !== newValue) { + result[prop] = newValue; + } + } else { + result[prop] = null; + } + } + } + + for (let prop in objNew) { + if (objNew.hasOwnProperty(prop)) { + if (isUndefined(objOrig[prop])) { + result[prop] = objNew[prop]; + } + } + } + + return result; +}; + + const on = (el, ev, fn) => { ev = ev.split(/\s+/); el = el instanceof Array ? el : [el]; @@ -41,5 +85,6 @@ export { upFirst, matches, camelCase, + shallowDiff, getUnitFromValue }