Вход Регистрация
Файл: fckeditor/editor/_source/commandclasses/fcklistcommands.js
Строк: 534
<?php

/*
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
 * Copyright (C) 2003-2008 Frederico Caldeira Knabben
 *
 * == BEGIN LICENSE ==
 *
 * Licensed under the terms of any of the following licenses at your
 * choice:
 *
 *  - GNU General Public License Version 2 or later (the "GPL")
 *    http://www.gnu.org/licenses/gpl.html
 *
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 *    http://www.gnu.org/licenses/lgpl.html
 *
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
 *    http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * == END LICENSE ==
 *
 * Implementation for the "Insert/Remove Ordered/Unordered List" commands.
 */

var FCKListCommand = function( nametagName )
{
    
this.Name name ;
    
this.TagName tagName ;
}

FCKListCommand.prototype =
{
    
GetState : function()
    {
        
// Disabled if not WYSIWYG.
        
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
            return 
FCK_TRISTATE_DISABLED ;

        
// We'll use the style system's convention to determine list state here...
        // If the starting block is a descendant of an <ol> or <ul> node, then we're in a list.
        
var startContainer FCKSelection.GetBoundaryParentElementtrue ) ;
        var 
listNode startContainer ;
        while ( 
listNode )
        {
            if ( 
listNode.nodeName.IEquals( [ 'ul''ol' ] ) )
                break ;
            
listNode listNode.parentNode ;
        }
        if ( 
listNode && listNode.nodeName.IEqualsthis.TagName ) )
            return 
FCK_TRISTATE_ON ;
        else
            return 
FCK_TRISTATE_OFF ;
    },

    
Execute : function()
    {
        
FCKUndo.SaveUndoStep() ;

        var 
doc FCK.EditorDocument ;
        var 
range = new FCKDomRangeFCK.EditorWindow ) ;
        
range.MoveToSelection() ;
        var 
state this.GetState() ;

        
// Midas lists rule #1 says we can create a list even in an empty document.
        // But FCKDomRangeIterator wouldn't run if the document is really empty.
        // So create a paragraph if the document is empty and we're going to create a list.
        
if ( state == FCK_TRISTATE_OFF )
        {
            
FCKDomTools.TrimNodedoc.body ) ;
            if ( ! 
doc.body.firstChild )
            {
                var 
paragraph doc.createElement'p' ) ;
                
doc.body.appendChildparagraph ) ;
                
range.MoveToNodeContentsparagraph ) ;
            }
        }

        var 
bookmark range.CreateBookmark() ;

        
// Group the blocks up because there are many cases where multiple lists have to be created,
        // or multiple lists have to be cancelled.
        
var listGroups = [] ;
        var 
markerObj = {} ;
        var 
iterator = new FCKDomRangeIteratorrange ) ;
        var 
block ;

        
iterator.ForceBrBreak = ( state == FCK_TRISTATE_OFF ) ;
        var 
nextRangeExists true ;
        var 
rangeQueue null ;
        while ( 
nextRangeExists )
        {
            while ( ( 
block iterator.GetNextParagraph() ) )
            {
                var 
path = new FCKElementPathblock ) ;
                var 
listNode null ;
                var 
processedFlag false ;
                var 
blockLimit path.BlockLimit ;

                
// First, try to group by a list ancestor.
                
for ( var path.Elements.length >= i-- )
                {
                    var 
el path.Elements[i] ;
                    if ( 
el.nodeName.IEquals( ['ol''ul'] ) )
                    {
                        
// If we've encountered a list inside a block limit
                        // The last group object of the block limit element should
                        // no longer be valid. Since paragraphs after the list
                        // should belong to a different group of paragraphs before
                        // the list. (Bug #1309)
                        
if ( blockLimit._FCK_ListGroupObject )
                            
blockLimit._FCK_ListGroupObject null ;

                        var 
groupObj el._FCK_ListGroupObject ;
                        if ( 
groupObj )
                            
groupObj.contents.pushblock ) ;
                        else
                        {
                            
groupObj = { 'root' el'contents' : [ block ] } ;
                            
listGroups.pushgroupObj ) ;
                            
FCKDomTools.SetElementMarkermarkerObjel'_FCK_ListGroupObject'groupObj ) ;
                        }
                        
processedFlag true ;
                        break ;
                    }
                }

                if ( 
processedFlag )
                    continue ;

                
// No list ancestor? Group by block limit.
                
var root blockLimit ;
                if ( 
root._FCK_ListGroupObject )
                    
root._FCK_ListGroupObject.contents.pushblock ) ;
                else
                {
                    var 
groupObj = { 'root' root'contents' : [ block ] } ;
                    
FCKDomTools.SetElementMarkermarkerObjroot'_FCK_ListGroupObject'groupObj ) ;
                    
listGroups.pushgroupObj ) ;
                }
            }

            if ( 
FCKBrowserInfo.IsIE )
                
