如何在 jupyterlab 扩展中使用事件?

How to use events in jupyterlab extensions?

我想在自定义扩展中收听 JupyterLab 笔记本(版本 3.2.0)的单元格事件。我该怎么做?

a) 搜索有关“事件”的文档没有提供有用的信息:

https://jupyterlab.readthedocs.io/en/latest/search.html?q=events&check_keywords=yes&area=default

b) 这是我能找到的一些过时的例子:

Jupyter.events.on('execute.CodeCell', function(evt, data) {
    // data.cell is the cell object
});

https://github.com/jupyter/notebook/issues/2321

b) 这是截取的另一个过时代码:

require([
    "base/js/namespace",
    "base/js/events"
], 
    function(Jupyter, events){
        console.log("hello2");  
        events.on('notebook_loaded.Notebook', function(){
            console.log("hello3");
        });
        events.on('app_initialized.NotebookApp', function(){
            console.log("hello4");
        });
});

https://github.com/jupyter/notebook/issues/2499

我希望使用类似

的东西
app.events

var { Events } = require('@jupyterlab/events');

但是,这些变体不起作用。

编辑

我找到了另一个代码片段:

panel.notebook.model.cells.changed.connect((list, changed) => {
            if (changed.type == 'add') {
                each(changed.newValues, cellmodel => {
                    let cell = panel.notebook.widgets.find(x => x.model.id === cellmodel.id);
                    // do something with cell widget.
                });
            }
        });

https://github.com/jupyterlab/jupyterlab/issues/4316

也许不再有全局“事件注册表”,但需要通过模型访问事件 属性?

相关:

Where is a docs for Jupyter front-end extensions JavaScript API?

JupyterLab Extensions 应该使用 signal pattern which is based on lumino Signal 实现来监听与应用程序相关的事件。

您可以在参考文献中识别感兴趣的信号 JupyterLab API Reference (which is also linked from the documentation as the last entry), for example, cell execution signal is available as NotebookActions.executed

扩展示例

https://github.com/jupyterlab/extension-examples/tree/master/signals

NotebookActions 的信号

可观察列表的信号

单个细胞的信号

细胞模型提供信号

用法示例:

function __observeNotebook(app, dependencies){  

    let notebook = __tryToGetNotebook(app);
    if(notebook){       
        let cellModels = notebook.model.cells
        cellModels.changed.connect(__cellsChanged, this);   

        for(let cellIndex=0; cellIndex < cellModels.length; cellIndex++){
            let cellModel = cellModels.get(cellIndex);          
            __observeCell(cellModel, notebook);
        }

        let notebookActions = dependencies["NotebookActions"];
        notebookActions.executed.connect(__cellExecuted, this);  //selectionExecuted, exutionScheduled
    }        

}

function __observeCell(cellModel, notebook){   
    cellModel.contentChanged.connect(cellModel => __cellContentChanged(cellModel, notebook), this);   
    cellModel.stateChanged.connect(__cellStateChanged, this);   
}

function __cellsChanged(cellModels, change){
    console.log("Cells changed:")
    console.log("type: " + change.type);
    console.log("oldIndex: " + change.oldIndex);
    console.log("newIndex: " + change.newIndex);
    console.log("oldValues: " + change.oldValues); 
    console.log("newValues: " + change.newValues); 

    if(change.type == "add"){
        var newCellModel = cellModels.get(change.newIndex);
        __observeCell(newCellModel);
    }
}

function __cellContentChanged(cellModel, notebook){ 
    let id = cellModel.id
    console.log("Content of cell " + id + " changed");

    let currentText =  cellModel.value.text;
    console.log(currentText);
   
    let cellWidget = notebook.widgets.find(widget=>{
        return widget.model.id == id;
    });

    let outputArea = cellWidget.outputArea;
    let children = outputArea.node.children;
    if(children.length==1){
        let output = children[0];
        console.log(output);
    }
   
}

function __cellStateChanged(cellModel, change){
    let currentText =  cellModel.value.text;
    console.log("State of cell " + cellModel.id + " changed:");
    console.log("name: " + change.name);
    console.log("old value: " + change.oldValue);
    console.log("new value: " + change.newValue);
}

function __cellExecuted(any, context){
    let {cell, notebook, success, error} = context; 
    console.log("Executed cell " + cell.model.id);
}


function __tryToGetNotebookCell(app){   
    var notebook = __tryToGetNotebook(app);
    return notebook
        ?notebook.activeCell
        :null;      
}

function __tryToGetNotebook(app){
    var notebookPanel = __getFirstVisibleNotebookPanel(app);
    return notebookPanel
        ?notebookPanel.content
        :null;
}


function __getFirstVisibleNotebookPanel(app){
    var mainWidgets = app.shell.widgets('main');
    var widget = mainWidgets.next();
    while(widget){
        var type = widget.sessionContext.type;
        if(type == 'notebook'){  //other wigets might be of type DocumentWidget
            if (widget.isVisible){
                return widget;
            }
        }
        widget = mainWidgets.next();
    }
    return null;
}