Hackathon - Better Markdown Editor (#11540)

* Hackathon - better markdown editor - modified Bold to wrap selection in HTML. Split Image button into two new options: embed and link. Made preview container contentEditable.

* Removed the new dropdown from Image button -- it is not necessary since we are adding a context panel instead.

* Modified preview icons

* Set code-component dimensions so it is not visible. It is still being used to pass markdown changes to however.

* add turndown and save markdown

* update model on UI when source changes

* Added conditional that sets element attribute contentEditable when it is in edit mode.

* Added textView component that can be used for editing.

* update source on MD view not on every keystroke

* Added markdown editor buttons that allow user to swap editor, preview views.

* Cleaning up implementation

* Setting base value of _showPreview to false.

* don't allow html edit on split view

* Update editor automagically

* Add an image picking dialog to notebook toolbar.

* Await transformText()

* revert pushEditOperations to fix cursor issue

* Implemented radio buttons for three view toggles.

* Added new, optional properties to radioButton: name, icon class and tooltip. This allows for display as toggleable icon. Updated styles and theme accordingly.

* Style tweaks.

* Added new ViewAction file where the RadioButton action will reside.

* Removed radio button implementation in exchange for native button instantiation. Adjusted CSS and theme accordingly.

* Styles, component and template changes to handle view toggle between text, markdownn an splitview. Includes reverting of radioButton as this is no longer used.

* WYSIWYG 3 Modes

* Ensure one action active at a time

* Setting Text View button active by default. Cleaned up styles. Moved toolbar element to prevent code cell layout overflow.

* Ensure we respect editMode, add showMarkdown

* hiding overflow on code-cell

* Empty text container needs 100% width. Eliminates weird selection border too.

* Initialize _previewMode

* Actions Compatibility

* Further toolbar enhancements

* Update yarn lock after merge

* Slim down changes

* Remove commented out code

* Added margins around notebook-preview container for more visual space for text

* Add turndown to workbench html

* Tweak import

* Add types/turndown

* Remove workbench.html fix

* Import cjs modules directly for turndown

* Leverage solution from github

* browser umd

* non browser umd

* welp dependency

* Modified updatePreview to insert a p tag only when text cell is empty.

* add listener for undo

* add turndown to remote and web

* Fix workbench, check in plugin

* PR comment

Co-authored-by: maddydev <makoripa@microsoft.com>
Co-authored-by: chlafreniere <hichise@gmail.com>
Co-authored-by: Cory Rivera <corivera@microsoft.com>
Co-authored-by: Lucy Zhang <luczhan@microsoft.com>
This commit is contained in:
Hale Rankin
2020-09-11 00:22:07 -07:00
committed by GitHub
parent 0f8fa0ccef
commit 6670289057
25 changed files with 2206 additions and 138 deletions

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { INotebookEditor, INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
@@ -13,9 +12,9 @@ import { TextModel } from 'vs/editor/common/model/textModel';
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor';
import { Selection } from 'vs/editor/common/core/selection';
import { ToggleableAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Position } from 'vs/editor/common/core/position';
import { MarkdownToolbarComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/markdownToolbar.component';
export class TransformMarkdownAction extends Action {
@@ -35,19 +34,70 @@ export class TransformMarkdownAction extends Action {
public run(context: any): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
try {
let markdownTextTransformer = new MarkdownTextTransformer(this._notebookService, this._cellModel);
markdownTextTransformer.transformText(this._type);
if (!context?.cellModel?.showMarkdown && context?.cellModel?.showPreview) {
this.transformDocumentCommand();
} else {
let markdownTextTransformer = new MarkdownTextTransformer(this._notebookService, this._cellModel);
markdownTextTransformer.transformText(this._type);
}
resolve(true);
} catch (e) {
reject(e);
}
});
}
private transformDocumentCommand() {
switch (this._type) {
case MarkdownButtonType.BOLD:
document.execCommand('bold');
break;
case MarkdownButtonType.CODE:
document.execCommand('formatBlock', false, 'pre');
break;
case MarkdownButtonType.HEADING1:
document.execCommand('formatBlock', false, 'H1');
break;
case MarkdownButtonType.HEADING2:
document.execCommand('formatBlock', false, 'H2');
break;
case MarkdownButtonType.HEADING3:
document.execCommand('formatBlock', false, 'H3');
break;
case MarkdownButtonType.HIGHLIGHT:
document.execCommand('hiliteColor', false, 'Yellow');
break;
case MarkdownButtonType.IMAGE:
// TODO
break;
case MarkdownButtonType.ITALIC:
document.execCommand('italic');
break;
case MarkdownButtonType.LINK:
document.execCommand('createLink', false, window.getSelection()?.focusNode?.textContent);
break;
case MarkdownButtonType.ORDERED_LIST:
document.execCommand('insertOrderedList');
break;
case MarkdownButtonType.PARAGRAPH:
document.execCommand('formatBlock', false, 'p');
break;
case MarkdownButtonType.UNDERLINE:
document.execCommand('underline');
break;
case MarkdownButtonType.UNORDERED_LIST:
document.execCommand('insertUnorderedList');
break;
}
}
}
export class MarkdownTextTransformer {
constructor(private _notebookService: INotebookService, private _cellModel: ICellModel, private _notebookEditor?: INotebookEditor) { }
constructor(
private _notebookService: INotebookService,
private _cellModel: ICellModel,
private _notebookEditor?: INotebookEditor) { }
public get notebookEditor(): INotebookEditor {
return this._notebookEditor;
@@ -473,39 +523,24 @@ function getColumnOffsetForSelection(type: MarkdownButtonType, nothingSelected:
}
}
export class TogglePreviewAction extends ToggleableAction {
private static readonly previewShowLabel = localize('previewShowLabel', "Show Preview");
private static readonly previewHideLabel = localize('previewHideLabel', "Hide Preview");
private static readonly baseClass = 'codicon';
private static readonly previewShowCssClass = 'split-toggle-on';
private static readonly previewHideCssClass = 'split-toggle-off';
private static readonly maskedIconClass = 'masked-icon';
export class ToggleViewAction extends Action {
constructor(
id: string, toggleTooltip: boolean, showPreview: boolean
id: string,
label: string,
cssClass: string,
tooltip: string,
private showPreview: boolean,
private showMarkdown: boolean
) {
super(id, {
baseClass: TogglePreviewAction.baseClass,
toggleOffLabel: TogglePreviewAction.previewShowLabel,
toggleOffClass: TogglePreviewAction.previewShowCssClass,
toggleOnLabel: TogglePreviewAction.previewHideLabel,
toggleOnClass: TogglePreviewAction.previewHideCssClass,
maskedIconClass: TogglePreviewAction.maskedIconClass,
shouldToggleTooltip: toggleTooltip,
isOn: showPreview
});
super(id, label, cssClass);
this._tooltip = tooltip;
}
public get previewMode(): boolean {
return this.state.isOn;
}
public set previewMode(value: boolean) {
this.toggle(value);
}
public async run(context: any): Promise<boolean> {
this.previewMode = !this.previewMode;
context.cellModel.showPreview = this.previewMode;
public async run(context: MarkdownToolbarComponent): Promise<boolean> {
context.removeActiveClassFromModeActions();
this.class += ' active';
context.cellModel.showPreview = this.showPreview;
context.cellModel.showMarkdown = this.showMarkdown;
return true;
}
}