insertoperation.js 3.6 KB

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