plugin.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or http://ckeditor.com/license
  4. */
  5. CKEDITOR.plugins.add( 'listblock', {
  6. requires: 'panel',
  7. onLoad: function() {
  8. var list = CKEDITOR.addTemplate( 'panel-list', '<ul role="presentation" class="cke_panel_list">{items}</ul>' ),
  9. listItem = CKEDITOR.addTemplate( 'panel-list-item', '<li id="{id}" class="cke_panel_listItem" role=presentation>' +
  10. '<a id="{id}_option" _cke_focus=1 hidefocus=true' +
  11. ' title="{title}"' +
  12. ' href="javascript:void(\'{val}\')" ' +
  13. ' {onclick}="CKEDITOR.tools.callFunction({clickFn},\'{val}\'); return false;"' + // #188
  14. ' role="option">' +
  15. '{text}' +
  16. '</a>' +
  17. '</li>' ),
  18. listGroup = CKEDITOR.addTemplate( 'panel-list-group', '<h1 id="{id}" class="cke_panel_grouptitle" role="presentation" >{label}</h1>' ),
  19. reSingleQuote = /\'/g,
  20. escapeSingleQuotes = function( str ) {
  21. return str.replace( reSingleQuote, '\\\'' );
  22. };
  23. CKEDITOR.ui.panel.prototype.addListBlock = function( name, definition ) {
  24. return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), definition ) );
  25. };
  26. CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass( {
  27. base: CKEDITOR.ui.panel.block,
  28. $: function( blockHolder, blockDefinition ) {
  29. blockDefinition = blockDefinition || {};
  30. var attribs = blockDefinition.attributes || ( blockDefinition.attributes = {} );
  31. ( this.multiSelect = !!blockDefinition.multiSelect ) && ( attribs[ 'aria-multiselectable' ] = true );
  32. // Provide default role of 'listbox'.
  33. !attribs.role && ( attribs.role = 'listbox' );
  34. // Call the base contructor.
  35. this.base.apply( this, arguments );
  36. // Set the proper a11y attributes.
  37. this.element.setAttribute( 'role', attribs.role );
  38. var keys = this.keys;
  39. keys[ 40 ] = 'next'; // ARROW-DOWN
  40. keys[ 9 ] = 'next'; // TAB
  41. keys[ 38 ] = 'prev'; // ARROW-UP
  42. keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
  43. keys[ 32 ] = CKEDITOR.env.ie ? 'mouseup' : 'click'; // SPACE
  44. CKEDITOR.env.ie && ( keys[ 13 ] = 'mouseup' ); // Manage ENTER, since onclick is blocked in IE (#8041).
  45. this._.pendingHtml = [];
  46. this._.pendingList = [];
  47. this._.items = {};
  48. this._.groups = {};
  49. },
  50. _: {
  51. close: function() {
  52. if ( this._.started ) {
  53. var output = list.output( { items: this._.pendingList.join( '' ) } );
  54. this._.pendingList = [];
  55. this._.pendingHtml.push( output );
  56. delete this._.started;
  57. }
  58. },
  59. getClick: function() {
  60. if ( !this._.click ) {
  61. this._.click = CKEDITOR.tools.addFunction( function( value ) {
  62. var marked = this.toggle( value );
  63. if ( this.onClick )
  64. this.onClick( value, marked );
  65. }, this );
  66. }
  67. return this._.click;
  68. }
  69. },
  70. proto: {
  71. add: function( value, html, title ) {
  72. var id = CKEDITOR.tools.getNextId();
  73. if ( !this._.started ) {
  74. this._.started = 1;
  75. this._.size = this._.size || 0;
  76. }
  77. this._.items[ value ] = id;
  78. var data = {
  79. id: id,
  80. val: escapeSingleQuotes( CKEDITOR.tools.htmlEncodeAttr( value ) ),
  81. onclick: CKEDITOR.env.ie ? 'onclick="return false;" onmouseup' : 'onclick',
  82. clickFn: this._.getClick(),
  83. title: CKEDITOR.tools.htmlEncodeAttr( title || value ),
  84. text: html || value
  85. };
  86. this._.pendingList.push( listItem.output( data ) );
  87. },
  88. startGroup: function( title ) {
  89. this._.close();
  90. var id = CKEDITOR.tools.getNextId();
  91. this._.groups[ title ] = id;
  92. this._.pendingHtml.push( listGroup.output( { id: id, label: title } ) );
  93. },
  94. commit: function() {
  95. this._.close();
  96. this.element.appendHtml( this._.pendingHtml.join( '' ) );
  97. delete this._.size;
  98. this._.pendingHtml = [];
  99. },
  100. toggle: function( value ) {
  101. var isMarked = this.isMarked( value );
  102. if ( isMarked )
  103. this.unmark( value );
  104. else
  105. this.mark( value );
  106. return !isMarked;
  107. },
  108. hideGroup: function( groupTitle ) {
  109. var group = this.element.getDocument().getById( this._.groups[ groupTitle ] ),
  110. list = group && group.getNext();
  111. if ( group ) {
  112. group.setStyle( 'display', 'none' );
  113. if ( list && list.getName() == 'ul' )
  114. list.setStyle( 'display', 'none' );
  115. }
  116. },
  117. hideItem: function( value ) {
  118. this.element.getDocument().getById( this._.items[ value ] ).setStyle( 'display', 'none' );
  119. },
  120. showAll: function() {
  121. var items = this._.items,
  122. groups = this._.groups,
  123. doc = this.element.getDocument();
  124. for ( var value in items ) {
  125. doc.getById( items[ value ] ).setStyle( 'display', '' );
  126. }
  127. for ( var title in groups ) {
  128. var group = doc.getById( groups[ title ] ),
  129. list = group.getNext();
  130. group.setStyle( 'display', '' );
  131. if ( list && list.getName() == 'ul' )
  132. list.setStyle( 'display', '' );
  133. }
  134. },
  135. mark: function( value ) {
  136. if ( !this.multiSelect )
  137. this.unmarkAll();
  138. var itemId = this._.items[ value ],
  139. item = this.element.getDocument().getById( itemId );
  140. item.addClass( 'cke_selected' );
  141. this.element.getDocument().getById( itemId + '_option' ).setAttribute( 'aria-selected', true );
  142. this.onMark && this.onMark( item );
  143. },
  144. unmark: function( value ) {
  145. var doc = this.element.getDocument(),
  146. itemId = this._.items[ value ],
  147. item = doc.getById( itemId );
  148. item.removeClass( 'cke_selected' );
  149. doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
  150. this.onUnmark && this.onUnmark( item );
  151. },
  152. unmarkAll: function() {
  153. var items = this._.items,
  154. doc = this.element.getDocument();
  155. for ( var value in items ) {
  156. var itemId = items[ value ];
  157. doc.getById( itemId ).removeClass( 'cke_selected' );
  158. doc.getById( itemId + '_option' ).removeAttribute( 'aria-selected' );
  159. }
  160. this.onUnmark && this.onUnmark();
  161. },
  162. isMarked: function( value ) {
  163. return this.element.getDocument().getById( this._.items[ value ] ).hasClass( 'cke_selected' );
  164. },
  165. focus: function( value ) {
  166. this._.focusIndex = -1;
  167. var links = this.element.getElementsByTag( 'a' ),
  168. link,
  169. selected,
  170. i = -1;
  171. if ( value ) {
  172. selected = this.element.getDocument().getById( this._.items[ value ] ).getFirst();
  173. while ( ( link = links.getItem( ++i ) ) ) {
  174. if ( link.equals( selected ) ) {
  175. this._.focusIndex = i;
  176. break;
  177. }
  178. }
  179. }
  180. else {
  181. this.element.focus();
  182. }
  183. selected && setTimeout( function() {
  184. selected.focus();
  185. }, 0 );
  186. }
  187. }
  188. } );
  189. }
  190. } );