Skip to content

Instantly share code, notes, and snippets.

@psychemedia
Last active April 8, 2022 09:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save psychemedia/da20c8b4a1ce111498f20176c1a1ce6d to your computer and use it in GitHub Desktop.
Save psychemedia/da20c8b4a1ce111498f20176c1a1ce6d to your computer and use it in GitHub Desktop.
Jupyterlab-empinken early sketches
// Most of the code cribbed from @krassowski
// https://stackoverflow.com/questions/71736749/accessing-notebook-cell-metadata-and-html-class-attributes-in-jupyterlab-extensi/71744107?noredirect=1#comment126807644_71744107
// Testing this in:
// https://github.com/jupyterlab/jupyterlab-plugin-playground
import { IDisposable, DisposableDelegate } from '@lumino/disposable';
import {
JupyterFrontEnd,
JupyterFrontEndPlugin,
} from '@jupyterlab/application';
import { DocumentRegistry } from '@jupyterlab/docregistry';
import {
NotebookActions,
NotebookPanel,
INotebookModel,
} from '@jupyterlab/notebook';
/**
* The plugin registration information.
*/
const plugin: JupyterFrontEndPlugin<void> = {
activate,
id: 'ouseful-tag-class-demo',
autoStart: true,
};
/*
The most relevant docs appear to be:
https://jupyterlab.readthedocs.io/en/stable/api/modules/notebook.notebookactions.html
*/
export class ClassDemoExtension
implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel>
{
/**
* Create a new extension for the notebook panel widget.
*
* @param panel Notebook panel
* @param context Notebook context
* @returns Disposable
*/
createNew(
panel: NotebookPanel,
context: DocumentRegistry.IContext<INotebookModel>
): IDisposable {
const notebook = panel.content;
function check_tags(notebook){
/*
Iterate through all the cells
If we see a cell with a tag that starts with class-
then add a corresponding tag to differnt elements in the
notebook HTML DOM
*/
for (const cell of notebook.widgets) {
let tagList = cell.model.metadata.get('tags') as string[];
if (tagList) {
for (let i = 0; i < tagList.length; i++) {
var tag = tagList[i];
if tag.startsWith("class-") {
/*
The plugin playground extension is rather hostile
to have-a-go end-user devs (it's rather strict in
its Javascript epxectations) so if you don't
declare things with let, const or var then an
error of the following form is likely to be thrown
that stops further execution:
ReferenceError: class_name is not definred
*/
//This will replace just the first instance of class-
const class_name = tag.replace("class-", "tag-")
// Add class tags to various parts of the DOM
// What sort of cell are we?
console.log("Cell type: " + cell.model.type)
// Try to see what's going on...
console.log("Try node...")
cell.node.classList.add(class_name + "-" + cell.model.type + "-node");
console.log("Try inputArea.node...")
cell.inputArea.node.classList.add(class_name + "-" + cell.model.type + "-inputArea_node");
console.log("Try editor.node...")
cell.editor.host.classList.add(class_name + "-" + cell.model.type + "-editor_host");
console.log("Try .inputArea.promptNode...")
cell.inputArea.promptNode.classList.add(class_name + "-" + cell.model.type + "-inputArea_promptNode");
if (cell.model.type=="markdown") {
//console.log("Try RenderedHTMLCommon.node...")
//cell.RenderedHTMLCommon.node.classList.add(class_name + "-" + cell.model.type + "-RenderedHTMLCommon.node")
//TO DO - access lm-Widget p-Widget jp-RenderedHTMLCommon jp-RenderedMarkdown jp-MarkdownOutput
// DOESN'T WORK: cell.MarkdownOutput.node, MarkdownOutput.host, RenderedMarkdown.node, RenderedHTMLCommon.node
}
else {
console.log("Try outputArea.node...")
cell.outputArea.node.classList.add(class_name + "-" + cell.model.type + "-outputArea_node")
}
} // end: if class starts with tag...
} // end: tags iterator
} //end: if there are tags
} // end: iterate cells
} // end: check_tags function definition
notebook.modelChanged.connect((notebook) => {
console.log("I think we're changed");
// This doesn't seem to do anything on notebook load
// iterate cells and toggle DOM classes as needed, e.g.
//check_tags(notebook);
});
notebook.fullyRendered.connect((notebook) => {
/*
I don't think this means fully rendered on a cells becuase it seems
like we try to add the tags mutliple times on notebook load
which is really inefficient.
This may be unstable anyway, eg the following comment:
https://stackoverflow.com/questions/71736749/accessing-notebook-cell-metadata-and-html-class-attributes-in-jupyterlab-extensi/71744107?noredirect=1#comment126807644_71744107
I'll with go with in now in the expectation it will be break
and I will hopefully be able to find another even to fire from.
I get the impression the UI is some some of signal hell and
the solution is just to keep redoing things on everything
if anything changes. Who needs efficiency or elegance anyway...!
After all, this is just an end-user hack-from-a-position-of-ignorance
and works sort of enough to do something that I couldn't do before...
*/
console.log("I think we're fullyRendered...(?!)");
// iterate cells and toggle DOM classes as needed, e.g.
check_tags(notebook);
});
return new DisposableDelegate(() => {
});
}
}
/**
* Activate the extension.
*
* @param app Main application object
*/
function activate(app: JupyterFrontEnd): void {
app.docRegistry.addWidgetExtension('Notebook', new ClassDemoExtension());
}
/**
* Export the plugin as default.
*/
export default plugin;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment