UNPKG

3.95 kBJavaScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3import { Signal } from '@lumino/signaling';
4/**
5 * A class that manages the auto saving of a document.
6 *
7 * #### Notes
8 * Implements https://github.com/ipython/ipython/wiki/IPEP-15:-Autosaving-the-IPython-Notebook.
9 */
10export class SaveHandler {
11 /**
12 * Construct a new save handler.
13 */
14 constructor(options) {
15 this._autosaveTimer = -1;
16 this._minInterval = -1;
17 this._interval = -1;
18 this._isActive = false;
19 this._inDialog = false;
20 this._isDisposed = false;
21 this._multiplier = 10;
22 this._context = options.context;
23 this._isConnectedCallback = options.isConnectedCallback || (() => true);
24 const interval = options.saveInterval || 120;
25 this._minInterval = interval * 1000;
26 this._interval = this._minInterval;
27 // Restart the timer when the contents model is updated.
28 this._context.fileChanged.connect(this._setTimer, this);
29 this._context.disposed.connect(this.dispose, this);
30 }
31 /**
32 * The save interval used by the timer (in seconds).
33 */
34 get saveInterval() {
35 return this._interval / 1000;
36 }
37 set saveInterval(value) {
38 this._minInterval = this._interval = value * 1000;
39 if (this._isActive) {
40 this._setTimer();
41 }
42 }
43 /**
44 * Get whether the handler is active.
45 */
46 get isActive() {
47 return this._isActive;
48 }
49 /**
50 * Get whether the save handler is disposed.
51 */
52 get isDisposed() {
53 return this._isDisposed;
54 }
55 /**
56 * Dispose of the resources used by the save handler.
57 */
58 dispose() {
59 if (this.isDisposed) {
60 return;
61 }
62 this._isDisposed = true;
63 clearTimeout(this._autosaveTimer);
64 Signal.clearData(this);
65 }
66 /**
67 * Start the autosaver.
68 */
69 start() {
70 this._isActive = true;
71 this._setTimer();
72 }
73 /**
74 * Stop the autosaver.
75 */
76 stop() {
77 this._isActive = false;
78 clearTimeout(this._autosaveTimer);
79 }
80 /**
81 * Set the timer.
82 */
83 _setTimer() {
84 clearTimeout(this._autosaveTimer);
85 if (!this._isActive) {
86 return;
87 }
88 this._autosaveTimer = window.setTimeout(() => {
89 if (this._isConnectedCallback()) {
90 this._save();
91 }
92 }, this._interval);
93 }
94 /**
95 * Handle an autosave timeout.
96 */
97 _save() {
98 const context = this._context;
99 // Trigger the next update.
100 this._setTimer();
101 if (!context) {
102 return;
103 }
104 // Bail if the model is not dirty or the file is not writable, or the dialog
105 // is already showing.
106 const writable = context.contentsModel && context.contentsModel.writable;
107 if (!writable || !context.model.dirty || this._inDialog) {
108 return;
109 }
110 const start = new Date().getTime();
111 context
112 .save()
113 .then(() => {
114 if (this.isDisposed) {
115 return;
116 }
117 const duration = new Date().getTime() - start;
118 // New save interval: higher of 10x save duration or min interval.
119 this._interval = Math.max(this._multiplier * duration, this._minInterval);
120 // Restart the update to pick up the new interval.
121 this._setTimer();
122 })
123 .catch(err => {
124 // If the user canceled the save, do nothing.
125 const { name } = err;
126 if (name === 'ModalCancelError' || name === 'ModalDuplicateError') {
127 return;
128 }
129 // Otherwise, log the error.
130 console.error('Error in Auto-Save', err.message);
131 });
132 }
133}
134//# sourceMappingURL=savehandler.js.map
\No newline at end of file