From e0aad96df245c7148966887cbcc77417a4b7675b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksander=20=C5=81ukasz?= Date: Wed, 2 Apr 2014 14:17:10 +0200 Subject: [PATCH] third batch - register - replacing on class change - first approach to new rendering code path --- .../modules/documentCanvas/canvas/canvas.js | 65 +++++-------------- .../documentCanvas/canvas/canvas.test.js | 31 +++++---- .../documentCanvas/canvas/documentElement.js | 15 ++--- .../documentCanvas/canvas/elementsRegister.js | 59 +++++++++++++++++ .../canvas/elementsRegister.test.js | 64 ++++++++++++++++++ .../documentCanvas/canvas/wlxmlListener.js | 14 ++-- src/editor/plugins/core/canvasElements.js | 9 +-- 7 files changed, 176 insertions(+), 81 deletions(-) create mode 100644 src/editor/modules/documentCanvas/canvas/elementsRegister.js create mode 100644 src/editor/modules/documentCanvas/canvas/elementsRegister.test.js diff --git a/src/editor/modules/documentCanvas/canvas/canvas.js b/src/editor/modules/documentCanvas/canvas/canvas.js index af1ed28..0ec22a1 100644 --- a/src/editor/modules/documentCanvas/canvas/canvas.js +++ b/src/editor/modules/documentCanvas/canvas/canvas.js @@ -3,13 +3,13 @@ define([ 'libs/underscore', 'libs/backbone', 'fnpjs/logging/logging', -'wlxml/wlxml', 'modules/documentCanvas/canvas/documentElement', 'modules/documentCanvas/canvas/keyboard', 'modules/documentCanvas/canvas/utils', 'modules/documentCanvas/canvas/wlxmlListener', -'modules/documentCanvas/canvas/genericElement' -], function($, _, Backbone, logging, wlxml, documentElement, keyboard, utils, wlxmlListener, genericElement) { +'modules/documentCanvas/canvas/elementsRegister', +'modules/documentCanvas/canvas/genericElement', +], function($, _, Backbone, logging, documentElement, keyboard, utils, wlxmlListener, ElementsRegister, genericElement) { 'use strict'; /* global document:false, window:false, Node:false, gettext */ @@ -56,48 +56,20 @@ $.extend(TextHandler.prototype, { }); -var ElementsRegister = function() { - this._register = { - '': ElementsRegister.createCanvasElementType(genericElement, documentElement.DocumentNodeElement) - }; - -} -_.extend(ElementsRegister, { - createCanvasElementType: function(elementPrototype, inheritFrom) { - var Constructor = function() { - if(!this.super) { - this.super = inheritFrom.prototype; - } - inheritFrom.apply(this, Array.prototype.slice.call(arguments, 0)); - - }; - Constructor.prototype = Object.create(inheritFrom.prototype); - _.extend(Constructor.prototype, elementPrototype); - return Constructor; - } -}); -_.extend(ElementsRegister.prototype, { - register: function(klass, elementPrototype) { - this._register[klass] = ElementsRegister.createCanvasElementType(elementPrototype, this.getFactoryFor('')); - }, - getFactoryFor: function(klass) { - var Factory; - wlxml.getClassHierarchy(klass).reverse().some(function(klass) { - Factory = this._register[klass]; - if(Factory) { - return true; - } - }.bind(this)); - return Factory; - } -}); - - var Canvas = function(wlxmlDocument, elements) { - this.elementsRegister = new ElementsRegister(); - (elements || []).forEach(function(elementDesc) { - this.elementsRegister.register(elementDesc.klass, elementDesc.element); + this.elementsRegister = new ElementsRegister(documentElement.DocumentNodeElement, genericElement); + + elements = [ + {tag: 'section', klass: null, prototype: genericElement}, + {tag: 'div', klass: null, prototype: genericElement}, + {tag: 'header', klass: null, prototype: genericElement}, + {tag: 'span', klass: null, prototype: genericElement}, + {tag: 'aside', klass: null, prototype: genericElement} + ].concat(elements || []); + + (elements).forEach(function(elementDesc) { + this.elementsRegister.register(elementDesc); }.bind(this)); this.eventBus = _.extend({}, Backbone.Events); this.wrapper = $('
').addClass('canvas-wrapper').attr('contenteditable', true); @@ -122,12 +94,9 @@ $.extend(Canvas.prototype, Backbone.Events, { createElement: function(wlxmlNode) { var Factory; if(wlxmlNode.nodeType === Node.TEXT_NODE) { - Factory = documentElement.DocumentTextElement + Factory = documentElement.DocumentTextElement; } else { - if(wlxmlNode.getClass() === 'p') { - // debugger; - } - Factory = this.elementsRegister.getFactoryFor(wlxmlNode.getClass()); + Factory = this.elementsRegister.getElement({tag: wlxmlNode.getTagName(), klass: wlxmlNode.getClass()}); } return new Factory(wlxmlNode, this); }, diff --git a/src/editor/modules/documentCanvas/canvas/canvas.test.js b/src/editor/modules/documentCanvas/canvas/canvas.test.js index 8e3c1c8..9059e3f 100644 --- a/src/editor/modules/documentCanvas/canvas/canvas.test.js +++ b/src/editor/modules/documentCanvas/canvas/canvas.test.js @@ -12,8 +12,8 @@ define([ var expect = chai.expect; -var getCanvasFromXML = function(xml) { - return canvas.fromXMLDocument(getDocumentFromXML(xml), null); +var getCanvasFromXML = function(xml, elements) { + return canvas.fromXMLDocument(getDocumentFromXML(xml), elements); }; var getDocumentFromXML = function(xml) { @@ -35,7 +35,7 @@ describe('wtf', function() { txtNode.wrapWith({tagName: 'header', start: 1, end: 2}); expect(c.doc().children().length).to.equal(3); }); -}) +}); describe('new Canvas', function() { it('abc', function() { @@ -81,7 +81,6 @@ describe('Listening to document changes', function() { b = doc.root.contents()[1], c = canvas.fromXMLDocument(doc); - debugger; a.before(b); var sectionChildren = c.doc().children(); expect(sectionChildren.length).to.equal(2); @@ -229,34 +228,34 @@ describe('Default document changes handling', function() { describe('Custom elements based on wlxml class attribute', function() { it('allows custom rendering', function() { - var c = getCanvasFromXML('
', { - testClass: { + var c = getCanvasFromXML('
', [ + {tag: 'div', klass: 'testClass', prototype: { init: function() { - debugger; - this.dom.append(''); + this._container().append(''); } - } - }); + }, extending: {tag: 'div'}} + ]); + expect(c.doc().children()[0]._container().children('test').length).to.equal(1); // @! }); it('allows handling changes to internal structure of rendered node', function() { - var c = getCanvasFromXML('
', { - testClass: { + var c = getCanvasFromXML('
', [ + {tag: 'div', klass: 'testClass', prototype: { init: function() { this.header = $('

'); - this.dom.append(this.header); + this._container().append(this.header); this.refresh2(); }, refresh2: function() { - this.header.text(this.el.wlxmlNode.contents().length); + this.header.text(this.wlxmlNode.contents().length); }, onNodeAdded: function(event) { void(event); this.refresh2(); } - } - }); + }, extending: {tag: 'div'}} + ]); var node = c.wlxmlDocument.root.contents()[0], element = node.getData('canvasElement'); diff --git a/src/editor/modules/documentCanvas/canvas/documentElement.js b/src/editor/modules/documentCanvas/canvas/documentElement.js index 283f873..7325938 100644 --- a/src/editor/modules/documentCanvas/canvas/documentElement.js +++ b/src/editor/modules/documentCanvas/canvas/documentElement.js @@ -12,7 +12,7 @@ var DocumentElement = function(wlxmlNode, canvas) { this.wlxmlNode = wlxmlNode; this.canvas = canvas; - this.createDOM(); + this.$element = this.createDOM(); this.$element.data('canvas-element', this); }; @@ -80,10 +80,7 @@ $.extend(DocumentElement.prototype, { var DocumentNodeElement = function(wlxmlNode, canvas) { DocumentElement.call(this, wlxmlNode, canvas); wlxmlNode.setData('canvasElement', this); - if(this.init) { - this.init(); - } - + this.init(this.$element); }; @@ -126,8 +123,7 @@ $.extend(DocumentNodeElement.prototype, { wrapper.append(widgetsContainer, contentContainer); widgetsContainer.find('*').add(widgetsContainer).attr('tabindex', -1); - this.$element = wrapper; - this.displayAs(this.defaultDisplayStyle); + return wrapper; }, _container: function() { return this.dom().children('[document-element-content]'); @@ -182,7 +178,7 @@ $.extend(DocumentNodeElement.prototype, { // } // }) this.dom().css('display', what); - this._container().css('display', what); + this._container().css('display', what); } }); @@ -202,9 +198,10 @@ DocumentTextElement.prototype = Object.create(DocumentElement.prototype); $.extend(DocumentTextElement.prototype, { createDOM: function() { - this.$element = $('
') + var dom = $('
') .attr('document-text-element', '') .text(this.wlxmlNode.getText() || utils.unicode.ZWS); + return dom; }, detach: function() { this.dom().detach(); diff --git a/src/editor/modules/documentCanvas/canvas/elementsRegister.js b/src/editor/modules/documentCanvas/canvas/elementsRegister.js new file mode 100644 index 0000000..0d31c7d --- /dev/null +++ b/src/editor/modules/documentCanvas/canvas/elementsRegister.js @@ -0,0 +1,59 @@ +define(function(require) { + +'use strict'; +var _ = require('libs/underscore'), + wlxml = require('wlxml/wlxml'); + + +var ElementsRegister = function(basePrototype, defaultPrototype) { + this._register = {}; + this.basePrototype = basePrototype; + this.DefaultType = this.createCanvasElementType(defaultPrototype); +}; + +_.extend(ElementsRegister.prototype, { + createCanvasElementType: function(elementPrototype, extending) { + var inheritFrom = this.basePrototype; + if(extending && extending.tag) { + inheritFrom = this.getElement(extending); + } + var Constructor = function() { + if(!this.super) { + this.super = inheritFrom.prototype; + } + inheritFrom.apply(this, Array.prototype.slice.call(arguments, 0)); + + }; + Constructor.prototype = Object.create(inheritFrom.prototype); + _.extend(Constructor.prototype, elementPrototype); + return Constructor; + }, + register: function(params) { + params.klass = params.klass || ''; + params.prototype = params.prototype || Object.create({}); + + this._register[params.tag] = this._register[params.tag] || {}; + this._register[params.tag][params.klass] = this.createCanvasElementType(params.prototype, params.extending); + }, + getElement: function(params) { + params.klass = params.klass || ''; + var Factory; + if(this._register[params.tag]) { + wlxml.getClassHierarchy(params.klass).reverse().some(function(klass) { + Factory = this._register[params.tag][klass]; + if(Factory) { + return true; + } + }.bind(this)); + } + if(!Factory) { + Factory = this.DefaultType; + } + return Factory; + } +}); + + +return ElementsRegister; + +}); diff --git a/src/editor/modules/documentCanvas/canvas/elementsRegister.test.js b/src/editor/modules/documentCanvas/canvas/elementsRegister.test.js new file mode 100644 index 0000000..eb7ad89 --- /dev/null +++ b/src/editor/modules/documentCanvas/canvas/elementsRegister.test.js @@ -0,0 +1,64 @@ +define(function(require) { + +'use strict'; +/* globals describe, it */ + + +var ElementsRegister = require('./elementsRegister.js'), + documentElement = require('./documentElement.js'), + chai = require('libs/chai'); + +var expect = chai.expect; + +describe('Elements register', function() { + it('registers element for a tag', function() { + var register = new ElementsRegister(documentElement.DocumentNodeElement), + prototype = {testMethod: function(){}}; + + register.register({ + tag: 'div', + prototype: prototype, + }); + + var Element = register.getElement({tag: 'div'}); + expect(Element.prototype.testMethod).to.equal(prototype.testMethod, '1'); + expect(Element.prototype instanceof documentElement.DocumentNodeElement).to.equal(true, '2'); + }); + it('registers element for a class', function() { + var register = new ElementsRegister(documentElement.DocumentNodeElement), + prototype = {testMethod: function(){}}; + + register.register({ + tag: 'div', + klass: 'a.b', + prototype: prototype, + }); + var Element = register.getElement({tag: 'div', klass: 'a.b.c'}); + expect(Element.prototype.testMethod).to.equal(prototype.testMethod, '1'); + expect(Element.prototype instanceof documentElement.DocumentNodeElement).to.equal(true, '2'); + }); + it('allows inheriting from selected element', function() { + var register = new ElementsRegister(documentElement.DocumentNodeElement), + method1 = function() {}, + method2 = function() {}; + + register.register({ + tag: 'div', + prototype: {method1: method1} + }); + + register.register({ + tag: 'div', + klass: 'a', + prototype: {method2: method2}, + extending: {tag: 'div'} + }); + + var Element = register.getElement({tag: 'div', klass: 'a'}); + expect(Element.prototype.method2).to.equal(method2, '2'); + expect(Element.prototype instanceof register.getElement({tag: 'div'})).to.equal(true, '2'); + }); +}); + + +}); diff --git a/src/editor/modules/documentCanvas/canvas/wlxmlListener.js b/src/editor/modules/documentCanvas/canvas/wlxmlListener.js index faee6c8..e521c97 100644 --- a/src/editor/modules/documentCanvas/canvas/wlxmlListener.js +++ b/src/editor/modules/documentCanvas/canvas/wlxmlListener.js @@ -43,12 +43,18 @@ var _metadataEventHandler = function(event) { var handlers = { nodeAttrChange: function(event) { var element = utils.getElementForNode(event.meta.node), - objectChanged; + newElement; if(event.meta.attr === 'class') { - objectChanged = element.updateObject(); - } + if(element.wlxmlNode.getClass() !== event.meta.attr) { + if(event.meta.node.isRoot()) { + this.canvas.reloadRoot(); + } else { + newElement = this.canvas.createElement(event.meta.node); + element.dom().replaceWith(newElement.dom()); + } + } - if(!objectChanged) { + } else { element.handle(event); } }, diff --git a/src/editor/plugins/core/canvasElements.js b/src/editor/plugins/core/canvasElements.js index 37eefb8..b0f51b6 100644 --- a/src/editor/plugins/core/canvasElements.js +++ b/src/editor/plugins/core/canvasElements.js @@ -1,6 +1,7 @@ define(function(require) { 'use strict'; +var $ = require('libs/jquery'); var widgets = { @@ -49,7 +50,7 @@ var widgets = { }); return mydom; } -} +}; var comment = { @@ -102,12 +103,12 @@ var footnote = { this.trigger('elementToggled', toggle, this.documentElement); } } -} +}; return [ - {klass: 'comment', element: comment}, - {klass: 'footnote', element: footnote} + {tag: 'aside', klass: 'comment', prototype: comment, extending: {tag: 'div'}}, + {tag: 'aside', klass: 'footnote', prototype: footnote, extending: {tag: 'aside'}} ]; -- 2.20.1