[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/libraries/ckeditor/_source/plugins/indent/ -> 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  /**

   7   * @file Increse and decrease indent commands.

   8   */
   9  
  10  (function()
  11  {
  12      var listNodeNames = { ol : 1, ul : 1 };
  13  
  14      var isNotWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
  15          isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true );
  16  
  17  	function setState( editor, state )
  18      {
  19          editor.getCommand( this.name ).setState( state );
  20      }
  21  
  22  	function onSelectionChange( evt )
  23      {
  24          var editor = evt.editor;
  25  
  26          var elementPath = evt.data.path,
  27                  list = elementPath && elementPath.contains( listNodeNames );
  28  
  29          if ( list )
  30                  return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
  31  
  32          if ( !this.useIndentClasses && this.name == 'indent' )
  33              return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
  34  
  35          var path = evt.data.path,
  36              firstBlock = path.block || path.blockLimit;
  37          if ( !firstBlock )
  38              return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
  39  
  40          if ( this.useIndentClasses )
  41          {
  42              var indentClass = firstBlock.$.className.match( this.classNameRegex ),
  43                  indentStep = 0;
  44              if ( indentClass )
  45              {
  46                  indentClass = indentClass[1];
  47                  indentStep = this.indentClassMap[ indentClass ];
  48              }
  49              if ( ( this.name == 'outdent' && !indentStep ) ||
  50                      ( this.name == 'indent' && indentStep == editor.config.indentClasses.length ) )
  51                  return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
  52              return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
  53          }
  54          else
  55          {
  56              var indent = parseInt( firstBlock.getStyle( getIndentCssProperty( firstBlock ) ), 10 );
  57              if ( isNaN( indent ) )
  58                  indent = 0;
  59              if ( indent <= 0 )
  60                  return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
  61              return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
  62          }
  63      }
  64  
  65  	function indentCommand( editor, name )
  66      {
  67          this.name = name;
  68          this.useIndentClasses = editor.config.indentClasses && editor.config.indentClasses.length > 0;
  69          if ( this.useIndentClasses )
  70          {
  71              this.classNameRegex = new RegExp( '(?:^|\\s+)(' + editor.config.indentClasses.join( '|' ) + ')(?=$|\\s)' );
  72              this.indentClassMap = {};
  73              for ( var i = 0 ; i < editor.config.indentClasses.length ; i++ )
  74                  this.indentClassMap[ editor.config.indentClasses[i] ] = i + 1;
  75          }
  76  
  77          this.startDisabled = name == 'outdent';
  78      }
  79  
  80      // Returns the CSS property to be used for identing a given element.

  81  	function getIndentCssProperty( element )
  82      {
  83          return element.getComputedStyle( 'direction' ) == 'ltr' ? 'margin-left' : 'margin-right';
  84      }
  85  
  86  	function isListItem( node )
  87      {
  88          return node.type = CKEDITOR.NODE_ELEMENT && node.is( 'li' );
  89      }
  90  
  91      indentCommand.prototype = {
  92          exec : function( editor )
  93          {
  94              var self = this, database = {};
  95  
  96  			function indentList( listNode )
  97              {
  98                  // Our starting and ending points of the range might be inside some blocks under a list item...

  99                  // So before playing with the iterator, we need to expand the block to include the list items.

 100                  var startContainer = range.startContainer,
 101                      endContainer = range.endContainer;
 102                  while ( startContainer && !startContainer.getParent().equals( listNode ) )
 103                      startContainer = startContainer.getParent();
 104                  while ( endContainer && !endContainer.getParent().equals( listNode ) )
 105                      endContainer = endContainer.getParent();
 106  
 107                  if ( !startContainer || !endContainer )
 108                      return;
 109  
 110                  // Now we can iterate over the individual items on the same tree depth.

 111                  var block = startContainer,
 112                      itemsToMove = [],
 113                      stopFlag = false;
 114                  while ( !stopFlag )
 115                  {
 116                      if ( block.equals( endContainer ) )
 117                          stopFlag = true;
 118                      itemsToMove.push( block );
 119                      block = block.getNext();
 120                  }
 121                  if ( itemsToMove.length < 1 )
 122                      return;
 123  
 124                  // Do indent or outdent operations on the array model of the list, not the

 125                  // list's DOM tree itself. The array model demands that it knows as much as

 126                  // possible about the surrounding lists, we need to feed it the further

 127                  // ancestor node that is still a list.

 128                  var listParents = listNode.getParents( true );
 129                  for ( var i = 0 ; i < listParents.length ; i++ )
 130                  {
 131                      if ( listParents[i].getName && listNodeNames[ listParents[i].getName() ] )
 132                      {
 133                          listNode = listParents[i];
 134                          break;
 135                      }
 136                  }
 137                  var indentOffset = self.name == 'indent' ? 1 : -1,
 138                      startItem = itemsToMove[0],
 139                      lastItem = itemsToMove[ itemsToMove.length - 1 ];
 140  
 141                  // Convert the list DOM tree into a one dimensional array.

 142                  var listArray = CKEDITOR.plugins.list.listToArray( listNode, database );
 143  
 144                  // Apply indenting or outdenting on the array.

 145                  var baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
 146                  for ( i = startItem.getCustomData( 'listarray_index' ); i <= lastItem.getCustomData( 'listarray_index' ); i++ )
 147                  {
 148                      listArray[ i ].indent += indentOffset;
 149                      // Make sure the newly created sublist get a brand-new element of the same type. (#5372)

 150                      var listRoot = listArray[ i ].parent;
 151                      listArray[ i ].parent = new CKEDITOR.dom.element( listRoot.getName(), listRoot.getDocument() );
 152                  }
 153  
 154                  for ( i = lastItem.getCustomData( 'listarray_index' ) + 1 ;
 155                          i < listArray.length && listArray[i].indent > baseIndent ; i++ )
 156                      listArray[i].indent += indentOffset;
 157  
 158                  // Convert the array back to a DOM forest (yes we might have a few subtrees now).

 159                  // And replace the old list with the new forest.

 160                  var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 0 );
 161  
 162                  // Avoid nested <li> after outdent even they're visually same,

 163                  // recording them for later refactoring.(#3982)

 164                  if ( self.name == 'outdent' )
 165                  {
 166                      var parentLiElement;
 167                      if ( ( parentLiElement = listNode.getParent() ) && parentLiElement.is( 'li' ) )
 168                      {
 169                          var children = newList.listNode.getChildren(),
 170                              pendingLis = [],
 171                              count = children.count(),
 172                              child;
 173  
 174                          for ( i = count - 1 ; i >= 0 ; i-- )
 175                          {
 176                              if ( ( child = children.getItem( i ) ) && child.is && child.is( 'li' )  )
 177                                  pendingLis.push( child );
 178                          }
 179                      }
 180                  }
 181  
 182                  if ( newList )
 183                      newList.listNode.replace( listNode );
 184  
 185                  // Move the nested <li> to be appeared after the parent.

 186                  if ( pendingLis && pendingLis.length )
 187                  {
 188                      for (  i = 0; i < pendingLis.length ; i++ )
 189                      {
 190                          var li = pendingLis[ i ],
 191                              followingList = li;
 192  
 193                          // Nest preceding <ul>/<ol> inside current <li> if any.

 194                          while ( ( followingList = followingList.getNext() ) &&
 195                                 followingList.is &&
 196                                 followingList.getName() in listNodeNames )
 197                          {
 198                              // IE requires a filler NBSP for nested list inside empty list item,

 199                              // otherwise the list item will be inaccessiable. (#4476)

 200                              if ( CKEDITOR.env.ie && !li.getFirst( function( node ){ return isNotWhitespaces( node ) && isNotBookmark( node ); } ) )
 201                                  li.append( range.document.createText( '\u00a0' ) );
 202  
 203                              li.append( followingList );
 204                          }
 205  
 206                          li.insertAfter( parentLiElement );
 207                      }
 208                  }
 209              }
 210  
 211  			function indentBlock()
 212              {
 213                  var iterator = range.createIterator(),
 214                      enterMode = editor.config.enterMode;
 215                  iterator.enforceRealBlocks = true;
 216                  iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
 217                  var block;
 218                  while ( ( block = iterator.getNextParagraph() ) )
 219                      indentElement( block );
 220              }
 221  
 222  			function indentElement( element )
 223              {
 224                  if ( element.getCustomData( 'indent_processed' ) )
 225                      return false;
 226  
 227                  if ( self.useIndentClasses )
 228                  {
 229                      // Transform current class name to indent step index.

 230                      var indentClass = element.$.className.match( self.classNameRegex ),
 231                              indentStep = 0;
 232                      if ( indentClass )
 233                      {
 234                          indentClass = indentClass[1];
 235                          indentStep = self.indentClassMap[ indentClass ];
 236                      }
 237  
 238                      // Operate on indent step index, transform indent step index back to class

 239                      // name.

 240                      if ( self.name == 'outdent' )
 241                          indentStep--;
 242                      else
 243                          indentStep++;
 244  
 245                      if ( indentStep < 0 )
 246                          return false;
 247  
 248                      indentStep = Math.min( indentStep, editor.config.indentClasses.length );
 249                      indentStep = Math.max( indentStep, 0 );
 250                      var className = CKEDITOR.tools.ltrim( element.$.className.replace( self.classNameRegex, '' ) );
 251                      if ( indentStep < 1 )
 252                          element.$.className = className;
 253                      else
 254                          element.addClass( editor.config.indentClasses[ indentStep - 1 ] );
 255                  }
 256                  else
 257                  {
 258                      var indentCssProperty = getIndentCssProperty( element );
 259                      var currentOffset = parseInt( element.getStyle( indentCssProperty ), 10 );
 260                      if ( isNaN( currentOffset ) )
 261                          currentOffset = 0;
 262                      currentOffset += ( self.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;
 263  
 264                      if ( currentOffset < 0 )
 265                          return false;
 266  
 267                      currentOffset = Math.max( currentOffset, 0 );
 268                      currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;
 269                      element.setStyle( indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );
 270                      if ( element.getAttribute( 'style' ) === '' )
 271                          element.removeAttribute( 'style' );
 272                  }
 273  
 274                  CKEDITOR.dom.element.setMarker( database, element, 'indent_processed', true );
 275                  return true;
 276              }
 277  
 278              var selection = editor.getSelection(),
 279                  bookmarks = selection.createBookmarks( true ),
 280                  ranges = selection && selection.getRanges( true ),
 281                  range;
 282  
 283              var iterator = ranges.createIterator();
 284              while ( ( range = iterator.getNextRange() ) )
 285              {
 286                  var startContainer = range.startContainer,
 287                      endContainer = range.endContainer,
 288                      rangeRoot = range.getCommonAncestor(),
 289                      nearestListBlock = rangeRoot;
 290  
 291                  while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&
 292                      listNodeNames[ nearestListBlock.getName() ] ) )
 293                      nearestListBlock = nearestListBlock.getParent();
 294  
 295                  // Avoid selection anchors under list root.

 296                  // <ul>[<li>...</li>]</ul> =>    <ul><li>[...]</li></ul>

 297                  if ( nearestListBlock && startContainer.type == CKEDITOR.NODE_ELEMENT
 298                      && startContainer.getName() in listNodeNames )
 299                  {
 300                      var walker = new CKEDITOR.dom.walker( range );
 301                      walker.evaluator = isListItem;
 302                      range.startContainer = walker.next();
 303                  }
 304  
 305                  if ( nearestListBlock && endContainer.type == CKEDITOR.NODE_ELEMENT
 306                      && endContainer.getName() in listNodeNames )
 307                  {
 308                      walker = new CKEDITOR.dom.walker( range );
 309                      walker.evaluator = isListItem;
 310                      range.endContainer = walker.previous();
 311                  }
 312  
 313                  if ( nearestListBlock  )
 314                  {
 315                      var firstListItem = nearestListBlock.getFirst( function( node )
 316                          {
 317                              return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );
 318                          }),
 319                          rangeStart = range.startContainer,
 320                          indentWholeList = firstListItem.equals( rangeStart ) || firstListItem.contains( rangeStart );
 321  
 322                      // Indent the entire list if  cursor is inside the first list item. (#3893)

 323                      if ( !( indentWholeList && indentElement( nearestListBlock ) ) )
 324                          indentList( nearestListBlock );
 325                  }
 326                  else
 327                      indentBlock();
 328              }
 329  
 330              // Clean up the markers.

 331              CKEDITOR.dom.element.clearAllMarkers( database );
 332  
 333              editor.forceNextSelectionCheck();
 334              selection.selectBookmarks( bookmarks );
 335          }
 336      };
 337  
 338      CKEDITOR.plugins.add( 'indent',
 339      {
 340          init : function( editor )
 341          {
 342              // Register commands.

 343              var indent = new indentCommand( editor, 'indent' ),
 344                  outdent = new indentCommand( editor, 'outdent' );
 345              editor.addCommand( 'indent', indent );
 346              editor.addCommand( 'outdent', outdent );
 347  
 348              // Register the toolbar buttons.

 349              editor.ui.addButton( 'Indent',
 350                  {
 351                      label : editor.lang.indent,
 352                      command : 'indent'
 353                  });
 354              editor.ui.addButton( 'Outdent',
 355                  {
 356                      label : editor.lang.outdent,
 357                      command : 'outdent'
 358                  });
 359  
 360              // Register the state changing handlers.

 361              editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, indent ) );
 362              editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, outdent ) );
 363  
 364              // [IE6/7] Raw lists are using margin instead of padding for visual indentation in wysiwyg mode. (#3893)

 365              if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat )
 366              {
 367                  editor.addCss(
 368                      "ul,ol" +
 369                      "{" +
 370                      "    margin-left: 0px;" +
 371                      "    padding-left: 40px;" +
 372                      "}" );
 373              }
 374          },
 375  
 376          requires : [ 'domiterator', 'list' ]
 377      } );
 378  })();
 379  
 380  CKEDITOR.tools.extend( CKEDITOR.config,
 381      {
 382          indentOffset : 40,
 383          indentUnit : 'px',
 384          indentClasses : null
 385      });
 386  
 387  /**

 388   * Size of each indentation step

 389   * @type Number

 390   * @example

 391   * config.indentOffset = 40;

 392   */
 393  
 394   /**

 395   * Unit for the indentation style

 396   * @type String

 397   * @example

 398   * config.indentUnit = 'px';

 399   */
 400  
 401   /**

 402   * List of classes to use for indenting the contents.

 403   * @type Array

 404   * @example

 405   * // Don't use classes for indenting. (this is the default value)

 406   * config.indentClasses = null;

 407   * @example

 408   * // Use the classes 'Indent1', 'Indent2', 'Indent3'

 409   * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];

 410   */
 411  
 412  /**

 413   * Size of each indentation step

 414   * @type Number

 415   * @default 40

 416   * @example

 417   * config.indentOffset = 4;

 418   */
 419  
 420   /**

 421   * Unit for the indentation style

 422   * @type String

 423   * @default 'px'

 424   * @example

 425   * config.indentUnit = 'em';

 426   */
 427  
 428   /**

 429   * List of classes to use for indenting the contents. If it's null, no classes will be used

 430   * and instead the {@link #indentUnit} and {@link #indentOffset} properties will be used.

 431   * @type Array

 432   * default null

 433   * @example

 434   * // Use the classes 'Indent1', 'Indent2', 'Indent3'

 435   * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];

 436   */


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