save richTextCursorPosition/markdownCursorPosition (#17180)

* save richTextCursorPosition/markdownCursorPosition

* rename variables

* check to see if the nodes exist

* added comments

* add comments

* check if valid offset

* pr comments

* sqllint error fix
This commit is contained in:
Maddy
2021-10-06 23:24:22 -07:00
committed by GitHub
parent 56e961c972
commit f88bef8b4c
4 changed files with 97 additions and 2 deletions

View File

@@ -282,6 +282,10 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
DOM.getContentHeight(this.codeElement.nativeElement)));
this._editor.setHeightToScrollHeight(false, this._cellModel.isCollapsed);
this.horizontalScrollbar();
// Move cursor to the last known location
if (this.cellModel.markdownCursorPosition) {
this._editor.getControl().setPosition(this.cellModel.markdownCursorPosition);
}
}
/**

View File

@@ -23,7 +23,7 @@ import { IMarkdownRenderResult } from 'vs/editor/browser/core/markdownRenderer';
import { NotebookMarkdownRenderer } from 'sql/workbench/contrib/notebook/browser/outputs/notebookMarkdown';
import { CellView } from 'sql/workbench/contrib/notebook/browser/cellViews/interfaces';
import { CellEditModes, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { ICaretPosition, CellEditModes, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
import { ISanitizer, defaultSanitizer } from 'sql/workbench/services/notebook/browser/outputs/sanitizer';
import { CodeComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/code.component';
@@ -211,10 +211,48 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
this._changeRef.detectChanges();
}));
this._register(this.cellModel.onCellPreviewModeChanged(preview => {
// On preview mode change, get the cursor position (get the position only when the selection node is a text node)
if (window.getSelection() && window.getSelection().focusNode?.nodeName === '#text' && window.getSelection().getRangeAt(0)) {
let selection = window.getSelection().getRangeAt(0);
// Check to see if the last cursor position is still the same and skip
if (selection.startOffset !== this.cellModel.richTextCursorPosition?.startOffset) {
// window.getSelection gives the exact html element and offsets of cursor location
// Since we only have the output element reference which is the parent of all html nodes
// we iterate through it's child nodes until we get the selection element and store the node indexes
// in the startElementNodes and endElementNodes and their offsets respectively.
let startElementNodes = [];
let startNode = selection.startContainer;
let endNode = selection.endContainer;
while (startNode !== this.output.nativeElement) {
startElementNodes.push(this.getNodeIndex(startNode));
startNode = startNode.parentNode;
}
let endElementNodes = [];
while (endNode !== this.output.nativeElement) {
endElementNodes.push(this.getNodeIndex(endNode));
endNode = endNode.parentNode;
}
// Create cursor position
let cursorPosition: ICaretPosition = {
startElementNodes: startElementNodes,
startOffset: selection.startOffset,
endElementNodes: endElementNodes,
endOffset: selection.endOffset
};
this.cellModel.richTextCursorPosition = cursorPosition;
}
}
this.previewMode = preview;
this.focusIfPreviewMode();
}));
this._register(this.cellModel.onCellMarkdownModeChanged(markdown => {
if (!markdown) {
let editorControl = this.cellEditors.length > 0 ? this.cellEditors[0].getEditor().getControl() : undefined;
if (editorControl) {
let selection = editorControl.getSelection();
this.cellModel.markdownCursorPosition = selection?.getPosition();
}
}
this.markdownMode = markdown;
this.focusIfPreviewMode();
}));
@@ -236,6 +274,17 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
}
}
getNodeIndex(n) {
let i = 0;
// walk up the node to the top and get it's index
n = n.previousSibling;
while (n) {
i++;
n = n.previousSibling;
}
return i;
}
public cellGuid(): string {
return this.cellModel.cellGuid;
}
@@ -452,6 +501,35 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
} else {
this.setSplitViewHeight();
}
// Move cursor to the richTextCursorPosition
// We iterate through the output element childnodes to get to the element of cursor location
// If the elements exist, we set the selection, else the cursor defaults to beginning.
if (!this.markdownMode && this.cellModel.richTextCursorPosition) {
let selection = window.getSelection();
let htmlNodes = this.cellModel.richTextCursorPosition.startElementNodes;
let depthToNode = htmlNodes.length;
let startNodeElement: any = this.output.nativeElement;
while (depthToNode-- && startNodeElement) {
startNodeElement = startNodeElement.childNodes[htmlNodes[depthToNode]];
}
htmlNodes = this.cellModel.richTextCursorPosition.endElementNodes;
depthToNode = htmlNodes.length;
let endNodeElement: any = this.output.nativeElement;
while (depthToNode-- && endNodeElement) {
endNodeElement = endNodeElement?.childNodes[htmlNodes[depthToNode]];
}
// check to see if the nodes exist and set the cursor
if (startNodeElement && endNodeElement) {
// check the offset is still valid (element's text updates can make it invalid)
if (startNodeElement.length >= this.cellModel.richTextCursorPosition.startOffset && endNodeElement.length >= this.cellModel.richTextCursorPosition.endOffset) {
let range = document.createRange();
range.setStart(startNodeElement, this.cellModel.richTextCursorPosition.startOffset);
range.setEnd(endNodeElement, this.cellModel.richTextCursorPosition.endOffset);
selection.removeAllRanges();
selection.addRange(range);
}
}
}
} else {
this.setMarkdownEditorHeight(this._markdownMaxHeight);
}