PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/sites/all/libraries/ckeditor/_source/plugins/list/plugin.js

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