[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/styles/ -> 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  CKEDITOR.plugins.add( 'styles',
   7  {
   8      requires : [ 'selection' ]
   9  });
  10  
  11  /**

  12   * Registers a function to be called whenever a style changes its state in the

  13   * editing area. The current state is passed to the function. The possible

  14   * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}.

  15   * @param {CKEDITOR.style} The style to be watched.

  16   * @param {Function} The function to be called when the style state changes.

  17   * @example

  18   * // Create a style object for the <b> element.

  19   * var style = new CKEDITOR.style( { element : 'b' } );

  20   * var editor = CKEDITOR.instances.editor1;

  21   * editor.attachStyleStateChange( style, function( state )

  22   *     {

  23   *         if ( state == CKEDITOR.TRISTATE_ON )

  24   *             alert( 'The current state for the B element is ON' );

  25   *         else

  26   *             alert( 'The current state for the B element is OFF' );

  27   *     });

  28   */
  29  CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback )
  30  {
  31      // Try to get the list of attached callbacks.

  32      var styleStateChangeCallbacks = this._.styleStateChangeCallbacks;
  33  
  34      // If it doesn't exist, it means this is the first call. So, let's create

  35      // all the structure to manage the style checks and the callback calls.

  36      if ( !styleStateChangeCallbacks )
  37      {
  38          // Create the callbacks array.

  39          styleStateChangeCallbacks = this._.styleStateChangeCallbacks = [];
  40  
  41          // Attach to the selectionChange event, so we can check the styles at

  42          // that point.

  43          this.on( 'selectionChange', function( ev )
  44              {
  45                  // Loop throw all registered callbacks.

  46                  for ( var i = 0 ; i < styleStateChangeCallbacks.length ; i++ )
  47                  {
  48                      var callback = styleStateChangeCallbacks[ i ];
  49  
  50                      // Check the current state for the style defined for that

  51                      // callback.

  52                      var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF;
  53  
  54                      // If the state changed since the last check.

  55                      if ( callback.state !== currentState )
  56                      {
  57                          // Call the callback function, passing the current

  58                          // state to it.

  59                          callback.fn.call( this, currentState );
  60  
  61                          // Save the current state, so it can be compared next

  62                          // time.

  63                          callback.state = currentState;
  64                      }
  65                  }
  66              });
  67      }
  68  
  69      // Save the callback info, so it can be checked on the next occurrence of

  70      // selectionChange.

  71      styleStateChangeCallbacks.push( { style : style, fn : callback } );
  72  };
  73  
  74  CKEDITOR.STYLE_BLOCK = 1;
  75  CKEDITOR.STYLE_INLINE = 2;
  76  CKEDITOR.STYLE_OBJECT = 3;
  77  
  78  (function()
  79  {
  80      var blockElements    = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 };
  81      var objectElements    = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1};
  82  
  83      var semicolonFixRegex = /\s*(?:;\s*|$)/;
  84  
  85      CKEDITOR.style = function( styleDefinition, variablesValues )
  86      {
  87          if ( variablesValues )
  88          {
  89              styleDefinition = CKEDITOR.tools.clone( styleDefinition );
  90  
  91              replaceVariables( styleDefinition.attributes, variablesValues );
  92              replaceVariables( styleDefinition.styles, variablesValues );
  93          }
  94  
  95          var element = this.element = ( styleDefinition.element || '*' ).toLowerCase();
  96  
  97          this.type =
  98              ( element == '#' || blockElements[ element ] ) ?
  99                  CKEDITOR.STYLE_BLOCK
 100              : objectElements[ element ] ?
 101                  CKEDITOR.STYLE_OBJECT
 102              :
 103                  CKEDITOR.STYLE_INLINE;
 104  
 105          this._ =
 106          {
 107              definition : styleDefinition
 108          };
 109      };
 110  
 111      CKEDITOR.style.prototype =
 112      {
 113          apply : function( document )
 114          {
 115              applyStyle.call( this, document, false );
 116          },
 117  
 118          remove : function( document )
 119          {
 120              applyStyle.call( this, document, true );
 121          },
 122  
 123          applyToRange : function( range )
 124          {
 125              return ( this.applyToRange =
 126                          this.type == CKEDITOR.STYLE_INLINE ?
 127                              applyInlineStyle
 128                          : this.type == CKEDITOR.STYLE_BLOCK ?
 129                              applyBlockStyle
 130                          : this.type == CKEDITOR.STYLE_OBJECT ?
 131                              applyObjectStyle
 132                          : null ).call( this, range );
 133          },
 134  
 135          removeFromRange : function( range )
 136          {
 137              return ( this.removeFromRange =
 138                          this.type == CKEDITOR.STYLE_INLINE ?
 139                              removeInlineStyle
 140                          : null ).call( this, range );
 141          },
 142  
 143          applyToObject : function( element )
 144          {
 145              setupElement( element, this );
 146          },
 147  
 148          /**

 149           * Get the style state inside an element path. Returns "true" if the

 150           * element is active in the path.

 151           */
 152          checkActive : function( elementPath )
 153          {
 154              switch ( this.type )
 155              {
 156                  case CKEDITOR.STYLE_BLOCK :
 157                      return this.checkElementRemovable( elementPath.block || elementPath.blockLimit, true );
 158  
 159                  case CKEDITOR.STYLE_OBJECT :
 160                  case CKEDITOR.STYLE_INLINE :
 161  
 162                      var elements = elementPath.elements;
 163  
 164                      for ( var i = 0, element ; i < elements.length ; i++ )
 165                      {
 166                          element = elements[ i ];
 167  
 168                          if ( this.type == CKEDITOR.STYLE_INLINE
 169                                && ( element == elementPath.block || element == elementPath.blockLimit ) )
 170                              continue;
 171  
 172                          if( this.type == CKEDITOR.STYLE_OBJECT
 173                               && !( element.getName() in objectElements ) )
 174                                  continue;
 175  
 176                          if ( this.checkElementRemovable( element, true ) )
 177                              return true;
 178                      }
 179              }
 180              return false;
 181          },
 182  
 183          /**

 184           * Whether this style can be applied at the element path.

 185            * @param elementPath

 186           */
 187          checkApplicable : function( elementPath )
 188          {
 189              switch ( this.type )
 190              {
 191                  case CKEDITOR.STYLE_INLINE :
 192                  case CKEDITOR.STYLE_BLOCK :
 193                      break;
 194  
 195                  case CKEDITOR.STYLE_OBJECT :
 196                      return elementPath.lastElement.getAscendant( this.element, true );
 197              }
 198  
 199              return true;
 200          },
 201  
 202          // Checks if an element, or any of its attributes, is removable by the

 203          // current style definition.

 204          checkElementRemovable : function( element, fullMatch )
 205          {
 206              if ( !element )
 207                  return false;
 208  
 209              var def = this._.definition,
 210                  attribs;
 211  
 212              // If the element name is the same as the style name.

 213              if ( element.getName() == this.element )
 214              {
 215                  // If no attributes are defined in the element.

 216                  if ( !fullMatch && !element.hasAttributes() )
 217                      return true;
 218  
 219                  attribs = getAttributesForComparison( def );
 220  
 221                  if ( attribs._length )
 222                  {
 223                      for ( var attName in attribs )
 224                      {
 225                          if ( attName == '_length' )
 226                              continue;
 227  
 228                          var elementAttr = element.getAttribute( attName ) || '';
 229  
 230                          // Special treatment for 'style' attribute is required.

 231                          if ( attName == 'style' ?
 232                              compareCssText( attribs[ attName ], normalizeCssText( elementAttr, false ) )
 233                              : attribs[ attName ] == elementAttr  )
 234                          {
 235                              if ( !fullMatch )
 236                                  return true;
 237                          }
 238                          else if ( fullMatch )
 239                                  return false;
 240                      }
 241                      if ( fullMatch )
 242                          return true;
 243                  }
 244                  else
 245                      return true;
 246              }
 247  
 248              // Check if the element can be somehow overriden.

 249              var override = getOverrides( this )[ element.getName() ] ;
 250              if ( override )
 251              {
 252                  // If no attributes have been defined, remove the element.

 253                  if ( !( attribs = override.attributes ) )
 254                      return true;
 255  
 256                  for ( var i = 0 ; i < attribs.length ; i++ )
 257                  {
 258                      attName = attribs[i][0];
 259                      var actualAttrValue = element.getAttribute( attName );
 260                      if ( actualAttrValue )
 261                      {
 262                          var attValue = attribs[i][1];
 263  
 264                          // Remove the attribute if:

 265                          //    - The override definition value is null;

 266                          //    - The override definition value is a string that

 267                          //      matches the attribute value exactly.

 268                          //    - The override definition value is a regex that

 269                          //      has matches in the attribute value.

 270                          if ( attValue === null ||
 271                                  ( typeof attValue == 'string' && actualAttrValue == attValue ) ||
 272                                  attValue.test( actualAttrValue ) )
 273                              return true;
 274                      }
 275                  }
 276              }
 277              return false;
 278          },
 279  
 280          // Builds the preview HTML based on the styles definition.

 281          buildPreview : function()
 282          {
 283              var styleDefinition = this._.definition,
 284                  html = [],
 285                  elementName = styleDefinition.element;
 286  
 287              // Avoid <bdo> in the preview.

 288              if ( elementName == 'bdo' )
 289                  elementName = 'span';
 290  
 291              html = [ '<', elementName ];
 292  
 293              // Assign all defined attributes.

 294              var attribs    = styleDefinition.attributes;
 295              if ( attribs )
 296              {
 297                  for ( var att in attribs )
 298                  {
 299                      html.push( ' ', att, '="', attribs[ att ], '"' );
 300                  }
 301              }
 302  
 303              // Assign the style attribute.

 304              var cssStyle = CKEDITOR.style.getStyleText( styleDefinition );
 305              if ( cssStyle )
 306                  html.push( ' style="', cssStyle, '"' );
 307  
 308              html.push( '>', styleDefinition.name, '</', elementName, '>' );
 309  
 310              return html.join( '' );
 311          }
 312      };
 313  
 314      // Build the cssText based on the styles definition.

 315      CKEDITOR.style.getStyleText = function( styleDefinition )
 316      {
 317          // If we have already computed it, just return it.

 318          var stylesDef = styleDefinition._ST;
 319          if ( stylesDef )
 320              return stylesDef;
 321  
 322          stylesDef = styleDefinition.styles;
 323  
 324          // Builds the StyleText.

 325          var stylesText = ( styleDefinition.attributes && styleDefinition.attributes[ 'style' ] ) || '',
 326                  specialStylesText = '';
 327  
 328          if ( stylesText.length )
 329              stylesText = stylesText.replace( semicolonFixRegex, ';' );
 330  
 331          for ( var style in stylesDef )
 332          {
 333              var styleVal = stylesDef[ style ],
 334                      text = ( style + ':' + styleVal ).replace( semicolonFixRegex, ';' );
 335  
 336              // Some browsers don't support 'inherit' property value, leave them intact. (#5242)

 337              if ( styleVal == 'inherit' )
 338                  specialStylesText += text;
 339              else
 340                  stylesText += text;
 341          }
 342  
 343          // Browsers make some changes to the style when applying them. So, here

 344          // we normalize it to the browser format.

 345          if ( stylesText.length )
 346              stylesText = normalizeCssText( stylesText );
 347  
 348          stylesText += specialStylesText;
 349  
 350          // Return it, saving it to the next request.

 351          return ( styleDefinition._ST = stylesText );
 352      };
 353  
 354  	function applyInlineStyle( range )
 355      {
 356          var document = range.document;
 357  
 358          if ( range.collapsed )
 359          {
 360              // Create the element to be inserted in the DOM.

 361              var collapsedElement = getElement( this, document );
 362  
 363              // Insert the empty element into the DOM at the range position.

 364              range.insertNode( collapsedElement );
 365  
 366              // Place the selection right inside the empty element.

 367              range.moveToPosition( collapsedElement, CKEDITOR.POSITION_BEFORE_END );
 368  
 369              return;
 370          }
 371  
 372          var elementName = this.element;
 373          var def = this._.definition;
 374          var isUnknownElement;
 375  
 376          // Get the DTD definition for the element. Defaults to "span".

 377          var dtd = CKEDITOR.dtd[ elementName ] || ( isUnknownElement = true, CKEDITOR.dtd.span );
 378  
 379          // Expand the range.

 380          range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
 381          range.trim();
 382  
 383          // Get the first node to be processed and the last, which concludes the

 384          // processing.

 385          var boundaryNodes = range.createBookmark(),
 386              firstNode = boundaryNodes.startNode,
 387              lastNode = boundaryNodes.endNode;
 388  
 389          var currentNode = firstNode;
 390  
 391          var styleRange;
 392  
 393          while ( currentNode )
 394          {
 395              var applyStyle = false;
 396  
 397              if ( currentNode.equals( lastNode ) )
 398              {
 399                  currentNode = null;
 400                  applyStyle = true;
 401              }
 402              else
 403              {
 404                  var nodeType = currentNode.type;
 405                  var nodeName = nodeType == CKEDITOR.NODE_ELEMENT ? currentNode.getName() : null;
 406  
 407                  if ( nodeName && currentNode.getAttribute( '_fck_bookmark' ) )
 408                  {
 409                      currentNode = currentNode.getNextSourceNode( true );
 410                      continue;
 411                  }
 412  
 413                  // Check if the current node can be a child of the style element.

 414                  if ( !nodeName || ( dtd[ nodeName ]
 415                      && ( currentNode.getPosition( lastNode ) | CKEDITOR.POSITION_PRECEDING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED )
 416                      && ( !def.childRule || def.childRule( currentNode ) ) ) )
 417                  {
 418                      var currentParent = currentNode.getParent();
 419  
 420                      // Check if the style element can be a child of the current

 421                      // node parent or if the element is not defined in the DTD.

 422                      if ( currentParent
 423                          && ( ( currentParent.getDtd() || CKEDITOR.dtd.span )[ elementName ] || isUnknownElement )
 424                          && ( !def.parentRule || def.parentRule( currentParent ) ) )
 425                      {
 426                          // This node will be part of our range, so if it has not

 427                          // been started, place its start right before the node.

 428                          // In the case of an element node, it will be included

 429                          // only if it is entirely inside the range.

 430                          if ( !styleRange && ( !nodeName || !CKEDITOR.dtd.$removeEmpty[ nodeName ] || ( currentNode.getPosition( lastNode ) | CKEDITOR.POSITION_PRECEDING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_PRECEDING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) ) )
 431                          {
 432                              styleRange = new CKEDITOR.dom.range( document );
 433                              styleRange.setStartBefore( currentNode );
 434                          }
 435  
 436                          // Non element nodes, or empty elements can be added

 437                          // completely to the range.

 438                          if ( nodeType == CKEDITOR.NODE_TEXT || ( nodeType == CKEDITOR.NODE_ELEMENT && !currentNode.getChildCount() ) )
 439                          {
 440                              var includedNode = currentNode;
 441                              var parentNode;
 442  
 443                              // This node is about to be included completelly, but,

 444                              // if this is the last node in its parent, we must also

 445                              // check if the parent itself can be added completelly

 446                              // to the range.

 447                              while ( !includedNode.$.nextSibling
 448                                  && ( parentNode = includedNode.getParent(), dtd[ parentNode.getName() ] )
 449                                  && ( parentNode.getPosition( firstNode ) | CKEDITOR.POSITION_FOLLOWING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_FOLLOWING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED )
 450                                  && ( !def.childRule || def.childRule( parentNode ) ) )
 451                              {
 452                                  includedNode = parentNode;
 453                              }
 454  
 455                              styleRange.setEndAfter( includedNode );
 456  
 457                              // If the included node still is the last node in its

 458                              // parent, it means that the parent can't be included

 459                              // in this style DTD, so apply the style immediately.

 460                              if ( !includedNode.$.nextSibling )
 461                                  applyStyle = true;
 462  
 463                          }
 464                      }
 465                      else
 466                          applyStyle = true;
 467                  }
 468                  else
 469                      applyStyle = true;
 470  
 471                  // Get the next node to be processed.

 472                  currentNode = currentNode.getNextSourceNode();
 473              }
 474  
 475              // Apply the style if we have something to which apply it.

 476              if ( applyStyle && styleRange && !styleRange.collapsed )
 477              {
 478                  // Build the style element, based on the style object definition.

 479                  var styleNode = getElement( this, document );
 480  
 481                  // Get the element that holds the entire range.

 482                  var parent = styleRange.getCommonAncestor();
 483  
 484                  // Loop through the parents, removing the redundant attributes

 485                  // from the element to be applied.

 486                  while ( styleNode && parent )
 487                  {
 488                      if ( parent.getName() == elementName )
 489                      {
 490                          for ( var attName in def.attributes )
 491                          {
 492                              if ( styleNode.getAttribute( attName ) == parent.getAttribute( attName ) )
 493                                  styleNode.removeAttribute( attName );
 494                          }
 495  
 496                          for ( var styleName in def.styles )
 497                          {
 498                              if ( styleNode.getStyle( styleName ) == parent.getStyle( styleName ) )
 499                                  styleNode.removeStyle( styleName );
 500                          }
 501  
 502                          if ( !styleNode.hasAttributes() )
 503                          {
 504                              styleNode = null;
 505                              break;
 506                          }
 507                      }
 508  
 509                      parent = parent.getParent();
 510                  }
 511  
 512                  if ( styleNode )
 513                  {
 514                      // Move the contents of the range to the style element.

 515                      styleRange.extractContents().appendTo( styleNode );
 516  
 517                      // Here we do some cleanup, removing all duplicated

 518                      // elements from the style element.

 519                      removeFromInsideElement( this, styleNode );
 520  
 521                      // Insert it into the range position (it is collapsed after

 522                      // extractContents.

 523                      styleRange.insertNode( styleNode );
 524  
 525                      // Let's merge our new style with its neighbors, if possible.

 526                      styleNode.mergeSiblings();
 527  
 528                      // As the style system breaks text nodes constantly, let's normalize

 529                      // things for performance.

 530                      // With IE, some paragraphs get broken when calling normalize()

 531                      // repeatedly. Also, for IE, we must normalize body, not documentElement.

 532                      // IE is also known for having a "crash effect" with normalize().

 533                      // We should try to normalize with IE too in some way, somewhere.

 534                      if ( !CKEDITOR.env.ie )
 535                          styleNode.$.normalize();
 536                  }
 537  
 538                  // Style applied, let's release the range, so it gets

 539                  // re-initialization in the next loop.

 540                  styleRange = null;
 541              }
 542          }
 543  
 544          // Remove the bookmark nodes.

 545          range.moveToBookmark( boundaryNodes );
 546  
 547          // Minimize the result range to exclude empty text nodes. (#5374)

 548          range.shrink( CKEDITOR.SHRINK_TEXT );
 549      }
 550  
 551  	function removeInlineStyle( range )
 552      {
 553          /*

 554           * Make sure our range has included all "collpased" parent inline nodes so

 555           * that our operation logic can be simpler.

 556           */
 557          range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
 558  
 559          var bookmark = range.createBookmark(),
 560              startNode = bookmark.startNode;
 561  
 562          if ( range.collapsed )
 563          {
 564  
 565              var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ),
 566                  // The topmost element in elementspatch which we should jump out of.

 567                  boundaryElement;
 568  
 569  
 570              for ( var i = 0, element ; i < startPath.elements.length
 571                      && ( element = startPath.elements[i] ) ; i++ )
 572              {
 573                  /*

 574                   * 1. If it's collaped inside text nodes, try to remove the style from the whole element.

 575                   *

 576                   * 2. Otherwise if it's collapsed on element boundaries, moving the selection

 577                   *  outside the styles instead of removing the whole tag,

 578                   *  also make sure other inner styles were well preserverd.(#3309)

 579                   */
 580                  if ( element == startPath.block || element == startPath.blockLimit )
 581                      break;
 582  
 583                  if ( this.checkElementRemovable( element ) )
 584                  {
 585                      var isStart;
 586  
 587                      if ( range.collapsed && (
 588                           range.checkBoundaryOfElement( element, CKEDITOR.END ) ||
 589                           ( isStart = range.checkBoundaryOfElement( element, CKEDITOR.START ) ) ) )
 590                      {
 591                          boundaryElement = element;
 592                          boundaryElement.match = isStart ? 'start' : 'end';
 593                      }
 594                      else
 595                      {
 596                          /*

 597                           * Before removing the style node, there may be a sibling to the style node

 598                           * that's exactly the same to the one to be removed. To the user, it makes

 599                           * no difference that they're separate entities in the DOM tree. So, merge

 600                           * them before removal.

 601                           */
 602                          element.mergeSiblings();
 603                          removeFromElement( this, element );
 604  
 605                      }
 606                  }
 607              }
 608  
 609              // Re-create the style tree after/before the boundary element,

 610              // the replication start from bookmark start node to define the

 611              // new range.

 612              if ( boundaryElement )
 613              {
 614                  var clonedElement = startNode;
 615                  for ( i = 0 ;; i++ )
 616                  {
 617                      var newElement = startPath.elements[ i ];
 618                      if ( newElement.equals( boundaryElement ) )
 619                          break;
 620                      // Avoid copying any matched element.

 621                      else if ( newElement.match )
 622                          continue;
 623                      else
 624                          newElement = newElement.clone();
 625                      newElement.append( clonedElement );
 626                      clonedElement = newElement;
 627                  }
 628                  clonedElement[ boundaryElement.match == 'start' ?
 629                              'insertBefore' : 'insertAfter' ]( boundaryElement );
 630              }
 631          }
 632          else
 633          {
 634              /*

 635               * Now our range isn't collapsed. Lets walk from the start node to the end

 636               * node via DFS and remove the styles one-by-one.

 637               */
 638              var endNode = bookmark.endNode,
 639                  me = this;
 640  
 641              /*

 642               * Find out the style ancestor that needs to be broken down at startNode

 643               * and endNode.

 644               */
 645  			function breakNodes()
 646              {
 647                  var startPath = new CKEDITOR.dom.elementPath( startNode.getParent() ),
 648                      endPath = new CKEDITOR.dom.elementPath( endNode.getParent() ),
 649                      breakStart = null,
 650                      breakEnd = null;
 651                  for ( var i = 0 ; i < startPath.elements.length ; i++ )
 652                  {
 653                      var element = startPath.elements[ i ];
 654  
 655                      if ( element == startPath.block || element == startPath.blockLimit )
 656                          break;
 657  
 658                      if ( me.checkElementRemovable( element ) )
 659                          breakStart = element;
 660                  }
 661                  for ( i = 0 ; i < endPath.elements.length ; i++ )
 662                  {
 663                      element = endPath.elements[ i ];
 664  
 665                      if ( element == endPath.block || element == endPath.blockLimit )
 666                          break;
 667  
 668                      if ( me.checkElementRemovable( element ) )
 669                          breakEnd = element;
 670                  }
 671  
 672                  if ( breakEnd )
 673                      endNode.breakParent( breakEnd );
 674                  if ( breakStart )
 675                      startNode.breakParent( breakStart );
 676              }
 677              breakNodes();
 678  
 679              // Now, do the DFS walk.

 680              var currentNode = startNode.getNext();
 681              while ( !currentNode.equals( endNode ) )
 682              {
 683                  /*

 684                   * Need to get the next node first because removeFromElement() can remove

 685                   * the current node from DOM tree.

 686                   */
 687                  var nextNode = currentNode.getNextSourceNode();
 688                  if ( currentNode.type == CKEDITOR.NODE_ELEMENT && this.checkElementRemovable( currentNode ) )
 689                  {
 690                      // Remove style from element or overriding element.

 691                      if ( currentNode.getName() == this.element )
 692                          removeFromElement( this, currentNode );
 693                      else
 694                          removeOverrides( currentNode, getOverrides( this )[ currentNode.getName() ] );
 695  
 696                      /*

 697                       * removeFromElement() may have merged the next node with something before

 698                       * the startNode via mergeSiblings(). In that case, the nextNode would

 699                       * contain startNode and we'll have to call breakNodes() again and also

 700                       * reassign the nextNode to something after startNode.

 701                       */
 702                      if ( nextNode.type == CKEDITOR.NODE_ELEMENT && nextNode.contains( startNode ) )
 703                      {
 704                          breakNodes();
 705                          nextNode = startNode.getNext();
 706                      }
 707                  }
 708                  currentNode = nextNode;
 709              }
 710          }
 711  
 712          range.moveToBookmark( bookmark );
 713  }
 714  
 715  	function applyObjectStyle( range )
 716      {
 717          var root = range.getCommonAncestor( true, true ),
 718                  element = root.getAscendant( this.element, true );
 719          element && setupElement( element, this );
 720      }
 721  
 722  	function applyBlockStyle( range )
 723      {
 724          // Serializible bookmarks is needed here since

 725          // elements may be merged.

 726          var bookmark = range.createBookmark( true );
 727  
 728          var iterator = range.createIterator();
 729          iterator.enforceRealBlocks = true;
 730  
 731          // make recognize <br /> tag as a separator in ENTER_BR mode (#5121)

 732          if ( this._.enterMode )
 733              iterator.enlargeBr = ( this._.enterMode != CKEDITOR.ENTER_BR );
 734  
 735          var block;
 736          var doc = range.document;
 737          var previousPreBlock;
 738  
 739          while ( ( block = iterator.getNextParagraph() ) )        // Only one =
 740          {
 741              var newBlock = getElement( this, doc );
 742              replaceBlock( block, newBlock );
 743          }
 744  
 745          range.moveToBookmark( bookmark );
 746      }
 747  
 748      // Replace the original block with new one, with special treatment

 749      // for <pre> blocks to make sure content format is well preserved, and merging/splitting adjacent

 750      // when necessary.(#3188)

 751  	function replaceBlock( block, newBlock )
 752      {
 753          var newBlockIsPre    = newBlock.is( 'pre' );
 754          var blockIsPre        = block.is( 'pre' );
 755  
 756          var isToPre    = newBlockIsPre && !blockIsPre;
 757          var isFromPre    = !newBlockIsPre && blockIsPre;
 758  
 759          if ( isToPre )
 760              newBlock = toPre( block, newBlock );
 761          else if ( isFromPre )
 762              // Split big <pre> into pieces before start to convert.

 763              newBlock = fromPres( splitIntoPres( block ), newBlock );
 764          else
 765              block.moveChildren( newBlock );
 766  
 767          newBlock.replace( block );
 768  
 769          if ( newBlockIsPre )
 770          {
 771              // Merge previous <pre> blocks.

 772              mergePre( newBlock );
 773          }
 774      }
 775  
 776      var nonWhitespaces = CKEDITOR.dom.walker.whitespaces( true );
 777      /**

 778       * Merge a <pre> block with a previous sibling if available.

 779       */
 780  	function mergePre( preBlock )
 781      {
 782          var previousBlock;
 783          if ( !( ( previousBlock = preBlock.getPrevious( nonWhitespaces ) )
 784                   && previousBlock.is
 785                   && previousBlock.is( 'pre') ) )
 786              return;
 787  
 788          // Merge the previous <pre> block contents into the current <pre>

 789          // block.

 790          //

 791          // Another thing to be careful here is that currentBlock might contain

 792          // a '\n' at the beginning, and previousBlock might contain a '\n'

 793          // towards the end. These new lines are not normally displayed but they

 794          // become visible after merging.

 795          var mergedHtml = replace( previousBlock.getHtml(), /\n$/, '' ) + '\n\n' +
 796                  replace( preBlock.getHtml(), /^\n/, '' ) ;
 797  
 798          // Krugle: IE normalizes innerHTML from <pre>, breaking whitespaces.

 799          if ( CKEDITOR.env.ie )
 800              preBlock.$.outerHTML = '<pre>' + mergedHtml + '</pre>';
 801          else
 802              preBlock.setHtml( mergedHtml );
 803  
 804          previousBlock.remove();
 805      }
 806  
 807      /**

 808       * Split into multiple <pre> blocks separated by double line-break.

 809       * @param preBlock

 810       */
 811  	function splitIntoPres( preBlock )
 812      {
 813          // Exclude the ones at header OR at tail,

 814          // and ignore bookmark content between them.

 815          var duoBrRegex = /(\S\s*)\n(?:\s|(<span[^>]+_fck_bookmark.*?\/span>))*\n(?!$)/gi,
 816              blockName = preBlock.getName(),
 817              splitedHtml = replace( preBlock.getOuterHtml(),
 818                  duoBrRegex,
 819                  function( match, charBefore, bookmark )
 820                  {
 821                    return charBefore + '</pre>' + bookmark + '<pre>';
 822                  } );
 823  
 824          var pres = [];
 825          splitedHtml.replace( /<pre\b.*?>([\s\S]*?)<\/pre>/gi, function( match, preContent ){
 826              pres.push( preContent );
 827          } );
 828          return pres;
 829      }
 830  
 831      // Wrapper function of String::replace without considering of head/tail bookmarks nodes.

 832  	function replace( str, regexp, replacement )
 833      {
 834          var headBookmark = '',
 835              tailBookmark = '';
 836  
 837          str = str.replace( /(^<span[^>]+_fck_bookmark.*?\/span>)|(<span[^>]+_fck_bookmark.*?\/span>$)/gi,
 838              function( str, m1, m2 ){
 839                      m1 && ( headBookmark = m1 );
 840                      m2 && ( tailBookmark = m2 );
 841                  return '';
 842              } );
 843          return headBookmark + str.replace( regexp, replacement ) + tailBookmark;
 844      }
 845      /**

 846       * Converting a list of <pre> into blocks with format well preserved.

 847       */
 848  	function fromPres( preHtmls, newBlock )
 849      {
 850          var docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() );
 851          for ( var i = 0 ; i < preHtmls.length ; i++ )
 852          {
 853              var blockHtml = preHtmls[ i ];
 854  
 855              // 1. Trim the first and last line-breaks immediately after and before <pre>,

 856              // they're not visible.

 857               blockHtml =  blockHtml.replace( /(\r\n|\r)/g, '\n' ) ;
 858               blockHtml = replace(  blockHtml, /^[ \t]*\n/, '' ) ;
 859               blockHtml = replace(  blockHtml, /\n$/, '' ) ;
 860              // 2. Convert spaces or tabs at the beginning or at the end to &nbsp;

 861               blockHtml = replace(  blockHtml, /^[ \t]+|[ \t]+$/g, function( match, offset, s )
 862                      {
 863                          if ( match.length == 1 )    // one space, preserve it
 864                              return '&nbsp;' ;
 865                          else if ( !offset )        // beginning of block
 866                              return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ';
 867                          else                // end of block
 868                              return ' ' + CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 );
 869                      } ) ;
 870  
 871              // 3. Convert \n to <BR>.

 872              // 4. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;

 873               blockHtml =  blockHtml.replace( /\n/g, '<br>' ) ;
 874               blockHtml =  blockHtml.replace( /[ \t]{2,}/g,
 875                      function ( match )
 876                      {
 877                          return CKEDITOR.tools.repeat( '&nbsp;', match.length - 1 ) + ' ' ;
 878                      } ) ;
 879  
 880              var newBlockClone = newBlock.clone();
 881              newBlockClone.setHtml(  blockHtml );
 882              docFrag.append( newBlockClone );
 883          }
 884          return docFrag;
 885      }
 886  
 887      /**

 888       * Converting from a non-PRE block to a PRE block in formatting operations.

 889       */
 890  	function toPre( block, newBlock )
 891      {
 892          // First trim the block content.

 893          var preHtml = block.getHtml();
 894  
 895          // 1. Trim head/tail spaces, they're not visible.

 896          preHtml = replace( preHtml, /(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '' );
 897          // 2. Delete ANSI whitespaces immediately before and after <BR> because

 898          //    they are not visible.

 899          preHtml = preHtml.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '$1' );
 900          // 3. Compress other ANSI whitespaces since they're only visible as one

 901          //    single space previously.

 902          // 4. Convert &nbsp; to spaces since &nbsp; is no longer needed in <PRE>.

 903          preHtml = preHtml.replace( /([ \t\n\r]+|&nbsp;)/g, ' ' );
 904          // 5. Convert any <BR /> to \n. This must not be done earlier because

 905          //    the \n would then get compressed.

 906          preHtml = preHtml.replace( /<br\b[^>]*>/gi, '\n' );
 907  
 908          // Krugle: IE normalizes innerHTML to <pre>, breaking whitespaces.

 909          if ( CKEDITOR.env.ie )
 910          {
 911              var temp = block.getDocument().createElement( 'div' );
 912              temp.append( newBlock );
 913              newBlock.$.outerHTML =  '<pre>' + preHtml + '</pre>';
 914              newBlock = temp.getFirst().remove();
 915          }
 916          else
 917              newBlock.setHtml( preHtml );
 918  
 919          return newBlock;
 920      }
 921  
 922      // Removes a style from an element itself, don't care about its subtree.

 923  	function removeFromElement( style, element )
 924      {
 925          var def = style._.definition,
 926              attributes = CKEDITOR.tools.extend( {}, def.attributes, getOverrides( style )[ element.getName() ] ),
 927              styles = def.styles,
 928              // If the style is only about the element itself, we have to remove the element.

 929              removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );
 930  
 931          // Remove definition attributes/style from the elemnt.

 932          for ( var attName in attributes )
 933          {
 934              // The 'class' element value must match (#1318).

 935              if ( ( attName == 'class' || style._.definition.fullMatch )
 936                  && element.getAttribute( attName ) != normalizeProperty( attName, attributes[ attName ] ) )
 937                  continue;
 938              removeEmpty = element.hasAttribute( attName );
 939              element.removeAttribute( attName );
 940          }
 941  
 942          for ( var styleName in styles )
 943          {
 944              // Full match style insist on having fully equivalence. (#5018)

 945              if ( style._.definition.fullMatch
 946                  && element.getStyle( styleName ) != normalizeProperty( styleName, styles[ styleName ], true ) )
 947                  continue;
 948  
 949              removeEmpty = removeEmpty || !!element.getStyle( styleName );
 950              element.removeStyle( styleName );
 951          }
 952  
 953          removeEmpty && removeNoAttribsElement( element );
 954      }
 955  
 956      // Removes a style from inside an element.

 957  	function removeFromInsideElement( style, element )
 958      {
 959          var def = style._.definition,
 960              attribs = def.attributes,
 961              styles = def.styles,
 962              overrides = getOverrides( style );
 963  
 964          var innerElements = element.getElementsByTag( style.element );
 965  
 966          for ( var i = innerElements.count(); --i >= 0 ; )
 967              removeFromElement( style,  innerElements.getItem( i ) );
 968  
 969          // Now remove any other element with different name that is

 970          // defined to be overriden.

 971          for ( var overrideElement in overrides )
 972          {
 973              if ( overrideElement != style.element )
 974              {
 975                  innerElements = element.getElementsByTag( overrideElement ) ;
 976                  for ( i = innerElements.count() - 1 ; i >= 0 ; i-- )
 977                  {
 978                      var innerElement = innerElements.getItem( i );
 979                      removeOverrides( innerElement, overrides[ overrideElement ] ) ;
 980                  }
 981              }
 982          }
 983  
 984      }
 985  
 986      /**

 987       *  Remove overriding styles/attributes from the specific element.

 988       *  Note: Remove the element if no attributes remain.

 989       * @param {Object} element

 990       * @param {Object} overrides

 991       */
 992  	function removeOverrides( element, overrides )
 993      {
 994          var attributes = overrides && overrides.attributes ;
 995  
 996          if ( attributes )
 997          {
 998              for ( var i = 0 ; i < attributes.length ; i++ )
 999              {
1000                  var attName = attributes[i][0], actualAttrValue ;
1001  
1002                  if ( ( actualAttrValue = element.getAttribute( attName ) ) )
1003                  {
1004                      var attValue = attributes[i][1] ;
1005  
1006                      // Remove the attribute if:

1007                      //    - The override definition value is null ;

1008                      //    - The override definition valie is a string that

1009                      //      matches the attribute value exactly.

1010                      //    - The override definition value is a regex that

1011                      //      has matches in the attribute value.

1012                      if ( attValue === null ||
1013                              ( attValue.test && attValue.test( actualAttrValue ) ) ||
1014                              ( typeof attValue == 'string' && actualAttrValue == attValue ) )
1015                          element.removeAttribute( attName ) ;
1016                  }
1017              }
1018          }
1019  
1020          removeNoAttribsElement( element );
1021      }
1022  
1023      // If the element has no more attributes, remove it.

