1/* 2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 3 * Copyright (C) 2003-2007 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 * 21 * FCKBlockQuoteCommand Class: adds or removes blockquote tags. 22 */ 23 24var FCKBlockQuoteCommand = function() 25{ 26} 27 28FCKBlockQuoteCommand.prototype = 29{ 30 Execute : function() 31 { 32 FCKUndo.SaveUndoStep() ; 33 34 var state = this.GetState() ; 35 var range = new FCKDomRange( FCK.EditorWindow ) ; 36 range.MoveToSelection() ; 37 var bookmark = range.CreateBookmark() ; 38 var iterator = new FCKDomRangeIterator( range ) ; 39 var block ; 40 41 if ( state == FCK_TRISTATE_OFF ) 42 { 43 iterator.EnforceRealBlocks = true ; 44 var paragraphs = [] ; 45 while ( ( block = iterator.GetNextParagraph() ) ) 46 paragraphs.push( block ) ; 47 48 // Make sure all paragraphs have the same parent. 49 var commonParent = paragraphs[0].parentNode ; 50 var tmp = [] ; 51 for ( var i = 0 ; i < paragraphs.length ; i++ ) 52 { 53 block = paragraphs[i] ; 54 commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ; 55 } 56 var lastBlock = null ; 57 while ( paragraphs.length > 0 ) 58 { 59 block = paragraphs.shift() ; 60 while ( block.parentNode != commonParent ) 61 block = block.parentNode ; 62 if ( block != lastBlock ) 63 tmp.push( block ) ; 64 lastBlock = block ; 65 } 66 67 // If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes. 68 while ( tmp.length > 0 ) 69 { 70 block = tmp.shift() ; 71 if ( block.nodeName.IEquals( 'blockquote' ) ) 72 { 73 var docFrag = block.ownerDocument.createDocumentFragment() ; 74 while ( block.firstChild ) 75 { 76 docFrag.appendChild( block.removeChild( block.firstChild ) ) ; 77 paragraphs.push( docFrag.lastChild ) ; 78 } 79 block.parentNode.replaceChild( docFrag, block ) ; 80 } 81 else 82 paragraphs.push( block ) ; 83 } 84 85 // Now we have all the blocks to be included in a new blockquote node. 86 var bqBlock = range.Window.document.createElement( 'blockquote' ) ; 87 commonParent.insertBefore( bqBlock, paragraphs[0] ) ; 88 while ( paragraphs.length > 0 ) 89 { 90 block = paragraphs.shift() ; 91 bqBlock.appendChild( block ) ; 92 } 93 } 94 else if ( state == FCK_TRISTATE_ON ) 95 { 96 var moveOutNodes = [] ; 97 while ( ( block = iterator.GetNextParagraph() ) ) 98 { 99 var bqParent = null ; 100 var bqChild = null ; 101 while ( block.parentNode ) 102 { 103 if ( block.parentNode.nodeName.IEquals( 'blockquote' ) ) 104 { 105 bqParent = block.parentNode ; 106 bqChild = block ; 107 break ; 108 } 109 block = block.parentNode ; 110 } 111 112 if ( bqParent && bqChild ) 113 moveOutNodes.push( bqChild ) ; 114 } 115 116 var movedNodes = [] ; 117 while ( moveOutNodes.length > 0 ) 118 { 119 var node = moveOutNodes.shift() ; 120 var bqBlock = node.parentNode ; 121 122 // If the node is located at the beginning or the end, just take it out without splitting. 123 // Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes. 124 if ( node == node.parentNode.firstChild ) 125 { 126 bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ; 127 if ( ! bqBlock.firstChild ) 128 bqBlock.parentNode.removeChild( bqBlock ) ; 129 } 130 else if ( node == node.parentNode.lastChild ) 131 { 132 bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ; 133 if ( ! bqBlock.firstChild ) 134 bqBlock.parentNode.removeChild( bqBlock ) ; 135 } 136 else 137 FCKDomTools.BreakParent( node, node.parentNode, range ) ; 138 139 movedNodes.push( node ) ; 140 } 141 142 if ( FCKConfig.EnterMode.IEquals( 'br' ) ) 143 { 144 while ( movedNodes.length ) 145 { 146 var node = movedNodes.shift() ; 147 var firstTime = true ; 148 if ( node.nodeName.IEquals( 'div' ) ) 149 { 150 var docFrag = node.ownerDocument.createDocumentFragment() ; 151 var needBeginBr = firstTime && node.previousSibling && 152 !FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ; 153 if ( firstTime && needBeginBr ) 154 docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ; 155 var needEndBr = node.nextSibling && 156 !FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ; 157 while ( node.firstChild ) 158 docFrag.appendChild( node.removeChild( node.firstChild ) ) ; 159 if ( needEndBr ) 160 docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ; 161 node.parentNode.replaceChild( docFrag, node ) ; 162 firstTime = false ; 163 } 164 } 165 } 166 } 167 range.MoveToBookmark( bookmark ) ; 168 range.Select() ; 169 170 FCK.Focus() ; 171 FCK.Events.FireEvent( 'OnSelectionChange' ) ; 172 }, 173 174 GetState : function() 175 { 176 // Disabled if not WYSIWYG. 177 if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow ) 178 return FCK_TRISTATE_DISABLED ; 179 180 var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ; 181 var firstBlock = path.Block || path.BlockLimit ; 182 183 if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' ) 184 return FCK_TRISTATE_OFF ; 185 186 // See if the first block has a blockquote parent. 187 for ( var i = 0 ; i < path.Elements.length ; i++ ) 188 { 189 if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) ) 190 return FCK_TRISTATE_ON ; 191 } 192 return FCK_TRISTATE_OFF ; 193 } 194} ; 195