|
@@ -1,7 +1,6 @@
|
|
|
// Copyright (c) Jupyter Development Team.
|
|
|
// Distributed under the terms of the Modified BSD License.
|
|
|
|
|
|
-import { isValidFileName } from '@jupyterlab/docmanager';
|
|
|
import { DocumentRegistry, DocumentWidget } from '@jupyterlab/docregistry';
|
|
|
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
|
|
import {
|
|
@@ -383,14 +382,12 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
this._hsplitPanel.updated.connect(this._onLayoutModified, this);
|
|
|
|
|
|
// Setup single-document-mode title bar
|
|
|
- const titleWidgetHandler = (this._titleWidgetHandler = new Private.TitleWidgetHandler(
|
|
|
- this
|
|
|
- ));
|
|
|
- this.add(titleWidgetHandler.titleWidget, 'top', { rank: 100 });
|
|
|
+ const titleHandler = (this._titleHandler = new Private.TitleHandler(this));
|
|
|
+ this.add(titleHandler, 'top', { rank: 100 });
|
|
|
|
|
|
if (this._dockPanel.mode === 'multiple-document') {
|
|
|
this._topHandler.addWidget(this._menuHandler.panel, 100);
|
|
|
- titleWidgetHandler.hide();
|
|
|
+ titleHandler.hide();
|
|
|
} else {
|
|
|
rootLayout.insertWidget(2, this._menuHandler.panel);
|
|
|
}
|
|
@@ -536,7 +533,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
|
|
|
// Adjust menu and title
|
|
|
(this.layout as BoxLayout).insertWidget(2, this._menuHandler.panel);
|
|
|
- this._titleWidgetHandler.show();
|
|
|
+ this._titleHandler.show();
|
|
|
this._updateTitlePanelTitle();
|
|
|
} else {
|
|
|
// Cache a reference to every widget currently in the dock panel.
|
|
@@ -574,7 +571,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
// Adjust menu and title
|
|
|
this.add(this._menuHandler.panel, 'top', { rank: 100 });
|
|
|
// this._topHandler.addWidget(this._menuHandler.panel, 100)
|
|
|
- this._titleWidgetHandler.hide();
|
|
|
+ this._titleHandler.hide();
|
|
|
}
|
|
|
|
|
|
// Set the mode data attribute on the applications shell node.
|
|
@@ -765,7 +762,6 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
return;
|
|
|
}
|
|
|
this._layoutDebouncer.dispose();
|
|
|
- this._titleWidgetHandler.dispose();
|
|
|
super.dispose();
|
|
|
}
|
|
|
|
|
@@ -1001,8 +997,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
*/
|
|
|
private _updateTitlePanelTitle() {
|
|
|
let current = this.currentWidget;
|
|
|
- const inputElement = this._titleWidgetHandler.titleWidget.node
|
|
|
- .children[0] as HTMLInputElement;
|
|
|
+ const inputElement = this._titleHandler.inputElement;
|
|
|
inputElement.value = current ? current.title.label : '';
|
|
|
inputElement.title = current ? current.title.caption : '';
|
|
|
}
|
|
@@ -1395,7 +1390,7 @@ export class LabShell extends Widget implements JupyterFrontEnd.IShell {
|
|
|
private _topHandler: Private.PanelHandler;
|
|
|
private _menuHandler: Private.PanelHandler;
|
|
|
private _skipLinkWidget: Private.SkipLinkWidget;
|
|
|
- private _titleWidgetHandler: Private.TitleWidgetHandler;
|
|
|
+ private _titleHandler: Private.TitleHandler;
|
|
|
private _bottomPanel: Panel;
|
|
|
private _mainOptionsCache = new Map<Widget, DocumentRegistry.IOpenOptions>();
|
|
|
private _sideOptionsCache = new Map<Widget, DocumentRegistry.IOpenOptions>();
|
|
@@ -1785,21 +1780,37 @@ namespace Private {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- export class TitleWidgetHandler {
|
|
|
+ export class TitleHandler extends Widget {
|
|
|
/**
|
|
|
- * Construct a new title widget handler.
|
|
|
+ * Construct a new title handler.
|
|
|
*/
|
|
|
constructor(shell: ILabShell) {
|
|
|
+ super();
|
|
|
+ const inputElement = document.createElement('input');
|
|
|
+ inputElement.type = 'text';
|
|
|
+ this.node.appendChild(inputElement);
|
|
|
this._shell = shell;
|
|
|
- const titleWidget = (this._titleWidget = new Widget());
|
|
|
- titleWidget.id = 'jp-title-panel-title';
|
|
|
- const titleInput = document.createElement('input');
|
|
|
- titleInput.type = 'text';
|
|
|
- titleInput.addEventListener('keyup', this);
|
|
|
- titleInput.addEventListener('click', this);
|
|
|
- titleInput.addEventListener('blur', this);
|
|
|
+ this.id = 'jp-title-panel-title';
|
|
|
+ }
|
|
|
|
|
|
- titleWidget.node.appendChild(titleInput);
|
|
|
+ /**
|
|
|
+ * Handle `after-attach` messages for the widget.
|
|
|
+ */
|
|
|
+ protected onAfterAttach(msg: Message): void {
|
|
|
+ super.onAfterAttach(msg);
|
|
|
+ this.inputElement.addEventListener('keyup', this);
|
|
|
+ this.inputElement.addEventListener('click', this);
|
|
|
+ this.inputElement.addEventListener('blur', this);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Handle `before-detach` messages for the widget.
|
|
|
+ */
|
|
|
+ protected onBeforeDetach(msg: Message): void {
|
|
|
+ super.onBeforeDetach(msg);
|
|
|
+ this.inputElement.removeEventListener('keyup', this);
|
|
|
+ this.inputElement.removeEventListener('click', this);
|
|
|
+ this.inputElement.removeEventListener('blur', this);
|
|
|
}
|
|
|
|
|
|
handleEvent(event: Event): void {
|
|
@@ -1822,17 +1833,18 @@ namespace Private {
|
|
|
private async _evtKeyUp(event: KeyboardEvent): Promise<void> {
|
|
|
if (event.key == 'Enter') {
|
|
|
const widget = this._shell.currentWidget;
|
|
|
- if (widget instanceof DocumentWidget) {
|
|
|
- const oldName = widget.context.path.split('/').pop()!;
|
|
|
- const inputElement = this.titleWidget.node
|
|
|
- .children[0] as HTMLInputElement;
|
|
|
- const newName = inputElement.value;
|
|
|
- inputElement.blur();
|
|
|
- if (newName !== oldName && isValidFileName(newName)) {
|
|
|
- await widget.context.rename(newName);
|
|
|
- } else {
|
|
|
- inputElement.value = oldName;
|
|
|
- }
|
|
|
+ if (widget == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const oldName = widget.title.label;
|
|
|
+ const inputElement = this.inputElement;
|
|
|
+ const newName = inputElement.value;
|
|
|
+ inputElement.blur();
|
|
|
+
|
|
|
+ if (newName !== oldName) {
|
|
|
+ widget.title.label = newName;
|
|
|
+ } else {
|
|
|
+ inputElement.value = oldName;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1846,15 +1858,7 @@ namespace Private {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const currentWidget = this._shell.currentWidget;
|
|
|
- const inputElement = this.titleWidget.node
|
|
|
- .children[0] as HTMLInputElement;
|
|
|
- if (currentWidget == null || !(currentWidget instanceof DocumentWidget)) {
|
|
|
- inputElement.readOnly = true;
|
|
|
- return;
|
|
|
- } else {
|
|
|
- inputElement.removeAttribute('readOnly');
|
|
|
- }
|
|
|
+ const inputElement = this.inputElement;
|
|
|
|
|
|
event.preventDefault();
|
|
|
event.stopPropagation();
|
|
@@ -1870,50 +1874,13 @@ namespace Private {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Get the input element managed by the handler.
|
|
|
- */
|
|
|
- get titleWidget(): Widget {
|
|
|
- return this._titleWidget;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Dispose of the handler and the resources it holds.
|
|
|
- */
|
|
|
- dispose(): void {
|
|
|
- if (this.isDisposed) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._isDisposed = true;
|
|
|
- this._titleWidget.node.removeEventListener('keyup', this);
|
|
|
- this._titleWidget.node.removeEventListener('click', this);
|
|
|
- this._titleWidget.node.removeEventListener('blur', this);
|
|
|
- this._titleWidget.dispose();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Hide the title widget.
|
|
|
- */
|
|
|
- hide(): void {
|
|
|
- this._titleWidget.hide();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Show the title widget.
|
|
|
- */
|
|
|
- show(): void {
|
|
|
- this._titleWidget.show();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Test whether the handler has been disposed.
|
|
|
+ * The input element containing the parent widget's title.
|
|
|
*/
|
|
|
- get isDisposed(): boolean {
|
|
|
- return this._isDisposed;
|
|
|
+ get inputElement(): HTMLInputElement {
|
|
|
+ return this.node.children[0] as HTMLInputElement;
|
|
|
}
|
|
|
|
|
|
- private _titleWidget: Widget;
|
|
|
private _shell: ILabShell;
|
|
|
- private _isDisposed: boolean = false;
|
|
|
private _selected: boolean = false;
|
|
|
}
|
|
|
|