From 4d9c547b48e37a64ed2b6423a524bb7b09f2eceb Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Tue, 4 Nov 2014 12:06:35 +0000 Subject: [PATCH 1/6] Adds node and element from Scribe common and removes the Scribe common dependency --- Plumbing.js | 3 +- bower.json | 3 +- package.json | 3 +- src/api/selection.js | 2 +- src/dom-observer.js | 4 +-- src/element.js | 34 +++++++++++++++++++ src/node.js | 23 +++++++++++++ .../formatters/html/enforce-p-elements.js | 2 +- .../html/ensure-selectable-containers.js | 2 +- .../core/patches/commands/insert-html.js | 2 +- .../core/patches/commands/insert-list.js | 4 +-- src/plugins/core/patches/events.js | 2 +- 12 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 src/element.js create mode 100644 src/node.js diff --git a/Plumbing.js b/Plumbing.js index 20ef233a..3d4ca315 100644 --- a/Plumbing.js +++ b/Plumbing.js @@ -16,8 +16,7 @@ module.exports = function (pipelines) { // FIXME: auto? preserveLicenseComments: false, paths: { - 'lodash-amd': '../bower_components/lodash-amd', - 'scribe-common': '../bower_components/scribe-common' + 'lodash-amd': '../bower_components/lodash-amd' } }); diff --git a/bower.json b/bower.json index 9206c74b..9b5a138c 100644 --- a/bower.json +++ b/bower.json @@ -1,8 +1,7 @@ { "name": "scribe", "dependencies": { - "lodash-amd": "2.4.1", - "scribe-common": "0.0.11" + "lodash-amd": "2.4.1" }, "devDependencies": { "requirejs": "~2.1.9", diff --git a/package.json b/package.json index ddf386b6..3f855dc8 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "version": "0.1.25", "main": "src/scribe.js", "dependencies": { - "lodash-amd": "~2.4.1", - "scribe-common": "~0.0.11" + "lodash-amd": "~2.4.1" }, "devDependencies": { "chai": "~1.9.1", diff --git a/src/api/selection.js b/src/api/selection.js index 6a32c551..56ee3b71 100644 --- a/src/api/selection.js +++ b/src/api/selection.js @@ -1,5 +1,5 @@ define([ - 'scribe-common/src/element' + '../element' ], function (elementHelper) { diff --git a/src/dom-observer.js b/src/dom-observer.js index 49c3f2aa..b3528de7 100644 --- a/src/dom-observer.js +++ b/src/dom-observer.js @@ -1,8 +1,8 @@ define([ 'lodash-amd/modern/arrays/flatten', 'lodash-amd/modern/collections/toArray', - 'scribe-common/src/element', - 'scribe-common/src/node' + './element', + './node' ], function ( flatten, toArray, diff --git a/src/element.js b/src/element.js new file mode 100644 index 00000000..e84fc9b7 --- /dev/null +++ b/src/element.js @@ -0,0 +1,34 @@ +define(['lodash-amd/modern/collections/contains'], function (contains) { + + 'use strict'; + + // TODO: not exhaustive? + var blockElementNames = ['P', 'LI', 'DIV', 'BLOCKQUOTE', 'UL', 'OL', 'H1', + 'H2', 'H3', 'H4', 'H5', 'H6', 'TABLE', 'TH', 'TD']; + function isBlockElement(node) { + return contains(blockElementNames, node.nodeName); + } + + function isSelectionMarkerNode(node) { + return (node.nodeType === Node.ELEMENT_NODE && node.className === 'scribe-marker'); + } + + function isCaretPositionNode(node) { + return (node.nodeType === Node.ELEMENT_NODE && node.className === 'caret-position'); + } + + function unwrap(node, childNode) { + while (childNode.childNodes.length > 0) { + node.insertBefore(childNode.childNodes[0], childNode); + } + node.removeChild(childNode); + } + + return { + isBlockElement: isBlockElement, + isSelectionMarkerNode: isSelectionMarkerNode, + isCaretPositionNode: isCaretPositionNode, + unwrap: unwrap + }; + +}); diff --git a/src/node.js b/src/node.js new file mode 100644 index 00000000..a562b6e5 --- /dev/null +++ b/src/node.js @@ -0,0 +1,23 @@ +define([], function () { + + 'use strict'; + + function isEmptyTextNode(node) { + return (node.nodeType === Node.TEXT_NODE && node.textContent === ''); + } + + function insertAfter(newNode, referenceNode) { + return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); + } + + function removeNode(node) { + return node.parentNode.removeChild(node); + } + + return { + isEmptyTextNode: isEmptyTextNode, + insertAfter: insertAfter, + removeNode: removeNode + }; + +}); diff --git a/src/plugins/core/formatters/html/enforce-p-elements.js b/src/plugins/core/formatters/html/enforce-p-elements.js index 809fc745..561e4501 100644 --- a/src/plugins/core/formatters/html/enforce-p-elements.js +++ b/src/plugins/core/formatters/html/enforce-p-elements.js @@ -1,6 +1,6 @@ define([ 'lodash-amd/modern/arrays/last', - 'scribe-common/src/element' + '../../../../element' ], function ( last, element diff --git a/src/plugins/core/formatters/html/ensure-selectable-containers.js b/src/plugins/core/formatters/html/ensure-selectable-containers.js index 6a64cef2..946b8bbf 100644 --- a/src/plugins/core/formatters/html/ensure-selectable-containers.js +++ b/src/plugins/core/formatters/html/ensure-selectable-containers.js @@ -1,5 +1,5 @@ define([ - 'scribe-common/src/element', + '../../../../element', 'lodash-amd/modern/collections/contains' ], function ( element, diff --git a/src/plugins/core/patches/commands/insert-html.js b/src/plugins/core/patches/commands/insert-html.js index 3bd4d93b..94d5421e 100644 --- a/src/plugins/core/patches/commands/insert-html.js +++ b/src/plugins/core/patches/commands/insert-html.js @@ -1,4 +1,4 @@ -define(['scribe-common/src/element'], function (element) { +define(['../../../../element'], function (element) { 'use strict'; diff --git a/src/plugins/core/patches/commands/insert-list.js b/src/plugins/core/patches/commands/insert-list.js index b37a57b5..6b475cab 100644 --- a/src/plugins/core/patches/commands/insert-list.js +++ b/src/plugins/core/patches/commands/insert-list.js @@ -1,5 +1,5 @@ -define(['scribe-common/src/element', - 'scribe-common/src/node'], function (element, nodeHelpers) { +define(['../../../../element', + '../../../../node'], function (element, nodeHelpers) { 'use strict'; diff --git a/src/plugins/core/patches/events.js b/src/plugins/core/patches/events.js index 465ddd0b..28ca374e 100644 --- a/src/plugins/core/patches/events.js +++ b/src/plugins/core/patches/events.js @@ -1,4 +1,4 @@ -define(['scribe-common/src/element'], function (element) { +define(['../../../element'], function (element) { 'use strict'; From a79b7fc248f1b2f136408aa76e4fe9d299a38554 Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Wed, 5 Nov 2014 16:57:31 +0000 Subject: [PATCH 2/6] Ports one of the formatters to the new api idea --- .../formatters/html/enforce-p-elements.js | 24 +++++++++---------- src/scribe.js | 11 +++++++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/plugins/core/formatters/html/enforce-p-elements.js b/src/plugins/core/formatters/html/enforce-p-elements.js index 561e4501..a73c879c 100644 --- a/src/plugins/core/formatters/html/enforce-p-elements.js +++ b/src/plugins/core/formatters/html/enforce-p-elements.js @@ -1,9 +1,7 @@ define([ - 'lodash-amd/modern/arrays/last', - '../../../../element' + 'lodash-amd/modern/arrays/last' ], function ( - last, - element + last ) { /** @@ -26,15 +24,15 @@ define([ /** * Wrap consecutive inline elements and text nodes in a P element. */ - function wrapChildNodes(parentNode) { + function wrapChildNodes(scribe, parentNode) { var groups = Array.prototype.reduce.call(parentNode.childNodes, function (accumulator, binChildNode) { var group = last(accumulator); if (! group) { startNewGroup(); } else { - var isBlockGroup = element.isBlockElement(group[0]); - if (isBlockGroup === element.isBlockElement(binChildNode)) { + var isBlockGroup = scribe.elementHelpers.isBlockElement(group[0]); + if (isBlockGroup === scribe.elementHelpers.isBlockElement(binChildNode)) { group.push(binChildNode); } else { startNewGroup(); @@ -50,7 +48,7 @@ define([ }, []); var consecutiveInlineElementsAndTextNodes = groups.filter(function (group) { - var isBlockGroup = element.isBlockElement(group[0]); + var isBlockGroup = scribe.elementHelpers.isBlockElement(group[0]); return ! isBlockGroup; }); @@ -66,7 +64,7 @@ define([ } // Traverse the tree, wrapping child nodes as we go. - function traverse(parentNode) { + function traverse(scribe, parentNode) { var treeWalker = document.createTreeWalker(parentNode, NodeFilter.SHOW_ELEMENT); var node = treeWalker.firstChild(); @@ -76,8 +74,8 @@ define([ // TODO: At the moment we only support BLOCKQUOTEs. See failing // tests. if (node.nodeName === 'BLOCKQUOTE' && ! node._isWrapped) { - wrapChildNodes(node); - traverse(parentNode); + wrapChildNodes(scribe, node); + traverse(scribe, parentNode); break; } node = treeWalker.nextSibling(); @@ -100,8 +98,8 @@ define([ var bin = document.createElement('div'); bin.innerHTML = html; - wrapChildNodes(bin); - traverse(bin); + wrapChildNodes(scribe, bin); + traverse(scribe, bin); return bin.innerHTML; }); diff --git a/src/scribe.js b/src/scribe.js index 6608df5a..9abeb99f 100644 --- a/src/scribe.js +++ b/src/scribe.js @@ -13,7 +13,9 @@ define([ './api', './transaction-manager', './undo-manager', - './event-emitter' + './event-emitter', + './element', + './node' ], function ( defaults, flatten, @@ -29,7 +31,9 @@ define([ Api, buildTransactionManager, buildUndoManager, - EventEmitter + EventEmitter, + elementHelpers, + nodeHelpers ) { 'use strict'; @@ -49,6 +53,9 @@ define([ this.api = new Api(this); + this.nodeHelpers = nodeHelpers; + this.elementHelpers = elementHelpers; + var TransactionManager = buildTransactionManager(this); this.transactionManager = new TransactionManager(); From 08fbe84b15d3431310c864c7593e8f65403b8199 Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Wed, 5 Nov 2014 17:06:26 +0000 Subject: [PATCH 3/6] Ports command to new Scribe api --- src/plugins/core/patches/commands/insert-html.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/core/patches/commands/insert-html.js b/src/plugins/core/patches/commands/insert-html.js index 94d5421e..9e629bb9 100644 --- a/src/plugins/core/patches/commands/insert-html.js +++ b/src/plugins/core/patches/commands/insert-html.js @@ -1,10 +1,11 @@ -define(['../../../../element'], function (element) { +define([], function () { 'use strict'; return function () { return function (scribe) { var insertHTMLCommandPatch = new scribe.api.CommandPatch('insertHTML'); + var element = scribe.elementHelpers; insertHTMLCommandPatch.execute = function (value) { scribe.transactionManager.run(function () { From 771d2b1e804aaf9077bc58983a0400e12a189ca8 Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Wed, 5 Nov 2014 17:10:20 +0000 Subject: [PATCH 4/6] More ports --- src/plugins/core/patches/commands/insert-list.js | 6 ++++-- src/plugins/core/patches/events.js | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/core/patches/commands/insert-list.js b/src/plugins/core/patches/commands/insert-list.js index 6b475cab..94753d41 100644 --- a/src/plugins/core/patches/commands/insert-list.js +++ b/src/plugins/core/patches/commands/insert-list.js @@ -1,10 +1,12 @@ -define(['../../../../element', - '../../../../node'], function (element, nodeHelpers) { +define([], function () { 'use strict'; return function () { return function (scribe) { + var element = scribe.elementHelpers; + var nodeHelpers = scribe.nodeHelpers; + var InsertListCommandPatch = function (commandName) { scribe.api.CommandPatch.call(this, commandName); }; diff --git a/src/plugins/core/patches/events.js b/src/plugins/core/patches/events.js index 28ca374e..749ff212 100644 --- a/src/plugins/core/patches/events.js +++ b/src/plugins/core/patches/events.js @@ -1,4 +1,4 @@ -define(['../../../element'], function (element) { +define([], function () { 'use strict'; @@ -21,6 +21,9 @@ define(['../../../element'], function (element) { // TODO: run in a transaction so as to record the change? how do // we know in advance whether there will be a change though? // TODO: share somehow with `InsertList` command + + var element = scribe.elementHelpers; + if (scribe.allowsBlockElements()) { scribe.el.addEventListener('keyup', function (event) { if (event.keyCode === 8 || event.keyCode === 46) { // backspace or delete From 7d7fd432543215fb205958476267dcc97a83666e Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Wed, 5 Nov 2014 18:03:50 +0000 Subject: [PATCH 5/6] Performs the final hack to migrate the plugins --- .../formatters/html/ensure-selectable-containers.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/core/formatters/html/ensure-selectable-containers.js b/src/plugins/core/formatters/html/ensure-selectable-containers.js index 946b8bbf..f5d12db5 100644 --- a/src/plugins/core/formatters/html/ensure-selectable-containers.js +++ b/src/plugins/core/formatters/html/ensure-selectable-containers.js @@ -17,7 +17,7 @@ define([ // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements var html5VoidElements = ['AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR']; - function parentHasNoTextContent(node) { + function parentHasNoTextContent(element, node) { if (element.isCaretPositionNode(node)) { return true; } else { @@ -26,7 +26,7 @@ define([ } - function traverse(parentNode) { + function traverse(element, parentNode) { // Instead of TreeWalker, which gets confused when the BR is added to the dom, // we recursively traverse the tree to look for an empty node that can have childNodes @@ -41,7 +41,7 @@ define([ // Do not insert BR in empty non block elements with parent containing text if (!element.isBlockElement(node) && node.children.length === 0) { - return parentHasNoTextContent(node); + return parentHasNoTextContent(element, node); } return false; @@ -56,7 +56,7 @@ define([ !contains(html5VoidElements, node.nodeName)) { node.appendChild(document.createElement('br')); } else if (node.children.length > 0) { - traverse(node); + traverse(element, node); } } node = node.nextElementSibling; @@ -70,7 +70,7 @@ define([ var bin = document.createElement('div'); bin.innerHTML = html; - traverse(bin); + traverse(scribe.elementHelpers, bin); return bin.innerHTML; }); From 234cf75595943ce041c1e57e15e87e3e23413dbd Mon Sep 17 00:00:00 2001 From: Robert Rees Date: Thu, 6 Nov 2014 10:16:38 +0000 Subject: [PATCH 6/6] Renames the expose api roots as "helpers" is weak sauce and the plugins used element almost exclusively --- src/plugins/core/formatters/html/enforce-p-elements.js | 6 +++--- .../core/formatters/html/ensure-selectable-containers.js | 2 +- src/plugins/core/patches/commands/insert-html.js | 2 +- src/plugins/core/patches/commands/insert-list.js | 4 ++-- src/plugins/core/patches/events.js | 4 ++-- src/scribe.js | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/plugins/core/formatters/html/enforce-p-elements.js b/src/plugins/core/formatters/html/enforce-p-elements.js index a73c879c..891f2418 100644 --- a/src/plugins/core/formatters/html/enforce-p-elements.js +++ b/src/plugins/core/formatters/html/enforce-p-elements.js @@ -31,8 +31,8 @@ define([ if (! group) { startNewGroup(); } else { - var isBlockGroup = scribe.elementHelpers.isBlockElement(group[0]); - if (isBlockGroup === scribe.elementHelpers.isBlockElement(binChildNode)) { + var isBlockGroup = scribe.element.isBlockElement(group[0]); + if (isBlockGroup === scribe.element.isBlockElement(binChildNode)) { group.push(binChildNode); } else { startNewGroup(); @@ -48,7 +48,7 @@ define([ }, []); var consecutiveInlineElementsAndTextNodes = groups.filter(function (group) { - var isBlockGroup = scribe.elementHelpers.isBlockElement(group[0]); + var isBlockGroup = scribe.element.isBlockElement(group[0]); return ! isBlockGroup; }); diff --git a/src/plugins/core/formatters/html/ensure-selectable-containers.js b/src/plugins/core/formatters/html/ensure-selectable-containers.js index f5d12db5..7b486079 100644 --- a/src/plugins/core/formatters/html/ensure-selectable-containers.js +++ b/src/plugins/core/formatters/html/ensure-selectable-containers.js @@ -70,7 +70,7 @@ define([ var bin = document.createElement('div'); bin.innerHTML = html; - traverse(scribe.elementHelpers, bin); + traverse(scribe.element, bin); return bin.innerHTML; }); diff --git a/src/plugins/core/patches/commands/insert-html.js b/src/plugins/core/patches/commands/insert-html.js index 9e629bb9..707585ef 100644 --- a/src/plugins/core/patches/commands/insert-html.js +++ b/src/plugins/core/patches/commands/insert-html.js @@ -5,7 +5,7 @@ define([], function () { return function () { return function (scribe) { var insertHTMLCommandPatch = new scribe.api.CommandPatch('insertHTML'); - var element = scribe.elementHelpers; + var element = scribe.element; insertHTMLCommandPatch.execute = function (value) { scribe.transactionManager.run(function () { diff --git a/src/plugins/core/patches/commands/insert-list.js b/src/plugins/core/patches/commands/insert-list.js index 94753d41..bd037aae 100644 --- a/src/plugins/core/patches/commands/insert-list.js +++ b/src/plugins/core/patches/commands/insert-list.js @@ -4,8 +4,8 @@ define([], function () { return function () { return function (scribe) { - var element = scribe.elementHelpers; - var nodeHelpers = scribe.nodeHelpers; + var element = scribe.element; + var nodeHelpers = scribe.node; var InsertListCommandPatch = function (commandName) { scribe.api.CommandPatch.call(this, commandName); diff --git a/src/plugins/core/patches/events.js b/src/plugins/core/patches/events.js index 749ff212..f09b7035 100644 --- a/src/plugins/core/patches/events.js +++ b/src/plugins/core/patches/events.js @@ -22,8 +22,8 @@ define([], function () { // we know in advance whether there will be a change though? // TODO: share somehow with `InsertList` command - var element = scribe.elementHelpers; - + var element = scribe.element; + if (scribe.allowsBlockElements()) { scribe.el.addEventListener('keyup', function (event) { if (event.keyCode === 8 || event.keyCode === 46) { // backspace or delete diff --git a/src/scribe.js b/src/scribe.js index 9abeb99f..26b8f9a8 100644 --- a/src/scribe.js +++ b/src/scribe.js @@ -53,8 +53,8 @@ define([ this.api = new Api(this); - this.nodeHelpers = nodeHelpers; - this.elementHelpers = elementHelpers; + this.node = nodeHelpers; + this.element = elementHelpers; var TransactionManager = buildTransactionManager(this); this.transactionManager = new TransactionManager();