Ticket #1272: 1272_2.patch

File 1272_2.patch, 10.2 KB (added by Garry Yao, 10 years ago)
  • _source/plugins/styles/plugin.js

     
    1818        }
    1919});
    2020
    21 /**
    22  * Registers a function to be called whenever a style changes its state in the
    23  * editing area. The current state is passed to the function. The possible
    24  * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.
     21CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
     22{
     23        /**
     24         * Registers a function to be called whenever a style changes its state in the
     25         * editing area. The current state is passed to the function. The possible
     26         * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.
    2527 * @param {CKEDITOR.style} style The style to be watched.
    2628 * @param {Function} callback The function to be called when the style state changes.
    27  * @example
    28  * // Create a style object for the <b> element.
    29  * var style = new CKEDITOR.style( { element : 'b' } );
    30  * var editor = CKEDITOR.instances.editor1;
    31  * editor.attachStyleStateChange( style, function( state )
    32  *     {
    33  *         if ( state == CKEDITOR.TRISTATE_ON )
    34  *             alert( 'The current state for the B element is ON' );
    35  *         else
    36  *             alert( 'The current state for the B element is OFF' );
    37  *     });
    38  */
    39 CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback )
    40 {
    41         // Try to get the list of attached callbacks.
    42         var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
     29        * @example
     30        * // Create a style object for the <b> element.
     31        * var style = new CKEDITOR.style( { element : 'b' } );
     32        * var editor = CKEDITOR.instances.editor1;
     33        * editor.attachStyleStateChange( style, function( state )
     34        *     {
     35        *         if ( state == CKEDITOR.TRISTATE_ON )
     36        *             alert( 'The current state for the B element is ON' );
     37        *         else
     38        *             alert( 'The current state for the B element is OFF' );
     39        *     });
     40        */
     41        attachStyleStateChange : function( style, callback )
     42        {
     43                // Try to get the list of attached callbacks.
     44                var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
    4345
    44         // If it doesn't exist, it means this is the first call. So, let's create
    45         // all the structure to manage the style checks and the callback calls.
    46         if ( !styleStateChangeCallbacks )
    47         {
    48                 // Create the callbacks array.
    49                 styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
     46                // If it doesn't exist, it means this is the first call. So, let's create
     47                // all the structure to manage the style checks and the callback calls.
     48                if ( !styleStateChangeCallbacks )
     49                {
     50                        // Create the callbacks array.
     51                        styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
    5052
    51                 // Attach to the selectionChange event, so we can check the styles at
    52                 // that point.
    53                 this.on( 'selectionChange', function( ev )
    54                         {
    55                                 // Loop throw all registered callbacks.
    56                                 for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
    57                                 {
    58                                         var callback = styleStateChangeCallbacks[ i ];
     53                        // Attach to the selectionChange event, so we can check the styles at
     54                        // that point.
     55                        this.on( 'selectionChange', function( ev )
     56                                {
     57                                        // Loop throw all registered callbacks.
     58                                        for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
     59                                        {
     60                                                var callback = styleStateChangeCallbacks[ i ];
    5961
    60                                         // Check the current state for the style defined for that
    61                                         // callback.
    62                                         var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
     62                                                // Check the current state for the style defined for that
     63                                                // callback.
     64                                                var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
    6365
    64                                         // If the state changed since the last check.
    65                                         if ( callback.state !== currentState )
    66                                         {
    67                                                 // Call the callback function, passing the current
    68                                                 // state to it.
    69                                                 callback.fn.call( this, currentState );
     66                                                // If the state changed since the last check.
     67                                                if ( callback.state !== currentState )
     68                                                {
     69                                                        // Call the callback function, passing the current
     70                                                        // state to it.
     71                                                        callback.fn.call( this, currentState );
    7072
    71                                                 // Save the current state, so it can be compared next
    72                                                 // time.
    73                                                 callback.state = currentState;
    74                                         }
    75                                 }
    76                         });
    77         }
     73                                                        // Save the current state, so it can be compared next
     74                                                        // time.
     75                                                        callback.state = currentState;
     76                                                }
     77                                        }
     78                                });
     79                }
    7880
    79         // Save the callback info, so it can be checked on the next occurrence of
    80         // selectionChange.
    81         styleStateChangeCallbacks.push( { style : style, fn : callback } );
    82 };
     81                // Save the callback info, so it can be checked on the next occurrence of
     82                // selectionChange.
     83                styleStateChangeCallbacks.push( { style : style, fn : callback } );
     84        },
    8385
     86        fireStyleStateChange : function( style, state )
     87        {
     88                var callbacks = this._.styleStateChangeCallbacks;
     89
     90                for ( var i = 0 ; i < callbacks.length ; i++ )
     91                {
     92                        var callback = callbacks[ i ];
     93                        if ( callback.style == style &&
     94                                        callback.state !== state )
     95                        {
     96                                callback.fn.call( this, state );
     97                                callback.state = state;
     98                        }
     99                }
     100        },
     101
     102        pendStyle : function ( style, type )
     103        {
     104                var pendings = this._.pendingStyles || ( this._.pendingStyles = [] ),
     105                                length = pendings.length,
     106                                pendingStyle,
     107                                remove = -1,
     108                                duplicate = -1;
     109
     110                for ( var i = 0; i < length; i++ )
     111                {
     112                        pendingStyle = pendings[ i ];
     113                        if( pendingStyle.style == style )
     114                        {
     115                                if( pendingStyle.type != type )
     116                                        remove = i;
     117                                else
     118                                        duplicate = i;
     119                        }
     120                }
     121
     122                if( duplicate == -1 )
     123                {
     124                        if( remove != -1 )
     125                                pendings.splice( remove, 1 );
     126                        else
     127                                pendings.push( { style : style, type : type } );
     128                }
     129
     130                this.fireStyleStateChange( style, type );
     131                return pendings.length;
     132        },
     133
     134        applyPending : function ( range )
     135        {
     136                var pendings = this._.pendingStyles,
     137                                length = pendings && pendings.length,
     138                                pendingStyle;
     139
     140                for ( var i = 0; i < length; i++ )
     141                {
     142                        pendingStyle = pendings[ i ];
     143                        range ? pendingStyle.style[ ( pendingStyle.type == CKEDITOR.TRISTATE_ON ?  'applyTo' : 'removeFrom' ) + 'Range']( range)
     144                                        : pendingStyle.style[ pendingStyle.type == CKEDITOR.TRISTATE_ON ?  'apply' : 'remove']( this.document );
     145                }
     146
     147                this._.pendingStyles = [];
     148        },
     149
     150        removePending : function ()
     151        {
     152                var pendings = this._.pendingStyles,
     153                                length = pendings && pendings.length,
     154                                pendingStyle;
     155
     156                for ( var i = 0; i < length; i++ )
     157                {
     158                        pendingStyle = pendings[ i ];
     159                        this.fireStyleStateChange( pendingStyle.style, CKEDITOR.TRISTATE_ON ?  CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_ON );
     160                }
     161
     162                this._.pendingStyles = [];
     163        }
     164
     165} );
     166
    84167CKEDITOR.STYLE_BLOCK = 1;
    85168CKEDITOR.STYLE_INLINE = 2;
    86169CKEDITOR.STYLE_OBJECT = 3;
     
    293376                        return false;
    294377                },
    295378
     379                pendApply : function( isRemove )
     380                {
     381                        var editor = CKEDITOR.currentInstance;
     382                        if( editor && editor.pendStyle(
     383                                        this, CKEDITOR[ isRemove ? 'TRISTATE_OFF' : 'TRISTATE_ON' ] ) )
     384                        {
     385                                var doc = editor.document;
     386                                doc.$.execCommand( 'FontName', false, '_cke_style' );
     387                                doc.on( 'DOMNodeInserted', onDomChangeDetectPending, editor );
     388                               
     389                                var sel = editor.getSelection(),
     390                                                nativeSel = sel.getNative(),
     391                                                image = { anchorNode : nativeSel.anchorNode ,
     392                                                        anchorOffset : nativeSel.anchorOffset };
     393
     394                                function checkRemovePending( evt )
     395                                {
     396                                        if( evt.name == 'blur'
     397                                                        || nativeSel.anchorNode != image.anchorNode
     398                                                        || nativeSel.anchorOffset != image.anchorOffset )
     399                                        {
     400                                                evt.removeListener();
     401                                                editor.removePending();
     402                                                doc.removeListener( 'DOMNodeInserted', onDomChangeDetectPending );
     403                                        }
     404                                }
     405                               
     406                                doc.on( 'mouseup', checkRemovePending );
     407                                doc.on( 'keyup', checkRemovePending );
     408                                editor.on( 'blur', checkRemovePending );
     409                                editor.on( 'contentDomUnload', checkRemovePending );
     410                        }
     411                },
     412
     413                pendRemove : function()
     414                {
     415                        this.pendApply( true );
     416                },
     417
    296418                // Builds the preview HTML based on the styles definition.
    297419                buildPreview : function()
    298420                {
     
    402524
    403525                if ( range.collapsed )
    404526                {
     527                        if( CKEDITOR.env.webkit )
     528                        {
     529                                this.pendApply();
     530                                return false;
     531                        }
     532                       
    405533                        // Create the element to be inserted in the DOM.
    406534                        var collapsedElement = getElement( this, document );
    407535
     
    653781
    654782        function removeInlineStyle( range )
    655783        {
     784
     785                if( range.collapsed && CKEDITOR.env.webkit )
     786                {
     787                        this.pendRemove();
     788                        return false;
     789                }
     790
    656791                /*
    657792                 * Make sure our range has included all "collpased" parent inline nodes so
    658793                 * that our operation logic can be simpler.
     
    14721607                var selection = document.getSelection(),
    14731608                        ranges = selection.getRanges( true ),
    14741609                        func = remove ? this.removeFromRange : this.applyToRange,
     1610                        retval,
    14751611                        range;
    14761612
    14771613                var iterator = ranges.createIterator();
    14781614                while ( ( range = iterator.getNextRange() ) )
    1479                         func.call( this, range );
     1615                        retval = func.call( this, range );
    14801616
    1481                 selection.selectRanges( ranges );
     1617                retval  !== false && selection.selectRanges( ranges );
    14821618
    14831619                document.removeCustomData( 'doc_processing_style' );
    14841620        }
     1621
     1622        function onDomChangeDetectPending( evt )
     1623        {
     1624                var target = evt.data.getTarget(),
     1625                                parent = target.type == CKEDITOR.NODE_TEXT && target.getParent(),
     1626                                styleMarker = parent && parent.$.face == '_cke_style' ? parent : null;
     1627
     1628                if ( styleMarker )
     1629                {
     1630                        var range = new CKEDITOR.dom.range( this.document );
     1631                        range.selectNodeContents( styleMarker );
     1632
     1633                        // Remove Apple-style-span marker;
     1634                        var bookmark = range.createBookmark();
     1635                        styleMarker.remove( true );
     1636                        range.moveToBookmark( bookmark );
     1637
     1638                        // Apply pending styles to the marked range.
     1639                        this.applyPending( range );
     1640
     1641                        range.collapse();
     1642                        range.select();
     1643                }
     1644        }
    14851645})();
    14861646
    14871647CKEDITOR.styleCommand = function( style )
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy