8
0

alignmentcommand.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module alignment/alignmentcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import first from '@ckeditor/ckeditor5-utils/src/first';
  10. import { isDefault } from './utils';
  11. const ALIGNMENT = 'alignment';
  12. /**
  13. * The alignment command plugin.
  14. *
  15. * @extends module:core/command~Command
  16. */
  17. export default class AlignmentCommand extends Command {
  18. /**
  19. * @inheritDoc
  20. */
  21. refresh() {
  22. const editor = this.editor;
  23. const locale = editor.locale;
  24. const firstBlock = first( this.editor.model.document.selection.getSelectedBlocks() );
  25. // As first check whether to enable or disable the command as the value will always be false if the command cannot be enabled.
  26. this.isEnabled = !!firstBlock && this._canBeAligned( firstBlock );
  27. /**
  28. * A value of the current block's alignment.
  29. *
  30. * @observable
  31. * @readonly
  32. * @member {String} #value
  33. */
  34. if ( this.isEnabled && firstBlock.hasAttribute( 'alignment' ) ) {
  35. this.value = firstBlock.getAttribute( 'alignment' );
  36. } else {
  37. this.value = locale.contentLanguageDirection === 'rtl' ? 'right' : 'left';
  38. }
  39. }
  40. /**
  41. * Executes the command. Applies the alignment `value` to the selected blocks.
  42. * If no `value` is passed, the `value` is the default one or it is equal to the currently selected block's alignment attribute,
  43. * the command will remove the attribute from the selected blocks.
  44. *
  45. * @param {Object} [options] Options for the executed command.
  46. * @param {String} [options.value] The value to apply.
  47. * @fires execute
  48. */
  49. execute( options = {} ) {
  50. const editor = this.editor;
  51. const locale = editor.locale;
  52. const model = editor.model;
  53. const doc = model.document;
  54. const value = options.value;
  55. model.change( writer => {
  56. // Get only those blocks from selected that can have alignment set
  57. const blocks = Array.from( doc.selection.getSelectedBlocks() ).filter( block => this._canBeAligned( block ) );
  58. const currentAlignment = blocks[ 0 ].getAttribute( 'alignment' );
  59. // Remove alignment attribute if current alignment is:
  60. // - default (should not be stored in model as it will bloat model data)
  61. // - equal to currently set
  62. // - or no value is passed - denotes default alignment.
  63. const removeAlignment = isDefault( value, locale ) || currentAlignment === value || !value;
  64. if ( removeAlignment ) {
  65. removeAlignmentFromSelection( blocks, writer );
  66. } else {
  67. setAlignmentOnSelection( blocks, writer, value );
  68. }
  69. } );
  70. }
  71. /**
  72. * Checks whether a block can have alignment set.
  73. *
  74. * @private
  75. * @param {module:engine/model/element~Element} block The block to be checked.
  76. * @returns {Boolean}
  77. */
  78. _canBeAligned( block ) {
  79. return this.editor.model.schema.checkAttribute( block, ALIGNMENT );
  80. }
  81. }
  82. // Removes the alignment attribute from blocks.
  83. // @private
  84. function removeAlignmentFromSelection( blocks, writer ) {
  85. for ( const block of blocks ) {
  86. writer.removeAttribute( ALIGNMENT, block );
  87. }
  88. }
  89. // Sets the alignment attribute on blocks.
  90. // @private
  91. function setAlignmentOnSelection( blocks, writer, alignment ) {
  92. for ( const block of blocks ) {
  93. writer.setAttribute( ALIGNMENT, alignment, block );
  94. }
  95. }