Jelajahi Sumber

Add rename menu option and dialog

Steven Silvester 8 tahun lalu
induk
melakukan
83fd61cc65

+ 30 - 11
packages/docmanager-extension/src/index.ts

@@ -10,8 +10,8 @@ import {
 } from '@jupyterlab/apputils';
 
 import {
-  createFromDialog, DocumentManager, IDocumentManager, IFileContainer,
-  showErrorMessage
+  createFromDialog, renameDialog, DocumentManager, IDocumentManager,
+  IFileContainer, showErrorMessage
 } from '@jupyterlab/docmanager';
 
 import {
@@ -58,6 +58,9 @@ namespace CommandIDs {
   export
   const saveAs = 'file-operations:save-as';
 
+  export
+  const rename = 'file-operations:rename';
+
   export
   const createLauncher = 'file-operations:create-launcher';
 };
@@ -90,15 +93,6 @@ const plugin: JupyterLabPlugin<IDocumentManager> = {
     // Register the file operations commands.
     addCommands(app, docManager, registry, palette);
 
-    // Handle fileCreator items as they are added.
-    registry.changed.connect((sender, args) => {
-      if (args.type === 'fileCreator') {
-        menu.dispose();
-        menu = createMenu(app, docManager, registry);
-        mainMenu.addMenu(menu, { rank: 1 });
-      }
-    });
-
     return docManager;
   }
 };
@@ -257,6 +251,30 @@ function addCommands(app: JupyterLab, docManager: IDocumentManager, registry: ID
     }
   });
 