1024  	function removeNoAttribsElement( element )
1025      {
1026          // If no more attributes remained in the element, remove it,

1027          // leaving its children.

1028          if ( !element.hasAttributes() )
1029          {
1030              // Removing elements may open points where merging is possible,

1031              // so let's cache the first and last nodes for later checking.

1032              var firstChild    = element.getFirst();
1033              var lastChild    = element.getLast();
1034  
1035              element.remove( true );
1036  
1037              if ( firstChild )
1038              {
1039                  // Check the cached nodes for merging.

1040                  firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.mergeSiblings();
1041  
1042                  if ( lastChild && !firstChild.equals( lastChild )
1043                      && lastChild.type == CKEDITOR.NODE_ELEMENT  )
1044                      lastChild.mergeSiblings();
1045              }
1046          }
1047      }
1048  
1049  	function getElement( style, targetDocument )
1050      {
1051          var el;
1052  
1053          var def = style._.definition;
1054  
1055          var elementName = style.element;
1056  
1057          // The "*" element name will always be a span for this function.

1058          if ( elementName == '*' )
1059              elementName = 'span';
1060  
1061          // Create the element.

1062          el = new CKEDITOR.dom.element( elementName, targetDocument );
1063  
1064          return setupElement( el, style );
1065      }
1066  
1067  	function setupElement( el, style )
1068      {
1069          var def = style._.definition;
1070          var attributes = def.attributes;
1071          var styles = CKEDITOR.style.getStyleText( def );
1072  
1073          // Assign all defined attributes.

1074          if ( attributes )
1075          {
1076              for ( var att in attributes )
1077              {
1078                  el.setAttribute( att, attributes[ att ] );
1079              }
1080          }
1081  
1082          // Assign all defined styles.

1083          if ( styles )
1084              el.setAttribute( 'style', styles );
1085  
1086          return el;
1087      }
1088  
1089      var varRegex = /#\((.+?)\)/g;
1090  	function replaceVariables( list, variablesValues )
1091      {
1092          for ( var item in list )
1093          {
1094              list[ item ] = list[ item ].replace( varRegex, function( match, varName )
1095                  {
1096                      return variablesValues[ varName ];
1097                  });
1098          }
1099      }
1100  
1101  
1102      // Returns an object that can be used for style matching comparison.

