dropdownview.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. /**
  89. * @inheritDoc
  90. */
  91. init() {
  92. // Listen for keystrokes coming from within #element.
  93. this.keystrokes.listenTo( this.element );
  94. // Register #element in the focus tracker.
  95. this.focusTracker.add( this.element );
  96. const closeDropdown = ( data, cancel ) => {
  97. if ( this.isOpen ) {
  98. this.buttonView.focus();
  99. this.isOpen = false;
  100. cancel();
  101. }
  102. };
  103. // Open the dropdown panel using the arrow down key, just like with return or space.
  104. this.keystrokes.set( 'arrowdown', ( data, cancel ) => {
  105. // Don't open if the dropdown is disabled or already open.
  106. if ( this.buttonView.isEnabled && !this.isOpen ) {
  107. this.isOpen = true;
  108. cancel();
  109. }
  110. } );
  111. // Block the right arrow key (until nested dropdowns are implemented).
  112. this.keystrokes.set( 'arrowright', ( data, cancel ) => {
  113. if ( this.isOpen ) {
  114. cancel();
  115. }
  116. } );
  117. // Close the dropdown using the arrow left/escape key.
  118. this.keystrokes.set( 'arrowleft', closeDropdown );
  119. this.keystrokes.set( 'esc', closeDropdown );
  120. return super.init();
  121. }
  122. /**
  123. * Focuses the {@link #buttonView}.
  124. */
  125. focus() {
  126. this.buttonView.focus();
  127. }
  128. }