; its format clashes with
nodes = node.querySelectorAll( 'CODE' );
l = nodes.length;
while ( l-- ) {
detach( nodes[l] );
}
if ( output.childNodes.length ) {
output.appendChild( document.createTextNode( '\n' ) );
}
output.appendChild( empty( node ) );
}
// 4. Replace nbsp with regular sp
walker = new TreeWalker( output, SHOW_TEXT );
while (( node = walker.nextNode() )) {
node.data = node.data.replace( / /g, ' ' ); // nbsp -> sp
}
output.normalize();
return fixCursor( this.createElement( 'PRE',
this._config.tagAttributes.pre, [
output
]), root );
};
var removePre = function ( frag ) {
var document = this._doc;
var root = this._root;
var pres = frag.querySelectorAll( 'PRE' );
var l = pres.length;
var pre, walker, node, value, contents, index;
while ( l-- ) {
pre = pres[l];
walker = new TreeWalker( pre, SHOW_TEXT );
while (( node = walker.nextNode() )) {
value = node.data;
value = value.replace( / (?= )/g, ' ' ); // sp -> nbsp
contents = document.createDocumentFragment();
while (( index = value.indexOf( '\n' ) ) > -1 ) {
contents.appendChild(
document.createTextNode( value.slice( 0, index ) )
);
contents.appendChild( document.createElement( 'BR' ) );
value = value.slice( index + 1 );
}
node.parentNode.insertBefore( contents, node );
node.data = value;
}
fixContainer( pre, root );
replaceWith( pre, empty( pre ) );
}
return frag;
};
proto.code = function () {
var range = this.getSelection();
if ( range.collapsed || isContainer( range.commonAncestorContainer ) ) {
this.modifyBlocks( addPre, range );
} else {
this.changeFormat({
tag: 'CODE',
attributes: this._config.tagAttributes.code
}, null, range );
}
return this.focus();
};
proto.removeCode = function () {
var range = this.getSelection();
var ancestor = range.commonAncestorContainer;
var inPre = getNearest( ancestor, this._root, 'PRE' );
if ( inPre ) {
this.modifyBlocks( removePre, range );
} else {
this.changeFormat( null, { tag: 'CODE' }, range );
}
return this.focus();
};
proto.toggleCode = function () {
if ( this.hasFormat( 'PRE' ) || this.hasFormat( 'CODE' ) ) {
this.removeCode();
} else {
this.code();
}
return this;
};
// ---
function removeFormatting ( self, root, clean ) {
var node, next;
for ( node = root.firstChild; node; node = next ) {
next = node.nextSibling;
if ( isInline( node ) ) {
if ( node.nodeType === TEXT_NODE || node.nodeName === 'BR' || node.nodeName === 'IMG' ) {
clean.appendChild( node );
continue;
}
} else if ( isBlock( node ) ) {
clean.appendChild( self.createDefaultBlock([
removeFormatting(
self, node, self._doc.createDocumentFragment() )
]));
continue;
}
removeFormatting( self, node, clean );
}
return clean;
}
proto.removeAllFormatting = function ( range ) {
if ( !range && !( range = this.getSelection() ) || range.collapsed ) {
return this;
}
var root = this._root;
var stopNode = range.commonAncestorContainer;
while ( stopNode && !isBlock( stopNode ) ) {
stopNode = stopNode.parentNode;
}
if ( !stopNode ) {
expandRangeToBlockBoundaries( range, root );
stopNode = root;
}
if ( stopNode.nodeType === TEXT_NODE ) {
return this;
}
// Record undo point
this.saveUndoState( range );
// Avoid splitting where we're already at edges.
moveRangeBoundariesUpTree( range, stopNode, stopNode, root );
// Split the selection up to the block, or if whole selection in same
// block, expand range boundaries to ends of block and split up to root.
var doc = stopNode.ownerDocument;
var startContainer = range.startContainer;
var startOffset = range.startOffset;
var endContainer = range.endContainer;
var endOffset = range.endOffset;
// Split end point first to avoid problems when end and start
// in same container.
var formattedNodes = doc.createDocumentFragment();
var cleanNodes = doc.createDocumentFragment();
var nodeAfterSplit = split( endContainer, endOffset, stopNode, root );
var nodeInSplit = split( startContainer, startOffset, stopNode, root );
var nextNode, childNodes;
// Then replace contents in split with a cleaned version of the same:
// blocks become default blocks, text and leaf nodes survive, everything
// else is obliterated.
while ( nodeInSplit !== nodeAfterSplit ) {
nextNode = nodeInSplit.nextSibling;
formattedNodes.appendChild( nodeInSplit );
nodeInSplit = nextNode;
}
removeFormatting( this, formattedNodes, cleanNodes );
cleanNodes.normalize();
nodeInSplit = cleanNodes.firstChild;
nextNode = cleanNodes.lastChild;
// Restore selection
childNodes = stopNode.childNodes;
if ( nodeInSplit ) {
stopNode.insertBefore( cleanNodes, nodeAfterSplit );
startOffset = indexOf.call( childNodes, nodeInSplit );
endOffset = indexOf.call( childNodes, nextNode ) + 1;
} else {
startOffset = indexOf.call( childNodes, nodeAfterSplit );
endOffset = startOffset;
}
// Merge text nodes at edges, if possible
range.setStart( stopNode, startOffset );
range.setEnd( stopNode, endOffset );
mergeInlines( stopNode, range );
// And move back down the tree
moveRangeBoundariesDownTree( range );
this.setSelection( range );
this._updatePath( range, true );
return this.focus();
};
proto.increaseQuoteLevel = command( 'modifyBlocks', increaseBlockQuoteLevel );
proto.decreaseQuoteLevel = command( 'modifyBlocks', decreaseBlockQuoteLevel );
proto.makeUnorderedList = command( 'modifyBlocks', makeUnorderedList );
proto.makeOrderedList = command( 'modifyBlocks', makeOrderedList );
proto.removeList = command( 'modifyBlocks', removeList );