8
0

pendingactions.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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 core/pendingactions
  7. */
  8. import ContextPlugin from './contextplugin';
  9. import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
  10. import Collection from '@ckeditor/ckeditor5-utils/src/collection';
  11. import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
  12. /**
  13. * The list of pending editor actions.
  14. *
  15. * This plugin should be used to synchronise plugins that execute long-lasting actions
  16. * (e.g. file upload) with the editor integration. It gives the developer who integrates the editor
  17. * an easy way to check if there are any actions pending whenever such information is needed.
  18. * All plugins that register a pending action also provide a message about the action that is ongoing
  19. * which can be displayed to the user. This lets them decide if they want to interrupt the action or wait.
  20. *
  21. * Adding and updating a pending action:
  22. *
  23. * const pendingActions = editor.plugins.get( 'PendingActions' );
  24. * const action = pendingActions.add( 'Upload in progress: 0%.' );
  25. *
  26. * // You can update the message:
  27. * action.message = 'Upload in progress: 10%.';
  28. *
  29. * Removing a pending action:
  30. *
  31. * const pendingActions = editor.plugins.get( 'PendingActions' );
  32. * const action = pendingActions.add( 'Unsaved changes.' );
  33. *
  34. * pendingActions.remove( action );
  35. *
  36. * Getting pending actions:
  37. *
  38. * const pendingActions = editor.plugins.get( 'PendingActions' );
  39. *
  40. * const action1 = pendingActions.add( 'Action 1' );
  41. * const action2 = pendingActions.add( 'Action 2' );
  42. *
  43. * pendingActions.first; // Returns action1
  44. * Array.from( pendingActions ); // Returns [ action1, action2 ]
  45. *
  46. * This plugin is used by features like {@link module:upload/filerepository~FileRepository} to register their ongoing actions
  47. * and by features like {@link module:autosave/autosave~Autosave} to detect whether there are any ongoing actions.
  48. * Read more about saving the data in the {@glink builds/guides/integration/saving-data Saving and getting data} guide.
  49. *
  50. * @extends module:core/contextplugin~ContextPlugin
  51. */
  52. export default class PendingActions extends ContextPlugin {
  53. /**
  54. * @inheritDoc
  55. */
  56. static get pluginName() {
  57. return 'PendingActions';
  58. }
  59. /**
  60. * @inheritDoc
  61. */
  62. init() {
  63. /**
  64. * Defines whether there is any registered pending action.
  65. *
  66. * @readonly
  67. * @observable
  68. * @member {Boolean} #hasAny
  69. */
  70. this.set( 'hasAny', false );
  71. /**
  72. * A list of pending actions.
  73. *
  74. * @private
  75. * @type {module:utils/collection~Collection}
  76. */
  77. this._actions = new Collection( { idProperty: '_id' } );
  78. this._actions.delegate( 'add', 'remove' ).to( this );
  79. }
  80. /**
  81. * Adds an action to the list of pending actions.
  82. *
  83. * This method returns an action object with an observable message property.
  84. * The action object can be later used in the {@link #remove} method. It also allows you to change the message.
  85. *
  86. * @param {String} message The action message.
  87. * @returns {Object} An observable object that represents a pending action.
  88. */
  89. add( message ) {
  90. if ( typeof message !== 'string' ) {
  91. /**
  92. * The message must be a string.
  93. *
  94. * @error pendingactions-add-invalid-message
  95. */
  96. throw new CKEditorError( 'pendingactions-add-invalid-message', this );
  97. }
  98. const action = Object.create( ObservableMixin );
  99. action.set( 'message', message );
  100. this._actions.add( action );
  101. this.hasAny = true;
  102. return action;
  103. }
  104. /**
  105. * Removes an action from the list of pending actions.
  106. *
  107. * @param {Object} action An action object.
  108. */
  109. remove( action ) {
  110. this._actions.remove( action );
  111. this.hasAny = !!this._actions.length;
  112. }
  113. /**
  114. * Returns the first action from the list or null when list is empty
  115. *
  116. * returns {Object|null} The pending action object.
  117. */
  118. get first() {
  119. return this._actions.get( 0 );
  120. }
  121. /**
  122. * Iterable interface.
  123. *
  124. * @returns {Iterable.<*>}
  125. */
  126. [ Symbol.iterator ]() {
  127. return this._actions[ Symbol.iterator ]();
  128. }
  129. /**
  130. * Fired when an action is added to the list.
  131. *
  132. * @event add
  133. * @param {Object} action The added action.
  134. */
  135. /**
  136. * Fired when an action is removed from the list.
  137. *
  138. * @event remove
  139. * @param {Object} action The removed action.
  140. */
  141. }