282 lines
8.8 KiB
JavaScript
282 lines
8.8 KiB
JavaScript
/*
|
|
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
|
|
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
|
|
*
|
|
* == BEGIN LICENSE ==
|
|
*
|
|
* Licensed under the terms of any of the following licenses at your
|
|
* choice:
|
|
*
|
|
* - GNU General Public License Version 2 or later (the "GPL")
|
|
* http://www.gnu.org/licenses/gpl.html
|
|
*
|
|
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
|
|
* http://www.gnu.org/licenses/lgpl.html
|
|
*
|
|
* - Mozilla Public License Version 1.1 or later (the "MPL")
|
|
* http://www.mozilla.org/MPL/MPL-1.1.html
|
|
*
|
|
* == END LICENSE ==
|
|
*
|
|
* FCKBlockQuoteCommand Class: adds or removes blockquote tags.
|
|
*/
|
|
|
|
var FCKBlockQuoteCommand = function()
|
|
{
|
|
}
|
|
|
|
FCKBlockQuoteCommand.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
FCKUndo.SaveUndoStep() ;
|
|
|
|
var state = this.GetState() ;
|
|
|
|
var range = new FCKDomRange( FCK.EditorWindow ) ;
|
|
range.MoveToSelection() ;
|
|
|
|
var bookmark = range.CreateBookmark() ;
|
|
|
|
// Kludge for #1592: if the bookmark nodes are in the beginning of
|
|
// blockquote, then move them to the nearest block element in the
|
|
// blockquote.
|
|
if ( FCKBrowserInfo.IsIE )
|
|
{
|
|
var bStart = range.GetBookmarkNode( bookmark, true ) ;
|
|
var bEnd = range.GetBookmarkNode( bookmark, false ) ;
|
|
|
|
var cursor ;
|
|
|
|
if ( bStart
|
|
&& bStart.parentNode.nodeName.IEquals( 'blockquote' )
|
|
&& !bStart.previousSibling )
|
|
{
|
|
cursor = bStart ;
|
|
while ( ( cursor = cursor.nextSibling ) )
|
|
{
|
|
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
|
|
FCKDomTools.MoveNode( bStart, cursor, true ) ;
|
|
}
|
|
}
|
|
|
|
if ( bEnd
|
|
&& bEnd.parentNode.nodeName.IEquals( 'blockquote' )
|
|
&& !bEnd.previousSibling )
|
|
{
|
|
cursor = bEnd ;
|
|
while ( ( cursor = cursor.nextSibling ) )
|
|
{
|
|
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
|
|
{
|
|
if ( cursor.firstChild == bStart )
|
|
FCKDomTools.InsertAfterNode( bStart, bEnd ) ;
|
|
else
|
|
FCKDomTools.MoveNode( bEnd, cursor, true ) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var iterator = new FCKDomRangeIterator( range ) ;
|
|
var block ;
|
|
|
|
if ( state == FCK_TRISTATE_OFF )
|
|
{
|
|
var paragraphs = [] ;
|
|
while ( ( block = iterator.GetNextParagraph() ) )
|
|
paragraphs.push( block ) ;
|
|
|
|
// If no paragraphs, create one from the current selection position.
|
|
if ( paragraphs.length < 1 )
|
|
{
|
|
para = range.Window.document.createElement( FCKConfig.EnterMode.IEquals( 'p' ) ? 'p' : 'div' ) ;
|
|
range.InsertNode( para ) ;
|
|
para.appendChild( range.Window.document.createTextNode( '\ufeff' ) ) ;
|
|
range.MoveToBookmark( bookmark ) ;
|
|
range.MoveToNodeContents( para ) ;
|
|
range.Collapse( true ) ;
|
|
bookmark = range.CreateBookmark() ;
|
|
paragraphs.push( para ) ;
|
|
}
|
|
|
|
// Make sure all paragraphs have the same parent.
|
|
var commonParent = paragraphs[0].parentNode ;
|
|
var tmp = [] ;
|
|
for ( var i = 0 ; i < paragraphs.length ; i++ )
|
|
{
|
|
block = paragraphs[i] ;
|
|
commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ;
|
|
}
|
|
|
|
// The common parent must not be the following tags: table, tbody, tr, ol, ul.
|
|
while ( commonParent.nodeName.IEquals( 'table', 'tbody', 'tr', 'ol', 'ul' ) )
|
|
commonParent = commonParent.parentNode ;
|
|
|
|
// Reconstruct the block list to be processed such that all resulting blocks
|
|
// satisfy parentNode == commonParent.
|
|
var lastBlock = null ;
|
|
while ( paragraphs.length > 0 )
|
|
{
|
|
block = paragraphs.shift() ;
|
|
while ( block.parentNode != commonParent )
|
|
block = block.parentNode ;
|
|
if ( block != lastBlock )
|
|
tmp.push( block ) ;
|
|
lastBlock = block ;
|
|
}
|
|
|
|
// If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes.
|
|
while ( tmp.length > 0 )
|
|
{
|
|
block = tmp.shift() ;
|
|
if ( block.nodeName.IEquals( 'blockquote' ) )
|
|
{
|
|
var docFrag = FCKTools.GetElementDocument( block ).createDocumentFragment() ;
|
|
while ( block.firstChild )
|
|
{
|
|
docFrag.appendChild( block.removeChild( block.firstChild ) ) ;
|
|
paragraphs.push( docFrag.lastChild ) ;
|
|
}
|
|
block.parentNode.replaceChild( docFrag, block ) ;
|
|
}
|
|
else
|
|
paragraphs.push( block ) ;
|
|
}
|
|
|
|
// Now we have all the blocks to be included in a new blockquote node.
|
|
var bqBlock = range.Window.document.createElement( 'blockquote' ) ;
|
|
commonParent.insertBefore( bqBlock, paragraphs[0] ) ;
|
|
while ( paragraphs.length > 0 )
|
|
{
|
|
block = paragraphs.shift() ;
|
|
bqBlock.appendChild( block ) ;
|
|
}
|
|
}
|
|
else if ( state == FCK_TRISTATE_ON )
|
|
{
|
|
var moveOutNodes = [] ;
|
|
var elementMarkers = {} ;
|
|
while ( ( block = iterator.GetNextParagraph() ) )
|
|
{
|
|
var bqParent = null ;
|
|
var bqChild = null ;
|
|
while ( block.parentNode )
|
|
{
|
|
if ( block.parentNode.nodeName.IEquals( 'blockquote' ) )
|
|
{
|
|
bqParent = block.parentNode ;
|
|
bqChild = block ;
|
|
break ;
|
|
}
|
|
block = block.parentNode ;
|
|
}
|
|
|
|
// Remember the blocks that were recorded down in the moveOutNodes array
|
|
// to prevent duplicates.
|
|
if ( bqParent && bqChild && !bqChild._fckblockquotemoveout )
|
|
{
|
|
moveOutNodes.push( bqChild ) ;
|
|
FCKDomTools.SetElementMarker( elementMarkers, bqChild, '_fckblockquotemoveout', true ) ;
|
|
}
|
|
}
|
|
FCKDomTools.ClearAllMarkers( elementMarkers ) ;
|
|
|
|
var movedNodes = [] ;
|
|
var processedBlockquoteBlocks = [], elementMarkers = {} ;
|
|
var noBlockLeft = function( bqBlock )
|
|
{
|
|
for ( var i = 0 ; i < bqBlock.childNodes.length ; i++ )
|
|
{
|
|
if ( FCKListsLib.BlockElements[ bqBlock.childNodes[i].nodeName.toLowerCase() ] )
|
|
return false ;
|
|
}
|
|
return true ;
|
|
} ;
|
|
while ( moveOutNodes.length > 0 )
|
|
{
|
|
var node = moveOutNodes.shift() ;
|
|
var bqBlock = node.parentNode ;
|
|
|
|
// If the node is located at the beginning or the end, just take it out without splitting.
|
|
// Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes.
|
|
if ( node == node.parentNode.firstChild )
|
|
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ;
|
|
else if ( node == node.parentNode.lastChild )
|
|
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
|
|
else
|
|
FCKDomTools.BreakParent( node, node.parentNode, range ) ;
|
|
|
|
// Remember the blockquote node so we can clear it later (if it becomes empty).
|
|
if ( !bqBlock._fckbqprocessed )
|
|
{
|
|
processedBlockquoteBlocks.push( bqBlock ) ;
|
|
FCKDomTools.SetElementMarker( elementMarkers, bqBlock, '_fckbqprocessed', true );
|
|
}
|
|
|
|
movedNodes.push( node ) ;
|
|
}
|
|
|
|
// Clear blockquote nodes that have become empty.
|
|
for ( var i = processedBlockquoteBlocks.length - 1 ; i >= 0 ; i-- )
|
|
{
|
|
var bqBlock = processedBlockquoteBlocks[i] ;
|
|
if ( noBlockLeft( bqBlock ) )
|
|
FCKDomTools.RemoveNode( bqBlock ) ;
|
|
}
|
|
FCKDomTools.ClearAllMarkers( elementMarkers ) ;
|
|
|
|
if ( FCKConfig.EnterMode.IEquals( 'br' ) )
|
|
{
|
|
while ( movedNodes.length )
|
|
{
|
|
var node = movedNodes.shift() ;
|
|
var firstTime = true ;
|
|
if ( node.nodeName.IEquals( 'div' ) )
|
|
{
|
|
var docFrag = FCKTools.GetElementDocument( node ).createDocumentFragment() ;
|
|
var needBeginBr = firstTime && node.previousSibling &&
|
|
!FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
|
|
if ( firstTime && needBeginBr )
|
|
docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
|
|
var needEndBr = node.nextSibling &&
|
|
!FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ;
|
|
while ( node.firstChild )
|
|
docFrag.appendChild( node.removeChild( node.firstChild ) ) ;
|
|
if ( needEndBr )
|
|
docFrag.appendChild( FCKTools.GetElementDocument( node ).createElement( 'br' ) ) ;
|
|
node.parentNode.replaceChild( docFrag, node ) ;
|
|
firstTime = false ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
range.MoveToBookmark( bookmark ) ;
|
|
range.Select() ;
|
|
|
|
FCK.Focus() ;
|
|
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
// Disabled if not WYSIWYG.
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
|
|
var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
|
|
var firstBlock = path.Block || path.BlockLimit ;
|
|
|
|
if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
|
|
return FCK_TRISTATE_OFF ;
|
|
|
|
// See if the first block has a blockquote parent.
|
|
for ( var i = 0 ; i < path.Elements.length ; i++ )
|
|
{
|
|
if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) )
|
|
return FCK_TRISTATE_ON ;
|
|
}
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
} ;
|