8
0

insertoperation.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module engine/model/operation/insertoperation
  7. */
  8. import Operation from './operation';
  9. import Position from '../position';
  10. import NodeList from '../nodelist';
  11. import RemoveOperation from './removeoperation';
  12. import { insert, normalizeNodes } from '../writer';
  13. import Text from '../text';
  14. import Element from '../element';
  15. /**
  16. * Operation to insert one or more nodes at given position in the model.
  17. *
  18. * @extends module:engine/model/operation/operation~Operation
  19. */
  20. export default class InsertOperation extends Operation {
  21. /**
  22. * Creates an insert operation.
  23. *
  24. * @param {module:engine/model/position~Position} position Position of insertion.
  25. * @param {module:engine/model/node~NodeSet} nodes The list of nodes to be inserted.
  26. * @param {Number} baseVersion {@link module:engine/model/document~Document#version} on which operation can be applied.
  27. */
  28. constructor( position, nodes, baseVersion ) {
  29. super( baseVersion );
  30. /**
  31. * Position of insertion.
  32. *
  33. * @readonly
  34. * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position
  35. */
  36. this.position = Position.createFromPosition( position );
  37. /**
  38. * List of nodes to insert.
  39. *
  40. * @readonly
  41. * @member {module:engine/model/nodelist~NodeList} module:engine/model/operation/insertoperation~InsertOperation#nodeList
  42. */
  43. this.nodes = new NodeList( normalizeNodes( nodes ) );
  44. }
  45. /**
  46. * @inheritDoc
  47. */
  48. get type() {
  49. return 'insert';
  50. }
  51. /**
  52. * Creates and returns an operation that has the same parameters as this operation.
  53. *
  54. * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.
  55. */
  56. clone() {
  57. const nodes = new NodeList( [ ...this.nodes ].map( node => node.clone( true ) ) );
  58. return new InsertOperation( this.position, nodes, this.baseVersion );
  59. }
  60. /**
  61. * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
  62. *
  63. * @returns {module:engine/model/operation/removeoperation~RemoveOperation}
  64. */
  65. getReversed() {
  66. const graveyard = this.position.root.document.graveyard;
  67. const gyPosition = new Position( graveyard, [ 0 ] );
  68. return new RemoveOperation( this.position, this.nodes.maxOffset, gyPosition, this.baseVersion + 1 );
  69. }
  70. /**
  71. * @inheritDoc
  72. */
  73. _execute() {
  74. // What happens here is that we want original nodes be passed to writer because we want original nodes
  75. // to be inserted to the model. But in InsertOperation, we want to keep those nodes as they were added
  76. // to the operation, not modified. For example, text nodes can get merged or cropped while Elements can
  77. // get children. It is important that InsertOperation has the copy of original nodes in intact state.
  78. const originalNodes = this.nodes;
  79. this.nodes = new NodeList( [ ...originalNodes ].map( node => node.clone( true ) ) );
  80. const range = insert( this.position, originalNodes );
  81. return { range };
  82. }
  83. /**
  84. * @inheritDoc
  85. */
  86. static get className() {
  87. return 'engine.model.operation.InsertOperation';
  88. }
  89. /**
  90. * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.
  91. *
  92. * @param {Object} json Deserialized JSON object.
  93. * @param {module:engine/model/document~Document} document Document on which this operation will be applied.
  94. * @returns {module:engine/model/operation/insertoperation~InsertOperation}
  95. */
  96. static fromJSON( json, document ) {
  97. const children = [];
  98. for ( const child of json.nodes ) {
  99. if ( child.name ) {
  100. // If child has name property, it is an Element.
  101. children.push( Element.fromJSON( child ) );
  102. } else {
  103. // Otherwise, it is a Text node.
  104. children.push( Text.fromJSON( child ) );
  105. }
  106. }
  107. return new InsertOperation( Position.fromJSON( json.position, document ), children, json.baseVersion );
  108. }
  109. }