observablestring.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { IDisposable } from '@phosphor/disposable';
  4. import { ISignal, Signal } from '@phosphor/signaling';
  5. import { IObservable } from './modeldb';
  6. /**
  7. * A string which can be observed for changes.
  8. */
  9. export interface IObservableString extends IDisposable, IObservable {
  10. /**
  11. * The type of the Observable.
  12. */
  13. type: 'String';
  14. /**
  15. * A signal emitted when the string has changed.
  16. */
  17. readonly changed: ISignal<this, IObservableString.IChangedArgs>;
  18. /**
  19. * The value of the string.
  20. */
  21. text: string;
  22. /**
  23. * Insert a substring.
  24. *
  25. * @param index - The starting index.
  26. *
  27. * @param text - The substring to insert.
  28. */
  29. insert(index: number, text: string): void;
  30. /**
  31. * Remove a substring.
  32. *
  33. * @param start - The starting index.
  34. *
  35. * @param end - The ending index.
  36. */
  37. remove(start: number, end: number): void;
  38. /**
  39. * Set the ObservableString to an empty string.
  40. */
  41. clear(): void;
  42. /**
  43. * Dispose of the resources held by the string.
  44. */
  45. dispose(): void;
  46. }
  47. /**
  48. * The namespace for `IObservableString` associate interfaces.
  49. */
  50. export namespace IObservableString {
  51. /**
  52. * The change types which occur on an observable string.
  53. */
  54. export type ChangeType =
  55. /**
  56. * Text was inserted.
  57. */
  58. | 'insert'
  59. /**
  60. * Text was removed.
  61. */
  62. | 'remove'
  63. /**
  64. * Text was set.
  65. */
  66. | 'set';
  67. /**
  68. * The changed args object which is emitted by an observable string.
  69. */
  70. export interface IChangedArgs {
  71. /**
  72. * The type of change undergone by the list.
  73. */
  74. type: ChangeType;
  75. /**
  76. * The starting index of the change.
  77. */
  78. start: number;
  79. /**
  80. * The end index of the change.
  81. */
  82. end: number;
  83. /**
  84. * The value of the change.
  85. *
  86. * ### Notes
  87. * If `ChangeType` is `set`, then
  88. * this is the new value of the string.
  89. *
  90. * If `ChangeType` is `insert` this is
  91. * the value of the inserted string.
  92. *
  93. * If `ChangeType` is remove this is the
  94. * value of the removed substring.
  95. */
  96. value: string;
  97. }
  98. }
  99. /**
  100. * A concrete implementation of [[IObservableString]]
  101. */
  102. export class ObservableString implements IObservableString {
  103. /**
  104. * Construct a new observable string.
  105. */
  106. constructor(initialText: string = '') {
  107. this._text = initialText;
  108. }
  109. /**
  110. * The type of the Observable.
  111. */
  112. get type(): 'String' {
  113. return 'String';
  114. }
  115. /**
  116. * A signal emitted when the string has changed.
  117. */
  118. get changed(): ISignal<this, IObservableString.IChangedArgs> {
  119. return this._changed;
  120. }
  121. /**
  122. * Set the value of the string.
  123. */
  124. set text(value: string) {
  125. if (value.length === this._text.length && value === this._text) {
  126. return;
  127. }
  128. this._text = value;
  129. this._changed.emit({
  130. type: 'set',
  131. start: 0,
  132. end: value.length,
  133. value: value
  134. });
  135. }
  136. /**
  137. * Get the value of the string.
  138. */
  139. get text(): string {
  140. return this._text;
  141. }
  142. /**
  143. * Insert a substring.
  144. *
  145. * @param index - The starting index.
  146. *
  147. * @param text - The substring to insert.
  148. */
  149. insert(index: number, text: string): void {
  150. this._text = this._text.slice(0, index) + text + this._text.slice(index);
  151. this._changed.emit({
  152. type: 'insert',
  153. start: index,
  154. end: index + text.length,
  155. value: text
  156. });
  157. }
  158. /**
  159. * Remove a substring.
  160. *
  161. * @param start - The starting index.
  162. *
  163. * @param end - The ending index.
  164. */
  165. remove(start: number, end: number): void {
  166. let oldValue: string = this._text.slice(start, end);
  167. this._text = this._text.slice(0, start) + this._text.slice(end);
  168. this._changed.emit({
  169. type: 'remove',
  170. start: start,
  171. end: end,
  172. value: oldValue
  173. });
  174. }
  175. /**
  176. * Set the ObservableString to an empty string.
  177. */
  178. clear(): void {
  179. this.text = '';
  180. }
  181. /**
  182. * Test whether the string has been disposed.
  183. */
  184. get isDisposed(): boolean {
  185. return this._isDisposed;
  186. }
  187. /**
  188. * Dispose of the resources held by the string.
  189. */
  190. dispose(): void {
  191. if (this._isDisposed) {
  192. return;
  193. }
  194. this._isDisposed = true;
  195. Signal.clearData(this);
  196. this.clear();
  197. }
  198. private _text = '';
  199. private _isDisposed: boolean = false;
  200. private _changed = new Signal<this, IObservableString.IChangedArgs>(this);
  201. }