createbuttondropdown.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module ui/dropdown/button/createbuttondropdown
  7. */
  8. import createDropdown from '../createdropdown';
  9. import ToolbarView from '../../toolbar/toolbarview';
  10. import { closeDropdownOnBlur, closeDropdownOnExecute, focusDropdownContentsOnArrows } from '../utils';
  11. import '../../../theme/components/dropdown/buttondropdown.css';
  12. /**
  13. * Creates an instance of {@link module:ui/dropdown/button/buttondropdownview~ButtonDropdownView} class using
  14. * a provided {@link module:ui/dropdown/button/buttondropdownmodel~ButtonDropdownModel}.
  15. *
  16. * const buttons = [];
  17. *
  18. * buttons.push( new ButtonView() );
  19. * buttons.push( editor.ui.componentFactory.get( 'someButton' ) );
  20. *
  21. * const model = new Model( {
  22. * label: 'A button dropdown',
  23. * isVertical: true,
  24. * buttons
  25. * } );
  26. *
  27. * const dropdown = createButtonDropdown( model, locale );
  28. *
  29. * // Will render a vertical button dropdown labeled "A button dropdown"
  30. * // with a button group in the panel containing two buttons.
  31. * dropdown.render()
  32. * document.body.appendChild( dropdown.element );
  33. *
  34. * The model instance remains in control of the dropdown after it has been created. E.g. changes to the
  35. * {@link module:ui/dropdown/dropdownmodel~DropdownModel#label `model.label`} will be reflected in the
  36. * dropdown button's {@link module:ui/button/buttonview~ButtonView#label} attribute and in DOM.
  37. *
  38. * See {@link module:ui/dropdown/createdropdown~createDropdown}.
  39. *
  40. * @param {module:ui/dropdown/button/buttondropdownmodel~ButtonDropdownModel} model Model of the list dropdown.
  41. * @param {module:utils/locale~Locale} locale The locale instance.
  42. * @returns {module:ui/dropdown/button/buttondropdownview~ButtonDropdownView} The button dropdown view instance.
  43. * @returns {module:ui/dropdown/dropdownview~DropdownView}
  44. */
  45. export default function createButtonDropdown( model, locale ) {
  46. // Make disabled when all buttons are disabled
  47. model.bind( 'isEnabled' ).to(
  48. // Bind to #isEnabled of each command...
  49. ...getBindingTargets( model.buttons, 'isEnabled' ),
  50. // ...and set it true if any command #isEnabled is true.
  51. ( ...areEnabled ) => areEnabled.some( isEnabled => isEnabled )
  52. );
  53. // If defined `staticIcon` use the `defautlIcon` without binding it to active a button.
  54. if ( model.staticIcon ) {
  55. model.bind( 'icon' ).to( model, 'defaultIcon' );
  56. } else {
  57. // Make dropdown icon as any active button.
  58. model.bind( 'icon' ).to(
  59. // Bind to #isOn of each button...
  60. ...getBindingTargets( model.buttons, 'isOn' ),
  61. // ...and chose the title of the first one which #isOn is true.
  62. ( ...areActive ) => {
  63. const index = areActive.findIndex( value => value );
  64. // If none of the commands is active, display either defaultIcon or first button icon.
  65. if ( index < 0 && model.defaultIcon ) {
  66. return model.defaultIcon;
  67. }
  68. return model.buttons[ index < 0 ? 0 : index ].icon;
  69. }
  70. );
  71. }
  72. const dropdownView = createDropdown( model, locale );
  73. const toolbarView = dropdownView.toolbarView = new ToolbarView();
  74. toolbarView.bind( 'isVertical', 'className' ).to( model, 'isVertical', 'toolbarClassName' );
  75. model.buttons.map( view => toolbarView.items.add( view ) );
  76. dropdownView.extendTemplate( {
  77. attributes: {
  78. class: [ 'ck-buttondropdown' ]
  79. }
  80. } );
  81. dropdownView.panelView.children.add( toolbarView );
  82. closeDropdownOnBlur( dropdownView );
  83. closeDropdownOnExecute( dropdownView, toolbarView.items );
  84. focusDropdownContentsOnArrows( dropdownView, toolbarView );
  85. return dropdownView;
  86. }
  87. // Returns an array of binding components for
  88. // {@link module:utils/observablemixin~Observable#bind} from a set of iterable
  89. // buttons.
  90. //
  91. // @private
  92. // @param {Iterable.<module:ui/button/buttonview~ButtonView>} buttons
  93. // @param {String} attribute
  94. // @returns {Array.<String>}
  95. function getBindingTargets( buttons, attribute ) {
  96. return Array.prototype.concat( ...buttons.map( button => [ button, attribute ] ) );
  97. }