8
0

createbuttondropdown.js 4.2 KB

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