fckindentcommands.js
上传用户:ah_jiwei
上传日期:2022-07-24
资源大小:54044k
文件大小:10k
源码类别:

数据库编程

开发平台:

Visual C++

  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.  * 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. range.Expand( 'block_contents' ) ;
  122. var commonParents = FCKDomTools.GetCommonParents( range.StartContainer, range.EndContainer ) ;
  123. var nearestParent = commonParents[commonParents.length - 1] ;
  124. var block ;
  125. while ( ( block = iterator.GetNextParagraph() ) )
  126. {
  127. // We don't want to indent subtrees recursively, so only perform the indent operation
  128. // if the block itself is the nearestParent, or the block's parent is the nearestParent.
  129. if ( ! ( block == nearestParent || block.parentNode == nearestParent ) )
  130. continue ;
  131. if ( FCKIndentCommand._UseIndentClasses )
  132. {
  133. // Transform current class name to indent step index.
  134. var indentClass = block.className.match( FCKIndentCommand._ClassNameRegex ) ;
  135. var indentStep = 0 ;
  136. if ( indentClass != null )
  137. {
  138. indentClass = indentClass[1] ;
  139. indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;
  140. }
  141. // Operate on indent step index, transform indent step index back to class name.
  142. if ( this.Name.IEquals( 'outdent' ) )
  143. indentStep-- ;
  144. else if ( this.Name.IEquals( 'indent' ) )
  145. indentStep++ ;
  146. indentStep = Math.min( indentStep, FCKConfig.IndentClasses.length ) ;
  147. indentStep = Math.max( indentStep, 0 ) ;
  148. var className = block.className.replace( FCKIndentCommand._ClassNameRegex, '' ) ;
  149. if ( indentStep < 1 )
  150. block.className = className ;
  151. else
  152. block.className = ( className.length > 0 ? className + ' ' : '' ) +
  153. FCKConfig.IndentClasses[indentStep - 1] ;
  154. }
  155. else
  156. {
  157. // Offset distance is assumed to be in pixels for now.
  158. var currentOffset = parseInt( block.style[this.IndentCSSProperty], 10 ) ;
  159. if ( isNaN( currentOffset ) )
  160. currentOffset = 0 ;
  161. currentOffset += this.Offset ;
  162. currentOffset = Math.max( currentOffset, 0 ) ;
  163. currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ;
  164. block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + FCKConfig.IndentUnit : '' ;
  165. if ( block.getAttribute( 'style' ) == '' )
  166. block.removeAttribute( 'style' ) ;
  167. }
  168. }
  169. },
  170. _IndentList : function( range, listNode )
  171. {
  172. // Our starting and ending points of the range might be inside some blocks under a list item...
  173. // So before playing with the iterator, we need to expand the block to include the list items.
  174. var startContainer = range.StartContainer ;
  175. var endContainer = range.EndContainer ;
  176. while ( startContainer && startContainer.parentNode != listNode )
  177. startContainer = startContainer.parentNode ;
  178. while ( endContainer && endContainer.parentNode != listNode )
  179. endContainer = endContainer.parentNode ;
  180. if ( ! startContainer || ! endContainer )
  181. return ;
  182. // Now we can iterate over the individual items on the same tree depth.
  183. var block = startContainer ;
  184. var itemsToMove = [] ;
  185. var stopFlag = false ;
  186. while ( stopFlag == false )
  187. {
  188. if ( block == endContainer )
  189. stopFlag = true ;
  190. itemsToMove.push( block ) ;
  191. block = block.nextSibling ;
  192. }
  193. if ( itemsToMove.length < 1 )
  194. return ;
  195. // Do indent or outdent operations on the array model of the list, not the list's DOM tree itself.
  196. // The array model demands that it knows as much as possible about the surrounding lists, we need
  197. // to feed it the further ancestor node that is still a list.
  198. var listParents = FCKDomTools.GetParents( listNode ) ;
  199. for ( var i = 0 ; i < listParents.length ; i++ )
  200. {
  201. if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) )
  202. {
  203. listNode = listParents[i] ;
  204. break ;
  205. }
  206. }
  207. var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ;
  208. var startItem = itemsToMove[0] ;
  209. var lastItem = itemsToMove[ itemsToMove.length - 1 ] ;
  210. var markerObj = {} ;
  211. // Convert the list DOM tree into a one dimensional array.
  212. var listArray = FCKDomTools.ListToArray( listNode, markerObj ) ;
  213. // Apply indenting or outdenting on the array.
  214. var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ;
  215. for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ )
  216. listArray[i].indent += indentOffset ;
  217. for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ )
  218. listArray[i].indent += indentOffset ;
  219. /* For debug use only
  220. var PrintArray = function( listArray, doc )
  221. {
  222. var s = [] ;
  223. for ( var i = 0 ; i < listArray.length ; i++ )
  224. {
  225. for ( var j in listArray[i] )
  226. {
  227. if ( j != 'contents' )
  228. s.push( j + ":" + listArray[i][j] + "; " ) ;
  229. else
  230. {
  231. var docFrag = doc.createDocumentFragment() ;
  232. var tmpNode = doc.createElement( 'span' ) ;
  233. for ( var k = 0 ; k < listArray[i][j].length ; k++ )
  234. docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ;
  235. tmpNode.appendChild( docFrag ) ;
  236. s.push( j + ":" + tmpNode.innerHTML + "; ") ;
  237. }
  238. }
  239. s.push( 'n' ) ;
  240. }
  241. alert( s.join('') ) ;
  242. }
  243. PrintArray( listArray, FCK.EditorDocument ) ;
  244. */
  245. // Convert the array back to a DOM forest (yes we might have a few subtrees now).
  246. // And replace the old list with the new forest.
  247. var newList = FCKDomTools.ArrayToList( listArray ) ;
  248. if ( newList )
  249. listNode.parentNode.replaceChild( newList.listNode, listNode ) ;
  250. // Clean up the markers.
  251. FCKDomTools.ClearAllMarkers( markerObj ) ;
  252. }
  253. } ;