From 7812b8db2348af48a935b9f57103bee7fbd1e697 Mon Sep 17 00:00:00 2001 From: Neil Jenkins Date: Thu, 20 Jun 2013 21:03:01 +1000 Subject: [PATCH] Turn Range prototype extensions into functions. A step towards being able to share code between multiple concurrent instances of the editor. Also reduces minified size slightly. --- build/squire-raw.js | 260 ++++++++++++++++++++++---------------------- build/squire.js | 2 +- source/Editor.js | 79 ++++++++------ source/Range.js | 181 ++++++++++++++---------------- 4 files changed, 263 insertions(+), 259 deletions(-) diff --git a/build/squire-raw.js b/build/squire-raw.js index e96754d..d9384ef 100644 --- a/build/squire-raw.js +++ b/build/squire-raw.js @@ -580,9 +580,7 @@ if ( function () { fixCursor, split, mergeWithBlock, - mergeContainers, - - Range + mergeContainers */ /*jshint strict:false */ @@ -611,11 +609,11 @@ var getNodeAfter = function ( node, offset ) { return node; }; -var RangePrototype = Range.prototype; +// --- -RangePrototype.forEachTextNode = function ( fn ) { - var range = this.cloneRange(); - range.moveBoundariesDownTree(); +var forEachTextNodeInRange = function ( range, fn ) { + range = range.cloneRange(); + moveRangeBoundariesDownTree( range ); var startContainer = range.startContainer, endContainer = range.endContainer, @@ -631,9 +629,9 @@ RangePrototype.forEachTextNode = function ( fn ) { ( textnode = walker.nextNode() ) ) {} }; -RangePrototype.getTextContent = function () { +var getTextContentInRange = function ( range ) { var textContent = ''; - this.forEachTextNode( function ( textnode, range ) { + forEachTextNodeInRange( range, function ( textnode, range ) { var value = textnode.data; if ( value && ( /\S/.test( value ) ) ) { if ( textnode === range.endContainer ) { @@ -650,12 +648,12 @@ RangePrototype.getTextContent = function () { // --- -RangePrototype._insertNode = function ( node ) { +var insertNodeInRange = function ( range, node ) { // Insert at start. - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, parent, children, childCount, afterSplit; // If part way through a text node, split it. @@ -664,7 +662,7 @@ RangePrototype._insertNode = function ( node ) { children = parent.childNodes; if ( startOffset === startContainer.length ) { startOffset = indexOf.call( children, startContainer ) + 1; - if ( this.collapsed ) { + if ( range.collapsed ) { endContainer = parent; endOffset = startOffset; } @@ -698,20 +696,18 @@ RangePrototype._insertNode = function ( node ) { endOffset += children.length - childCount; } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - - return this; + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); }; -RangePrototype._extractContents = function ( common ) { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset; +var extractContentsOfRange = function ( range, common ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset; if ( !common ) { - common = this.commonAncestorContainer; + common = range.commonAncestorContainer; } if ( common.nodeType === TEXT_NODE ) { @@ -730,28 +726,28 @@ RangePrototype._extractContents = function ( common ) { startNode = next; } - this.setStart( common, endNode ? + range.setStart( common, endNode ? indexOf.call( common.childNodes, endNode ) : common.childNodes.length ); - this.collapse( true ); + range.collapse( true ); fixCursor( common ); return frag; }; -RangePrototype._deleteContents = function () { +var deleteContentsOfRange = function ( range ) { // Move boundaries up as much as possible to reduce need to split. - this.moveBoundariesUpTree(); + moveRangeBoundariesUpTree( range ); // Remove selected range - this._extractContents(); + extractContentsOfRange( range ); // If we split into two different blocks, merge the blocks. - var startBlock = this.getStartBlock(), - endBlock = this.getEndBlock(); + var startBlock = getStartBlockOfRange( range ), + endBlock = getEndBlockOfRange( range ); if ( startBlock && endBlock && startBlock !== endBlock ) { - mergeWithBlock( startBlock, endBlock, this ); + mergeWithBlock( startBlock, endBlock, range ); } // Ensure block has necessary children @@ -760,27 +756,25 @@ RangePrototype._deleteContents = function () { } // Ensure body has a block-level element in it. - var body = this.endContainer.ownerDocument.body, + var body = range.endContainer.ownerDocument.body, child = body.firstChild; if ( !child || child.nodeName === 'BR' ) { fixCursor( body ); - this.selectNodeContents( body.firstChild ); + range.selectNodeContents( body.firstChild ); } // Ensure valid range (must have only block or inline containers) - var isCollapsed = this.collapsed; - this.moveBoundariesDownTree(); + var isCollapsed = range.collapsed; + moveRangeBoundariesDownTree( range ); if ( isCollapsed ) { // Collapse - this.collapse( true ); + range.collapse( true ); } - - return this; }; // --- -RangePrototype.insertTreeFragment = function ( frag ) { +var insertTreeFragmentIntoRange = function ( range, frag ) { // Check if it's all inline content var allInline = true, children = frag.childNodes, @@ -793,23 +787,23 @@ RangePrototype.insertTreeFragment = function ( frag ) { } // Delete any selected content - if ( !this.collapsed ) { - this._deleteContents(); + if ( !range.collapsed ) { + deleteContentsOfRange( range ); } // Move range down into text ndoes - this.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); // If inline, just insert at the current position. if ( allInline ) { - this._insertNode( frag ); - this.collapse( false ); + insertNodeInRange( range, frag ); + range.collapse( false ); } // Otherwise, split up to body, insert inline before and after split // and insert block in between split, then merge containers. else { - var nodeAfterSplit = split( this.startContainer, this.startOffset, - this.startContainer.ownerDocument.body ), + var nodeAfterSplit = split( range.startContainer, range.startOffset, + range.startContainer.ownerDocument.body ), nodeBeforeSplit = nodeAfterSplit.previousSibling, startContainer = nodeBeforeSplit, startOffset = startContainer.childNodes.length, @@ -865,17 +859,16 @@ RangePrototype.insertTreeFragment = function ( frag ) { mergeContainers( nodeBeforeSplit ); } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - this.moveBoundariesDownTree(); + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); + moveRangeBoundariesDownTree( range ); } }; // --- -RangePrototype.containsNode = function ( node, partial ) { - var range = this, - nodeRange = node.ownerDocument.createRange(); +var isNodeContainedInRange = function ( range, node, partial ) { + var nodeRange = node.ownerDocument.createRange(); nodeRange.selectNode( node ); @@ -899,11 +892,11 @@ RangePrototype.containsNode = function ( node, partial ) { } }; -RangePrototype.moveBoundariesDownTree = function () { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, +var moveRangeBoundariesDownTree = function ( range ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, child; while ( startContainer.nodeType !== TEXT_NODE ) { @@ -936,26 +929,24 @@ RangePrototype.moveBoundariesDownTree = function () { // If collapsed, this algorithm finds the nearest text node positions // *outside* the range rather than inside, but also it flips which is // assigned to which. - if ( this.collapsed ) { - this.setStart( endContainer, endOffset ); - this.setEnd( startContainer, startOffset ); + if ( range.collapsed ) { + range.setStart( endContainer, endOffset ); + range.setEnd( startContainer, startOffset ); } else { - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); } - - return this; }; -RangePrototype.moveBoundariesUpTree = function ( common ) { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, +var moveRangeBoundariesUpTree = function ( range, common ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, parent; if ( !common ) { - common = this.commonAncestorContainer; + common = range.commonAncestorContainer; } while ( startContainer !== common && !startOffset ) { @@ -971,16 +962,14 @@ RangePrototype.moveBoundariesUpTree = function ( common ) { endContainer = parent; } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - - return this; + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); }; // Returns the first block at least partially contained by the range, // or null if no block is contained by the range. -RangePrototype.getStartBlock = function () { - var container = this.startContainer, +var getStartBlockOfRange = function ( range ) { + var container = range.startContainer, block; // If inline, get the containing block. @@ -989,17 +978,17 @@ RangePrototype.getStartBlock = function () { } else if ( isBlock( container ) ) { block = container; } else { - block = getNodeBefore( container, this.startOffset ); + block = getNodeBefore( container, range.startOffset ); block = getNextBlock( block ); } // Check the block actually intersects the range - return block && this.containsNode( block, true ) ? block : null; + return block && isNodeContainedInRange( range, block, true ) ? block : null; }; // Returns the last block at least partially contained by the range, // or null if no block is contained by the range. -RangePrototype.getEndBlock = function () { - var container = this.endContainer, +var getEndBlockOfRange = function ( range ) { + var container = range.endContainer, block, child; // If inline, get the containing block. @@ -1008,7 +997,7 @@ RangePrototype.getEndBlock = function () { } else if ( isBlock( container ) ) { block = container; } else { - block = getNodeAfter( container, this.endOffset ); + block = getNodeAfter( container, range.endOffset ); if ( !block ) { block = container.ownerDocument.body; while ( child = block.lastChild ) { @@ -1019,12 +1008,12 @@ RangePrototype.getEndBlock = function () { } // Check the block actually intersects the range - return block && this.containsNode( block, true ) ? block : null; + return block && isNodeContainedInRange( range, block, true ) ? block : null; }; -RangePrototype.startsAtBlockBoundary = function () { - var startContainer = this.startContainer, - startOffset = this.startOffset, +var rangeDoesStartAtBlockBoundary = function ( range ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, parent, child; while ( isInline( startContainer ) ) { @@ -1044,9 +1033,9 @@ RangePrototype.startsAtBlockBoundary = function () { return !startOffset; }; -RangePrototype.endsAtBlockBoundary = function () { - var endContainer = this.endContainer, - endOffset = this.endOffset, +var rangeDoesEndAtBlockBoundary = function ( range ) { + var endContainer = range.endContainer, + endOffset = range.endOffset, length = getLength( endContainer ), parent, child; @@ -1068,19 +1057,17 @@ RangePrototype.endsAtBlockBoundary = function () { return endOffset === length; }; -RangePrototype.expandToBlockBoundaries = function () { - var start = this.getStartBlock(), - end = this.getEndBlock(), +var expandRangeToBlockBoundaries = function ( range ) { + var start = getStartBlockOfRange( range ), + end = getEndBlockOfRange( range ), parent; if ( start && end ) { parent = start.parentNode; - this.setStart( parent, indexOf.call( parent.childNodes, start ) ); + range.setStart( parent, indexOf.call( parent.childNodes, start ) ); parent = end.parentNode; - this.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 ); + range.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 ); } - - return this; }; /*global DOCUMENT_POSITION_PRECEDING, @@ -1128,6 +1115,21 @@ RangePrototype.expandToBlockBoundaries = function () { mergeContainers, createElement, + forEachTextNodeInRange, + getTextContentInRange, + insertNodeInRange, + extractContentsOfRange, + deleteContentsOfRange, + insertTreeFragmentIntoRange, + isNodeContainedInRange, + moveRangeBoundariesDownTree, + moveRangeBoundariesUpTree, + getStartBlockOfRange, + getEndBlockOfRange, + rangeDoesStartAtBlockBoundary, + rangeDoesEndAtBlockBoundary, + expandRangeToBlockBoundaries, + Range, top, console, @@ -1405,11 +1407,11 @@ var insertElement = function ( el, range ) { if ( !range ) { range = getSelection(); } range.collapse( true ); if ( isInline( el ) ) { - range._insertNode( el ); + insertNodeInRange( range, el ); range.setStartAfter( el ); } else { // Get containing block node. - var splitNode = range.getStartBlock() || body, + var splitNode = getStartBlockOfRange( range ) || body, parent, nodeAfterSplit; // While at end of container node, move up DOM tree. while ( splitNode !== body && !splitNode.nextSibling ) { @@ -1424,7 +1426,7 @@ var insertElement = function ( el, range ) { body.insertBefore( el, nodeAfterSplit ); range.setStart( nodeAfterSplit, 0 ); range.setStart( nodeAfterSplit, 0 ); - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); } else { body.appendChild( el ); // Insert blank line below block. @@ -1454,9 +1456,9 @@ var saveRangeToBookmark = function ( range ) { }), temp; - range._insertNode( startNode ); + insertNodeInRange( range, startNode ); range.collapse( false ); - range._insertNode( endNode ); + insertNodeInRange( range, endNode ); // In a collapsed range, the start is sometimes inserted after the end! if ( startNode.compareDocumentPosition( endNode ) & @@ -1508,7 +1510,7 @@ var getRangeAndRemoveBookmark = function ( range ) { range.setEnd( _range.endContainer, _range.endOffset ); collapsed = range.collapsed; - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); if ( collapsed ) { range.collapse( true ); } @@ -1638,7 +1640,7 @@ var hasFormat = function ( tag, attributes, range ) { // Otherwise, check each text node at least partially contained within // the selection and make sure all of them have the format we want. walker = new TreeWalker( root, SHOW_TEXT, function ( node ) { - return range.containsNode( node, true ) ? + return isNodeContainedInRange( range, node, true ) ? FILTER_ACCEPT : FILTER_SKIP; }, false ); @@ -1661,7 +1663,7 @@ var addFormat = function ( tag, attributes, range ) { if ( range.collapsed ) { el = fixCursor( createElement( tag, attributes ) ); - range._insertNode( el ); + insertNodeInRange( range, el ); range.setStart( el.firstChild, el.firstChild.length ); range.collapse( true ); } @@ -1678,7 +1680,7 @@ var addFormat = function ( tag, attributes, range ) { range.commonAncestorContainer, SHOW_TEXT, function ( node ) { - return range.containsNode( node, true ) ? + return isNodeContainedInRange( range, node, true ) ? FILTER_ACCEPT : FILTER_SKIP; }, false @@ -1741,7 +1743,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { } else { fixer = doc.createTextNode( '' ); } - range._insertNode( fixer ); + insertNodeInRange( range, fixer ); } // Find block-level ancestor of selection @@ -1760,7 +1762,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { examineNode = function ( node, exemplar ) { // If the node is completely contained by the range then // we're going to remove all formatting so ignore it. - if ( range.containsNode( node, false ) ) { + if ( isNodeContainedInRange( range, node, false ) ) { return; } @@ -1769,7 +1771,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { // If not at least partially contained, wrap entire contents // in a clone of the tag we're removing and we're done. - if ( !range.containsNode( node, true ) ) { + if ( !isNodeContainedInRange( range, node, true ) ) { // Ignore bookmarks and empty text nodes if ( node.nodeName !== 'INPUT' && ( !isText || node.data ) ) { @@ -1800,7 +1802,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { }, formatTags = Array.prototype.filter.call( root.getElementsByTagName( tag ), function ( el ) { - return range.containsNode( el, true ) && + return isNodeContainedInRange( range, el, true ) && hasTagAttributes( el, tag, attributes ); } ); @@ -1912,8 +1914,8 @@ var forEachBlock = function ( fn, mutates, range ) { getRangeAndRemoveBookmark( range ); } - var start = range.getStartBlock(), - end = range.getEndBlock(); + var start = getStartBlockOfRange( range ), + end = getEndBlockOfRange( range ); if ( start && end ) { do { if ( fn( start ) || start === end ) { break; } @@ -1950,14 +1952,14 @@ var modifyBlocks = function ( modify, range ) { } // 3. Expand range to block boundaries - range.expandToBlockBoundaries(); + expandRangeToBlockBoundaries( range ); // 4. Remove range. - range.moveBoundariesUpTree( body ); - var frag = range._extractContents( body ); + moveRangeBoundariesUpTree( range, body ); + var frag = extractContentsOfRange( range, body ); // 5. Modify tree of fragment and reinsert. - range._insertNode( modify( frag ) ); + insertNodeInRange( range, modify( frag ) ); // 6. Merge containers at edges if ( range.endOffset < range.endContainer.childNodes.length ) { @@ -2541,7 +2543,7 @@ addEventListener( isIE ? 'beforepaste' : 'paste', function ( event ) { // Insert pasted data if ( doPaste ) { - range.insertTreeFragment( frag ); + insertTreeFragmentIntoRange( range, frag ); docWasChanged(); range.collapse( false ); @@ -2615,7 +2617,7 @@ var afterDelete = function () { parent = getPreviousBlock( parent ); } fixCursor( parent ); - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); setSelection( range ); updatePath( range ); } @@ -2656,10 +2658,10 @@ var keyHandlers = { // Selected text is overwritten, therefore delete the contents // to collapse selection. if ( !range.collapsed ) { - range._deleteContents(); + deleteContentsOfRange( range ); } - var block = range.getStartBlock(), + var block = getStartBlockOfRange( range ), tag = block ? block.nodeName : 'DIV', splitTag = tagAfterSplit[ tag ], nodeAfterSplit; @@ -2667,7 +2669,7 @@ var keyHandlers = { // If this is a malformed bit of document, just play it safe // and insert a
. if ( !block ) { - range._insertNode( createElement( 'BR' ) ); + insertNodeInRange( range, createElement( 'BR' ) ); range.collapse( false ); setSelection( range ); updatePath( range, true ); @@ -2711,7 +2713,7 @@ var keyHandlers = { } range.setStart( splitNode, splitOffset ); range.setEnd( splitNode, splitOffset ); - block = range.getStartBlock(); + block = getStartBlockOfRange( range ); } if ( !block.textContent ) { @@ -2785,16 +2787,16 @@ var keyHandlers = { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - range._deleteContents(); + deleteContentsOfRange( range ); setSelection( range ); updatePath( range, true ); } // If at beginning of block, merge with previous - else if ( range.startsAtBlockBoundary() ) { + else if ( rangeDoesStartAtBlockBoundary( range ) ) { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - var current = range.getStartBlock(), + var current = getStartBlockOfRange( range ), previous = current && getPreviousBlock( current ); // Must not be at the very beginning of the text area. if ( previous ) { @@ -2851,16 +2853,16 @@ var keyHandlers = { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - range._deleteContents(); + deleteContentsOfRange( range ); setSelection( range ); updatePath( range, true ); } // If at end of block, merge next into this block - else if ( range.endsAtBlockBoundary() ) { + else if ( rangeDoesEndAtBlockBoundary( range ) ) { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - var current = range.getStartBlock(), + var current = getStartBlockOfRange( range ), next = current && getNextBlock( current ); // Must not be at the very end of the text area. if ( next ) { @@ -3093,7 +3095,7 @@ editor = win.editor = { }, getSelectedText: function () { - return getSelection().getTextContent(); + return getTextContentInRange( getSelection() ); }, insertElement: chain( insertElement ), diff --git a/build/squire.js b/build/squire.js index 925fc91..26d5022 100644 --- a/build/squire.js +++ b/build/squire.js @@ -1 +1 @@ -!function(e){"use strict";function t(e,t,n){this.root=this.currentNode=e,this.nodeType=t,this.filter=n}function n(e,t){for(var n=e.length;n--;)if(!t(e[n]))return!1;return!0}function r(e,t,n){if(e.nodeName!==t)return!1;for(var r in n)if(e.getAttribute(r)!==n[r])return!1;return!0}function o(e,t){return e.nodeType===t.nodeType&&e.nodeName===t.nodeName&&e.className===t.className&&(!e.style&&!t.style||e.style.cssText===t.style.cssText)}function i(e){return e.nodeType===E&&!!et[e.nodeName]}function a(e){return J.test(e.nodeName)}function s(e){return e.nodeType===E&&!a(e)&&n(e.childNodes,a)}function d(e){return e.nodeType===E&&!a(e)&&!s(e)}function l(e){return s(e)?I:L}function f(e){var n=e.ownerDocument,r=new t(n.body,D,l,!1);return r.currentNode=e,r}function c(e){return f(e).previousNode()}function u(e){return f(e).nextNode()}function h(e,t,n){do if(r(e,t,n))return e;while(e=e.parentNode);return null}function p(e){var t,n,r,o,i=e.parentNode;return i&&e.nodeType===E?(t=p(i),t+=(t?">":"")+e.nodeName,(n=e.id)&&(t+="#"+n),(r=e.className.trim())&&(o=r.split(/\s\s*/),o.sort(),t+=".",t+=o.join("."))):t=i?p(i):"",t}function N(e){var t=e.nodeType;return t===E?e.childNodes.length:e.length||0}function C(e){var t=e.parentNode;return t&&t.removeChild(e),e}function v(e,t){var n=e.parentNode;n&&n.replaceChild(t,e)}function g(e){for(var t=e.ownerDocument.createDocumentFragment(),n=e.childNodes,r=n?n.length:0;r--;)t.appendChild(e.firstChild);return t}function m(e){var t,n,r=e.ownerDocument,o=e;if("BODY"===e.nodeName&&((n=e.firstChild)&&"BR"!==n.nodeName||(t=r.createElement("DIV"),n?e.replaceChild(t,n):e.appendChild(t),e=t,t=null)),a(e))e.firstChild||($?(t=r.createTextNode("​"),Bt(t)):t=r.createTextNode(""));else if(Y){for(;e.nodeType!==b&&!i(e);){if(n=e.firstChild,!n){t=r.createTextNode("");break}e=n}e.nodeType===b?/^ +$/.test(e.data)&&(e.data=""):i(e)&&e.parentNode.insertBefore(r.createTextNode(""),e)}else if(!e.querySelector("BR"))for(t=r.createElement("BR");(n=e.lastElementChild)&&!a(n);)e=n;return t&&e.appendChild(t),o}function y(e,t,n){var r,o,i,a=e.nodeType;if(a===b&&e!==n)return y(e.parentNode,e.splitText(t),n);if(a===E){if("number"==typeof t&&(t=td?t.startOffset-=1:t.startOffset===d&&(t.startContainer=r,t.startOffset=N(r))),t.endContainer===e&&(t.endOffset>d?t.endOffset-=1:t.endOffset===d&&(t.endContainer=r,t.endOffset=N(r))),C(n),n.nodeType===b?r.appendData(n.data.replace(/\u200B/g,"")):l.push(g(n));else if(n.nodeType===E){for(i=l.length;i--;)n.appendChild(l.pop());T(n,t)}}function S(e,t,n){for(var r,o,i,a=t;1===a.parentNode.childNodes.length;)a=a.parentNode;C(a),o=e.childNodes.length,r=e.lastChild,r&&"BR"===r.nodeName&&(e.removeChild(r),o-=1),i={startContainer:e,startOffset:o,endContainer:e,endOffset:o},e.appendChild(g(t)),T(e,i),n.setStart(i.startContainer,i.startOffset),n.collapse(!0),q&&(r=e.lastChild)&&"BR"===r.nodeName&&e.removeChild(r)}function B(e){var t=e.previousSibling,n=e.firstChild;t&&o(t,e)&&d(t)&&(C(e),t.appendChild(g(e)),n&&B(n))}function O(t,n,r){var o,i,a,s=e.createElement(t);if(n instanceof Array&&(r=n,n=null),n)for(o in n)s.setAttribute(o,n[o]);if(r)for(i=0,a=r.length;a>i;i+=1)s.appendChild(r[i]);return s}var x=2,E=1,b=3,D=1,A=4,I=1,L=3,R=0,k=1,w=2,P=3,U=e.defaultView,V=e.body,H=navigator.userAgent,_=/iP(?:ad|hone|od)/.test(H),F=/Mac OS X/.test(H),z=/Gecko\//.test(H),M=/Trident\//.test(H),K=8===U.ie,q=!!U.opera,G=/WebKit\//.test(H),Q=F?"meta-":"ctrl-",Y=M||q,$=M||G,j=M,W=/\S/,X=Array.prototype.indexOf,Z={1:1,2:2,3:4,8:128,9:256,11:1024};t.prototype.nextNode=function(){for(var e,t=this.currentNode,n=this.root,r=this.nodeType,o=this.filter;;){for(e=t.firstChild;!e&&t&&t!==n;)e=t.nextSibling,e||(t=t.parentNode);if(!e)return null;if(Z[e.nodeType]&r&&o(e)===I)return this.currentNode=e,e;t=e}},t.prototype.previousNode=function(){for(var e,t=this.currentNode,n=this.root,r=this.nodeType,o=this.filter;;){if(t===n)return null;if(e=t.previousSibling)for(;t=e.lastChild;)e=t;else e=t.parentNode;if(!e)return null;if(Z[e.nodeType]&r&&o(e)===I)return this.currentNode=e,e;t=e}};var J=/^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:FN|EL)|EM|FONT|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TRONG|AMP)|U)$/,et={BR:1,IMG:1,INPUT:1};!function(){var t=e.createElement("div"),n=e.createTextNode("12");return t.appendChild(n),n.splitText(2),2!==t.childNodes.length}()&&(Text.prototype.splitText=function(e){var t=this.ownerDocument.createTextNode(this.data.slice(e)),n=this.nextSibling,r=this.parentNode,o=this.length-e;return n?r.insertBefore(t,n):r.appendChild(t),o&&this.deleteData(e,o),t});var tt=function(e,t){for(var n=e.childNodes;t&&e.nodeType===E;)e=n[t-1],n=e.childNodes,t=n.length;return e},nt=function(e,t){if(e.nodeType===E){var n=e.childNodes;if(t-1,i=n.compareBoundaryPoints(k,r)<1;return!o&&!i}var a=n.compareBoundaryPoints(R,r)<1,s=n.compareBoundaryPoints(w,r)>-1;return a&&s},rt.moveBoundariesDownTree=function(){for(var e,t=this.startContainer,n=this.startOffset,r=this.endContainer,o=this.endOffset;t.nodeType!==b&&(e=t.childNodes[n],e&&!i(e));)t=e,n=0;if(o)for(;r.nodeType!==b&&(e=r.childNodes[o-1],e&&!i(e));)r=e,o=N(r);else for(;r.nodeType!==b&&(e=r.firstChild,e&&!i(e));)r=e;return this.collapsed?(this.setStart(r,o),this.setEnd(t,n)):(this.setStart(t,n),this.setEnd(r,o)),this},rt.moveBoundariesUpTree=function(e){var t,n=this.startContainer,r=this.startOffset,o=this.endContainer,i=this.endOffset;for(e||(e=this.commonAncestorContainer);n!==e&&!r;)t=n.parentNode,r=X.call(t.childNodes,n),n=t;for(;o!==e&&i===N(o);)t=o.parentNode,i=X.call(t.childNodes,o)+1,o=t;return this.setStart(n,r),this.setEnd(o,i),this},rt.getStartBlock=function(){var e,t=this.startContainer;return a(t)?e=c(t):s(t)?e=t:(e=tt(t,this.startOffset),e=u(e)),e&&this.containsNode(e,!0)?e:null},rt.getEndBlock=function(){var e,t,n=this.endContainer;if(a(n))e=c(n);else if(s(n))e=n;else{if(e=nt(n,this.endOffset),!e)for(e=n.ownerDocument.body;t=e.lastChild;)e=t;e=c(e)}return e&&this.containsNode(e,!0)?e:null},rt.startsAtBlockBoundary=function(){for(var e,t,n=this.startContainer,r=this.startOffset;a(n);){if(r)return!1;e=n.parentNode,r=X.call(e.childNodes,n),n=e}for(;r&&(t=n.childNodes[r-1])&&(""===t.data||"BR"===t.nodeName);)r-=1;return!r},rt.endsAtBlockBoundary=function(){for(var e,t,n=this.endContainer,r=this.endOffset,o=N(n);a(n);){if(r!==o)return!1;e=n.parentNode,r=X.call(e.childNodes,n)+1,n=e,o=n.childNodes.length}for(;o>r&&(t=n.childNodes[r])&&(""===t.data||"BR"===t.nodeName);)r+=1;return r===o},rt.expandToBlockBoundaries=function(){var e,t=this.getStartBlock(),n=this.getEndBlock();return t&&n&&(e=t.parentNode,this.setStart(e,X.call(e.childNodes,t)),e=n.parentNode,this.setEnd(e,X.call(e.childNodes,n)+1)),this};var ot,it={focus:1,blur:1,pathChange:1,select:1,input:1,undoStateChange:1},at={},st=function(e,t){var n,r,o,i=at[e];if(i)for(t||(t={}),t.type!==e&&(t.type=e),i=i.slice(),n=0,r=i.length;r>n;n+=1){o=i[n];try{o.handleEvent?o.handleEvent(t):o(t)}catch(a){a.details="Squire: fireEvent error. Event type: "+e,ot.didError(a)}}},dt=function(e){st(e.type,e)},lt=function(t,n){var r=at[t];return n?(r||(r=at[t]=[],it[t]||e.addEventListener(t,dt,!1)),r.push(n),void 0):(ot.didError({name:"Squire: addEventListener with null or undefined fn",message:"Event type: "+t}),void 0)},ft=function(t,n){var r,o=at[t];if(o){for(r=o.length;r--;)o[r]===n&&o.splice(r,1);o.length||(delete at[t],it[t]||e.removeEventListener(t,dt,!1))}},ct=function(t,n,r,o){if(t instanceof Range)return t.cloneRange();var i=e.createRange();return i.setStart(t,n),r?i.setEnd(r,o):i.setEnd(t,n),i},ut=U.getSelection(),ht=null,pt=function(e){e&&(_&&U.focus(),ut.removeAllRanges(),ut.addRange(e))},Nt=function(){if(ut.rangeCount){ht=ut.getRangeAt(0).cloneRange();var e=ht.startContainer,t=ht.endContainer;try{e&&i(e)&&ht.setStartBefore(e),t&&i(t)&&ht.setEndBefore(t)}catch(n){ot.didError({name:"Squire#getSelection error",message:"Starts: "+e.nodeName+"\nEnds: "+t.nodeName})}}return ht};j&&U.addEventListener("beforedeactivate",Nt,!0);var Ct,vt,gt=null,mt=!0,yt=!1,Tt=function(){mt=!0,yt=!1,ft("keydown",Tt)},St=function(){if(mt){var e,t=gt;if(gt=null,t.parentNode){for(;(e=t.data.indexOf("​"))>-1;)t.deleteData(e,1);t.data||t.nextSibling||t.previousSibling||!a(t.parentNode)||C(t.parentNode)}}},Bt=function(e){gt&&(mt=!0,St()),yt||(lt("keydown",Tt),yt=!0),mt=!1,gt=e},Ot="",xt=function(e,t){gt&&!t&&St(e);var n,r=e.startContainer,o=e.endContainer;(t||r!==Ct||o!==vt)&&(Ct=r,vt=o,n=r&&o?r===o?p(o):"(selection)":"",Ot!==n&&(Ot=n,st("pathChange",{path:n}))),r!==o&&st("select")},Et=function(){xt(Nt())};lt("keyup",Et),lt("mouseup",Et);var bt=function(){z&&V.focus(),U.focus()},Dt=function(){z&&V.blur(),top.focus()};U.addEventListener("focus",dt,!1),U.addEventListener("blur",dt,!1);var At,It,Lt,Rt,kt=function(){return V.innerHTML},wt=function(e){var t=V;t.innerHTML=e;do m(t);while(t=u(t))},Pt=function(e,t){if(t||(t=Nt()),t.collapse(!0),a(e))t._insertNode(e),t.setStartAfter(e);else{for(var n,r,o=t.getStartBlock()||V;o!==V&&!o.nextSibling;)o=o.parentNode;o!==V&&(n=o.parentNode,r=y(n,o.nextSibling,V)),r?(V.insertBefore(e,r),t.setStart(r,0),t.setStart(r,0),t.moveBoundariesDownTree()):(V.appendChild(e),V.appendChild(m(O("div"))),t.setStart(e,0),t.setEnd(e,0)),bt(),pt(t),xt(t)}},Ut="squire-selection-start",Vt="squire-selection-end",Ht=function(e){var t,n=O("INPUT",{id:Ut,type:"hidden"}),r=O("INPUT",{id:Vt,type:"hidden"});e._insertNode(n),e.collapse(!1),e._insertNode(r),n.compareDocumentPosition(r)&x&&(n.id=Vt,r.id=Ut,t=n,n=r,r=t),e.setStartAfter(n),e.setEndBefore(r)},_t=function(t){var n=e.getElementById(Ut),r=e.getElementById(Vt);if(n&&r){var o,i=n.parentNode,a=r.parentNode,s={startContainer:i,endContainer:a,startOffset:X.call(i.childNodes,n),endOffset:X.call(a.childNodes,r)};i===a&&(s.endOffset-=1),C(n),C(r),T(i,s),i!==a&&T(a,s),t||(t=e.createRange()),t.setStart(s.startContainer,s.startOffset),t.setEnd(s.endContainer,s.endOffset),o=t.collapsed,t.moveBoundariesDownTree(),o&&t.collapse(!0)}return t||null},Ft=function(){Rt&&(Rt=!1,st("undoStateChange",{canUndo:!0,canRedo:!1})),st("input")};lt("keyup",function(e){var t=e.keyCode;e.ctrlKey||e.metaKey||e.altKey||!(16>t||t>20)||!(33>t||t>45)||Ft()});var zt=function(e){Rt||(At+=1,Lt>At&&(It.length=Lt=At),e&&Ht(e),It[At]=kt(),Lt+=1,Rt=!0)},Mt=function(){if(0!==At||!Rt){zt(Nt()),At-=1,wt(It[At]);var e=_t();e&&pt(e),Rt=!0,st("undoStateChange",{canUndo:0!==At,canRedo:!0}),st("input")}},Kt=function(){if(Lt>At+1&&Rt){At+=1,wt(It[At]);var e=_t();e&&pt(e),st("undoStateChange",{canUndo:!0,canRedo:Lt>At+1}),st("input")}},qt=function(e,n,r){if(e=e.toUpperCase(),n||(n={}),!r&&!(r=Nt()))return!1;var o,i,a=r.commonAncestorContainer;if(h(a,e,n))return!0;if(a.nodeType===b)return!1;o=new t(a,A,function(e){return r.containsNode(e,!0)?I:L},!1);for(var s=!1;i=o.nextNode();){if(!h(i,e,n))return!1;s=!0}return s},Gt=function(e,n,r){var o,i,a,s,d,l,f,c;if(r.collapsed)o=m(O(e,n)),r._insertNode(o),r.setStart(o.firstChild,o.firstChild.length),r.collapse(!0);else{i=new t(r.commonAncestorContainer,A,function(e){return r.containsNode(e,!0)?I:L},!1),d=0,l=0,f=i.currentNode=r.startContainer,f.nodeType!==b&&(f=i.nextNode());do c=!h(f,e,n),f===r.endContainer&&(c&&f.length>r.endOffset?f.splitText(r.endOffset):l=r.endOffset),f===r.startContainer&&(c&&r.startOffset?f=f.splitText(r.startOffset):d=r.startOffset),c&&(o=O(e,n),v(f,o),o.appendChild(f),l=f.length),s=f,a||(a=s);while(f=i.nextNode());r=ct(a,d,s,l)}return r},Qt=function(t,n,o,i){Ht(o);var s;o.collapsed&&($?(s=e.createTextNode("​"),Bt(s)):s=e.createTextNode(""),o._insertNode(s));for(var d=o.commonAncestorContainer;a(d);)d=d.parentNode;var l=o.startContainer,f=o.startOffset,c=o.endContainer,u=o.endOffset,h=[],p=function(e,t){if(!o.containsNode(e,!1)){var n,r,i=e.nodeType===b;if(!o.containsNode(e,!0))return"INPUT"===e.nodeName||i&&!e.data||h.push([t,e]),void 0;if(i)e===c&&u!==e.length&&h.push([t,e.splitText(u)]),e===l&&f&&(e.splitText(f),h.push([t,e]));else for(n=e.firstChild;n;n=r)r=n.nextSibling,p(n,t)}},N=Array.prototype.filter.call(d.getElementsByTagName(t),function(e){return o.containsNode(e,!0)&&r(e,t,n)});i||N.forEach(function(e){p(e,e)}),h.forEach(function(e){var t=e[0].cloneNode(!1),n=e[1];v(n,t),t.appendChild(n)}),N.forEach(function(e){v(e,g(e))}),_t(o),s&&o.collapse(!1);var C={startContainer:o.startContainer,startOffset:o.startOffset,endContainer:o.endContainer,endOffset:o.endOffset};return T(d,C),o.setStart(C.startContainer,C.startOffset),o.setEnd(C.endContainer,C.endOffset),o},Yt=function(e,t,n,r){(n||(n=Nt()))&&(zt(n),_t(n),t&&(n=Qt(t.tag.toUpperCase(),t.attributes||{},n,r)),e&&(n=Gt(e.tag.toUpperCase(),e.attributes||{},n)),pt(n),xt(n,!0),Ft())},$t={DIV:"DIV",PRE:"DIV",H1:"DIV",H2:"DIV",H3:"DIV",H4:"DIV",H5:"DIV",H6:"DIV",P:"DIV",DT:"DD",DD:"DT",LI:"LI"},jt=function(e,t,n){var r=$t[e.nodeName],o=y(t,n,e.parentNode);return o.nodeName!==r&&(e=O(r),e.className="rtl"===o.dir?"dir-rtl":"",e.dir=o.dir,v(o,e),e.appendChild(g(o)),o=e),o},Wt=function(e,t,n){if(n||(n=Nt())){t&&(zt(n),_t(n));var r=n.getStartBlock(),o=n.getEndBlock();if(r&&o)do if(e(r)||r===o)break;while(r=u(r));t&&(pt(n),xt(n,!0),Ft())}},Xt=function(e,t){if(t||(t=Nt())){q||V.setAttribute("contenteditable","false"),Rt?Ht(t):zt(t),t.expandToBlockBoundaries(),t.moveBoundariesUpTree(V);var n=t._extractContents(V);t._insertNode(e(n)),t.endOffsetn;n+=1)o=e[n],i=o.nodeName,s(o)?"LI"!==i&&(l=O("LI",{"class":"rtl"===o.dir?"dir-rtl":"",dir:o.dir},[g(o)]),o.parentNode.nodeName===t?v(o,l):(a=o.previousSibling)&&a.nodeName===t?(a.appendChild(l),C(o),n-=1,r-=1):v(o,O(t,[l]))):d(o)&&(i!==t&&/^[DOU]L$/.test(i)?v(o,O(t,[g(o)])):tn(o.childNodes,t))},nn=function(e){return tn(e.childNodes,"UL"),e},rn=function(e){return tn(e.childNodes,"OL"),e},on=function(e){var t=e.querySelectorAll("UL, OL");return Array.prototype.filter.call(t,function(e){return!h(e.parentNode,"UL")&&!h(e.parentNode,"OL")}).forEach(function(e){for(var t,n=g(e),r=n.childNodes,o=r.length;o--;)t=r[o],"LI"===t.nodeName&&n.replaceChild(O("DIV",{"class":"rtl"===t.dir?"dir-rtl":"",dir:t.dir},[g(t)]),t);v(e,n)}),e},an=/\b((?:(?:ht|f)tps?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:[\w\-.%+]+@(?:[\w\-]+\.)+[A-Z]{2,4}))/i,sn=function(e){for(var n,r,o,i,a,s,d,l=e.ownerDocument,f=new t(e,A,function(e){return h(e,"A")?L:I},!1);n=f.nextNode();)if(r=n.data.split(an),i=r.length,i>1){for(s=n.parentNode,d=n.nextSibling,o=0;i>o;o+=1)a=r[o],o?(o%2?(n=l.createElement("A"),n.textContent=a,n.href=/@/.test(a)?"mailto:"+a:/^(?:ht|f)tps?:/.test(a)?a:"http://"+a):n=l.createTextNode(a),d?s.insertBefore(n,d):s.appendChild(n)):n.data=a;f.currentNode=n}},dn=/^(?:A(?:DDRESS|RTICLE|SIDE)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/,ln={1:10,2:13,3:16,4:18,5:24,6:32,7:48},fn={backgroundColor:{regexp:W,replace:function(e){return O("SPAN",{"class":"highlight",style:"background-color: "+e})}},color:{regexp:W,replace:function(e){return O("SPAN",{"class":"colour",style:"color:"+e})}},fontWeight:{regexp:/^bold/i,replace:function(){return O("B")}},fontStyle:{regexp:/^italic/i,replace:function(){return O("I")}},fontFamily:{regexp:W,replace:function(e){return O("SPAN",{"class":"font",style:"font-family:"+e})}},fontSize:{regexp:W,replace:function(e){return O("SPAN",{"class":"size",style:"font-size:"+e})}}},cn={SPAN:function(e,t){var n,r,o,i,a,s,d=e.style;for(n in fn)r=fn[n],o=d[n],o&&r.regexp.test(o)&&(s=r.replace(o),i&&i.appendChild(s),i=s,a||(a=s));return a&&(i.appendChild(g(e)),t.replaceChild(a,e)),i||e},STRONG:function(e,t){var n=O("B");return t.replaceChild(n,e),n.appendChild(g(e)),n},EM:function(e,t){var n=O("I");return t.replaceChild(n,e),n.appendChild(g(e)),n},FONT:function(e,t){var n,r,o,i,a=e.face,s=e.size;return a&&(n=O("SPAN",{"class":"font",style:"font-family:"+a})),s&&(r=O("SPAN",{"class":"size",style:"font-size:"+ln[s]+"px"}),n&&n.appendChild(r)),i=n||r||O("SPAN"),o=r||n||i,t.replaceChild(i,e),o.appendChild(g(e)),o},TT:function(e,t){var n=O("SPAN",{"class":"font",style:'font-family:menlo,consolas,"courier new",monospace'});return t.replaceChild(n,e),n.appendChild(g(e)),n}},un=function(e){for(var t,n=e.childNodes,r=n.length;r--;)t=n[r],t.nodeType===E&&"IMG"!==t.nodeName&&(un(t),a(t)&&!t.firstChild&&e.removeChild(t))},hn=function(e,t){var n,r,o,i,s,d,l,f=e.childNodes;for(n=0,r=f.length;r>n;n+=1)if(o=f[n],i=o.nodeName,s=o.nodeType,d=cn[i],s===E){if(l=o.childNodes.length,d)o=d(o,e);else{if(!dn.test(i)&&!a(o)){n-=1,r+=l-1,e.replaceChild(g(o),o);continue}!t&&o.style.cssText&&o.removeAttribute("style")}l&&hn(o,t)}else s===b&&(W.test(o.data)||n>0&&a(f[n-1])||r>n+1&&a(f[n+1]))||(e.removeChild(o),n-=1,r-=1);return e},pn=function(e,t){var n,r,o,i,s=e.childNodes,d=null;for(n=0,r=s.length;r>n;n+=1)o=s[n],i="BR"===o.nodeName,!i&&a(o)?(d||(d=O(t)),d.appendChild(o),n-=1,r-=1):(i||d)&&(d||(d=O(t)),m(d),i?e.replaceChild(d,o):(e.insertBefore(d,o),n+=1,r+=1),d=null);return d&&e.appendChild(m(d)),e},Nn=function(e){return(e.nodeType===E?"BR"===e.nodeName:W.test(e.data))?I:L},Cn=function(e){for(var n,r=e.parentNode;a(r);)r=r.parentNode;return n=new t(r,D|A,Nn),n.currentNode=e,!!n.nextNode()},vn=function(e){var t,n,r,o=e.querySelectorAll("BR"),i=[],d=o.length;for(t=0;d>t;t+=1)i[t]=Cn(o[t]);for(;d--;)if(n=o[d],r=n.parentNode){for(;a(r);)r=r.parentNode;s(r)&&$t[r.nodeName]?(i[d]&&jt(r,n.parentNode,n),C(n)):pn(r,"DIV")}},gn=function(){try{m(V)}catch(e){ot.didError(e)}};lt(M?"beforecut":"cut",function(){var e=Nt();zt(e),_t(e),pt(e),setTimeout(gn,0)});var mn=!1;lt(M?"beforepaste":"paste",function(e){if(!mn){var t,n,r=e.clipboardData,o=r&&r.items,i=!1,a=!1;if(o){for(t=o.length;t--;){if(n=o[t].type,"text/html"===n){a=!1;break}/^image\/.*/.test(n)&&(a=!0)}if(a)return e.preventDefault(),st("dragover",{dataTransfer:r,preventDefault:function(){i=!0}}),i&&st("drop",{dataTransfer:r}),void 0}mn=!0;var s=Nt(),d=s.startContainer,l=s.startOffset,f=s.endContainer,c=s.endOffset,h=O("DIV",{style:"position: absolute; overflow: hidden; top:"+(V.scrollTop+30)+"px; left: 0; width: 1px; height: 1px;"});V.appendChild(h),s.selectNodeContents(h),pt(s),setTimeout(function(){try{var e=g(C(h)),t=e.firstChild,n=ct(d,l,f,c);if(t){t===e.lastChild&&"DIV"===t.nodeName&&e.replaceChild(g(t),t),e.normalize(),sn(e),hn(e,!1),vn(e),un(e);for(var r=e,o=!0;r=u(r);)m(r);st("willPaste",{fragment:e,preventDefault:function(){o=!1}}),o&&(n.insertTreeFragment(e),Ft(),n.collapse(!1))}pt(n),xt(n,!0),mn=!1}catch(i){ot.didError(i)}},0)}});var yn={8:"backspace",9:"tab",13:"enter",32:"space",37:"left",39:"right",46:"delete"},Tn=function(e){return function(t){t.preventDefault(),e()}},Sn=function(e){return function(t){t.preventDefault();var n=Nt();qt(e,null,n)?Yt(null,{tag:e},n):Yt({tag:e},null,n)}},Bn=function(){try{var e,t=Nt(),n=t.startContainer;if(n.nodeType===b&&(n=n.parentNode),a(n)&&!n.textContent){do e=n.parentNode;while(a(e)&&!e.textContent&&(n=e));t.setStart(e,X.call(e.childNodes,n)),t.collapse(!0),e.removeChild(n),s(e)||(e=c(e)),m(e),t.moveBoundariesDownTree(),pt(t),xt(t)}}catch(r){ot.didError(r)}};K&<("keyup",function(){var e=V.firstChild;"P"===e.nodeName&&(Ht(Nt()),v(e,O("DIV",[g(e)])),pt(_t()))});var On={enter:function(t){t.preventDefault();var n=Nt();if(n){zt(n),sn(n.startContainer),_t(n),n.collapsed||n._deleteContents();var r,o=n.getStartBlock(),i=o?o.nodeName:"DIV",a=$t[i];if(!o)return n._insertNode(O("BR")),n.collapse(!1),pt(n),xt(n,!0),Ft(),void 0;var s,d=n.startContainer,l=n.startOffset;if(a||(d===o&&(d=l?d.childNodes[l-1]:null,l=0,d&&("BR"===d.nodeName?d=d.nextSibling:l=N(d),d&&"BR"!==d.nodeName||(s=m(O("DIV")),d?o.replaceChild(s,d):o.appendChild(s),d=s))),pn(o,"DIV"),a="DIV",d||(d=o.firstChild),n.setStart(d,l),n.setEnd(d,l),o=n.getStartBlock()),!o.textContent){if(h(o,"UL")||h(o,"OL"))return Xt(on,n);if(h(o,"BLOCKQUOTE"))return Xt(en,n)}for(r=jt(o,d,l);r.nodeType===E;){var f,c=r.firstChild;if("A"!==r.nodeName){for(;c&&c.nodeType===b&&!c.data&&(f=c.nextSibling,f&&"BR"!==f.nodeName);)C(c),c=f;if(!c||"BR"===c.nodeName||c.nodeType===b&&!q)break;r=c}else v(r,g(r)),r=c}n=ct(r,0),pt(n),xt(n,!0),r.nodeType===b&&(r=r.parentNode),r.offsetTop+r.offsetHeight>(e.documentElement.scrollTop||V.scrollTop)+V.offsetHeight&&r.scrollIntoView(!1),Ft()}},backspace:function(e){var t=Nt();if(t.collapsed)if(t.startsAtBlockBoundary()){zt(t),_t(t),e.preventDefault();var n=t.getStartBlock(),r=n&&c(n);if(r){if(!r.isContentEditable)return C(r),void 0;for(S(r,n,t),n=r.parentNode;n&&!n.nextSibling;)n=n.parentNode;n&&(n=n.nextSibling)&&B(n),pt(t)}else if(n){if(h(n,"UL")||h(n,"OL"))return Xt(on,t);if(h(n,"BLOCKQUOTE"))return Xt(Jt,t);pt(t),xt(t,!0)}}else{var o=t.startContainer.data||"";W.test(o.charAt(t.startOffset-1))||(zt(t),_t(t),pt(t)),setTimeout(Bn,0)}else zt(t),_t(t),e.preventDefault(),t._deleteContents(),pt(t),xt(t,!0)},"delete":function(e){var t=Nt();if(t.collapsed)if(t.endsAtBlockBoundary()){zt(t),_t(t),e.preventDefault();var n=t.getStartBlock(),r=n&&u(n);if(r){if(!r.isContentEditable)return C(r),void 0;for(S(n,r,t),r=n.parentNode;r&&!r.nextSibling;)r=r.parentNode;r&&(r=r.nextSibling)&&B(r),pt(t),xt(t,!0)}}else{var o=t.startContainer.data||"";W.test(o.charAt(t.startOffset))||(zt(t),_t(t),pt(t)),setTimeout(Bn,0)}else zt(t),_t(t),e.preventDefault(),t._deleteContents(),pt(t),xt(t,!0)},space:function(){var e=Nt();zt(e),sn(e.startContainer),_t(e),pt(e)}};F&&z&&ut.modify&&(On["meta-left"]=function(e){e.preventDefault(),ut.modify("move","backward","lineboundary")},On["meta-right"]=function(e){e.preventDefault(),ut.modify("move","forward","lineboundary")}),On[Q+"b"]=Sn("B"),On[Q+"i"]=Sn("I"),On[Q+"u"]=Sn("U"),On[Q+"y"]=Tn(Kt),On[Q+"z"]=Tn(Mt),On[Q+"shift-z"]=Tn(Kt),lt(q?"keypress":"keydown",function(e){var t=e.keyCode,n=yn[t]||String.fromCharCode(t).toLowerCase(),r="";q&&46===e.which&&(n="."),t>111&&124>t&&(n="f"+(t-111)),e.altKey&&(r+="alt-"),e.ctrlKey&&(r+="ctrl-"),e.metaKey&&(r+="meta-"),e.shiftKey&&(r+="shift-"),n=r+n,On[n]&&On[n](e)});var xn=function(e){return function(){return e.apply(null,arguments),this}},En=function(e,t,n){return function(){return e(t,n),bt(),this}};ot=U.editor={didError:function(e){console.log(e)},addEventListener:xn(lt),removeEventListener:xn(ft),focus:xn(bt),blur:xn(Dt),getDocument:function(){return e},addStyles:function(t){if(t){var n=e.documentElement.firstChild,r=O("STYLE",{type:"text/css"});r.styleSheet?(n.appendChild(r),r.styleSheet.cssText=t):(r.appendChild(e.createTextNode(t)),n.appendChild(r))}return this},getHTML:function(e){var t,n,r,o,i,a=[];if(e&&(i=Nt())&&Ht(i),Y)for(t=V;t=u(t);)t.textContent||t.querySelector("BR")||(n=O("BR"),t.appendChild(n),a.push(n));if(r=kt(),Y)for(o=a.length;o--;)C(a[o]);return i&&_t(i),r},setHTML:function(t){var n,r=e.createDocumentFragment(),o=O("DIV");o.innerHTML=t,r.appendChild(g(o)),hn(r,!0),vn(r),pn(r,"DIV");for(var i=r;i=u(i);)m(i);for(;n=V.lastChild;)V.removeChild(n);V.appendChild(r),m(V),At=-1,It=[],Lt=0,Rt=!1;var a=_t()||ct(V.firstChild,0);return zt(a),_t(a),j?ht=a:pt(a),xt(a,!0),this},getSelectedText:function(){return Nt().getTextContent()},insertElement:xn(Pt),insertImage:function(e){var t=O("IMG",{src:e});return Pt(t),t},getPath:function(){return Ot},getSelection:Nt,setSelection:xn(pt),undo:xn(Mt),redo:xn(Kt),hasFormat:qt,changeFormat:xn(Yt),bold:En(Yt,{tag:"B"}),italic:En(Yt,{tag:"I"}),underline:En(Yt,{tag:"U"}),removeBold:En(Yt,null,{tag:"B"}),removeItalic:En(Yt,null,{tag:"I"}),removeUnderline:En(Yt,null,{tag:"U"}),makeLink:function(t){t=encodeURI(t);var n=Nt();if(n.collapsed){var r=t.indexOf(":")+1;if(r)for(;"/"===t[r];)r+=1;n._insertNode(e.createTextNode(t.slice(r)))}return Yt({tag:"A",attributes:{href:t}},{tag:"A"},n),bt(),this},removeLink:function(){return Yt(null,{tag:"A"},Nt(),!0),bt(),this},setFontFace:function(e){return Yt({tag:"SPAN",attributes:{"class":"font",style:"font-family: "+e+", sans-serif;"}},{tag:"SPAN",attributes:{"class":"font"}}),bt(),this},setFontSize:function(e){return Yt({tag:"SPAN",attributes:{"class":"size",style:"font-size: "+("number"==typeof e?e+"px":e)}},{tag:"SPAN",attributes:{"class":"size"}}),bt(),this},setTextColour:function(e){return Yt({tag:"SPAN",attributes:{"class":"colour",style:"color: "+e}},{tag:"SPAN",attributes:{"class":"colour"}}),bt(),this},setHighlightColour:function(e){return Yt({tag:"SPAN",attributes:{"class":"highlight",style:"background-color: "+e}},{tag:"SPAN",attributes:{"class":"highlight"}}),bt(),this},setTextAlignment:function(e){return Wt(function(t){t.className=(t.className.split(/\s+/).filter(function(e){return!/align/.test(e)}).join(" ")+" align-"+e).trim(),t.style.textAlign=e},!0),bt(),this},setTextDirection:function(e){return Wt(function(t){t.className=(t.className.split(/\s+/).filter(function(e){return!/dir/.test(e)}).join(" ")+" dir-"+e).trim(),t.dir=e},!0),bt(),this},forEachBlock:xn(Wt),modifyBlocks:xn(Xt),increaseQuoteLevel:En(Xt,Zt),decreaseQuoteLevel:En(Xt,Jt),makeUnorderedList:En(Xt,nn),makeOrderedList:En(Xt,rn),removeList:En(Xt,on)},V.setAttribute("contenteditable","true"),ot.setHTML(""),U.onEditorLoad&&(U.onEditorLoad(U.editor),U.onEditorLoad=null)}(document); \ No newline at end of file +(function(e){"use strict";function t(e,t,n){this.root=this.currentNode=e,this.nodeType=t,this.filter=n}function n(e,t){for(var n=e.length;n--;)if(!t(e[n]))return!1;return!0}function r(e,t,n){if(e.nodeName!==t)return!1;for(var r in n)if(e.getAttribute(r)!==n[r])return!1;return!0}function o(e,t){return e.nodeType===t.nodeType&&e.nodeName===t.nodeName&&e.className===t.className&&(!e.style&&!t.style||e.style.cssText===t.style.cssText)}function i(e){return e.nodeType===x&&!!et[e.nodeName]}function a(e){return J.test(e.nodeName)}function d(e){return e.nodeType===x&&!a(e)&&n(e.childNodes,a)}function l(e){return e.nodeType===x&&!a(e)&&!d(e)}function s(e){return d(e)?I:L}function f(e){var n=e.ownerDocument,r=new t(n.body,B,s,!1);return r.currentNode=e,r}function c(e){return f(e).previousNode()}function u(e){return f(e).nextNode()}function p(e,t,n){do if(r(e,t,n))return e;while(e=e.parentNode);return null}function h(e){var t,n,r,o,i=e.parentNode;return i&&e.nodeType===x?(t=h(i),t+=(t?">":"")+e.nodeName,(n=e.id)&&(t+="#"+n),(r=e.className.trim())&&(o=r.split(/\s\s*/),o.sort(),t+=".",t+=o.join("."))):t=i?h(i):"",t}function N(e){var t=e.nodeType;return t===x?e.childNodes.length:e.length||0}function C(e){var t=e.parentNode;return t&&t.removeChild(e),e}function v(e,t){var n=e.parentNode;n&&n.replaceChild(t,e)}function m(e){for(var t=e.ownerDocument.createDocumentFragment(),n=e.childNodes,r=n?n.length:0;r--;)t.appendChild(e.firstChild);return t}function g(e){var t,n,r=e.ownerDocument,o=e;if("BODY"===e.nodeName&&((n=e.firstChild)&&"BR"!==n.nodeName||(t=r.createElement("DIV"),n?e.replaceChild(t,n):e.appendChild(t),e=t,t=null)),a(e))e.firstChild||(j?(t=r.createTextNode("​"),kt(t)):t=r.createTextNode(""));else if($){for(;e.nodeType!==D&&!i(e);){if(n=e.firstChild,!n){t=r.createTextNode("");break}e=n}e.nodeType===D?/^ +$/.test(e.data)&&(e.data=""):i(e)&&e.parentNode.insertBefore(r.createTextNode(""),e)}else if(!e.querySelector("BR"))for(t=r.createElement("BR");(n=e.lastElementChild)&&!a(n);)e=n;return t&&e.appendChild(t),o}function y(e,t,n){var r,o,i,a=e.nodeType;if(a===D&&e!==n)return y(e.parentNode,e.splitText(t),n);if(a===x){if("number"==typeof t&&(t=e.childNodes.length>t?e.childNodes[t]:null),e===n)return t;for(r=e.parentNode,o=e.cloneNode(!1);t;)i=t.nextSibling,o.appendChild(t),t=i;return g(e),g(o),(i=e.nextSibling)?r.insertBefore(o,i):r.appendChild(o),y(r,o,n)}return t}function T(e,t){if(e.nodeType===x)for(var n,r,i,d=e.childNodes,l=d.length,s=[];l--;)if(n=d[l],r=l&&d[l-1],l&&a(n)&&o(n,r)&&!et[n.nodeName])t.startContainer===n&&(t.startContainer=r,t.startOffset+=N(r)),t.endContainer===n&&(t.endContainer=r,t.endOffset+=N(r)),t.startContainer===e&&(t.startOffset>l?t.startOffset-=1:t.startOffset===l&&(t.startContainer=r,t.startOffset=N(r))),t.endContainer===e&&(t.endOffset>l?t.endOffset-=1:t.endOffset===l&&(t.endContainer=r,t.endOffset=N(r))),C(n),n.nodeType===D?r.appendData(n.data.replace(/\u200B/g,"")):s.push(m(n));else if(n.nodeType===x){for(i=s.length;i--;)n.appendChild(s.pop());T(n,t)}}function S(e,t,n){for(var r,o,i,a=t;1===a.parentNode.childNodes.length;)a=a.parentNode;C(a),o=e.childNodes.length,r=e.lastChild,r&&"BR"===r.nodeName&&(e.removeChild(r),o-=1),i={startContainer:e,startOffset:o,endContainer:e,endOffset:o},e.appendChild(m(t)),T(e,i),n.setStart(i.startContainer,i.startOffset),n.collapse(!0),G&&(r=e.lastChild)&&"BR"===r.nodeName&&e.removeChild(r)}function O(e){var t=e.previousSibling,n=e.firstChild;t&&o(t,e)&&l(t)&&(C(e),t.appendChild(m(e)),n&&O(n))}function b(t,n,r){var o,i,a,d=e.createElement(t);if(n instanceof Array&&(r=n,n=null),n)for(o in n)d.setAttribute(o,n[o]);if(r)for(i=0,a=r.length;a>i;i+=1)d.appendChild(r[i]);return d}var E=2,x=1,D=3,B=1,A=4,I=1,L=3,R=0,w=1,P=2,U=3,k=e.defaultView,V=e.body,H=navigator.userAgent,z=/iP(?:ad|hone|od)/.test(H),M=/Mac OS X/.test(H),F=/Gecko\//.test(H),K=/Trident\//.test(H),q=8===k.ie,G=!!k.opera,Q=/WebKit\//.test(H),Y=M?"meta-":"ctrl-",$=K||G,j=K||Q,W=K,X=/\S/,Z=Array.prototype.indexOf,_={1:1,2:2,3:4,8:128,9:256,11:1024};t.prototype.nextNode=function(){for(var e,t=this.currentNode,n=this.root,r=this.nodeType,o=this.filter;;){for(e=t.firstChild;!e&&t&&t!==n;)e=t.nextSibling,e||(t=t.parentNode);if(!e)return null;if(_[e.nodeType]&r&&o(e)===I)return this.currentNode=e,e;t=e}},t.prototype.previousNode=function(){for(var e,t=this.currentNode,n=this.root,r=this.nodeType,o=this.filter;;){if(t===n)return null;if(e=t.previousSibling)for(;t=e.lastChild;)e=t;else e=t.parentNode;if(!e)return null;if(_[e.nodeType]&r&&o(e)===I)return this.currentNode=e,e;t=e}};var J=/^(?:#text|A(?:BBR|CRONYM)?|B(?:R|D[IO])?|C(?:ITE|ODE)|D(?:FN|EL)|EM|FONT|HR|I(?:NPUT|MG|NS)?|KBD|Q|R(?:P|T|UBY)|S(?:U[BP]|PAN|TRONG|AMP)|U)$/,et={BR:1,IMG:1,INPUT:1};(function(){var t=e.createElement("div"),n=e.createTextNode("12");return t.appendChild(n),n.splitText(2),2!==t.childNodes.length})()&&(Text.prototype.splitText=function(e){var t=this.ownerDocument.createTextNode(this.data.slice(e)),n=this.nextSibling,r=this.parentNode,o=this.length-e;return n?r.insertBefore(t,n):r.appendChild(t),o&&this.deleteData(e,o),t});var tt,nt=function(e,t){for(var n=e.childNodes;t&&e.nodeType===x;)e=n[t-1],n=e.childNodes,t=n.length;return e},rt=function(e,t){if(e.nodeType===x){var n=e.childNodes;if(n.length>t)e=n[t];else{for(;e&&!e.nextSibling;)e=e.parentNode;e&&(e=e.nextSibling)}}return e},ot=function(e,n){e=e.cloneRange(),ct(e);for(var r=e.startContainer,o=e.endContainer,i=e.commonAncestorContainer,a=new t(i,A,function(){return I},!1),d=a.currentNode=r;!n(d,e)&&d!==o&&(d=a.nextNode()););},it=function(e){var t="";return ot(e,function(e,n){var r=e.data;r&&/\S/.test(r)&&(e===n.endContainer&&(r=r.slice(0,n.endOffset)),e===n.startContainer&&(r=r.slice(n.startOffset)),t+=r)}),t},at=function(e,t){var n,r,o,i,a=e.startContainer,d=e.startOffset,l=e.endContainer,s=e.endOffset;a.nodeType===D?(n=a.parentNode,r=n.childNodes,d===a.length?(d=Z.call(r,a)+1,e.collapsed&&(l=n,s=d)):(d&&(i=a.splitText(d),l===a?(s-=d,l=i):l===n&&(s+=1),a=i),d=Z.call(r,a)),a=n):r=a.childNodes,o=r.length,d===o?a.appendChild(t):a.insertBefore(t,r[d]),a===l&&(s+=r.length-o),e.setStart(a,d),e.setEnd(l,s)},dt=function(e,t){var n=e.startContainer,r=e.startOffset,o=e.endContainer,i=e.endOffset;t||(t=e.commonAncestorContainer),t.nodeType===D&&(t=t.parentNode);for(var a,d=y(o,i,t),l=y(n,r,t),s=t.ownerDocument.createDocumentFragment();l!==d;)a=l.nextSibling,s.appendChild(l),l=a;return e.setStart(t,d?Z.call(t.childNodes,d):t.childNodes.length),e.collapse(!0),g(t),s},lt=function(e){ut(e),dt(e);var t=pt(e),n=ht(e);t&&n&&t!==n&&S(t,n,e),t&&g(t);var r=e.endContainer.ownerDocument.body,o=r.firstChild;o&&"BR"!==o.nodeName||(g(r),e.selectNodeContents(r.firstChild));var i=e.collapsed;ct(e),i&&e.collapse(!0)},st=function(e,t){for(var n=!0,r=t.childNodes,o=r.length;o--;)if(!a(r[o])){n=!1;break}if(e.collapsed||lt(e),ct(e),n)at(e,t),e.collapse(!1);else{for(var i,d,l=y(e.startContainer,e.startOffset,e.startContainer.ownerDocument.body),s=l.previousSibling,f=s,c=f.childNodes.length,p=l,h=0,C=l.parentNode;(i=f.lastChild)&&i.nodeType===x&&"BR"!==i.nodeName;)f=i,c=f.childNodes.length;for(;(i=p.firstChild)&&i.nodeType===x&&"BR"!==i.nodeName;)p=i;for(;(i=t.firstChild)&&a(i);)f.appendChild(i);for(;(i=t.lastChild)&&a(i);)p.insertBefore(i,p.firstChild),h+=1;for(d=t;d=u(d);)g(d);C.insertBefore(t,l),d=l.previousSibling,l.textContent?O(l):C.removeChild(l),l.parentNode||(p=d,h=N(p)),s.textContent?O(s):(f=s.nextSibling,c=0,C.removeChild(s)),e.setStart(f,c),e.setEnd(p,h),ct(e)}},ft=function(e,t,n){var r=t.ownerDocument.createRange();if(r.selectNode(t),n){var o=e.compareBoundaryPoints(U,r)>-1,i=1>e.compareBoundaryPoints(w,r);return!o&&!i}var a=1>e.compareBoundaryPoints(R,r),d=e.compareBoundaryPoints(P,r)>-1;return a&&d},ct=function(e){for(var t,n=e.startContainer,r=e.startOffset,o=e.endContainer,a=e.endOffset;n.nodeType!==D&&(t=n.childNodes[r],t&&!i(t));)n=t,r=0;if(a)for(;o.nodeType!==D&&(t=o.childNodes[a-1],t&&!i(t));)o=t,a=N(o);else for(;o.nodeType!==D&&(t=o.firstChild,t&&!i(t));)o=t;e.collapsed?(e.setStart(o,a),e.setEnd(n,r)):(e.setStart(n,r),e.setEnd(o,a))},ut=function(e,t){var n,r=e.startContainer,o=e.startOffset,i=e.endContainer,a=e.endOffset;for(t||(t=e.commonAncestorContainer);r!==t&&!o;)n=r.parentNode,o=Z.call(n.childNodes,r),r=n;for(;i!==t&&a===N(i);)n=i.parentNode,a=Z.call(n.childNodes,i)+1,i=n;e.setStart(r,o),e.setEnd(i,a)},pt=function(e){var t,n=e.startContainer;return a(n)?t=c(n):d(n)?t=n:(t=nt(n,e.startOffset),t=u(t)),t&&ft(e,t,!0)?t:null},ht=function(e){var t,n,r=e.endContainer;if(a(r))t=c(r);else if(d(r))t=r;else{if(t=rt(r,e.endOffset),!t)for(t=r.ownerDocument.body;n=t.lastChild;)t=n;t=c(t)}return t&&ft(e,t,!0)?t:null},Nt=function(e){for(var t,n,r=e.startContainer,o=e.startOffset;a(r);){if(o)return!1;t=r.parentNode,o=Z.call(t.childNodes,r),r=t}for(;o&&(n=r.childNodes[o-1])&&(""===n.data||"BR"===n.nodeName);)o-=1;return!o},Ct=function(e){for(var t,n,r=e.endContainer,o=e.endOffset,i=N(r);a(r);){if(o!==i)return!1;t=r.parentNode,o=Z.call(t.childNodes,r)+1,r=t,i=r.childNodes.length}for(;i>o&&(n=r.childNodes[o])&&(""===n.data||"BR"===n.nodeName);)o+=1;return o===i},vt=function(e){var t,n=pt(e),r=ht(e);n&&r&&(t=n.parentNode,e.setStart(t,Z.call(t.childNodes,n)),t=r.parentNode,e.setEnd(t,Z.call(t.childNodes,r)+1))},mt={focus:1,blur:1,pathChange:1,select:1,input:1,undoStateChange:1},gt={},yt=function(e,t){var n,r,o,i=gt[e];if(i)for(t||(t={}),t.type!==e&&(t.type=e),i=i.slice(),n=0,r=i.length;r>n;n+=1){o=i[n];try{o.handleEvent?o.handleEvent(t):o(t)}catch(a){a.details="Squire: fireEvent error. Event type: "+e,tt.didError(a)}}},Tt=function(e){yt(e.type,e)},St=function(t,n){var r=gt[t];return n?(r||(r=gt[t]=[],mt[t]||e.addEventListener(t,Tt,!1)),r.push(n),void 0):(tt.didError({name:"Squire: addEventListener with null or undefined fn",message:"Event type: "+t}),void 0)},Ot=function(t,n){var r,o=gt[t];if(o){for(r=o.length;r--;)o[r]===n&&o.splice(r,1);o.length||(delete gt[t],mt[t]||e.removeEventListener(t,Tt,!1))}},bt=function(t,n,r,o){if(t instanceof Range)return t.cloneRange();var i=e.createRange();return i.setStart(t,n),r?i.setEnd(r,o):i.setEnd(t,n),i},Et=k.getSelection(),xt=null,Dt=function(e){e&&(z&&k.focus(),Et.removeAllRanges(),Et.addRange(e))},Bt=function(){if(Et.rangeCount){xt=Et.getRangeAt(0).cloneRange();var e=xt.startContainer,t=xt.endContainer;try{e&&i(e)&&xt.setStartBefore(e),t&&i(t)&&xt.setEndBefore(t)}catch(n){tt.didError({name:"Squire#getSelection error",message:"Starts: "+e.nodeName+"\nEnds: "+t.nodeName})}}return xt};W&&k.addEventListener("beforedeactivate",Bt,!0);var At,It,Lt=null,Rt=!0,wt=!1,Pt=function(){Rt=!0,wt=!1,Ot("keydown",Pt)},Ut=function(){if(Rt){var e,t=Lt;if(Lt=null,t.parentNode){for(;(e=t.data.indexOf("​"))>-1;)t.deleteData(e,1);t.data||t.nextSibling||t.previousSibling||!a(t.parentNode)||C(t.parentNode)}}},kt=function(e){Lt&&(Rt=!0,Ut()),wt||(St("keydown",Pt),wt=!0),Rt=!1,Lt=e},Vt="",Ht=function(e,t){Lt&&!t&&Ut(e);var n,r=e.startContainer,o=e.endContainer;(t||r!==At||o!==It)&&(At=r,It=o,n=r&&o?r===o?h(o):"(selection)":"",Vt!==n&&(Vt=n,yt("pathChange",{path:n}))),r!==o&&yt("select")},zt=function(){Ht(Bt())};St("keyup",zt),St("mouseup",zt);var Mt=function(){F&&V.focus(),k.focus()},Ft=function(){F&&V.blur(),top.focus()};k.addEventListener("focus",Tt,!1),k.addEventListener("blur",Tt,!1);var Kt,qt,Gt,Qt,Yt=function(){return V.innerHTML},$t=function(e){var t=V;t.innerHTML=e;do g(t);while(t=u(t))},jt=function(e,t){if(t||(t=Bt()),t.collapse(!0),a(e))at(t,e),t.setStartAfter(e);else{for(var n,r,o=pt(t)||V;o!==V&&!o.nextSibling;)o=o.parentNode;o!==V&&(n=o.parentNode,r=y(n,o.nextSibling,V)),r?(V.insertBefore(e,r),t.setStart(r,0),t.setStart(r,0),ct(t)):(V.appendChild(e),V.appendChild(g(b("div"))),t.setStart(e,0),t.setEnd(e,0)),Mt(),Dt(t),Ht(t)}},Wt="squire-selection-start",Xt="squire-selection-end",Zt=function(e){var t,n=b("INPUT",{id:Wt,type:"hidden"}),r=b("INPUT",{id:Xt,type:"hidden"});at(e,n),e.collapse(!1),at(e,r),n.compareDocumentPosition(r)&E&&(n.id=Xt,r.id=Wt,t=n,n=r,r=t),e.setStartAfter(n),e.setEndBefore(r)},_t=function(t){var n=e.getElementById(Wt),r=e.getElementById(Xt);if(n&&r){var o,i=n.parentNode,a=r.parentNode,d={startContainer:i,endContainer:a,startOffset:Z.call(i.childNodes,n),endOffset:Z.call(a.childNodes,r)};i===a&&(d.endOffset-=1),C(n),C(r),T(i,d),i!==a&&T(a,d),t||(t=e.createRange()),t.setStart(d.startContainer,d.startOffset),t.setEnd(d.endContainer,d.endOffset),o=t.collapsed,ct(t),o&&t.collapse(!0)}return t||null},Jt=function(){Qt&&(Qt=!1,yt("undoStateChange",{canUndo:!0,canRedo:!1})),yt("input")};St("keyup",function(e){var t=e.keyCode;e.ctrlKey||e.metaKey||e.altKey||!(16>t||t>20)||!(33>t||t>45)||Jt()});var en=function(e){Qt||(Kt+=1,Gt>Kt&&(qt.length=Gt=Kt),e&&Zt(e),qt[Kt]=Yt(),Gt+=1,Qt=!0)},tn=function(){if(0!==Kt||!Qt){en(Bt()),Kt-=1,$t(qt[Kt]);var e=_t();e&&Dt(e),Qt=!0,yt("undoStateChange",{canUndo:0!==Kt,canRedo:!0}),yt("input")}},nn=function(){if(Gt>Kt+1&&Qt){Kt+=1,$t(qt[Kt]);var e=_t();e&&Dt(e),yt("undoStateChange",{canUndo:!0,canRedo:Gt>Kt+1}),yt("input")}},rn=function(e,n,r){if(e=e.toUpperCase(),n||(n={}),!r&&!(r=Bt()))return!1;var o,i,a=r.commonAncestorContainer;if(p(a,e,n))return!0;if(a.nodeType===D)return!1;o=new t(a,A,function(e){return ft(r,e,!0)?I:L},!1);for(var d=!1;i=o.nextNode();){if(!p(i,e,n))return!1;d=!0}return d},on=function(e,n,r){var o,i,a,d,l,s,f,c;if(r.collapsed)o=g(b(e,n)),at(r,o),r.setStart(o.firstChild,o.firstChild.length),r.collapse(!0);else{i=new t(r.commonAncestorContainer,A,function(e){return ft(r,e,!0)?I:L},!1),l=0,s=0,f=i.currentNode=r.startContainer,f.nodeType!==D&&(f=i.nextNode());do c=!p(f,e,n),f===r.endContainer&&(c&&f.length>r.endOffset?f.splitText(r.endOffset):s=r.endOffset),f===r.startContainer&&(c&&r.startOffset?f=f.splitText(r.startOffset):l=r.startOffset),c&&(o=b(e,n),v(f,o),o.appendChild(f),s=f.length),d=f,a||(a=d);while(f=i.nextNode());r=bt(a,l,d,s)}return r},an=function(t,n,o,i){Zt(o);var d;o.collapsed&&(j?(d=e.createTextNode("​"),kt(d)):d=e.createTextNode(""),at(o,d));for(var l=o.commonAncestorContainer;a(l);)l=l.parentNode;var s=o.startContainer,f=o.startOffset,c=o.endContainer,u=o.endOffset,p=[],h=function(e,t){if(!ft(o,e,!1)){var n,r,i=e.nodeType===D;if(!ft(o,e,!0))return"INPUT"===e.nodeName||i&&!e.data||p.push([t,e]),void 0;if(i)e===c&&u!==e.length&&p.push([t,e.splitText(u)]),e===s&&f&&(e.splitText(f),p.push([t,e]));else for(n=e.firstChild;n;n=r)r=n.nextSibling,h(n,t)}},N=Array.prototype.filter.call(l.getElementsByTagName(t),function(e){return ft(o,e,!0)&&r(e,t,n)});i||N.forEach(function(e){h(e,e)}),p.forEach(function(e){var t=e[0].cloneNode(!1),n=e[1];v(n,t),t.appendChild(n)}),N.forEach(function(e){v(e,m(e))}),_t(o),d&&o.collapse(!1);var C={startContainer:o.startContainer,startOffset:o.startOffset,endContainer:o.endContainer,endOffset:o.endOffset};return T(l,C),o.setStart(C.startContainer,C.startOffset),o.setEnd(C.endContainer,C.endOffset),o},dn=function(e,t,n,r){(n||(n=Bt()))&&(en(n),_t(n),t&&(n=an(t.tag.toUpperCase(),t.attributes||{},n,r)),e&&(n=on(e.tag.toUpperCase(),e.attributes||{},n)),Dt(n),Ht(n,!0),Jt())},ln={DIV:"DIV",PRE:"DIV",H1:"DIV",H2:"DIV",H3:"DIV",H4:"DIV",H5:"DIV",H6:"DIV",P:"DIV",DT:"DD",DD:"DT",LI:"LI"},sn=function(e,t,n){var r=ln[e.nodeName],o=y(t,n,e.parentNode);return o.nodeName!==r&&(e=b(r),e.className="rtl"===o.dir?"dir-rtl":"",e.dir=o.dir,v(o,e),e.appendChild(m(o)),o=e),o},fn=function(e,t,n){if(n||(n=Bt())){t&&(en(n),_t(n));var r=pt(n),o=ht(n);if(r&&o)do if(e(r)||r===o)break;while(r=u(r));t&&(Dt(n),Ht(n,!0),Jt())}},cn=function(e,t){if(t||(t=Bt())){G||V.setAttribute("contenteditable","false"),Qt?Zt(t):en(t),vt(t),ut(t,V);var n=dt(t,V);at(t,e(n)),t.endOffsetn;n+=1)o=e[n],i=o.nodeName,d(o)?"LI"!==i&&(s=b("LI",{"class":"rtl"===o.dir?"dir-rtl":"",dir:o.dir},[m(o)]),o.parentNode.nodeName===t?v(o,s):(a=o.previousSibling)&&a.nodeName===t?(a.appendChild(s),C(o),n-=1,r-=1):v(o,b(t,[s]))):l(o)&&(i!==t&&/^[DOU]L$/.test(i)?v(o,b(t,[m(o)])):Nn(o.childNodes,t))},Cn=function(e){return Nn(e.childNodes,"UL"),e},vn=function(e){return Nn(e.childNodes,"OL"),e},mn=function(e){var t=e.querySelectorAll("UL, OL");return Array.prototype.filter.call(t,function(e){return!p(e.parentNode,"UL")&&!p(e.parentNode,"OL")}).forEach(function(e){for(var t,n=m(e),r=n.childNodes,o=r.length;o--;)t=r[o],"LI"===t.nodeName&&n.replaceChild(b("DIV",{"class":"rtl"===t.dir?"dir-rtl":"",dir:t.dir},[m(t)]),t);v(e,n)}),e},gn=/\b((?:(?:ht|f)tps?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\([^\s()<>]+\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])|(?:[\w\-.%+]+@(?:[\w\-]+\.)+[A-Z]{2,4}))/i,yn=function(e){for(var n,r,o,i,a,d,l,s=e.ownerDocument,f=new t(e,A,function(e){return p(e,"A")?L:I},!1);n=f.nextNode();)if(r=n.data.split(gn),i=r.length,i>1){for(d=n.parentNode,l=n.nextSibling,o=0;i>o;o+=1)a=r[o],o?(o%2?(n=s.createElement("A"),n.textContent=a,n.href=/@/.test(a)?"mailto:"+a:/^(?:ht|f)tps?:/.test(a)?a:"http://"+a):n=s.createTextNode(a),l?d.insertBefore(n,l):d.appendChild(n)):n.data=a;f.currentNode=n}},Tn=/^(?:A(?:DDRESS|RTICLE|SIDE)|BLOCKQUOTE|CAPTION|D(?:[DLT]|IV)|F(?:IGURE|OOTER)|H[1-6]|HEADER|L(?:ABEL|EGEND|I)|O(?:L|UTPUT)|P(?:RE)?|SECTION|T(?:ABLE|BODY|D|FOOT|H|HEAD|R)|UL)$/,Sn={1:10,2:13,3:16,4:18,5:24,6:32,7:48},On={backgroundColor:{regexp:X,replace:function(e){return b("SPAN",{"class":"highlight",style:"background-color: "+e})}},color:{regexp:X,replace:function(e){return b("SPAN",{"class":"colour",style:"color:"+e})}},fontWeight:{regexp:/^bold/i,replace:function(){return b("B")}},fontStyle:{regexp:/^italic/i,replace:function(){return b("I")}},fontFamily:{regexp:X,replace:function(e){return b("SPAN",{"class":"font",style:"font-family:"+e})}},fontSize:{regexp:X,replace:function(e){return b("SPAN",{"class":"size",style:"font-size:"+e})}}},bn={SPAN:function(e,t){var n,r,o,i,a,d,l=e.style;for(n in On)r=On[n],o=l[n],o&&r.regexp.test(o)&&(d=r.replace(o),i&&i.appendChild(d),i=d,a||(a=d));return a&&(i.appendChild(m(e)),t.replaceChild(a,e)),i||e},STRONG:function(e,t){var n=b("B");return t.replaceChild(n,e),n.appendChild(m(e)),n},EM:function(e,t){var n=b("I");return t.replaceChild(n,e),n.appendChild(m(e)),n},FONT:function(e,t){var n,r,o,i,a=e.face,d=e.size;return a&&(n=b("SPAN",{"class":"font",style:"font-family:"+a})),d&&(r=b("SPAN",{"class":"size",style:"font-size:"+Sn[d]+"px"}),n&&n.appendChild(r)),i=n||r||b("SPAN"),o=r||n||i,t.replaceChild(i,e),o.appendChild(m(e)),o},TT:function(e,t){var n=b("SPAN",{"class":"font",style:'font-family:menlo,consolas,"courier new",monospace'});return t.replaceChild(n,e),n.appendChild(m(e)),n}},En=function(e){for(var t,n=e.childNodes,r=n.length;r--;)t=n[r],t.nodeType===x&&"IMG"!==t.nodeName&&(En(t),a(t)&&!t.firstChild&&e.removeChild(t))},xn=function(e,t){var n,r,o,i,d,l,s,f=e.childNodes;for(n=0,r=f.length;r>n;n+=1)if(o=f[n],i=o.nodeName,d=o.nodeType,l=bn[i],d===x){if(s=o.childNodes.length,l)o=l(o,e);else{if(!Tn.test(i)&&!a(o)){n-=1,r+=s-1,e.replaceChild(m(o),o);continue}!t&&o.style.cssText&&o.removeAttribute("style")}s&&xn(o,t)}else d===D&&(X.test(o.data)||n>0&&a(f[n-1])||r>n+1&&a(f[n+1]))||(e.removeChild(o),n-=1,r-=1);return e},Dn=function(e,t){var n,r,o,i,d=e.childNodes,l=null;for(n=0,r=d.length;r>n;n+=1)o=d[n],i="BR"===o.nodeName,!i&&a(o)?(l||(l=b(t)),l.appendChild(o),n-=1,r-=1):(i||l)&&(l||(l=b(t)),g(l),i?e.replaceChild(l,o):(e.insertBefore(l,o),n+=1,r+=1),l=null);return l&&e.appendChild(g(l)),e},Bn=function(e){return(e.nodeType===x?"BR"===e.nodeName:X.test(e.data))?I:L},An=function(e){for(var n,r=e.parentNode;a(r);)r=r.parentNode;return n=new t(r,B|A,Bn),n.currentNode=e,!!n.nextNode()},In=function(e){var t,n,r,o=e.querySelectorAll("BR"),i=[],l=o.length;for(t=0;l>t;t+=1)i[t]=An(o[t]);for(;l--;)if(n=o[l],r=n.parentNode){for(;a(r);)r=r.parentNode;d(r)&&ln[r.nodeName]?(i[l]&&sn(r,n.parentNode,n),C(n)):Dn(r,"DIV")}},Ln=function(){try{g(V)}catch(e){tt.didError(e)}};St(K?"beforecut":"cut",function(){var e=Bt();en(e),_t(e),Dt(e),setTimeout(Ln,0)});var Rn=!1;St(K?"beforepaste":"paste",function(e){if(!Rn){var t,n,r=e.clipboardData,o=r&&r.items,i=!1,a=!1;if(o){for(t=o.length;t--;){if(n=o[t].type,"text/html"===n){a=!1;break}/^image\/.*/.test(n)&&(a=!0)}if(a)return e.preventDefault(),yt("dragover",{dataTransfer:r,preventDefault:function(){i=!0}}),i&&yt("drop",{dataTransfer:r}),void 0}Rn=!0;var d=Bt(),l=d.startContainer,s=d.startOffset,f=d.endContainer,c=d.endOffset,p=b("DIV",{style:"position: absolute; overflow: hidden; top:"+(V.scrollTop+30)+"px; left: 0; width: 1px; height: 1px;"});V.appendChild(p),d.selectNodeContents(p),Dt(d),setTimeout(function(){try{var e=m(C(p)),t=e.firstChild,n=bt(l,s,f,c);if(t){t===e.lastChild&&"DIV"===t.nodeName&&e.replaceChild(m(t),t),e.normalize(),yn(e),xn(e,!1),In(e),En(e);for(var r=e,o=!0;r=u(r);)g(r);yt("willPaste",{fragment:e,preventDefault:function(){o=!1}}),o&&(st(n,e),Jt(),n.collapse(!1))}Dt(n),Ht(n,!0),Rn=!1}catch(i){tt.didError(i)}},0)}});var wn={8:"backspace",9:"tab",13:"enter",32:"space",37:"left",39:"right",46:"delete"},Pn=function(e){return function(t){t.preventDefault(),e()}},Un=function(e){return function(t){t.preventDefault();var n=Bt();rn(e,null,n)?dn(null,{tag:e},n):dn({tag:e},null,n)}},kn=function(){try{var e,t=Bt(),n=t.startContainer;if(n.nodeType===D&&(n=n.parentNode),a(n)&&!n.textContent){do e=n.parentNode;while(a(e)&&!e.textContent&&(n=e));t.setStart(e,Z.call(e.childNodes,n)),t.collapse(!0),e.removeChild(n),d(e)||(e=c(e)),g(e),ct(t),Dt(t),Ht(t)}}catch(r){tt.didError(r)}};q&&St("keyup",function(){var e=V.firstChild;"P"===e.nodeName&&(Zt(Bt()),v(e,b("DIV",[m(e)])),Dt(_t()))});var Vn={enter:function(t){t.preventDefault();var n=Bt();if(n){en(n),yn(n.startContainer),_t(n),n.collapsed||lt(n);var r,o=pt(n),i=o?o.nodeName:"DIV",a=ln[i];if(!o)return at(n,b("BR")),n.collapse(!1),Dt(n),Ht(n,!0),Jt(),void 0;var d,l=n.startContainer,s=n.startOffset;if(a||(l===o&&(l=s?l.childNodes[s-1]:null,s=0,l&&("BR"===l.nodeName?l=l.nextSibling:s=N(l),l&&"BR"!==l.nodeName||(d=g(b("DIV")),l?o.replaceChild(d,l):o.appendChild(d),l=d))),Dn(o,"DIV"),a="DIV",l||(l=o.firstChild),n.setStart(l,s),n.setEnd(l,s),o=pt(n)),!o.textContent){if(p(o,"UL")||p(o,"OL"))return cn(mn,n);if(p(o,"BLOCKQUOTE"))return cn(hn,n)}for(r=sn(o,l,s);r.nodeType===x;){var f,c=r.firstChild;if("A"!==r.nodeName){for(;c&&c.nodeType===D&&!c.data&&(f=c.nextSibling,f&&"BR"!==f.nodeName);)C(c),c=f;if(!c||"BR"===c.nodeName||c.nodeType===D&&!G)break;r=c}else v(r,m(r)),r=c}n=bt(r,0),Dt(n),Ht(n,!0),r.nodeType===D&&(r=r.parentNode),r.offsetTop+r.offsetHeight>(e.documentElement.scrollTop||V.scrollTop)+V.offsetHeight&&r.scrollIntoView(!1),Jt()}},backspace:function(e){var t=Bt();if(t.collapsed)if(Nt(t)){en(t),_t(t),e.preventDefault();var n=pt(t),r=n&&c(n);if(r){if(!r.isContentEditable)return C(r),void 0;for(S(r,n,t),n=r.parentNode;n&&!n.nextSibling;)n=n.parentNode;n&&(n=n.nextSibling)&&O(n),Dt(t)}else if(n){if(p(n,"UL")||p(n,"OL"))return cn(mn,t);if(p(n,"BLOCKQUOTE"))return cn(pn,t);Dt(t),Ht(t,!0)}}else{var o=t.startContainer.data||"";X.test(o.charAt(t.startOffset-1))||(en(t),_t(t),Dt(t)),setTimeout(kn,0)}else en(t),_t(t),e.preventDefault(),lt(t),Dt(t),Ht(t,!0)},"delete":function(e){var t=Bt();if(t.collapsed)if(Ct(t)){en(t),_t(t),e.preventDefault();var n=pt(t),r=n&&u(n);if(r){if(!r.isContentEditable)return C(r),void 0;for(S(n,r,t),r=n.parentNode;r&&!r.nextSibling;)r=r.parentNode;r&&(r=r.nextSibling)&&O(r),Dt(t),Ht(t,!0)}}else{var o=t.startContainer.data||"";X.test(o.charAt(t.startOffset))||(en(t),_t(t),Dt(t)),setTimeout(kn,0)}else en(t),_t(t),e.preventDefault(),lt(t),Dt(t),Ht(t,!0)},space:function(){var e=Bt();en(e),yn(e.startContainer),_t(e),Dt(e)}};M&&F&&Et.modify&&(Vn["meta-left"]=function(e){e.preventDefault(),Et.modify("move","backward","lineboundary")},Vn["meta-right"]=function(e){e.preventDefault(),Et.modify("move","forward","lineboundary")}),Vn[Y+"b"]=Un("B"),Vn[Y+"i"]=Un("I"),Vn[Y+"u"]=Un("U"),Vn[Y+"y"]=Pn(nn),Vn[Y+"z"]=Pn(tn),Vn[Y+"shift-z"]=Pn(nn),St(G?"keypress":"keydown",function(e){var t=e.keyCode,n=wn[t]||String.fromCharCode(t).toLowerCase(),r="";G&&46===e.which&&(n="."),t>111&&124>t&&(n="f"+(t-111)),e.altKey&&(r+="alt-"),e.ctrlKey&&(r+="ctrl-"),e.metaKey&&(r+="meta-"),e.shiftKey&&(r+="shift-"),n=r+n,Vn[n]&&Vn[n](e)});var Hn=function(e){return function(){return e.apply(null,arguments),this}},zn=function(e,t,n){return function(){return e(t,n),Mt(),this}};tt=k.editor={didError:function(e){console.log(e)},addEventListener:Hn(St),removeEventListener:Hn(Ot),focus:Hn(Mt),blur:Hn(Ft),getDocument:function(){return e},addStyles:function(t){if(t){var n=e.documentElement.firstChild,r=b("STYLE",{type:"text/css"});r.styleSheet?(n.appendChild(r),r.styleSheet.cssText=t):(r.appendChild(e.createTextNode(t)),n.appendChild(r))}return this},getHTML:function(e){var t,n,r,o,i,a=[];if(e&&(i=Bt())&&Zt(i),$)for(t=V;t=u(t);)t.textContent||t.querySelector("BR")||(n=b("BR"),t.appendChild(n),a.push(n));if(r=Yt(),$)for(o=a.length;o--;)C(a[o]);return i&&_t(i),r},setHTML:function(t){var n,r=e.createDocumentFragment(),o=b("DIV");o.innerHTML=t,r.appendChild(m(o)),xn(r,!0),In(r),Dn(r,"DIV");for(var i=r;i=u(i);)g(i);for(;n=V.lastChild;)V.removeChild(n);V.appendChild(r),g(V),Kt=-1,qt=[],Gt=0,Qt=!1;var a=_t()||bt(V.firstChild,0);return en(a),_t(a),W?xt=a:Dt(a),Ht(a,!0),this},getSelectedText:function(){return it(Bt())},insertElement:Hn(jt),insertImage:function(e){var t=b("IMG",{src:e});return jt(t),t},getPath:function(){return Vt},getSelection:Bt,setSelection:Hn(Dt),undo:Hn(tn),redo:Hn(nn),hasFormat:rn,changeFormat:Hn(dn),bold:zn(dn,{tag:"B"}),italic:zn(dn,{tag:"I"}),underline:zn(dn,{tag:"U"}),removeBold:zn(dn,null,{tag:"B"}),removeItalic:zn(dn,null,{tag:"I"}),removeUnderline:zn(dn,null,{tag:"U"}),makeLink:function(t){t=encodeURI(t);var n=Bt();if(n.collapsed){var r=t.indexOf(":")+1;if(r)for(;"/"===t[r];)r+=1;n._insertNode(e.createTextNode(t.slice(r)))}return dn({tag:"A",attributes:{href:t}},{tag:"A"},n),Mt(),this},removeLink:function(){return dn(null,{tag:"A"},Bt(),!0),Mt(),this},setFontFace:function(e){return dn({tag:"SPAN",attributes:{"class":"font",style:"font-family: "+e+", sans-serif;"}},{tag:"SPAN",attributes:{"class":"font"}}),Mt(),this},setFontSize:function(e){return dn({tag:"SPAN",attributes:{"class":"size",style:"font-size: "+("number"==typeof e?e+"px":e)}},{tag:"SPAN",attributes:{"class":"size"}}),Mt(),this},setTextColour:function(e){return dn({tag:"SPAN",attributes:{"class":"colour",style:"color: "+e}},{tag:"SPAN",attributes:{"class":"colour"}}),Mt(),this},setHighlightColour:function(e){return dn({tag:"SPAN",attributes:{"class":"highlight",style:"background-color: "+e}},{tag:"SPAN",attributes:{"class":"highlight"}}),Mt(),this},setTextAlignment:function(e){return fn(function(t){t.className=(t.className.split(/\s+/).filter(function(e){return!/align/.test(e)}).join(" ")+" align-"+e).trim(),t.style.textAlign=e},!0),Mt(),this},setTextDirection:function(e){return fn(function(t){t.className=(t.className.split(/\s+/).filter(function(e){return!/dir/.test(e)}).join(" ")+" dir-"+e).trim(),t.dir=e},!0),Mt(),this},forEachBlock:Hn(fn),modifyBlocks:Hn(cn),increaseQuoteLevel:zn(cn,un),decreaseQuoteLevel:zn(cn,pn),makeUnorderedList:zn(cn,Cn),makeOrderedList:zn(cn,vn),removeList:zn(cn,mn)},V.setAttribute("contenteditable","true"),tt.setHTML(""),k.onEditorLoad&&(k.onEditorLoad(k.editor),k.onEditorLoad=null)})(document); \ No newline at end of file diff --git a/source/Editor.js b/source/Editor.js index e78ad89..a23d8db 100644 --- a/source/Editor.js +++ b/source/Editor.js @@ -44,6 +44,21 @@ mergeContainers, createElement, + forEachTextNodeInRange, + getTextContentInRange, + insertNodeInRange, + extractContentsOfRange, + deleteContentsOfRange, + insertTreeFragmentIntoRange, + isNodeContainedInRange, + moveRangeBoundariesDownTree, + moveRangeBoundariesUpTree, + getStartBlockOfRange, + getEndBlockOfRange, + rangeDoesStartAtBlockBoundary, + rangeDoesEndAtBlockBoundary, + expandRangeToBlockBoundaries, + Range, top, console, @@ -321,11 +336,11 @@ var insertElement = function ( el, range ) { if ( !range ) { range = getSelection(); } range.collapse( true ); if ( isInline( el ) ) { - range._insertNode( el ); + insertNodeInRange( range, el ); range.setStartAfter( el ); } else { // Get containing block node. - var splitNode = range.getStartBlock() || body, + var splitNode = getStartBlockOfRange( range ) || body, parent, nodeAfterSplit; // While at end of container node, move up DOM tree. while ( splitNode !== body && !splitNode.nextSibling ) { @@ -340,7 +355,7 @@ var insertElement = function ( el, range ) { body.insertBefore( el, nodeAfterSplit ); range.setStart( nodeAfterSplit, 0 ); range.setStart( nodeAfterSplit, 0 ); - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); } else { body.appendChild( el ); // Insert blank line below block. @@ -370,9 +385,9 @@ var saveRangeToBookmark = function ( range ) { }), temp; - range._insertNode( startNode ); + insertNodeInRange( range, startNode ); range.collapse( false ); - range._insertNode( endNode ); + insertNodeInRange( range, endNode ); // In a collapsed range, the start is sometimes inserted after the end! if ( startNode.compareDocumentPosition( endNode ) & @@ -424,7 +439,7 @@ var getRangeAndRemoveBookmark = function ( range ) { range.setEnd( _range.endContainer, _range.endOffset ); collapsed = range.collapsed; - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); if ( collapsed ) { range.collapse( true ); } @@ -554,7 +569,7 @@ var hasFormat = function ( tag, attributes, range ) { // Otherwise, check each text node at least partially contained within // the selection and make sure all of them have the format we want. walker = new TreeWalker( root, SHOW_TEXT, function ( node ) { - return range.containsNode( node, true ) ? + return isNodeContainedInRange( range, node, true ) ? FILTER_ACCEPT : FILTER_SKIP; }, false ); @@ -577,7 +592,7 @@ var addFormat = function ( tag, attributes, range ) { if ( range.collapsed ) { el = fixCursor( createElement( tag, attributes ) ); - range._insertNode( el ); + insertNodeInRange( range, el ); range.setStart( el.firstChild, el.firstChild.length ); range.collapse( true ); } @@ -594,7 +609,7 @@ var addFormat = function ( tag, attributes, range ) { range.commonAncestorContainer, SHOW_TEXT, function ( node ) { - return range.containsNode( node, true ) ? + return isNodeContainedInRange( range, node, true ) ? FILTER_ACCEPT : FILTER_SKIP; }, false @@ -657,7 +672,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { } else { fixer = doc.createTextNode( '' ); } - range._insertNode( fixer ); + insertNodeInRange( range, fixer ); } // Find block-level ancestor of selection @@ -676,7 +691,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { examineNode = function ( node, exemplar ) { // If the node is completely contained by the range then // we're going to remove all formatting so ignore it. - if ( range.containsNode( node, false ) ) { + if ( isNodeContainedInRange( range, node, false ) ) { return; } @@ -685,7 +700,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { // If not at least partially contained, wrap entire contents // in a clone of the tag we're removing and we're done. - if ( !range.containsNode( node, true ) ) { + if ( !isNodeContainedInRange( range, node, true ) ) { // Ignore bookmarks and empty text nodes if ( node.nodeName !== 'INPUT' && ( !isText || node.data ) ) { @@ -716,7 +731,7 @@ var removeFormat = function ( tag, attributes, range, partial ) { }, formatTags = Array.prototype.filter.call( root.getElementsByTagName( tag ), function ( el ) { - return range.containsNode( el, true ) && + return isNodeContainedInRange( range, el, true ) && hasTagAttributes( el, tag, attributes ); } ); @@ -828,8 +843,8 @@ var forEachBlock = function ( fn, mutates, range ) { getRangeAndRemoveBookmark( range ); } - var start = range.getStartBlock(), - end = range.getEndBlock(); + var start = getStartBlockOfRange( range ), + end = getEndBlockOfRange( range ); if ( start && end ) { do { if ( fn( start ) || start === end ) { break; } @@ -866,14 +881,14 @@ var modifyBlocks = function ( modify, range ) { } // 3. Expand range to block boundaries - range.expandToBlockBoundaries(); + expandRangeToBlockBoundaries( range ); // 4. Remove range. - range.moveBoundariesUpTree( body ); - var frag = range._extractContents( body ); + moveRangeBoundariesUpTree( range, body ); + var frag = extractContentsOfRange( range, body ); // 5. Modify tree of fragment and reinsert. - range._insertNode( modify( frag ) ); + insertNodeInRange( range, modify( frag ) ); // 6. Merge containers at edges if ( range.endOffset < range.endContainer.childNodes.length ) { @@ -1457,7 +1472,7 @@ addEventListener( isIE ? 'beforepaste' : 'paste', function ( event ) { // Insert pasted data if ( doPaste ) { - range.insertTreeFragment( frag ); + insertTreeFragmentIntoRange( range, frag ); docWasChanged(); range.collapse( false ); @@ -1531,7 +1546,7 @@ var afterDelete = function () { parent = getPreviousBlock( parent ); } fixCursor( parent ); - range.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); setSelection( range ); updatePath( range ); } @@ -1572,10 +1587,10 @@ var keyHandlers = { // Selected text is overwritten, therefore delete the contents // to collapse selection. if ( !range.collapsed ) { - range._deleteContents(); + deleteContentsOfRange( range ); } - var block = range.getStartBlock(), + var block = getStartBlockOfRange( range ), tag = block ? block.nodeName : 'DIV', splitTag = tagAfterSplit[ tag ], nodeAfterSplit; @@ -1583,7 +1598,7 @@ var keyHandlers = { // If this is a malformed bit of document, just play it safe // and insert a
. if ( !block ) { - range._insertNode( createElement( 'BR' ) ); + insertNodeInRange( range, createElement( 'BR' ) ); range.collapse( false ); setSelection( range ); updatePath( range, true ); @@ -1627,7 +1642,7 @@ var keyHandlers = { } range.setStart( splitNode, splitOffset ); range.setEnd( splitNode, splitOffset ); - block = range.getStartBlock(); + block = getStartBlockOfRange( range ); } if ( !block.textContent ) { @@ -1701,16 +1716,16 @@ var keyHandlers = { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - range._deleteContents(); + deleteContentsOfRange( range ); setSelection( range ); updatePath( range, true ); } // If at beginning of block, merge with previous - else if ( range.startsAtBlockBoundary() ) { + else if ( rangeDoesStartAtBlockBoundary( range ) ) { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - var current = range.getStartBlock(), + var current = getStartBlockOfRange( range ), previous = current && getPreviousBlock( current ); // Must not be at the very beginning of the text area. if ( previous ) { @@ -1767,16 +1782,16 @@ var keyHandlers = { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - range._deleteContents(); + deleteContentsOfRange( range ); setSelection( range ); updatePath( range, true ); } // If at end of block, merge next into this block - else if ( range.endsAtBlockBoundary() ) { + else if ( rangeDoesEndAtBlockBoundary( range ) ) { recordUndoState( range ); getRangeAndRemoveBookmark( range ); event.preventDefault(); - var current = range.getStartBlock(), + var current = getStartBlockOfRange( range ), next = current && getNextBlock( current ); // Must not be at the very end of the text area. if ( next ) { @@ -2009,7 +2024,7 @@ editor = win.editor = { }, getSelectedText: function () { - return getSelection().getTextContent(); + return getTextContentInRange( getSelection() ); }, insertElement: chain( insertElement ), diff --git a/source/Range.js b/source/Range.js index 1997a1d..3efdde1 100644 --- a/source/Range.js +++ b/source/Range.js @@ -20,9 +20,7 @@ fixCursor, split, mergeWithBlock, - mergeContainers, - - Range + mergeContainers */ /*jshint strict:false */ @@ -51,11 +49,11 @@ var getNodeAfter = function ( node, offset ) { return node; }; -var RangePrototype = Range.prototype; +// --- -RangePrototype.forEachTextNode = function ( fn ) { - var range = this.cloneRange(); - range.moveBoundariesDownTree(); +var forEachTextNodeInRange = function ( range, fn ) { + range = range.cloneRange(); + moveRangeBoundariesDownTree( range ); var startContainer = range.startContainer, endContainer = range.endContainer, @@ -71,9 +69,9 @@ RangePrototype.forEachTextNode = function ( fn ) { ( textnode = walker.nextNode() ) ) {} }; -RangePrototype.getTextContent = function () { +var getTextContentInRange = function ( range ) { var textContent = ''; - this.forEachTextNode( function ( textnode, range ) { + forEachTextNodeInRange( range, function ( textnode, range ) { var value = textnode.data; if ( value && ( /\S/.test( value ) ) ) { if ( textnode === range.endContainer ) { @@ -90,12 +88,12 @@ RangePrototype.getTextContent = function () { // --- -RangePrototype._insertNode = function ( node ) { +var insertNodeInRange = function ( range, node ) { // Insert at start. - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, parent, children, childCount, afterSplit; // If part way through a text node, split it. @@ -104,7 +102,7 @@ RangePrototype._insertNode = function ( node ) { children = parent.childNodes; if ( startOffset === startContainer.length ) { startOffset = indexOf.call( children, startContainer ) + 1; - if ( this.collapsed ) { + if ( range.collapsed ) { endContainer = parent; endOffset = startOffset; } @@ -138,20 +136,18 @@ RangePrototype._insertNode = function ( node ) { endOffset += children.length - childCount; } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - - return this; + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); }; -RangePrototype._extractContents = function ( common ) { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset; +var extractContentsOfRange = function ( range, common ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset; if ( !common ) { - common = this.commonAncestorContainer; + common = range.commonAncestorContainer; } if ( common.nodeType === TEXT_NODE ) { @@ -170,28 +166,28 @@ RangePrototype._extractContents = function ( common ) { startNode = next; } - this.setStart( common, endNode ? + range.setStart( common, endNode ? indexOf.call( common.childNodes, endNode ) : common.childNodes.length ); - this.collapse( true ); + range.collapse( true ); fixCursor( common ); return frag; }; -RangePrototype._deleteContents = function () { +var deleteContentsOfRange = function ( range ) { // Move boundaries up as much as possible to reduce need to split. - this.moveBoundariesUpTree(); + moveRangeBoundariesUpTree( range ); // Remove selected range - this._extractContents(); + extractContentsOfRange( range ); // If we split into two different blocks, merge the blocks. - var startBlock = this.getStartBlock(), - endBlock = this.getEndBlock(); + var startBlock = getStartBlockOfRange( range ), + endBlock = getEndBlockOfRange( range ); if ( startBlock && endBlock && startBlock !== endBlock ) { - mergeWithBlock( startBlock, endBlock, this ); + mergeWithBlock( startBlock, endBlock, range ); } // Ensure block has necessary children @@ -200,27 +196,25 @@ RangePrototype._deleteContents = function () { } // Ensure body has a block-level element in it. - var body = this.endContainer.ownerDocument.body, + var body = range.endContainer.ownerDocument.body, child = body.firstChild; if ( !child || child.nodeName === 'BR' ) { fixCursor( body ); - this.selectNodeContents( body.firstChild ); + range.selectNodeContents( body.firstChild ); } // Ensure valid range (must have only block or inline containers) - var isCollapsed = this.collapsed; - this.moveBoundariesDownTree(); + var isCollapsed = range.collapsed; + moveRangeBoundariesDownTree( range ); if ( isCollapsed ) { // Collapse - this.collapse( true ); + range.collapse( true ); } - - return this; }; // --- -RangePrototype.insertTreeFragment = function ( frag ) { +var insertTreeFragmentIntoRange = function ( range, frag ) { // Check if it's all inline content var allInline = true, children = frag.childNodes, @@ -233,23 +227,23 @@ RangePrototype.insertTreeFragment = function ( frag ) { } // Delete any selected content - if ( !this.collapsed ) { - this._deleteContents(); + if ( !range.collapsed ) { + deleteContentsOfRange( range ); } // Move range down into text ndoes - this.moveBoundariesDownTree(); + moveRangeBoundariesDownTree( range ); // If inline, just insert at the current position. if ( allInline ) { - this._insertNode( frag ); - this.collapse( false ); + insertNodeInRange( range, frag ); + range.collapse( false ); } // Otherwise, split up to body, insert inline before and after split // and insert block in between split, then merge containers. else { - var nodeAfterSplit = split( this.startContainer, this.startOffset, - this.startContainer.ownerDocument.body ), + var nodeAfterSplit = split( range.startContainer, range.startOffset, + range.startContainer.ownerDocument.body ), nodeBeforeSplit = nodeAfterSplit.previousSibling, startContainer = nodeBeforeSplit, startOffset = startContainer.childNodes.length, @@ -305,17 +299,16 @@ RangePrototype.insertTreeFragment = function ( frag ) { mergeContainers( nodeBeforeSplit ); } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - this.moveBoundariesDownTree(); + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); + moveRangeBoundariesDownTree( range ); } }; // --- -RangePrototype.containsNode = function ( node, partial ) { - var range = this, - nodeRange = node.ownerDocument.createRange(); +var isNodeContainedInRange = function ( range, node, partial ) { + var nodeRange = node.ownerDocument.createRange(); nodeRange.selectNode( node ); @@ -339,11 +332,11 @@ RangePrototype.containsNode = function ( node, partial ) { } }; -RangePrototype.moveBoundariesDownTree = function () { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, +var moveRangeBoundariesDownTree = function ( range ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, child; while ( startContainer.nodeType !== TEXT_NODE ) { @@ -376,26 +369,24 @@ RangePrototype.moveBoundariesDownTree = function () { // If collapsed, this algorithm finds the nearest text node positions // *outside* the range rather than inside, but also it flips which is // assigned to which. - if ( this.collapsed ) { - this.setStart( endContainer, endOffset ); - this.setEnd( startContainer, startOffset ); + if ( range.collapsed ) { + range.setStart( endContainer, endOffset ); + range.setEnd( startContainer, startOffset ); } else { - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); } - - return this; }; -RangePrototype.moveBoundariesUpTree = function ( common ) { - var startContainer = this.startContainer, - startOffset = this.startOffset, - endContainer = this.endContainer, - endOffset = this.endOffset, +var moveRangeBoundariesUpTree = function ( range, common ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, + endContainer = range.endContainer, + endOffset = range.endOffset, parent; if ( !common ) { - common = this.commonAncestorContainer; + common = range.commonAncestorContainer; } while ( startContainer !== common && !startOffset ) { @@ -411,16 +402,14 @@ RangePrototype.moveBoundariesUpTree = function ( common ) { endContainer = parent; } - this.setStart( startContainer, startOffset ); - this.setEnd( endContainer, endOffset ); - - return this; + range.setStart( startContainer, startOffset ); + range.setEnd( endContainer, endOffset ); }; // Returns the first block at least partially contained by the range, // or null if no block is contained by the range. -RangePrototype.getStartBlock = function () { - var container = this.startContainer, +var getStartBlockOfRange = function ( range ) { + var container = range.startContainer, block; // If inline, get the containing block. @@ -429,17 +418,17 @@ RangePrototype.getStartBlock = function () { } else if ( isBlock( container ) ) { block = container; } else { - block = getNodeBefore( container, this.startOffset ); + block = getNodeBefore( container, range.startOffset ); block = getNextBlock( block ); } // Check the block actually intersects the range - return block && this.containsNode( block, true ) ? block : null; + return block && isNodeContainedInRange( range, block, true ) ? block : null; }; // Returns the last block at least partially contained by the range, // or null if no block is contained by the range. -RangePrototype.getEndBlock = function () { - var container = this.endContainer, +var getEndBlockOfRange = function ( range ) { + var container = range.endContainer, block, child; // If inline, get the containing block. @@ -448,7 +437,7 @@ RangePrototype.getEndBlock = function () { } else if ( isBlock( container ) ) { block = container; } else { - block = getNodeAfter( container, this.endOffset ); + block = getNodeAfter( container, range.endOffset ); if ( !block ) { block = container.ownerDocument.body; while ( child = block.lastChild ) { @@ -459,12 +448,12 @@ RangePrototype.getEndBlock = function () { } // Check the block actually intersects the range - return block && this.containsNode( block, true ) ? block : null; + return block && isNodeContainedInRange( range, block, true ) ? block : null; }; -RangePrototype.startsAtBlockBoundary = function () { - var startContainer = this.startContainer, - startOffset = this.startOffset, +var rangeDoesStartAtBlockBoundary = function ( range ) { + var startContainer = range.startContainer, + startOffset = range.startOffset, parent, child; while ( isInline( startContainer ) ) { @@ -484,9 +473,9 @@ RangePrototype.startsAtBlockBoundary = function () { return !startOffset; }; -RangePrototype.endsAtBlockBoundary = function () { - var endContainer = this.endContainer, - endOffset = this.endOffset, +var rangeDoesEndAtBlockBoundary = function ( range ) { + var endContainer = range.endContainer, + endOffset = range.endOffset, length = getLength( endContainer ), parent, child; @@ -508,17 +497,15 @@ RangePrototype.endsAtBlockBoundary = function () { return endOffset === length; }; -RangePrototype.expandToBlockBoundaries = function () { - var start = this.getStartBlock(), - end = this.getEndBlock(), +var expandRangeToBlockBoundaries = function ( range ) { + var start = getStartBlockOfRange( range ), + end = getEndBlockOfRange( range ), parent; if ( start && end ) { parent = start.parentNode; - this.setStart( parent, indexOf.call( parent.childNodes, start ) ); + range.setStart( parent, indexOf.call( parent.childNodes, start ) ); parent = end.parentNode; - this.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 ); + range.setEnd( parent, indexOf.call( parent.childNodes, end ) + 1 ); } - - return this; };