| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
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 Insert and remove numbered and bulleted lists. 8 */ 9 10 (function() 11 { 12 var listNodeNames = { ol : 1, ul : 1 }, 13 emptyTextRegex = /^[\n\r\t ]*$/; 14 15 CKEDITOR.plugins.list = { 16 /* 17 * Convert a DOM list tree into a data structure that is easier to 18 * manipulate. This operation should be non-intrusive in the sense that it 19 * does not change the DOM tree, with the exception that it may add some 20 * markers to the list item nodes when database is specified. 21 */ 22 listToArray : function( listNode, database, baseArray, baseIndentLevel, grandparentNode ) 23 { 24 if ( !listNodeNames[ listNode.getName() ] ) 25 return []; 26 27 if ( !baseIndentLevel ) 28 baseIndentLevel = 0; 29 if ( !baseArray ) 30 baseArray = []; 31 32 // Iterate over all list items to and look for inner lists. 33 for ( var i = 0, count = listNode.getChildCount() ; i < count ; i++ ) 34 { 35 var listItem = listNode.getChild( i ); 36 37 // It may be a text node or some funny stuff. 38 if ( listItem.$.nodeName.toLowerCase() != 'li' ) 39 continue; 40 41 var itemObj = { 'parent' : listNode, indent : baseIndentLevel, element : listItem, contents : [] }; 42 if ( !grandparentNode ) 43 { 44 itemObj.grandparent = listNode.getParent(); 45 if ( itemObj.grandparent && itemObj.grandparent.$.nodeName.toLowerCase() == 'li' ) 46 itemObj.grandparent = itemObj.grandparent.getParent(); 47 } 48 else 49 itemObj.grandparent = grandparentNode; 50 51 if ( database ) 52 CKEDITOR.dom.element.setMarker( database, listItem, 'listarray_index', baseArray.length ); 53 baseArray.push( itemObj ); 54 55 for ( var j = 0, itemChildCount = listItem.getChildCount(), child; j < itemChildCount ; j++ ) 56 { 57 child = listItem.getChild( j ); 58 if ( child.type == CKEDITOR.NODE_ELEMENT && listNodeNames[ child.getName() ] ) 59 // Note the recursion here, it pushes inner list items with 60 // +1 indentation in the correct order. 61 CKEDITOR.plugins.list.listToArray( child, database, baseArray, baseIndentLevel + 1, itemObj.grandparent ); 62 else 63 itemObj.contents.push( child ); 64 } 65 } 66 return baseArray; 67 }, 68 69 // Convert our internal representation of a list back to a DOM forest. 70 arrayToList : function( listArray, database, baseIndex, paragraphMode, dir ) 71 { 72 if ( !baseIndex ) 73 baseIndex = 0; 74 if ( !listArray || listArray.length < baseIndex + 1 ) 75 return null; 76 var doc = listArray[ baseIndex ].parent.getDocument(), 77 retval = new CKEDITOR.dom.documentFragment( doc ), 78 rootNode = null, 79 currentIndex = baseIndex, 80 indentLevel = Math.max( listArray[ baseIndex ].indent, 0 ), 81 currentListItem = null, 82 paragraphName = ( paragraphMode == CKEDITOR.ENTER_P ? 'p' : 'div' ); 83 while ( true ) 84 { 85 var item = listArray[ currentIndex ]; 86 if ( item.indent == indentLevel ) 87 { 88 if ( !rootNode || listArray[ currentIndex ].parent.getName() != rootNode.getName() ) 89 { 90 rootNode = listArray[ currentIndex ].parent.clone( false, true ); 91 retval.append( rootNode ); 92 } 93 currentListItem = rootNode.append( item.element.clone( false, true ) ); 94 for ( var i = 0 ; i < item.contents.length ; i++ ) 95 currentListItem.append( item.contents[i].clone( true, true ) ); 96 currentIndex++; 97 } 98 else if ( item.indent == Math.max( indentLevel, 0 ) + 1 ) 99 { 100 var listData = CKEDITOR.plugins.list.arrayToList( listArray, null, currentIndex, paragraphMode ); 101 currentListItem.append( listData.listNode ); 102 currentIndex = listData.nextIndex; 103 } 104 else if ( item.indent == -1 && !baseIndex && item.grandparent ) 105 { 106 currentListItem; 107 if ( listNodeNames[ item.grandparent.getName() ] ) 108 currentListItem = item.element.clone( false, true ); 109 else 110 { 111 // Create completely new blocks here, attributes are dropped. 112 if ( dir || ( paragraphMode != CKEDITOR.ENTER_BR && item.grandparent.getName() != 'td' ) ) 113 { 114 currentListItem = doc.createElement( paragraphName ); 115 if ( dir ) 116 currentListItem.setAttribute( 'dir', dir ); 117 } 118 else 119 currentListItem = new CKEDITOR.dom.documentFragment( doc ); 120 } 121 122 for ( i = 0 ; i < item.contents.length ; i++ ) 123 currentListItem.append( item.contents[i].clone( true, true ) ); 124 125 if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT 126 && currentIndex != listArray.length - 1 ) 127 { 128 if ( currentListItem.getLast() 129 && currentListItem.getLast().type == CKEDITOR.NODE_ELEMENT 130 && currentListItem.getLast().getAttribute( 'type' ) == '_moz' ) 131 currentListItem.getLast().remove(); 132 currentListItem.appendBogus(); 133 } 134 135 if ( currentListItem.type == CKEDITOR.NODE_ELEMENT && 136 currentListItem.getName() == paragraphName && 137 currentListItem.$.firstChild ) 138 { 139 currentListItem.trim(); 140 var firstChild = currentListItem.getFirst(); 141 if ( firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.isBlockBoundary() ) 142 { 143 var tmp = new CKEDITOR.dom.documentFragment( doc ); 144 currentListItem.moveChildren( tmp ); 145 currentListItem = tmp; 146 } 147 } 148 149 var currentListItemName = currentListItem.$.nodeName.toLowerCase(); 150 if ( !CKEDITOR.env.ie && ( currentListItemName == 'div' || currentListItemName == 'p' ) ) 151 currentListItem.appendBogus(); 152 retval.append( currentListItem ); 153 rootNode = null; 154 currentIndex++; 155 } 156 else 157 return null; 158 159 if ( listArray.length <= currentIndex || Math.max( listArray[ currentIndex ].indent, 0 ) < indentLevel ) 160 break; 161 } 162 163 // Clear marker attributes for the new list tree made of cloned nodes, if any. 164 if ( database ) 165 { 166 var currentNode = retval.getFirst(); 167 while ( currentNode ) 168 { 169 if ( currentNode.type == CKEDITOR.NODE_ELEMENT ) 170 CKEDITOR.dom.element.clearMarkers( database, currentNode ); 171 currentNode = currentNode.getNextSourceNode(); 172 } 173 } 174 175 return { listNode : retval, nextIndex : currentIndex }; 176 } 177 }; 178 179 function setState( editor, state ) 180 { 181 editor.getCommand( this.name ).setState( state ); 182 } 183 184 function onSelectionChange( evt ) 185 { 186 var path = evt.data.path, 187 blockLimit = path.blockLimit, 188 elements = path.elements, 189 element; 190 191 // Grouping should only happen under blockLimit.(#3940). 192 for ( var i = 0 ; i < elements.length && ( element = elements[ i ] ) 193 && !element.equals( blockLimit ); i++ ) 194 { 195 if ( listNodeNames[ elements[i].getName() ] ) 196 { 197 return setState.call( this, evt.editor, 198 this.type == elements[i].getName() ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); 199 } 200 } 201 202 return setState.call( this, evt.editor, CKEDITOR.TRISTATE_OFF ); 203 } 204 205 function changeListType( editor, groupObj, database, listsCreated ) 206 { 207 // This case is easy... 208 // 1. Convert the whole list into a one-dimensional array. 209 // 2. Change the list type by modifying the array. 210 // 3. Recreate the whole list by converting the array to a list. 211 // 4. Replace the original list with the recreated list. 212 var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ), 213 selectedListItems = []; 214 215 for ( var i = 0 ; i < groupObj.contents.length ; i++ ) 216 { 217 var itemNode = groupObj.contents[i]; 218 itemNode = itemNode.getAscendant( 'li', true ); 219 if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) ) 220 continue; 221 selectedListItems.push( itemNode ); 222 CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true ); 223 } 224 225 var root = groupObj.root, 226 fakeParent = root.getDocument().createElement( this.type ); 227 // Copy all attributes, except from 'start' and 'type'. 228 root.copyAttributes( fakeParent, { start : 1, type : 1 } ); 229 // The list-style-type property should be ignored. 230 fakeParent.removeStyle( 'list-style-type' ); 231 232 for ( i = 0 ; i < selectedListItems.length ; i++ ) 233 { 234 var listIndex = selectedListItems[i].getCustomData( 'listarray_index' ); 235 listArray[listIndex].parent = fakeParent; 236 } 237 var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode ); 238 var child, length = newList.listNode.getChildCount(); 239 for ( i = 0 ; i < length && ( child = newList.listNode.getChild( i ) ) ; i++ ) 240 { 241 if ( child.getName() == this.type ) 242 listsCreated.push( child ); 243 } 244 newList.listNode.replace( groupObj.root ); 245 } 246 247 var headerTagRegex = /^h[1-6]$/; 248 249 function createList( editor, groupObj, listsCreated ) 250 { 251 var contents = groupObj.contents, 252 doc = groupObj.root.getDocument(), 253 listContents = []; 254 255 // It is possible to have the contents returned by DomRangeIterator to be the same as the root. 256 // e.g. when we're running into table cells. 257 // In such a case, enclose the childNodes of contents[0] into a <div>. 258 if ( contents.length == 1 && contents[0].equals( groupObj.root ) ) 259 { 260 var divBlock = doc.createElement( 'div' ); 261 contents[0].moveChildren && contents[0].moveChildren( divBlock ); 262 contents[0].append( divBlock ); 263 contents[0] = divBlock; 264 } 265 266 // Calculate the common parent node of all content blocks. 267 var commonParent = groupObj.contents[0].getParent(); 268 for ( var i = 0 ; i < contents.length ; i++ ) 269 commonParent = commonParent.getCommonAncestor( contents[i].getParent() ); 270 271 // We want to insert things that are in the same tree level only, so calculate the contents again 272 // by expanding the selected blocks to the same tree level. 273 for ( i = 0 ; i < contents.length ; i++ ) 274 { 275 var contentNode = contents[i], 276 parentNode; 277 while ( ( parentNode = contentNode.getParent() ) ) 278 { 279 if ( parentNode.equals( commonParent ) ) 280 { 281 listContents.push( contentNode ); 282 break; 283 } 284 contentNode = parentNode; 285 } 286 } 287 288 if ( listContents.length < 1 ) 289 return; 290 291 // Insert the list to the DOM tree. 292 var insertAnchor = listContents[ listContents.length - 1 ].getNext(), 293 listNode = doc.createElement( this.type ), 294 dir; 295 296 listsCreated.push( listNode ); 297 while ( listContents.length ) 298 { 299 var contentBlock = listContents.shift(), 300 listItem = doc.createElement( 'li' ); 301 302 // Preserve heading structure when converting to list item. (#5271) 303 if ( headerTagRegex.test( contentBlock.getName() ) ) 304 contentBlock.appendTo( listItem ); 305 else 306 { 307 if ( contentBlock.hasAttribute( 'dir' ) ) 308 { 309 dir = dir || contentBlock.getAttribute( 'dir' ); 310 contentBlock.removeAttribute( 'dir' ); 311 } 312 contentBlock.copyAttributes( listItem ); 313 contentBlock.moveChildren( listItem ); 314 contentBlock.remove(); 315 } 316 317 listItem.appendTo( listNode ); 318 319 // Append a bogus BR to force the LI to render at full height 320 if ( !CKEDITOR.env.ie ) 321 listItem.appendBogus(); 322 } 323 324 if ( dir ) 325 listNode.setAttribute( 'dir', dir ); 326 327 if ( insertAnchor ) 328 listNode.insertBefore( insertAnchor ); 329 else 330 listNode.appendTo( commonParent ); 331 } 332 333 function removeList( editor, groupObj, database ) 334 { 335 // This is very much like the change list type operation. 336 // Except that we're changing the selected items' indent to -1 in the list array. 337 var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ), 338 selectedListItems = []; 339 340 for ( var i = 0 ; i < groupObj.contents.length ; i++ ) 341 { 342 var itemNode = groupObj.contents[i]; 343 itemNode = itemNode.getAscendant( 'li', true ); 344 if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) ) 345 continue; 346 selectedListItems.push( itemNode ); 347 CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true ); 348 } 349 350 var lastListIndex = null; 351 for ( i = 0 ; i < selectedListItems.length ; i++ ) 352 { 353 var listIndex = selectedListItems[i].getCustomData( 'listarray_index' ); 354 listArray[listIndex].indent = -1; 355 lastListIndex = listIndex; 356 } 357 358 // After cutting parts of the list out with indent=-1, we still have to maintain the array list 359 // model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the 360 // list cannot be converted back to a real DOM list. 361 for ( i = lastListIndex + 1 ; i < listArray.length ; i++ ) 362 { 363 if ( listArray[i].indent > listArray[i-1].indent + 1 ) 364 { 365 var indentOffset = listArray[i-1].indent + 1 - listArray[i].indent; 366 var oldIndent = listArray[i].indent; 367 while ( listArray[i] && listArray[i].indent >= oldIndent ) 368 { 369 listArray[i].indent += indentOffset; 370 i++; 371 } 372 i--; 373 } 374 } 375 376 var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 377 groupObj.root.getAttribute( 'dir' ) ); 378 379 // Compensate <br> before/after the list node if the surrounds are non-blocks.(#3836) 380 var docFragment = newList.listNode, boundaryNode, siblingNode; 381 function compensateBrs( isStart ) 382 { 383 if ( ( boundaryNode = docFragment[ isStart ? 'getFirst' : 'getLast' ]() ) 384 && !( boundaryNode.is && boundaryNode.isBlockBoundary() ) 385 && ( siblingNode = groupObj.root[ isStart ? 'getPrevious' : 'getNext' ] 386 ( CKEDITOR.dom.walker.whitespaces( true ) ) ) 387 && !( siblingNode.is && siblingNode.isBlockBoundary( { br : 1 } ) ) ) 388 editor.document.createElement( 'br' )[ isStart ? 'insertBefore' : 'insertAfter' ]( boundaryNode ); 389 } 390 compensateBrs( true ); 391 compensateBrs(); 392 393 docFragment.replace( groupObj.root ); 394 } 395 396 function listCommand( name, type ) 397 { 398 this.name = name; 399 this.type = type; 400 } 401 402 listCommand.prototype = { 403 exec : function( editor ) 404 { 405 editor.focus(); 406 407 var doc = editor.document, 408 selection = editor.getSelection(), 409 ranges = selection && selection.getRanges( true ); 410 411 // There should be at least one selected range. 412 if ( !ranges || ranges.length < 1 ) 413 return; 414 415 // Midas lists rule #1 says we can create a list even in an empty document. 416 // But DOM iterator wouldn't run if the document is really empty. 417 // So create a paragraph if the document is empty and we're going to create a list. 418 if ( this.state == CKEDITOR.TRISTATE_OFF ) 419 { 420 var body = doc.getBody(); 421 body.trim(); 422 if ( !body.getFirst() ) 423 { 424 var paragraph = doc.createElement( editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 425 ( editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'br' ) ); 426 paragraph.appendTo( body ); 427 ranges = [ new CKEDITOR.dom.range( doc ) ]; 428 // IE exception on inserting anything when anchor inside <br>. 429 if ( paragraph.is( 'br' ) ) 430 { 431 ranges[ 0 ].setStartBefore( paragraph ); 432 ranges[ 0 ].setEndAfter( paragraph ); 433 } 434 else 435 ranges[ 0 ].selectNodeContents( paragraph ); 436 selection.selectRanges( ranges ); 437 } 438 // Maybe a single range there enclosing the whole list, 439 // turn on the list state manually(#4129). 440 else 441 { 442 var range = ranges.length == 1 && ranges[ 0 ], 443 enclosedNode = range && range.getEnclosedNode(); 444 if ( enclosedNode && enclosedNode.is 445 && this.type == enclosedNode.getName() ) 446 { 447 setState.call( this, editor, CKEDITOR.TRISTATE_ON ); 448 } 449 } 450 } 451 452 var bookmarks = selection.createBookmarks( true ); 453 454 // Group the blocks up because there are many cases where multiple lists have to be created, 455 // or multiple lists have to be cancelled. 456 var listGroups = [], 457 database = {}, 458 rangeIterator = ranges.createIterator(), 459 index = 0; 460 461 while ( ( range = rangeIterator.getNextRange() ) && ++index ) 462 { 463 var boundaryNodes = range.getBoundaryNodes(), 464 startNode = boundaryNodes.startNode, 465 endNode = boundaryNodes.endNode; 466 467 if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.getName() == 'td' ) 468 range.setStartAt( boundaryNodes.startNode, CKEDITOR.POSITION_AFTER_START ); 469 470 if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.getName() == 'td' ) 471 range.setEndAt( boundaryNodes.endNode, CKEDITOR.POSITION_BEFORE_END ); 472 473 var iterator = range.createIterator(), 474 block; 475 476 iterator.forceBrBreak = ( this.state == CKEDITOR.TRISTATE_OFF ); 477 478 while ( ( block = iterator.getNextParagraph() ) ) 479 { 480 // Avoid duplicate blocks get processed across ranges. 481 if( block.getCustomData( 'list_block' ) ) 482 continue; 483 else 484 CKEDITOR.dom.element.setMarker( database, block, 'list_block', 1 ); 485 486 var path = new CKEDITOR.dom.elementPath( block ), 487 pathElements = path.elements, 488 pathElementsCount = pathElements.length, 489 listNode = null, 490 processedFlag = false, 491 blockLimit = path.blockLimit, 492 element; 493 494 // First, try to group by a list ancestor. 495 for ( var i = pathElementsCount - 1; i >= 0 && ( element = pathElements[ i ] ); i-- ) 496 { 497 if ( listNodeNames[ element.getName() ] 498 && blockLimit.contains( element ) ) // Don't leak outside block limit (#3940). 499 { 500 // If we've encountered a list inside a block limit 501 // The last group object of the block limit element should 502 // no longer be valid. Since paragraphs after the list 503 // should belong to a different group of paragraphs before 504 // the list. (Bug #1309) 505 blockLimit.removeCustomData( 'list_group_object_' + index ); 506 507 var groupObj = element.getCustomData( 'list_group_object' ); 508 if ( groupObj ) 509 groupObj.contents.push( block ); 510 else 511 { 512 groupObj = { root : element, contents : [ block ] }; 513 listGroups.push( groupObj ); 514 CKEDITOR.dom.element.setMarker( database, element, 'list_group_object', groupObj ); 515 } 516 processedFlag = true; 517 break; 518 } 519 } 520 521 if ( processedFlag ) 522 continue; 523 524 // No list ancestor? Group by block limit, but don't mix contents from different ranges. 525 var root = blockLimit; 526 if ( root.getCustomData( 'list_group_object_' + index ) ) 527 root.getCustomData( 'list_group_object_' + index ).contents.push( block ); 528 else 529 { 530 groupObj = { root : root, contents : [ block ] }; 531 CKEDITOR.dom.element.setMarker( database, root, 'list_group_object_' + index, groupObj ); 532 listGroups.push( groupObj ); 533 } 534 } 535 } 536 537 // Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element. 538 // We either have to build lists or remove lists, for removing a list does not makes sense when we are looking 539 // at the group that's not rooted at lists. So we have three cases to handle. 540 var listsCreated = []; 541 while ( listGroups.length > 0 ) 542 { 543 groupObj = listGroups.shift(); 544 if ( this.state == CKEDITOR.TRISTATE_OFF ) 545 { 546 if ( listNodeNames[ groupObj.root.getName() ] ) 547 changeListType.call( this, editor, groupObj, database, listsCreated ); 548 else 549 createList.call( this, editor, groupObj, listsCreated ); 550 } 551 else if ( this.state == CKEDITOR.TRISTATE_ON && listNodeNames[ groupObj.root.getName() ] ) 552 removeList.call( this, editor, groupObj, database ); 553 } 554 555 // For all new lists created, merge adjacent, same type lists. 556 for ( i = 0 ; i < listsCreated.length ; i++ ) 557 { 558 listNode = listsCreated[i]; 559 var mergeSibling, listCommand = this; 560 ( mergeSibling = function( rtl ){ 561 562 var sibling = listNode[ rtl ? 563 'getPrevious' : 'getNext' ]( CKEDITOR.dom.walker.whitespaces( true ) ); 564 if ( sibling && sibling.getName && 565 sibling.getName() == listCommand.type ) 566 { 567 sibling.remove(); 568 // Move children order by merge direction.(#3820) 569 sibling.moveChildren( listNode, rtl ? true : false ); 570 } 571 } )(); 572 mergeSibling( true ); 573 } 574 575 // Clean up, restore selection and update toolbar button states. 576 CKEDITOR.dom.element.clearAllMarkers( database ); 577 selection.selectBookmarks( bookmarks ); 578 editor.focus(); 579 } 580 }; 581 582 var dtd = CKEDITOR.dtd; 583 var tailNbspRegex = /[\t\r\n ]*(?: |\xa0)$/; 584 585 function indexOfFirstChildElement( element, tagNameList ) 586 { 587 var child, 588 children = element.children, 589 length = children.length; 590 591 for ( var i = 0 ; i < length ; i++ ) 592 { 593 child = children[ i ]; 594 if ( child.name && ( child.name in tagNameList ) ) 595 return i; 596 } 597 598 return length; 599 } 600 601 function getExtendNestedListFilter( isHtmlFilter ) 602 { 603 // An element filter function that corrects nested list start in an empty 604 // list item for better displaying/outputting. (#3165) 605 return function( listItem ) 606 { 607 var children = listItem.children, 608 firstNestedListIndex = indexOfFirstChildElement( listItem, dtd.$list ), 609 firstNestedList = children[ firstNestedListIndex ], 610 nodeBefore = firstNestedList && firstNestedList.previous, 611 tailNbspmatch; 612 613 if ( nodeBefore 614 && ( nodeBefore.name && nodeBefore.name == 'br' 615 || nodeBefore.value && ( tailNbspmatch = nodeBefore.value.match( tailNbspRegex ) ) ) ) 616 { 617 var fillerNode = nodeBefore; 618 619 // Always use 'nbsp' as filler node if we found a nested list appear 620 // in front of a list item. 621 if ( !( tailNbspmatch && tailNbspmatch.index ) && fillerNode == children[ 0 ] ) 622 children[ 0 ] = ( isHtmlFilter || CKEDITOR.env.ie ) ? 623 new CKEDITOR.htmlParser.text( '\xa0' ) : 624 new CKEDITOR.htmlParser.element( 'br', {} ); 625 626 // Otherwise the filler is not needed anymore. 627 else if ( fillerNode.name == 'br' ) 628 children.splice( firstNestedListIndex - 1, 1 ); 629 else 630 fillerNode.value = fillerNode.value.replace( tailNbspRegex, '' ); 631 } 632 633 }; 634 } 635 636 var defaultListDataFilterRules = { elements : {} }; 637 for ( var i in dtd.$listItem ) 638 defaultListDataFilterRules.elements[ i ] = getExtendNestedListFilter(); 639 640 var defaultListHtmlFilterRules = { elements : {} }; 641 for ( i in dtd.$listItem ) 642 defaultListHtmlFilterRules.elements[ i ] = getExtendNestedListFilter( true ); 643 644 CKEDITOR.plugins.add( 'list', 645 { 646 init : function( editor ) 647 { 648 // Register commands. 649 var numberedListCommand = new listCommand( 'numberedlist', 'ol' ), 650 bulletedListCommand = new listCommand( 'bulletedlist', 'ul' ); 651 editor.addCommand( 'numberedlist', numberedListCommand ); 652 editor.addCommand( 'bulletedlist', bulletedListCommand ); 653 654 // Register the toolbar button. 655 editor.ui.addButton( 'NumberedList', 656 { 657 label : editor.lang.numberedlist, 658 command : 'numberedlist' 659 } ); 660 editor.ui.addButton( 'BulletedList', 661 { 662 label : editor.lang.bulletedlist, 663 command : 'bulletedlist' 664 } ); 665 666 // Register the state changing handlers. 667 editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, numberedListCommand ) ); 668 editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, bulletedListCommand ) ); 669 }, 670 671 afterInit : function ( editor ) 672 { 673 var dataProcessor = editor.dataProcessor; 674 if ( dataProcessor ) 675 { 676 dataProcessor.dataFilter.addRules( defaultListDataFilterRules ); 677 dataProcessor.htmlFilter.addRules( defaultListHtmlFilterRules ); 678 } 679 }, 680 681 requires : [ 'domiterator' ] 682 } ); 683 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |