operationreplayer.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 engine/dev-utils/operationreplayer
  7. */
  8. /* global setTimeout */
  9. import OperationFactory from '../model/operation/operationfactory';
  10. /**
  11. * Operation replayer is a development tool created for easy replaying of operations on the document from stringified operations.
  12. */
  13. export default class OperationReplayer {
  14. /**
  15. * @param {module:engine/model/model~Model} model Data model.
  16. * @param {String} logSeparator Separator between operations.
  17. * @param {String} stringifiedOperations Operations to replay.
  18. */
  19. constructor( model, logSeparator, stringifiedOperations ) {
  20. this._model = model;
  21. this._logSeparator = logSeparator;
  22. this.setStringifiedOperations( stringifiedOperations );
  23. }
  24. /**
  25. * Parses the given string containing stringified operations and sets parsed operations as operations to replay.
  26. *
  27. * @param {String} stringifiedOperations Stringified operations to replay.
  28. */
  29. setStringifiedOperations( stringifiedOperations ) {
  30. if ( stringifiedOperations === '' ) {
  31. this._operationsToReplay = [];
  32. return;
  33. }
  34. this._operationsToReplay = stringifiedOperations
  35. .split( this._logSeparator )
  36. .map( stringifiedOperation => JSON.parse( stringifiedOperation ) );
  37. }
  38. /**
  39. * Returns operations to replay.
  40. *
  41. * @returns {Array.<module:engine/model/operation/operation~Operation>}
  42. */
  43. getOperationsToReplay() {
  44. return this._operationsToReplay;
  45. }
  46. /**
  47. * Applies all operations with a delay between actions.
  48. *
  49. * @param {Number} timeInterval Time between applying operations.
  50. * @returns {Promise}
  51. */
  52. play( timeInterval = 1000 ) {
  53. const operationReplayer = this; // eslint-disable-line consistent-this
  54. return new Promise( ( res, rej ) => {
  55. play();
  56. function play() {
  57. operationReplayer.applyNextOperation().then( isFinished => {
  58. if ( isFinished ) {
  59. return res();
  60. }
  61. setTimeout( play, timeInterval );
  62. } ).catch( err => {
  63. rej( err );
  64. } );
  65. }
  66. } );
  67. }
  68. /**
  69. * Applies `numberOfOperations` operations, beginning after the last applied operation (or first, if no operations were applied).
  70. *
  71. * @param {Number} numberOfOperations The number of operations to apply.
  72. * @returns {Promise}
  73. */
  74. applyOperations( numberOfOperations ) {
  75. if ( numberOfOperations <= 0 ) {
  76. return;
  77. }
  78. return this.applyNextOperation()
  79. .then( isFinished => {
  80. if ( !isFinished ) {
  81. return this.applyOperations( numberOfOperations - 1 );
  82. }
  83. } );
  84. }
  85. /**
  86. * Applies all operations to replay at once.
  87. *
  88. * @returns {Promise}
  89. */
  90. applyAllOperations() {
  91. return this.applyNextOperation()
  92. .then( isFinished => {
  93. if ( !isFinished ) {
  94. return this.applyAllOperations();
  95. }
  96. } );
  97. }
  98. /**
  99. * Applies the next operation to replay. Returns a promise with the `isFinished` parameter that is `true` if the last
  100. * operation in the replayer has been applied, `false` otherwise.
  101. *
  102. * @returns {Promise.<Boolean>}
  103. */
  104. applyNextOperation() {
  105. const model = this._model;
  106. return new Promise( res => {
  107. model.enqueueChange( writer => {
  108. const operationJson = this._operationsToReplay.shift();
  109. if ( !operationJson ) {
  110. return res( true );
  111. }
  112. const operation = OperationFactory.fromJSON( operationJson, model.document );
  113. writer.batch.addOperation( operation );
  114. model.applyOperation( operation );
  115. res( false );
  116. } );
  117. } );
  118. }
  119. }