@jupyterlab/notebook 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/src/widget.ts CHANGED
@@ -175,7 +175,6 @@ export type NotebookMode = 'command' | 'edit';
175
175
  if ((window as any).requestIdleCallback === undefined) {
176
176
  // On Safari, requestIdleCallback is not available, so we use replacement functions for `idleCallbacks`
177
177
  // See: https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API#falling_back_to_settimeout
178
- // eslint-disable-next-line @typescript-eslint/ban-types
179
178
  (window as any).requestIdleCallback = function (handler: Function) {
180
179
  let startTime = Date.now();
181
180
  return setTimeout(function () {
@@ -615,6 +614,7 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
615
614
  for (const cell of cells) {
616
615
  this._insertCell(++index, cell);
617
616
  }
617
+ this._syncMarkdownCellTrust();
618
618
  newValue.cells.changed.connect(this._onCellsChanged, this);
619
619
  newValue.metadataChanged.connect(this.onMetadataChanged, this);
620
620
  newValue.contentChanged.connect(this.onModelContentChanged, this);
@@ -628,6 +628,7 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
628
628
  args: IObservableList.IChangedArgs<ICellModel>
629
629
  ): void {
630
630
  this.removeHeader();
631
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
631
632
  switch (args.type) {
632
633
  case 'add': {
633
634
  let index = 0;
@@ -675,6 +676,7 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
675
676
  this.addHeader();
676
677
  }
677
678
 
679
+ this._syncMarkdownCellTrust();
678
680
  this.update();
679
681
  }
680
682
 
@@ -697,10 +699,12 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
697
699
  default:
698
700
  widget = this._createRawCell(cell as IRawCellModel);
699
701
  }
702
+ cell.stateChanged.connect(this._onCellStateChanged, this);
700
703
  widget.inViewportChanged.connect(this._onCellInViewportChanged, this);
701
704
  widget.addClass(NB_CELL_CLASS);
702
705
 
703
706
  ArrayExt.insert(this.cellsArray, index, widget);
707
+ this._syncMarkdownCellTrust(widget);
704
708
  this.onCellInserted(index, widget);
705
709
 
706
710
  this._scheduleCellRenderOnIdle();
@@ -725,9 +729,15 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
725
729
  translator: this.translator
726
730
  };
727
731
  const cell = this.contentFactory.createCodeCell(options);
728
- cell.syncCollapse = true;
729
- cell.syncEditable = true;
730
- cell.syncScrolled = true;
732
+ if (cell.syncCollapse === undefined) {
733
+ cell.syncCollapse = true;
734
+ }
735
+ if (cell.syncEditable === undefined) {
736
+ cell.syncEditable = true;
737
+ }
738
+ if (cell.syncScrolled === undefined) {
739
+ cell.syncScrolled = true;
740
+ }
731
741
  cell.outputArea.inputRequested.connect((_, stdin) => {
732
742
  this._onInputRequested(cell).catch(reason => {
733
743
  console.error('Failed to scroll to cell requesting input.', reason);
@@ -759,8 +769,12 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
759
769
  this._notebookConfig.showEditorForReadOnlyMarkdown
760
770
  };
761
771
  const cell = this.contentFactory.createMarkdownCell(options);
762
- cell.syncCollapse = true;
763
- cell.syncEditable = true;
772
+ if (cell.syncCollapse === undefined) {
773
+ cell.syncCollapse = true;
774
+ }
775
+ if (cell.syncEditable === undefined) {
776
+ cell.syncEditable = true;
777
+ }
764
778
  // Connect collapsed signal for each markdown cell widget
765
779
  cell.headingCollapsedChanged.connect(this._onCellCollapsed, this);
766
780
  return cell;
@@ -779,8 +793,12 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
779
793
  placeholder: this._notebookConfig.windowingMode !== 'none'
780
794
  };
781
795
  const cell = this.contentFactory.createRawCell(options);
782
- cell.syncCollapse = true;
783
- cell.syncEditable = true;
796
+ if (cell.syncCollapse === undefined) {
797
+ cell.syncCollapse = true;
798
+ }
799
+ if (cell.syncEditable === undefined) {
800
+ cell.syncEditable = true;
801
+ }
784
802
  return cell;
785
803
  }
786
804
 
@@ -789,12 +807,60 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
789
807
  */
790
808
  private _removeCell(index: number): void {
791
809
  const widget = this.cellsArray[index];
810
+ widget.model.stateChanged.disconnect(this._onCellStateChanged, this);
792
811
  widget.parent = null;
793
812
  ArrayExt.removeAt(this.cellsArray, index);
794
813
  this.onCellRemoved(index, widget);
795
814
  widget.dispose();
796
815
  }
797
816
 
817
+ private _shouldTrustMarkdown(): boolean {
818
+ // Note: this returns false in a notebook without trsuted code cells;
819
+ // This is intended since only Code cells carry trust status on disk.
820
+ if (!this._notebookModel) {
821
+ return false;
822
+ }
823
+ let hasCodeCell = false;
824
+ for (const cell of this._notebookModel.cells) {
825
+ if (cell.type === 'code') {
826
+ hasCodeCell = true;
827
+ if (!cell.trusted) {
828
+ return false;
829
+ }
830
+ }
831
+ }
832
+ return hasCodeCell;
833
+ }
834
+
835
+ private _syncMarkdownCellTrust(cell?: Cell): void {
836
+ const trusted = this._shouldTrustMarkdown();
837
+ const trustHandler = this.rendermime.trustHandler;
838
+ if (!trustHandler) {
839
+ return;
840
+ }
841
+
842
+ const cells = cell ? [cell] : this.widgets;
843
+ for (const widget of cells) {
844
+ if (!(widget instanceof MarkdownCell)) {
845
+ continue;
846
+ }
847
+ if (trusted) {
848
+ trustHandler.markTrusted(widget.node);
849
+ } else {
850
+ trustHandler.unmarkTrusted(widget.node);
851
+ }
852
+ }
853
+ }
854
+
855
+ private _onCellStateChanged(
856
+ model: ICellModel,
857
+ args: IChangedArgs<any>
858
+ ): void {
859
+ if (args.name === 'trusted') {
860
+ this._syncMarkdownCellTrust();
861
+ }
862
+ }
863
+
798
864
  /**
799
865
  * Update the mimetype of the notebook.
800
866
  */
@@ -821,6 +887,14 @@ export class StaticNotebook extends WindowedList<NotebookViewModel> {
821
887
  cell
822
888
  .getHeadings()
823
889
  .then(() => {
890
+ // Heading parsing is async; ignore stale callbacks that no longer match
891
+ // the current collapsed state.
892
+ if (
893
+ cell.isDisposed ||
894
+ (cell instanceof MarkdownCell && cell.headingCollapsed !== collapsed)
895
+ ) {
896
+ return;
897
+ }
824
898
  NotebookActions.setHeadingCollapse(cell, collapsed, this);
825
899
  this._cellCollapsed.emit(cell);
826
900
  })
@@ -1635,6 +1709,7 @@ export class Notebook extends StaticNotebook {
1635
1709
  * Construct a notebook widget.
1636
1710
  */
1637
1711
  constructor(options: Notebook.IOptions) {
1712
+ const trans = (options.translator || nullTranslator).load('jupyterlab');
1638
1713
  super({
1639
1714
  renderer: {
1640
1715
  createOuter(): HTMLElement {
@@ -1644,7 +1719,7 @@ export class Notebook extends StaticNotebook {
1644
1719
  createViewport(): HTMLElement {
1645
1720
  const el = document.createElement('div');
1646
1721
  el.setAttribute('role', 'feed');
1647
- el.setAttribute('aria-label', 'Cells');
1722
+ el.setAttribute('aria-label', trans.__('Cells'));
1648
1723
  return el;
1649
1724
  },
1650
1725
 
@@ -2034,7 +2109,8 @@ export class Notebook extends StaticNotebook {
2034
2109
  this._selectionChanged.emit(void 0);
2035
2110
  }
2036
2111
  // Make sure we have a valid active cell.
2037
- this.activeCellIndex = this.activeCellIndex; // eslint-disable-line
2112
+ // eslint-disable-next-line no-self-assign
2113
+ this.activeCellIndex = this.activeCellIndex;
2038
2114
  this.update();
2039
2115
  }
2040
2116
 
@@ -2823,7 +2899,9 @@ export class Notebook extends StaticNotebook {
2823
2899
  if (widget && widget.editorWidget?.node.contains(target)) {
2824
2900
  // Prevent CodeMirror from focusing the editor.
2825
2901
  // TODO: find an editor-agnostic solution.
2826
- event.preventDefault();
2902
+ if (!target.closest('[data-jp-suppress-context-menu]')) {
2903
+ event.preventDefault();
2904
+ }
2827
2905
  }
2828
2906
  }
2829
2907
 
@@ -3011,6 +3089,7 @@ export class Notebook extends StaticNotebook {
3011
3089
  event.stopPropagation();
3012
3090
 
3013
3091
  // If in select mode, update the selection
3092
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
3014
3093
  switch (this._mouseMode) {
3015
3094
  case 'select': {
3016
3095
  const target = event.target as HTMLElement;
package/style/base.css CHANGED
@@ -62,6 +62,13 @@
62
62
 
63
63
  .jp-Notebook .jp-Cell {
64
64
  overflow: visible;
65
+
66
+ /* Prevent scroll anchoring to inactive cells */
67
+ overflow-anchor: none;
68
+ }
69
+
70
+ .jp-Notebook .jp-Cell.jp-mod-active {
71
+ overflow-anchor: auto;
65
72
  }
66
73
 
67
74
  .jp-Notebook .jp-Cell .jp-InputPrompt {
@@ -393,85 +400,6 @@
393
400
  display: none;
394
401
  }
395
402
 
396
- /*-----------------------------------------------------------------------------
397
- | Placeholder
398
- |----------------------------------------------------------------------------*/
399
-
400
- .jp-Cell-Placeholder {
401
- padding-left: 55px;
402
- }
403
-
404
- .jp-Cell-Placeholder-wrapper {
405
- background: #fff;
406
- border: 1px solid;
407
- border-color: #e5e6e9 #dfe0e4 #d0d1d5;
408
- border-radius: 4px;
409
- -webkit-border-radius: 4px;
410
- margin: 10px 15px;
411
- }
412
-
413
- .jp-Cell-Placeholder-wrapper-inner {
414
- padding: 15px;
415
- position: relative;
416
- }
417
-
418
- .jp-Cell-Placeholder-wrapper-body {
419
- background-repeat: repeat;
420
- background-size: 50% auto;
421
- }
422
-
423
- .jp-Cell-Placeholder-wrapper-body div {
424
- background: #f6f7f8;
425
- background-image: -webkit-linear-gradient(
426
- left,
427
- #f6f7f8 0%,
428
- #edeef1 20%,
429
- #f6f7f8 40%,
430
- #f6f7f8 100%
431
- );
432
- background-repeat: no-repeat;
433
- background-size: 800px 104px;
434
- height: 104px;
435
- position: absolute;
436
- right: 15px;
437
- left: 15px;
438
- top: 15px;
439
- }
440
-
441
- div.jp-Cell-Placeholder-h1 {
442
- top: 20px;
443
- height: 20px;
444
- left: 15px;
445
- width: 150px;
446
- }
447
-
448
- div.jp-Cell-Placeholder-h2 {
449
- left: 15px;
450
- top: 50px;
451
- height: 10px;
452
- width: 100px;
453
- }
454
-
455
- div.jp-Cell-Placeholder-content-1,
456
- div.jp-Cell-Placeholder-content-2,
457
- div.jp-Cell-Placeholder-content-3 {
458
- left: 15px;
459
- right: 15px;
460
- height: 10px;
461
- }
462
-
463
- div.jp-Cell-Placeholder-content-1 {
464
- top: 100px;
465
- }
466
-
467
- div.jp-Cell-Placeholder-content-2 {
468
- top: 120px;
469
- }
470
-
471
- div.jp-Cell-Placeholder-content-3 {
472
- top: 140px;
473
- }
474
-
475
403
  /*-----------------------------------------------------------------------------
476
404
  | Virtual scrollbar
477
405
  |----------------------------------------------------------------------------*/
@@ -517,7 +445,7 @@ div.jp-Cell-Placeholder-content-3 {
517
445
 
518
446
  .jp-Notebook .jp-scrollbarItem-executionIndicator {
519
447
  display: inline-block;
520
- font-family: monospace;
448
+ font-family: var(--jp-cell-prompt-font-family);
521
449
  font-size: 80%;
522
450
  line-height: 100%;
523
451
  margin-left: -1px;
@@ -527,6 +455,7 @@ div.jp-Cell-Placeholder-content-3 {
527
455
 
528
456
  .jp-Notebook .jp-scrollbarItem-source {
529
457
  display: inline-block;
458
+ /* stylelint-disable-next-line declaration-property-value-allowed-list */
530
459
  font-size: 3px;
531
460
  vertical-align: middle;
532
461
  max-height: 10em;
@@ -61,12 +61,6 @@
61
61
  display: block;
62
62
  }
63
63
 
64
- .jp-Notebook-ExecutionIndicator-progress-bar {
65
- display: flex;
66
- justify-content: center;
67
- height: 100%;
68
- }
69
-
70
64
  .jp-Notebook-ExecutionIndicator-jumpButton {
71
65
  margin-top: 4px;
72
66
  margin-bottom: 3px;