transaction-base.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. CKEDITOR.define( [ 'ckeditorerror' ], ( CKEditorError ) => {
  7. /**
  8. * The transaction class groups document changes (deltas). All deltas grouped in a single transactions can be
  9. * reverted together, so you can think about the transaction as a single undo step. If you want to extend one
  10. * undo step you can call another method on the same transaction object. If you want to create a separate undo step
  11. * you can create a new transaction.
  12. *
  13. * For example to create two separate undo steps you can call:
  14. *
  15. * doc.createTransaction().insert( firstPosition, 'foo' );
  16. * doc.createTransaction().insert( secondPosition, 'bar' );
  17. *
  18. * To create a single undo step:
  19. *
  20. * const transaction = doc.createTransaction()
  21. * transaction.insert( firstPosition, 'foo' );
  22. * transaction.insert( secontPosition, 'bar' );
  23. *
  24. * Note that all document modification methods (insert, remove, split, etc.) are chainable so you can shorten code to:
  25. *
  26. * doc.createTransaction().insert( firstPosition, 'foo' ).insert( secontPosition, 'bar' );
  27. *
  28. * @class document.Transaction
  29. */
  30. class Transaction {
  31. /**
  32. * Creates transaction instance. Not recommended to use directly, use {@link document.Document#createTransaction}
  33. * instead.
  34. *
  35. * @constructor
  36. * @param {document.Document} doc Document which this transaction changes.
  37. */
  38. constructor( doc ) {
  39. /**
  40. * Document which this transaction changes.
  41. *
  42. * @readonly
  43. * @type {document.Document}
  44. */
  45. this.doc = doc;
  46. /**
  47. * Array of deltas which compose transaction.
  48. *
  49. * @readonly
  50. * @type {document.delta.Delta[]}
  51. */
  52. this.deltas = [];
  53. }
  54. /**
  55. * Adds delta to the transaction instance. All modification methods (insert, remove, split, etc.) use this method
  56. * to add created deltas.
  57. *
  58. * @param {document.delta.Delta} delta Delta to add.
  59. * @return {document.delta.Delta} Added delta.
  60. */
  61. addDelta( delta ) {
  62. delta.transaction = this;
  63. this.deltas.push( delta );
  64. return delta;
  65. }
  66. /**
  67. * Static method to register transaction methods. To make code scalable transaction do not have modification
  68. * methods built in. They can be registered using this method.
  69. *
  70. * This method checks if there is no naming collision and throw `transaction-register-taken` if the method name
  71. * is already taken.
  72. *
  73. * It also passes {@link document.Document} and {@link document.Transaction} do the creator class.
  74. *
  75. * Registered function returns `this` so they can be chainable by default.
  76. *
  77. * Beside that no magic happens here, the method is added to the `Transaction` class prototype.
  78. *
  79. * For example:
  80. *
  81. * Transaction.register( 'insert', ( doc, transaction, position, nodes ) => {
  82. * // You can use a class inherit from Delta if that class should handle OT in the special way.
  83. * const delta = new Delta();
  84. *
  85. * // Create operations which should be components of this delta.
  86. * const operation = new InsertOperation( position, nodes, doc.version );
  87. *
  88. * // Remember to apply every operation, no magic, you need to do it manually.
  89. * doc.applyOperation( operation );
  90. *
  91. * // Add operation to the delta.
  92. * delta.addOperation( operation );
  93. *
  94. * // Add delta to the transaction instance.
  95. * transaction.addDelta( delta );
  96. *
  97. * // You do not need to return transaction, register method will take care to make the method chainable.
  98. * } );
  99. *
  100. * @param {String} name Method name.
  101. * @param {Fuction} creator Method body.
  102. */
  103. static register( name, creator ) {
  104. if ( Transaction.prototype[ name ] ) {
  105. /**
  106. * This transaction method is already taken.
  107. *
  108. * @error transaction-register-taken
  109. * @param {String} name
  110. */
  111. throw new CKEditorError(
  112. 'transaction-register-taken: This transaction method is already taken.',
  113. { name: name } );
  114. }
  115. Transaction.prototype[ name ] = function() {
  116. creator.apply( this, [ this.doc, this ].concat( Array.from( arguments ) ) );
  117. return this;
  118. };
  119. }
  120. }
  121. return Transaction;
  122. } );