fckindentcommands.js
上传用户:dbstep
上传日期:2022-08-06
资源大小:2803k
文件大小:10k
源码类别:

WEB源码(ASP,PHP,...)

开发平台:

ASP/ASPX

  1. /*
  2.  * FCKeditor - The text editor for Internet - http://www.fckeditor.net
  3.  * Copyright (C) 2003-2009 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.  * FCKIndentCommand Class: controls block indentation.
  22.  */
  23. var FCKIndentCommand = function( name, offset )
  24. {
  25. this.Name = name ;
  26. this.Offset = offset ;
  27. this.IndentCSSProperty = FCKConfig.ContentLangDirection.IEquals( 'ltr' ) ? 'marginLeft' : 'marginRight' ;
  28. }
  29. FCKIndentCommand._InitIndentModeParameters = function()
  30. {
  31. if ( FCKConfig.IndentClasses && FCKConfig.IndentClasses.length > 0 )
  32. {
  33. this._UseIndentClasses = true ;
  34. this._IndentClassMap = {} ;
  35. for ( var i = 0 ; i < FCKConfig.IndentClasses.length ;i++ )
  36. this._IndentClassMap[FCKConfig.IndentClasses[i]] = i + 1 ;
  37. this._ClassNameRegex = new RegExp( '(?:^|\s+)(' + FCKConfig.IndentClasses.join( '|' ) + ')(?=$|\s)' ) ;
  38. }
  39. else
  40. this._UseIndentClasses = false ;
  41. }
  42. FCKIndentCommand.prototype =
  43. {
  44. Execute : function()
  45. {
  46. // Save an undo snapshot before doing anything.
  47. FCKUndo.SaveUndoStep() ;
  48. var range = new FCKDomRange( FCK.EditorWindow ) ;
  49. range.MoveToSelection() ;
  50. var bookmark = range.CreateBookmark() ;
  51. // Two cases to handle here: either we're in a list, or not.
  52. // If we're in a list, then the indent/outdent operations would be done on the list nodes.
  53. // Otherwise, apply the operation on the nearest block nodes.
  54. var nearestListBlock = FCKDomTools.GetCommonParentNode( range.StartNode || range.StartContainer ,
  55. range.EndNode || range.EndContainer,
  56. ['ul', 'ol'] ) ;
  57. if ( nearestListBlock )
  58. this._IndentList( range, nearestListBlock ) ;
  59. else
  60. this._IndentBlock( range ) ;
  61. range.MoveToBookmark( bookmark ) ;
  62. range.Select() ;
  63. FCK.Focus() ;
  64. FCK.Events.FireEvent( 'OnSelectionChange' ) ;
  65. },
  66. GetState : function()
  67. {
  68. // Disabled if not WYSIWYG.
  69. if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
  70. return FCK_TRISTATE_DISABLED ;
  71. // Initialize parameters if not already initialzed.
  72. if ( FCKIndentCommand._UseIndentClasses == undefined )
  73. FCKIndentCommand._InitIndentModeParameters() ;
  74. // If we're not in a list, and the starting block's indentation is zero, and the current
  75. // command is the outdent command, then we should return FCK_TRISTATE_DISABLED.
  76. var startContainer = FCKSelection.GetBoundaryParentElement( true ) ;
  77. var endContainer = FCKSelection.GetBoundaryParentElement( false ) ;
  78. var listNode = FCKDomTools.GetCommonParentNode( startContainer, endContainer, ['ul','ol'] ) ;
  79. if ( listNode )
  80. {
  81. if ( this.Name.IEquals( 'outdent' ) )
  82. return FCK_TRISTATE_OFF ;
  83. var firstItem = FCKTools.GetElementAscensor( startContainer, 'li' ) ;
  84. if ( !firstItem || !firstItem.previousSibling )
  85. return FCK_TRISTATE_DISABLED ;
  86. return FCK_TRISTATE_OFF ;
  87. }
  88. if ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) )
  89. return FCK_TRISTATE_OFF;
  90. var path = new FCKElementPath( startContainer ) ;
  91. var firstBlock = path.Block || path.BlockLimit ;
  92. if ( !firstBlock )
  93. return FCK_TRISTATE_DISABLED ;
  94. if ( FCKIndentCommand._UseIndentClasses )
  95. {
  96. var indentClass = firstBlock.className.match( FCKIndentCommand._ClassNameRegex ) ;
  97. var indentStep = 0 ;
  98. if ( indentClass != null )
  99. {
  100. indentClass = indentClass[1] ;
  101. indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;
  102. }
  103. if ( ( this.Name == 'outdent' && indentStep == 0 ) ||
  104. ( this.Name == 'indent' && indentStep == FCKConfig.IndentClasses.length ) )
  105. return FCK_TRISTATE_DISABLED ;
  106. return FCK_TRISTATE_OFF ;
  107. }
  108. else
  109. {
  110. var indent = parseInt( firstBlock.style[this.IndentCSSProperty], 10 ) ;
  111. if ( isNaN( indent ) )
  112. indent = 0 ;
  113. if ( indent <= 0 )
  114. return FCK_TRISTATE_DISABLED ;
  115. return FCK_TRISTATE_OFF ;
  116. }
  117. },
  118. _IndentBlock : function( range )
  119. {
  120. var iterator = new FCKDomRangeIterator( range ) ;
  121. iterator.EnforceRealBlocks = true ;
  122. range.Expand( 'block_contents' ) ;
  123. var commonParents = FCKDomTools.GetCommonParents( range.StartContainer, range.EndContainer ) ;
  124. var nearestParent = commonParents[commonParents.length - 1] ;
  125. var block ;
  126. while ( ( block = iterator.GetNextParagraph() ) )
  127. {
  128. // We don't want to indent subtrees recursively, so only perform the indent operation
  129. // if the block itself is the nearestParent, or the block's parent is the nearestParent.
  130. if ( ! ( block == nearestParent || block.parentNode == nearestParent ) )
  131. continue ;
  132. if ( FCKIndentCommand._UseIndentClasses )
  133. {
  134. // Transform current class name to indent step index.
  135. var indentClass = block.className.match( FCKIndentCommand._ClassNameRegex ) ;
  136. var indentStep = 0 ;
  137. if ( indentClass != null )
  138. {
  139. indentClass = indentClass[1] ;
  140. indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;
  141. }
  142. // Operate on indent step index, transform indent step index back to class name.
  143. if ( this.Name.IEquals( 'outdent' ) )
  144. indentStep-- ;
  145. else if ( this.Name.IEquals( 'indent' ) )
  146. indentStep++ ;
  147. indentStep = Math.min( indentStep, FCKConfig.IndentClasses.length ) ;
  148. indentStep = Math.max( indentStep, 0 ) ;
  149. var className = block.className.replace( FCKIndentCommand._ClassNameRegex, '' ) ;
  150. if ( indentStep < 1 )
  151. block.className = className ;
  152. else
  153. block.className = ( className.length > 0 ? className + ' ' : '' ) +
  154. FCKConfig.IndentClasses[indentStep - 1] ;
  155. }
  156. else
  157. {
  158. // Offset distance is assumed to be in pixels for now.
  159. var currentOffset = parseInt( block.style[this.IndentCSSProperty], 10 ) ;
  160. if ( isNaN( currentOffset ) )
  161. currentOffset = 0 ;
  162. currentOffset += this.Offset ;
  163. currentOffset = Math.max( currentOffset, 0 ) ;
  164. currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ;
  165. block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + FCKConfig.IndentUnit : '' ;
  166. if ( block.getAttribute( 'style' ) == '' )
  167. block.removeAttribute( 'style' ) ;
  168. }
  169. }
  170. },
  171. _IndentList : function( range, listNode )
  172. {
  173. // Our starting and ending points of the range might be inside some blocks under a list item...
  174. // So before playing with the iterator, we need to expand the block to include the list items.
  175. var startContainer = range.StartContainer ;
  176. var endContainer = range.EndContainer ;
  177. while ( startContainer && startContainer.parentNode != listNode )
  178. startContainer = startContainer.parentNode ;
  179. while ( endContainer && endContainer.parentNode != listNode )
  180. endContainer = endContainer.parentNode ;
  181. if ( ! startContainer || ! endContainer )
  182. return ;
  183. // Now we can iterate over the individual items on the same tree depth.
  184. var block = startContainer ;
  185. var itemsToMove = [] ;
  186. var stopFlag = false ;
  187. while ( stopFlag == false )
  188. {
  189. if ( block == endContainer )
  190. stopFlag = true ;
  191. itemsToMove.push( block ) ;
  192. block = block.nextSibling ;
  193. }
  194. if ( itemsToMove.length < 1 )
  195. return ;
  196. // Do indent or outdent operations on the array model of the list, not the list's DOM tree itself.
  197. // The array model demands that it knows as much as possible about the surrounding lists, we need
  198. // to feed it the further ancestor node that is still a list.
  199. var listParents = FCKDomTools.GetParents( listNode ) ;
  200. for ( var i = 0 ; i < listParents.length ; i++ )
  201. {
  202. if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) )
  203. {
  204. listNode = listParents[i] ;
  205. break ;
  206. }
  207. }
  208. var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ;
  209. var startItem = itemsToMove[0] ;
  210. var lastItem = itemsToMove[ itemsToMove.length - 1 ] ;
  211. var markerObj = {} ;
  212. // Convert the list DOM tree into a one dimensional array.
  213. var listArray = FCKDomTools.ListToArray( listNode, markerObj ) ;
  214. // Apply indenting or outdenting on the array.
  215. var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ;
  216. for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ )
  217. listArray[i].indent += indentOffset ;
  218. for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ )
  219. listArray[i].indent += indentOffset ;
  220. /* For debug use only
  221. var PrintArray = function( listArray, doc )
  222. {
  223. var s = [] ;
  224. for ( var i = 0 ; i < listArray.length ; i++ )
  225. {
  226. for ( var j in listArray[i] )
  227. {
  228. if ( j != 'contents' )
  229. s.push( j + ":" + listArray[i][j] + "; " ) ;
  230. else
  231. {
  232. var docFrag = doc.createDocumentFragment() ;
  233. var tmpNode = doc.createElement( 'span' ) ;
  234. for ( var k = 0 ; k < listArray[i][j].length ; k++ )
  235. docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ;
  236. tmpNode.appendChild( docFrag ) ;
  237. s.push( j + ":" + tmpNode.innerHTML + "; ") ;
  238. }
  239. }
  240. s.push( 'n' ) ;
  241. }
  242. alert( s.join('') ) ;
  243. }
  244. PrintArray( listArray, FCK.EditorDocument ) ;
  245. */
  246. // Convert the array back to a DOM forest (yes we might have a few subtrees now).
  247. // And replace the old list with the new forest.
  248. var newList = FCKDomTools.ArrayToList( listArray ) ;
  249. if ( newList )
  250. listNode.parentNode.replaceChild( newList.listNode, listNode ) ;
  251. // Clean up the markers.
  252. FCKDomTools.ClearAllMarkers( markerObj ) ;
  253. }
  254. } ;