Changeset 858
- Timestamp:
- 09/21/07 15:56:59 (6 years ago)
- Location:
- FCKeditor/branches/features/custom_list_command
- Files:
-
- 2 edited
- 2 copied
-
. (copied) (copied from FCKeditor/trunk)
-
editor/_source/commandclasses/fcklistcommands.js (modified) (2 diffs)
-
editor/_source/internals/fckcommands.js (modified) (1 diff)
-
editor/_source/internals/fckdomtools.js (copied) (copied from FCKeditor/trunk/editor/_source/internals/fckdomtools.js)
Legend:
- Unmodified
- Added
- Removed
-
FCKeditor/branches/features/custom_list_command/editor/_source/commandclasses/fcklistcommands.js
r771 r858 22 22 */ 23 23 24 var FCKListCommand = function( name ) 24 // TODO: 25 // 1. Handle unioning of lists and paragraphs. 26 // 2. Creating separate lists inside table cells isn't working. 27 28 var FCKListCommand = function( name, tagName ) 25 29 { 26 30 this.Name = name ; 31 this.TagName = tagName ; 27 32 } 28 33 … … 31 36 GetState : function() 32 37 { 33 return FCK.GetNamedCommandState( this.Name ) ; 38 // Disabled if not WYSIWYG. 39 if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow ) 40 return FCK_TRISTATE_DISABLED ; 41 42 // We'll use the style system's convention to determine list state here... 43 // If the starting block is a descendant of an <ol> or <ul> node, then we're in a list. 44 var startContainer = FCKSelection.GetBoundaryParentElement( true ) ; 45 var listNode = FCKTools.GetElementAscensor( startContainer, this.TagName ) ; 46 if ( listNode ) 47 return FCK_TRISTATE_ON ; 48 else 49 return FCK_TRISTATE_OFF ; 34 50 }, 35 51 36 52 Execute : function() 37 53 { 38 if ( FCKBrowserInfo.IsIE && this.GetState() == FCK_TRISTATE_OFF ) 39 { 40 // IE does not split selected <br> tags when it is making lists. (See #428) 41 // So, pre-split the blocks for IE. 42 var range = new FCKDomRange( FCK.EditorWindow ) ; 43 range.MoveToSelection() ; 44 var startNode = range._Range.startContainer ; 45 var endNode = range._Range.endContainer ; 46 if ( startNode.nodeType == 1 ) 47 { 48 if ( startNode.firstChild ) 54 FCKUndo.SaveUndoStep() ; 55 56 var range = new FCKDomRange( FCK.EditorWindow ) ; 57 range.MoveToSelection() ; 58 var bookmark = range.CreateBookmark() ; 59 60 // Group the blocks up because there are many cases where multiple lists have to be created, 61 // or multiple lists have to be cancelled. 62 var listGroups = [] ; 63 var markerObj = {} ; 64 var iterator = new FCKDomRangeIterator( range ) ; 65 var block ; 66 var state = this.GetState() ; 67 iterator.ForceBrBreak = ( state == FCK_TRISTATE_OFF ) ; 68 while ( ( block = iterator.GetNextParagraph() ) ) 69 { 70 var path = new FCKElementPath( block ) ; 71 var listNode = null ; 72 var processedFlag = false ; 73 74 // First, try to group by a list ancestor. 75 for ( var i = path.Elements.length - 1 ; i >= 0 ; i-- ) 76 { 77 var el = path.Elements[i] ; 78 if ( el.nodeName.IEquals( ['ol', 'ul'] ) ) 49 79 { 50 if ( startNode.childNodes.length <= range._Range.startOffset ) 51 startNode = startNode.lastChild ; 80 var groupObj = el._FCK_ListGroupObject ; 81 if ( groupObj ) 82 groupObj.contents.push( block ) ; 52 83 else 53 startNode = startNode.childNodes[ range._Range.startOffset ] ; 84 { 85 groupObj = { 'root' : el, 'contents' : [ block ] } ; 86 listGroups.push( groupObj ) ; 87 FCKDomTools.SetElementMarker( markerObj, el, '_FCK_ListGroupObject', groupObj ) ; 88 } 89 processedFlag = true ; 90 break ; 54 91 } 55 92 } 56 if ( endNode.nodeType == 1 ) 57 { 58 if ( endNode.firstChild ) 93 94 if ( processedFlag ) 95 continue ; 96 97 // No list ancestor? Group by block limit. 98 var root = path.BlockLimit ; 99 if ( root._FCK_ListGroupObject ) 100 root._FCK_ListGroupObject.contents.push( block ) ; 101 else 102 { 103 var groupObj = { 'root' : root, 'contents' : [ block ] } ; 104 FCKDomTools.SetElementMarker( markerObj, root, '_FCK_ListGroupObject', groupObj ) ; 105 listGroups.push( groupObj ) ; 106 } 107 } 108 109 // Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element. 110 // We either have to build lists or remove lists, for removing a list does not makes sense when we are looking 111 // at the group that's not rooted at lists. So we have three cases to handle. 112 while ( listGroups.length > 0 ) 113 { 114 var groupObj = listGroups.shift() ; 115 if ( state == FCK_TRISTATE_OFF ) 116 { 117 if ( groupObj.root.nodeName.IEquals( ['ul', 'ol'] ) ) 118 this._ChangeListType( groupObj, markerObj ) ; 119 else 120 this._CreateList( groupObj ) ; 121 } 122 else if ( state == FCK_TRISTATE_ON && groupObj.root.nodeName.IEquals( ['ul', 'ol'] ) ) 123 this._RemoveList( groupObj, markerObj ) ; 124 } 125 126 // Clean up, restore selection and update toolbar button states. 127 FCKDomTools.ClearElementMarkers( markerObj ) ; 128 range.MoveToBookmark( bookmark ) ; 129 range.Select() ; 130 FCK.Events.FireEvent( 'OnSelectionChange' ) ; 131 }, 132 133 _ChangeListType : function( groupObj, markerObj ) 134 { 135 // This case is easy... 136 // 1. Convert the whole list into a one-dimensional array. 137 // 2. Change the list type by modifying the array. 138 // 3. Recreate the whole list by converting the array to a list. 139 // 4. Replace the original list with the recreated list. 140 var listArray = FCKDomTools.ListToArray( groupObj.root, null, null, markerObj ) ; 141 var selectedListItems = [] ; 142 for ( var i = 0 ; i < groupObj.contents.length ; i++ ) 143 { 144 var itemNode = groupObj.contents[i] ; 145 itemNode = FCKTools.GetElementAscensor( itemNode, 'li' ) ; 146 if ( ! itemNode || itemNode._FCK_ListItem_Processed ) 147 continue ; 148 selectedListItems.push( itemNode ) ; 149 FCKDomTools.SetElementMarker( markerObj, itemNode, '_FCK_ListItem_Processed', true ) ; 150 } 151 var fakeParent = groupObj.root.ownerDocument.createElement( this.TagName ) ; 152 for ( var i = 0 ; i < selectedListItems.length ; i++ ) 153 { 154 var listIndex = selectedListItems[i]._FCK_ListArray_Index ; 155 listArray[listIndex].parent = fakeParent ; 156 } 157 var newList = FCKDomTools.ArrayToList( listArray ) ; 158 groupObj.root.parentNode.replaceChild( newList.listNode, groupObj.root ) ; 159 }, 160 161 _CreateList : function( groupObj ) 162 { 163 var contents = groupObj.contents ; 164 var commonParent = groupObj.contents[0].parentNode ; 165 var listContents = [] ; 166 for ( var i = 0 ; i < contents.length ; i++ ) 167 commonParent = FCKDomTools.GetCommonParents( commonParent, contents[i].parentNode ).pop() ; 168 for ( var i = 0 ; i < contents.length ; i++ ) 169 { 170 var contentNode = contents[i] ; 171 while ( contentNode.parentNode ) 172 { 173 if ( contentNode.parentNode == commonParent ) 59 174 { 60 if ( endNode.childNodes.length <= range._Range.endOffset ) 61 endNode = endNode.lastChild ; 62 else 63 endNode = endNode.childNodes[ range._Range.endOffset ] ; 175 listContents.push( contentNode ) ; 176 break ; 64 177 } 65 } 66 67 var brNodes = [] ; 68 var curNode = startNode ; 69 while ( curNode && curNode != endNode ) 70 { 71 if ( curNode.nodeType == 1 && curNode.tagName.toLowerCase() == 'br' ) 72 brNodes.push( curNode ) ; 73 curNode = FCKTools.GetNextNode( curNode ) ; 74 } 75 76 for ( var i = brNodes.length - 1 ; i >= 0 ; i-- ) 77 { 78 range.SetStart( brNodes[i], 3 ) ; 79 range.SetEnd( brNodes[i], 3 ) ; 80 brNodes[i].parentNode.removeChild( brNodes[i] ) ; 81 range.SplitBlock() ; 82 } 83 84 range.SetStart( startNode, 1 ) ; 85 range.SetEnd( endNode, 4 ) ; 86 range.Select() ; 87 } 88 FCK.ExecuteNamedCommand( this.Name ) ; 178 contentNode = contentNode.parentNode ; 179 } 180 } 181 182 if ( listContents.length < 1 ) 183 return ; 184 185 var insertAnchor = listContents[listContents.length - 1].nextSibling ; 186 var doc = commonParent.ownerDocument ; 187 var listNode = doc.createElement( this.TagName ) ; 188 while ( listContents.length ) 189 { 190 var contentBlock = listContents.shift() ; 191 var docFrag = doc.createDocumentFragment() ; 192 while ( contentBlock.firstChild ) 193 docFrag.appendChild( contentBlock.removeChild( contentBlock.firstChild ) ) ; 194 contentBlock.parentNode.removeChild( contentBlock ) ; 195 var listItem = doc.createElement( 'li' ) ; 196 listItem.appendChild( docFrag ) ; 197 listNode.appendChild( listItem ) ; 198 } 199 commonParent.insertBefore( listNode, insertAnchor ) ; 200 }, 201 202 _RemoveList : function( groupObj, markerObj ) 203 { 204 // This is very much like the change list type operation. 205 // Except that we're changing the selected items' indent to -1 in the list array. 206 var listArray = FCKDomTools.ListToArray( groupObj.root, null, null, markerObj ) ; 207 var selectedListItems = [] ; 208 for ( var i = 0 ; i < groupObj.contents.length ; i++ ) 209 { 210 var itemNode = groupObj.contents[i] ; 211 itemNode = FCKTools.GetElementAscensor( itemNode, 'li' ) ; 212 if ( ! itemNode || itemNode._FCK_ListItem_Processed ) 213 continue ; 214 selectedListItems.push( itemNode ) ; 215 FCKDomTools.SetElementMarker( markerObj, itemNode, '_FCK_ListItem_Processed', true ) ; 216 } 217 218 var lastListIndex = null ; 219 for ( var i = 0 ; i < selectedListItems.length ; i++ ) 220 { 221 var listIndex = selectedListItems[i]._FCK_ListArray_Index ; 222 listArray[listIndex].indent = -1 ; 223 lastListIndex = listIndex ; 224 } 225 226 // After cutting parts of the list out with indent=-1, we still have to maintain the array list 227 // model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the 228 // list cannot be converted back to a real DOM list. 229 for ( var i = lastListIndex + 1; i < listArray.length ; i++ ) 230 { 231 if ( listArray[i].indent > listArray[i-1].indent + 1 ) 232 { 233 var indentOffset = listArray[i-1].indent + 1 - listArray[i].indent ; 234 var oldIndent = listArray[i].indent ; 235 while ( listArray[i] && listArray[i].indent >= oldIndent) 236 { 237 listArray[i].indent += indentOffset ; 238 i++ ; 239 } 240 i-- ; 241 } 242 } 243 244 var newList = FCKDomTools.ArrayToList( listArray ) ; 245 groupObj.root.parentNode.replaceChild( newList.listNode, groupObj.root ) ; 89 246 } 90 247 }; -
FCKeditor/branches/features/custom_list_command/editor/_source/internals/fckcommands.js
r850 r858 131 131 132 132 case 'SelectAll' : oCommand = new FCKSelectAllCommand() ; break ; 133 case 'InsertOrderedList' : oCommand = new FCKListCommand( 'insertorderedlist' ) ; break ;134 case 'InsertUnorderedList' : oCommand = new FCKListCommand( 'insertunorderedlist' ) ; break ;133 case 'InsertOrderedList' : oCommand = new FCKListCommand( 'insertorderedlist', 'ol' ) ; break ; 134 case 'InsertUnorderedList' : oCommand = new FCKListCommand( 'insertunorderedlist', 'ul' ) ; break ; 135 135 case 'ShowBlocks' : oCommand = new FCKShowBlockCommand( 'ShowBlocks', FCKConfig.StartupShowBlocks ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ) ; break ; 136 136
Note: See TracChangeset
for help on using the changeset viewer.
