horizontallinecommand.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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 horizontal-line/horizontallinecommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';
  10. /**
  11. * The horizontal line command.
  12. *
  13. * The command is registered by {@link module:horizontal-line/horizontallineediting~HorizontalLineEditing} as `'horizontalLine'`.
  14. *
  15. * To insert a horizontal line at the current selection, execute the command:
  16. *
  17. * editor.execute( 'horizontalLine' );
  18. *
  19. * @extends module:core/command~Command
  20. */
  21. export default class HorizontalLineCommand extends Command {
  22. /**
  23. * @inheritDoc
  24. */
  25. refresh() {
  26. this.isEnabled = isHorizontalLineAllowed( this.editor.model );
  27. }
  28. /**
  29. * Executes the command.
  30. *
  31. * @fires execute
  32. */
  33. execute() {
  34. const model = this.editor.model;
  35. model.change( writer => {
  36. const horizontalElement = writer.createElement( 'horizontalLine' );
  37. model.insertContent( horizontalElement );
  38. let nextElement = horizontalElement.nextSibling;
  39. // Check whether an element next to the inserted horizontal line is defined and can contain a text.
  40. const canSetSelection = nextElement && model.schema.checkChild( nextElement, '$text' );
  41. // If the element is missing, but a paragraph could be inserted next to the horizontal line, let's add it.
  42. if ( !canSetSelection && model.schema.checkChild( horizontalElement.parent, 'paragraph' ) ) {
  43. nextElement = writer.createElement( 'paragraph' );
  44. model.insertContent( nextElement, writer.createPositionAfter( horizontalElement ) );
  45. }
  46. // Put the selection inside the element, at the beginning.
  47. if ( nextElement ) {
  48. writer.setSelection( nextElement, 0 );
  49. }
  50. } );
  51. }
  52. }
  53. // Checks if the `horizontalLine` element can be inserted at the current model selection.
  54. //
  55. // @param {module:engine/model/model~Model} model
  56. // @returns {Boolean}
  57. function isHorizontalLineAllowed( model ) {
  58. const schema = model.schema;
  59. const selection = model.document.selection;
  60. return isHorizontalLineAllowedInParent( selection, schema, model ) &&
  61. !checkSelectionOnObject( selection, schema );
  62. }
  63. // Checks if a horizontal line is allowed by the schema in the optimal insertion parent.
  64. //
  65. // @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
  66. // @param {module:engine/model/schema~Schema} schema
  67. // @param {module:engine/model/model~Model} model Model instance.
  68. // @returns {Boolean}
  69. function isHorizontalLineAllowedInParent( selection, schema, model ) {
  70. const parent = getInsertHorizontalLineParent( selection, model );
  71. return schema.checkChild( parent, 'horizontalLine' );
  72. }
  73. // Checks if the selection is on object.
  74. //
  75. // @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
  76. // @param {module:engine/model/schema~Schema} schema
  77. // @returns {Boolean}
  78. function checkSelectionOnObject( selection, schema ) {
  79. const selectedElement = selection.getSelectedElement();
  80. return selectedElement && schema.isObject( selectedElement );
  81. }
  82. // Returns a node that will be used to insert a horizontal line with `model.insertContent` to check if the horizontal line can be
  83. // placed there.
  84. //
  85. // @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
  86. // @param {module:engine/model/model~Model} model Model instance.
  87. // @returns {module:engine/model/element~Element}
  88. function getInsertHorizontalLineParent( selection, model ) {
  89. const insertAt = findOptimalInsertionPosition( selection, model );
  90. const parent = insertAt.parent;
  91. if ( parent.isEmpty && !parent.is( 'element', '$root' ) ) {
  92. return parent.parent;
  93. }
  94. return parent;
  95. }