1103      // Attributes names and values are all lowercased, and the styles get

1104      // merged with the style attribute.

1105  	function getAttributesForComparison( styleDefinition )
1106      {
1107          // If we have already computed it, just return it.

1108          var attribs = styleDefinition._AC;
1109          if ( attribs )
1110              return attribs;
1111  
1112          attribs = {};
1113  
1114          var length = 0;
1115  
1116          // Loop through all defined attributes.

1117          var styleAttribs = styleDefinition.attributes;
1118          if ( styleAttribs )
1119          {
1120              for ( var styleAtt in styleAttribs )
1121              {
1122                  length++;
1123                  attribs[ styleAtt ] = styleAttribs[ styleAtt ];
1124              }
1125          }
1126  
1127          // Includes the style definitions.

1128          var styleText = CKEDITOR.style.getStyleText( styleDefinition );
1129          if ( styleText )
1130          {
1131              if ( !attribs[ 'style' ] )
1132                  length++;
1133              attribs[ 'style' ] = styleText;
1134          }
1135  
1136          // Appends the "length" information to the object.

1137          attribs._length = length;
1138  
1139          // Return it, saving it to the next request.

1140          return ( styleDefinition._AC = attribs );
1141      }
1142  
1143      /**

1144       * Get the the collection used to compare the elements and attributes,

1145       * defined in this style overrides, with other element. All information in

1146       * it is lowercased.

1147       * @param {CKEDITOR.style} style

1148       */
1149  	function getOverrides( style )
1150      {
1151          if ( style._.overrides )
1152              return style._.overrides;
1153  
1154          var overrides = ( style._.overrides = {} ),
1155              definition = style._.definition.overrides;
1156  
1157          if ( definition )
1158          {
1159              // The override description can be a string, object or array.

1160              // Internally, well handle arrays only, so transform it if needed.

1161              if ( !CKEDITOR.tools.isArray( definition ) )
1162                  definition = [ definition ];
1163  
1164              // Loop through all override definitions.

1165              for ( var i = 0 ; i < definition.length ; i++ )
1166              {
1167                  var override = definition[i];
1168                  var elementName;
1169                  var overrideEl;
1170                  var attrs;
1171  
1172                  // If can be a string with the element name.

1173                  if ( typeof override == 'string' )
1174                      elementName = override.toLowerCase();
1175                  // Or an object.

1176                  else
1177                  {
1178                      elementName = override.element ? override.element.toLowerCase() : style.element;
1179                      attrs = override.attributes;
1180                  }
1181  
1182                  // We can have more than one override definition for the same

1183                  // element name, so we attempt to simply append information to

1184                  // it if it already exists.

1185                  overrideEl = overrides[ elementName ] || ( overrides[ elementName ] = {} );
1186  
1187                  if ( attrs )
1188                  {
1189                      // The returning attributes list is an array, because we

1190                      // could have different override definitions for the same

1191                      // attribute name.

1192                      var overrideAttrs = ( overrideEl.attributes = overrideEl.attributes || new Array() );
1193                      for ( var attName in attrs )
1194                      {
1195                          // Each item in the attributes array is also an array,

1196                          // where [0] is the attribute name and [1] is the

1197                          // override value.

1198                          overrideAttrs.push( [ attName.toLowerCase(), attrs[ attName ] ] );
1199                      }
1200                  }
1201              }
1202          }
1203  
1204          return overrides;
1205      }
1206  
1207      // Make the comparison of attribute value easier by standardizing it.

