Переглянути джерело

Add a close confirmation dialog for unsaved documents

Steven Silvester 9 роки тому
батько
коміт
940d2d5b66
2 змінених файлів з 72 додано та 21 видалено
  1. 23 1
      examples/docmanager/index.css
  2. 49 20
      src/docmanager/handler.ts

+ 23 - 1
examples/docmanager/index.css

@@ -2,6 +2,22 @@
 | Copyright (c) Jupyter Development Team.
 | Distributed under the terms of the Modified BSD License.
 |----------------------------------------------------------------------------*/
+body {
+  margin: 0;
+  padding: 0;
+}
+
+
+#main {
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  right: 10px;
+  bottom: 10px;
+  padding: 8px;
+}
+
+
 .p-SplitPanel {
   height: 400px;
 }
@@ -105,8 +121,14 @@
 
 
 .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:before {
-  content: '\f00d';
   font-family: FontAwesome;
+  content: '\f00d'; /* close */
+}
+
+
+.p-TabBar-tab.p-mod-closable.jp-mod-dirty > .p-TabBar-tabCloseIcon:before {
+  font-family: FontAwesome;
+  content: '\f069'; /* asterisk */
 }
 
 

+ 49 - 20
src/docmanager/handler.ts

@@ -29,6 +29,10 @@ import {
   Widget, Title
 } from 'phosphor-widget';
 
+import {
+  showDialog
+} from '../dialog';
+
 import {
   JupyterCodeMirrorWidget as CodeMirrorWidget
 } from './widget';
@@ -235,16 +239,10 @@ abstract class AbstractFileHandler<T extends Widget> implements IMessageFilter {
     if (!widget) {
       return Promise.resolve(false);
     }
-    if (widget.hasClass(DIRTY_CLASS)) {
-      // TODO: implement a dialog here.
-      console.log('CLOSING DIRTY FILE');
-    }
-    widget.dispose();
-    let index = this._widgets.indexOf(widget);
-    this._widgets.splice(index, 1);
-    if (widget === this.activeWidget) {
-      this._activeWidget = null;
+    if (this.isDirty(widget)) {
+      return this._maybeClose(widget);
     }
+    this._close(widget);
     return Promise.resolve(true);
   }
 
@@ -329,6 +327,24 @@ abstract class AbstractFileHandler<T extends Widget> implements IMessageFilter {
     return model.name;
   }
 
+  /**
+   * Resolve a given widget.
+   */
+  protected resolveWidget(widget: T): T {
+    widget = widget || this.activeWidget;
+    if (this._widgets.indexOf(widget) === -1) {
+      return;
+    }
+    return widget;
+  }
+
+  /**
+   * Find a widget given a model.
+   */
+  protected findWidgetByModel(model: IContentsModel): T {
+    return arrays.find(this._widgets, widget => this._getModel(widget).path === model.path);
+  }
+
   /**
    * Get the model for a given widget.
    */
@@ -344,21 +360,31 @@ abstract class AbstractFileHandler<T extends Widget> implements IMessageFilter {
   }
 
   /**
-   * Resolve a given widget.
+   * Ask the user whether to close an unsaved file.
    */
-  protected resolveWidget(widget: T): T {
-    widget = widget || this.activeWidget;
-    if (this._widgets.indexOf(widget) === -1) {
-      return;
-    }
-    return widget;
+  private _maybeClose(widget: T): Promise<boolean> {
+    return showDialog({
+      title: 'Close without saving?',
+      body: `File "${widget.title.text}" has unsaved changes, close without saving?`
+    }).then(value => {
+      if (value.text === 'OK') {
+        this._close(widget);
+        return true;
+      }
+      return false;
+    });
   }
 
   /**
-   * Find a widget given a model.
+   * Actually close the file.
    */
-  protected findWidgetByModel(model: IContentsModel): T {
-    return arrays.find(this._widgets, widget => this._getModel(widget).path === model.path);
+  private _close(widget: T): void {
+    widget.dispose();
+    let index = this._widgets.indexOf(widget);
+    this._widgets.splice(index, 1);
+    if (widget === this.activeWidget) {
+      this._activeWidget = null;
+    }
   }
 
   /**
@@ -402,7 +428,10 @@ class FileHandler extends AbstractFileHandler<CodeMirrorWidget> {
    */
   protected createWidget(model: IContentsModel): CodeMirrorWidget {
     let widget = new CodeMirrorWidget();
-    widget.editor.on('change', () => this.setDirty(widget));
+    CodeMirror.on(widget.editor.getDoc(), 'change', () => {
+      this.setDirty(widget);
+      console.log('changed')
+    });
     return widget;
   }