nextRangeExists false ;
            else
            {
                if ( 
rangeQueue == null )
                {
                    
rangeQueue = [] ;
                    var 
selectionObject FCKSelection.GetSelection() ;
                    if ( 
selectionObject && listGroups.length == )
                        
rangeQueue.pushselectionObject.getRangeAt) ) ;
                    for ( var 
selectionObject && selectionObject.rangeCount i++ )
                        
rangeQueue.pushselectionObject.getRangeAt) ) ;
                }
                if ( 
rangeQueue.length )
                    
nextRangeExists false ;
                else
                {
                    var 
internalRange FCKW3CRange.CreateFromRangedocrangeQueue.shift() ) ;
                    
range._Range internalRange ;
                    
range._UpdateElementInfo() ;
                    if ( 
range.StartNode.nodeName.IEquals'td' ) )
                        
range.SetStartrange.StartNode) ;
                    if ( 
range.EndNode.nodeName.IEquals'td' ) )
                        
range.SetEndrange.EndNode) ;
                    
iterator = new FCKDomRangeIteratorrange ) ;
                    
iterator.ForceBrBreak = ( state == FCK_TRISTATE_OFF ) ;
                }
            }
        }

        
// Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element.
        // We either have to build lists or remove lists, for removing a list does not makes sense when we are looking
        // at the group that's not rooted at lists. So we have three cases to handle.
        
var listsCreated = [] ;
        while ( 
listGroups.length )
        {
            var 
groupObj listGroups.shift() ;
            if ( 
state == FCK_TRISTATE_OFF )
            {
                if ( 
groupObj.root.nodeName.IEquals( ['ul''ol'] ) )
                    
this._ChangeListTypegroupObjmarkerObjlistsCreated ) ;
                else
                    
this._CreateListgroupObjlistsCreated ) ;
            }
            else if ( 
state == FCK_TRISTATE_ON && groupObj.root.nodeName.IEquals( ['ul''ol'] ) )
                
this._RemoveListgroupObjmarkerObj ) ;
        }

        
// For all new lists created, merge adjacent, same type lists.
        
for ( var listsCreated.length i++ )
        {
            var 
listNode listsCreated[i] ;
            var 
stopFlag false ;
            var 
currentNode listNode ;
            while ( ! 
stopFlag )
            {
                
currentNode currentNode.nextSibling ;
                if ( 
currentNode && currentNode.nodeType == && currentNode.nodeValue.search( /^[nrt ]*$/ ) == )
                    continue ;
                
stopFlag true ;
            }

            if ( 
currentNode && currentNode.nodeName.IEqualsthis.TagName ) )
            {
                
currentNode.parentNode.removeChildcurrentNode ) ;
                while ( 
currentNode.firstChild )
                    
listNode.appendChildcurrentNode.removeChildcurrentNode.firstChild ) ) ;
            }

            
stopFlag false ;
            
currentNode listNode ;
            while ( ! 
stopFlag )
            {
                
currentNode currentNode.previousSibling ;
                if ( 
currentNode && currentNode.nodeType == && currentNode.nodeValue.search( /^[nrt ]*$/ ) == )
                    continue ;
                
stopFlag true ;
            }
            if ( 
currentNode && currentNode.nodeName.IEqualsthis.TagName ) )
            {
                
currentNode.parentNode.removeChildcurrentNode ) ;
                while ( 
currentNode.lastChild )
                    
listNode.insertBeforecurrentNode.removeChildcurrentNode.lastChild ),
                               
listNode.firstChild ) ;
            }
        }

        
// Clean up, restore selection and update toolbar button states.
        
FCKDomTools.ClearAllMarkersmarkerObj ) ;
        
range.MoveToBookmarkbookmark ) ;
        
range.Select() ;

        
FCK.Focus() ;
        
FCK.Events.FireEvent'OnSelectionChange' ) ;
    },

    
_ChangeListType : function( groupObjmarkerObjlistsCreated )
    {
        
// This case is easy...
        // 1. Convert the whole list into a one-dimensional array.
        // 2. Change the list type by modifying the array.
        // 3. Recreate the whole list by converting the array to a list.
        // 4. Replace the original list with the recreated list.
        
var listArray FCKDomTools.ListToArraygroupObj.rootmarkerObj ) ;
        var 
selectedListItems = [] ;
        for ( var 
groupObj.contents.length i++ )
        {
            var 
itemNode groupObj.contents[i] ;
            
itemNode FCKTools.GetElementAscensoritemNode'li' ) ;
            if ( ! 
itemNode || itemNode._FCK_ListItem_Processed )
                continue ;
            
selectedListItems.pushitemNode ) ;
            
FCKDomTools.SetElementMarkermarkerObjitemNode'_FCK_ListItem_Processed'true ) ;
        }
        var 
fakeParent FCKTools.GetElementDocumentgroupObj.root ).createElementthis.TagName ) ;
        for ( var 
selectedListItems.length i++ )
        {
            var 
listIndex selectedListItems[i]._FCK_ListArray_Index ;
            
listArray[listIndex].parent fakeParent ;
        }
        var 