1208  	function normalizeProperty( name, value, isStyle )
1209      {
1210          var temp = new CKEDITOR.dom.element( 'span' );
1211          temp [ isStyle ? 'setStyle' : 'setAttribute' ]( name, value );
1212          return temp[ isStyle ? 'getStyle' : 'getAttribute' ]( name );
1213      }
1214  
1215      // Make the comparison of style text easier by standardizing it.

1216  	function normalizeCssText( unparsedCssText, nativeNormalize )
1217      {
1218          var styleText;
1219          if ( nativeNormalize !== false )
1220          {
1221              // Injects the style in a temporary span object, so the browser parses it,

1222              // retrieving its final format.

1223              var temp = new CKEDITOR.dom.element( 'span' );
1224              temp.setAttribute( 'style', unparsedCssText );
1225              styleText = temp.getAttribute( 'style' ) || '';
1226          }
1227          else
1228              styleText = unparsedCssText;
1229  
1230          // Shrinking white-spaces around colon and semi-colon (#4147).

1231          // Compensate tail semi-colon.

1232          return styleText.replace( /\s*([;:])\s*/, '$1' )
1233                               .replace( /([^\s;])$/, '$1;')
1234                               .replace( /,\s+/g, ',' ) // Trimming spaces after comma (e.g. font-family name)(#4107).
1235                               .toLowerCase();
1236      }
1237  
1238      // Turn inline style text properties into one hash.

