[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/htmldataprocessor/ -> plugin.js (source)

   1  /*

   2  Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.

   3  For licensing, see LICENSE.html or http://ckeditor.com/license

   4  */
   5  
   6  (function()
   7  {
   8      // Regex to scan for   at the end of blocks, which are actually placeholders.

   9      // Safari transforms the   to \xa0. (#4172)

  10      var tailNbspRegex = /^[\t\r\n ]*(?: |\xa0)$/;
  11  
  12      var protectedSourceMarker = '{cke_protected}';
  13  
  14      // Return the last non-space child node of the block (#4344).

  15  	function lastNoneSpaceChild( block )
  16      {
  17          var lastIndex = block.children.length,
  18              last = block.children[ lastIndex - 1 ];
  19          while (  last && last.type == CKEDITOR.NODE_TEXT && !CKEDITOR.tools.trim( last.value ) )
  20              last = block.children[ --lastIndex ];
  21          return last;
  22      }
  23  
  24  	function trimFillers( block, fromSource )
  25      {
  26          // If the current node is a block, and if we're converting from source or

  27          // we're not in IE then search for and remove any tailing BR node.

  28          //

  29          // Also, any   at the end of blocks are fillers, remove them as well.

  30          // (#2886)

  31          var children = block.children, lastChild = lastNoneSpaceChild( block );
  32          if ( lastChild )
  33          {
  34              if ( ( fromSource || !CKEDITOR.env.ie ) && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br' )
  35                  children.pop();
  36              if ( lastChild.type == CKEDITOR.NODE_TEXT && tailNbspRegex.test( lastChild.value ) )
  37                  children.pop();
  38          }
  39      }
  40  
  41  	function blockNeedsExtension( block )
  42      {
  43          var lastChild = lastNoneSpaceChild( block );
  44  
  45          return !lastChild
  46              || lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br'
  47              // Some of the controls in form needs extension too,

  48              // to move cursor at the end of the form. (#4791)

  49              || block.name == 'form' && lastChild.name == 'input';
  50      }
  51  
  52  	function extendBlockForDisplay( block )
  53      {
  54          trimFillers( block, true );
  55  
  56          if ( blockNeedsExtension( block ) )
  57          {
  58              if ( CKEDITOR.env.ie )
  59                  block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
  60              else
  61                  block.add( new CKEDITOR.htmlParser.element( 'br', {} ) );
  62          }
  63      }
  64  
  65  	function extendBlockForOutput( block )
  66      {
  67          trimFillers( block );
  68  
  69          if ( blockNeedsExtension( block ) )
  70              block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
  71      }
  72  
  73      var dtd = CKEDITOR.dtd;
  74  
  75      // Find out the list of block-like tags that can contain <br>.

  76      var blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent );
  77      for ( var i in blockLikeTags )
  78      {
  79          if ( ! ( 'br' in dtd[i] ) )
  80              delete blockLikeTags[i];
  81      }
  82      // We just avoid filler in <pre> right now.

  83      // TODO: Support filler for <pre>, line break is also occupy line height.

  84      delete blockLikeTags.pre;
  85      var defaultDataFilterRules =
  86      {
  87          elements : {},
  88          attributeNames :
  89          [
  90              // Event attributes (onXYZ) must not be directly set. They can become

  91              // active in the editing area (IE|WebKit).

  92              [ ( /^on/ ), '_cke_pa_on' ]
  93          ]
  94      };
  95  
  96      var defaultDataBlockFilterRules = { elements : {} };
  97  
  98      for ( i in blockLikeTags )
  99          defaultDataBlockFilterRules.elements[ i ] = extendBlockForDisplay;
 100  
 101      var defaultHtmlFilterRules =
 102          {
 103              elementNames :
 104              [
 105                  // Remove the "cke:" namespace prefix.

 106                  [ ( /^cke:/ ), '' ],
 107  
 108                  // Ignore <?xml:namespace> tags.

 109                  [ ( /^\?xml:namespace$/ ), '' ]
 110              ],
 111  
 112              attributeNames :
 113              [
 114                  // Attributes saved for changes and protected attributes.

 115                  [ ( /^_cke_(saved|pa)_/ ), '' ],
 116  
 117                  // All "_cke" attributes are to be ignored.

 118                  [ ( /^_cke.*/ ), '' ],
 119  
 120                  [ 'hidefocus', '' ]
 121              ],
 122  
 123              elements :
 124              {
 125                  $ : function( element )
 126                  {
 127                      var attribs = element.attributes;
 128  
 129                      if ( attribs )
 130                      {
 131                          // Elements marked as temporary are to be ignored.

 132                          if ( attribs.cke_temp )
 133                              return false;
 134  
 135                          // Remove duplicated attributes - #3789.

 136                          var attributeNames = [ 'name', 'href', 'src' ],
 137                              savedAttributeName;
 138                          for ( var i = 0 ; i < attributeNames.length ; i++ )
 139                          {
 140                              savedAttributeName = '_cke_saved_' + attributeNames[ i ];
 141                              savedAttributeName in attribs && ( delete attribs[ attributeNames[ i ] ] );
 142                          }
 143                      }
 144  
 145                      return element;
 146                  },
 147  
 148                  embed : function( element )
 149                  {
 150                      var parent = element.parent;
 151  
 152                      // If the <embed> is child of a <object>, copy the width

 153                      // and height attributes from it.

 154                      if ( parent && parent.name == 'object' )
 155                      {
 156                          var parentWidth = parent.attributes.width,
 157                              parentHeight = parent.attributes.height;
 158                          parentWidth && ( element.attributes.width = parentWidth );
 159                          parentHeight && ( element.attributes.height = parentHeight );
 160                      }
 161                  },
 162                  // Restore param elements into self-closing.

 163                  param : function( param )
 164                  {
 165                      param.children = [];
 166                      param.isEmpty = true;
 167                      return param;
 168                  },
 169  
 170                  // Remove empty link but not empty anchor.(#3829)

 171                  a : function( element )
 172                  {
 173                      if ( !( element.children.length ||
 174                              element.attributes.name ||
 175                              element.attributes._cke_saved_name ) )
 176                      {
 177                          return false;
 178                      }
 179                  },
 180  
 181                  html : function( element )
 182                  {
 183                      delete element.attributes.contenteditable;
 184                      delete element.attributes[ 'class' ];
 185                  },
 186  
 187                  body : function( element )
 188                  {
 189                      delete element.attributes.spellcheck;
 190                      delete element.attributes.contenteditable;
 191                  },
 192  
 193                  style : function( element )
 194                  {
 195                      var child = element.children[ 0 ];
 196                      child && child.value && ( child.value = CKEDITOR.tools.trim( child.value ));
 197  
 198                      if ( !element.attributes.type )
 199                          element.attributes.type = 'text/css';
 200                  },
 201  
 202                  title : function( element )
 203                  {
 204                      var titleText = element.children[ 0 ];
 205                      titleText && ( titleText.value = element.attributes[ '_cke_title' ] || '' );
 206                  }
 207              },
 208  
 209              attributes :
 210              {
 211                  'class' : function( value, element )
 212                  {
 213                      // Remove all class names starting with "cke_".

 214                      return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false;
 215                  }
 216              },
 217  
 218              comment : function( contents )
 219              {
 220                  // If this is a comment for protected source.

 221                  if ( contents.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker )
 222                  {
 223                      // Remove the extra marker for real comments from it.

 224                      if ( contents.substr( protectedSourceMarker.length, 3 ) == '{C}' )
 225                          contents = contents.substr( protectedSourceMarker.length + 3 );
 226                      else
 227                          contents = contents.substr( protectedSourceMarker.length );
 228  
 229                      return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents ) );
 230                  }
 231  
 232                  return contents;
 233              }
 234          };
 235  
 236      var defaultHtmlBlockFilterRules = { elements : {} };
 237  
 238      for ( i in blockLikeTags )
 239          defaultHtmlBlockFilterRules.elements[ i ] = extendBlockForOutput;
 240  
 241      if ( CKEDITOR.env.ie )
 242      {
 243          // IE outputs style attribute in capital letters. We should convert

 244          // them back to lower case.

 245          defaultHtmlFilterRules.attributes.style = function( value, element )
 246          {
 247              return value.toLowerCase();
 248          };
 249      }
 250  
 251  	function protectReadOnly( element )
 252      {
 253          element.attributes.contenteditable = "false";
 254      }
 255  	function unprotectReadyOnly( element )
 256      {
 257          delete element.attributes.contenteditable;
 258      }
 259      // Disable form elements editing mode provided by some browers. (#5746)

 260      for ( i in { input : 1, textarea : 1 } )
 261      {
 262          defaultDataFilterRules.elements[ i ] = protectReadOnly;
 263          defaultHtmlFilterRules.elements[ i ] = unprotectReadyOnly;
 264      }
 265  
 266      var protectAttributeRegex = /<(?:a|area|img|input)[\s\S]*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi;
 267  
 268      var protectElementsRegex = /(?:<style(?=[ >])[^>]*>[\s\S]*<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi,
 269          encodedElementsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi;
 270  
 271      var protectElementNamesRegex = /(<\/?)((?:object|embed|param|html|body|head|title)[^>]*>)/gi,
 272          unprotectElementNamesRegex = /(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi;
 273  
 274      var protectSelfClosingRegex = /<cke:(param|embed)([^>]*?)\/?>(?!\s*<\/cke:\1)/gi;
 275  
 276  	function protectAttributes( html )
 277      {
 278          return html.replace( protectAttributeRegex, '$& _cke_saved_$1' );
 279      }
 280  
 281  	function protectElements( html )
 282      {
 283          return html.replace( protectElementsRegex, function( match )
 284              {
 285                  return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>';
 286              });
 287      }
 288  
 289  	function unprotectElements( html )
 290      {
 291          return html.replace( encodedElementsRegex, function( match, encoded )
 292              {
 293                  return decodeURIComponent( encoded );
 294              });
 295      }
 296  
 297  	function protectElementsNames( html )
 298      {
 299          return html.replace( protectElementNamesRegex, '$1cke:$2');
 300      }
 301  
 302  	function unprotectElementNames( html )
 303      {
 304          return html.replace( unprotectElementNamesRegex, '$1$2' );
 305      }
 306  
 307  	function protectSelfClosingElements( html )
 308      {
 309          return html.replace( protectSelfClosingRegex, '<cke:$1$2></cke:$1>' );
 310      }
 311  
 312  	function protectRealComments( html )
 313      {
 314          return html.replace( /<!--(?!{cke_protected})[\s\S]+?-->/g, function( match )
 315              {
 316                  return '<!--' + protectedSourceMarker +
 317                          '{C}' +
 318                          encodeURIComponent( match ).replace( /--/g, '%2D%2D' ) +
 319                          '-->';
 320              });
 321      }
 322  
 323  	function unprotectRealComments( html )
 324      {
 325          return html.replace( /<!--\{cke_protected\}\{C\}([\s\S]+?)-->/g, function( match, data )
 326              {
 327                  return decodeURIComponent( data );
 328              });
 329      }
 330  
 331  	function protectSource( data, protectRegexes )
 332      {
 333          var protectedHtml = [],
 334              tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g;
 335  
 336          var regexes =
 337              [
 338                  // Script tags will also be forced to be protected, otherwise

 339                  // IE will execute them.

 340                  ( /<script[\s\S]*?<\/script>/gi ),
 341  
 342                  // <noscript> tags (get lost in IE and messed up in FF).

 343                  /<noscript[\s\S]*?<\/noscript>/gi
 344              ]
 345              .concat( protectRegexes );
 346  
 347          // First of any other protection, we must protect all comments

 348          // to avoid loosing them (of course, IE related).

 349          // Note that we use a different tag for comments, as we need to

 350          // transform them when applying filters.

 351          data = data.replace( (/<!--[\s\S]*?-->/g), function( match )
 352              {
 353                  return  '<!--{cke_tempcomment}' + ( protectedHtml.push( match ) - 1 ) + '-->';
 354              });
 355  
 356          for ( var i = 0 ; i < regexes.length ; i++ )
 357          {
 358              data = data.replace( regexes[i], function( match )
 359                  {
 360                      match = match.replace( tempRegex,         // There could be protected source inside another one. (#3869).
 361                          function( $, isComment, id )
 362                          {
 363                              return protectedHtml[ id ];
 364                          }
 365                      );
 366                      return  '<!--{cke_temp}' + ( protectedHtml.push( match ) - 1 ) + '-->';
 367                  });
 368          }
 369          data = data.replace( tempRegex,    function( $, isComment, id )
 370              {
 371                  return '<!--' + protectedSourceMarker +
 372                          ( isComment ? '{C}' : '' ) +
 373                          encodeURIComponent( protectedHtml[ id ] ).replace( /--/g, '%2D%2D' ) +
 374                          '-->';
 375              }
 376          );
 377          return data;
 378      }
 379  
 380      CKEDITOR.plugins.add( 'htmldataprocessor',
 381      {
 382          requires : [ 'htmlwriter' ],
 383  
 384          init : function( editor )
 385          {
 386              var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor );
 387  
 388              dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
 389  
 390              dataProcessor.dataFilter.addRules( defaultDataFilterRules );
 391              dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules );
 392              dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules );
 393              dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules );
 394          }
 395      });
 396  
 397      CKEDITOR.htmlDataProcessor = function( editor )
 398      {
 399          this.editor = editor;
 400  
 401          this.writer = new CKEDITOR.htmlWriter();
 402          this.dataFilter = new CKEDITOR.htmlParser.filter();
 403          this.htmlFilter = new CKEDITOR.htmlParser.filter();
 404      };
 405  
 406      CKEDITOR.htmlDataProcessor.prototype =
 407      {
 408          toHtml : function( data, fixForBody )
 409          {
 410              // The source data is already HTML, but we need to clean

 411              // it up and apply the filter.

 412  
 413              data = protectSource( data, this.editor.config.protectedSource );
 414  
 415              // Before anything, we must protect the URL attributes as the

 416              // browser may changing them when setting the innerHTML later in

 417              // the code.

 418              data = protectAttributes( data );
 419  
 420              // Protect elements than can't be set inside a DIV. E.g. IE removes

 421              // style tags from innerHTML. (#3710)

 422              data = protectElements( data );
 423  
 424              // Certain elements has problem to go through DOM operation, protect

 425              // them by prefixing 'cke' namespace. (#3591)

 426              data = protectElementsNames( data );
 427  
 428              // All none-IE browsers ignore self-closed custom elements,

 429              // protecting them into open-close. (#3591)

 430              data = protectSelfClosingElements( data );
 431  
 432              // Call the browser to help us fixing a possibly invalid HTML

 433              // structure.

 434              var div = new CKEDITOR.dom.element( 'div' );
 435              // Add fake character to workaround IE comments bug. (#3801)

 436              div.setHtml( 'a' + data );
 437              data = div.getHtml().substr( 1 );
 438  
 439              // Unprotect "some" of the protected elements at this point.

 440              data = unprotectElementNames( data );
 441  
 442              data = unprotectElements( data );
 443  
 444              // Restore the comments that have been protected, in this way they

 445              // can be properly filtered.

 446              data = unprotectRealComments( data );
 447  
 448              // Now use our parser to make further fixes to the structure, as

 449              // well as apply the filter.

 450              var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ),
 451                  writer = new CKEDITOR.htmlParser.basicWriter();
 452  
 453              fragment.writeHtml( writer, this.dataFilter );
 454              data = writer.getHtml( true );
 455  
 456              // Protect the real comments again.

 457              data = protectRealComments( data );
 458  
 459              return data;
 460          },
 461  
 462          toDataFormat : function( html, fixForBody )
 463          {
 464              var writer = this.writer,
 465                  fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody );
 466  
 467              writer.reset();
 468  
 469              fragment.writeHtml( writer, this.htmlFilter );
 470  
 471              return writer.getHtml( true );
 472          }
 473      };
 474  })();
 475  
 476  /**

 477   * Whether to force using "&" instead of "&amp;amp;" in elements attributes

 478   * values. It's not recommended to change this setting for compliance with the

 479   * W3C XHTML 1.0 standards

 480   * (<a href="http://www.w3.org/TR/xhtml1/#C_12">C.12, XHTML 1.0</a>).

 481   * @type Boolean

 482   * @default false

 483   * @example

 484   * config.forceSimpleAmpersand = false;

 485   */
 486  CKEDITOR.config.forceSimpleAmpersand = false;


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7