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..891f2418 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', - 'scribe-common/src/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.element.isBlockElement(group[0]); + if (isBlockGroup === scribe.element.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.element.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/plugins/core/formatters/html/ensure-selectable-containers.js b/src/plugins/core/formatters/html/ensure-selectable-containers.js index 6a64cef2..7b486079 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, @@ -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.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 3bd4d93b..707585ef 100644 --- a/src/plugins/core/patches/commands/insert-html.js +++ b/src/plugins/core/patches/commands/insert-html.js @@ -1,10 +1,11 @@ -define(['scribe-common/src/element'], function (element) { +define([], function () { 'use strict'; return function () { return function (scribe) { var insertHTMLCommandPatch = new scribe.api.CommandPatch('insertHTML'); + 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 b37a57b5..bd037aae 100644 --- a/src/plugins/core/patches/commands/insert-list.js +++ b/src/plugins/core/patches/commands/insert-list.js @@ -1,10 +1,12 @@ -define(['scribe-common/src/element', - 'scribe-common/src/node'], function (element, nodeHelpers) { +define([], function () { 'use strict'; return function () { return function (scribe) { + 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 465ddd0b..f09b7035 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([], function () { 'use strict'; @@ -21,6 +21,9 @@ define(['scribe-common/src/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.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 6608df5a..26b8f9a8 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.node = nodeHelpers; + this.element = elementHelpers; + var TransactionManager = buildTransactionManager(this); this.transactionManager = new TransactionManager();