1239  	function parseStyleText( styleText )
1240      {
1241          var retval = {};
1242          styleText
1243             .replace( /&quot;/g, '"' )
1244             .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value )
1245          {
1246              retval[ name ] = value;
1247          } );
1248          return retval;
1249      }
1250  
1251      /**

1252       * Compare two bunch of styles, with the speciality that value 'inherit'

1253       * is treated as a wildcard which will match any value.

1254       * @param {Object|String} source

1255       * @param {Object|String} target

1256       */
1257  	function compareCssText( source, target )
1258      {
1259          typeof source == 'string' && ( source = parseStyleText( source ) );
1260          typeof target == 'string' && ( target = parseStyleText( target ) );
1261          for( var name in source )
1262          {
1263              if ( !( name in target &&
1264                      ( target[ name ] == source[ name ]
1265                          || source[ name ] == 'inherit'
1266                          || target[ name ] == 'inherit' ) ) )
1267              {
1268                  return false;
1269              }
1270          }
1271          return true;
1272      }
1273  
1274  	function applyStyle( document, remove )
1275      {
1276          var selection = document.getSelection(),
1277              // Bookmark the range so we can re-select it after processing.

1278              bookmarks = selection.createBookmarks(),
1279              ranges = selection.getRanges( true ),
1280              func = remove ? this.removeFromRange : this.applyToRange,
1281              range;
1282  
1283          var iterator = ranges.createIterator();
1284          while ( ( range = iterator.getNextRange() ) )
1285              func.call( this, range );
1286  
1287          if ( bookmarks.length == 1 && bookmarks[0].collapsed )
1288          {
1289              selection.selectRanges( ranges );
1290              bookmarks[0].startNode.remove();
1291          }
1292          else
1293              selection.selectBookmarks( bookmarks );
1294      }
1295  })();
1296  
1297  CKEDITOR.styleCommand = function( style )
1298  {
1299      this.style = style;
1300  };
1301  
1302  CKEDITOR.styleCommand.prototype.exec = function( editor )
1303  {
1304      editor.focus();
1305  
1306      var doc = editor.document;
1307  
1308      if ( doc )
1309      {
1310          if ( this.state == CKEDITOR.TRISTATE_OFF )
1311              this.style.apply( doc );
1312          else if ( this.state == CKEDITOR.TRISTATE_ON )
1313              this.style.remove( doc );
1314      }
1315  
1316      return !!doc;
1317  };
1318  
1319  CKEDITOR.stylesSet = new CKEDITOR.resourceManager( '', 'stylesSet' );
1320  
1321  // Backward compatibility (#5025).

