jupyterlab-emrys
Version:
A computational environment for Jupyter. Powered by Emrys
370 lines (369 loc) • 13.6 kB
JavaScript
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
;
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var phosphor_menus_1 = require('phosphor-menus');
var phosphor_widget_1 = require('phosphor-widget');
var dialog_1 = require('../dialog');
var utils = require('./utils');
/**
* The class name added to a file buttons widget.
*/
var FILE_BUTTONS_CLASS = 'jp-FileButtons';
/**
* The class name added to a button node.
*/
var BUTTON_CLASS = 'jp-FileButtons-button';
/**
* The class name added to a button content node.
*/
var CONTENT_CLASS = 'jp-FileButtons-buttonContent';
/**
* The class name added to a button icon node.
*/
var ICON_CLASS = 'jp-FileButtons-buttonIcon';
/**
* The class name added to the create button.
*/
var CREATE_CLASS = 'jp-id-create';
/**
* The class name added to the upload button.
*/
var UPLOAD_CLASS = 'jp-id-upload';
/**
* The class name added to the refresh button.
*/
var REFRESH_CLASS = 'jp-id-refresh';
/**
* The class name added to an active create button.
*/
var ACTIVE_CLASS = 'jp-mod-active';
/**
* The class name added to a dropdown icon.
*/
var DROPDOWN_CLASS = 'jp-FileButtons-dropdownIcon';
/**
* A widget which hosts the file browser buttons.
*/
var FileButtons = (function (_super) {
__extends(FileButtons, _super);
/**
* Construct a new file browser buttons widget.
*
* @param model - The file browser view model.
*/
function FileButtons(options) {
var _this = this;
_super.call(this);
/**
* The 'mousedown' handler for the create button.
*/
this._onCreateButtonPressed = function (event) {
// Do nothing if nothing if it's not a left press.
if (event.button !== 0) {
return;
}
// Do nothing if the create button is already active.
var button = _this._buttons.create;
if (button.classList.contains(ACTIVE_CLASS)) {
return;
}
// Create a new dropdown menu and snap the button geometry.
var dropdown = Private.createDropdownMenu(_this);
var rect = button.getBoundingClientRect();
// Mark the button as active.
button.classList.add(ACTIVE_CLASS);
// Setup the `closed` signal handler. The menu is disposed on an
// animation frame to allow a mouse press event which closed the
// menu to run its course. This keeps the button from re-opening.
dropdown.closed.connect(function () {
requestAnimationFrame(function () { dropdown.dispose(); });
});
// Setup the `disposed` signal handler. This restores the button
// to the non-active state and allows a new menu to be opened.
dropdown.disposed.connect(function () {
button.classList.remove(ACTIVE_CLASS);
});
// Popup the menu aligned with the bottom of the create button.
dropdown.popup(rect.left, rect.bottom, false, false);
};
/**
* The 'click' handler for the upload button.
*/
this._onUploadButtonClicked = function (event) {
if (event.button !== 0) {
return;
}
_this._input.click();
};
/**
* The 'click' handler for the refresh button.
*/
this._onRefreshButtonClicked = function (event) {
if (event.button !== 0) {
return;
}
_this._model.refresh().catch(function (error) {
utils.showErrorMessage(_this, 'Server Connection Error', error);
});
};
/**
* The 'change' handler for the input field.
*/
this._onInputChanged = function () {
var files = Array.prototype.slice.call(_this._input.files);
Private.uploadFiles(_this, files);
};
this._buttons = Private.createButtons();
this._input = Private.createUploadInput();
this._manager = null;
this._opener = null;
this.addClass(FILE_BUTTONS_CLASS);
this._model = options.model;
this._buttons.create.onmousedown = this._onCreateButtonPressed;
this._buttons.upload.onclick = this._onUploadButtonClicked;
this._buttons.refresh.onclick = this._onRefreshButtonClicked;
this._input.onchange = this._onInputChanged;
var node = this.node;
node.appendChild(this._buttons.create);
node.appendChild(this._buttons.upload);
node.appendChild(this._buttons.refresh);
this._manager = options.manager;
this._opener = options.opener;
}
/**
* Dispose of the resources held by the widget.
*/
FileButtons.prototype.dispose = function () {
this._model = null;
this._buttons = null;
this._input = null;
this._manager = null;
this._opener = null;
_super.prototype.dispose.call(this);
};
Object.defineProperty(FileButtons.prototype, "model", {
/**
* Get the model used by the widget.
*
* #### Notes
* This is a read-only property.
*/
get: function () {
return this._model;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FileButtons.prototype, "manager", {
/**
* Get the document manager used by the widget.
*/
get: function () {
return this._manager;
},
enumerable: true,
configurable: true
});
/**
* Open a file by path.
*/
FileButtons.prototype.open = function (path, widgetName, kernel) {
var _this = this;
if (widgetName === void 0) { widgetName = 'default'; }
var widget = this._manager.open(path, widgetName, kernel);
var opener = this._opener;
opener.open(widget);
var context = this._manager.contextForWidget(widget);
context.populated.connect(function () { return _this.model.refresh(); });
context.kernelChanged.connect(function () { return _this.model.refresh(); });
};
/**
* Create a new file by path.
*/
FileButtons.prototype.createNew = function (path, widgetName, kernel) {
var _this = this;
if (widgetName === void 0) { widgetName = 'default'; }
var widget = this._manager.createNew(path, widgetName, kernel);
var opener = this._opener;
opener.open(widget);
var context = this._manager.contextForWidget(widget);
context.populated.connect(function () { return _this.model.refresh(); });
context.kernelChanged.connect(function () { return _this.model.refresh(); });
};
return FileButtons;
}(phosphor_widget_1.Widget));
exports.FileButtons = FileButtons;
/**
* The namespace for the `FileButtons` private data.
*/
var Private;
(function (Private) {
/**
* Create the button group for a file buttons widget.
*/
function createButtons() {
var create = document.createElement('button');
var upload = document.createElement('button');
var refresh = document.createElement('button');
var createContent = document.createElement('span');
var uploadContent = document.createElement('span');
var refreshContent = document.createElement('span');
var createIcon = document.createElement('span');
var uploadIcon = document.createElement('span');
var refreshIcon = document.createElement('span');
var dropdownIcon = document.createElement('span');
create.type = 'button';
upload.type = 'button';
refresh.type = 'button';
create.title = 'Create New...';
upload.title = 'Upload File(s)';
refresh.title = 'Refresh File List';
create.className = BUTTON_CLASS + " " + CREATE_CLASS;
upload.className = BUTTON_CLASS + " " + UPLOAD_CLASS;
refresh.className = BUTTON_CLASS + " " + REFRESH_CLASS;
createContent.className = CONTENT_CLASS;
uploadContent.className = CONTENT_CLASS;
refreshContent.className = CONTENT_CLASS;
// TODO make these icons configurable.
createIcon.className = ICON_CLASS + ' fa fa-plus';
uploadIcon.className = ICON_CLASS + ' fa fa-upload';
refreshIcon.className = ICON_CLASS + ' fa fa-refresh';
dropdownIcon.className = DROPDOWN_CLASS + ' fa fa-caret-down';
createContent.appendChild(createIcon);
createContent.appendChild(dropdownIcon);
uploadContent.appendChild(uploadIcon);
refreshContent.appendChild(refreshIcon);
create.appendChild(createContent);
upload.appendChild(uploadContent);
refresh.appendChild(refreshContent);
return { create: create, upload: upload, refresh: refresh };
}
Private.createButtons = createButtons;
/**
* Create the upload input node for a file buttons widget.
*/
function createUploadInput() {
var input = document.createElement('input');
input.type = 'file';
input.multiple = true;
return input;
}
Private.createUploadInput = createUploadInput;
/**
* Create a new source file.
*/
function createNewFile(widget) {
widget.model.newUntitled({ type: 'file' }).then(function (contents) {
return widget.open(contents.path);
}).catch(function (error) {
utils.showErrorMessage(widget, 'New File Error', error);
});
}
Private.createNewFile = createNewFile;
/**
* Create a new folder.
*/
function createNewFolder(widget) {
widget.model.newUntitled({ type: 'directory' }).then(function (contents) {
widget.model.refresh();
}).catch(function (error) {
utils.showErrorMessage(widget, 'New Folder Error', error);
});
}
Private.createNewFolder = createNewFolder;
/**
* Create a new item using a file creator.
*/
function createNewItem(widget, fileType, widgetName, kernelName) {
var kernel;
if (kernelName) {
kernel = { name: kernelName };
}
widget.model.newUntitled({ type: fileType.fileType, ext: fileType.extension })
.then(function (contents) {
widget.createNew(contents.path, widgetName, kernel);
});
}
/**
* Create a new dropdown menu for the create new button.
*/
function createDropdownMenu(widget) {
var items = [
new phosphor_menus_1.MenuItem({
text: 'Text File',
handler: function () { createNewFile(widget); }
}),
new phosphor_menus_1.MenuItem({
text: 'Folder',
handler: function () { createNewFolder(widget); }
})
];
var registry = widget.manager.registry;
var creators = registry.listCreators();
if (creators) {
items.push(new phosphor_menus_1.MenuItem({ type: phosphor_menus_1.MenuItem.Separator }));
}
var _loop_1 = function(creator) {
var fileType = registry.getFileType(creator.fileType);
var item = new phosphor_menus_1.MenuItem({
text: creator.name,
handler: function () {
var widgetName = creator.widgetName || 'default';
var kernelName = creator.kernelName;
createNewItem(widget, fileType, widgetName, kernelName);
}
});
items.push(item);
};
for (var _i = 0, creators_1 = creators; _i < creators_1.length; _i++) {
var creator = creators_1[_i];
_loop_1(creator);
}
return new phosphor_menus_1.Menu(items);
}
Private.createDropdownMenu = createDropdownMenu;
/**
* Upload an array of files to the server.
*/
function uploadFiles(widget, files) {
var pending = files.map(function (file) { return uploadFile(widget, file); });
Promise.all(pending).then(function () {
widget.model.refresh();
}).catch(function (error) {
utils.showErrorMessage(widget, 'Upload Error', error);
});
}
Private.uploadFiles = uploadFiles;
/**
* Upload a file to the server.
*/
function uploadFile(widget, file) {
return widget.model.upload(file).catch(function (error) {
var exists = error.message.indexOf('already exists') !== -1;
if (exists) {
return uploadFileOverride(widget, file);
}
throw error;
});
}
/**
* Upload a file to the server checking for override.
*/
function uploadFileOverride(widget, file) {
var options = {
title: 'Overwrite File?',
body: "\"" + file.name + "\" already exists, overwrite?"
};
return dialog_1.showDialog(options).then(function (button) {
if (button.text !== 'Ok') {
return;
}
return widget.model.upload(file, true);
});
}
})(Private || (Private = {}));