From a1774f55911c89ed93ff2367435641381ab7d04e Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 26 May 2016 23:55:52 +0200 Subject: [PATCH] Refactor Editor and update on Components --- src/dom_components/main.js | 43 ++++++++--- src/dom_components/model/Components.js | 11 +++ src/editor/config/config.js | 7 +- src/editor/model/Editor.js | 101 +++++++++++++++---------- src/parser/model/ParserHtml.js | 16 +++- styles/css/main.css | 9 ++- styles/scss/main.scss | 7 +- test/specs/dom_components/main.js | 2 +- test/specs/parser/model/ParserHtml.js | 24 ++++++ 9 files changed, 161 insertions(+), 59 deletions(-) diff --git a/src/dom_components/main.js b/src/dom_components/main.js index c73170b5e..163f974a2 100644 --- a/src/dom_components/main.js +++ b/src/dom_components/main.js @@ -59,21 +59,21 @@ define(function(require) { if (!(name in c)) c[name] = defaults[name]; } - - if(!c.wrapper.attributes) - c.wrapper.attributes = {}; - c.wrapper.attributes.id = 'wrapper'; - +/* // If there is no components try to append defaults if(!c.wrapper.components.length && c.defaults.length){ c.wrapper.components = c.defaults; } +*/ + //c.wrapper.style.position = 'relative'; + var component = new Component(c.wrapper, { sm: c.em }); - if(!c.wrapper.style) - c.wrapper.style = {}; + component.set({ + attributes: {id: 'wrapper'} + }); - c.wrapper.style.position = 'relative'; - var component = new Component(c.wrapper, { sm: c.em }); + if(c.components) + component.get('components').add(c.components); var obj = { model: component, @@ -178,9 +178,32 @@ define(function(require) { * updated immediately * @return {HTMLElement} */ - render : function(){ + render: function(){ return componentView.render().el; }, + + /** + * Clear all components + * @return {this} + * @private + */ + clear: function(){ + var c = this.getComponents(); + for(var i = 0, len = c.length; i < len; i++) + c.pop(); + return this; + }, + + /** + * Set components + * @param {Object|string} components HTML string or components model + * @return {this} + * @private + */ + setComponents: function(components){ + this.clear().addComponent(components); + }, + }; }; diff --git a/src/dom_components/model/Components.js b/src/dom_components/model/Components.js index 743adac71..05a13ca0b 100644 --- a/src/dom_components/model/Components.js +++ b/src/dom_components/model/Components.js @@ -5,6 +5,10 @@ define([ 'backbone', 'require'], initialize: function(models, opt){ + // Inject editor + if(opt && opt.sm) + this.editor = opt.sm; + this.model = function(attrs, options) { var model; @@ -37,5 +41,12 @@ define([ 'backbone', 'require'], }, + add: function(models, opt){ + if(typeof models === 'string') + models = this.editor.Parser.parseHtml(models); + + return Backbone.Collection.prototype.add.apply(this, [models, opt]); + }, + }); }); diff --git a/src/editor/config/config.js b/src/editor/config/config.js index 67eca657f..398e2303b 100644 --- a/src/editor/config/config.js +++ b/src/editor/config/config.js @@ -1,6 +1,9 @@ define(function () { var config = { + //TEMP + components: '', + // Style prefix stylePrefix: 'wte-', @@ -46,8 +49,8 @@ define(function () { //Configurations for Rich Text Editor rte : {}, - //Configurations for Components - components : {}, + //Configurations for DomComponents + domComponents : {}, //Configurations for Modal Dialog modal : {}, diff --git a/src/editor/model/Editor.js b/src/editor/model/Editor.js index feca8caac..9c45690c6 100644 --- a/src/editor/model/Editor.js +++ b/src/editor/model/Editor.js @@ -49,6 +49,7 @@ define([ this.rulesName = this.pfx + 'rules' + this.config.id; this.set('Config', c); + this.initParser(); this.initStorage(); this.initClassManager(); this.initModal(); @@ -62,7 +63,6 @@ define([ this.initUndoManager(); this.initCssComposer(); this.initUtils(); - this.initParser(); this.on('change:selectedComponent', this.componentSelected, this); }, @@ -71,8 +71,8 @@ define([ * Initialize Parser * */ initParser: function() { - this.parser = new Parser(); - this.set('parser', this.parser); + this.Parser = new Parser(); + this.set('parser', this.Parser); }, /** @@ -161,30 +161,31 @@ define([ * @private * */ initComponents: function() { - var cfg = this.config.components, - comp = this.loadComponents(), - cmpStylePfx = cfg.stylePrefix || 'comp-'; + var cfg = this.config.domComponents, + comp = this.loadComponents(), + cmpStylePfx = cfg.stylePrefix || 'comp-'; cfg.stylePrefix = this.config.stylePrefix + cmpStylePfx; if(comp) - cfg.wrapper = comp; + cfg.components = comp; if(this.rte) - cfg.rte = this.rte; + cfg.rte = this.rte; if(this.modal) - cfg.modal = this.modal; + cfg.modal = this.modal; if(this.am) - cfg.am = this.am; + cfg.am = this.am; - cfg.em = this; + cfg.em = this; - this.cmp = new DomComponents(cfg); + this.cmp = new DomComponents(cfg); this.Components = this.cmp; + if(this.stm.isAutosave()){ - var md = this.cmp.getComponent(); + var md = this.cmp.getComponent(); this.updateComponents( md, null, { avoidStore : 1 }); // Call UndoManager here so it's possible to call it also for children inside @@ -398,15 +399,20 @@ define([ * @return {Object} * */ loadComponents: function() { - var result = null; - try{ - var r = this.stm.load(this.compName); - if(r) - result = JSON.parse(r); - }catch(err){ - //console.warn("Error encountered while parsing JSON response"); + var comps = ''; + var result = this.getCacheLoad(); + + if(result.components){ + try{ + comps = JSON.parse(result.components); + }catch(err){} + }else if(result.html){ + comps = result.html; } - return result; + + console.log('loadComponents'); + console.log(comps); + return comps; }, /** @@ -415,11 +421,12 @@ define([ * @return void * */ storeComponents: function() { - var wrp = this.cmp.getComponent(); + /*var wrp = this.cmp.getComponent(); if(wrp && this.cm){ var res = this.cm.getCode(wrp, 'json'); this.stm.store(this.compName, JSON.stringify(res)); - } + }*/ + this.store(); }, /** @@ -518,7 +525,7 @@ define([ * @return {this} */ setComponents: function(components){ - return this; + return this.Components.setComponents(components); }, /** @@ -608,6 +615,8 @@ define([ if(smc.storeStyles) store.styles = JSON.stringify(this.getStyle()); + console.log('Store'); + console.log(store); sm.store(store); }, @@ -615,11 +624,38 @@ define([ * Load data from the current storage */ load: function(){ + var result = this.getCacheLoad(1); + var comps = []; + + if(result.components){ + try{ + comps = JSON.parse(result.components); + }catch(err){} + }else if(result.html){ + comps = result.html; + } + + console.log(result); + //this.setComponents(comps); + }, + + /** + * Returns cached load + * @param {Boolean} force Force to reload + * @return {Object} + * @private + */ + getCacheLoad: function(force){ + var f = force ? 1 : 0; + + if(this.cacheLoad && !f) + return this.cacheLoad; + var sm = this.StorageManager; var load = []; if(!sm) - return; + return {}; var smc = sm.getConfig(); @@ -635,20 +671,9 @@ define([ if(smc.storeStyles) load.push('styles'); - var result = sm.load(load); - - var comps = []; - if(result.components){ - try{ - comps = JSON.parse(result.components); - }catch(err){} - }else if(result.html){ - comps = result.html; - } - - console.log(result); - //this.setComponents(comps); + this.cacheLoad = sm.load(load); + return this.cacheLoad; }, }); diff --git a/src/parser/model/ParserHtml.js b/src/parser/model/ParserHtml.js index 6009fb2be..e33fec30f 100644 --- a/src/parser/model/ParserHtml.js +++ b/src/parser/model/ParserHtml.js @@ -2,6 +2,8 @@ define(function(require) { return function(config) { + var TEXT_NODE = 'span'; + return { /** @@ -84,13 +86,21 @@ define(function(require) { } // Check for nested elements - if(node.childNodes.length) - model.components = this.parseNode(node); + var nodeChild = node.childNodes.length; + if(nodeChild){ + // Avoid infinite text nodes nesting + var firstChild = node.childNodes[0]; + if(nodeChild === 1 && firstChild.nodeType === 3 && model.tagName === TEXT_NODE){ + model.type = 'text'; + model.content = firstChild.nodeValue; + }else + model.components = this.parseNode(node); + } // Find text nodes if(!model.tagName && node.nodeType === 3 && node.nodeValue.trim()){ model.type = 'text'; - model.tagName = 'span'; + model.tagName = TEXT_NODE; model.content = node.nodeValue; } diff --git a/styles/css/main.css b/styles/css/main.css index c027bca8e..f2ed6d101 100644 --- a/styles/css/main.css +++ b/styles/css/main.css @@ -2614,8 +2614,10 @@ html, body, #wte-app, .wte-editor { top: 0; left: 3.5%; overflow: auto; - z-index: 1; } + z-index: 1; + /* This simulate body behaviour */ } .wte-cv-canvas > div { + position: relative; height: 100%; overflow: auto; width: 100%; } @@ -2686,7 +2688,7 @@ ol.example li.placeholder:before { outline: none !important; } /********* COMMANDS **********/ -.wte-com-dashed div { +.wte-com-dashed * { outline: 1px dashed #888; outline-offset: -2px; box-sizing: border-box; } @@ -3444,7 +3446,8 @@ ol.example li.placeholder:before { width: 25px; border-right: 1px solid #353535; text-align: center; - cursor: pointer; } + cursor: pointer; + outline: none; } #wte-rte-toolbar .wte-rte-btn:last-child { border-right: none; } #wte-rte-toolbar .wte-rte-btn.btn-info { diff --git a/styles/scss/main.scss b/styles/scss/main.scss index 418989bc3..89a4e4398 100644 --- a/styles/scss/main.scss +++ b/styles/scss/main.scss @@ -98,7 +98,9 @@ html,body,#wte-app, .#{$app-prefix}editor{ height: 100%; } overflow: auto; z-index:1; + /* This simulate body behaviour */ > div { + position: relative; height: 100%; overflow: auto; width: 100%; @@ -149,7 +151,7 @@ ol.example li.placeholder:before {position: absolute;} /********* COMMANDS **********/ -.#{$com-prefix}dashed div { +.#{$com-prefix}dashed *{ outline: 1px dashed #888; outline-offset: -2px; box-sizing: border-box; @@ -1031,12 +1033,13 @@ $uploadPadding: 150px 10px; z-index: 5; .#{$rte-prefix}btn { - color: $fontColor; + color: $fontColor; padding: 5px; width: 25px; border-right: 1px solid #353535; text-align: center; cursor: pointer; + outline: none; &:last-child{ border-right:none; } &.btn-info{ background-color: darken($mainDkColor,3%); } diff --git a/test/specs/dom_components/main.js b/test/specs/dom_components/main.js index 074974f38..52b205dcd 100644 --- a/test/specs/dom_components/main.js +++ b/test/specs/dom_components/main.js @@ -58,7 +58,7 @@ define([ it('Add components at init', function() { obj = new DomComponents({ - defaults : [{}, {}, {}] + components : [{}, {}, {}] }); obj.getComponents().length.should.equal(3); }); diff --git a/test/specs/parser/model/ParserHtml.js b/test/specs/parser/model/ParserHtml.js index a4c128764..7a6c6caaf 100644 --- a/test/specs/parser/model/ParserHtml.js +++ b/test/specs/parser/model/ParserHtml.js @@ -155,6 +155,30 @@ define([path + 'model/ParserHtml',], obj.parse(str).should.deep.equal(result); }); + it('Parse nested span text nodes', function() { + var str = '
content1
nested
content2
'; + var result = { + tagName: 'div', + components: [{ + tagName: 'span', + type: 'text', + content: 'content1 ', + },{ + tagName: 'div', + components: [{ + tagName: 'span', + type: 'text', + content: 'nested', + }] + },{ + tagName: 'span', + type: 'text', + content: ' content2', + }], + }; + obj.parse(str).should.deep.equal(result); + }); + it('Parse multiple nodes', function() { var str = '
'; var result = [{ tagName: 'div'},{ tagName: 'div'}];