From feca3e4d8fcedc8ab6fc6213f10c32bb4ca8c44f Mon Sep 17 00:00:00 2001 From: Neil Jenkins Date: Mon, 14 Nov 2011 17:55:40 +1100 Subject: [PATCH] Make forEachBlock method public. And tidy a few bits and pieces. --- Readme.md | 13 +++++++++++++ source/Editor.js | 39 +++++++++++++++++---------------------- source/Node.js | 2 +- source/Range.js | 41 ++++++++++++++++++++++------------------- 4 files changed, 53 insertions(+), 42 deletions(-) diff --git a/Readme.md b/Readme.md index 7c49dd7..50f2772 100644 --- a/Readme.md +++ b/Readme.md @@ -299,6 +299,19 @@ Sets the text alignment in all blocks at least partially contained by the select Returns self. +### forEachBlock ### + +Executes a function on each block in the current selection, or until the function returns a truthy value. + +#### Parameters #### + +* **fn** The function to execute on each block node at least partially contained in the current selection. The function will be called with the block node as the only argument. +* **mutates** A boolean indicating whether your function may modify anything in the document in any way. + +#### Returns #### + +Returns self. + ### modifyBlocks ### Extracts a portion of the DOM tree (up to the block boundaries of the current selection), modifies it and then reinserts it and merges the edges. See the code for examples if you're interested in using this function. diff --git a/source/Editor.js b/source/Editor.js index 54ef71a..9e7e8af 100644 --- a/source/Editor.js +++ b/source/Editor.js @@ -620,30 +620,33 @@ // --- Block formatting --- - var forEachBlock = function ( fn, range ) { + var forEachBlock = function ( fn, mutates, range ) { if ( !range && !( range = getSelection() ) ) { return; } // Save undo checkpoint - recordUndoState( range ); - getRangeAndRemoveBookmark( range ); + if ( mutates ) { + recordUndoState( range ); + getRangeAndRemoveBookmark( range ); + } var start = range.getStartBlock(), end = range.getEndBlock(); if ( start && end ) { while ( true ) { - fn( start ); - if ( start === end ) { break; } + if ( fn( start ) || start === end ) { break; } start = start.getNextBlock(); } } - // Path may have changed - updatePath( 0, true ); + if ( mutates ) { + // Path may have changed + updatePath( 0, true ); - // We're not still in an undo state - docWasChanged(); + // We're not still in an undo state + docWasChanged(); + } }; var modifyBlocks = function ( modify, range ) { @@ -1398,20 +1401,11 @@ // And insert new content // Add the styles if ( styles ) { - var head = doc.documentElement.firstChild, - style = createElement( 'STYLE', { + var style = createElement( 'STYLE', { type: 'text/css' }); - if ( style.styleSheet ) { - // IE8: must append to document BEFORE adding styles - // or you get the IE7 CSS parser! - head.appendChild( style ); - style.styleSheet.cssText = styles; - } else { - // Everyone else - style.appendChild( doc.createTextNode( styles ) ); - head.appendChild( style ); - } + style.appendChild( doc.createTextNode( styles ) ); + doc.documentElement.firstChild.appendChild( style ); } body.appendChild( frag ); @@ -1560,11 +1554,12 @@ forEachBlock( function ( block ) { block.className = 'align-' + dir; block.style.textAlign = dir; - }); + }, true ); focus(); return this; }, + forEachBlock: chain( forEachBlock ), modifyBlocks: chain( modifyBlocks ), incQuoteLevel: command( modifyBlocks, increaseBlockQuoteLevel ), diff --git a/source/Node.js b/source/Node.js index 09c301c..4ce6ee7 100644 --- a/source/Node.js +++ b/source/Node.js @@ -102,8 +102,8 @@ implement( Node, { }); implement( Text, { - isInline: $True, isLeaf: $True, + isInline: $True, getLength: function () { return this.length; }, diff --git a/source/Range.js b/source/Range.js index e76dcaf..e2c6513 100644 --- a/source/Range.js +++ b/source/Range.js @@ -51,36 +51,39 @@ var getNodeAfter = function ( node, offset ) { }; implement( Range, { - getTextContent: function () { - this.moveBoundariesDownTree(); + + forEachTextNode: function ( fn ) { + var range = this.cloneRange(); + range.moveBoundariesDownTree(); - var startContainer = this.startContainer, - endContainer = this.endContainer, - root = this.commonAncestorContainer, + var startContainer = range.startContainer, + endContainer = range.endContainer, + root = range.commonAncestorContainer, walker = root.ownerDocument.createTreeWalker( root, SHOW_TEXT, function ( node ) { return FILTER_ACCEPT; }, false ), - textnode = walker.currentNode = startContainer, - textContent = '', - value; + textnode = walker.currentNode = startContainer; - do { - value = textnode.data; + while ( !fn( textnode, range ) && + textnode !== endContainer && + ( textnode = walker.nextNode() ) ) {} + }, + + getTextContent: function () { + var textContent = ''; + this.forEachTextNode( function ( textnode, range ) { + var value = textnode.data; if ( value && ( /\S/.test( value ) ) ) { - if ( textnode === endContainer ) { - value = value.slice( 0, this.endOffset ); + if ( textnode === range.endContainer ) { + value = value.slice( 0, range.endOffset ); } - if ( textnode === startContainer ) { - value = value.slice( this.startOffset ); + if ( textnode === range.startContainer ) { + value = value.slice( range.startOffset ); } textContent += value; } - if ( textnode === endContainer ) { - break; - } - } while ( textnode = walker.nextNode() ); - + }); return textContent; },