1322  CKEDITOR.addStylesSet = CKEDITOR.tools.bind( CKEDITOR.stylesSet.add, CKEDITOR.stylesSet );
1323  CKEDITOR.loadStylesSet = function( name, url, callback )
1324      {
1325          CKEDITOR.stylesSet.addExternal( name, url, '' );
1326          CKEDITOR.stylesSet.load( name, callback );
1327      };
1328  
1329  
1330  /**

1331   * Gets the current styleSet for this instance

1332   * @param {Function} The function to be called with the styles data.

1333   * @example

1334   * editor.getStylesSet( function( stylesDefinitions ) {} );

1335   */
1336  CKEDITOR.editor.prototype.getStylesSet = function( callback )
1337  {
1338      if ( !this._.stylesDefinitions )
1339      {
1340          var editor = this,
1341              // Respect the backwards compatible definition entry

1342              configStyleSet = editor.config.stylesCombo_stylesSet || editor.config.stylesSet || 'default';
1343  
1344          // #5352 Allow to define the styles directly in the config object

1345          if ( configStyleSet instanceof Array )
1346          {
1347              editor._.stylesDefinitions = configStyleSet;
1348              callback( configStyleSet );
1349              return;
1350          }
1351  
1352          var    partsStylesSet = configStyleSet.split( ':' ),
1353              styleSetName = partsStylesSet[ 0 ],
1354              externalPath = partsStylesSet[ 1 ],
1355              pluginPath = CKEDITOR.plugins.registered.styles.path;
1356  
1357          CKEDITOR.stylesSet.addExternal( styleSetName,
1358                  externalPath ?
1359                      partsStylesSet.slice( 1 ).join( ':' ) :
1360                      pluginPath + 'styles/' + styleSetName + '.js', '' );
1361  
1362          CKEDITOR.stylesSet.load( styleSetName, function( stylesSet )
1363              {
1364                  editor._.stylesDefinitions = stylesSet[ styleSetName ];
1365                  callback( editor._.stylesDefinitions );
1366              } ) ;
1367      }
1368      else
1369          callback( this._.stylesDefinitions );
1370  };
1371  
1372  /**

1373   * The "styles definition set" to use in the editor. They will be used in the

1374   * styles combo and the Style selector of the div container. <br>

1375   * The styles may be defined in the page containing the editor, or can be

1376   * loaded on demand from an external file. In the second case, if this setting

1377   * contains only a name, the styles definition file will be loaded from the

1378   * "styles" folder inside the styles plugin folder.

1379   * Otherwise, this setting has the "name:url" syntax, making it

1380   * possible to set the URL from which loading the styles file.<br>

1381   * Previously this setting was available as config.stylesCombo_stylesSet<br>

1382   * @name CKEDITOR.config.stylesSet

1383   * @type String|Array

1384   * @default 'default'

1385   * @since 3.3

1386   * @example

1387   * // Load from the styles' styles folder (mystyles.js file).

1388   * config.stylesSet = 'mystyles';

1389   * @example

1390   * // Load from a relative URL.

1391   * config.stylesSet = 'mystyles:/editorstyles/styles.js';

1392   * @example

1393   * // Load from a full URL.

1394   * config.stylesSet = 'mystyles:http://www.example.com/editorstyles/styles.js';

1395   * @example

1396   * // Load from a list of definitions.

1397   * config.stylesSet = [

1398   *  { name : 'Strong Emphasis', element : 'strong' },

1399   * { name : 'Emphasis', element : 'em' }, ... ];

1400   */


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