From f098ff9873de73d1fd6d71ce64b83ae318e8bd7e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Aleksander=20=C5=81ukasz?= Date: Tue, 22 Apr 2014 16:04:20 +0200 Subject: [PATCH] editor: new rules for backspace/delete --- .../modules/documentCanvas/canvas/keyboard.js | 4 +- src/editor/plugins/core/core.js | 34 +++++-- src/editor/plugins/core/core.test.js | 97 ++++++++----------- 3 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/editor/modules/documentCanvas/canvas/keyboard.js b/src/editor/modules/documentCanvas/canvas/keyboard.js index fc8be1e..4cf3d77 100644 --- a/src/editor/modules/documentCanvas/canvas/keyboard.js +++ b/src/editor/modules/documentCanvas/canvas/keyboard.js @@ -298,7 +298,9 @@ handlers.push({keys: [KEYS.BACKSPACE, KEYS.DELETE], } if(element) { goto = element.wlxmlNode.mergeContentUp(); - canvas.setCurrentElement(goto.node, {caretTo: goto.offset}); + if(goto) { + canvas.setCurrentElement(goto.node, {caretTo: goto.offset}); + } } event.preventDefault(); } diff --git a/src/editor/plugins/core/core.js b/src/editor/plugins/core/core.js index a780227..b678ca3 100644 --- a/src/editor/plugins/core/core.js +++ b/src/editor/plugins/core/core.js @@ -31,15 +31,37 @@ plugin.documentExtension.textNode.transformations = { } }, mergeContentUp: function() { - var myPrev = this.prev(), + /* globals Node */ + var myPrev = this, + base = this, ret; - if(myPrev) { - ret = myPrev.append(this); + if(myPrev.nodeType === Node.TEXT_NODE) { + if(myPrev.getIndex() > 0) { + return; + } + myPrev = base = myPrev.parent(); + } + + myPrev = myPrev && myPrev.prev(); + + if(myPrev && myPrev.nodeType === Node.ELEMENT_NODE) { + var ptr = this, + next; + while(ptr) { + next = ptr.next(); + if(!ret) { + ret = myPrev.append(ptr); + } else { + myPrev.append(ptr); + } + + ptr = next; + } + if(base !== this) { + base.detach(); + } return {node: ret, offset: ret.sameNode(this) ? null : ret.getText().length - this.getText().length}; - } else { - var range = this.parent().unwrapContent(); - return {node: range.element1, offset: 0}; } } }; diff --git a/src/editor/plugins/core/core.test.js b/src/editor/plugins/core/core.test.js index 0ed38eb..ed61328 100644 --- a/src/editor/plugins/core/core.test.js +++ b/src/editor/plugins/core/core.test.js @@ -4,6 +4,7 @@ define(function(require) { /* globals describe, it */ var chai = require('libs/chai'), + sinon = require('libs/sinon'), wlxml = require('wlxml/wlxml'), corePlugin = require('./core.js'), expect = chai.expect; @@ -88,65 +89,47 @@ describe('Document extensions', function() { }); }); - describe('merging with adjacent content', function() { + describe('mergin text with preceding content', function() { + it('does nothing if text node parent has no preceding element', function() { + var doc = getDocumentFromXML('
some text
'), + text = getTextNode('some text', doc), + spy = sinon.spy(); - describe('when text preceded by element', function() { - describe('when text followed by element', function() { - it('appends text to the preceding element, following elements stays in place', function() { - var doc = getDocumentFromXML('
AtextB
'), - text = getTextNode('text', doc); - - text.mergeContentUp(); - var contents = doc.root.contents(); - - expect(contents.length).to.equal(2); - expect(contents[0].getTagName()).to.equal('a'); - expect(contents[0].contents()[0].getText()).to.equal('Atext'); - expect(contents[1].getTagName()).to.equal('b'); - }); - }); - describe('when text is a last child', function() { - it('appends text to the preceding element', function() { - var doc = getDocumentFromXML('
Atext
'), - text = getTextNode('text', doc); - - text.mergeContentUp(); - var contents = doc.root.contents(); - - expect(contents.length).to.equal(1); - expect(contents[0].getTagName()).to.equal('a'); - expect(contents[0].contents()[0].getText()).to.equal('Atext'); - }); - }); - }); + doc.on('change', spy); + text.mergeContentUp(); + expect(spy.callCount).to.equal(0); + }); + it('does nothing if text node parent is precedeed by text node', function() { + var doc = getDocumentFromXML('
another text
some text
'), + text = getTextNode('some text', doc), + spy = sinon.spy(); + + doc.on('change', spy); + text.mergeContentUp(); + expect(spy.callCount).to.equal(0); + }); + it('does nothing if text node is not first child of its parent', function() { + var doc = getDocumentFromXML('
some text
'), + text = getTextNode('some text', doc), + spy = sinon.spy(); - describe('when text is a first child', function() { - describe('when text followed by element', function() { - it('appends text and its siblings to the parent preceding element', function() { - var doc = getDocumentFromXML('
B
textA
'), - text = getTextNode('text', doc); - - text.mergeContentUp(); - var contents = doc.root.contents(); - - expect(contents.length).to.equal(3); - expect(contents[0].getTagName()).to.equal('b'); - expect(contents[1].getText()).to.equal('text'); - expect(contents[2].getTagName()).to.equal('a'); - }); - it('appends text and its siblings after the parent preceding text', function() { - var doc = getDocumentFromXML('
B
textA
'), - text = getTextNode('text', doc); - - text.mergeContentUp(); - var contents = doc.root.contents(); - - expect(contents.length).to.equal(2); - expect(contents[0].getText()).to.equal('Btext'); - expect(contents[1].getTagName()).to.equal('a'); - }); - }); - }); + doc.on('change', spy); + text.mergeContentUp(); + expect(spy.callCount).to.equal(0); + }); + it('moves text node and its siblings to the block element preceding text node parent', function() { + var doc = getDocumentFromXML('
some textis here!
'), + text = getTextNode('some text', doc); + + text.mergeContentUp(); + + var contents = doc.root.contents(); + expect(contents.length).to.equal(1); + expect(contents[0].contents().length).to.equal(3); + expect(contents[0].contents()[0].getText()).to.equal('some text'); + expect(contents[0].contents()[1].getTagName()).to.equal('span'); + expect(contents[0].contents()[2].getText()).to.equal(' here!'); + }); }); }); -- 2.20.1