/source/Plug-in/fck/editor/_source/commandclasses/fckblockquotecommand.js

http://prosporous.googlecode.com/ · JavaScript · 250 lines · 192 code · 25 blank · 33 comment · 62 complexity · aaa3f5fc9b49f12b15406144bcbccc2d MD5 · raw file

  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. var FCKBlockQuoteCommand = function()
  24. {
  25. }
  26. FCKBlockQuoteCommand.prototype =
  27. {
  28. Execute : function()
  29. {
  30. FCKUndo.SaveUndoStep() ;
  31. var state = this.GetState() ;
  32. var range = new FCKDomRange( FCK.EditorWindow ) ;
  33. range.MoveToSelection() ;
  34. var bookmark = range.CreateBookmark() ;
  35. // Kludge for #1592: if the bookmark nodes are in the beginning of
  36. // blockquote, then move them to the nearest block element in the
  37. // blockquote.
  38. if ( FCKBrowserInfo.IsIE )
  39. {
  40. var bStart = range.GetBookmarkNode( bookmark, true ) ;
  41. var bEnd = range.GetBookmarkNode( bookmark, false ) ;
  42. var cursor ;
  43. if ( bStart
  44. && bStart.parentNode.nodeName.IEquals( 'blockquote' )
  45. && !bStart.previousSibling )
  46. {
  47. cursor = bStart ;
  48. while ( ( cursor = cursor.nextSibling ) )
  49. {
  50. if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
  51. FCKDomTools.MoveNode( bStart, cursor, true ) ;
  52. }
  53. }
  54. if ( bEnd
  55. && bEnd.parentNode.nodeName.IEquals( 'blockquote' )
  56. && !bEnd.previousSibling )
  57. {
  58. cursor = bEnd ;
  59. while ( ( cursor = cursor.nextSibling ) )
  60. {
  61. if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
  62. {
  63. if ( cursor.firstChild == bStart )
  64. FCKDomTools.InsertAfterNode( bStart, bEnd ) ;
  65. else
  66. FCKDomTools.MoveNode( bEnd, cursor, true ) ;
  67. }
  68. }
  69. }
  70. }
  71. var iterator = new FCKDomRangeIterator( range ) ;
  72. var block ;
  73. if ( state == FCK_TRISTATE_OFF )
  74. {
  75. iterator.EnforceRealBlocks = true ;
  76. var paragraphs = [] ;
  77. while ( ( block = iterator.GetNextParagraph() ) )
  78. paragraphs.push( block ) ;
  79. // If no paragraphs, create one from the current selection position.
  80. if ( paragraphs.length < 1 )
  81. {
  82. para = range.Window.document.createElement( FCKConfig.EnterMode.IEquals( 'p' ) ? 'p' : 'div' ) ;
  83. range.InsertNode( para ) ;
  84. para.appendChild( range.Window.document.createTextNode( '\ufeff' ) ) ;
  85. range.MoveToBookmark( bookmark ) ;
  86. range.MoveToNodeContents( para ) ;
  87. range.Collapse( true ) ;
  88. bookmark = range.CreateBookmark() ;
  89. paragraphs.push( para ) ;
  90. }
  91. // Make sure all paragraphs have the same parent.
  92. var commonParent = paragraphs[0].parentNode ;
  93. var tmp = [] ;
  94. for ( var i = 0 ; i < paragraphs.length ; i++ )
  95. {
  96. block = paragraphs[i] ;
  97. commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ;
  98. }
  99. var lastBlock = null ;
  100. while ( paragraphs.length > 0 )
  101. {
  102. block = paragraphs.shift() ;
  103. while ( block.parentNode != commonParent )
  104. block = block.parentNode ;
  105. if ( block != lastBlock )
  106. tmp.push( block ) ;
  107. lastBlock = block ;
  108. }
  109. // If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes.
  110. while ( tmp.length > 0 )
  111. {
  112. block = tmp.shift() ;
  113. if ( block.nodeName.IEquals( 'blockquote' ) )
  114. {
  115. var docFrag = block.ownerDocument.createDocumentFragment() ;
  116. while ( block.firstChild )
  117. {
  118. docFrag.appendChild( block.removeChild( block.firstChild ) ) ;
  119. paragraphs.push( docFrag.lastChild ) ;
  120. }
  121. block.parentNode.replaceChild( docFrag, block ) ;
  122. }
  123. else
  124. paragraphs.push( block ) ;
  125. }
  126. // Now we have all the blocks to be included in a new blockquote node.
  127. var bqBlock = range.Window.document.createElement( 'blockquote' ) ;
  128. commonParent.insertBefore( bqBlock, paragraphs[0] ) ;
  129. while ( paragraphs.length > 0 )
  130. {
  131. block = paragraphs.shift() ;
  132. bqBlock.appendChild( block ) ;
  133. }
  134. }
  135. else if ( state == FCK_TRISTATE_ON )
  136. {
  137. var moveOutNodes = [] ;
  138. while ( ( block = iterator.GetNextParagraph() ) )
  139. {
  140. var bqParent = null ;
  141. var bqChild = null ;
  142. while ( block.parentNode )
  143. {
  144. if ( block.parentNode.nodeName.IEquals( 'blockquote' ) )
  145. {
  146. bqParent = block.parentNode ;
  147. bqChild = block ;
  148. break ;
  149. }
  150. block = block.parentNode ;
  151. }
  152. if ( bqParent && bqChild )
  153. moveOutNodes.push( bqChild ) ;
  154. }
  155. var movedNodes = [] ;
  156. while ( moveOutNodes.length > 0 )
  157. {
  158. var node = moveOutNodes.shift() ;
  159. var bqBlock = node.parentNode ;
  160. // If the node is located at the beginning or the end, just take it out without splitting.
  161. // Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes.
  162. if ( node == node.parentNode.firstChild )
  163. {
  164. bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ;
  165. if ( ! bqBlock.firstChild )
  166. bqBlock.parentNode.removeChild( bqBlock ) ;
  167. }
  168. else if ( node == node.parentNode.lastChild )
  169. {
  170. bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
  171. if ( ! bqBlock.firstChild )
  172. bqBlock.parentNode.removeChild( bqBlock ) ;
  173. }
  174. else
  175. FCKDomTools.BreakParent( node, node.parentNode, range ) ;
  176. movedNodes.push( node ) ;
  177. }
  178. if ( FCKConfig.EnterMode.IEquals( 'br' ) )
  179. {
  180. while ( movedNodes.length )
  181. {
  182. var node = movedNodes.shift() ;
  183. var firstTime = true ;
  184. if ( node.nodeName.IEquals( 'div' ) )
  185. {
  186. var docFrag = node.ownerDocument.createDocumentFragment() ;
  187. var needBeginBr = firstTime && node.previousSibling &&
  188. !FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
  189. if ( firstTime && needBeginBr )
  190. docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ;
  191. var needEndBr = node.nextSibling &&
  192. !FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ;
  193. while ( node.firstChild )
  194. docFrag.appendChild( node.removeChild( node.firstChild ) ) ;
  195. if ( needEndBr )
  196. docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ;
  197. node.parentNode.replaceChild( docFrag, node ) ;
  198. firstTime = false ;
  199. }
  200. }
  201. }
  202. }
  203. range.MoveToBookmark( bookmark ) ;
  204. range.Select() ;
  205. FCK.Focus() ;
  206. FCK.Events.FireEvent( 'OnSelectionChange' ) ;
  207. },
  208. GetState : function()
  209. {
  210. // Disabled if not WYSIWYG.
  211. if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
  212. return FCK_TRISTATE_DISABLED ;
  213. var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
  214. var firstBlock = path.Block || path.BlockLimit ;
  215. if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
  216. return FCK_TRISTATE_OFF ;
  217. // See if the first block has a blockquote parent.
  218. for ( var i = 0 ; i < path.Elements.length ; i++ )
  219. {
  220. if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) )
  221. return FCK_TRISTATE_ON ;
  222. }
  223. return FCK_TRISTATE_OFF ;
  224. }
  225. } ;