I’m changing a single icon of a specific named folder in either the directory list or the breadcrumb when the directory listing is loaded. I’m able to do this in my frontend extension’s activate(), but I have to add a delay because the DOM is not yet created on extension activation. Ideally there is a hook for when JL’s directory listing changes because I need to re-call the code at that time.
How can I listen to document or window events within the JupyterFrontEndPlugin activate function? I find it strange that I am unable to use document.addEventListener()
but I am able to use document.getElementsByClassName()
. I have the following so far. JupyterLab 4.3.0.
index.ts
import {
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
const extension: JupyterFrontEndPlugin<void> = {
id: 'my_first_extension:plugin',
description: 'my first plugin',
autoStart: true,
activate: (
app: JupyterFrontEnd,
) => {
// add event listeners - three of four calls yield no output in the console
window.addEventListener("load", (event) => {
console.log("loaded", event);
});
window.addEventListener("unload", (event) => {
console.log("unloaded", event);
// this works when we leave the page
});
document.addEventListener("readystatechange", (event) => {
console.log(`readystate: ${document.readyState}`, event);
});
document.addEventListener("DOMContentLoaded", (event) => {
console.log(`DOMContentLoaded`, event);
});
// this code works correctly after 3 seconds have elapsed
setTimeout(() => {
// replace the folder icon in the directory list
const folderIconElements = document.getElementsByClassName('jp-DirListing-itemName') as HTMLCollectionOf<HTMLElement>;
for (let i = 0; i < folderIconElements.length; i++) {
if (folderIconElements[i]['innerText'] === 'my directory') {
const children = folderIconElements[i].children;
for (let j = 0; j < children.length; j++) {
if (j === 0) {
// replace folder svg with folderFavorite
children[j].innerHTML = children[j].innerHTML.replace(
'd="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"',
'd="M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2m-2.06 11L15 15.28 12.06 17l.78-3.33-2.59-2.24 3.41-.29L15 8l1.34 3.14 3.41.29-2.59 2.24z"'
);
}
}
}
}
// replace the folder icon in the breadcrumb
const breadcrumbElement = document.getElementsByClassName('jp-FileBrowser-crumbs') as HTMLCollectionOf<HTMLElement>;
const bChildren = breadcrumbElement[0].children;
if (bChildren.length > 3 && bChildren[2].innerHTML === 'my directory') {
bChildren[0].innerHTML = bChildren[0].innerHTML.replace(
'd="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"',
'd="M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2m-2.06 11L15 15.28 12.06 17l.78-3.33-2.59-2.24 3.41-.29L15 8l1.34 3.14 3.41.29-2.59 2.24z"'
);
}
}, 3000);
console.log('my first extension is activated!');
}
};
export default extension;
I did not understand how to use use app.handleEvent() (only seems to register keyup, keydown, resize, and context menu), or addEventListeners (v3.x?) as an element in the JupyterFrontEndPlugin definition (after autoStart and before the activate: () => {} definition).
I had some success with a MutationObserver on document.getElementsByClassName("jp-DirListing-content")[0]
, and am working through that, but would prefer if there was a built in event/hook for when the directory changes.