123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import {
- Contents, Kernel
- } from '@jupyterlab/services';
- import {
- each
- } from '@phosphor/algorithm';
- import {
- Widget
- } from '@phosphor/widgets';
- import {
- ClientSession, Dialog, showDialog
- } from '@jupyterlab/apputils';
- import {
- DocumentManager
- } from '@jupyterlab/docmanager';
- import {
- DocumentRegistry
- } from '@jupyterlab/docregistry';
- import {
- FileBrowserModel
- } from './model';
- /**
- * The class name added for a file conflict.
- */
- const FILE_CONFLICT_CLASS = 'jp-mod-conflict';
- /**
- * Open a file using a dialog.
- */
- export
- function openWithDialog(path: string, manager: DocumentManager, host?: HTMLElement): Promise<Widget> {
- let handler: OpenWithHandler;
- return manager.services.ready.then(() => {
- handler = new OpenWithHandler(path, manager);
- return showDialog({
- title: 'Open File',
- body: handler.node,
- primaryElement: handler.inputNode,
- buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'OPEN' })]
- });
- }).then(result => {
- if (result.accept) {
- return handler.open();
- }
- });
- }
- /**
- * Create a new file using a dialog.
- */
- export
- function createNewDialog(model: FileBrowserModel, manager: DocumentManager, host?: HTMLElement): Promise<Widget> {
- let handler: CreateNewHandler;
- return manager.services.ready.then(() => {
- handler = new CreateNewHandler(model, manager);
- return showDialog({
- title: 'Create New File',
- host,
- body: handler.node,
- primaryElement: handler.inputNode,
- buttons: [Dialog.cancelButton(), Dialog.okButton({ label: 'OPEN' })]
- });
- }).then(result => {
- if (result.accept) {
- return handler.open();
- }
- });
- }
- /**
- * A widget used to open files with a specific widget/kernel.
- */
- class OpenWithHandler extends Widget {
- /**
- * Construct a new "open with" dialog.
- */
- constructor(path: string, manager: DocumentManager) {
- super({ node: Private.createOpenWithNode() });
- this._manager = manager;
- this.inputNode.textContent = path;
- this._ext = DocumentRegistry.extname(path);
- this.populateFactories();
- this.widgetDropdown.onchange = this.widgetChanged.bind(this);
- }
- /**
- * Dispose of the resources used by the widget.
- */
- dispose(): void {
- this._manager = null;
- super.dispose();
- }
- /**
- * Get the input text node.
- */
- get inputNode(): HTMLElement {
- return this.node.firstChild as HTMLElement;
- }
- /**
- * Get the widget dropdown node.
- */
- get widgetDropdown(): HTMLSelectElement {
- return this.node.children[1] as HTMLSelectElement;
- }
- /**
- * Get the kernel dropdown node.
- */
- get kernelDropdownNode(): HTMLSelectElement {
- return this.node.children[2] as HTMLSelectElement;
- }
- /**
- * Open the file and return the document widget.
- */
- open(): Widget {
- let path = this.inputNode.textContent;
- let widgetName = this.widgetDropdown.value;
- let kernelValue = this.kernelDropdownNode.value;
- let kernelId: Kernel.IModel;
- if (kernelValue !== 'null') {
- kernelId = JSON.parse(kernelValue) as Kernel.IModel;
- }
- return this._manager.open(path, widgetName, kernelId);
- }
- /**
- * Populate the widget factories.
- */
- protected populateFactories(): void {
- let factories = this._manager.registry.preferredWidgetFactories(this._ext);
- let widgetDropdown = this.widgetDropdown;
- each(factories, factory => {
- let option = document.createElement('option');
- option.text = factory.name;
- widgetDropdown.appendChild(option);
- });
- this.widgetChanged();
- }
- /**
- * Handle a change to the widget.
- */
- protected widgetChanged(): void {
- let widgetName = this.widgetDropdown.value;
- let preference = this._manager.registry.getKernelPreference(
- this._ext, widgetName
- );
- let services = this._manager.services;
- ClientSession.populateKernelSelect(this.kernelDropdownNode, {
- specs: services.specs,
- sessions: services.sessions.running(),
- preference
- });
- }
- private _ext = '';
- private _manager: DocumentManager = null;
- }
- /**
- * A widget used to create new files.
- */
- class CreateNewHandler extends Widget {
- /**
- * Construct a new "create new" dialog.
- */
- constructor(model: FileBrowserModel, manager: DocumentManager) {
- super({ node: Private.createCreateNewNode() });
- this._model = model;
- this._manager = manager;
- // Create a file name based on the current time.
- let time = new Date();
- time.setMinutes(time.getMinutes() - time.getTimezoneOffset());
- let name = time.toJSON().slice(0, 10);
- name += '-' + time.getHours() + time.getMinutes() + time.getSeconds();
- this.inputNode.value = name + '.txt';
- this.inputNode.setSelectionRange(0, name.length);
- // Check for name conflicts when the inputNode changes.
- this.inputNode.addEventListener('input', () => {
- this.inputNodeChanged();
- });
- // Update the widget choices when the file type changes.
- this.fileTypeDropdown.addEventListener('change', () => {
- this.fileTypeChanged();
- });
- // Update the kernel choices when the widget changes.
- this.widgetDropdown.addEventListener('change', () => {
- this.widgetDropdownChanged();
- });
- // Populate the lists of file types and widget factories.
- this.populateFileTypes();
- this.populateFactories();
- }
- /**
- * Dispose of the resources used by the widget.
- */
- dispose(): void {
- this._model = null;
- this._manager = null;
- super.dispose();
- }
- /**
- * Get the input text node.
- */
- get inputNode(): HTMLInputElement {
- return this.node.firstChild as HTMLInputElement;
- }
- /**
- * Get the file type dropdown node.
- */
- get fileTypeDropdown(): HTMLSelectElement {
- return this.node.children[1] as HTMLSelectElement;
- }
- /**
- * Get the widget dropdown node.
- */
- get widgetDropdown(): HTMLSelectElement {
- return this.node.children[2] as HTMLSelectElement;
- }
- /**
- * Get the kernel dropdown node.
- */
- get kernelDropdownNode(): HTMLSelectElement {
- return this.node.children[3] as HTMLSelectElement;
- }
- /**
- * Get the current extension for the file.
- */
- get ext(): string {
- return DocumentRegistry.extname(this.inputNode.value);
- }
- /**
- * Open the file and return the document widget.
- */
- open(): Widget {
- let path = this.inputNode.textContent;
- let widgetName = this.widgetDropdown.value;
- let kernelValue = this.kernelDropdownNode.value;
- let kernelId: Kernel.IModel;
- if (kernelValue !== 'null') {
- kernelId = JSON.parse(kernelValue) as Kernel.IModel;
- }
- return this._manager.createNew(path, widgetName, kernelId);
- }
- /**
- * Handle a change to the inputNode.
- */
- protected inputNodeChanged(): void {
- let path = this.inputNode.value;
- each(this._model.items(), item => {
- if (item.path === path) {
- this.addClass(FILE_CONFLICT_CLASS);
- return;
- }
- });
- let ext = this.ext;
- if (ext === this._prevExt) {
- return;
- }
- // Update the file type dropdown and the factories.
- if (this._extensions.indexOf(ext) === -1) {
- this.fileTypeDropdown.value = this._sentinel;
- } else {
- this.fileTypeDropdown.value = ext;
- }
- this.populateFactories();
- }
- /**
- * Populate the file types.
- */
- protected populateFileTypes(): void {
- let dropdown = this.fileTypeDropdown;
- let option = document.createElement('option');
- option.text = 'File';
- option.value = this._sentinel;
- each(this._manager.registry.fileTypes(), ft => {
- option = document.createElement('option');
- option.text = `${ft.name} (${ft.extension})`;
- option.value = ft.extension;
- dropdown.appendChild(option);
- this._extensions.push(ft.extension);
- });
- if (this.ext in this._extensions) {
- dropdown.value = this.ext;
- } else {
- dropdown.value = this._sentinel;
- }
- }
- /**
- * Populate the widget factories.
- */
- protected populateFactories(): void {
- let ext = this.ext;
- let factories = this._manager.registry.preferredWidgetFactories(ext);
- let widgetDropdown = this.widgetDropdown;
- each(factories, factory => {
- let option = document.createElement('option');
- option.text = factory.name;
- widgetDropdown.appendChild(option);
- });
- this.widgetDropdownChanged();
- this._prevExt = ext;
- }
- /**
- * Handle changes to the file type dropdown.
- */
- protected fileTypeChanged(): void {
- // Update the current inputNode.
- let oldExt = this.ext;
- let newExt = this.fileTypeDropdown.value;
- if (oldExt === newExt || newExt === '') {
- return;
- }
- let oldName = this.inputNode.value;
- let base = oldName.slice(0, oldName.length - oldExt.length - 1);
- this.inputNode.value = base + newExt;
- }
- /**
- * Handle a change to the widget dropdown.
- */
- protected widgetDropdownChanged(): void {
- let ext = this.ext;
- let widgetName = this.widgetDropdown.value;
- let manager = this._manager;
- let preference = manager.registry.getKernelPreference(ext, widgetName);
- let services = this._manager.services;
- ClientSession.populateKernelSelect(this.kernelDropdownNode, {
- specs: services.specs,
- sessions: services.sessions.running(),
- preference
- });
- }
- private _model: FileBrowserModel = null;
- private _manager: DocumentManager = null;
- private _sentinel = 'UNKNOWN_EXTENSION';
- private _prevExt = '';
- private _extensions: string[] = [];
- }
- /**
- * A namespace for private data.
- */
- namespace Private {
- /**
- * Create the node for an open with handler.
- */
- export
- function createOpenWithNode(): HTMLElement {
- let body = document.createElement('div');
- let nameTitle = document.createElement('label');
- nameTitle.textContent = 'File Name';
- let name = document.createElement('div');
- let widgetTitle = document.createElement('label');
- widgetTitle.textContent = 'Widget Type';
- let widgetDropdown = document.createElement('select');
- let kernelTitle = document.createElement('label');
- kernelTitle.textContent = 'Kernel';
- let kernelDropdownNode = document.createElement('select');
- body.appendChild(nameTitle);
- body.appendChild(name);
- body.appendChild(widgetTitle);
- body.appendChild(widgetDropdown);
- body.appendChild(kernelTitle);
- body.appendChild(kernelDropdownNode);
- return body;
- }
- /**
- * Create the node for a create new handler.
- */
- export
- function createCreateNewNode(): HTMLElement {
- let body = document.createElement('div');
- let nameTitle = document.createElement('label');
- nameTitle.textContent = 'File Name';
- let name = document.createElement('input');
- let typeTitle = document.createElement('label');
- typeTitle.textContent = 'File Type';
- let fileTypeDropdown = document.createElement('select');
- let widgetTitle = document.createElement('label');
- widgetTitle.textContent = 'Widget Type';
- let widgetDropdown = document.createElement('select');
- let kernelTitle = document.createElement('label');
- kernelTitle.textContent = 'Kernel';
- let kernelDropdownNode = document.createElement('select');
- body.appendChild(nameTitle);
- body.appendChild(name);
- body.appendChild(typeTitle);
- body.appendChild(fileTypeDropdown);
- body.appendChild(widgetTitle);
- body.appendChild(widgetDropdown);
- body.appendChild(kernelTitle);
- body.appendChild(kernelDropdownNode);
- return body;
- }
- /**
- * Create the node for a create from handler.
- */
- export
- function createCreateFromNode(): HTMLElement {
- let body = document.createElement('div');
- let nameTitle = document.createElement('label');
- nameTitle.textContent = 'File Name';
- let name = document.createElement('input');
- let kernelTitle = document.createElement('label');
- kernelTitle.textContent = 'Kernel';
- let kernelDropdownNode = document.createElement('select');
- body.appendChild(nameTitle);
- body.appendChild(name);
- body.appendChild(kernelTitle);
- body.appendChild(kernelDropdownNode);
- return body;
- }
- }
|