Ticket #2864: 2864_2.patch

File 2864_2.patch, 31.5 KB (added by Martin Kou, 12 years ago)
  • _source/plugins/selection/plugin.js

     
    110110                                });
    111111                }
    112112        });
    113 })();
    114113
    115 /**
    116  * Gets the current selection from the editing area when in WYSIWYG mode.
    117  * @returns {CKEDITOR.dom.selection} A selection object or null if not on
    118  *              WYSIWYG mode or no selection is available.
    119  * @example
    120  * var selection = CKEDITOR.instances.editor1.<b>getSelection()</b>;
    121  * alert( selection.getType() );
    122  */
    123 CKEDITOR.editor.prototype.getSelection = function()
    124 {
    125         var retval = this.document ? this.document.getSelection() : null;
     114        /**
     115        * Gets the current selection from the editing area when in WYSIWYG mode.
     116        * @returns {CKEDITOR.dom.selection} A selection object or null if not on
     117        *              WYSIWYG mode or no selection is available.
     118        * @example
     119        * var selection = CKEDITOR.instances.editor1.<b>getSelection()</b>;
     120        * alert( selection.getType() );
     121        */
     122        CKEDITOR.editor.prototype.getSelection = function()
     123        {
     124                var retval = this.document ? this.document.getSelection() : null;
    126125
     126                /**
     127                 * IE BUG: The selection's document may be a different document than the
     128                 * editor document. Return null if that's the case.
     129                 */
     130                if ( retval && CKEDITOR.env.ie )
     131                {
     132                        var range = retval.getNative().createRange();
     133                        if ( !range )
     134                                return null;
     135                        else if ( range.item )
     136                                return range.item(0).ownerDocument == this.document.$ ? retval : null;
     137                        else
     138                                return range.parentElement().ownerDocument == this.document.$ ? retval : null;
     139                }
     140
     141                retval.onSelectionSet = CKEDITOR.tools.bind( checkSelectionChangeTimeout, this );
     142                return retval;
     143        };
     144
    127145        /**
    128          * IE BUG: The selection's document may be a different document than the
    129          * editor document. Return null if that's the case.
     146         * Gets the current selection from the document.
     147         * @returns {CKEDITOR.dom.selection} A selection object.
     148         * @example
     149         * var selection = CKEDITOR.instances.editor1.document.<b>getSelection()</b>;
     150         * alert( selection.getType() );
    130151         */
    131         if ( retval && CKEDITOR.env.ie )
     152        CKEDITOR.dom.document.prototype.getSelection = function()
    132153        {
    133                 var range = retval.getNative().createRange();
    134                 if ( !range )
    135                         return null;
    136                 else if ( range.item )
    137                         return range.item(0).ownerDocument == this.document.$ ? retval : null;
    138                 else
    139                         return range.parentElement().ownerDocument == this.document.$ ? retval : null;
    140         }
    141         return retval;
    142 };
     154                return new CKEDITOR.dom.selection( this );
     155        };
    143156
    144 /**
    145  * Gets the current selection from the document.
    146  * @returns {CKEDITOR.dom.selection} A selection object.
    147  * @example
    148  * var selection = CKEDITOR.instances.editor1.document.<b>getSelection()</b>;
    149  * alert( selection.getType() );
    150  */
    151 CKEDITOR.dom.document.prototype.getSelection = function()
    152 {
    153         return new CKEDITOR.dom.selection( this );
    154 };
     157        /**
     158         * No selection.
     159         * @constant
     160         * @example
     161         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
     162         *     alert( 'Nothing is selected' );
     163         */
     164        CKEDITOR.SELECTION_NONE         = 1;
    155165
    156 /**
    157  * No selection.
    158  * @constant
    159  * @example
    160  * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
    161  *     alert( 'Nothing is selected' );
    162  */
    163 CKEDITOR.SELECTION_NONE         = 1;
     166        /**
     167         * Text or collapsed selection.
     168        * @constant
     169        * @example
     170         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
     171         *     alert( 'Text is selected' );
     172        */
     173        CKEDITOR.SELECTION_TEXT         = 2;
    164174
    165 /**
    166  * Text or collapsed selection.
    167  * @constant
    168  * @example
    169  * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
    170  *     alert( 'Text is selected' );
    171  */
    172 CKEDITOR.SELECTION_TEXT         = 2;
     175        /**
     176         * Element selection.
     177        * @constant
     178        * @example
     179         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
     180         *     alert( 'An element is selected' );
     181        */
     182        CKEDITOR.SELECTION_ELEMENT      = 3;
    173183
    174 /**
    175  * Element selection.
    176  * @constant
    177  * @example
    178  * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
    179  *     alert( 'An element is selected' );
    180  */
    181 CKEDITOR.SELECTION_ELEMENT      = 3;
    182 
    183 /**
    184  * Manipulates the selection in a DOM document.
    185  * @constructor
    186  * @example
    187  */
    188 CKEDITOR.dom.selection = function( document )
    189 {
    190         this.document = document;
    191         this._ =
     184        /**
     185         * Manipulates the selection in a DOM document.
     186         * @constructor
     187         * @example
     188         */
     189        CKEDITOR.dom.selection = function( document )
    192190        {
    193                 cache : {}
     191                this.document = document;
     192                this._ =
     193                {
     194                        cache : {}
     195                };
    194196        };
    195 };
    196197
    197 (function()
    198 {
    199198        var styleObjectElements = { img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1 };
    200199
    201200        CKEDITOR.dom.selection.prototype =
     
    578577                                        }
    579578
    580579                                        range.select();
     580                                        this.onSelectionSet && this.onSelectionSet();
    581581                                }
    582582                        :
    583583                                function( element )
     
    590590                                        var sel = this.getNative();
    591591                                        sel.removeAllRanges();
    592592                                        sel.addRange( range );
     593                                        this.onSelectionSet && this.onSelectionSet();
    593594                                },
    594595
    595596                selectRanges :
     
    600601                                        // select the first one.
    601602                                        if ( ranges[ 0 ] )
    602603                                                ranges[ 0 ].select();
     604                                        this.onSelectionSet && this.onSelectionSet();
    603605                                }
    604606                        :
    605607                                function( ranges )
     
    617619                                                // Select the range.
    618620                                                sel.addRange( nativeRange );
    619621                                        }
     622                                        this.onSelectionSet && this.onSelectionSet();
    620623                                },
    621624
    622625                createBookmarks : function()
  • _source/plugins/toolbar/plugin.js

     
    209209                'Source', '-',
    210210                'NewPage', '-',
    211211                'Bold', 'Italic', 'Underline', 'Strike', '-',
     212                'NumberedList', 'BulletedList', '-',
    212213                'Subscript', 'Superscript', '-',
    213214                'SelectAll', 'RemoveFormat', '-',
    214215                'Smiley', 'HorizontalRule', 'SpecialChar', 'PageBreak'
  • _source/plugins/list/plugin.js

     
     1/*
     2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
     3For licensing, see LICENSE.html or http://ckeditor.com/license
     4*/
     5
     6/**
     7 * @file Insert and remove numbered and bulleted lists.
     8 */
     9
     10(function()
     11{
     12        var listNodeNames = { ol : 1, ul : 1 },
     13                emptyTextRegex = /^[\n\r\t ]*$/;
     14
     15        CKEDITOR.plugins.list = {
     16                /*
     17                 * Convert a DOM list tree into a data structure that is easier to
     18                 * manipulate. This operation should be non-intrusive in the sense that it
     19                 * does not change the DOM tree, with the exception that it may add some
     20                 * markers to the list item nodes when database is specified.
     21                 */
     22                listToArray : function( listNode, database, baseArray, baseIndentLevel, grandparentNode )
     23                {
     24                        if ( !listNodeNames[ listNode.getName() ] )
     25                                return [];
     26
     27                        if ( !baseIndentLevel )
     28                                baseIndentLevel = 0;
     29                        if ( !baseArray )
     30                                baseArray = [];
     31
     32                        // Iterate over all list items to get their contents and look for inner lists.
     33                        for ( var i = 0, count = listNode.getChildCount() ; i < count ; i++ )
     34                        {
     35                                var listItem = listNode.getChild( i );
     36
     37                                // It may be a text node or some funny stuff.
     38                                if ( listItem.$.nodeName.toLowerCase() != 'li' )
     39                                        continue;
     40                                var itemObj = { 'parent' : listNode, indent : baseIndentLevel, contents : [] };
     41                                if ( !grandparentNode )
     42                                {
     43                                        itemObj.grandparent = listNode.getParent();
     44                                        if ( itemObj.grandparent && itemObj.grandparent.$.nodeName.toLowerCase() == 'li' )
     45                                                itemObj.grandparent = itemObj.grandparent.getParent();
     46                                }
     47                                else
     48                                        itemObj.grandparent = grandparentNode;
     49
     50                                if ( database )
     51                                        CKEDITOR.dom.element.setMarker( database, listItem, 'listarray_index', baseArray.length );
     52                                baseArray.push( itemObj );
     53
     54                                for ( var j = 0, itemChildCount = listItem.getChildCount() ; j < itemChildCount ; j++ )
     55                                {
     56                                        var child = listItem.getChild( j );
     57                                        if ( child.type == CKEDITOR.NODE_ELEMENT && listNodeNames[ child.getName() ] )
     58                                                // Note the recursion here, it pushes inner list items with
     59                                                // +1 indentation in the correct order.
     60                                                CKEDITOR.plugins.list.listToArray( child, database, baseArray, baseIndentLevel + 1, itemObj.grandparent );
     61                                        else
     62                                                itemObj.contents.push( child );
     63                                }
     64                        }
     65                        return baseArray;
     66                },
     67
     68                // Convert our internal representation of a list back to a DOM forest.
     69                arrayToList : function( listArray, database, baseIndex, paragraphMode )
     70                {
     71                        if ( !baseIndex )
     72                                baseIndex = 0;
     73                        if ( !listArray || listArray.length < baseIndex + 1 )
     74                                return null;
     75                        var doc = listArray[ baseIndex ].parent.getDocument(),
     76                                retval = new CKEDITOR.dom.documentFragment( doc ),
     77                                rootNode = null,
     78                                currentIndex = baseIndex,
     79                                indentLevel = Math.max( listArray[ baseIndex ].indent, 0 ),
     80                                currentListItem = null;
     81                        while ( true )
     82                        {
     83                                var item = listArray[ currentIndex ];
     84                                if ( item.indent == indentLevel )
     85                                {
     86                                        if ( !rootNode || listArray[ currentIndex ].parent.getName() != rootNode.getName() )
     87                                        {
     88                                                rootNode = listArray[ currentIndex ].parent.clone( false );
     89                                                retval.append( rootNode );
     90                                        }
     91                                        currentListItem = rootNode.append( doc.createElement( 'li' ) );
     92                                        for ( var i = 0 ; i < item.contents.length ; i++ )
     93                                                currentListItem.append( item.contents[i].clone( true ) );
     94                                        currentIndex++;
     95                                }
     96                                else if ( item.indent == Math.max( indentLevel, 0 ) + 1 )
     97                                {
     98                                        var listData = CKEDITOR.plugins.list.arrayToList( listArray, null, currentIndex, paragraphMode );
     99                                        currentListItem.append( listData.listNode );
     100                                        currentIndex = listData.nextIndex;
     101                                }
     102                                else if ( item.indent == -1 && baseIndex == 0 && item.grandparent )
     103                                {
     104                                        var currentListItem;
     105                                        if ( listNodeNames[ item.grandparent.getName() ] )
     106                                                currentListItem = doc.createElement( 'li' );
     107                                        else
     108                                        {
     109                                                if ( paragraphMode != 'br' && item.grandparent.getName() != 'td' )
     110                                                        currentListItem = doc.createElement( paragraphMode );
     111                                                else
     112                                                        currentListItem = new CKEDITOR.dom.documentFragment( doc );
     113                                        }
     114
     115                                        for ( var i = 0 ; i < item.contents.length ; i++ )
     116                                                currentListItem.append( item.contents[i].clone( true ) );
     117
     118                                        if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT )
     119                                        {
     120                                                if ( currentListItem.getLast()
     121                                                                && currentListItem.getLast().type == CKEDITOR.NODE_ELEMENT
     122                                                                && currentListItem.getLast().getAttribute( 'type' ) == '_moz' )
     123                                                        currentListItem.getLast().remove();
     124                                                currentListItem.append( doc.createElement( 'br' ) );
     125                                        }
     126
     127                                        if ( currentListItem.getName() == paragraphMode && currentListItem.$.firstChild )
     128                                        {
     129                                                currentListItem.trim();
     130                                                var firstChild = currentListItem.getFirst();
     131                                                if ( firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.isBlockBoundary() )
     132                                                {
     133                                                        var tmp = new CKEDITOR.dom.documentFragment( doc );
     134                                                        currentListItem.moveChildren( tmp );
     135                                                        currentListItem = tmp;
     136                                                }
     137                                        }
     138
     139                                        var currentListItemName = currentListItem.$.nodeName.toLowerCase();
     140                                        if ( !CKEDITOR.env.ie && currentListItemName == 'div' || currentListItemName == 'p' )
     141                                                currentListItem.append( doc.createElement( 'br' ) );
     142                                        retval.append( currentListItem );
     143                                        rootNode = null;
     144                                        currentIndex++;
     145                                }
     146                                else
     147                                        return null;
     148
     149                                if ( listArray.length <= currentIndex || Math.max( listArray[ currentIndex ].indent, 0 ) < indentLevel )
     150                                        break;
     151                        }
     152
     153                        // Clear marker attributes for the new list tree made of cloned nodes, if any.
     154                        if ( database )
     155                        {
     156                                var currentNode = retval.getFirst();
     157                                while ( currentNode )
     158                                {
     159                                        if ( currentNode.type == CKEDITOR.NODE_ELEMENT )
     160                                                CKEDITOR.dom.element.clearMarkers( database, currentNode );
     161                                        currentNode = currentNode.getNextSourceNode();
     162                                }
     163                        }
     164
     165                        return { listNode : retval, nextIndex : currentIndex };
     166                }
     167        };
     168
     169        function setState( editor, state )
     170        {
     171                var command = editor.getCommand( this.name );
     172                command.state = state;
     173                command.fire( 'state' );
     174        }
     175
     176        function onSelectionChange( evt )
     177        {
     178                var elements = evt.data.path.elements;
     179
     180                for ( var i = 0 ; i < elements.length ; i++ )
     181                {
     182                        if ( listNodeNames[ elements[i].getName() ] )
     183                                return setState.call( this, evt.editor,
     184                                                this.type == elements[i].getName() ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
     185                }
     186
     187                setState.call( this, evt.editor, CKEDITOR.TRISTATE_OFF );
     188        }
     189
     190        function changeListType( editor, groupObj, database, listsCreated )
     191        {
     192                // This case is easy...
     193                // 1. Convert the whole list into a one-dimensional array.
     194                // 2. Change the list type by modifying the array.
     195                // 3. Recreate the whole list by converting the array to a list.
     196                // 4. Replace the original list with the recreated list.
     197                var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
     198                        selectedListItems = [];
     199
     200                for ( var i = 0 ; i < groupObj.contents.length ; i++ )
     201                {
     202                        var itemNode = groupObj.contents[i];
     203                        itemNode = itemNode.getAscendant( 'li', true );
     204                        if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
     205                                continue;
     206                        selectedListItems.push( itemNode );
     207                        CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
     208                }
     209               
     210                var fakeParent = groupObj.root.getDocument().createElement( this.type );
     211                for ( var i = 0 ; i < selectedListItems.length ; i++ )
     212                {
     213                        var listIndex = selectedListItems[i].getCustomData( 'listarray_index' );
     214                        listArray[listIndex].parent = fakeParent;
     215                }
     216                var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
     217                for ( var i = 0, length = newList.listNode.getChildCount(), child ;
     218                                i < length && ( child = newList.listNode.getChild( i ) ) ; i++ )
     219                {
     220                        if ( child.getName() == this.type )
     221                                listsCreated.push( child );
     222                }
     223                newList.listNode.replace( groupObj.root );
     224        }
     225
     226        function createList( editor, groupObj, listsCreated )
     227        {
     228                var contents = groupObj.contents,
     229                        doc = groupObj.root.getDocument(),
     230                        listContents = [];
     231
     232                // It is possible to have the contents returned by DomRangeIterator to be the same as the root.
     233                // e.g. when we're running into table cells.
     234                // In such a case, enclose the childNodes of contents[0] into a <div>.
     235                if ( contents.length == 1 && contents[0].equals( groupObj.root ) )
     236                {
     237                        var divBlock = doc.createElement( 'div' );
     238                        contents[0].moveChildren && contents[0].moveChildren( divBlock );
     239                        contents[0].append( divBlock );
     240                        contents[0] = divBlock;
     241                }
     242
     243                // Calculate the common parent node of all content blocks.
     244                var commonParent = groupObj.contents[0].getParent();
     245                for ( var i = 0 ; i < contents.length ; i++ )
     246                        commonParent = commonParent.getCommonAncestor( contents[i].getParent() );
     247
     248                // We want to insert things that are in the same tree level only, so calculate the contents again
     249                // by expanding the selected blocks to the same tree level.
     250                for ( var i = 0 ; i < contents.length ; i++ )
     251                {
     252                        var contentNode = contents[i],
     253                                parentNode;
     254                        while ( ( parentNode = contentNode.getParent() ) )
     255                        {
     256                                if ( parentNode.equals( commonParent ) )
     257                                {
     258                                        listContents.push( contentNode );
     259                                        break;
     260                                }
     261                                contentNode = parentNode;
     262                        }
     263                }
     264
     265                if ( listContents.length < 1 )
     266                        return;
     267
     268                // Insert the list to the DOM tree.
     269                var insertAnchor = listContents[ listContents.length - 1 ].getNext(),
     270                        listNode = doc.createElement( this.type );
     271
     272                listsCreated.push( listNode );
     273                while ( listContents.length )
     274                {
     275                        var contentBlock = listContents.shift(),
     276                                listItem = doc.createElement( 'li' );
     277                        contentBlock.moveChildren( listItem );
     278                        contentBlock.remove();
     279                        listItem.appendTo( listNode );
     280                }
     281                if ( insertAnchor )
     282                        listNode.insertBefore( insertAnchor );
     283                else
     284                        listNode.appendTo( commonParent );
     285        }
     286
     287        function removeList( editor, groupObj, database )
     288        {
     289                // This is very much like the change list type operation.
     290                // Except that we're changing the selected items' indent to -1 in the list array.
     291                var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
     292                        selectedListItems = [];
     293
     294                for ( var i = 0 ; i < groupObj.contents.length ; i++ )
     295                {
     296                        var itemNode = groupObj.contents[i];
     297                        itemNode = itemNode.getAscendant( 'li', true );
     298                        if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
     299                                continue;
     300                        selectedListItems.push( itemNode );
     301                        CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
     302                }
     303
     304                var lastListIndex = null;
     305                for ( var i = 0 ; i < selectedListItems.length ; i++ )
     306                {
     307                        var listIndex = selectedListItems[i].getCustomData( 'listarray_index' );
     308                        listArray[listIndex].indent = -1;
     309                        lastListIndex = listIndex;
     310                }
     311
     312                // After cutting parts of the list out with indent=-1, we still have to maintain the array list
     313                // model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the
     314                // list cannot be converted back to a real DOM list.
     315                for ( var i = lastListIndex + 1 ; i < listArray.length ; i++ )
     316                {
     317                        if ( listArray[i].indent > listArray[i-1].indent + 1 )
     318                        {
     319                                var indentOffset = listArray[i-1].indent + 1 - listArray[i].indent;
     320                                var oldIndent = listArray[i].indent;
     321                                while ( listArray[i] && listArray[i].indent >= oldIndent )
     322                                {
     323                                        listArray[i].indent += indentOffset;
     324                                        i++;
     325                                }
     326                                i--;
     327                        }
     328                }
     329
     330                var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
     331                // If groupObj.root is the last element in its parent, or its nextSibling is a <br>, then we should
     332                // not add a <br> after the final item. So, check for the cases and trim the <br>.
     333                if ( groupObj.root.getNext() == null || groupObj.root.getNext().$.nodeName.toLowerCase() == 'br' )
     334                {
     335                        if ( newList.listNode.getLast().$.nodeName.toLowerCase() == 'br' )
     336                                newList.listNode.getLast().remove();
     337                }
     338                newList.listNode.replace( groupObj.root );
     339        }
     340
     341        function listCommand( name, type )
     342        {
     343                this.name = name;
     344                this.type = type;
     345        }
     346
     347        listCommand.prototype = {
     348                exec : function( editor )
     349                {
     350                        editor.focus();
     351
     352                        var doc = editor.document,
     353                                selection = editor.getSelection(),
     354                                ranges = selection && selection.getRanges();
     355
     356                        // There should be at least one selected range.
     357                        if ( !ranges || ranges.length < 1 )
     358                                return;
     359                       
     360                        // Midas lists rule #1 says we can create a list even in an empty document.
     361                        // But DOM iterator wouldn't run if the document is really empty.
     362                        // So create a paragraph if the document is empty and we're going to create a list.
     363                        if ( this.state == CKEDITOR.TRISTATE_OFF )
     364                        {
     365                                var body = doc.getBody();
     366                                body.trim();
     367                                if ( !body.getFirst() )
     368                                {
     369                                        var paragraph = doc.createElement( editor.config.enterMode );
     370                                        paragraph.appendTo( body );
     371                                        ranges = [ new CKEDITOR.dom.range( doc ) ];
     372                                        ranges[0].selectNodeContents( paragraph );
     373                                        selection.selectRanges( ranges );
     374                                }
     375                        }
     376                       
     377                        var bookmarks = selection.createBookmarks();
     378
     379                        // Group the blocks up because there are many cases where multiple lists have to be created,
     380                        // or multiple lists have to be cancelled.
     381                        var listGroups = [],
     382                                database = {};
     383
     384                        while ( ranges.length > 0 )
     385                        {
     386                                var range = ranges.shift(),
     387                                        boundaryNodes = range.getBoundaryNodes(),
     388                                        startNode = boundaryNodes.startNode,
     389                                        endNode = boundaryNodes.endNode;
     390                                if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.getName() == 'td' )
     391                                        range.setStartAt( boundaryNodes.startNode, CKEDITOR.POSITION_AFTER_START );
     392                                if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.getName() == 'td' )
     393                                        range.setEndAt( boundaryNodes.endNode, CKEDITOR.POSITION_BEFORE_END );
     394
     395                                var iterator = range.createIterator(),
     396                                        block;
     397                                iterator.forceBrBreak = ( this.state == CKEDITOR.TRISTATE_OFF );
     398
     399                                while ( ( block = iterator.getNextParagraph() ) )
     400                                {
     401                                        var path = new CKEDITOR.dom.elementPath( block ),
     402                                                listNode = null,
     403                                                processedFlag = false,
     404                                                blockLimit = path.blockLimit;
     405
     406                                        // First, try to group by a list ancestor.
     407                                        for ( var i = 0 ; i < path.elements.length ; i++ )
     408                                        {
     409                                                var element = path.elements[i];
     410                                                if ( listNodeNames[ element.getName() ] )
     411                                                {
     412                                                        // If we've encountered a list inside a block limit
     413                                                        // The last group object of the block limit element should
     414                                                        // no longer be valid. Since paragraphs after the list
     415                                                        // should belong to a different group of paragraphs before
     416                                                        // the list. (Bug #1309)
     417                                                        blockLimit.removeCustomData( 'list_group_object' );
     418
     419                                                        var groupObj = element.getCustomData( 'list_group_object' );
     420                                                        if ( groupObj )
     421                                                                groupObj.contents.push( block );
     422                                                        else
     423                                                        {
     424                                                                groupObj = { root : element, contents : [ block ] };
     425                                                                listGroups.push( groupObj );
     426                                                                CKEDITOR.dom.element.setMarker( database, element, 'list_group_object', groupObj );
     427                                                        }
     428                                                        processedFlag = true;
     429                                                        break;
     430                                                }
     431                                        }
     432
     433                                        if ( processedFlag )
     434                                                continue;
     435
     436                                        // No list ancestor? Group by block limit.
     437                                        var root = blockLimit;
     438                                        if ( root.getCustomData( 'list_group_object' ) )
     439                                                root.getCustomData( 'list_group_object' ).contents.push( block );
     440                                        else
     441                                        {
     442                                                var groupObj = { root : root, contents : [ block ] };
     443                                                CKEDITOR.dom.element.setMarker( database, root, 'list_group_object', groupObj );
     444                                                listGroups.push( groupObj );
     445                                        }
     446                                }
     447                        }
     448
     449                        // Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element.
     450                        // We either have to build lists or remove lists, for removing a list does not makes sense when we are looking
     451                        // at the group that's not rooted at lists. So we have three cases to handle.
     452                        var listsCreated = [];
     453                        while ( listGroups.length > 0 )
     454                        {
     455                                var groupObj = listGroups.shift();
     456                                if ( this.state == CKEDITOR.TRISTATE_OFF )
     457                                {
     458                                        if ( listNodeNames[ groupObj.root.getName() ] )
     459                                                changeListType.call( this, editor, groupObj, database, listsCreated );
     460                                        else
     461                                                createList.call( this, editor, groupObj, listsCreated );
     462                                }
     463                                else if ( this.state == CKEDITOR.TRISTATE_ON && listNodeNames[ groupObj.root.getName() ] )
     464                                        removeList.call( this, editor, groupObj, database );
     465                        }
     466
     467                        // For all new lists created, merge adjacent, same type lists.
     468                        for ( var i = 0 ; i < listsCreated.length ; i++ )
     469                        {
     470                                var listNode = listsCreated[i],
     471                                        stopFlag = false,
     472                                        currentNode = listNode;
     473
     474                                while ( !stopFlag )
     475                                {
     476                                        currentNode = currentNode.getNext();
     477                                        if ( currentNode && currentNode.type == CKEDITOR.NODE_TEXT && emptyTextRegex.test( currentNode.getText() ) )
     478                                                continue;
     479                                        stopFlag = true;
     480                                }
     481
     482                                if ( currentNode && currentNode.getName() == this.type )
     483                                {
     484                                        currentNode.remove();
     485                                        currentNode.moveChildren( listNode );
     486                                }
     487                               
     488                                stopFlag = false;
     489                                currentNode = listNode;
     490                                while ( !stopFlag )
     491                                {
     492                                        currentNode = currentNode.getNext();
     493                                        if ( currentNode && currentNode.type == CKEDITOR.NODE_TEXT && emptyTextRegex.test( currentNode.getText() ) )
     494                                                continue;
     495                                        stopFlag = true;
     496                                }
     497                                if ( currentNode && currentNode.getName() == this.type  )
     498                                {
     499                                        currentNode.remove();
     500                                        currentNode.moveChildren( listNode, true );
     501                                }
     502                        }
     503
     504                        // Clean up, restore selection and update toolbar button states.
     505                        CKEDITOR.dom.element.clearAllMarkers( database );
     506                        selection.selectBookmarks( bookmarks );
     507                        editor.focus();
     508                }
     509        };
     510
     511        CKEDITOR.plugins.add( 'list',
     512        {
     513                init : function( editor )
     514                {
     515                        // Register commands.
     516                        var numberedListCommand = new listCommand( 'numberedlist', 'ol' ),
     517                                bulletedListCommand = new listCommand( 'bulletedlist', 'ul' );
     518                        editor.addCommand( 'numberedlist', numberedListCommand );
     519                        editor.addCommand( 'bulletedlist', bulletedListCommand );
     520
     521                        // Register the toolbar button.
     522                        editor.ui.addButton( 'NumberedList',
     523                                {
     524                                        label : editor.lang.numberedlist,
     525                                        command : 'numberedlist'
     526                                } );
     527                        editor.ui.addButton( 'BulletedList',
     528                                {
     529                                        label : editor.lang.bulletedlist,
     530                                        command : 'bulletedlist'
     531                                } );
     532
     533                        // Register the state changing handlers.
     534                        editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, numberedListCommand ) );
     535                        editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, bulletedListCommand ) );
     536                },
     537
     538                requires : [ 'domiterator' ]
     539        } );
     540})();
  • _source/skins/default/toolbar.css

     
    305305{
    306306        background-position: 0 -880px;
    307307}
     308
     309.cke_skin_default a.cke_button_numberedlist .cke_icon
     310{
     311        background-position: 0 -400px;
     312}
     313
     314.cke_skin_default a.cke_button_bulletedlist .cke_icon
     315{
     316        background-position: 0 -416px;
     317}
  • _source/core/config.js

     
    146146         * @example
    147147         * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea';
    148148         */
    149         plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,removeformat,smiley,sourcearea,specialchar,tab,toolbar,wysiwygarea',
     149        plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,removeformat,smiley,list,sourcearea,specialchar,tab,toolbar,wysiwygarea',
    150150
    151151        /**
    152152         * The theme to be used to build the UI.
  • _source/core/dom/node.js

     
    305305                        return parents;
    306306                },
    307307
     308                getCommonAncestor : function( node )
     309                {
     310                        if ( node.equals( this ) )
     311                                return this;
     312
     313                        if ( node.contains && node.contains( this ) )
     314                                return node;
     315
     316                        var start = this.contains ? this : this.getParent();
     317
     318                        do
     319                        {
     320                                if ( start.contains( end ) )
     321                                        return start;
     322                        }
     323                        while ( ( start = start.getParent() ) );
     324
     325                        return null;
     326                },
     327
    308328                getPosition : function( otherNode )
    309329                {
    310330                        var $ = this.$;
  • _source/core/dom/domobject.js

     
    165165                var expandoNumber = this.$._cke_expando,
    166166                        dataSlot = expandoNumber && customData[ expandoNumber ];
    167167
    168                 return ( dataSlot && dataSlot[ key ] ) || null;
     168                if ( dataSlot && dataSlot[ key ] !== undefined )
     169                        return dataSlot[ key ];
     170                return null;
    169171        };
    170172
     173        domObjectProto.removeCustomData = function( key )
     174        {
     175                var expandoNumber = this.$._cke_expando,
     176                        dataSlot = expandoNumber && customData[ expandoNumber ],
     177                        retval = dataSlot[ key ];
     178
     179                delete dataSlot[ key ];
     180                return retval || null;
     181        };
     182
    171183        // Implement CKEDITOR.event.
    172184        CKEDITOR.event.implementOn( domObjectProto );
    173185
  • _source/core/dom/element.js

     
    7373        return temp.getFirst().remove();
    7474};
    7575
     76CKEDITOR.dom.element.setMarker = function( database, element, name, value )
     77{
     78        var id = element.getCustomData( 'list_marker_id' ) ||
     79                        ( element.setCustomData( 'list_marker_id', CKEDITOR.tools.getNextNumber() ).getCustomData( 'list_marker_id' ) ),
     80                markerNames = element.getCustomData( 'list_marker_names' ) ||
     81                        ( element.setCustomData( 'list_marker_names', {} ).getCustomData( 'list_marker_names' ) );
     82        database[id] = element;
     83        markerNames[name] = 1;
     84
     85        return element.setCustomData( name, value );
     86};
     87
     88CKEDITOR.dom.element.clearAllMarkers = function( database )
     89{
     90        for ( var i in database )
     91                CKEDITOR.dom.element.clearMarkers( database, database[i], true );
     92};
     93
     94CKEDITOR.dom.element.clearMarkers = function( database, element, removeFromDatabase )
     95{
     96        var names = element.getCustomData( 'list_marker_names' ),
     97                id = element.getCustomData( 'list_marker_id' );
     98        for ( var i in names )
     99                element.removeCustomData( names[i] );
     100        element.removeCustomData( 'list_marker_names' );
     101        if ( removeFromDatabase )
     102        {
     103                element.removeCustomData( 'list_marker_id' );
     104                delete database[id];
     105        }
     106};
     107
    76108CKEDITOR.tools.extend( CKEDITOR.dom.element.prototype,
    77109        /** @lends CKEDITOR.dom.element.prototype */
    78110        {
  • _source/core/dom/range.js

     
    490490                                return start;
    491491                        }
    492492
    493                         if ( end.type == CKEDITOR.NODE_ELEMENT && end.contains( start ) )
    494                                 return end;
    495 
    496                         if ( start.type != CKEDITOR.NODE_ELEMENT )
    497                                 start = start.getParent();
    498 
    499                         do
    500                         {
    501                                 if ( start.contains( end ) )
    502                                         return start;
    503                         }
    504                         while( ( start = start.getParent() ) )
    505 
    506                         return null;
     493                        return start.getCommonAncestor( end );
    507494                },
    508495
    509496                /**
  • _source/core/dom/documentFragment.js

     
    2626                                targetElement.$.appendChild( this.$ );
    2727                },
    2828
     29                moveChildren : elementPrototype.moveChildren,
     30
    2931                insertAfterNode : function( node )
    3032                {
    3133                        var $ = this.$;
     
    3941                        }
    4042                        else
    4143                                $parent.insertBefore( $, $node.nextSibling );
    42                 }
     44                },
     45
     46                replace : function( nodeToReplace )
     47                {
     48                        this.insertAfterNode( nodeToReplace );
     49                        nodeToReplace.remove();
     50                },
     51
     52                trim : elementPrototype.trim,
     53                ltrim : elementPrototype.ltrim,
     54                rtrim : elementPrototype.rtrim,
     55                getFirst : elementPrototype.getFirst,
     56                getLast : elementPrototype.getLast,
     57                getDocument : elementPrototype.getDocument,
     58                getChildCount : elementPrototype.getChildCount,
     59                getChild : elementPrototype.getChild,
     60                contains : elementPrototype.contains
    4361        };
    4462})();
  • _source/core/tools.js

     
    310310                                return i;
    311311                }
    312312                return -1;
     313        },
     314
     315        bind : function( func, obj )
     316        {
     317                return function() { return func.apply( obj, arguments ); };
    313318        }
    314319};
    315320
© 2003 – 2020 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy