headingui.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module heading/headingui
  7. */
  8. import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  9. import Model from '@ckeditor/ckeditor5-ui/src/model';
  10. import { createDropdown, addListToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
  11. import Collection from '@ckeditor/ckeditor5-utils/src/collection';
  12. import '../theme/heading.css';
  13. /**
  14. * The headings UI feature. It introduces the `headings` drop-down.
  15. *
  16. * @extends module:core/plugin~Plugin
  17. */
  18. export default class HeadingUI extends Plugin {
  19. /**
  20. * @inheritDoc
  21. */
  22. init() {
  23. const editor = this.editor;
  24. const t = editor.t;
  25. const options = this._getLocalizedOptions();
  26. const defaultTitle = t( 'Choose heading' );
  27. const dropdownTooltip = t( 'Heading' );
  28. // Register UI component.
  29. editor.ui.componentFactory.add( 'heading', locale => {
  30. const titles = {};
  31. const dropdownItems = new Collection();
  32. const headingCommand = editor.commands.get( 'heading' );
  33. const paragraphCommand = editor.commands.get( 'paragraph' );
  34. const commands = [ headingCommand ];
  35. for ( const option of options ) {
  36. const itemModel = new Model( {
  37. label: option.title,
  38. class: option.class
  39. } );
  40. if ( option.model === 'paragraph' ) {
  41. itemModel.bind( 'isActive' ).to( paragraphCommand, 'value' );
  42. itemModel.set( 'commandName', 'paragraph' );
  43. commands.push( paragraphCommand );
  44. } else {
  45. itemModel.bind( 'isActive' ).to( headingCommand, 'value', value => value === option.model );
  46. itemModel.set( {
  47. commandName: 'heading',
  48. commandValue: option.model
  49. } );
  50. }
  51. // Add the option to the collection.
  52. dropdownItems.add( itemModel );
  53. titles[ option.model ] = option.title;
  54. }
  55. const dropdownView = createDropdown( locale );
  56. addListToDropdown( dropdownView, dropdownItems );
  57. dropdownView.buttonView.set( {
  58. isOn: false,
  59. withText: true,
  60. tooltip: dropdownTooltip
  61. } );
  62. dropdownView.extendTemplate( {
  63. attributes: {
  64. class: [
  65. 'ck-heading-dropdown'
  66. ]
  67. }
  68. } );
  69. dropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {
  70. return areEnabled.some( isEnabled => isEnabled );
  71. } );
  72. dropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( value, para ) => {
  73. const whichModel = value || para && 'paragraph';
  74. // If none of the commands is active, display default title.
  75. return titles[ whichModel ] ? titles[ whichModel ] : defaultTitle;
  76. } );
  77. // Execute command when an item from the dropdown is selected.
  78. this.listenTo( dropdownView, 'execute', evt => {
  79. editor.execute( evt.source.commandName );
  80. editor.editing.view.focus();
  81. } );
  82. return dropdownView;
  83. } );
  84. }
  85. /**
  86. * Returns heading options as defined in `config.heading.options` but processed to consider
  87. * editor localization, i.e. to display {@link module:heading/heading~HeadingOption}
  88. * in the correct language.
  89. *
  90. * Note: The reason behind this method is that there's no way to use {@link module:utils/locale~Locale#t}
  91. * when the user config is defined because the editor does not exist yet.
  92. *
  93. * @private
  94. * @returns {Array.<module:heading/heading~HeadingOption>}.
  95. */
  96. _getLocalizedOptions() {
  97. const editor = this.editor;
  98. const t = editor.t;
  99. const localizedTitles = {
  100. Paragraph: t( 'Paragraph' ),
  101. 'Heading 1': t( 'Heading 1' ),
  102. 'Heading 2': t( 'Heading 2' ),
  103. 'Heading 3': t( 'Heading 3' )
  104. };
  105. return editor.config.get( 'heading.options' ).map( option => {
  106. const title = localizedTitles[ option.title ];
  107. if ( title && title != option.title ) {
  108. // Clone the option to avoid altering the original `config.heading.options`.
  109. option = Object.assign( {}, option, { title } );
  110. }
  111. return option;
  112. } );
  113. }
  114. }