jupyterlab / extension-examples

JupyterLab Extensions by Examples
BSD 3-Clause "New" or "Revised" License
438 stars 167 forks source link

Add example of toolbar button in text editor (+for particular file extension) #188

Open ktaletsk opened 2 years ago

ktaletsk commented 2 years ago

Problem

There is an excellent example on how to add a button to the notebook toolbar, which boils down to https://github.com/jupyterlab/extension-examples/blob/9c35013ce5da125f1b5865b3f7cbb301970d5970/toolbar-button/src/index.ts#L67

Now, I would like to do the same with other editors available in JupyterLab, in particular tailored for the specific file extension (think .py or .md or .tex). I played around with the example and reached the desired result. I thought the answer might be useful for someone else searching for the same functionality.

The first part (adding button to all text editors) is straightforward: change the name of the widget factory widgetName in the addWidgetExtension call from 'Notebook' to 'Editor'. The second part I achieved by checking the path ending:

// Limit the toolbar button for .tex files only
if (context.path.endsWith('.tex')) {
  panel.toolbar.insertItem(10, 'clearOutputs', button);
}

I am not sure this is the best (or even valid) way to do this, but it gave the desired result. The full example is available in my fork: https://github.com/ktaletsk/extension-examples/blob/toolbar-button-editor/toolbar-button/src/index.ts

To summarize, I would like to:

  1. Ask community if the proposed solution is the way to go for buttons in specific file extension editors
  2. Add the accepted solution (either mine or better one from community) as part of toolbar-button example or posible a different example in this repo. I would be happy to create PR.

Proposed Solution

Add example of the toolbar button enabled only for specific file extension

Additional context

Proposed example in action: image

welcome[bot] commented 2 years ago

Thank you for opening your first issue in this project! Engagement like this is essential for open source projects! :hugs:
If you haven't done so already, check out Jupyter's Code of Conduct. Also, please try to follow the issue template as it helps other other community members to contribute more effectively. welcome You can meet the other Jovyans by joining our Discourse forum. There is also an intro thread there where you can stop by and say Hi! :wave:
Welcome to the Jupyter community! :tada:

fcollonval commented 2 years ago

Hey @ktaletsk thanks for proposing.

This looks great. For information there is a simpler way coming in JLab 3.3 to add buttons from settings (see documentation).
In that method the command isEnabled method is used but not the isVisible.

But for the case you are targeting with conditions on whether the button should be added or not. This looks good (note that the type of the widget should be updated as you are not receiving a NotebookPanel in the case of the file editor).

Happy to review a PR on this.

ktaletsk commented 2 years ago

@fcollonval thanks for offering to review. Draft PR is now open. I added the new editor toolbar button alongside with the old notebook toolbar button in the index.ts. I would be interested to also add the Toolbar Registry button example once 3.3 ships.

I have to admit, I do not understand the machinery of widgets/panels/registries very well, so bear with me here. What should be the equivalent of NotebookPanel for the file editor? Also, my new example is compiling and working, even though I am passing NotebookPanel there.

fcollonval commented 2 years ago

@fcollonval thanks for offering to review. Draft PR is now open. I added the new editor toolbar button alongside with the old notebook toolbar button in the index.ts. I would be interested to also add the Toolbar Registry button example once 3.3 ships.

:rocket:

I have to admit, I do not understand the machinery of widgets/panels/registries very well, so bear with me here. What should be the equivalent of NotebookPanel for the file editor? Also, my new example is compiling and working, even though I am passing NotebookPanel there.

For the file editor, you will receive a IDocumentWidget<FileEditor>. This is hidden because TypeScript is only a static typer. It does not act at runtime (during which the browser is executing pure non-typed JavaScript). And it works because you are only using the common interface provided by IDocumentWidget (that is both implemented by NotebookPanel and the file editor.

More in-depth, the reason TypeScript is not complaining is that function

addWidgetExtension(
    widgetName: string,
    extension: DocumentRegistry.WidgetExtension
  )

There the type of extension is linked dynamically by the provided name. So you can provide any kind of extension that provide the correct interface.