8
0

splitbuttonview.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module ui/dropdown/button/splitbuttonview
  7. */
  8. import View from '../../view';
  9. import ButtonView from '../../button/buttonview';
  10. import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
  11. import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
  12. import dropdownArrowIcon from '../../../theme/icons/dropdown-arrow.svg';
  13. import '../../../theme/components/dropdown/splitbutton.css';
  14. /**
  15. * The split button view class.
  16. *
  17. * const view = new SplitButtonView();
  18. *
  19. * view.set( {
  20. * label: 'A button',
  21. * keystroke: 'Ctrl+B',
  22. * tooltip: true
  23. * } );
  24. *
  25. * view.render();
  26. *
  27. * document.body.append( view.element );
  28. *
  29. * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.
  30. *
  31. * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton
  32. * @extends module:ui/view~View
  33. */
  34. export default class SplitButtonView extends View {
  35. /**
  36. * @inheritDoc
  37. */
  38. constructor( locale ) {
  39. super( locale );
  40. const bind = this.bindTemplate;
  41. // Implement the Button interface.
  42. this.set( 'icon' );
  43. this.set( 'isEnabled', true );
  44. this.set( 'isOn', false );
  45. this.set( 'isVisible', true );
  46. this.set( 'keystroke' );
  47. this.set( 'label' );
  48. this.set( 'tabindex', -1 );
  49. this.set( 'tooltip' );
  50. this.set( 'tooltipPosition', 's' );
  51. this.set( 'type', 'button' );
  52. this.set( 'withText', false );
  53. /**
  54. * Collection of the child views inside of the split button {@link #element}.
  55. *
  56. * @readonly
  57. * @member {module:ui/viewcollection~ViewCollection}
  58. */
  59. this.children = this.createCollection();
  60. /**
  61. * A main button of split button.
  62. *
  63. * @readonly
  64. * @member {module:ui/button/buttonview~ButtonView}
  65. */
  66. this.actionView = this._createActionView();
  67. /**
  68. * A secondary button of split button that opens dropdown.
  69. *
  70. * @readonly
  71. * @member {module:ui/button/buttonview~ButtonView}
  72. */
  73. this.arrowView = this._createArrowView();
  74. /**
  75. * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages
  76. * keystrokes of the split button:
  77. *
  78. * * <kbd>▶</kbd> moves focus to arrow view when action view is focused,
  79. * * <kbd>◀</kbd> moves focus to action view when arrow view is focused.
  80. *
  81. * @readonly
  82. * @member {module:utils/keystrokehandler~KeystrokeHandler}
  83. */
  84. this.keystrokes = new KeystrokeHandler();
  85. /**
  86. * Tracks information about DOM focus in the dropdown.
  87. *
  88. * @readonly
  89. * @member {module:utils/focustracker~FocusTracker}
  90. */
  91. this.focusTracker = new FocusTracker();
  92. this.setTemplate( {
  93. tag: 'div',
  94. attributes: {
  95. class: [
  96. 'ck',
  97. 'ck-splitbutton',
  98. bind.if( 'isVisible', 'ck-hidden', value => !value ),
  99. this.arrowView.bindTemplate.if( 'isOn', 'ck-splitbutton_open' )
  100. ]
  101. },
  102. children: this.children
  103. } );
  104. }
  105. /**
  106. * @inheritDoc
  107. */
  108. render() {
  109. super.render();
  110. this.children.add( this.actionView );
  111. this.children.add( this.arrowView );
  112. this.focusTracker.add( this.actionView.element );
  113. this.focusTracker.add( this.arrowView.element );
  114. this.keystrokes.listenTo( this.element );
  115. // Overrides toolbar focus cycling behavior.
  116. this.keystrokes.set( 'arrowright', ( evt, cancel ) => {
  117. if ( this.focusTracker.focusedElement === this.actionView.element ) {
  118. this.arrowView.focus();
  119. cancel();
  120. }
  121. } );
  122. // Overrides toolbar focus cycling behavior.
  123. this.keystrokes.set( 'arrowleft', ( evt, cancel ) => {
  124. if ( this.focusTracker.focusedElement === this.arrowView.element ) {
  125. this.actionView.focus();
  126. cancel();
  127. }
  128. } );
  129. }
  130. /**
  131. * Focuses the {@link #actionView#element} of the action part of split button.
  132. */
  133. focus() {
  134. this.actionView.focus();
  135. }
  136. /**
  137. * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #actionView} and binds it with main split button
  138. * attributes.
  139. *
  140. * @private
  141. * @returns {module:ui/button/buttonview~ButtonView}
  142. */
  143. _createActionView() {
  144. const actionView = new ButtonView();
  145. actionView.bind(
  146. 'icon',
  147. 'isEnabled',
  148. 'isOn',
  149. 'keystroke',
  150. 'label',
  151. 'tabindex',
  152. 'tooltip',
  153. 'tooltipPosition',
  154. 'type',
  155. 'withText'
  156. ).to( this );
  157. actionView.extendTemplate( {
  158. attributes: {
  159. class: 'ck-splitbutton__action'
  160. }
  161. } );
  162. actionView.delegate( 'execute' ).to( this );
  163. return actionView;
  164. }
  165. /**
  166. * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #arrowView} and binds it with main split button
  167. * attributes.
  168. *
  169. * @private
  170. * @returns {module:ui/button/buttonview~ButtonView}
  171. */
  172. _createArrowView() {
  173. const arrowView = new ButtonView();
  174. arrowView.icon = dropdownArrowIcon;
  175. arrowView.extendTemplate( {
  176. attributes: {
  177. class: 'ck-splitbutton__arrow',
  178. 'aria-haspopup': true
  179. }
  180. } );
  181. arrowView.bind( 'isEnabled' ).to( this );
  182. arrowView.delegate( 'execute' ).to( this, 'open' );
  183. return arrowView;
  184. }
  185. }