Procházet zdrojové kódy

Make internal focus handling synchronous

Steven Silvester před 8 roky
rodič
revize
74f5df327d

+ 3 - 3
src/console/content.ts

@@ -388,7 +388,7 @@ class ConsoleContent extends Widget {
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    sendMessage(this.prompt.editor, WidgetMessage.ActivateRequest);
+    this.prompt.editor.editor.focus();
     this.update();
   }
 
@@ -423,7 +423,7 @@ class ConsoleContent extends Widget {
     this._completerHandler.activeCell = prompt;
     this._inspectionHandler.activeCell = prompt;
 
-    sendMessage(prompt.editor, WidgetMessage.ActivateRequest);
+    prompt.editor.editor.focus();
     this.update();
   }
 
@@ -479,7 +479,7 @@ class ConsoleContent extends Widget {
    */
   private _evtKeyDown(event: KeyboardEvent): void {
     if (event.keyCode === 13 && !this.prompt.editor.hasFocus()) {
-      this.prompt.editor.activate();
+      this.prompt.editor.editor.focus();
     }
   }
 

+ 1 - 1
src/console/panel.ts

@@ -78,7 +78,7 @@ class ConsolePanel extends Panel {
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    this.content.activate();
+    this.content.prompt.editor.editor.focus();
   }
 
   /**

+ 37 - 22
src/notebook/cells/widget.ts

@@ -251,7 +251,7 @@ class BaseCellWidget extends Widget {
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    this._editor.activate();
+    this._editor.editor.focus();
   }
 
   /**
@@ -659,7 +659,7 @@ class MarkdownCellWidget extends BaseCellWidget {
       return;
     }
     this._rendered = value;
-    this.update();
+    this._handleRendered();
   }
 
   /**
@@ -673,36 +673,51 @@ class MarkdownCellWidget extends BaseCellWidget {
     super.dispose();
   }
 
-  /**
+  /*
    * Handle `update-request` messages.
    */
   protected onUpdateRequest(msg: Message): void {
-    let model = this.model;
-    if (this.rendered) {
-      let text = model && model.source || DEFAULT_MARKDOWN_TEXT;
-      // Do not re-render if the text has not changed.
-      if (text !== this._prev) {
-        let bundle: RenderMime.MimeMap<string> = { 'text/markdown': text };
-        let trusted = this.trusted;
-        let widget = this._rendermime.render({ bundle, trusted });
-        this._output = widget || new Widget();
-        this._output.addClass(MARKDOWN_OUTPUT_CLASS);
-        this.update();
-      } else {
-        this._output.show();
-      }
-      this._prev = text;
-      this.renderInput(this._output);
-    } else {
+    // Make sure we are properly rendered.
+    this._handleRendered();
+    super.onUpdateRequest(msg);
+  }
+
+  /**
+   * Handle the rendered state.
+   */
+  private _handleRendered(): void {
+    if (!this._rendered) {
       this.showEditor();
+    } else {
+      this._updateOutput();
+      this.renderInput(this._output);
     }
-    super.onUpdateRequest(msg);
+  }
+
+  /**
+   * Update the output.
+   */
+  private _updateOutput(): void {
+    let model = this.model;
+    let text = model && model.source || DEFAULT_MARKDOWN_TEXT;
+    let trusted = this.trusted;
+    // Do not re-render if the text has not changed and the trusted
+    // has not changed.
+    if (text !== this._prevText || trusted !== this._prevTrusted) {
+      let bundle: RenderMime.MimeMap<string> = { 'text/markdown': text };
+      let widget = this._rendermime.render({ bundle, trusted });
+      this._output = widget || new Widget();
+      this._output.addClass(MARKDOWN_OUTPUT_CLASS);
+    }
+    this._prevText = text;
+    this._prevTrusted = trusted;
   }
 
   private _rendermime: RenderMime = null;
   private _output: Widget = null;
   private _rendered = true;
-  private _prev = '';
+  private _prevText = '';
+  private _prevTrusted = false;
 }
 
 

+ 36 - 38
src/notebook/notebook/widget.ts

@@ -703,25 +703,29 @@ class Notebook extends StaticNotebook {
     return this._mode;
   }
   set mode(newValue: NotebookMode) {
-    // Always post an update request.
-    this.update();
+    let activeCell = this.activeCell;
+    if (!activeCell) {
+      newValue = 'command';
+    }
     if (newValue === this._mode) {
+      this._ensureFocus();
       return;
     }
+    // Post an update request.
+    this.update();
     let oldValue = this._mode;
     this._mode = newValue;
-    this.stateChanged.emit({ name: 'mode', oldValue, newValue });
-    let activeCell = this.activeCell;
-    if (!activeCell) {
-      return;
-    }
-    // Edit mode deselects all cells.
+
     if (newValue === 'edit') {
+      // Edit mode deselects all cells.
       each(this.widgets, widget => { this.deselect(widget); });
+      //  Edit mode unrenders an active markdown widget.
       if (activeCell instanceof MarkdownCellWidget) {
         activeCell.rendered = false;
       }
     }
+    this.stateChanged.emit({ name: 'mode', oldValue, newValue });
+    this._ensureFocus();
   }
 
   /**
@@ -737,8 +741,6 @@ class Notebook extends StaticNotebook {
     return this.model.cells.length ? this._activeCellIndex : -1;
   }
   set activeCellIndex(newValue: number) {
-    // Always post an update request.
-    this.update();
     let oldValue = this._activeCellIndex;
     if (!this.model || !this.model.cells.length) {
       newValue = -1;
@@ -749,15 +751,18 @@ class Notebook extends StaticNotebook {
     this._activeCellIndex = newValue;
     let cell = this.widgets.at(newValue);
     if (cell !== this._activeCell) {
+      // Post an update request.
+      this.update();
       this._activeCell = cell;
       this.activeCellChanged.emit(cell);
     }
-    if (newValue === oldValue) {
-      return;
-    }
     if (this.mode === 'edit' && cell instanceof MarkdownCellWidget) {
       cell.rendered = false;
     }
+    this._ensureFocus();
+    if (newValue === oldValue) {
+      return;
+    }
     this.stateChanged.emit({ name: 'activeCellIndex', oldValue, newValue });
   }
 
@@ -937,7 +942,7 @@ class Notebook extends StaticNotebook {
    * Handle `'activate-request'` messages.
    */
   protected onActivateRequest(msg: Message): void {
-    this._ensureFocus();
+    this._ensureFocus(true);
   }
 
   /**
@@ -945,10 +950,6 @@ class Notebook extends StaticNotebook {
    */
   protected onUpdateRequest(msg: Message): void {
     let activeCell = this.activeCell;
-    // Ensure we have the correct focus.
-    if (this.node.contains(document.activeElement)) {
-      this._ensureFocus();
-    }
 
     // Set the appropriate classes on the cells.
     if (this.mode === 'edit') {
@@ -1023,9 +1024,6 @@ class Notebook extends StaticNotebook {
    */
   private _onEdgeRequest(widget: Widget, location: EdgeLocation): void {
     let prev = this.activeCellIndex;
-    // Clear the previous cell focus.
-    this.node.focus();
-
     if (location === 'top') {
       this.activeCellIndex--;
       // Move the cursor to the first position on the last line.
@@ -1040,20 +1038,16 @@ class Notebook extends StaticNotebook {
         this.activeCell.editor.setCursorPosition(0);
       }
     }
-    // Attempt to focus the new cell.
-    this.activeCell.activate();
   }
 
   /**
    * Ensure that the notebook has proper focus.
    */
-  private _ensureFocus(): void {
+  private _ensureFocus(force=false): void {
     let activeCell = this.activeCell;
-    if (this.mode === 'edit' && activeCell) {
-      activeCell.editor.activate();
-    } else if (!this.node.contains(document.activeElement)) {
-      this.node.focus();
-    } else {
+    if (this.mode === 'edit') {
+      activeCell.editor.editor.focus();
+    } else if (this.node.contains(document.activeElement)) {
       // If an editor currently has focus, focus our node.
       // Otherwise, another input field has focus and should keep it.
       let w = find(this.layout, widget => {
@@ -1063,6 +1057,9 @@ class Notebook extends StaticNotebook {
         this.node.focus();
       }
     }
+    if (force && !this.node.contains(document.activeElement)) {
+      this.node.focus();
+    }
   }
 
   /**
@@ -1351,10 +1348,15 @@ class Notebook extends StaticNotebook {
    * Handle `blur` events for the widget.
    */
   private _evtBlur(event: MouseEvent): void {
-    let target = event.relatedTarget as HTMLElement;
-    if (!this.node.contains(target)) {
+    let relatedTarget = event.relatedTarget as HTMLElement;
+    if (!this.node.contains(relatedTarget)) {
       this.mode = 'command';
     }
+    // If the root node is not blurring and we are in command mode,
+    // focus ourselves.
+    if (this.mode === 'command' && event.target !== this.node) {
+      this.node.focus();
+    }
   }
 
   /**
@@ -1370,13 +1372,9 @@ class Notebook extends StaticNotebook {
     if (i === -1) {
       return;
     }
-    let layout = this.layout as PanelLayout;
-    let cell = model.cells.at(i) as MarkdownCellModel;
-    let widget = layout.widgets.at(i) as MarkdownCellWidget;
-    if (cell.type === 'markdown') {
-      widget.rendered = false;
-      widget.activate();
-      return;
+    this.activeCellIndex = i;
+    if (model.cells.at(i).type === 'markdown') {
+      this.mode = 'edit';
     } else if (target.localName === 'img') {
       target.classList.toggle(UNCONFINED_CLASS);
     }

+ 2 - 0
test/src/notebook/notebook/widget.spec.ts

@@ -915,7 +915,9 @@ describe('notebook/notebook/widget', () => {
           widget.model.cells.pushBack(cell);
           let child = widget.widgets.at(widget.widgets.length - 1) as MarkdownCellWidget;
           expect(child.rendered).to.be(true);
+          expect(widget.mode).to.be('command');
           simulate(child.node, 'dblclick');
+          expect(widget.mode).to.be('edit');
           expect(child.rendered).to.be(false);
         });