From 608a1751fac4a4a51fac8deac24ab777b6389af1 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Tue, 10 Oct 2017 21:34:31 +0200 Subject: [PATCH] Refactor ComponentTextView --- src/dom_components/view/ComponentTextView.js | 92 +++++++++----------- src/dom_components/view/ComponentView.js | 42 ++++----- src/dom_components/view/ComponentsView.js | 61 +++++++------ src/utils/extender.js | 6 ++ 4 files changed, 98 insertions(+), 103 deletions(-) diff --git a/src/dom_components/view/ComponentTextView.js b/src/dom_components/view/ComponentTextView.js index 058e11f32..e907f6d0c 100644 --- a/src/dom_components/view/ComponentTextView.js +++ b/src/dom_components/view/ComponentTextView.js @@ -6,18 +6,16 @@ module.exports = ComponentView.extend({ events: { 'dblclick': 'enableEditing', - 'change': 'parseRender', }, initialize(o) { ComponentView.prototype.initialize.apply(this, arguments); - _.bindAll(this,'disableEditing'); + this.disableEditing = this.disableEditing.bind(this); const model = this.model; this.listenTo(model, 'focus active', this.enableEditing); this.listenTo(model, 'change:content', this.updateContent); this.rte = this.config.rte || ''; this.activeRte = null; - this.em = this.config.em; }, /** @@ -26,15 +24,18 @@ module.exports = ComponentView.extend({ * @private * */ enableEditing(e) { - var editable = this.model.get('editable'); - if(this.rte && editable) { + const editable = this.model.get('editable'); + const rte = this.rte; + + if (rte && editable) { try { - this.activeRte = this.rte.attach(this, this.activeRte); - this.rte.focus(this, this.activeRte); + this.activeRte = rte.attach(this, this.activeRte); + rte.focus(this, this.activeRte); } catch (err) { console.error(err); } } + this.toggleEvents(1); }, @@ -44,23 +45,46 @@ module.exports = ComponentView.extend({ * @private * */ disableEditing(e) { - var model = this.model; - var editable = model.get('editable'); + const model = this.model; + const editable = model.get('editable'); + const rte = this.rte; - if(this.rte && editable) { + if (rte && editable) { try { - this.rte.detach(this, this.activeRte); + rte.detach(this, this.activeRte); } catch (err) { console.error(err); } - var el = this.getChildrenContainer(); - // Avoid double content by removing its children components - model.get('components').reset(); - model.set('content', el.innerHTML); - } - if(!this.rte.customRte && editable) { - this.parseRender(); + const content = this.getChildrenContainer().innerHTML; + const comps = model.get('components'); + + // If there is a custom RTE the content is just baked staticly + // inside 'content' + if (rte.customRte) { + // Avoid double content by removing its children components + comps.reset(); + model.set('content', content); + } else { + const clean = model => { + model.set({ + highlightable: 0, + removable: 0, + draggable: 0, + copyable: 0, + toolbar: '', + }); + model.get('components').each(model => clean(model)); + } + + // Avoid re-render on reset with silent option + model.set('content', ''); + comps.reset(); + comps.add(content); + comps.each(model => clean(model)); + // With rerender is possible to see changes applied after clean + this.render(); + } } this.toggleEvents(); @@ -75,38 +99,6 @@ module.exports = ComponentView.extend({ e.stopPropagation(); }, - /** - * Parse content and re-render it - * @private - */ - parseRender() { - const model = this.model; - var el = this.getChildrenContainer(); - var comps = model.get('components'); - var opts = {silent: true}; - const clean = model => { - model.set({ - highlightable: 0, - removable: 0, - draggable: 0, - copyable: 0, - toolbar: '', - }, opts); - model.get('components').each(model => clean(model)); - } - - // Avoid re-render on reset with silent option - comps.reset(null, opts); - comps.add(el.innerHTML, opts); - comps.each(model => clean(model)); - model.set('content', ''); - this.render(); - - // As the reset was in silent mode I need to notify - // the navigator about the change - comps.trigger('resetNavigator'); - }, - /** * Enable/Disable events * @param {Boolean} enable diff --git a/src/dom_components/view/ComponentView.js b/src/dom_components/view/ComponentView.js index 28c9f6f85..e2def9bd6 100644 --- a/src/dom_components/view/ComponentView.js +++ b/src/dom_components/view/ComponentView.js @@ -1,5 +1,4 @@ const ComponentsView = require('./ComponentsView'); -const $ = Backbone.$; module.exports = Backbone.View.extend({ @@ -12,15 +11,16 @@ module.exports = Backbone.View.extend({ }, initialize(opt) { - var model = this.model; + const model = this.model; this.opts = opt || {}; this.config = this.opts.config || {}; this.em = this.config.em || ''; this.pfx = this.config.stylePrefix || ''; this.ppfx = this.config.pStylePrefix || ''; - this.components = model.get('components'); - this.attr = model.get("attributes"); + this.attr = model.get('attributes'); this.classe = this.attr.class || []; + const $el = this.$el; + const classes = model.get('classes'); this.listenTo(model, 'destroy remove', this.remove); this.listenTo(model, 'change:style', this.updateStyle); this.listenTo(model, 'change:attributes', this.updateAttributes); @@ -28,26 +28,20 @@ module.exports = Backbone.View.extend({ this.listenTo(model, 'change:state', this.updateState); this.listenTo(model, 'change:script', this.render); this.listenTo(model, 'change', this.handleChange); - this.listenTo(model.get('classes'), 'add remove change', this.updateClasses); - - const $el = this.$el; - const el = this.el; - const em = this.em; + this.listenTo(classes, 'add remove change', this.updateClasses); $el.data('model', model); - $el.data('collection', this.components); + $el.data('collection', model.get('components')); model.view = this; - - if (em) { - em.data(el, 'model', model); - em.data(el, 'collection', model.get('components')); - } - - if(model.get('classes').length) - this.importClasses(); - + classes.length && this.importClasses(); this.init(); }, + remove() { + Backbone.View.prototype.remove.apply(this); + const children = this.childrenView; + children && children.stopListening(); + }, + /** * Initialize callback */ @@ -309,15 +303,16 @@ module.exports = Backbone.View.extend({ * @private */ renderChildren() { - var view = new ComponentsView({ + const container = this.getChildrenContainer(); + const view = new ComponentsView({ collection: this.model.get('components'), config: this.config, componentTypes: this.opts.componentTypes, }); - var container = this.getChildrenContainer(); - var childNodes = view.render($(container)).el.childNodes; - childNodes = Array.prototype.slice.call(childNodes); + view.render(container); + this.childrenView = view; + const childNodes = Array.prototype.slice.call(view.el.childNodes); for (var i = 0, len = childNodes.length ; i < len; i++) { container.appendChild(childNodes.shift()); @@ -348,7 +343,6 @@ module.exports = Backbone.View.extend({ render() { this.renderAttributes(); - var model = this.model; this.updateContent(); this.renderChildren(); this.updateScript(); diff --git a/src/dom_components/view/ComponentsView.js b/src/dom_components/view/ComponentsView.js index 5f9366cf4..8becdc5bf 100644 --- a/src/dom_components/view/ComponentsView.js +++ b/src/dom_components/view/ComponentsView.js @@ -1,12 +1,13 @@ -var Backbone = require('backbone'); +import { isUndefined } from 'underscore' module.exports = Backbone.View.extend({ initialize(o) { this.opts = o || {}; this.config = o.config || {}; - this.listenTo( this.collection, 'add', this.addTo ); - this.listenTo( this.collection, 'reset', this.render ); + const coll = this.collection; + this.listenTo(coll, 'add', this.addTo); + this.listenTo(coll, 'reset', this.resetChildren); }, /** @@ -17,7 +18,7 @@ module.exports = Backbone.View.extend({ * @private * */ addTo(model) { - var i = this.collection.indexOf(model); + var i = this.collection.indexOf(model); this.addToCollection(model, null, i); var em = this.config.em; @@ -42,7 +43,6 @@ module.exports = Backbone.View.extend({ this.compView = require('./ComponentView'); var fragment = fragmentEl || null, viewObject = this.compView; - //console.log('Add to collection', model, 'Index',i); var dt = this.opts.componentTypes; @@ -66,44 +66,47 @@ module.exports = Backbone.View.extend({ if(view.model.get('type') == 'textnode') rendered = document.createTextNode(view.model.get('content')); - if(fragment){ + if (fragment) { fragment.appendChild(rendered); - }else{ - var p = this.$parent; - var pc = p.children; - if(typeof index != 'undefined'){ - var method = 'before'; + } else { + const parent = this.parentEl; + const children = parent.childNodes; + + if (!isUndefined(index)) { + const lastIndex = children.length == index; + // If the added model is the last of collection // need to change the logic of append - if(pc && p.children().length == index){ + if (lastIndex) { index--; - method = 'after'; } + // In case the added is new in the collection index will be -1 - if(index < 0) { - p.append(rendered); - }else { - if(pc) { - p.children().eq(index)[method](rendered); - } + if (lastIndex || !children.length) { + parent.appendChild(rendered); + } else { + parent.insertBefore(rendered, children[index]); } - }else{ - p.append(rendered); + } else { + parent.appendChild(rendered); } } return rendered; }, - render($p) { - var fragment = document.createDocumentFragment(); - this.$parent = $p || this.$el; - this.$el.empty(); - this.collection.each(function(model){ - this.addToCollection(model, fragment); - },this); - this.$el.append(fragment); + resetChildren() { + this.parentEl.innerHTML = ''; + this.collection.each(model => this.addToCollection(model)); + }, + render(parent) { + const el = this.el; + const frag = document.createDocumentFragment(); + this.parentEl = parent || this.el; + this.collection.each(model => this.addToCollection(model, frag)); + el.innerHTML = ''; + el.appendChild(frag); return this; } diff --git a/src/utils/extender.js b/src/utils/extender.js index f058e364d..45e05908e 100644 --- a/src/utils/extender.js +++ b/src/utils/extender.js @@ -213,6 +213,12 @@ module.exports = ({$, Backbone}) => { return this; } + fn.remove = function () { + return this.each(node => { + return node.parentNode && node.parentNode.removeChild(node); + }); + }, + // For spectrum compatibility fn.bind = function(ev, h) { return this.on(ev, h);