Ticket #2768: 2768.patch

File 2768.patch, 22.9 KB (added by Garry Yao, 12 years ago)
  • _source/core/editor.js

     
    345345                execCommand : function( commandName, data )
    346346                {
    347347                        var command = this.getCommand( commandName );
     348                        var exeResult;
     349                        var commandEvent =
     350       
     351                        /**
     352                         * The event data for this command
     353                         *
     354                         * @type FCKEDITOR.command.Event
     355                         */
     356                        {
     357                                name :commandName,
     358                                command :command
     359                        };
    348360                        if ( command && command.state != CKEDITOR.TRISTATE_DISABLED )
    349                                 return command.exec( this, data );
     361                        {
     362                                exeResult = command.exec( this , data );
     363                                this.fire( 'afterCommandExec' , commandEvent );
     364                                return exeResult;
     365                        }
    350366
    351367                        // throw 'Unknown command name "' + commandName + '"';
    352368                        return false;
  • _source/core/tools.js

     
    310310                                return i;
    311311                }
    312312                return -1;
     313        },
     314        /**
     315         * Binds a function with an object as its this reference.
     316         *
     317         * @param {Function}
     318         *            func The function to be bounded.
     319         * @param {Object}
     320         *            obj This this reference to bind to the function.
     321         * @returns {Function} The bound function.
     322         */
     323        bind : function ( func, obj )
     324        {
     325                return function ( )
     326                {
     327                        return func.apply( obj , arguments );
     328                }
    313329        }
    314330};
    315331
  • _source/core/dom/documentFragment.js

     
    88        this.$ = CKEDITOR.env.ie ? ownerDocument.$.createElement( 'div' ) : ownerDocument.$.createDocumentFragment();
    99};
    1010
     11/*
     12 * A DocumentFragment behaves like a conventional {@link CKEDITOR.dom.Node} with all of the same
     13 * methods, except that when a DocumentFragment is inserted into a Document (or
     14 * indeed any other Node that may take children) the children of the
     15 * DocumentFragment and not the DocumentFragment itself are inserted into the
     16 * Node.
     17 */
     18CKEDITOR.dom.documentFragment.prototype = CKEDITOR.tools
     19                .prototypedCopy( CKEDITOR.dom.node.prototype );
     20
    1121(function()
    1222{
    1323        var elementPrototype = CKEDITOR.dom.element.prototype;
    1424
    15         CKEDITOR.dom.documentFragment.prototype =
    16         {
     25        CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype , {
    1726                type : CKEDITOR.NODE_DOCUMENT_FRAGMENT,
    1827
    1928                append : elementPrototype.append,
     
    4049                        else
    4150                                $parent.insertBefore( $, $node.nextSibling );
    4251                }
    43         };
     52        } , true );
    4453})();
  • _source/core/dom/range.js

     
    457457                        };
    458458                },
    459459
    460                 moveToBookmark : function( bookmark )
     460                moveToBookmark : function( bookmark, isPreserve )
    461461                {
    462                         // Set the range start at the bookmark start node position.
    463                         this.setStartBefore( bookmark.startNode );
     462                        var st = bookmark.startNode , ed = bookmark.endNode;
    464463
    465                         // Remove it, because it may interfere in the setEndBefore call.
    466                         bookmark.startNode.remove();
     464            // Set the range start at the bookmark start node position.
     465            this.setStartBefore( typeof st === 'string' ? ( st = this.document
     466                    .getById( st ) ) : st );
    467467
    468                         // Set the range end at the bookmark end node position, or simply
    469                         // collapse it if it is not available.
    470                         var endNode = bookmark.endNode;
    471                         if ( endNode )
    472                         {
    473                                 this.setEndBefore( endNode );
    474                                 endNode.remove();
    475                         }
    476                         else
    477                                 this.collapse( true );
     468            // Remove it, because it may interfere in the setEndBefore call.
     469            if(!isPreserve)
     470                st.remove();
     471
     472            // Set the range end at the bookmark end node position, or simply
     473            // collapse it if it is not available.
     474            if ( ed )
     475            {
     476                this.setEndBefore( typeof ed === 'string' ?
     477                        ( ed = this.document.getById( ed ) )
     478                        : ed );
     479                if(!isPreserve)
     480                    ed.remove();
     481            }
     482            else
     483                this.collapse( true );
    478484                },
    479485
    480486                getCommonAncestor : function( includeSelf )
     
    9941000
    9951001                /**
    9961002                 * Inserts a node at the start of the range. The range will be expanded
    997                  * the contain the node.
     1003                 * to contain the node.
     1004                 * @param {CKEDITOR.dom.node}
    9981005                 */
    9991006                insertNode : function( node )
    10001007                {
     
    10021009
    10031010                        var startContainer = this.startContainer;
    10041011                        var startOffset = this.startOffset;
     1012                        var isDomFrag = false , firstChild , childCounts = 0;
    10051013
     1014                        // Inserted node might be {@link CKEDITOR.dom.documentFragment}
     1015                        if ( node.type === CKEDITOR.NODE_DOCUMENT_FRAGMENT )
     1016                        {
     1017                                isDomFrag = true;
     1018                                firstChild = node.getChild( 0 );
     1019                                childCounts = node.getChildCount();
     1020                        }
     1021
    10061022                        var nextNode = startContainer.getChild( startOffset );
    10071023
    10081024                        if ( nextNode )
     
    10111027                                startContainer.append( node );
    10121028
    10131029                        // Check if we need to update the end boundary.
    1014                         if ( node.getParent().equals( this.endContainer ) )
     1030                        if ( isDomFrag && firstChild.getParent().equals( this.endContainer ) )
     1031                        {
     1032                                this.endOffset += childCounts;
     1033                                // Expand the range to embrace the new nodes.
     1034                                this.setStartBefore( firstChild );
     1035                        }
     1036                        else if ( node.getParent().equals( this.endContainer ) )
    10151037                                this.endOffset++;
    10161038
    10171039                        // Expand the range to embrace the new node.
  • _source/plugins/selection/plugin.js

     
    8383        {
    8484                init : function( editor, pluginPath )
    8585                {
     86                        // Listen to non-user generated selection, e.g. selection changes produced by commands.
     87                        editor.on( 'afterCommandExec' , checkSelectionChangeTimeout ,
     88                                        editor );
    8689                        editor.on( 'contentDom', function()
    8790                                {
    8891                                        if ( CKEDITOR.env.ie )
  • _source/plugins/styles/plugin.js

     
    55
    66CKEDITOR.plugins.add( 'styles',
    77{
    8         requires : [ 'selection' ]
    9 });
    10 
    11 /**
    12  * Registers a function to be called whenever a style changes its state in the
    13  * editing area. The current state is passed to the function. The possible
    14  * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.
    15  * @param {CKEDITOR.style} The style to be watched.
    16  * @param {Function} The function to be called when the style state changes.
    17  * @example
    18  * // Create a style object for the <b> element.
    19  * var style = new CKEDITOR.style( { element : 'b' } );
    20  * var editor = CKEDITOR.instances.editor1;
    21  * editor.attachStyleStateChange( style, function( state )
    22  *     {
    23  *         if ( state == CKEDITOR.TRISTATE_ON )
    24  *             alert( 'The current state for the B element is ON' );
    25  *         else
    26  *             alert( 'The current state for the B element is OFF' );
    27  *     });
    28  */
    29 CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback )
    30 {
    31         // Try to get the list of attached callbacks.
    32         var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
    33 
    34         // If it doesn't exist, it means this is the first call. So, let's create
    35         // all the structure to manage the style checks and the callback calls.
    36         if ( !styleStateChangeCallbacks )
     8        requires : [ 'selection' ],
     9        beforeInit : function( editor, pluginPath )
    3710        {
    38                 // Create the callbacks array.
    39                 styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
     11               
     12        var blockElements   = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 };
     13        var objectElements  = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,ul:1 };
    4014
    41                 // Attach to the selectionChange event, so we can check the styles at
    42                 // that point.
    43                 this.on( 'selectionChange', function( ev )
    44                         {
    45                                 // Loop throw all registered callbacks.
    46                                 for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
    47                                 {
    48                                         var callback = styleStateChangeCallbacks[ i ];
    49 
    50                                         // Check the current state for the style defined for that
    51                                         // callback.
    52                                         var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
    53 
    54                                         // If the state changed since the last check.
    55                                         if ( callback.state !== currentState )
    56                                         {
    57                                                 // Call the callback function, passing the current
    58                                                 // state to it.
    59                                                 callback.fn.call( this, currentState );
    60 
    61                                                 // Save the current state, so it can be compared next
    62                                                 // time.
    63                                                 callback.state !== currentState;
    64                                         }
    65                                 }
    66                         });
    67         }
    68 
    69         // Save the callback info, so it can be checked on the next occurence of
    70         // selectionChange.
    71         styleStateChangeCallbacks.push( { style : style, fn : callback } );
    72 };
    73 
    74 CKEDITOR.STYLE_BLOCK = 1;
    75 CKEDITOR.STYLE_INLINE = 2;
    76 CKEDITOR.STYLE_OBJECT = 3;
    77 
    78 (function()
    79 {
    80         var blockElements       = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 };
    81         var objectElements      = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,ul:1 };
    82 
    8315        CKEDITOR.style = function( styleDefinition )
    8416        {
    8517                var element = this.element = ( styleDefinition.element || '*' ).toLowerCase();
     
    10032
    10133        CKEDITOR.style.prototype =
    10234        {
    103                 apply : function( document )
    104                 {
     35                /**
     36                 * @param {CKEDITOR.dom.document} document The target document the style applies to.
     37                 * @param {Boolean} isReverse Whether it's a reverse apply (remove).
     38                 */
     39                apply : function( document , isReverse)
     40                {
    10541                        // Get all ranges from the selection.
    10642                        var selection = document.getSelection();
    10743                        var ranges = selection.getRanges();
    108 
     44                        var styleFuncName = isReverse? 'removeFromRange':'applyToRange';
    10945                        // Apply the style to the ranges.
    11046                        for ( var i = 0 ; i < ranges.length ; i++ )
    111                                 this.applyToRange( ranges[ i ] );
    112 
     47                        {
     48                                        this[styleFuncName].call( this, ranges[i]);
     49                        }
    11350                        // Select the ranges again.
    11451                        selection.selectRanges( ranges );
    11552                },
     53               
     54                reverse: function (document) {
     55                  this.apply(document, true);
     56                },
    11657
    11758                applyToRange : function( range )
    11859                {
     
    12364                                                        applyBlockStyle
    12465                                                : null ).call( this, range );
    12566                },
     67               
     68                removeFromRange: function (range) {
     69                 
     70                        return (this.type == CKEDITOR.STYLE_INLINE ? removeInlineStyle :
     71                         this.type == CKEDITOR.STYLE_BLOCK ? removeBlockStyle :
     72                         null).call(this, range);
     73                },
     74               
     75                /**
     76                 * Remove all related attributes, styles on the element, or even intrinsic semantics(the element itself) which related with this style
     77                 * @param {CKEditor.dom.element} element The target element
     78                 */
     79                removeFromElement: function(element)
     80                {
     81                        if(element.$.nodeType !== 1||element.getName() !== this.element)
     82                                return;
     83                        var def = this._.definition;
     84                        var attribs = def.attributes;
     85                        var styles = def.styles;
     86                       
     87                        for (var attName in attribs)
     88                        {
     89                                // The 'class' element value must match (#1318).
     90                                if (attName == 'class' && element.getAttribute('class') != attribs[attName])
     91                                        continue;
     92                               
     93                                element.removeAttribute(attName);
     94                        }
     95                       
     96                        for (var styleName in styles)
     97                        {
     98                                element.removeStyle(styleName);
     99                        }
     100                       
     101                        removeNoAttribsElement(element);
     102                },
     103               
     104                /**
     105                 * Remove related style from all the childs of this element
     106                 * @param {CKEditor.dom.element} element The target element
     107                 * @see CKEditor.style::removeFromElement
     108                 */
     109                 removeFromAllChilds : function( element )
     110                {
     111                        var innerElements = element.getElementsByTag( this.element );
     112                        for ( var i = innerElements.count() ; --i >= 0 ; )
     113                        {
     114                                var innerElement = innerElements.getItem( i );
     115                                this.removeFromElement(innerElements);
     116                        }
     117                },
    126118
    127119                /**
    128120                 * Get the style state inside an element path. Returns "true" if the
     
    153145                        return false;
    154146                },
    155147
    156                 // Checks if an element, or any of its attributes, is removable by the
    157                 // current style definition.
     148                /**
     149         * @param {CKEDITOR.dom.element} element The target element to check.
     150         * @param {Boolean} fullMatch Whether require the attribute and styles are fully matched.
     151         */
    158152                checkElementRemovable : function( element, fullMatch )
    159153                {
    160154                        if ( !element || element.getName() != this.element )
     
    359353
    360354                                        // Here we do some cleanup, removing all duplicated
    361355                                        // elements from the style element.
    362                                         removeFromElement( this, styleNode );
     356                                        this.removeFromAllChilds( styleNode );
    363357
    364358                                        // Insert it into the range position (it is collapsed after
    365359                                        // extractContents.
     
    384378                        }
    385379                }
    386380
    387 //              this._FixBookmarkStart( startNode );
     381//      this._FixBookmarkStart( startNode );
    388382
    389383                range.moveToBookmark( bookmark );
    390384        };
     385       
     386        /**
     387         * Remove the style from the specified {@param range}.
     388         * @param {CKEDITOR.dom.range} range    The range to be processed.
     389         */
     390        function removeInlineStyle(range) {
     391           
     392                var
     393        self = this,
     394        //bookmark start and end boundaries
     395        bookmark, 
     396        startNode, endNode,
     397        walker,
     398        //the topmost parent node which conflicts with this style removing
     399                matchedTopParent;               
    391400
     401        var isCollapsed =  range.collapsed,
     402        // A placeholder for cheat with collapsed range
     403        marker; 
     404         
     405        // Expand the range, if inside inline element boundaries.
     406        if(!isCollapsed)
     407            range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
     408         
     409        //Cheat by insert a placeholder node which make the range no longer collapsed
     410        else         
     411        {
     412            marker = editor.document.createText( '&nbsp;' );
     413            range.insertNode(marker);
     414            range.setStartBefore(marker);
     415            range.setEndAfter(marker);
     416        }
     417
     418        // Bookmark the range, bookmark nodes are used to establish boundaries.
     419        bookmark = range.createBookmark(),
     420        startNode   = bookmark.startNode,
     421        endNode = bookmark.endNode;
     422
     423        if ( matchedTopParent = checkPath( startNode , CKEDITOR.tools.bind(
     424                        this.checkElementRemovable , this ) ) )
     425                branch( startNode , matchedTopParent , true );
     426        if ( matchedTopParent = checkPath( endNode , CKEDITOR.tools.bind(
     427                        this.checkElementRemovable , this ) ) )
     428                branch( endNode , matchedTopParent , true );
     429       
     430                walker = new CKEDITOR.dom.domWalker( startNode );
     431                walker.forward( function ( walkerEvt )
     432                {
     433                        var currentNode = walkerEvt.data.from;
     434                        if ( currentNode.equals( startNode ) )
     435                                return;
     436                        else if ( currentNode.equals( endNode ) )
     437                                this.stop();
     438                        else
     439                                self.removeFromElement( currentNode );
     440                } );
     441       
     442                if ( isCollapsed ) // remove the marker node
     443                {
     444                        marker.remove();
     445                }
     446                else
     447                {
     448                        if ( !CKEDITOR.env.ie ) // normalize text nodes for non-IE
     449                        {
     450                                var frag;
     451                                range.moveToBookmark( bookmark , true );
     452                                frag = range.extractContents();
     453                                frag.$.normalize();
     454                                range.insertNode( frag );
     455                        }
     456                }
     457               
     458                //TODO: Anchor range boundaries inside element if possible
     459               
     460                range.moveToBookmark(bookmark);
     461        }
    392462        var applyBlockStyle = function( range )
    393463        {
    394464        };
    395 
    396         // Removes a style from inside an element.
    397         var removeFromElement = function( style, element )
     465       
     466        /**
     467         * Create a new branch of the dom tree which rooted by {@param parentNode} and start from the {@param boundaryNode}, after then the {@param boundaryNode} would be placed between these two branches.
     468         * For example in the following dom tree, if we specified '<span/>' as the boundaryNode,
     469         * <pre>
     470         *      <b>This <i>is some<span /> sample</i> test text</b>
     471         *      </pre>
     472         *The dom tree will end up with:
     473         *<pre>     
     474         *      <b>This <i>is some</i><span /><i> sample</i> test text</b>          <!-- (If parent = <i>) -->
     475         *      <b>This <i>is some</i></b><span /><b><i> sample</i> test text</b>   <!-- (If parent = <b>) -->
     476         *<pre>     
     477         * @param {CKEDITOR.dom.node} boundaryNode The left-most node which used as boundary of this branch.
     478         * @param {CKEDITOR.dom.node} parentNode The first node which will be the root of this branch.
     479         * @see FCKDomTools.BreakParent The v2 similiar method.
     480         */
     481        function branch ( boundaryNode, parentNode )
    398482        {
    399                 var def = style._.definition;
    400                 var attribs = def.attributes;
    401                 var styles = def.styles;
    402483
    403                 var innerElements = element.getElementsByTag( style.element );
     484                var range = new CKEDITOR.dom.range( editor.document );
    404485
    405                 for ( var i = innerElements.count() ; --i >= 0 ; )
    406                 {
    407                         var innerElement = innerElements.getItem( i );
     486                // We'll be extracting part of this boundaryNode, so let's use our
     487                // range to get the correct piece.
     488                range.setStartAfter( boundaryNode );
     489                range.setEndAfter( parentNode );
    408490
    409                         for ( var attName in attribs )
    410                         {
    411                                 // The 'class' element value must match (#1318).
    412                                 if ( attName == 'class' && innerElement.getAttribute( 'class' ) != attribs[ attName ] )
    413                                         continue;
     491                // Extract it, range should be collapsed after the first branch
     492                var docFrag = range.extractContents();
    414493
    415                                 innerElement.removeAttribute( attName );
    416                         }
     494                // Place the boundary node right after first branch
     495                range.insertNode( boundaryNode.remove() );
    417496
    418                         for ( var styleName in styles )
     497                // Insert the second branch in following
     498                docFrag.insertAfterNode( boundaryNode );
     499        }
     500       
     501       
     502        /**
     503         * Reversely seaching on the element path which started by {@param pathStartNode}, return the first path element which satisfy {@param testFunction}.
     504         * @param {CKEditor.dom.node} pathStartNode
     505         * @param {Functoin} testFunction The function to test whether the element is the root of branch.
     506         * @param {Boolean} skipBlock Whether ignore all the block level elements included in this path.
     507         */
     508        function checkPath(pathStartNode, testFunction, skipBlock) {
     509               
     510                // Let's start checking the start boundary.
     511                var path = new CKEDITOR.dom.elementPath( pathStartNode ) , currentElements = path.elements;
     512                var currentElement;
     513                var i = skipBlock ? CKEDITOR.tools.indexOf( currentElements , path.block ) - 1
     514                                : currentElements.length - 1;
     515               
     516                for ( ; i > 0 ; i-- ) // skip the beginning node
     517                {
     518                        currentElement = currentElements[ i ];
     519
     520                        if ( testFunction( currentElement ) )
    419521                        {
    420                                 innerElement.removeStyle( styleName );
     522                                return currentElement;
    421523                        }
    422 
    423                         removeNoAttribsElement( innerElement );
    424524                }
    425525        };
     526       
    426527
    427         // If the element has no more attributes, remove it.
    428         var removeNoAttribsElement = function( element )
     528       
     529
     530        /**
     531         * If no more attributes remained in the element, remove it, but leaving its
     532         * children.
     533         *
     534         * @param {CKEDITOR.dom.element}
     535         *            The target element to remove.
     536         */
     537        function removeNoAttribsElement( element )
    429538        {
    430539                // If no more attributes remained in the element, remove it,
    431540                // leaving its children.
    432541                if ( !element.hasAttributes() )
    433542                {
    434                         // Removing elements may open points where merging is possible,
    435                         // so let's cache the first and last nodes for later checking.
    436                         var firstChild  = element.getFirst();
    437                         var lastChild   = element.getLast();
    438 
    439543                        element.remove( true );
    440 
    441                         if ( firstChild )
    442                         {
    443                                 // Check the cached nodes for merging.
    444                                 mergeSiblings( firstChild );
    445 
    446                                 if ( lastChild && !firstChild.equals( lastChild ) )
    447                                         mergeSiblings( lastChild );
    448                         }
    449544                }
    450545        };
    451546
     
    586681                // Save the created element. It will be reused on future calls.
    587682                return ( style._.element = el );
    588683        };
    589 })();
     684        }
     685});
    590686
     687/**
     688 * Registers a function to be called whenever a style changes its state in the
     689 * editing area. The current state is passed to the function. The possible
     690 * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.
     691 * @param {CKEDITOR.style} The style to be watched.
     692 * @param {Function} The function to be called when the style state changes.
     693 * @example
     694 * // Create a style object for the <b> element.
     695 * var style = new CKEDITOR.style( { element : 'b' } );
     696 * var editor = CKEDITOR.instances.editor1;
     697 * editor.attachStyleStateChange( style, function( state )
     698 *     {
     699 *         if ( state == CKEDITOR.TRISTATE_ON )
     700 *             alert( 'The current state for the B element is ON' );
     701 *         else
     702 *             alert( 'The current state for the B element is OFF' );
     703 *     });
     704 */
     705CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback )
     706{
     707        // Try to get the list of attached callbacks.
     708        var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
     709
     710        // If it doesn't exist, it means this is the first call. So, let's create
     711        // all the structure to manage the style checks and the callback calls.
     712        if ( !styleStateChangeCallbacks )
     713        {
     714                // Create the callbacks array.
     715                styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
     716
     717                // Attach to the selectionChange event, so we can check the styles at
     718                // that point.
     719                this.on( 'selectionChange', function( ev )
     720                        {
     721                                // Loop throw all registered callbacks.
     722                                for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
     723                                {
     724                                        var callback = styleStateChangeCallbacks[ i ];
     725
     726                                        // Check the current state for the style defined for that
     727                                        // callback.
     728                                        var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
     729
     730                                        // If the state changed since the last check.
     731                                        if ( callback.state !== currentState )
     732                                        {
     733                                                // Call the callback function, passing the current
     734                                                // state to it.
     735                                                callback.fn.call( this, currentState );
     736
     737                                                // Save the current state, so it can be compared next
     738                                                // time.
     739                                                callback.state !== currentState;
     740                                        }
     741                                }
     742                        });
     743        }
     744
     745        // Save the callback info, so it can be checked on the next occurence of
     746        // selectionChange.
     747        styleStateChangeCallbacks.push( { style : style, fn : callback } );
     748};
     749
     750CKEDITOR.STYLE_BLOCK = 1;
     751CKEDITOR.STYLE_INLINE = 2;
     752CKEDITOR.STYLE_OBJECT = 3;
     753
     754
    591755CKEDITOR.styleCommand = function( style )
    592756{
    593757        this.style = style;
     
    600764        var doc = editor.document;
    601765
    602766        if ( doc )
    603                 this.style.apply( doc );
     767        {
     768                if(this.state === CKEDITOR.TRISTATE_OFF)       
     769                {
     770                        this.style.apply( doc );
     771                }
     772                else if(this.state === CKEDITOR.TRISTATE_ON)
     773                {
     774                        this.style.reverse(doc);
     775                }
     776        }
    604777
    605778        return !!doc;
    606779};
© 2003 – 2020 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy