8
0

indentblockcommand.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module indent-block/indentblockcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import first from '@ckeditor/ckeditor5-utils/src/first';
  10. /**
  11. * The block indentation feature.
  12. *
  13. * @extends module:core/plugin~Plugin
  14. */
  15. export default class IndentBlockCommand extends Command {
  16. /**
  17. * Creates an instance of the command.
  18. *
  19. * @param {module:core/editor/editor~Editor} editor Editor instance.
  20. * @param {Object} config.
  21. */
  22. constructor( editor, { classes, offset, unit, direction } ) {
  23. super( editor );
  24. this.classes = classes;
  25. this.offset = offset;
  26. this.unit = unit;
  27. this.direction = direction == 'forward' ? 1 : -1;
  28. this.useClasses = !!classes.length;
  29. }
  30. /**
  31. * @inheritDoc
  32. */
  33. refresh() {
  34. this.isEnabled = this._checkEnabled();
  35. }
  36. /**
  37. * Indents or outdents (depends on the {@link #constructor}'s `indentDirection` parameter) selected list items.
  38. *
  39. * @fires execute
  40. */
  41. execute() {
  42. const model = this.editor.model;
  43. const doc = model.document;
  44. const itemsToChange = Array.from( doc.selection.getSelectedBlocks() );
  45. model.change( writer => {
  46. for ( const item of itemsToChange ) {
  47. // eslint-disable-next-line no-undef
  48. console.log( 'indent block', item );
  49. const currentIndent = item.getAttribute( 'indent' );
  50. let newIndent;
  51. // TODO: split potential:
  52. if ( this.useClasses ) {
  53. newIndent = this._getIndentClasses( currentIndent );
  54. } else {
  55. newIndent = this._getIndentOffset( currentIndent );
  56. }
  57. if ( newIndent ) {
  58. writer.setAttribute( 'indent', newIndent, item );
  59. } else {
  60. writer.removeAttribute( 'indent', item );
  61. }
  62. }
  63. } );
  64. }
  65. _getIndentOffset( currentIndent ) {
  66. const currentOffset = parseFloat( currentIndent || 0 );
  67. const offsetToSet = currentOffset + this.direction * this.offset;
  68. return offsetToSet && offsetToSet > 0 ? offsetToSet + this.unit : undefined;
  69. }
  70. _getIndentClasses( currentIndent ) {
  71. const currentIndex = this.classes.indexOf( currentIndent );
  72. return this.classes[ currentIndex + this.direction ];
  73. }
  74. /**
  75. * Checks whether the command can be enabled in the current context.
  76. *
  77. * @private
  78. * @returns {Boolean} Whether the command should be enabled.
  79. */
  80. _checkEnabled() {
  81. // Check whether any of position's ancestor is a list item.
  82. const editor = this.editor;
  83. const model = editor.model;
  84. const block = first( model.document.selection.getSelectedBlocks() );
  85. // If selection is not in a list item, the command is disabled.
  86. if ( !block || !model.schema.checkAttribute( block, 'indent' ) ) {
  87. return false;
  88. }
  89. const currentIndent = block.getAttribute( 'indent' );
  90. // TODO: split potential.
  91. if ( this.useClasses ) {
  92. return this._checkEnabledClasses( currentIndent );
  93. } else {
  94. return this._checkEnabledOffset( currentIndent );
  95. }
  96. }
  97. _checkEnabledOffset( currentIndent ) {
  98. const currentOffset = parseFloat( currentIndent || 0 );
  99. // is forward
  100. if ( this.direction > 0 ) {
  101. return true;
  102. } else {
  103. return currentOffset > 0;
  104. }
  105. }
  106. _checkEnabledClasses( currentIndent ) {
  107. const currentIndex = this.classes.indexOf( currentIndent );
  108. if ( this.direction > 0 ) {
  109. return currentIndex < this.classes.length - 1;
  110. } else {
  111. return currentIndex >= 0 && currentIndex < this.classes.length;
  112. }
  113. }
  114. }