jupyterlab-emrys
Version:
A computational environment for Jupyter. Powered by Emrys
230 lines (229 loc) • 8 kB
JavaScript
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
"use strict";
var phosphor_disposable_1 = require('phosphor-disposable');
var phosphor_messaging_1 = require('phosphor-messaging');
var phosphor_properties_1 = require('phosphor-properties');
var dialog_1 = require('../dialog');
/**
* The class name added to document widgets.
*/
var DOCUMENT_CLASS = 'jp-Document';
/**
* A class that maintains the lifecyle of file-backed widgets.
*/
var DocumentWidgetManager = (function () {
/**
* Construct a new document widget manager.
*/
function DocumentWidgetManager(options) {
this._closeGuard = false;
this._contextManager = null;
this._registry = null;
this._widgets = Object.create(null);
this._contextManager = options.contextManager;
this._registry = options.registry;
}
/**
* Dispose of the resources used by the widget manager.
*/
DocumentWidgetManager.prototype.dispose = function () {
this._registry = null;
this._contextManager = null;
for (var id in this._widgets) {
for (var _i = 0, _a = this._widgets[id]; _i < _a.length; _i++) {
var widget = _a[_i];
widget.dispose();
}
}
};
/**
* Create a widget for a document and handle its lifecycle.
*/
DocumentWidgetManager.prototype.createWidget = function (name, id, kernel) {
var factory = this._registry.getWidgetFactory(name);
var context = this._contextManager.getContext(id);
var widget = factory.createNew(context, kernel);
Private.nameProperty.set(widget, name);
// Handle widget extensions.
var disposables = new phosphor_disposable_1.DisposableSet();
for (var _i = 0, _a = this._registry.getWidgetExtensions(name); _i < _a.length; _i++) {
var extender = _a[_i];
disposables.add(extender.createNew(widget, context));
}
widget.disposed.connect(function () {
disposables.dispose();
});
this.adoptWidget(id, widget);
return widget;
};
/**
* Install the message filter for the widget and add to list
* of known widgets.
*/
DocumentWidgetManager.prototype.adoptWidget = function (id, widget) {
var _this = this;
if (!(id in this._widgets)) {
this._widgets[id] = [];
}
this._widgets[id].push(widget);
phosphor_messaging_1.installMessageFilter(widget, this);
widget.addClass(DOCUMENT_CLASS);
widget.title.closable = true;
widget.disposed.connect(function () {
// Remove the widget from the widget registry.
var index = _this._widgets[id].indexOf(widget);
_this._widgets[id].splice(index, 1);
// Dispose of the context if this is the last widget using it.
if (!_this._widgets[id].length) {
_this._contextManager.removeContext(id);
}
});
Private.idProperty.set(widget, id);
};
/**
* See if a widget already exists for the given path and widget name.
*
* #### Notes
* This can be used to use an existing widget instead of opening
* a new widget.
*/
DocumentWidgetManager.prototype.findWidget = function (path, widgetName) {
var ids = this._contextManager.getIdsForPath(path);
for (var _i = 0, ids_1 = ids; _i < ids_1.length; _i++) {
var id = ids_1[_i];
for (var _a = 0, _b = this._widgets[id]; _a < _b.length; _a++) {
var widget = _b[_a];
var name_1 = Private.nameProperty.get(widget);
if (name_1 === widgetName) {
return widget;
}
}
}
};
/**
* Get the document context for a widget.
*/
DocumentWidgetManager.prototype.contextForWidget = function (widget) {
var id = Private.idProperty.get(widget);
return this._contextManager.getContext(id);
};
/**
* Clone a widget.
*
* #### Notes
* This will create a new widget with the same model and context
* as this widget.
*/
DocumentWidgetManager.prototype.clone = function (widget) {
var id = Private.idProperty.get(widget);
var name = Private.nameProperty.get(widget);
var newWidget = this.createWidget(name, id);
this.adoptWidget(id, newWidget);
return widget;
};
/**
* Close the widgets associated with a given path.
*/
DocumentWidgetManager.prototype.closeFile = function (path) {
var ids = this._contextManager.getIdsForPath(path);
for (var _i = 0, ids_2 = ids; _i < ids_2.length; _i++) {
var id = ids_2[_i];
var widgets = this._widgets[id] || [];
for (var _a = 0, widgets_1 = widgets; _a < widgets_1.length; _a++) {
var w = widgets_1[_a];
w.close();
}
}
};
/**
* Close all of the open documents.
*/
DocumentWidgetManager.prototype.closeAll = function () {
for (var id in this._widgets) {
for (var _i = 0, _a = this._widgets[id]; _i < _a.length; _i++) {
var w = _a[_i];
w.close();
}
}
};
/**
* Filter a message sent to a message handler.
*
* @param handler - The target handler of the message.
*
* @param msg - The message dispatched to the handler.
*
* @returns `true` if the message should be filtered, of `false`
* if the message should be dispatched to the handler as normal.
*/
DocumentWidgetManager.prototype.filterMessage = function (handler, msg) {
if (msg.type === 'close-request') {
if (this._closeGuard) {
return false;
}
this.onClose(handler);
return true;
}
return false;
};
/**
* Handle `'close-request'` messages.
*/
DocumentWidgetManager.prototype.onClose = function (widget) {
var _this = this;
// Handle dirty state.
this._maybeClose(widget).then(function (result) {
if (result) {
_this._closeGuard = true;
widget.close();
_this._closeGuard = false;
// Dispose of document widgets when they are closed.
widget.dispose();
}
}).catch(function () {
widget.dispose();
});
};
/**
* Ask the user whether to close an unsaved file.
*/
DocumentWidgetManager.prototype._maybeClose = function (widget) {
// Bail if the model is not dirty or other widgets are using the model.
var id = Private.idProperty.get(widget);
var widgets = this._widgets[id];
var model = this._contextManager.getModel(id);
if (!model.dirty || widgets.length > 1) {
return Promise.resolve(true);
}
return dialog_1.showDialog({
title: 'Close without saving?',
body: "File \"" + widget.title.text + "\" has unsaved changes, close without saving?"
}).then(function (value) {
if (value && value.text === 'OK') {
return true;
}
return false;
});
};
return DocumentWidgetManager;
}());
exports.DocumentWidgetManager = DocumentWidgetManager;
/**
* A private namespace for DocumentManager data.
*/
var Private;
(function (Private) {
/**
* A private attached property for a widget context id.
*/
Private.idProperty = new phosphor_properties_1.Property({
name: 'id'
});
/**
* A private attached property for a widget factory name.
*/
Private.nameProperty = new phosphor_properties_1.Property({
name: 'name'
});
})(Private || (Private = {}));