dropdownview.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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/dropdownview
  7. */
  8. import View from '../view';
  9. import Template from '../template';
  10. import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
  11. import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
  12. /**
  13. * The dropdown view class.
  14. *
  15. * @extends module:ui/view~View
  16. */
  17. export default class DropdownView extends View {
  18. /**
  19. * @inheritDoc
  20. */
  21. constructor( locale, buttonView, panelView ) {
  22. super( locale );
  23. // Extend button's template before it's registered as a child of the dropdown because
  24. // by doing so, its #element is rendered and any post–render template extension will
  25. // not be reflected in DOM.
  26. Template.extend( buttonView.template, {
  27. attributes: {
  28. class: [
  29. 'ck-dropdown__button'
  30. ]
  31. }
  32. } );
  33. /**
  34. * Button of this dropdown view.
  35. *
  36. * @readonly
  37. * @member {ui.button.ButtonView} #buttonView
  38. */
  39. this.buttonView = buttonView;
  40. /**
  41. * Panel of this dropdown view.
  42. *
  43. * @readonly
  44. * @member {module:ui/dropdown/dropdownpanelview~DropdownPanelView} #panelView
  45. */
  46. this.panelView = panelView;
  47. /**
  48. * Controls whether the dropdown view is open, which also means its
  49. * {@link #panelView panel} is visible.
  50. *
  51. * @observable
  52. * @member {Boolean} #isOpen
  53. */
  54. this.set( 'isOpen', false );
  55. /**
  56. * Tracks information about DOM focus in the list.
  57. *
  58. * @readonly
  59. * @member {module:utils/focustracker~FocusTracker}
  60. */
  61. this.focusTracker = new FocusTracker();
  62. /**
  63. * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
  64. *
  65. * @readonly
  66. * @member {module:utils/keystrokehandler~KeystrokeHandler}
  67. */
  68. this.keystrokes = new KeystrokeHandler();
  69. this.template = new Template( {
  70. tag: 'div',
  71. attributes: {
  72. class: [
  73. 'ck-dropdown'
  74. ]
  75. },
  76. children: [
  77. buttonView,
  78. panelView
  79. ]
  80. } );
  81. // Toggle the the dropdown when it's button has been clicked.
  82. this.listenTo( buttonView, 'execute', () => {
  83. this.isOpen = !this.isOpen;
  84. } );
  85. // Toggle the visibility of the panel when the dropdown becomes open.
  86. panelView.bind( 'isVisible' ).to( this, 'isOpen' );
  87. /**
  88. * The label of the dropdown.
  89. *
  90. * @observable
  91. * @member {String} #label
  92. */
  93. /**
  94. * Controls whether the dropdown is enabled (can be clicked).
  95. *
  96. * @observable
  97. * @member {Boolean} #isEnabled
  98. */
  99. /**
  100. * Controls whether the {@link #buttonView} is "pushed".
  101. *
  102. * @observable
  103. * @member {Boolean} #isOn
  104. */
  105. /**
  106. * (Optional) Whether the label of the dropdown is visible. See {@link module:ui/button/buttonview~ButtonView#withText}.
  107. *
  108. * @observable
  109. * @member {Boolean} #withText
  110. */
  111. }
  112. /**
  113. * @inheritDoc
  114. */
  115. init() {
  116. // Listen for keystrokes coming from within #element.
  117. this.keystrokes.listenTo( this.element );
  118. // Register #element in the focus tracker.
  119. this.focusTracker.add( this.element );
  120. const closeDropdown = ( data, cancel ) => {
  121. if ( this.isOpen ) {
  122. this.buttonView.focus();
  123. this.isOpen = false;
  124. cancel();
  125. }
  126. };
  127. // Open the dropdown panel using the arrow down key, just like with return or space.
  128. this.keystrokes.set( 'arrowdown', ( data, cancel ) => {
  129. if ( !this.isOpen ) {
  130. this.isOpen = true;
  131. cancel();
  132. }
  133. } );
  134. // Block the right arrow key (until nested dropdowns are implemented).
  135. this.keystrokes.set( 'arrowright', ( data, cancel ) => {
  136. if ( this.isOpen ) {
  137. cancel();
  138. }
  139. } );
  140. // Close the dropdown using the arrow left/escape key.
  141. this.keystrokes.set( 'arrowleft', closeDropdown );
  142. this.keystrokes.set( 'esc', closeDropdown );
  143. return super.init();
  144. }
  145. /**
  146. * Focuses the {@link #buttonView}.
  147. */
  148. focus() {
  149. this.buttonView.focus();
  150. }
  151. }