Ticket #3002: 3002.patch

File 3002.patch, 61.1 KB (added by Frederico Caldeira Knabben, 9 years ago)
  • _source/core/editor.js

     
    188188                                CKEDITOR.scriptLoader.load( languageFiles, function()
    189189                                        {
    190190                                                // Initialize all plugins that have the "beforeInit" and "init" methods defined.
    191                                                 var methods = [ 'beforeInit', 'init' ];
     191                                                var methods = [ 'beforeInit', 'init', 'afterInit' ];
    192192                                                for ( var m = 0 ; m < methods.length ; m++ )
    193193                                                {
    194194                                                        for ( var i = 0 ; i < pluginsArray.length ; i++ )
  • _source/core/htmlparser/basicwriter.js

     
     1/*
     2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
     3For licensing, see LICENSE.html or http://ckeditor.com/license
     4*/
     5
     6CKEDITOR.htmlParser.basicWriter = CKEDITOR.tools.createClass(
     7{
     8        $ : function()
     9        {
     10                this._ =
     11                {
     12                        output : []
     13                }
     14        },
     15
     16        proto :
     17        {
     18                /**
     19                 * Writes the tag opening part for a opener tag.
     20                 * @param {String} tagName The element name for this tag.
     21                 * @param {Object} attributes The attributes defined for this tag. The
     22                 *              attributes could be used to inspect the tag.
     23                 * @example
     24                 * // Writes "&lt;p".
     25                 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
     26                 */
     27                openTag : function( tagName, attributes )
     28                {
     29                        this._.output.push( '<', tagName );
     30                },
     31
     32                /**
     33                 * Writes the tag closing part for a opener tag.
     34                 * @param {String} tagName The element name for this tag.
     35                 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
     36                 *              like "br" or "img".
     37                 * @example
     38                 * // Writes "&gt;".
     39                 * writer.openTagClose( 'p', false );
     40                 * @example
     41                 * // Writes " /&gt;".
     42                 * writer.openTagClose( 'br', true );
     43                 */
     44                openTagClose : function( tagName, isSelfClose )
     45                {
     46                        if ( isSelfClose )
     47                                this._.output.push( ' />' );
     48                        else
     49                                this._.output.push( '>' );
     50                },
     51
     52                /**
     53                 * Writes an attribute. This function should be called after opening the
     54                 * tag with {@link #openTagClose}.
     55                 * @param {String} attName The attribute name.
     56                 * @param {String} attValue The attribute value.
     57                 * @example
     58                 * // Writes ' class="MyClass"'.
     59                 * writer.attribute( 'class', 'MyClass' );
     60                 */
     61                attribute : function( attName, attValue )
     62                {
     63                        this._.output.push( ' ', attName, '="', attValue, '"' );
     64                },
     65
     66                /**
     67                 * Writes a closer tag.
     68                 * @param {String} tagName The element name for this tag.
     69                 * @example
     70                 * // Writes "&lt;/p&gt;".
     71                 * writer.closeTag( 'p' );
     72                 */
     73                closeTag : function( tagName )
     74                {
     75                        this._.output.push( '</', tagName, '>' );
     76                },
     77
     78                /**
     79                 * Writes text.
     80                 * @param {String} text The text value
     81                 * @example
     82                 * // Writes "Hello Word".
     83                 * writer.text( 'Hello Word' );
     84                 */
     85                text : function( text )
     86                {
     87                        this._.output.push( text );
     88                },
     89
     90                /**
     91                 * Writes a comment.
     92                 * @param {String} comment The comment text.
     93                 * @example
     94                 * // Writes "&lt;!-- My comment --&gt;".
     95                 * writer.comment( ' My comment ' );
     96                 */
     97                comment : function( comment )
     98                {
     99                        this._.output.push( '<!--', comment, '-->' );
     100                },
     101
     102                /**
     103                 * Writes any kind of data to the ouput.
     104                 * @example
     105                 * writer.write( 'This is an &lt;b&gt;example&lt;/b&gt;.' );
     106                 */
     107                write : function( data )
     108                {
     109                        this._.output.push( data );
     110                },
     111
     112                /**
     113                 * Empties the current output buffer.
     114                 * @example
     115                 * writer.reset();
     116                 */
     117                reset : function()
     118                {
     119                        this._.output = [];
     120                },
     121
     122                /**
     123                 * Empties the current output buffer.
     124                 * @param {Boolean} reset Indicates that the {@link reset} function is to
     125                 *              be automatically called after retrieving the HTML.
     126                 * @returns {String} The HTML written to the writer so far.
     127                 * @example
     128                 * var html = writer.getHtml();
     129                 */
     130                getHtml : function( reset )
     131                {
     132                        var html = this._.output.join( '' );
     133
     134                        if ( reset )
     135                                this.reset();
     136
     137                        return html;
     138                }
     139        }
     140});
     141 No newline at end of file
  • _source/core/htmlparser/comment.js

     
    3838         * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
    3939         * @example
    4040         */
    41         writeHtml : function( writer )
     41        writeHtml : function( writer, filter )
    4242        {
    43                 writer.comment( this.value );
     43                var comment = this.value;
     44
     45                if ( filter && !( comment = filter.onComment( comment ) ) )
     46                        return;
     47
     48                writer.comment( comment );
    4449        }
    4550};
  • _source/core/htmlparser/element.js

     
    1313 */
    1414CKEDITOR.htmlParser.element = function( name, attributes )
    1515{
    16         if ( attributes._cke_saved_src )
    17                 attributes.src = attributes._cke_saved_src;
    18 
    19         if ( attributes._cke_saved_href )
    20                 attributes.href = attributes._cke_saved_href;
    21 
    22         // IE outputs style attribute in capital letters. We should convert them
    23         // back to lower case.
    24         if ( CKEDITOR.env.ie && attributes.style )
    25                 attributes.style = attributes.style.toLowerCase();
    26                
    2716        /**
    2817         * The element name.
    2918         * @type String
     
    7160                return a < b ? -1 : a > b ? 1 : 0;
    7261        };
    7362
    74         var ckeAttrRegex = /^_cke/,
    75                 ckeNamespaceRegex = /^cke:/,
    76                 ckeStyleWidthRegex = /width\s*:\s*(\d+)/i,
    77                 ckeStyleHeightRegex = /height\s*:\s*(\d+)/i,
    78                 ckeClassRegex = /(?:^|\s+)cke_[^\s]*/g,
    79                 ckePrivateAttrRegex = /^_cke_pa_/;
    80 
    8163        CKEDITOR.htmlParser.element.prototype =
    8264        {
    8365                /**
     
    11395                 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
    11496                 * @example
    11597                 */
    116                 writeHtml : function( writer )
     98                writeHtml : function( writer, filter )
    11799                {
    118100                        var attributes = this.attributes;
    119101
    120                         // The "_cke_realelement" attribute indicates that the current
    121                         // element is a placeholder for another element.
    122                         if ( attributes._cke_realelement )
    123                         {
    124                                 var realFragment = new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( attributes._cke_realelement ) );
    125 
    126                                 // If _cke_resizable is set, and the fake element contains inline CSS width
    127                                 // and height; then sync the width and height to the real element.
    128                                 if ( attributes._cke_resizable && ( 'style' in attributes ) )
    129                                 {
    130                                         var match = ckeStyleWidthRegex.exec( attributes.style ),
    131                                                 width = match ? match[1] : null;
    132                                         match = ckeStyleHeightRegex.exec( attributes.style );
    133                                         var height = match ? match[1] : null;
    134                                        
    135                                         var targetElement = realFragment.children[ 0 ];
    136                                         if ( targetElement && ( width != null || height != null ) )
    137                                         {
    138                                                 targetElement.attributes.width = width;
    139                                                 targetElement.attributes.height = height;
    140 
    141                                                 // Special case for #2916: If there's an EMBED inside an OBJECT, we need
    142                                                 // to set the EMBED's dimensions as well.
    143                                                 if ( targetElement.name == 'cke:object' )
    144                                                 {
    145                                                         for ( var i = 0 ; i < targetElement.children.length ; i++ )
    146                                                         {
    147                                                                 var child = targetElement.children[i];
    148                                                                 if ( child.name == 'cke:embed' )
    149                                                                 {
    150                                                                         child.attributes.width = width;
    151                                                                         child.attributes.height = height;
    152                                                                         break;
    153                                                                 }
    154                                                         }
    155                                                 }
    156                                         }
    157                                 }
    158 
    159                                 realFragment.writeHtml( writer );
    160                                 return;
    161                         }
    162 
    163102                        // The "_cke_replacedata" indicates that this element is replacing
    164103                        // a data snippet, which should be outputted as is.
    165104                        if ( attributes._cke_replacedata )
     
    169108                        }
    170109
    171110                        // Ignore cke: prefixes when writing HTML.
    172                         var writeName = this.name.replace( ckeNamespaceRegex, '' );
     111                        var element = this,
     112                                writeName = element.name,
     113                                a, value;
    173114
    174                         // Open element tag.
    175                         writer.openTag( writeName, this.attributes );
    176 
    177                         // Copy all attributes to an array.
    178                         var attribsArray = [];
    179                         for ( var a in attributes )
     115                        if ( filter )
    180116                        {
    181                                 var value = attributes[ a ];
     117                                while ( true )
     118                                {
     119                                        if ( !( writeName = filter.onElementName( writeName ) ) )
     120                                                return;
    182121
    183                                 // If the attribute name is _cke_pa_*, strip away the _cke_pa part.
    184                                 a = a.replace( ckePrivateAttrRegex, '' );
     122                                        element.name = writeName;
    185123
    186                                 // Ignore all attributes starting with "_cke".
    187                                 if ( ckeAttrRegex.test( a ) )
    188                                         continue;
     124                                        if ( !( element = filter.onElement( element ) ) )
     125                                                return;
    189126
    190                                 // Ignore all cke_* CSS classes.
    191                                 if ( a.toLowerCase() == 'class' )
    192                                 {
    193                                         value = CKEDITOR.tools.ltrim( value.replace( ckeClassRegex, '' ) );
    194                                         if ( value == '' )
    195                                                 continue;
     127                                        if ( element.name == writeName )
     128                                                break;
     129
     130                                        writeName = element.name;
    196131                                }
    197132
    198                                 attribsArray.push( [ a, value ] );
     133                                // The element may have been changed, so update the local
     134                                // references.
     135                                attributes = element.attributes;
    199136                        }
    200137
    201                         // Sort the attributes by name.
    202                         attribsArray.sort( sortAttribs );
     138                        // Open element tag.
     139                        writer.openTag( writeName, attributes );
    203140
    204                         // Send the attributes.
    205                         for ( var i = 0, len = attribsArray.length ; i < len ; i++ )
     141                        if ( writer.sortAttributes )
    206142                        {
    207                                 var attrib = attribsArray[ i ];
    208                                 writer.attribute( attrib[0], attrib[1] );
     143                                // Copy all attributes to an array.
     144                                var attribsArray = [];
     145                                for ( a in attributes )
     146                                {
     147                                        value = attributes[ a ];
     148
     149                                        if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
     150                                                continue;
     151
     152                                        attribsArray.push( [ a, value ] );
     153                                }
     154
     155                                // Sort the attributes by name.
     156                                attribsArray.sort( sortAttribs );
     157
     158                                // Send the attributes.
     159                                for ( var i = 0, len = attribsArray.length ; i < len ; i++ )
     160                                {
     161                                        var attrib = attribsArray[ i ];
     162                                        writer.attribute( attrib[0], attrib[1] );
     163                                }
    209164                        }
     165                        else
     166                        {
     167                                for ( a in attributes )
     168                                {
     169                                        writer.attribute( a, attributes[ a ] );
     170                                }
     171                        }
    210172
    211173                        // Close the tag.
    212                         writer.openTagClose( writeName, this.isEmpty );
     174                        writer.openTagClose( writeName, element.isEmpty );
    213175
    214                         if ( !this.isEmpty )
     176                        if ( !element.isEmpty )
    215177                        {
    216178                                // Send children.
    217                                 CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( this, arguments );
     179                                CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
    218180
    219181                                // Close the element.
    220182                                writer.closeTag( writeName );
  • _source/core/htmlparser/filter.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(function()
     7{
     8        CKEDITOR.htmlParser.filter = CKEDITOR.tools.createClass(
     9        {
     10                $ : function( rules )
     11                {
     12                        this._ =
     13                        {
     14                                elementNames : [],
     15                                attributeNames : [],
     16                                elements : { $length : 0 },
     17                                attributes : { $length : 0 }
     18                        };
     19
     20                        if ( rules )
     21                                this.addRules( rules, 10 );
     22                },
     23
     24                proto :
     25                {
     26                        addRules : function( rules, priority )
     27                        {
     28                                if ( typeof priority != 'number' )
     29                                        priority = 10;
     30
     31                                // Add the elementNames.
     32                                addItemsToList( this._.elementNames, rules.elementNames, priority );
     33
     34                                // Add the attributeNames.
     35                                addItemsToList( this._.attributeNames, rules.attributeNames, priority );
     36
     37                                // Add the elements.
     38                                addNamedItems( this._.elements, rules.elements, priority );
     39
     40                                // Add the attributes.
     41                                addNamedItems( this._.attributes, rules.attributes, priority );
     42
     43                                // Add the text.
     44                                this._.text = transformNamedItem( this._.text, rules.text, priority ) || this._.text;
     45
     46                                // Add the comment.
     47                                this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment;
     48                        },
     49
     50                        onElementName : function( name )
     51                        {
     52                                return filterName( name, this._.elementNames );
     53                        },
     54
     55                        onAttributeName : function( name )
     56                        {
     57                                return filterName( name, this._.attributeNames );
     58                        },
     59
     60                        onText : function( text )
     61                        {
     62                                var textFilter = this._.text;
     63                                return textFilter ? textFilter.filter( text ) : text;
     64                        },
     65
     66                        onComment : function( commentText )
     67                        {
     68                                var textFilter = this._.comment;
     69                                return textFilter ? textFilter.filter( commentText ) : commentText;
     70                        },
     71
     72                        onElement : function( element )
     73                        {
     74                                // We must apply filters set to the specific element name as
     75                                // well as those set to the generic $ name. So, add both to an
     76                                // array and process them in a small loop.
     77                                var filters = [ this._.elements[ element.name ], this._.elements.$ ],
     78                                        filter, ret;
     79
     80                                for ( var i = 0 ; i < 2 ; i++ )
     81                                {
     82                                        filter = filters[ i ];
     83                                        if ( filter )
     84                                        {
     85                                                ret = filter.filter( element, this );
     86
     87                                                if ( ret === false )
     88                                                        return null;
     89
     90                                                if ( ret && ret != element )
     91                                                        return this.onElement( ret );;
     92                                        }
     93                                }
     94
     95                                return element;
     96                        },
     97
     98                        onAttribute : function( element, name, value )
     99                        {
     100                                var filter = this._.attributes[ name ];
     101
     102                                if ( filter )
     103                                {
     104                                        var ret = filter.filter( value, element, this );
     105
     106                                        if ( ret === false )
     107                                                return false;
     108
     109                                        if ( typeof ret != 'undefined' )
     110                                                return ret;
     111                                }
     112
     113                                return value;
     114                        }
     115                }
     116        });
     117
     118        function filterName( name, filters )
     119        {
     120                for ( var i = 0 ; name && i < filters.length ; i++ )
     121                {
     122                        var filter = filters[ i ];
     123                        name = name.replace( filter[ 0 ], filter[ 1 ] );
     124                }
     125                return name;
     126        }
     127
     128        function addItemsToList( list, items, priority )
     129        {
     130                var i, j,
     131                        listLength = list.length,
     132                        itemsLength = items && items.length;
     133
     134                if ( itemsLength )
     135                {
     136                        // Find the index to insert the items at.
     137                        for ( i = 0 ; i < listLength && list[ i ].pri < priority ; i++ )
     138                        {}
     139
     140                        // Add all new items to the list at the specific index.
     141                        for ( j = itemsLength - 1 ; j >= 0 ; j-- )
     142                        {
     143                                var item = items[ j ];
     144                                item.pri = priority;
     145                                list.splice( i, 0, item );
     146                        }
     147                }
     148        }
     149
     150        function addNamedItems( hashTable, items, priority )
     151        {
     152                if ( items )
     153                {
     154                        for ( var name in items )
     155                        {
     156                                var current = hashTable[ name ];
     157
     158                                hashTable[ name ] =
     159                                        transformNamedItem(
     160                                                current,
     161                                                items[ name ],
     162                                                priority );
     163
     164                                if ( !current )
     165                                        hashTable.$length++;
     166                        }
     167                }
     168        }
     169
     170        function transformNamedItem( current, item, priority )
     171        {
     172                if ( item )
     173                {
     174                        item.pri = priority;
     175
     176                        if ( current )
     177                        {
     178                                // If the current item is not an Array, transform it.
     179                                if ( !current.splice )
     180                                {
     181                                        if ( current.pri > priority )
     182                                                current = [ item, current ];
     183                                        else
     184                                                current = [ current, item ];
     185
     186                                        current.filter = callItems;
     187                                }
     188                                else
     189                                        addItemsToList( current, item, priority );
     190
     191                                return current;
     192                        }
     193                        else
     194                        {
     195                                item.filter = item;
     196                                return item;
     197                        }
     198                }
     199        }
     200
     201        function callItems( currentEntry )
     202        {
     203                var isObject = ( typeof currentEntry == 'object' );
     204
     205                for ( var i = 0 ; i < this.length ; i++ )
     206                {
     207                        var item = this[ i ],
     208                                ret = item.apply( window, arguments );
     209
     210                        if ( typeof ret != 'undefined' )
     211                        {
     212                                if ( ret === false )
     213                                        return false;
     214
     215                                if ( isObject && ret != currentEntry )
     216                                        return ret;
     217                        }
     218                }
     219        }
     220})();
     221
     222// "entities" plugin
     223/*
     224{
     225        text : function( text )
     226        {
     227                // TODO : Process entities.
     228                return text.toUpperCase();
     229        }
     230};
     231*/
     232 No newline at end of file
  • _source/core/htmlparser/fragment.js

     
    9090
    9191                parser.onTagOpen = function( tagName, attributes, selfClosing )
    9292                {
    93                         // If the tag name is ?xml:namespace, ignore.
    94                         if ( tagName == '?xml:namespace' )
    95                                 return;
    96 
    9793                        var element = new CKEDITOR.htmlParser.element( tagName, attributes );
    9894
    9995                        // "isEmpty" will be always "false" for unknown elements, so we
     
    278274                 * fragment.writeHtml( writer )
    279275                 * alert( writer.getHtml() );  "&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;"
    280276                 */
    281                 writeHtml : function( writer )
     277                writeHtml : function( writer, filter )
    282278                {
    283279                        for ( var i = 0, len = this.children.length ; i < len ; i++ )
    284                                 this.children[i].writeHtml( writer );
     280                                this.children[i].writeHtml( writer, filter );
    285281                }
    286282        };
    287283})();
  • _source/core/htmlparser/text.js

     
    4242                 * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
    4343                 * @example
    4444                 */
    45                 writeHtml : function( writer )
     45                writeHtml : function( writer, filter )
    4646                {
    47                         writer.text( this.value );
     47                        var text = this.value;
     48
     49                        if ( filter && !( text = filter.onText( text ) ) )
     50                                return;
     51
     52                        writer.text( text );
    4853                }
    4954        };
    5055})();
  • _source/core/loader.js

     
    2525                {
    2626                        'core/_bootstrap'               : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ],
    2727                        'core/ajax'                             : [ 'core/xml' ],
    28                         'core/ckeditor'                 : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/tools' ],
     28                        'core/ckeditor'                 : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ],
    2929                        'core/ckeditor_base'    : [],
    3030                        'core/ckeditor_basic'   : [ 'core/editor_basic', 'core/env', 'core/event' ],
    3131                        'core/command'                  : [],
     
    5454                        'core/htmlparser/element'       : [ 'core/htmlparser', 'core/htmlparser/fragment' ],
    5555                        'core/htmlparser/fragment'      : [ 'core/htmlparser', 'core/htmlparser/comment', 'core/htmlparser/text' ],
    5656                        'core/htmlparser/text'          : [ 'core/htmlparser' ],
     57                        'core/htmlparser/filter'        : [ 'core/htmlparser' ],
     58                        'core/htmlparser/basicwriter': [ 'core/htmlparser' ],
    5759                        'core/imagecacher'              : [ 'core/dom/element' ],
    5860                        'core/lang'                             : [],
    5961                        'core/plugins'                  : [ 'core/resourcemanager' ],
  • _source/plugins/fakeobjects/plugin.js

     
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
    55
    6 CKEDITOR.plugins.add( 'fakeobjects' );
     6(function()
     7{
     8        var htmlFilterRules =
     9        {
     10                elements :
     11                {
     12                        $ : function( element, filter )
     13                        {
     14                                var realHtml = element.attributes._cke_realelement;
     15                                        realFragment = realHtml && new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( realHtml ), filter ),
     16                                        realElement = realFragment && realFragment.children[ 0 ];
    717
     18                                if ( realElement )
     19                                {
     20                                        // If we have width/height in the element, we must move it into
     21                                        // the real element.
     22
     23                                        var style = element.attributes.style;
     24                                       
     25                                        if ( style )
     26                                        {
     27                                                // Get the width from the style.
     28                                                var match = /(?:$|\s)width\s*:\s*(\d+)/.exec( style ),
     29                                                        width = match && match[1];
     30
     31                                                // Get the height from the style.
     32                                                match = /(?:$|\s)height\s*:\s*(\d+)/.exec( style );
     33                                                var height = match && match[1];
     34
     35                                                if ( width )
     36                                                        realElement.attributes.width = width;
     37                                               
     38                                                if ( height )
     39                                                        realElement.attributes.height = height;
     40                                        }
     41                                }
     42                               
     43                                return realElement;
     44                        }
     45                }
     46        };
     47
     48        CKEDITOR.plugins.add( 'fakeobjects',
     49        {
     50                requires : [ 'htmlwriter' ],
     51
     52                afterInit : function( editor )
     53                {
     54                        var dataProcessor = editor.dataProcessor,
     55                                htmlFilter = dataProcessor && dataProcessor.htmlFilter;
     56
     57                        if ( htmlFilter )
     58                                htmlFilter.addRules( htmlFilterRules );
     59                }
     60        });
     61})();
     62
    863CKEDITOR.editor.prototype.createFakeElement = function( realElement, className, realElementType, isResizable )
    964{
    1065        var attributes =
     
    2176        return this.document.createElement( 'img', { attributes : attributes } );
    2277};
    2378
     79CKEDITOR.editor.prototype.createFakeParserElement = function( realElement, className, realElementType, isResizable )
     80{
     81        var writer = new CKEDITOR.htmlParser.basicWriter();
     82       
     83        realElement.writeHtml( writer );
     84       
     85        var html = writer.getHtml();
     86       
     87        var attributes =
     88        {
     89                'class' : className,
     90                src : CKEDITOR.getUrl( 'images/spacer.gif' ),
     91                _cke_realelement : encodeURIComponent( html )
     92        };
     93
     94        if ( realElementType )
     95                attributes._cke_real_element_type = realElementType;
     96
     97        if ( isResizable )
     98                attributes._cke_resizable = isResizable;
     99
     100        return new CKEDITOR.htmlParser.element( 'img', attributes );
     101};
     102
    24103CKEDITOR.editor.prototype.restoreRealElement = function( fakeElement )
    25104{
    26105        var html = decodeURIComponent( fakeElement.getAttribute( '_cke_realelement' ) );
  • _source/plugins/flash/plugin.js

     
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
    55
    6 CKEDITOR.plugins.add( 'flash',
     6(function()
    77{
    8         init : function( editor )
     8        var flashFilenameRegex = /\.swf(?:$|\?)/i,
     9                numberRegex = /^\d+(?:\.\d+)?$/;
     10
     11        function cssifyLength( length )
    912        {
    10                 var flash = CKEDITOR.plugins.flash,
    11                         flashFilenameRegex = /\.swf(?:$|\?)/i,
    12                         numberRegex = /^\d+(?:\.\d+)?$/;
     13                if ( numberRegex.test( length ) )
     14                        return length + 'px';
     15                return length;
     16        }
    1317       
    14                 function cssifyLength( length )
    15                 {
    16                         if ( numberRegex.test( length ) )
    17                                 return length + 'px';
    18                         return length;
    19                 }
     18        function isFlashEmbed( element )
     19        {
     20                var attributes = element.attributes;
    2021
    21                 editor.addCommand( 'flash', new CKEDITOR.dialogCommand( 'flash' ) );
    22                 editor.ui.addButton( 'Flash',
    23                         {
    24                                 label : editor.lang.common.flash,
    25                                 command : 'flash'
    26                         });
    27                 CKEDITOR.dialog.add( 'flash', this.path + 'dialogs/flash.js' );
     22                return ( attributes.type != 'application/x-shockwave-flash' || !flashFilenameRegex.test( attributes.src || '' ) );
     23        }
    2824
    29                 editor.addCss(
    30                         'img.cke_flash' +
    31                         '{' +
    32                                 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/flashlogo.gif' ) + ');' +
    33                                 'background-position: center center;' +
    34                                 'background-repeat: no-repeat;' +
    35                                 'border: 1px solid #a9a9a9;' +
    36                                 'width: 80px;' +
    37                                 'height: 80px;' +
    38                         '}'
    39                         );
     25        function createFakeElement( editor, realElement )
     26        {
     27                var fakeElement = editor.createFakeParserElement( realElement, 'cke_flash', 'flash', true ),
     28                        fakeStyle = fakeElement.attributes.style || '';
    4029
    41                 editor.on( 'contentDom', function()
    42                         {
    43                                 var rawObjectNodes = editor.document.$.getElementsByTagName( CKEDITOR.env.ie ? 'object' : 'cke:object' );
    44                                 for ( var i = rawObjectNodes.length - 1, objectNode ; i >= 0 ; i-- )
    45                                 {
    46                                         objectNode = new CKEDITOR.dom.element( rawObjectNodes[ i ] );
    47                                         if ( String( objectNode.getAttribute( 'classid' ) ).toLowerCase() != 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' )
    48                                                 continue;
     30                var width = realElement.attributes.width,
     31                        height = realElement.attributes.height;
    4932
    50                                         var fakeElement = editor.createFakeElement( objectNode, 'cke_flash', 'flash', true );
    51                                         if ( objectNode.getAttribute( 'width' ) != null )
    52                                                 fakeElement.setStyle( 'width', cssifyLength( objectNode.getAttribute( 'width' ) ) );
    53                                         if ( objectNode.getAttribute( 'height' ) != null )
    54                                                 fakeElement.setStyle( 'height', cssifyLength( objectNode.getAttribute( 'height' ) ) );
    55                                         fakeElement.replace( objectNode );
    56                                 }
     33                if ( typeof width != 'undefined' )
     34                        fakeStyle = fakeElement.attributes.style = fakeStyle + 'width:' + cssifyLength( width ) + ';';
    5735
    58                                 var rawEmbedNodes = editor.document.$.getElementsByTagName( CKEDITOR.env.ie ? 'embed' : 'cke:embed' );
    59                                 for ( var i = rawEmbedNodes.length - 1, embedNode ; i >= 0 ; i-- )
    60                                 {
    61                                         embedNode = new CKEDITOR.dom.element( rawEmbedNodes[ i ] );
    62                                         if ( embedNode.getAttribute( 'type' ) != 'application/x-shockwave-flash'
    63                                                 && !flashFilenameRegex.test( embedNode.getAttribute( 'src' ) ) )
    64                                                 continue;
    65                                         var fakeElement = editor.createFakeElement( embedNode, 'cke_flash', 'flash', true );
    66                                         if ( embedNode.getAttribute( 'width' ) != null )
    67                                                 fakeElement.setStyle( 'width', cssifyLength( embedNode.getAttribute( 'width' ) ) );
    68                                         if ( embedNode.getAttribute( 'height' ) != null )
    69                                                 fakeElement.setStyle( 'height', cssifyLength( embedNode.getAttribute( 'height' ) ) );
    70                                         fakeElement.replace( embedNode );
    71                                 }
    72                         } );
     36                if ( typeof height != 'undefined' )
     37                        fakeStyle = fakeElement.attributes.style = fakeStyle + 'height:' + cssifyLength( height ) + ';';
    7338
    74                 // If the "menu" plugin is loaded, register the menu items.
    75                 if ( editor.addMenuItems )
     39                return fakeElement;
     40        }
     41
     42        CKEDITOR.plugins.add( 'flash',
     43        {
     44                init : function( editor )
    7645                {
    77                         editor.addMenuItems(
     46                        editor.addCommand( 'flash', new CKEDITOR.dialogCommand( 'flash' ) );
     47                        editor.ui.addButton( 'Flash',
    7848                                {
    79                                         flash :
    80                                         {
    81                                                 label : editor.lang.flash.properties,
    82                                                 command : 'flash',
    83                                                 group : 'flash'
    84                                         }
     49                                        label : editor.lang.common.flash,
     50                                        command : 'flash'
    8551                                });
    86                 }
     52                        CKEDITOR.dialog.add( 'flash', this.path + 'dialogs/flash.js' );
    8753
    88                 // If the "contextmenu" plugin is loaded, register the listeners.
    89                 if ( editor.contextMenu )
     54                        editor.addCss(
     55                                'img.cke_flash' +
     56                                '{' +
     57                                        'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/flashlogo.gif' ) + ');' +
     58                                        'background-position: center center;' +
     59                                        'background-repeat: no-repeat;' +
     60                                        'border: 1px solid #a9a9a9;' +
     61                                        'width: 80px;' +
     62                                        'height: 80px;' +
     63                                '}'
     64                                );
     65
     66                        // If the "menu" plugin is loaded, register the menu items.
     67                        if ( editor.addMenuItems )
     68                        {
     69                                editor.addMenuItems(
     70                                        {
     71                                                flash :
     72                                                {
     73                                                        label : editor.lang.flash.properties,
     74                                                        command : 'flash',
     75                                                        group : 'flash'
     76                                                }
     77                                        });
     78                        }
     79
     80                        // If the "contextmenu" plugin is loaded, register the listeners.
     81                        if ( editor.contextMenu )
     82                        {
     83                                editor.contextMenu.addListener( function( element, selection )
     84                                        {
     85                                                if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' )
     86                                                        return { flash : CKEDITOR.TRISTATE_OFF };
     87                                        });
     88                        }
     89                },
     90
     91                afterInit : function( editor )
    9092                {
    91                         editor.contextMenu.addListener( function( element, selection )
    92                                 {
    93                                         if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' )
    94                                                 return { flash : CKEDITOR.TRISTATE_OFF };
    95                                 });
    96                 }
    97         },
     93                        var dataProcessor = editor.dataProcessor,
     94                                dataFilter = dataProcessor && dataProcessor.dataFilter;
    9895
    99         requires : [ 'fakeobjects' ]
    100 } );
     96                        if ( dataFilter )
     97                        {
     98                                dataFilter.addRules(
     99                                        {
     100                                                elements :
     101                                                {
     102                                                        'cke:object' : function( element )
     103                                                        {
     104                                                                var attributes = element.attributes,
     105                                                                        classId = attributes.classid && String( attributes.classid ).toLowerCase();
    101106
     107                                                                if ( !classId )
     108                                                                {
     109                                                                        // Look for the inner <embed>
     110                                                                        for ( var i = 0 ; i < element.children.length ; i++ )
     111                                                                        {
     112                                                                                if ( element.children[ i ].name == 'embed' )
     113                                                                                {
     114                                                                                        if ( !isFlashEmbed( element.children[ i ] ) )
     115                                                                                                return;
     116                                                                                       
     117                                                                                        return createFakeElement( editor, element );                                                           
     118                                                                                }
     119                                                                        }
     120                                                                        return;
     121                                                                }
     122
     123                                                                return createFakeElement( editor, element );
     124                                                        },
     125
     126                                                        'cke:embed' : function( element )
     127                                                        {
     128                                                                if ( !isFlashEmbed( element ) )
     129                                                                        return;
     130
     131                                                                return createFakeElement( editor, element );
     132                                                        }
     133                                                }
     134                                        },
     135                                        5);
     136                        }
     137                },
     138
     139                requires : [ 'fakeobjects' ]
     140        });
     141})();
     142
    102143CKEDITOR.tools.extend( CKEDITOR.config,
    103144{
    104145        flashUploadTab : true,
  • _source/plugins/htmldataprocessor/plugin.js

     
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
    55
    6 CKEDITOR.plugins.add( 'htmldataprocessor',
     6(function()
    77{
    8         requires : [ 'htmlwriter' ],
     8        var defaultDataFilterRules =
     9        {
     10                elementNames :
     11                [
     12                        // Elements that cause problems in wysiwyg mode.
     13                        [ /^(object|embed|param)$/, 'cke:$1' ]
     14                ],
    915
    10         init : function( editor, pluginPath )
     16                attributeNames :
     17                [
     18                        // Event attributes (onXYZ) must not be directly set. They can become
     19                        // active in the editing area (IE|WebKit).
     20                        [ /^on/, '_cke_pa_on' ]
     21                ]
     22        };
     23
     24        var defaultHtmlFilterRules =
     25                {
     26                        elementNames :
     27                        [
     28                                // Remove the "cke:" namespace prefix.
     29                                [ /^cke:/, '' ],
     30
     31                                // Ignore <?xml:namespace> tags.
     32                                [ /^\?xml:namespace$/, '' ]
     33                        ],
     34
     35                        attributeNames :
     36                        [
     37                                // Attributes saved for changes and protected attributes.
     38                                [ /^_cke_(saved|pa)_/, '' ],
     39
     40                                // All "_cke" attributes are to be ignored.
     41                                [ /^_cke.*/, '' ]
     42                        ],
     43
     44                        elements :
     45                        {
     46                                embed : function( element )
     47                                {
     48                                        var parent = element.parent;
     49
     50                                        // If the <embed> is child of a <object>, copy the width
     51                                        // and height attributes from it.
     52                                        if ( parent && parent.name == 'object' )
     53                                        {
     54                                                element.attributes.width = parent.attributes.width;
     55                                                element.attributes.height = parent.attributes.height;
     56                                        }
     57                                },
     58
     59                                img : function( element )
     60                                {
     61                                        var attribs = element.attributes;
     62
     63                                        if ( attribs._cke_saved_src )
     64                                                delete attribs.src;
     65                                },
     66
     67                                a : function( element )
     68                                {
     69                                        var attribs = element.attributes;
     70
     71                                        if ( attribs._cke_saved_href )
     72                                                delete attribs.href;
     73                                }
     74                        },
     75
     76                        attributes :
     77                        {
     78                                'class' : function( value, element )
     79                                {
     80                                        // Remove all class names starting with "cke_".
     81                                        return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false;
     82                                }
     83                        }
     84                };
     85
     86        if ( CKEDITOR.env.ie )
    1187        {
    12                 var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor();
    13                
    14                 dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
     88                // IE outputs style attribute in capital letters. We should convert
     89                // them back to lower case.
     90                defaultHtmlFilterRules.attributes.style = function( value, element )
     91                {
     92                        return value.toLowerCase();
     93                }
    1594        }
    16 });
    1795
    18 CKEDITOR.htmlDataProcessor = function()
    19 {
    20         this.writer = new CKEDITOR.htmlWriter();
    21 };
     96        var protectUrlTagRegex = /<(?:a|area|img).*?\s((?:href|src)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi;
    2297
    23 CKEDITOR.htmlDataProcessor.prototype =
    24 {
    25         toHtml : function( data )
     98        function protectUrls( html )
    2699        {
    27                 // The source data is already HTML, so just return it as is.
    28                 return data;
    29         },
     100                return html.replace( protectUrlTagRegex, '$& _cke_saved_$1' );
     101        };
    30102
    31         toDataFormat : function( element )
     103        CKEDITOR.plugins.add( 'htmldataprocessor',
    32104        {
    33                 var writer = this.writer,
    34                         fragment = CKEDITOR.htmlParser.fragment.fromHtml( element.getHtml() );
     105                requires : [ 'htmlwriter' ],
    35106
    36                 writer.reset();
     107                init : function( editor, pluginPath )
     108                {
     109                        var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor();
    37110
    38                 fragment.writeHtml( writer );
     111                        dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
    39112
    40                 return writer.getHtml( true );
    41         }
    42 };
     113                        dataProcessor.dataFilter.addRules( defaultDataFilterRules );
     114                        dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules );
     115                }
     116        });
    43117
     118        CKEDITOR.htmlDataProcessor = function()
     119        {
     120                this.writer = new CKEDITOR.htmlWriter();
     121                this.dataFilter = new CKEDITOR.htmlParser.filter();
     122                this.htmlFilter = new CKEDITOR.htmlParser.filter();
     123        };
     124
     125        CKEDITOR.htmlDataProcessor.prototype =
     126        {
     127                toHtml : function( data )
     128                {
     129                        // The source data is already HTML, but we need to clean
     130                        // it up and apply the filter.
     131
     132                        // Before anything, we must protect the URL attributes as the
     133                        // browser may changing them when setting the innerHTML later in
     134                        // the code.
     135                        data = protectUrls( data );
     136
     137                        // Call the browser to help us fixing a possibly invalid HTML
     138                        // structure.
     139                        var div = document.createElement( 'div' );
     140                        div.innerHTML = data;
     141
     142                        // Now use our parser to make further fixes to the structure, as
     143                        // well as apply the filter.
     144                        var fragment = CKEDITOR.htmlParser.fragment.fromHtml( div.innerHTML ),
     145                                writer = new CKEDITOR.htmlParser.basicWriter();
     146
     147                        fragment.writeHtml( writer, this.dataFilter );
     148
     149                        return writer.getHtml( true );
     150                },
     151
     152                toDataFormat : function( html )
     153                {
     154                        var writer = this.writer,
     155                                fragment = CKEDITOR.htmlParser.fragment.fromHtml( html );
     156
     157                        writer.reset();
     158
     159                        fragment.writeHtml( writer, this.htmlFilter );
     160
     161                        return writer.getHtml( true );
     162                }
     163        };
     164})();
     165
    44166CKEDITOR.config.forceSimpleAmpersand = false;
  • _source/plugins/htmlwriter/plugin.js

     
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
    55
     6CKEDITOR.plugins.add( 'htmlwriter' );
     7
    68/**
    79 * Class used to write HTML data.
    810 * @constructor
     
    1517 * writer.closeTag( 'p' );
    1618 * alert( writer.getHtml() );  "&lt;p class="MyClass"&gt;Hello&lt;/p&gt;"
    1719 */
    18 CKEDITOR.htmlWriter = function()
     20CKEDITOR.htmlWriter = CKEDITOR.tools.createClass(
    1921{
    20         /**
    21          * The characters to be used for each identation step.
    22          * @type String
    23          * @default "\t" (tab)
    24          * @example
    25          * // Use two spaces for indentation.
    26          * editorInstance.dataProcessor.writer.indentationChars = '  ';
    27          */
    28         this.indentationChars   = '\t';
     22        base : CKEDITOR.htmlParser.basicWriter,
    2923
    30         /**
    31          * The characters to be used to close "self-closing" elements, like "br" or
    32          * "img".
    33          * @type String
    34          * @default " /&gt;"
    35          * @example
    36          * // Use HTML4 notation for self-closing elements.
    37          * editorInstance.dataProcessor.writer.selfClosingEnd = '>';
    38          */
    39         this.selfClosingEnd             = ' />';
     24        $ : function()
     25        {
     26                // Call the base contructor.
     27                this.base();
    4028
    41         /**
    42          * The characters to be used for line breaks.
    43         * @type String
    44          * @default "\n" (LF)
    45         * @example
    46          * // Use CRLF for line breaks.
    47          * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';
    48         */
    49         this.lineBreakChars             = '\n';
     29                /**
     30                 * The characters to be used for each identation step.
     31                * @type String
     32                 * @default "\t" (tab)
     33                * @example
     34                 * // Use two spaces for indentation.
     35                 * editorInstance.dataProcessor.writer.indentationChars = '  ';
     36                */
     37                this.indentationChars = '\t';
    5038
    51         this.forceSimpleAmpersand = false;
     39                /**
     40                 * The characters to be used to close "self-closing" elements, like "br" or
     41                 * "img".
     42                 * @type String
     43                 * @default " /&gt;"
     44                 * @example
     45                 * // Use HTML4 notation for self-closing elements.
     46                 * editorInstance.dataProcessor.writer.selfClosingEnd = '>';
     47                 */
     48                this.selfClosingEnd = ' />';
    5249
    53         this._ =
    54         {
    55                 output : [],
    56                 indent : false,
    57                 indentation : '',
    58                 rules : {}
    59         };
     50                /**
     51                 * The characters to be used for line breaks.
     52                 * @type String
     53                 * @default "\n" (LF)
     54                 * @example
     55                 * // Use CRLF for line breaks.
     56                 * editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';
     57                 */
     58                this.lineBreakChars = '\n';
    6059
    61         var dtd = CKEDITOR.dtd;
     60                this.forceSimpleAmpersand = false;
    6261
    63         for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) )
    64         {
    65                 this.setRules( e,
    66                         {
    67                                 indent : true,
    68                                 breakBeforeOpen : true,
    69                                 breakAfterOpen : true,
    70                                 breakBeforeClose : !dtd[ e ][ '#' ],
    71                                 breakAfterClose : true
    72                         });
    73         }
     62                this.sortAttributes = true;
    7463
    75         this.setRules( 'br',
    76                 {
    77                         breakAfterOpen : true
    78                 });
    79 };
     64                this._.indent = false;
     65                this._.indentation = '';
     66                this._.rules = {};
    8067
    81 CKEDITOR.htmlWriter.prototype =
    82 {
    83         /**
    84          * Writes the tag opening part for a opener tag.
    85          * @param {String} tagName The element name for this tag.
    86          * @param {Object} attributes The attributes defined for this tag. The
    87          *              attributes could be used to inspect the tag.
    88          * @example
    89          * // Writes "&lt;p".
    90          * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
    91          */
    92         openTag : function( tagName, attributes )
    93         {
    94                 var rules = this._.rules[ tagName ];
     68                var dtd = CKEDITOR.dtd;
    9569
    96                 if ( this._.indent )
    97                         this.indentation();
    98                 // Do not break if indenting.
    99                 else if ( rules && rules.breakBeforeOpen )
     70                for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) )
    10071                {
    101                         this.lineBreak();
    102                         this.indentation();
     72                        this.setRules( e,
     73                                {
     74                                        indent : true,
     75                                        breakBeforeOpen : true,
     76                                        breakAfterOpen : true,
     77                                        breakBeforeClose : !dtd[ e ][ '#' ],
     78                                        breakAfterClose : true
     79                                });
    10380                }
    10481
    105                 this._.output.push( '<', tagName );
     82                this.setRules( 'br',
     83                        {
     84                                breakAfterOpen : true
     85                        });
    10686        },
    10787
    108         /**
    109          * Writes the tag closing part for a opener tag.
    110          * @param {String} tagName The element name for this tag.
    111          * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
    112          *              like "br" or "img".
    113          * @example
    114          * // Writes "&gt;".
    115          * writer.openTagClose( 'p', false );
    116          * @example
    117          * // Writes " /&gt;".
    118          * writer.openTagClose( 'br', true );
    119          */
    120         openTagClose : function( tagName, isSelfClose )
     88        proto :
    12189        {
    122                 var rules = this._.rules[ tagName ];
    123 
    124                 if ( isSelfClose )
    125                         this._.output.push( this.selfClosingEnd );
    126                 else
     90                /**
     91                 * Writes the tag opening part for a opener tag.
     92                 * @param {String} tagName The element name for this tag.
     93                 * @param {Object} attributes The attributes defined for this tag. The
     94                 *              attributes could be used to inspect the tag.
     95                 * @example
     96                 * // Writes "&lt;p".
     97                 * writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
     98                 */
     99                openTag : function( tagName, attributes )
    127100                {
    128                         this._.output.push( '>' );
     101                        var rules = this._.rules[ tagName ];
    129102
    130                         if ( rules && rules.indent )
    131                                 this._.indentation += this.indentationChars;
    132                 }
     103                        if ( this._.indent )
     104                                this.indentation();
     105                        // Do not break if indenting.
     106                        else if ( rules && rules.breakBeforeOpen )
     107                        {
     108                                this.lineBreak();
     109                                this.indentation();
     110                        }
    133111
    134                 if ( rules && rules.breakAfterOpen )
    135                         this.lineBreak();
    136         },
     112                        this._.output.push( '<', tagName );
     113                },
    137114
    138         /**
    139          * Writes an attribute. This function should be called after opening the
    140          * tag with {@link #openTagClose}.
    141          * @param {String} attName The attribute name.
    142          * @param {String} attValue The attribute value.
    143          * @example
    144          * // Writes ' class="MyClass"'.
    145          * writer.attribute( 'class', 'MyClass' );
    146          */
    147         attribute : function( attName, attValue )
    148         {
    149                 if ( this.forceSimpleAmpersand )
    150                         attValue = attValue.replace( /&amp;/, '&' );
     115                /**
     116                 * Writes the tag closing part for a opener tag.
     117                 * @param {String} tagName The element name for this tag.
     118                 * @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
     119                 *              like "br" or "img".
     120                 * @example
     121                 * // Writes "&gt;".
     122                 * writer.openTagClose( 'p', false );
     123                 * @example
     124                 * // Writes " /&gt;".
     125                 * writer.openTagClose( 'br', true );
     126                 */
     127                openTagClose : function( tagName, isSelfClose )
     128                {
     129                        var rules = this._.rules[ tagName ];
    151130
    152                 this._.output.push( ' ', attName, '="', attValue, '"' );
    153         },
     131                        if ( isSelfClose )
     132                                this._.output.push( this.selfClosingEnd );
     133                        else
     134                        {
     135                                this._.output.push( '>' );
    154136
    155         /**
    156          * Writes a closer tag.
    157          * @param {String} tagName The element name for this tag.
    158          * @example
    159          * // Writes "&lt;/p&gt;".
    160          * writer.closeTag( 'p' );
    161          */
    162         closeTag : function( tagName )
    163         {
    164                 var rules = this._.rules[ tagName ];
     137                                if ( rules && rules.indent )
     138                                        this._.indentation += this.indentationChars;
     139                        }
    165140
    166                 if ( rules && rules.indent )
    167                         this._.indentation = this._.indentation.substr( this.indentationChars.length );
     141                        if ( rules && rules.breakAfterOpen )
     142                                this.lineBreak();
     143                },
    168144
    169                 if ( this._.indent )
    170                         this.indentation();
    171                 // Do not break if indenting.
    172                 else if ( rules && rules.breakBeforeClose )
     145                /**
     146                 * Writes an attribute. This function should be called after opening the
     147                 * tag with {@link #openTagClose}.
     148                 * @param {String} attName The attribute name.
     149                 * @param {String} attValue The attribute value.
     150                 * @example
     151                 * // Writes ' class="MyClass"'.
     152                 * writer.attribute( 'class', 'MyClass' );
     153                 */
     154                attribute : function( attName, attValue )
    173155                {
    174                         this.lineBreak();
    175                         this.indentation();
    176                 }
     156                        if ( this.forceSimpleAmpersand )
     157                                attValue = attValue.replace( /&amp;/, '&' );
    177158
    178                 this._.output.push( '</', tagName, '>' );
     159                        this._.output.push( ' ', attName, '="', attValue, '"' );
     160                },
    179161
    180                 if ( rules && rules.breakAfterClose )
    181                         this.lineBreak();
    182         },
    183 
    184         /**
    185          * Writes text.
    186          * @param {String} text The text value
    187          * @example
    188          * // Writes "Hello Word".
    189          * writer.text( 'Hello Word' );
    190          */
    191         text : function( text )
    192         {
    193                 if ( this._.indent )
     162                /**
     163                 * Writes a closer tag.
     164                 * @param {String} tagName The element name for this tag.
     165                 * @example
     166                 * // Writes "&lt;/p&gt;".
     167                 * writer.closeTag( 'p' );
     168                 */
     169                closeTag : function( tagName )
    194170                {
    195                         this.indentation();
    196                         text = CKEDITOR.tools.ltrim( text );
    197                 }
     171                        var rules = this._.rules[ tagName ];
    198172
    199                 this._.output.push( text );
    200         },
     173                        if ( rules && rules.indent )
     174                                this._.indentation = this._.indentation.substr( this.indentationChars.length );
    201175
    202         /**
    203          * Writes a comment.
    204          * @param {String} comment The comment text.
    205          * @example
    206          * // Writes "&lt;!-- My comment --&gt;".
    207          * writer.comment( ' My comment ' );
    208          */
    209         comment : function( comment )
    210         {
    211                 if ( this._.indent )
    212                         this.indentation();
     176                        if ( this._.indent )
     177                                this.indentation();
     178                        // Do not break if indenting.
     179                        else if ( rules && rules.breakBeforeClose )
     180                        {
     181                                this.lineBreak();
     182                                this.indentation();
     183                        }
    213184
    214                 this._.output.push( '<!--', comment, '-->' );
    215         },
     185                        this._.output.push( '</', tagName, '>' );
    216186
    217         /**
    218          * Writes a line break. It uses the {@link #lineBreakChars} property for it.
    219          * @example
    220          * // Writes "\n" (e.g.).
    221          * writer.lineBreak();
    222          */
    223         lineBreak : function()
    224         {
    225                 if ( this._.output.length > 0 )
    226                         this._.output.push( this.lineBreakChars );
    227                 this._.indent = true;
    228         },
     187                        if ( rules && rules.breakAfterClose )
     188                                this.lineBreak();
     189                },
    229190
    230         /**
    231          * Writes the current indentation chars. It uses the
    232          * {@link #indentationChars} property, repeating it for the current
    233          * indentation steps.
    234          * @example
    235          * // Writes "\t" (e.g.).
    236          * writer.indentation();
    237          */
    238         indentation : function()
    239         {
    240                 this._.output.push( this._.indentation );
    241                 this._.indent = false;
    242         },
     191                /**
     192                 * Writes text.
     193                 * @param {String} text The text value
     194                 * @example
     195                 * // Writes "Hello Word".
     196                 * writer.text( 'Hello Word' );
     197                 */
     198                text : function( text )
     199                {
     200                        if ( this._.indent )
     201                        {
     202                                this.indentation();
     203                                text = CKEDITOR.tools.ltrim( text );
     204                        }
    243205
    244         /**
    245          * Writes any kind of data to the ouput.
    246          * @example
    247          * writer.write( 'This is an &lt;b&gt;example&lt;/b&gt;.' );
    248          */
    249         write : function( data )
    250         {
    251                 this._.output.push( data );
    252         },
     206                        this._.output.push( text );
     207                },
    253208
    254         /**
    255          * Empties the current output buffer.
    256          * @example
    257          * writer.reset();
    258          */
    259         reset : function()
    260         {
    261                 this._.output = [];
    262         },
     209                /**
     210                 * Writes a comment.
     211                 * @param {String} comment The comment text.
     212                 * @example
     213                 * // Writes "&lt;!-- My comment --&gt;".
     214                 * writer.comment( ' My comment ' );
     215                 */
     216                comment : function( comment )
     217                {
     218                        if ( this._.indent )
     219                                this.indentation();
    263220
    264         /**
    265          * Empties the current output buffer.
    266          * @param {Boolean} reset Indicates that the {@link reset} function is to
    267          *              be automatically called after retrieving the HTML.
    268          * @returns {String} The HTML written to the writer so far.
    269          * @example
    270          * var html = writer.getHtml();
    271          */
    272         getHtml : function( reset )
    273         {
    274                 var html = this._.output.join( '' );
     221                        this._.output.push( '<!--', comment, '-->' );
     222                },
    275223
    276                 if ( reset )
    277                         this.reset();
     224                /**
     225                 * Writes a line break. It uses the {@link #lineBreakChars} property for it.
     226                 * @example
     227                 * // Writes "\n" (e.g.).
     228                 * writer.lineBreak();
     229                 */
     230                lineBreak : function()
     231                {
     232                        if ( this._.output.length > 0 )
     233                                this._.output.push( this.lineBreakChars );
     234                        this._.indent = true;
     235                },
    278236
    279                 return html;
    280         },
     237                /**
     238                 * Writes the current indentation chars. It uses the
     239                 * {@link #indentationChars} property, repeating it for the current
     240                 * indentation steps.
     241                 * @example
     242                 * // Writes "\t" (e.g.).
     243                 * writer.indentation();
     244                 */
     245                indentation : function()
     246                {
     247                        this._.output.push( this._.indentation );
     248                        this._.indent = false;
     249                },
    281250
    282         /**
    283          * Sets formatting rules for a give element. The possible rules are:
    284          * <ul>
    285          *      <li><b>indent</b>: indent the element contents.</li>
    286          *      <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
    287          *      <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
    288          *      <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
    289          *      <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
    290          * </ul>
    291          *
    292          * All rules default to "false".
    293          *
    294          * By default, all elements available in the {@link CKEDITOR.dtd.$block),
    295          * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}
    296          * lists have all the above rules set to "true". Additionaly, the "br"
    297          * element has the "breakAfterOpen" set to "true".
    298          * @param {String} tagName The element name to which set the rules.
    299          * @param {Object} rules An object containing the element rules.
    300          * @example
    301          * // Break line before and after "img" tags.
    302          * writer.setRules( 'img',
    303          *     {
    304          *         breakBeforeOpen : true
    305          *         breakAfterOpen : true
    306          *     });
    307          * @example
    308          * // Reset the rules for the "h1" tag.
    309          * writer.setRules( 'h1', {} );
    310          */
    311         setRules : function( tagName, rules )
    312         {
    313                 this._.rules[ tagName ] = rules;
     251                /**
     252                 * Sets formatting rules for a give element. The possible rules are:
     253                 * <ul>
     254                 *      <li><b>indent</b>: indent the element contents.</li>
     255                 *      <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
     256                 *      <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
     257                 *      <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
     258                 *      <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
     259                 * </ul>
     260                 *
     261                 * All rules default to "false".
     262                 *
     263                 * By default, all elements available in the {@link CKEDITOR.dtd.$block),
     264                 * {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}
     265                 * lists have all the above rules set to "true". Additionaly, the "br"
     266                 * element has the "breakAfterOpen" set to "true".
     267                 * @param {String} tagName The element name to which set the rules.
     268                 * @param {Object} rules An object containing the element rules.
     269                 * @example
     270                 * // Break line before and after "img" tags.
     271                 * writer.setRules( 'img',
     272                 *     {
     273                 *         breakBeforeOpen : true
     274                 *         breakAfterOpen : true
     275                 *     });
     276                 * @example
     277                 * // Reset the rules for the "h1" tag.
     278                 * writer.setRules( 'h1', {} );
     279                 */
     280                setRules : function( tagName, rules )
     281                {
     282                        this._.rules[ tagName ] = rules;
     283                }
    314284        }
    315 };
    316 
    317 CKEDITOR.plugins.add( 'htmlwriter' );
     285});
  • _source/plugins/link/plugin.js

     
    1 /*
     1/*
    22Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
    33For licensing, see LICENSE.html or http://ckeditor.com/license
    44*/
     
    6565                                        command.setState( CKEDITOR.TRISTATE_DISABLED );
    6666                        } );
    6767
    68                 // Register a contentDom handler for displaying placeholders after mode change.
    69                 editor.on( 'contentDom', function()
    70                         {
    71                                 var rawAnchors = editor.document.$.anchors;
    72                                 for ( var i = rawAnchors.length - 1, anchor ; i >= 0 ; i-- )
    73                                 {
    74                                         anchor = new CKEDITOR.dom.element( rawAnchors[ i ] );
    75 
    76                                         // IE BUG: When an <a> tag doesn't have href, IE would return empty string
    77                                         // instead of null on getAttribute.
    78                                         if ( !anchor.getAttribute( 'href' ) )
    79                                                 editor.createFakeElement( anchor, 'cke_anchor', 'anchor' ).replace( anchor );
    80                                         else
    81                                                 anchor.addClass( 'cke_anchor' );
    82                                 }
    83                         });
    84 
    8568                // If the "menu" plugin is loaded, register the menu items.
    8669                if ( editor.addMenuItems )
    8770                {
     
    137120                }
    138121        },
    139122
     123        afterInit : function( editor )
     124        {
     125                // Register a filter to displaying placeholders after mode change.
     126
     127                var dataProcessor = editor.dataProcessor,
     128                        dataFilter = dataProcessor && dataProcessor.dataFilter;
     129
     130                if ( dataFilter )
     131                {
     132                        dataFilter.addRules(
     133                                {
     134                                        elements :
     135                                        {
     136                                                a : function( element )
     137                                                {
     138                                                        var attributes = element.attributes;
     139                                                        if ( attributes.name && !attributes.href )
     140                                                                return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' );
     141                                                }
     142                                        }
     143                                });
     144                }
     145        },
     146
    140147        requires : [ 'fakeobjects' ]
    141148} );
    142149
  • _source/plugins/pagebreak/plugin.js

     
    3838                                'height: 5px;' +
    3939
    4040                        '}' );
    41                
    42                 // Listen for the "contentDom" event, so the document can be fixed to
    43                 // display the placeholders.
    44                 editor.on( 'contentDom', function()
    45                         {
    46                                 var divs = editor.document.getBody().getElementsByTag( 'div' );
    47                                 for ( var div, i = 0, length = divs.count() ; i < length ; i++ )
     41        },
     42       
     43        afterInit : function( editor )
     44        {
     45                // Register a filter to displaying placeholders after mode change.
     46                               
     47                var dataProcessor = editor.dataProcessor,
     48                        dataFilter = dataProcessor && dataProcessor.dataFilter;
     49
     50                if ( dataFilter )
     51                {
     52                        dataFilter.addRules(
    4853                                {
    49                                         div = divs.getItem( i );
    50                                         if ( div.getStyle( 'page-break-after' ) == 'always' && !/[^\s\u00A0]/.test( div.getText() ) )
     54                                        elements :
    5155                                        {
    52                                                 editor.createFakeElement( div, 'cke_pagebreak', 'div' ).replace( div );
     56                                                div : function( element )
     57                                                {
     58                                                        var style = element.attributes.style,
     59                                                                child = style && element.children.length == 1 && element.children[ 0 ],
     60                                                                childStyle = child && ( child.name == 'span' ) && child.attributes.style;
     61
     62                                                        if ( childStyle && /page-break-after\s*:\s*always/i.test( style ) && /display\s*:\s*none/i.test( childStyle ) )
     63                                                                return editor.createFakeParserElement( element, 'cke_pagebreak', 'div' );
     64                                                }
    5365                                        }
    54                                 }
    55                         });
     66                                });
     67                }
    5668        },
     69
    5770        requires : [ 'fakeobjects' ]
    5871});
    5972
  • _source/plugins/wysiwygarea/plugin.js

     
    1010
    1111(function()
    1212{
    13         // Matches all self-closing tags that are not defined as empty elements in
    14         // the DTD (like &lt;span/&gt;).
    15         var invalidSelfCloseTagsRegex = /(<(?!br|hr|base|meta|link|param|img|area|input|col)([a-zA-Z0-9:]+)[^>]*)\/>/gi;
    16 
    17         // #### protectEvents - START
    18 
    19         // Matches all tags that have event attributes (onXYZ).
    20         var tagsWithEventRegex = /<[^\>]+ on\w+\s*=[\s\S]+?\>/g;
    21 
    22         // Matches all event attributes.
    23         var eventAttributesRegex = /\s(on\w+)(?=\s*=\s*?('|")[\s\S]*?\2)/g;
    24 
    25         // Matches the protected attribute prefix.
    26         var protectedEventsRegex = /_cke_pa_/g;
    27 
    28         var protectEvents = function( html )
     13        function onInsertHtml( evt )
    2914        {
    30                 return html.replace( tagsWithEventRegex, protectEvents_ReplaceTags );
    31         };
    32 
    33         var protectEvents_ReplaceTags = function( tagMatch )
    34         {
    35                 // Appends the "_cke_pa_" prefix to the event name.
    36                 return tagMatch.replace( eventAttributesRegex, ' _cke_pa_$1' );
    37         };
    38 
    39         var protectEventsRestore = function( html )
    40         {
    41                 return html.replace( protectedEventsRegex, '' ) ;
    42         };
    43 
    44         // #### protectEvents - END
    45 
    46         // #### protectAttributes - START
    47        
    48         // TODO: Clean and simplify these regexes.
    49         var protectUrlTagRegex = /<(?:a|area|img)(?=\s).*?\s(?:href|src)=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi,
    50                 protectUrlAttributeRegex = /\s(href|src)(\s*=\s*?('|")[\s\S]*?\3)/gi;
    51        
    52         var protectUrls = function( html )
    53         {
    54                 return html.replace( protectUrlTagRegex, protectUrls_ReplaceTags );
    55         };
    56 
    57         var protectUrls_ReplaceTags = function( tagMatch )
    58         {
    59                 return tagMatch.replace( protectUrlAttributeRegex, '$& _cke_saved_$1$2');
    60         };
    61 
    62         // #### protectAttributes - END
    63 
    64         var onInsertHtml = function( evt )
    65         {
    6615                if ( this.mode == 'wysiwyg' )
    6716                {
    68                         var $doc = this.document.$;
     17                        var $doc = this.document.$,
     18                                data = evt.data;
    6919                        var data = protectHtml( evt.data );
    7020
     21                        if ( editor.dataProcessor )
     22                                data = editor.dataProcessor.toHtml( data );
     23
    7124                        if ( CKEDITOR.env.ie )
    7225                                $doc.selection.createRange().pasteHTML( data );
    7326                        else
    7427                                $doc.execCommand( 'inserthtml', false, data );
    7528                }
    76         };
    77 
    78         // ### protectCkeTags - START
    79         var protectCkeTagRegex = /(<\/?)(object|embed|param)/gi
    80         var protectCkeTags = function( html )
    81         {
    82                 return html.replace( protectCkeTagRegex, '$1cke:$2' );
    83         };
    84         // ### protectCkeTags - END
    85        
    86         function protectHtml( html )
    87         {
    88                 // Prevent event attributes (like "onclick") to
    89                 // execute while editing.
    90                 if ( CKEDITOR.env.ie || CKEDITOR.env.webkit )
    91                         html = protectEvents( html );
    92 
    93                 // Protect src or href attributes.
    94                 html = protectUrls( html );
    95 
    96                 // Protect cke prefixed tags.
    97                 html = protectCkeTags( html );
    98 
    99                 return html;
    10029        }
    10130
    102         var onInsertElement = function( evt )
     31        function onInsertElement( evt )
    10332        {
    10433                if ( this.mode == 'wysiwyg' )
    10534                {
     
    14069                        range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );
    14170                        selection.selectRanges( [ range ] );
    14271                }
    143         };
     72        }
    14473
    14574        CKEDITOR.plugins.add( 'wysiwygarea',
    14675        {
     
    342271                                                                if ( editor.dataProcessor )
    343272                                                                        data = editor.dataProcessor.toHtml( data );
    344273
    345                                                                 // Fix for invalid self-closing tags (see #152).
    346                                                                 // TODO: Check if this fix is really needed as
    347                                                                 // soon as we have the XHTML generator.
    348                                                                 if ( CKEDITOR.env.ie )
    349                                                                         data = data.replace( invalidSelfCloseTagsRegex, '$1></$2>' );
    350 
    351                                                                 data = protectHtml( data );
    352274                                                                data =
    353275                                                                        editor.config.docType +
    354276                                                                        '<html dir="' + editor.config.contentsLangDirection + '">' +
     
    394316
    395317                                                        getData : function()
    396318                                                        {
    397                                                                 var data = iframe.$.contentWindow.document.body;
     319                                                                var data = iframe.$.contentWindow.document.body.innerHTML;
    398320
    399321                                                                if ( editor.dataProcessor )
    400                                                                         data = editor.dataProcessor.toDataFormat( new CKEDITOR.dom.element( data ) );
    401                                                                 else
    402                                                                         data = data.innerHTML;
     322                                                                        data = editor.dataProcessor.toDataFormat( data );
    403323
    404                                                                 // Restore protected attributes.
    405                                                                 data = protectEventsRestore( data );
    406 
    407324                                                                return data;
    408325                                                        },
    409326
  • _source/tests/plugins/htmldataprocessor/htmldataprocessor.html

     
    4040                {
    4141                        var element = new CKEDITOR.dom.element.createFromHtml( '<div><p>Test</p></div>' );
    4242
    43                         assert.areSame( '<p>Test</p>', getDataProcessor().toDataFormat( element ) );
     43                        assert.areSame( '<p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    4444                },
    4545
    4646                test_toDataFormat_1b : function()
     
    4949
    5050                        // IE adds the XML namespace tag.
    5151                        if ( CKEDITOR.env.ie )
    52                                 assert.areSame( '<?xml:namespace prefix="x" /><x:x>Test</x:x>', getDataProcessor().toDataFormat( element ) );
     52                                assert.areSame( '<?xml:namespace prefix="x" /><x:x>Test</x:x>', getDataProcessor().toDataFormat( element.getHtml() ) );
    5353                        else
    54                                 assert.areSame( '<x:x>Test</x:x>', getDataProcessor().toDataFormat( element ) );
     54                                assert.areSame( '<x:x>Test</x:x>', getDataProcessor().toDataFormat( element.getHtml() ) );
    5555                },
    5656
    5757                test_toDataFormat_2a : function()
    5858                {
    5959                        var element = new CKEDITOR.dom.element.createFromHtml( '<div><br /><p>Test</p></div>' );
    6060
    61                         assert.areSame( '<br /><p>Test</p>', getDataProcessor().toDataFormat( element ) );
     61                        assert.areSame( '<br /><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    6262                },
    6363
    6464                test_toDataFormat_2b : function()
     
    6767
    6868                        // IE adds the XML namespace tag.
    6969                        if ( CKEDITOR.env.ie )
    70                                 assert.areSame( '<?xml:namespace prefix="x" /><x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element ) );
     70                                assert.areSame( '<?xml:namespace prefix="x" /><x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    7171                        else
    72                                 assert.areSame( '<x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element ) );
     72                                assert.areSame( '<x:x></x:x><p>Test</p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    7373                },
    7474
    7575                test_toDataFormat_3 : function()
    7676                {
    7777                        var element = new CKEDITOR.dom.element.createFromHtml( '<div><x:x><p>Test</p></div>' );
    7878
    79                         assert.areSame( '<x:x><p>Test</p></x:x>', getDataProcessor().toDataFormat( element ) );
     79                        assert.areSame( '<x:x><p>Test</p></x:x>', getDataProcessor().toDataFormat( element.getHtml() ) );
    8080                },
    8181
    8282                test_toDataFormat_ticket_2774 : function()
     
    8585
    8686                        // IE adds the XML namespace tag.
    8787                        if ( CKEDITOR.env.ie )
    88                                 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><?xml:namespace prefix="o" /><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element ) );
     88                                assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><?xml:namespace prefix="o" /><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    8989                        else
    90                                 assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element ) );
     90                                assert.areSame( '<p class="MsoNormal"><b><i><span lang="EN-US"><o:p>Test</o:p></span></i></b></p>', getDataProcessor().toDataFormat( element.getHtml() ) );
    9191                },
    9292
    9393                name : document.title
  • ckeditor.pack

     
    109109                                        '_source/core/htmlparser/text.js',
    110110                                        '_source/core/htmlparser/fragment.js',
    111111                                        '_source/core/htmlparser/element.js',
     112                                        '_source/core/htmlparser/filter.js',
     113                                        '_source/core/htmlparser/basicwriter.js',
    112114                                        '_source/core/ckeditor.js',
    113115                                        '_source/core/dom/elementpath.js',
    114116                                        '_source/core/dom/text.js',
© 2003 – 2017 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy