Skip to content

Commit

Permalink
Move token to its own file (#50)
Browse files Browse the repository at this point in the history
* Move token to its own file

* Add factory token

* Add doc and lint
  • Loading branch information
fcollonval authored Sep 8, 2023
1 parent 866db0c commit e8dedca
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 59 deletions.
7 changes: 6 additions & 1 deletion packages/application/src/plugins/rise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@ export const plugin: JupyterFrontEndPlugin<void> = {
app.restored
]).then(async ([settings]) => {
const notebookPath = PageConfig.getOption('notebookPath');
const notebookPanel = documentManager.open(notebookPath) as NotebookPanel;
const notebookPanel = (documentManager.open(notebookPath, 'Notebook') ??
// If the file cannot be opened with the Notebook factory, try jupytext
documentManager.open(
notebookPath,
'Jupytext Notebook'
)) as NotebookPanel;
// With the new windowing, some cells are not visible and we need
// to deactivate the windowing and wait for each cell to be ready.
notebookPanel.content.notebookConfig = {
Expand Down
1 change: 1 addition & 0 deletions packages/lab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@lumino/coreutils": "^2.0.0",
"@lumino/disposable": "^2.0.0",
"@lumino/messaging": "^2.0.0",
"@lumino/signaling": "^2.0.0",
"@lumino/widgets": "^2.0.1"
},
"devDependencies": {
Expand Down
74 changes: 37 additions & 37 deletions packages/lab/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import {
WidgetTracker
} from '@jupyterlab/apputils';

import { PageConfig, URLExt } from '@jupyterlab/coreutils';

import { DocumentRegistry } from '@jupyterlab/docregistry';

import {
Expand All @@ -24,21 +22,19 @@ import {

import { ISettingRegistry } from '@jupyterlab/settingregistry';

import { ITranslator } from '@jupyterlab/translation';
import { ITranslator, nullTranslator } from '@jupyterlab/translation';

import { toArray } from '@lumino/algorithm';

import { ReadonlyPartialJSONObject } from '@lumino/coreutils';

import { fullScreenIcon, RISEIcon } from './icons';

import {
RisePreview,
IRisePreviewTracker,
RisePreviewFactory
} from './preview';
import { RisePreview } from './preview';

export { IRisePreviewTracker } from './preview';
import { IRisePreviewFactory, IRisePreviewTracker } from './tokens';

export { IRisePreviewFactory, IRisePreviewTracker } from './tokens';

/**
* Command IDs namespace for JupyterLab RISE extension
Expand All @@ -59,27 +55,46 @@ namespace CommandIDs {
export const riseSetSlideType = 'RISE:set-slide-type';
}

const factory: JupyterFrontEndPlugin<IRisePreviewFactory> = {
id: 'jupyterlab-rise:factory',
provides: IRisePreviewFactory,
optional: [ITranslator],
activate: (
app: JupyterFrontEnd,
translator: ITranslator | null
): IRisePreviewFactory => {
const { commands, docRegistry } = app;
return new RisePreview.FactoryToken({
commands,
docRegistry,
translator: translator ?? undefined
});
}
};

/**
* Open the notebook with RISE.
*/
const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
id: 'jupyterlab-rise:plugin',
autoStart: true,
requires: [ITranslator],
requires: [IRisePreviewFactory],
optional: [
INotebookTracker,
ICommandPalette,
ILayoutRestorer,
ISettingRegistry
ISettingRegistry,
ITranslator
],
provides: IRisePreviewTracker,
activate: (
app: JupyterFrontEnd,
translator: ITranslator,
factory: IRisePreviewFactory,
notebookTracker: INotebookTracker | null,
palette: ICommandPalette | null,
restorer: ILayoutRestorer | null,
settingRegistry: ISettingRegistry | null
settingRegistry: ISettingRegistry | null,
translator: ITranslator | null
): IRisePreviewTracker => {
console.log('JupyterLab extension jupyterlab-rise is activated!');

Expand All @@ -92,8 +107,8 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
return tracker;
}

const { commands, docRegistry, shell } = app;
const trans = translator.load('rise');
const { commands, shell } = app;
const trans = (translator ?? nullTranslator).load('rise');

let settings: ISettingRegistry.ISettings | null = null;
if (settingRegistry) {
Expand All @@ -102,28 +117,19 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
});
}

const factory = new RisePreviewFactory(getRiseUrl, commands, {
name: 'rise',
label: trans.__('Rise Slides'),
fileTypes: ['notebook'],
modelName: 'notebook'
});

if (restorer) {
restorer.restore(tracker, {
// Need to modify to handle auto full screen
command: 'docmanager:open',
args: panel => ({
path: panel.context.path,
factory: factory.name
factory: RisePreview.FACTORY_NAME
}),
name: panel => panel.context.path,
when: app.serviceManager.ready
});
}

docRegistry.addWidgetFactory(factory);

function getCurrent(args: ReadonlyPartialJSONObject): NotebookPanel | null {
const widget = notebookTracker?.currentWidget ?? null;
const activate = args['activate'] !== false;
Expand All @@ -142,15 +148,6 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
);
}

function getRiseUrl(path: string, activeCellIndex?: number): string {
const baseUrl = PageConfig.getBaseUrl();
let url = `${baseUrl}rise/${path}`;
if (typeof activeCellIndex === 'number') {
url += URLExt.objectToQueryString({ activeCellIndex });
}
return url;
}

factory.widgetCreated.connect((sender, widget) => {
// Notify the widget tracker if restore data needs to update.
widget.context.pathChanged.connect(() => {
Expand All @@ -176,7 +173,10 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
}
await current.context.save();
window.open(
getRiseUrl(current.context.path, current.content.activeCellIndex)
RisePreview.getRiseUrl(
current.context.path,
current.content.activeCellIndex
)
);
},
isEnabled
Expand All @@ -198,7 +198,7 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
'docmanager:open',
{
path: context.path,
factory: 'rise',
factory: RisePreview.FACTORY_NAME,
options: {
mode: 'split-right'
}
Expand Down Expand Up @@ -378,4 +378,4 @@ const plugin: JupyterFrontEndPlugin<IRisePreviewTracker> = {
}
};

export default plugin;
export default [factory, plugin];
127 changes: 106 additions & 21 deletions packages/lab/src/preview.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {
IFrame,
ToolbarButton,
IWidgetTracker,
Toolbar
} from '@jupyterlab/apputils';
import { IFrame, ToolbarButton, Toolbar } from '@jupyterlab/apputils';

import { PageConfig, URLExt } from '@jupyterlab/coreutils';

import {
ABCWidgetFactory,
Expand All @@ -19,28 +16,18 @@ import { refreshIcon } from '@jupyterlab/ui-components';

import { CommandRegistry } from '@lumino/commands';

import { PromiseDelegate, Token } from '@lumino/coreutils';
import { PromiseDelegate } from '@lumino/coreutils';

import { DisposableSet, IDisposable } from '@lumino/disposable';

import { Message } from '@lumino/messaging';

import { Signal } from '@lumino/signaling';
import { ISignal, Signal } from '@lumino/signaling';

import { Widget } from '@lumino/widgets';

import { fullScreenIcon, RISEIcon } from './icons';

/**
* A class that tracks Rise Preview widgets.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IRisePreviewTracker extends IWidgetTracker<RisePreview> {}

/**
* The Rise Preview tracker token.
*/
export const IRisePreviewTracker = new Token<IRisePreviewTracker>(
'jupyterlab-rise:IRisePreviewTracker'
);
import { IRisePreviewFactory } from './tokens';

/**
* A DocumentWidget that shows a Rise preview in an IFrame.
Expand Down Expand Up @@ -230,6 +217,8 @@ export class RisePreview extends DocumentWidget<IFrame, INotebookModel> {
* A namespace for RisePreview statics.
*/
export namespace RisePreview {
export const FACTORY_NAME = 'rise';

/**
* Instantiation options for `RisePreview`.
*/
Expand All @@ -249,8 +238,104 @@ export namespace RisePreview {
*/
renderOnSave?: boolean;
}

/**
* Generate the URL required to open a file as RISE slideshow.
*
* @param path File path
* @param activeCellIndex Active cell index
* @returns URL to open
*/
export function getRiseUrl(path: string, activeCellIndex?: number): string {
const baseUrl = PageConfig.getBaseUrl();
let url = `${baseUrl}rise/${path}`;
if (typeof activeCellIndex === 'number') {
url += URLExt.objectToQueryString({ activeCellIndex });
}
return url;
}

/**
* RISE Preview document factory token implementation.
*/
export class FactoryToken implements IRisePreviewFactory {
constructor({
commands,
docRegistry,
fileTypes,
translator
}: {
commands: CommandRegistry;
docRegistry: DocumentRegistry;
fileTypes?: string[];
translator?: ITranslator;
}) {
this._commands = commands;
this._docRegistry = docRegistry;
this._fileTypes = fileTypes ?? ['notebook'];
this._translator = translator ?? nullTranslator;

this._updateFactory();
}

/**
* Add a new file type to the RISE preview factory.
*
* #### Notes
* Useful to add file types for jupytext.
*
* @param ft File type
*/
addFileType(ft: string): void {
if (!this._fileTypes.includes(ft)) {
this._fileTypes.push(ft);
this._updateFactory();
}
}

/**
* Signal emitted when a RISE preview is created.
*/
get widgetCreated(): ISignal<IRisePreviewFactory, RisePreview> {
return this._widgetCreated;
}

private _updateFactory(): void {
if (this._disposeFactory) {
this._disposeFactory.dispose();
this._disposeFactory = null;
}

const trans = this._translator.load('rise');
const factory = new RisePreviewFactory(getRiseUrl, this._commands, {
name: FACTORY_NAME,
label: trans.__('Rise Slides'),
fileTypes: this._fileTypes,
modelName: 'notebook'
});

factory.widgetCreated.connect((_, args) => {
this._widgetCreated.emit(args);
}, this);

this._disposeFactory = DisposableSet.from([
this._docRegistry.addWidgetFactory(factory),
factory
]);
}

private _commands: CommandRegistry;
private _disposeFactory: IDisposable | null = null;
private _docRegistry: DocumentRegistry;
private _fileTypes: string[];
private _translator: ITranslator;
private _widgetCreated = new Signal<FactoryToken, RisePreview>(this);
}
}

/**
* RISE Preview widget factory
*/
export class RisePreviewFactory extends ABCWidgetFactory<
RisePreview,
INotebookModel
Expand Down
45 changes: 45 additions & 0 deletions packages/lab/src/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { IWidgetTracker } from '@jupyterlab/apputils';
import { Token } from '@lumino/coreutils';
import { ISignal } from '@lumino/signaling';
import type { RisePreview } from './preview';

/**
* A class that tracks Rise Preview widgets.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface IRisePreviewTracker extends IWidgetTracker<RisePreview> {}

/**
* The Rise Preview tracker token.
*/
export const IRisePreviewTracker = new Token<IRisePreviewTracker>(
'jupyterlab-rise:IRisePreviewTracker',
'Adds a tracker for RISE slides preview widgets.'
);

/**
* RISE Preview document factory interface
*/
export interface IRisePreviewFactory {
/**
* Signal emitted when a RISE preview is created.
*/
readonly widgetCreated: ISignal<IRisePreviewFactory, RisePreview>;
/**
* Add a new file type to the RISE preview factory.
*
* #### Notes
* Useful to add file types for jupytext.
*
* @param ft File type
*/
addFileType(ft: string): void;
}

/**
* RISE Preview factory token.
*/
export const IRisePreviewFactory = new Token<IRisePreviewFactory>(
'jupyterlab-rise:IRisePreviewFactory',
'Customize the RISE slides preview factory.'
);
Loading

0 comments on commit e8dedca

Please sign in to comment.