UNPKG

3.86 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 const interval = options.saveInterval || 120;
24 this._minInterval = interval * 1000;
25 this._interval = this._minInterval;
26 // Restart the timer when the contents model is updated.
27 this._context.fileChanged.connect(this._setTimer, this);
28 this._context.disposed.connect(this.dispose, this);
29 }
30 /**
31 * The save interval used by the timer (in seconds).
32 */
33 get saveInterval() {
34 return this._interval / 1000;
35 }
36 set saveInterval(value) {
37 this._minInterval = this._interval = value * 1000;
38 if (this._isActive) {
39 this._setTimer();
40 }
41 }
42 /**
43 * Get whether the handler is active.
44 */
45 get isActive() {
46 return this._isActive;
47 }
48 /**
49 * Get whether the save handler is disposed.
50 */
51 get isDisposed() {
52 return this._isDisposed;
53 }
54 /**
55 * Dispose of the resources used by the save handler.
56 */
57 dispose() {
58 if (this.isDisposed) {
59 return;
60 }
61 this._isDisposed = true;
62 clearTimeout(this._autosaveTimer);
63 Signal.clearData(this);
64 }
65 /**
66 * Start the autosaver.
67 */
68 start() {
69 this._isActive = true;
70 this._setTimer();
71 }
72 /**
73 * Stop the autosaver.
74 */
75 stop() {
76 this._isActive = false;
77 clearTimeout(this._autosaveTimer);
78 }
79 /**
80 * Set the timer.
81 */
82 _setTimer() {
83 clearTimeout(this._autosaveTimer);
84 if (!this._isActive) {
85 return;
86 }
87 this._autosaveTimer = window.setTimeout(() => {
88 this._save();
89 }, this._interval);
90 }
91 /**
92 * Handle an autosave timeout.
93 */
94 _save() {
95 const context = this._context;
96 // Trigger the next update.
97 this._setTimer();
98 if (!context) {
99 return;
100 }
101 // Bail if the model is not dirty or the file is not writable, or the dialog
102 // is already showing.
103 const writable = context.contentsModel && context.contentsModel.writable;
104 if (!writable || !context.model.dirty || this._inDialog) {
105 return;
106 }
107 const start = new Date().getTime();
108 context
109 .save()
110 .then(() => {
111 if (this.isDisposed) {
112 return;
113 }
114 const duration = new Date().getTime() - start;
115 // New save interval: higher of 10x save duration or min interval.
116 this._interval = Math.max(this._multiplier * duration, this._minInterval);
117 // Restart the update to pick up the new interval.
118 this._setTimer();
119 })
120 .catch(err => {
121 // If the user canceled the save, do nothing.
122 // FIXME-TRANS: Is this affected by localization?
123 if (err.message === 'Cancel' ||
124 err.message === 'Modal is already displayed') {
125 return;
126 }
127 // Otherwise, log the error.
128 console.error('Error in Auto-Save', err.message);
129 });
130 }
131}
132//# sourceMappingURL=savehandler.js.map
\No newline at end of file