newList FCKDomTools.ArrayToListlistArraymarkerObj ) ;
        for ( var 
newList.listNode.childNodes.length i++ )
        {
            if ( 
newList.listNode.childNodes[i].nodeName.IEqualsthis.TagName ) )
                
listsCreated.pushnewList.listNode.childNodes[i] ) ;
        }
        
groupObj.root.parentNode.replaceChildnewList.listNodegroupObj.root ) ;
    },

    
_CreateList : function( groupObjlistsCreated )
    {
        var 
contents groupObj.contents ;
        var 
doc FCKTools.GetElementDocumentgroupObj.root ) ;
        var 
listContents = [] ;

        
// It is possible to have the contents returned by DomRangeIterator to be the same as the root.
        // e.g. when we're running into table cells.
        // In such a case, enclose the childNodes of contents[0] into a <div>.
        
if ( contents.length == && contents[0] == groupObj.root )
        {
            var 
divBlock doc.createElement'div' );
            while ( 
contents[0].firstChild )
                
divBlock.appendChildcontents[0].removeChildcontents[0].firstChild ) ) ;
            
contents[0].appendChilddivBlock ) ;
            
contents[0] = divBlock ;
        }

        
// Calculate the common parent node of all content blocks.
        
var commonParent groupObj.contents[0].parentNode ;
        for ( var 
contents.length i++ )
            
commonParent FCKDomTools.GetCommonParentscommonParentcontents[i].parentNode ).pop() ;

        
// We want to insert things that are in the same tree level only, so calculate the contents again
        // by expanding the selected blocks to the same tree level.
        
for ( var contents.length i++ )
        {
            var 
contentNode contents[i] ;
            while ( 
contentNode.parentNode )
            {
                if ( 
contentNode.parentNode == commonParent )
                {
                    
listContents.pushcontentNode ) ;
                    break ;
                }
                
contentNode contentNode.parentNode ;
            }
        }

        if ( 
listContents.length )
            return ;

        
// Insert the list to the DOM tree.
        
var insertAnchor listContents[listContents.length 1].nextSibling ;
        var 
listNode doc.createElementthis.TagName ) ;
        
listsCreated.pushlistNode ) ;
        while ( 
listContents.length )
        {
            var 
contentBlock listContents.shift() ;
            var 
docFrag doc.createDocumentFragment() ;
            while ( 
contentBlock.firstChild )
                
docFrag.appendChildcontentBlock.removeChildcontentBlock.firstChild ) ) ;
            
contentBlock.parentNode.removeChildcontentBlock ) ;
            var 
listItem doc.createElement'li' ) ;
            
listItem.appendChilddocFrag ) ;
            
listNode.appendChildlistItem ) ;
        }
        
commonParent.insertBeforelistNodeinsertAnchor ) ;
    },

    
_RemoveList : function( groupObjmarkerObj )
    {
        
// This is very much like the change list type operation.
        // Except that we're changing the selected items' indent to -1 in the list array.
        
var listArray FCKDomTools.ListToArraygroupObj.rootmarkerObj ) ;
        var 
selectedListItems = [] ;
        for ( var 
groupObj.contents.length i++ )
        {
            var 
itemNode groupObj.contents[i] ;
            
itemNode FCKTools.GetElementAscensoritemNode'li' ) ;
            if ( ! 
itemNode || itemNode._FCK_ListItem_Processed )
                continue ;
            
selectedListItems.pushitemNode ) ;
            
FCKDomTools.SetElementMarkermarkerObjitemNode'_FCK_ListItem_Processed'true ) ;
        }

        var 
lastListIndex null ;
        for ( var 
selectedListItems.length i++ )
        {
            var 
listIndex selectedListItems[i]._FCK_ListArray_Index ;
            
listArray[listIndex].indent = -;
            
lastListIndex listIndex ;
        }

        
// After cutting parts of the list out with indent=-1, we still have to maintain the array list
        // model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the
        // list cannot be converted back to a real DOM list.
        
for ( var lastListIndex 1listArray.length i++ )
        {
            if ( 
listArray[i].indent listArray[i-1].indent )
            {
                var 
indentOffset listArray[i-1].indent listArray[i].indent ;
                var 
oldIndent listArray[i].indent ;
                while ( 
listArray[i] && listArray[i].indent >= oldIndent)
                {
                    
listArray[i].indent += indentOffset ;
                    
i++ ;
                }
                
i-- ;
            }
        }

        var 
newList FCKDomTools.ArrayToListlistArraymarkerObj ) ;
        
// If groupObj.root is the last element in its parent, or its nextSibling is a <br>, then we should
        // not add a <br> after the final item. So, check for the cases and trim the <br>.
        
if ( groupObj.root.nextSibling == null || groupObj.root.nextSibling.nodeName.IEquals'br' ) )
        {
            if ( 
newList.listNode.lastChild.nodeName.IEquals'br' ) )
                
newList.listNode.removeChildnewList.listNode.lastChild ) ;
        }
        
groupObj.root.parentNode.replaceChildnewList.listNodegroupObj.root ) ;
    }
};
?>
Онлайн: 0
Реклама