Changeset 846


Ignore:
Timestamp:
09/19/07 16:50:29 (7 years ago)
Author:
martinkou
Message:

Added array modeling logic for HTML lists in fckdomtools.js.
Fixed #1231 : Indenting and outdenting of normal blocks are now done by CSS attributes instead of by <blockquote>,
Fixed #1232 : Indenting and outdenting of list items are now XHTML 1.1 compliant.

Location:
FCKeditor/trunk/editor/_source
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • FCKeditor/trunk/editor/_source/commandclasses/fckindentcommands.js

    r837 r846  
    8585                var listNode = FCKDomTools.GetCommonParentNode( startContainer, endContainer, ['ul','ol'] ) ; 
    8686 
    87                 if ( ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) ) || listNode ) 
     87                if ( listNode ) 
     88                { 
     89                        if ( this.Name.IEquals( 'outdent' ) ) 
     90                                return FCK_TRISTATE_OFF ; 
     91                        var firstItem = FCKTools.GetElementAscensor( startContainer, 'li' ) ; 
     92                        if ( !firstItem || !firstItem.previousSibling ) 
     93                                return FCK_TRISTATE_DISABLED ; 
     94                        return FCK_TRISTATE_OFF ; 
     95                } 
     96                if ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) ) 
    8897                        return FCK_TRISTATE_OFF; 
    8998 
     
    166175                                currentOffset += this.Offset ; 
    167176                                currentOffset = Math.max( currentOffset, 0 ) ; 
    168                                 block.style[this.IndentCSSProperty] = currentOffset + 'px' ; 
     177                                currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ; 
     178                                block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + 'px' : '' ; 
     179                                if ( block.getAttribute( 'style' ) == '' ) 
     180                                        block.removeAttribute( 'style' ) ; 
    169181                        } 
    170182                } 
     
    177189                var startContainer = range.StartContainer ; 
    178190                var endContainer = range.EndContainer ; 
    179                 while ( startContainer && ! startContainer.nodeName.IEquals( ['li', 'ul', 'ol'] ) )  
     191                while ( startContainer && startContainer.parentNode != listNode )  
    180192                        startContainer = startContainer.parentNode ; 
    181                 while ( endContainer && ! endContainer.nodeName.IEquals( ['li', 'ul', 'ol'] ) ) 
     193                while ( endContainer && endContainer.parentNode != listNode ) 
    182194                        endContainer = endContainer.parentNode ; 
    183195 
     
    185197                        return ; 
    186198 
    187                 range.SetStart( startContainer, 1 ) ; 
    188                 range.SetEnd( endContainer, 2 ) ; 
    189  
    190                 // Now we can iterate over the individual items. 
    191                 var iterator = new FCKDomRangeIterator( range ) ; 
    192                 var block ; 
     199                // Now we can iterate over the individual items on the same tree depth. 
     200                var block = startContainer ; 
    193201                var itemsToMove = [] ; 
    194                 while ( ( block = iterator.GetNextParagraph() ) ) 
    195                 { 
    196                         if ( block.parentNode == listNode ) 
    197                                 itemsToMove.push( block ) ; 
     202                var stopFlag = false ; 
     203                while ( stopFlag == false )  
     204                { 
     205                        if ( block == endContainer ) 
     206                                stopFlag = true ; 
     207                        itemsToMove.push( block ) ; 
     208                        block = block.nextSibling ; 
    198209                } 
    199210                if ( itemsToMove.length < 1 ) 
    200211                        return ; 
     212 
     213                // Do indent or outdent operations on the array model of the list, not the list's DOM tree itself. 
     214                // The array model demands that it knows as much as possible about the surrounding lists, we need  
     215                // to feed it the further ancestor node that is still a list. 
     216                var listParents = FCKDomTools.GetParents( listNode ) ; 
     217                for ( var i = 0 ; i < listParents.length ; i++ ) 
     218                { 
     219                        if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) ) 
     220                        { 
     221                                listNode = listParents[i] ; 
     222                                break ; 
     223                        } 
     224                } 
     225                var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ; 
     226                var startItem = itemsToMove[0] ; 
    201227                var lastItem = itemsToMove[ itemsToMove.length - 1 ] ; 
    202  
    203                 if ( this.Name.IEquals( 'indent' ) ) 
    204                 { 
    205                         // Indent is easy... just clone the list node, add under the original, and  
    206                         // move the contents inside the clone. 
    207                         var indentList = listNode.cloneNode( false ) ; 
    208                         FCKDomTools.InsertAfterNode( lastItem, indentList ) ; 
    209                         while ( itemsToMove.length > 0 ) 
    210                                 indentList.appendChild( itemsToMove.shift() ) ; 
    211                 } 
    212                 else if ( this.Name.IEquals( 'outdent' ) ) 
    213                 { 
    214                         var startItem = itemsToMove[0] ; 
    215  
    216                         // If we're in the middle of the list, we will have to split the list into two. 
    217                         if ( startItem.previousSibling && lastItem.nextSibling ) 
    218                         { 
    219                                 range.SetStart( startItem, 3 ) ; 
    220                                 range.SetEnd( startItem, 3 ) ; 
    221                                 listNode = range.SplitBlock().NextBlock ; 
    222                         } 
    223  
    224                         // Remove the list items. 
    225                         for ( var i = 0 ; i < itemsToMove.length ; i++ ) 
    226                                 itemsToMove[i].parentNode.removeChild( itemsToMove[i] )  ; 
    227  
    228                         // If the parent of listNode is not another list, then we need to convert the  
    229                         // listItems into paragraphs, depending on EnterMode. 
    230                         if ( ! listNode.parentNode.nodeName.IEquals( ['ul', 'ol'] ) ) 
    231                         { 
    232                                 for ( var i = 0 ; i < itemsToMove.length ; i++ ) 
     228                var markerObj = {} ; 
     229 
     230                // Convert the list DOM tree into a one dimensional array. 
     231                var listArray = FCKDomTools.ListToArray( listNode, null, null, markerObj ) ; 
     232 
     233                // Apply indenting or outdenting on the array. 
     234                var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ; 
     235                for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ )  
     236                        listArray[i].indent += indentOffset ; 
     237                for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ ) 
     238                        listArray[i].indent += indentOffset ; 
     239 
     240                /* For debug use only 
     241                var PrintArray = function( listArray, doc ) 
     242                { 
     243                        var s = [] ; 
     244                        for ( var i = 0 ; i < listArray.length ; i++ ) 
     245                        { 
     246                                for ( var j in listArray[i] ) 
    233247                                { 
    234                                         var container ; 
    235                                         if ( FCKConfig.EnterMode.IEquals( ['p', 'div'] ) ) 
    236                                                 container = listNode.ownerDocument.createElement( FCKConfig.EnterMode ) ; 
     248                                        if ( j != 'contents' ) 
     249                                                s.push( j + ":" + listArray[i][j] + "; " ) ; 
    237250                                        else 
    238251                                        { 
    239                                                 container = listNode.ownerDocument.createDocumentFragment() ; 
    240                                                 container.appendChild( listNode.ownerDocument.createElement( 'br' ) ) ; 
     252                                                var docFrag = doc.createDocumentFragment() ; 
     253                                                var tmpNode = doc.createElement( 'span' ) ; 
     254                                                for ( var k = 0 ; k < listArray[i][j].length ; k++ ) 
     255                                                        docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ; 
     256                                                tmpNode.appendChild( docFrag ) ; 
     257                                                s.push( j + ":" + tmpNode.innerHTML + "; ") ; 
    241258                                        } 
    242  
    243                                         var listItem = itemsToMove[i] ; 
    244                                         while ( listItem.lastChild ) 
    245                                         { 
    246                                                 var node = listItem.removeChild( listItem.lastChild ) ; 
    247                                                 container.insertBefore( node, container.firstChild ) ; 
    248                                         } 
    249                                         itemsToMove[i] = container ; 
    250259                                } 
    251                         } 
    252  
    253                         // Insert the content nodes to listNode's parent. 
    254                         while ( itemsToMove.length > 0 ) 
    255                                 listNode.parentNode.insertBefore( itemsToMove.shift(), listNode ) ; 
    256  
    257                         // Cleanup: if the listNode becomes empty, remove it. 
    258                         if ( ! listNode.lastChild ) 
    259                                 listNode.parentNode.removeChild( listNode ) ; 
    260                 } 
     260                                s.push( '\n' ) ; 
     261                        } 
     262                        alert( s.join('') ) ; 
     263                } 
     264                PrintArray( listArray, FCK.EditorDocument ) ; 
     265                */ 
     266 
     267                // Convert the array back to a DOM forest (yes we might have a few subtrees now). 
     268                // And replace the old list with the new forest. 
     269                var newList = FCKDomTools.ArrayToList( listArray ) ; 
     270                listNode.parentNode.replaceChild( newList.listNode, listNode ) ; 
     271 
     272                // Clean up the markers. 
     273                FCKDomTools.ClearElementMarkers( markerObj ) ; 
    261274        } 
    262275} ; 
  • FCKeditor/trunk/editor/_source/internals/fckdomtools.js

    r824 r846  
    575575                 
    576576                return element ; 
     577        }, 
     578 
     579        ClearElementJSProperty : function( element, attrName ) 
     580        { 
     581                if ( FCKBrowserInfo.IsIE ) 
     582                        element.removeAttribute( attrName ) ; 
     583                else 
     584                        delete element[attrName] ; 
     585        }, 
     586 
     587        SetElementMarker : function ( markObj, element, attrName, value) 
     588        { 
     589                var id = String( parseInt( Math.random() * 0xfffffff, 10 ) ) ; 
     590                element._FCKMarkerId = id ; 
     591                element[attrName] = value ; 
     592                if ( ! markObj[id] ) 
     593                        markObj[id] = { 'element' : element, 'markers' : {} } ; 
     594                markObj[id]['markers'][attrName] = value ; 
     595        }, 
     596 
     597        ClearElementMarkers : function( markObj ) 
     598        { 
     599                for ( var i in markObj ) 
     600                { 
     601                        var element = markObj[i]['element'] ; 
     602                        this.ClearElementJSProperty( element, '_FCKMarkerId' ) ; 
     603                        for ( var j in markObj[i]['markers'] ) 
     604                                this.ClearElementJSProperty( element, j ) ; 
     605                        delete markObj[i] ; 
     606                } 
     607        }, 
     608 
     609        // Convert a DOM list tree into a data structure that is easier to manipulate. 
     610        // This operation should be non-intrusive in the sense that it does not change the DOM tree, 
     611        // with the exception that it may add some markers to the list item nodes when markerObj is specified. 
     612        ListToArray : function( listNode, baseArray, baseIndentLevel, markerObj ) 
     613        { 
     614                if ( ! listNode.nodeName.IEquals( ['ul', 'ol'] ) ) 
     615                        return [] ; 
     616 
     617                if ( ! baseIndentLevel ) 
     618                        baseIndentLevel = 0 ; 
     619                if ( ! baseArray ) 
     620                        baseArray = [] ; 
     621                // Iterate over all list items to get their contents and look for inner lists. 
     622                for ( var i = 0 ; i < listNode.childNodes.length ; i++ ) 
     623                { 
     624                        var listItem = listNode.childNodes[i] ; 
     625                        if ( ! listItem.nodeName.IEquals( 'li' ) ) 
     626                                continue ; 
     627                        var itemObj = { 'grandparent' : listNode.parentNode, 'parent' : listNode, 'indent' : baseIndentLevel, 'contents' : [] } ; 
     628                        if ( itemObj.grandparent && itemObj.grandparent.nodeName.IEquals( 'li' ) ) 
     629                                itemObj.grandparent = itemObj.grandparent.parentNode ; 
     630                        if ( markerObj ) 
     631                                this.SetElementMarker( markerObj, listItem, '_FCK_ListArray_Index', baseArray.length ) ; 
     632                        baseArray.push( itemObj ) ; 
     633                        for ( var j = 0 ; j < listItem.childNodes.length ; j++ ) 
     634                        { 
     635                                var child = listItem.childNodes[j] ; 
     636                                if ( child.nodeName.IEquals( ['ul', 'ol'] ) ) 
     637                                        // Note the recursion here, it pushes inner list items with +1 indentation in the correct 
     638                                        // order. 
     639                                        this.ListToArray( child, baseArray, baseIndentLevel + 1, markerObj ) ; 
     640                                else 
     641                                        itemObj.contents.push( child ) ; 
     642                        } 
     643                } 
     644                return baseArray ; 
     645        }, 
     646 
     647        // Convert our internal representation of a list back to a DOM tree. 
     648        ArrayToList : function( listArray, baseIndex ) 
     649        { 
     650                if ( baseIndex == undefined ) 
     651                        baseIndex = 0 ; 
     652                if ( ! listArray || listArray.length < baseIndex + 1 ) 
     653                        return null ; 
     654                var retval = listArray[baseIndex].parent.ownerDocument.createDocumentFragment() ; 
     655                var rootNode = listArray[baseIndex].parent.cloneNode( false ) ; 
     656                retval.appendChild( rootNode ) ; 
     657                var currentIndex = baseIndex ; 
     658                var indentLevel = listArray[baseIndex].indent ; 
     659                var currentListItem = null ; 
     660                while ( true ) 
     661                { 
     662                        var item = listArray[currentIndex] ; 
     663                        if ( item.indent == indentLevel ) 
     664                        { 
     665                                if ( ! rootNode || listArray[currentIndex].parent.nodeName != rootNode.nodeName ) 
     666                                { 
     667                                        rootNode = listArray[currentIndex].parent.cloneNode( false ) ; 
     668                                        retval.appendChild( rootNode ) ; 
     669                                } 
     670                                currentListItem = rootNode.ownerDocument.createElement( 'li' ) ; 
     671                                rootNode.appendChild( currentListItem ) ; 
     672                                for ( var i = 0 ; i < item.contents.length ; i++ ) 
     673                                        currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ; 
     674                                currentIndex++ ; 
     675                        } 
     676                        else if ( item.indent == Math.max( indentLevel, 0 ) + 1 ) 
     677                        { 
     678                                var listData = this.ArrayToList( listArray, currentIndex ) ; 
     679                                currentListItem.appendChild( listData.listNode ) ; 
     680                                currentIndex = listData.nextIndex ; 
     681                        } 
     682                        else if ( item.indent == -1 && baseIndex == 0 && item.grandparent ) 
     683                        { 
     684                                var currentListItem ; 
     685                                if ( item.grandparent.nodeName.IEquals( ['ul', 'ol'] ) ) 
     686                                        currentListItem = rootNode.ownerDocument.createElement( 'li' ) ; 
     687                                else 
     688                                { 
     689                                        if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) ) 
     690                                                currentListItem = rootNode.ownerDocument.createElement( FCKConfig.EnterMode ) ; 
     691                                        else 
     692                                                currentListItem = rootNode.ownerDocument.createDocumentFragment() ; 
     693                                } 
     694                                item.grandparent.appendChild( currentListItem )  ; 
     695                                for ( var i = 0 ; i < item.contents.length ; i++ ) 
     696                                        currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ; 
     697                                if ( currentListItem.nodeType == 11 ) 
     698                                        currentListItem.appendChild( currentListItem.ownerDocument.createElement( 'br' ) ) ; 
     699                                retval.appendChild( currentListItem ) ; 
     700                                rootNode = null ; 
     701                                currentIndex++ ; 
     702                        } 
     703                        else 
     704                                break ; 
     705 
     706                        if ( listArray.length <= currentIndex || Math.max( listArray[currentIndex].indent, 0 ) < indentLevel ) 
     707                        { 
     708                                break ; 
     709                        } 
     710                } 
     711                return { 'listNode' : retval, 'nextIndex' : currentIndex } ; 
    577712        } 
    578713} ; 
     714 
Note: See TracChangeset for help on using the changeset viewer.
© 2003 – 2012 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy