@jupyterlab/notebook-extension 4.6.0-alpha.3 → 4.6.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyterlab/notebook-extension",
3
- "version": "4.6.0-alpha.3",
3
+ "version": "4.6.0-alpha.5",
4
4
  "description": "JupyterLab - Notebook Extension",
5
5
  "homepage": "https://github.com/jupyterlab/jupyterlab",
6
6
  "bugs": {
@@ -37,36 +37,36 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@jupyter/ydoc": "^3.1.0",
40
- "@jupyterlab/application": "^4.6.0-alpha.3",
41
- "@jupyterlab/apputils": "^4.7.0-alpha.3",
42
- "@jupyterlab/cell-toolbar": "^4.6.0-alpha.3",
43
- "@jupyterlab/cells": "^4.6.0-alpha.3",
44
- "@jupyterlab/codeeditor": "^4.6.0-alpha.3",
45
- "@jupyterlab/codemirror": "^4.6.0-alpha.3",
46
- "@jupyterlab/completer": "^4.6.0-alpha.3",
47
- "@jupyterlab/coreutils": "^6.6.0-alpha.3",
48
- "@jupyterlab/docmanager": "^4.6.0-alpha.3",
49
- "@jupyterlab/docmanager-extension": "^4.6.0-alpha.3",
50
- "@jupyterlab/docregistry": "^4.6.0-alpha.3",
51
- "@jupyterlab/documentsearch": "^4.6.0-alpha.3",
52
- "@jupyterlab/filebrowser": "^4.6.0-alpha.3",
53
- "@jupyterlab/launcher": "^4.6.0-alpha.3",
54
- "@jupyterlab/logconsole": "^4.6.0-alpha.3",
55
- "@jupyterlab/lsp": "^4.6.0-alpha.3",
56
- "@jupyterlab/mainmenu": "^4.6.0-alpha.3",
57
- "@jupyterlab/metadataform": "^4.6.0-alpha.3",
58
- "@jupyterlab/nbformat": "^4.6.0-alpha.3",
59
- "@jupyterlab/notebook": "^4.6.0-alpha.3",
60
- "@jupyterlab/observables": "^5.6.0-alpha.3",
61
- "@jupyterlab/property-inspector": "^4.6.0-alpha.3",
62
- "@jupyterlab/rendermime": "^4.6.0-alpha.3",
63
- "@jupyterlab/services": "^7.6.0-alpha.3",
64
- "@jupyterlab/settingregistry": "^4.6.0-alpha.3",
65
- "@jupyterlab/statedb": "^4.6.0-alpha.3",
66
- "@jupyterlab/statusbar": "^4.6.0-alpha.3",
67
- "@jupyterlab/toc": "^6.6.0-alpha.3",
68
- "@jupyterlab/translation": "^4.6.0-alpha.3",
69
- "@jupyterlab/ui-components": "^4.6.0-alpha.3",
40
+ "@jupyterlab/application": "^4.6.0-alpha.5",
41
+ "@jupyterlab/apputils": "^4.7.0-alpha.5",
42
+ "@jupyterlab/cell-toolbar": "^4.6.0-alpha.5",
43
+ "@jupyterlab/cells": "^4.6.0-alpha.5",
44
+ "@jupyterlab/codeeditor": "^4.6.0-alpha.5",
45
+ "@jupyterlab/codemirror": "^4.6.0-alpha.5",
46
+ "@jupyterlab/completer": "^4.6.0-alpha.5",
47
+ "@jupyterlab/coreutils": "^6.6.0-alpha.5",
48
+ "@jupyterlab/docmanager": "^4.6.0-alpha.5",
49
+ "@jupyterlab/docmanager-extension": "^4.6.0-alpha.5",
50
+ "@jupyterlab/docregistry": "^4.6.0-alpha.5",
51
+ "@jupyterlab/documentsearch": "^4.6.0-alpha.5",
52
+ "@jupyterlab/filebrowser": "^4.6.0-alpha.5",
53
+ "@jupyterlab/launcher": "^4.6.0-alpha.5",
54
+ "@jupyterlab/logconsole": "^4.6.0-alpha.5",
55
+ "@jupyterlab/lsp": "^4.6.0-alpha.5",
56
+ "@jupyterlab/mainmenu": "^4.6.0-alpha.5",
57
+ "@jupyterlab/metadataform": "^4.6.0-alpha.5",
58
+ "@jupyterlab/nbformat": "^4.6.0-alpha.5",
59
+ "@jupyterlab/notebook": "^4.6.0-alpha.5",
60
+ "@jupyterlab/observables": "^5.6.0-alpha.5",
61
+ "@jupyterlab/property-inspector": "^4.6.0-alpha.5",
62
+ "@jupyterlab/rendermime": "^4.6.0-alpha.5",
63
+ "@jupyterlab/services": "^7.6.0-alpha.5",
64
+ "@jupyterlab/settingregistry": "^4.6.0-alpha.5",
65
+ "@jupyterlab/statedb": "^4.6.0-alpha.5",
66
+ "@jupyterlab/statusbar": "^4.6.0-alpha.5",
67
+ "@jupyterlab/toc": "^6.6.0-alpha.5",
68
+ "@jupyterlab/translation": "^4.6.0-alpha.5",
69
+ "@jupyterlab/ui-components": "^4.6.0-alpha.5",
70
70
  "@lumino/algorithm": "^2.0.4",
71
71
  "@lumino/commands": "^2.3.3",
72
72
  "@lumino/coreutils": "^2.2.2",
package/schema/tools.json CHANGED
@@ -28,6 +28,21 @@
28
28
  }
29
29
  ]
30
30
  },
31
+ "/deletable": {
32
+ "title": "Deletable",
33
+ "type": "boolean",
34
+ "default": true,
35
+ "oneOf": [
36
+ {
37
+ "const": true,
38
+ "title": "Deletable"
39
+ },
40
+ {
41
+ "const": false,
42
+ "title": "Not deletable"
43
+ }
44
+ ]
45
+ },
31
46
  "/slideshow/slide_type": {
32
47
  "title": "Slide Type",
33
48
  "type": "string",
@@ -99,6 +114,9 @@
99
114
  "uiSchema": {
100
115
  "/editable": {
101
116
  "ui:widget": "select"
117
+ },
118
+ "/deletable": {
119
+ "ui:widget": "select"
102
120
  }
103
121
  },
104
122
  "metadataOptions": {
@@ -316,15 +316,13 @@
316
316
  "rank": 20
317
317
  },
318
318
  {
319
- "command": "notebook:enable-output-scrolling",
319
+ "command": "notebook:toggle-output-scrolling",
320
+ "args": {
321
+ "isMenu": true
322
+ },
320
323
  "selector": ".jp-Notebook",
321
324
  "rank": 21
322
325
  },
323
- {
324
- "command": "notebook:disable-output-scrolling",
325
- "selector": ".jp-Notebook",
326
- "rank": 22
327
- },
328
326
  {
329
327
  "type": "separator",
330
328
  "selector": ".jp-Notebook",
@@ -379,32 +377,32 @@
379
377
  {
380
378
  "command": "notebook:change-cell-to-heading-1",
381
379
  "keys": ["1"],
382
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
380
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
383
381
  },
384
382
  {
385
383
  "command": "notebook:change-cell-to-heading-2",
386
384
  "keys": ["2"],
387
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
385
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
388
386
  },
389
387
  {
390
388
  "command": "notebook:change-cell-to-heading-3",
391
389
  "keys": ["3"],
392
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
390
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
393
391
  },
394
392
  {
395
393
  "command": "notebook:change-cell-to-heading-4",
396
394
  "keys": ["4"],
397
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
395
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
398
396
  },
399
397
  {
400
398
  "command": "notebook:change-cell-to-heading-5",
401
399
  "keys": ["5"],
402
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
400
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
403
401
  },
404
402
  {
405
403
  "command": "notebook:change-cell-to-heading-6",
406
404
  "keys": ["6"],
407
- "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) :focus"
405
+ "selector": ".jp-Notebook.jp-mod-commandMode:not(.jp-mod-readWrite) .jp-MarkdownCell:focus"
408
406
  },
409
407
  {
410
408
  "command": "notebook:change-cell-to-markdown",
package/src/index.ts CHANGED
@@ -66,6 +66,7 @@ import { IMetadataFormProvider } from '@jupyterlab/metadataform';
66
66
  import type * as nbformat from '@jupyterlab/nbformat';
67
67
  import type { Notebook } from '@jupyterlab/notebook';
68
68
  import {
69
+ CellCounterStatus,
69
70
  CommandEditStatus,
70
71
  ExecutionIndicator,
71
72
  INotebookCellExecutor,
@@ -312,6 +313,8 @@ namespace CommandIDs {
312
313
 
313
314
  export const disableOutputScrolling = 'notebook:disable-output-scrolling';
314
315
 
316
+ export const toggleOutputScrolling = 'notebook:toggle-output-scrolling';
317
+
315
318
  export const selectLastRunCell = 'notebook:select-last-run-cell';
316
319
 
317
320
  export const replaceSelection = 'notebook:replace-selection';
@@ -390,11 +393,11 @@ const trackerPlugin: JupyterFrontEndPlugin<INotebookTracker> = {
390
393
  };
391
394
 
392
395
  /**
393
- * The notebook cell factory provider.
396
+ * The notebook and cell factory provider.
394
397
  */
395
398
  const factory: JupyterFrontEndPlugin<NotebookPanel.IContentFactory> = {
396
399
  id: '@jupyterlab/notebook-extension:factory',
397
- description: 'Provides the notebook cell factory.',
400
+ description: 'Provides the notebook and cell factory.',
398
401
  provides: NotebookPanel.IContentFactory,
399
402
  requires: [IEditorServices],
400
403
  autoStart: true,
@@ -464,6 +467,50 @@ export const commandEditItem: JupyterFrontEndPlugin<void> = {
464
467
  }
465
468
  };
466
469
 
470
+ /**
471
+ * A plugin providing a current cell/total cells status item.
472
+ */
473
+ export const cellCounterItem: JupyterFrontEndPlugin<void> = {
474
+ id: '@jupyterlab/notebook-extension:cell-counter-status',
475
+ description: 'Adds a notebook cell counter status widget.',
476
+ autoStart: true,
477
+ requires: [INotebookTracker, ITranslator],
478
+ optional: [IStatusBar],
479
+ activate: (
480
+ app: JupyterFrontEnd,
481
+ tracker: INotebookTracker,
482
+ translator: ITranslator,
483
+ statusBar: IStatusBar | null
484
+ ) => {
485
+ if (!statusBar) {
486
+ // Automatically disable if statusbar missing
487
+ return;
488
+ }
489
+
490
+ const { shell } = app;
491
+ const item = new CellCounterStatus({ translator });
492
+
493
+ const updateNotebook = () => {
494
+ const current = tracker.currentWidget;
495
+ item.model.notebook = current && current.content;
496
+ };
497
+
498
+ tracker.currentChanged.connect(updateNotebook);
499
+ updateNotebook();
500
+
501
+ statusBar.registerStatusItem(cellCounterItem.id, {
502
+ priority: 1,
503
+ item,
504
+ align: 'right',
505
+ rank: 2.5,
506
+ isActive: () =>
507
+ !!shell.currentWidget &&
508
+ !!tracker.currentWidget &&
509
+ shell.currentWidget === tracker.currentWidget
510
+ });
511
+ }
512
+ };
513
+
467
514
  /**
468
515
  * A plugin that provides a execution indicator item to the status bar.
469
516
  */
@@ -691,7 +738,8 @@ export const exportPlugin: JupyterFrontEndPlugin<void> = {
691
738
  // Convert export list to palette and menu items.
692
739
  const formatList = Object.keys(response);
693
740
  formatList.forEach(function (key) {
694
- const capCaseKey = trans.__(key[0].toUpperCase() + key.substr(1));
741
+ const formattedKey = key[0].toLocaleUpperCase() + key.slice(1);
742
+ const capCaseKey = trans.__(formattedKey);
695
743
  const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
696
744
  let args = {
697
745
  format: key,
@@ -1027,7 +1075,8 @@ const updateRawMimetype: JupyterFrontEndPlugin<void> = {
1027
1075
  value => value.const === key
1028
1076
  ).length > 0;
1029
1077
  if (!mimetypeExists) {
1030
- const altOption = trans.__(key[0].toUpperCase() + key.substr(1));
1078
+ const formattedKey = key[0].toLocaleUpperCase() + key.slice(1);
1079
+ const altOption = trans.__(formattedKey);
1031
1080
  const option = formatLabels[key] ? formatLabels[key] : altOption;
1032
1081
  const mimeTypeValue = response[key].output_mimetype;
1033
1082
 
@@ -1203,6 +1252,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
1203
1252
  executionIndicator,
1204
1253
  exportPlugin,
1205
1254
  tools,
1255
+ cellCounterItem,
1206
1256
  commandEditItem,
1207
1257
  notebookTrustItem,
1208
1258
  widgetFactoryPlugin,
@@ -1613,7 +1663,7 @@ function activateCodeConsole(
1613
1663
  let fromFirst = curLine > 0;
1614
1664
  let firstLine = 0;
1615
1665
  let lastLine = firstLine + 1;
1616
- // eslint-disable-next-line
1666
+
1617
1667
  while (true) {
1618
1668
  code = srcLines.slice(firstLine, lastLine).join('\n');
1619
1669
  const reply =
@@ -2014,6 +2064,8 @@ function activateNotebookHandler(
2014
2064
  // If the notebook panel does not have an ID, assign it one.
2015
2065
  widget.id = widget.id || `notebook-${++id}`;
2016
2066
 
2067
+ widget.content.node.setAttribute('data-trust-command', CommandIDs.trust);
2068
+
2017
2069
  // Set up the title icon
2018
2070
  widget.title.icon = ft?.icon;
2019
2071
  widget.title.iconClass = ft?.iconClass ?? '';
@@ -2426,6 +2478,25 @@ function getCurrent(
2426
2478
  return widget;
2427
2479
  }
2428
2480
 
2481
+ // Whether all selected code cells have output scrolling enabled.
2482
+ function isOutputScrollingEnabled(notebook: Notebook): boolean {
2483
+ if (!notebook.model || !notebook.activeCell) {
2484
+ return false;
2485
+ }
2486
+
2487
+ let hasCodeCell = false;
2488
+ for (const cell of notebook.widgets) {
2489
+ if (notebook.isSelectedOrActive(cell) && cell.model.type === 'code') {
2490
+ hasCodeCell = true;
2491
+ if (!(cell as CodeCell).outputsScrolled) {
2492
+ return false;
2493
+ }
2494
+ }
2495
+ }
2496
+
2497
+ return hasCodeCell;
2498
+ }
2499
+
2429
2500
  /**
2430
2501
  * Add the notebook commands to the application's command registry.
2431
2502
  */
@@ -2450,6 +2521,11 @@ function addCommands(
2450
2521
  cell
2451
2522
  .getHeadings()
2452
2523
  .then(() => {
2524
+ // Heading parsing is async; avoid restoring an outdated collapse
2525
+ // state if the heading has been expanded in the meantime.
2526
+ if (cell.isDisposed || !cell.headingCollapsed) {
2527
+ return;
2528
+ }
2453
2529
  NotebookActions.setHeadingCollapse(cell, true, notebook);
2454
2530
  })
2455
2531
  .catch(error => {
@@ -2518,6 +2594,7 @@ function addCommands(
2518
2594
  commands.notifyCommandChanged(CommandIDs.runAndInsert);
2519
2595
  });
2520
2596
  tracker.activeCellChanged.connect(() => {
2597
+ commands.notifyCommandChanged(CommandIDs.deleteCell);
2521
2598
  commands.notifyCommandChanged(CommandIDs.moveUp);
2522
2599
  commands.notifyCommandChanged(CommandIDs.moveDown);
2523
2600
  });
@@ -2834,12 +2911,17 @@ function addCommands(
2834
2911
  });
2835
2912
  commands.addCommand(CommandIDs.trust, {
2836
2913
  label: () => trans.__('Trust Notebook'),
2837
- execute: args => {
2914
+ execute: async args => {
2838
2915
  const current = getCurrent(tracker, shell, args);
2839
2916
  if (current) {
2840
2917
  const { context, content } = current;
2841
- return NotebookActions.trust(content).then(() => context.save());
2918
+ const trustResult = await NotebookActions.trust(content);
2919
+ if (trustResult.trusted) {
2920
+ await context.save();
2921
+ }
2922
+ return trustResult;
2842
2923
  }
2924
+ return { trusted: false };
2843
2925
  },
2844
2926
  isEnabled,
2845
2927
  describedBy: {
@@ -3358,7 +3440,18 @@ function addCommands(
3358
3440
  return NotebookActions.deleteCells(current.content);
3359
3441
  }
3360
3442
  },
3361
- isEnabled: args => (args.toolbar ? true : isEnabled()),
3443
+ isEnabled: args => {
3444
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
3445
+ if (!current) {
3446
+ return false;
3447
+ }
3448
+ // The 'deletable' metadata is optional, null and undefined values should be made truthy
3449
+ const deletable =
3450
+ (current.content.activeCell?.model.getMetadata(
3451
+ 'deletable'
3452
+ ) as unknown as boolean) !== false;
3453
+ return deletable;
3454
+ },
3362
3455
  describedBy: {
3363
3456
  args: {
3364
3457
  type: 'object',
@@ -3384,7 +3477,7 @@ function addCommands(
3384
3477
  const current = getCurrent(tracker, shell, args);
3385
3478
 
3386
3479
  if (current) {
3387
- return NotebookActions.splitCell(current.content);
3480
+ return NotebookActions.splitCell(current.content, translator);
3388
3481
  }
3389
3482
  },
3390
3483
  isEnabled,
@@ -3404,7 +3497,12 @@ function addCommands(
3404
3497
  const addExtraLine =
3405
3498
  (settings?.get('addExtraLineOnCellMerge').composite as boolean) ??
3406
3499
  true;
3407
- return NotebookActions.mergeCells(current.content, false, addExtraLine);
3500
+ return NotebookActions.mergeCells(
3501
+ current.content,
3502
+ false,
3503
+ addExtraLine,
3504
+ translator
3505
+ );
3408
3506
  }
3409
3507
  },
3410
3508
  isEnabled,
@@ -3424,7 +3522,12 @@ function addCommands(
3424
3522
  const addExtraLine =
3425
3523
  (settings?.get('addExtraLineOnCellMerge').composite as boolean) ??
3426
3524
  true;
3427
- return NotebookActions.mergeCells(current.content, true, addExtraLine);
3525
+ return NotebookActions.mergeCells(
3526
+ current.content,
3527
+ true,
3528
+ addExtraLine,
3529
+ translator
3530
+ );
3428
3531
  }
3429
3532
  },
3430
3533
  isEnabled,
@@ -3444,7 +3547,12 @@ function addCommands(
3444
3547
  const addExtraLine =
3445
3548
  (settings?.get('addExtraLineOnCellMerge').composite as boolean) ??
3446
3549
  true;
3447
- return NotebookActions.mergeCells(current.content, false, addExtraLine);
3550
+ return NotebookActions.mergeCells(
3551
+ current.content,
3552
+ false,
3553
+ addExtraLine,
3554
+ translator
3555
+ );
3448
3556
  }
3449
3557
  },
3450
3558
  isEnabled,
@@ -4382,6 +4490,43 @@ function addCommands(
4382
4490
  }
4383
4491
  }
4384
4492
  });
4493
+ commands.addCommand(CommandIDs.toggleOutputScrolling, {
4494
+ label: args =>
4495
+ args['isMenu'] || args['isPalette']
4496
+ ? trans.__('Enable Scrolling for Outputs')
4497
+ : trans.__('Toggle Scrolling for Outputs'),
4498
+ execute: args => {
4499
+ const current = getCurrent(tracker, shell, args);
4500
+
4501
+ if (current) {
4502
+ if (isOutputScrollingEnabled(current.content)) {
4503
+ return NotebookActions.disableOutputScrolling(current.content);
4504
+ }
4505
+
4506
+ return NotebookActions.enableOutputScrolling(current.content);
4507
+ }
4508
+ },
4509
+ isEnabled,
4510
+ isToggled: args => {
4511
+ const current = getCurrent(tracker, shell, { ...args, activate: false });
4512
+ if (current) {
4513
+ return isOutputScrollingEnabled(current.content);
4514
+ } else {
4515
+ return false;
4516
+ }
4517
+ },
4518
+ describedBy: {
4519
+ args: {
4520
+ type: 'object',
4521
+ properties: {
4522
+ isMenu: {
4523
+ type: 'boolean',
4524
+ description: trans.__('Whether the command is called from a menu')
4525
+ }
4526
+ }
4527
+ }
4528
+ }
4529
+ });
4385
4530
  commands.addCommand(CommandIDs.selectLastRunCell, {
4386
4531
  label: trans.__('Select current running or last run cell'),
4387
4532
  execute: args => {
@@ -4925,13 +5070,16 @@ namespace Private {
4925
5070
  // If the container is not available, append the newly created container
4926
5071
  // to the current notebook panel and set related properties
4927
5072
  if (hiddenAlertContainer.getAttribute('id') !== hiddenAlertContainerId) {
4928
- hiddenAlertContainer.classList.add('sr-only');
4929
5073
  hiddenAlertContainer.setAttribute('id', hiddenAlertContainerId);
4930
- hiddenAlertContainer.setAttribute('role', 'alert');
4931
- hiddenAlertContainer.hidden = true;
4932
5074
  notebookNode.appendChild(hiddenAlertContainer);
4933
5075
  }
4934
5076
 
5077
+ hiddenAlertContainer.classList.add('jp-sr-only');
5078
+ hiddenAlertContainer.setAttribute('role', 'alert');
5079
+ hiddenAlertContainer.setAttribute('aria-live', 'assertive');
5080
+ hiddenAlertContainer.setAttribute('aria-atomic', 'true');
5081
+ hiddenAlertContainer.hidden = false;
5082
+
4935
5083
  // Insert/Update alert container with the notification message
4936
5084
  hiddenAlertContainer.innerText = message;
4937
5085
  }
@@ -4947,7 +5095,7 @@ namespace Private {
4947
5095
  this._index = options.index !== undefined ? options.index : -1;
4948
5096
  this._cell = options.cell || null;
4949
5097
  this.id = `LinkedOutputView-${UUID.uuid4()}`;
4950
- this.title.label = 'Output View';
5098
+ this.title.label = trans.__('Output View');
4951
5099
  this.title.icon = notebookIcon;
4952
5100
  this.title.caption = this._notebook.title.label
4953
5101
  ? trans.__('For Notebook: %1', this._notebook.title.label)