+  commands.addCommand(CommandIDs.rename, {
+    isVisible: () => {
+      const widget = app.shell.currentWidget;
+      if (!widget) {
+        return;
+      }
+      // Find the context for the widget.
+      let context = docManager.contextForWidget(widget);
+      return context !== null;
+    },
+    execute: () => {
+      const widget = app.shell.currentWidget;
+      if (!widget) {
+        return;
+      }
+      // Find the context for the widget.
+      let context = docManager.contextForWidget(widget);
+      if (context) {
+        return renameDialog(docManager, context.path);
+      }
+    },
+    label: 'Rename'
+  });
+
   [
     CommandIDs.save,
     CommandIDs.restoreCheckpoint,
@@ -279,6 +297,7 @@ function createMenu(app: JupyterLab, docManager: IDocumentManager, registry: IDo
     CommandIDs.createLauncher,
     CommandIDs.save,
     CommandIDs.saveAs,
+    CommandIDs.rename,
     CommandIDs.restoreCheckpoint,
     CommandIDs.close,
     CommandIDs.closeAllFiles

+ 90 - 2
packages/docmanager/src/dialogs.ts

@@ -65,11 +65,21 @@ function createFromDialog(container: IFileContainer, manager: IDocumentManager,
 }
 
 
+/**
+ * Rename a file with an optional dialog.
+ */
+export
+function renameDialog(manager: IDocumentManager, oldPath: string): Promise<Contents.IModel> {
+  let handler = new RenameHandler(manager, oldPath);
+  return handler.showDialog();
+}
+
+
 /**
  * Rename a file with optional dialog.
  */
 export
-function renameFileDialog(manager: IDocumentManager, oldPath: string, newPath: string, basePath = ''): Promise<Contents.IModel> {
+function renameFile(manager: IDocumentManager, oldPath: string, newPath: string, basePath = ''): Promise<Contents.IModel> {
   return manager.rename(oldPath, newPath, basePath).catch(error => {
     if (error.xhr) {
       error.message = `${error.xhr.statusText} ${error.xhr.status}`;
@@ -109,6 +119,62 @@ function showErrorMessage(title: string, error: Error): Promise<void> {
 }
 
 
+
+/**
+ * A widget used to rename a file.
+ */
+class RenameHandler extends Widget {
+  /**
+   * Construct a new "rename" dialog.
+   */
+  constructor(manager: IDocumentManager, oldPath: string) {
+    super({ node: Private.createRenameNode(oldPath) });
+    this.addClass(FILE_DIALOG_CLASS);
+    this._manager = manager;
+    this._oldPath = oldPath;
+    let ext = PathExt.extname(oldPath);
+    let value = this.inputNode.value = PathExt.basename(oldPath);
+    this.inputNode.setSelectionRange(0, value.length - ext.length);
+  }
+
+  /**
+   * Dispose of the resources used by the widget.
+   */
+  dispose(): void {
+    this._manager = null;
+    super.dispose();
+  }
+
+  /**
+   * Get the input text node.
+   */
+  get inputNode(): HTMLInputElement {
+    return this.node.getElementsByTagName('input')[0] as HTMLInputElement;
+  }
+
+  /**
+   * Show the rename dialog.
+   */
+  showDialog(): Promise<Widget> {
+    return showDialog({
+      title: 'Rename File',
+      body: this.node,
+      primaryElement: this.inputNode,
+      buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'RENAME' })]
+    }).then(result => {
+      if (result.accept) {
+        let basePath = PathExt.dirname(this._oldPath);
+        let newPath = PathExt.join(basePath, this.inputNode.value);
+        return renameFile(this._manager, this._oldPath, newPath);
+      }
+    });
+  }
+
+  private _oldPath: string;
+  private _manager: IDocumentManager;
+}
+
+
 /**
  * A widget used to create a file using a creator.
  */
@@ -251,7 +317,7 @@ class CreateFromHandler extends Widget {
     }
     if (file !== oldPath) {
       let basePath = this._container.path;
-      let promise = renameFileDialog(this._manager, oldPath, file, basePath);
+      let promise = renameFile(this._manager, oldPath, file, basePath);
       return promise.then((contents: Contents.IModel) => {
         if (!contents) {
           return null;
@@ -293,4 +359,26 @@ namespace Private {
     body.appendChild(kernelDropdownNode);
     return body;
   }
+
+  /**
+   * Create the node for a rename handler.
+   */
+  export
+  function createRenameNode(oldPath: string): HTMLElement {
+    let body = document.createElement('div');
+    let existingLabel = document.createElement('label');
+    existingLabel.textContent = 'File Path';
+    let existingPath = document.createElement('span');
+    existingPath.textContent = oldPath;
+
+    let nameTitle = document.createElement('label');
+    nameTitle.textContent = 'New Name';
+    let name = document.createElement('input');
+
+    body.appendChild(existingLabel);
+    body.appendChild(existingPath);
+    body.appendChild(nameTitle);
+    body.appendChild(name);
+    return body;
+  }
 }

+ 1 - 2
packages/filebrowser-extension/src/index.ts

@@ -316,12 +316,11 @@ function addCommands(app: JupyterLab, tracker: InstanceTracker<FileBrowser>, mai
   });
 
   commands.addCommand(CommandIDs.rename, {
-    execute: () => {
+    execute: (args) => {
       const widget = tracker.currentWidget;
       if (!widget) {
         return;
       }
-
       return widget.rename();
     },
     iconClass: 'jp-MaterialIcon jp-EditIcon',

+ 3 - 3
packages/filebrowser/src/listing.ts

@@ -10,7 +10,7 @@ import {
 } from '@jupyterlab/coreutils';
 
 import {
-  IDocumentManager, renameFileDialog
+  IDocumentManager, renameFile
 } from '@jupyterlab/docmanager';
 
 import {
@@ -1069,7 +1069,7 @@ class DirListing extends Widget {
     const names = event.mimeData.getData(CONTENTS_MIME) as string[];
     for (let name of names) {
       let newPath = path + name;
-      promises.push(renameFileDialog(manager, name, newPath, this._model.path));
+      promises.push(renameFile(manager, name, newPath, this._model.path));
     }
     Promise.all(promises).catch(error => {
       utils.showErrorMessage('Move Error', error);
@@ -1276,7 +1276,7 @@ class DirListing extends Widget {
 
       const manager = this._manager;
       const basePath = this._model.path;
-      const promise = renameFileDialog(manager, original, newName, basePath);
+      const promise = renameFile(manager, original, newName, basePath);
       return promise.catch(error => {
         utils.showErrorMessage('Rename Error', error);
         this._inRename = false;