diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index 9cca1743d2f..301ff35e4ae 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -23,6 +23,7 @@ [currentRevision]="currentRevision" (tableHideChange)="setAllParagraphTableHide($event)" (editorHideChange)="setAllParagraphEditorHide($event)" + #actionBar >
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 4bf9cae4f66..f7511cd75ca 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -198,6 +198,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit // Call when next tick setTimeout(() => { scrollIntoViewIfNeeded(paragraphComponent.getElement()); + paragraphComponent.focusEditor(); }); } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 415051d409c..e37dc3cb6ae 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -57,6 +57,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro @Output() readonly textChanged = new EventEmitter(); @Output() readonly editorBlur = new EventEmitter(); @Output() readonly editorFocus = new EventEmitter(); + @Output() readonly toggleEditorShow = new EventEmitter(); private editor?: IStandaloneCodeEditor; private monacoDisposables: IDisposable[] = []; height = 18; @@ -108,6 +109,72 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro } } + // Handle Ctrl+Alt+E: Toggle editor show/hide + handleToggleEditorShow() { + this.toggleEditorShow.emit(); + } + + // Handle Ctrl+K: Cut current line to clipboard + async handleCutLine() { + if (!this.editor) { + return; + } + + const position = this.editor.getPosition(); + const model = this.editor.getModel(); + if (!position || !model) { + return; + } + + const lineNumber = position.lineNumber; + const lineContent = model.getLineContent(lineNumber); + + if (!lineContent) { + return; + } + + await navigator.clipboard.writeText(lineContent); + + this.editor.executeEdits('cut-line', [ + { + range: new monaco.Range(lineNumber, 1, lineNumber, lineContent.length + 1), + text: '', + forceMoveMarkers: true + } + ]); + } + + // Handle Ctrl+Y: Paste from clipboard at current position + async handlePasteFromClipboard() { + if (!this.editor) { + return; + } + + const text = await navigator.clipboard.readText(); + const position = this.editor.getPosition(); + if (position) { + this.editor.executeEdits('my-source', [ + { + range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column), + text: text, + forceMoveMarkers: true + } + ]); + } + } + + // Handle Ctrl+S: Show find widget + handleShowFind() { + if (this.editor) { + this.editor.getAction('actions.find').run(); + + // Focus on the find widget input field + const findInput = document.querySelector('.find-widget .input') as HTMLInputElement; + findInput.focus(); + findInput.select(); + } + } + initializedEditor(editor: IEditor) { this.editor = editor as IStandaloneCodeEditor; this.editor.addCommand( @@ -119,6 +186,18 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro }, '!suggestWidgetVisible' ); + this.editor.addCommand(monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KeyE, () => { + this.handleToggleEditorShow(); + }); + this.editor.addCommand(monaco.KeyMod.WinCtrl | monaco.KeyCode.KeyK, () => { + this.handleCutLine(); + }); + this.editor.addCommand(monaco.KeyMod.WinCtrl | monaco.KeyCode.KeyY, () => { + this.handlePasteFromClipboard(); + }); + this.editor.addCommand(monaco.KeyMod.WinCtrl | monaco.KeyCode.KeyS, () => { + this.handleShowFind(); + }); this.updateEditorOptions(this.editor); this.setParagraphMode(); @@ -160,6 +239,9 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro scrollbar: { handleMouseWheel: false, alwaysConsumeMouseWheel: false + }, + find: { + addExtraSpaceOnTop: false } }); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index 3d39dcc1af4..741c9288c09 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -85,6 +85,14 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { trigger(): void; }> = []; + formatShortcut(shortcut: string, isMac: boolean) { + if (isMac) { + return shortcut.replace('Alt', 'Option'); + } + + return shortcut; + } + updateListOfMenu() { this.listOfMenu = [ { @@ -93,7 +101,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'play-circle', trigger: () => this.trigger(this.runParagraph), - shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + shortCut: this.formatShortcut('Shift+Enter', this.isMac) }, { label: 'Run all above', @@ -101,7 +109,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'up-square', trigger: () => this.trigger(this.runAllAbove), - shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + shortCut: this.formatShortcut('Shift+Ctrl+Up', this.isMac) }, { label: 'Run all below', @@ -109,7 +117,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'down-square', trigger: () => this.trigger(this.runAllBelowAndCurrent), - shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + shortCut: this.formatShortcut('Shift+Ctrl+Down', this.isMac) }, { label: 'Link this paragraph', @@ -119,7 +127,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { trigger: () => { this.openSingleParagraph.emit(this.pid); }, - shortCut: this.isMac ? '⌥+⌘+T' : 'Alt+Ctrl+T' + shortCut: this.formatShortcut('Ctrl+Alt+W', this.isMac) }, { label: 'Clear output', @@ -127,7 +135,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'fire', trigger: () => this.clearParagraphOutput(), - shortCut: this.isMac ? '⌥+⌘+L' : 'Alt+Ctrl+L' + shortCut: this.formatShortcut('Ctrl+Alt+L', this.isMac) }, { label: 'Remove', @@ -135,23 +143,23 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'delete', trigger: () => this.onRemoveParagraph(), - shortCut: this.isMac ? '⇧+Del (Command)' : 'Shift+Del (Command)' + shortCut: this.formatShortcut('Ctrl+Alt+D', this.isMac) }, { - label: 'Move up', + label: 'Move paragraph up', show: !this.first, disabled: this.isEntireNoteRunning, icon: 'up', trigger: () => this.trigger(this.moveUp), - shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+K (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+K', this.isMac) }, { - label: 'Move down', + label: 'Move paragraph down', show: !this.last, disabled: this.isEntireNoteRunning, icon: 'down', trigger: () => this.trigger(this.moveDown), - shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+J (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+J', this.isMac) }, { label: 'Insert new', @@ -159,7 +167,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'plus', trigger: () => this.trigger(this.insertNew), - shortCut: `B (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+B', this.isMac) }, { label: 'Clone paragraph', @@ -167,7 +175,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'copy', trigger: () => this.trigger(this.cloneParagraph), - shortCut: `C (Command)` + shortCut: this.formatShortcut('Shift+Ctrl+C', this.isMac) }, { label: this.title ? 'Hide Title' : 'Show Title', @@ -175,7 +183,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: false, icon: 'font-colors', trigger: () => this.toggleTitle(), - shortCut: `T (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+T', this.isMac) }, { label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers', @@ -183,7 +191,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: false, icon: 'ordered-list', trigger: () => this.toggleLineNumbers(), - shortCut: `L (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+M', this.isMac) }, { label: this.enabled ? 'Disable run' : 'Enable run', @@ -191,7 +199,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'api', trigger: () => this.toggleEnabled(), - shortCut: `R (Command)` + shortCut: this.formatShortcut('Ctrl+Alt+R', this.isMac) } ]; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 5892aee5514..63ecfa5639e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -82,6 +82,7 @@ (editorBlur)="onEditorBlur()" (editorFocus)="onEditorFocus()" (textChanged)="textChanged($event)" + (toggleEditorShow)="toggleEditorShow()" > (); @Output() readonly selected = new EventEmitter(); @Output() readonly selectAtIndex = new EventEmitter(); + @Output() readonly searchCode = new EventEmitter(); private destroy$ = new Subject(); private mode: Mode = 'command'; @@ -155,6 +156,11 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, } } + toggleEditorShow() { + this.setEditorHide(!this.paragraph.config.editorHide); + this.commitParagraph(); + } + saveParagraph() { const dirtyText = this.paragraph.text; if (dirtyText === undefined || dirtyText === this.originalText) { @@ -356,7 +362,7 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, this.cdr.markForCheck(); } - moveUpParagraph() { + moveCursorUp() { const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1; if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { return; @@ -369,7 +375,7 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, this.messageService.moveParagraph(this.paragraph.id, newIndex); } - moveDownParagraph() { + moveCursorDown() { const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) + 1; if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { return; @@ -382,6 +388,28 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, this.messageService.moveParagraph(this.paragraph.id, newIndex); } + moveParagraphUp() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + moveParagraphDown() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) + 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + clearParagraphOutput() { + if (!this.isEntireNoteRunning) { + this.messageService.paragraphClearOutput(this.paragraph.id); + } + } + changeColWidth(needCommit: boolean, updateResult = true) { if (needCommit) { this.commitParagraph(); @@ -485,89 +513,15 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, return; // ignore shortcut to make input work } - if (this.mode === 'command') { - switch (action) { - case ParagraphActions.InsertAbove: - this.insertParagraph('above'); - break; - case ParagraphActions.InsertBelow: - this.insertParagraph('below'); - break; - case ParagraphActions.SwitchEditorShow: - this.setEditorHide(!this.paragraph.config.editorHide); - this.commitParagraph(); - break; - case ParagraphActions.SwitchOutputShow: - this.setTableHide(!this.paragraph.config.tableHide); - this.commitParagraph(); - break; - case ParagraphActions.SwitchTitleShow: - this.paragraph.config.title = !this.paragraph.config.title; - this.commitParagraph(); - break; - case ParagraphActions.SwitchLineNumber: - this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; - this.commitParagraph(); - break; - case ParagraphActions.MoveToUp: - event.preventDefault(); - this.moveUpParagraph(); - break; - case ParagraphActions.MoveToDown: - event.preventDefault(); - this.moveDownParagraph(); - break; - case ParagraphActions.SwitchEnable: - this.paragraph.config.enabled = !this.paragraph.config.enabled; - this.commitParagraph(); - break; - case ParagraphActions.ReduceWidth: - if (!this.paragraph.config.colWidth) { - throw new Error('colWidth is required'); - } - this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); - this.cdr.markForCheck(); - this.changeColWidth(true); - break; - case ParagraphActions.IncreaseWidth: - if (!this.paragraph.config.colWidth) { - throw new Error('colWidth is required'); - } - this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); - this.cdr.markForCheck(); - this.changeColWidth(true); - break; - case ParagraphActions.Delete: - this.removeParagraph(); - break; - case ParagraphActions.SelectAbove: - event.preventDefault(); - this.selectAtIndex.emit(this.index - 1); - break; - case ParagraphActions.SelectBelow: - event.preventDefault(); - this.selectAtIndex.emit(this.index + 1); - break; - default: - break; - } - } switch (action) { - case ParagraphActions.Link: - this.openSingleParagraph(this.paragraph.id); - break; - case ParagraphActions.EditMode: - if (this.mode === 'command') { - event.preventDefault(); - } - if (!this.paragraph.config.editorHide) { - this.switchMode('edit'); - } - break; case ParagraphActions.Run: event.preventDefault(); this.runParagraph(); break; + case ParagraphActions.RunAbove: + this.waitConfirmFromEdit = true; + this.runAllAbove(); + break; case ParagraphActions.RunBelow: this.waitConfirmFromEdit = true; this.runAllBelowAndCurrent(); @@ -576,6 +530,75 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, event.preventDefault(); this.cancelParagraph(); break; + case ParagraphActions.MoveCursorUp: + event.preventDefault(); + this.moveCursorUp(); + break; + case ParagraphActions.MoveCursorDown: + event.preventDefault(); + this.moveCursorDown(); + break; + case ParagraphActions.Delete: + this.removeParagraph(); + break; + case ParagraphActions.InsertAbove: + this.insertParagraph('above'); + break; + case ParagraphActions.InsertBelow: + this.insertParagraph('below'); + break; + case ParagraphActions.InsertCopyOfParagraphBelow: + this.cloneParagraph('below'); + break; + case ParagraphActions.MoveParagraphUp: + event.preventDefault(); + this.moveParagraphUp(); + break; + case ParagraphActions.MoveParagraphDown: + event.preventDefault(); + this.moveParagraphDown(); + break; + case ParagraphActions.SwitchEnable: + this.paragraph.config.enabled = !this.paragraph.config.enabled; + this.commitParagraph(); + break; + case ParagraphActions.SwitchOutputShow: + this.setTableHide(!this.paragraph.config.tableHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchLineNumber: + this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; + this.commitParagraph(); + break; + case ParagraphActions.SwitchTitleShow: + this.paragraph.config.title = !this.paragraph.config.title; + this.commitParagraph(); + break; + case ParagraphActions.Clear: + this.clearParagraphOutput(); + break; + case ParagraphActions.Link: + this.openSingleParagraph(this.paragraph.id); + break; + case ParagraphActions.ReduceWidth: + if (!this.paragraph.config.colWidth) { + throw new Error('colWidth is required'); + } + this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.IncreaseWidth: + if (!this.paragraph.config.colWidth) { + throw new Error('colWidth is required'); + } + this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.FindInCode: + this.searchCode.emit(); + break; default: break; } diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts index 135de343887..f3cdb96620b 100644 --- a/zeppelin-web-angular/src/app/services/shortcut.service.ts +++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts @@ -16,56 +16,61 @@ import { EventManager } from '@angular/platform-browser'; import { Observable } from 'rxjs'; export enum ParagraphActions { - EditMode = 'Paragraph:EditMode', - CommandMode = 'Paragraph:CommandMode', Run = 'Paragraph:Run', + RunAbove = 'Paragraph:RunAbove', RunBelow = 'Paragraph:RunBelow', Cancel = 'Paragraph:Cancel', - Clear = 'Paragraph:Clear', - ReduceWidth = 'Paragraph:ReduceWidth', - IncreaseWidth = 'Paragraph:IncreaseWidth', + MoveCursorUp = 'Paragraph:MoveCursorUp', + MoveCursorDown = 'Paragraph:MoveCursorDown', Delete = 'Paragraph:Delete', - MoveToUp = 'Paragraph:MoveToUp', - MoveToDown = 'Paragraph:MoveToDown', - SelectAbove = 'Paragraph:SelectAbove', - SelectBelow = 'Paragraph:SelectBelow', InsertAbove = 'Paragraph:InsertAbove', InsertBelow = 'Paragraph:InsertBelow', + InsertCopyOfParagraphBelow = 'Paragraph:InsertCopyOfParagraphBelow', + MoveParagraphUp = 'Paragraph:MoveParagraphUp', + MoveParagraphDown = 'Paragraph:MoveParagraphDown', + SwitchEnable = 'Paragraph:SwitchEnable', + SwitchOutputShow = 'Paragraph:SwitchOutputShow', SwitchLineNumber = 'Paragraph:SwitchLineNumber', SwitchTitleShow = 'Paragraph:SwitchTitleShow', - SwitchOutputShow = 'Paragraph:SwitchOutputShow', - SwitchEditorShow = 'Paragraph:SwitchEditorShow', - SwitchEnable = 'Paragraph:SwitchEnable', - Link = 'Paragraph:Link' + Clear = 'Paragraph:Clear', + Link = 'Paragraph:Link', + ReduceWidth = 'Paragraph:ReduceWidth', + IncreaseWidth = 'Paragraph:IncreaseWidth', + FindInCode = 'Paragraph:FindInCode' } +// On macOS, pressing Option(Alt) + a letter produces a non-ASCII character +// Shortcuts must use this resulting character instead of the plain letter for macOS export const ShortcutsMap = { - [ParagraphActions.EditMode]: 'enter', - [ParagraphActions.CommandMode]: 'esc', - [ParagraphActions.Run]: 'shift.enter', - [ParagraphActions.RunBelow]: 'shift.ctrlCmd.enter', - [ParagraphActions.Cancel]: 'shift.ctrlCmd.c', - // Need register special character `¬` in MacOS - [ParagraphActions.Clear]: ['alt.ctrlCmd.l', 'alt.ctrlCmd.¬'], - // Need register special character `†` in MacOS - [ParagraphActions.Link]: ['alt.ctrlCmd.t', 'alt.ctrlCmd.†'], - // Need register special character `®` in MacOS - [ParagraphActions.SwitchEnable]: ['alt.ctrlCmd.r', 'alt.ctrlCmd.®'], - // Need register special character `–` in MacOS - [ParagraphActions.ReduceWidth]: ['alt.ctrlCmd.-', 'alt.ctrlCmd.–'], - // Need register special character `≠` in MacOS - [ParagraphActions.IncreaseWidth]: ['alt.ctrlCmd.+', 'alt.ctrlCmd.≠'], - [ParagraphActions.Delete]: 'shift.delete', - [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup', 'ctrlCmd.arrowleft'], - [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown', 'ctrlCmd.arrowright'], - [ParagraphActions.SelectAbove]: ['k', 'arrowup', 'arrowleft'], - [ParagraphActions.SelectBelow]: ['j', 'arrowdown', 'arrowright'], - [ParagraphActions.SwitchLineNumber]: 'l', - [ParagraphActions.SwitchTitleShow]: 't', - [ParagraphActions.SwitchOutputShow]: 'o', - [ParagraphActions.SwitchEditorShow]: 'e', - [ParagraphActions.InsertAbove]: 'a', - [ParagraphActions.InsertBelow]: 'b' + [ParagraphActions.Run]: 'shift.enter', // Run paragraph + [ParagraphActions.RunAbove]: 'control.shift.arrowup', // Run all above paragraphs (exclusive) + [ParagraphActions.RunBelow]: 'control.shift.arrowdown', // Run all below paragraphs (inclusive) + [ParagraphActions.Cancel]: ['control.alt.c', 'control.alt.ç'], // Cancel + [ParagraphActions.MoveCursorUp]: 'control.p', // Move cursor Up + [ParagraphActions.MoveCursorDown]: 'control.n', // Move cursor Down + [ParagraphActions.Delete]: ['control.alt.d', 'control.alt.∂'], // Remove paragraph + [ParagraphActions.InsertAbove]: ['control.alt.a', 'control.alt.å'], // Insert new paragraph above + [ParagraphActions.InsertBelow]: ['control.alt.b', 'control.alt.∫'], // Insert new paragraph below + [ParagraphActions.InsertCopyOfParagraphBelow]: 'control.shift.c', // Insert copy of paragraph below + [ParagraphActions.MoveParagraphUp]: ['control.alt.k', 'control.alt.˚'], // Move paragraph Up + [ParagraphActions.MoveParagraphDown]: ['control.alt.j', 'control.alt.∆'], // Move paragraph Down + [ParagraphActions.SwitchEnable]: ['control.alt.r', 'control.alt.®'], // Enable/Disable run paragraph + [ParagraphActions.SwitchOutputShow]: ['control.alt.o', 'control.alt.ø'], // Toggle output + // Toggle editor - Shortcut logic is implemented in the editor component + [ParagraphActions.SwitchLineNumber]: ['control.alt.m', 'control.alt.µ'], // Toggle line number + [ParagraphActions.SwitchTitleShow]: ['control.alt.t', 'control.alt.†'], // Toggle title + [ParagraphActions.Clear]: ['control.alt.l', 'control.alt.¬'], // Clear output + [ParagraphActions.Link]: ['control.alt.w', 'control.alt.∑'], // Link this paragraph + [ParagraphActions.ReduceWidth]: 'control.shift._', // Reduce paragraph width + [ParagraphActions.IncreaseWidth]: 'control.shift.=', // Increase paragraph width + // Auto-completion - No longer needed; always applied now + // Cut the line - Shortcut logic is implemented in the editor component + // Paste the line - Shortcut logic is implemented in the editor component + // Search inside the code - Shortcut logic is implemented in the editor component + // Move cursor to the beginning - System shortcut + // Move cursor at the end - System shortcut + // TODO: Check after the search code is implemented in action-bar.component.ts + [ParagraphActions.FindInCode]: ['control.alt.f', 'control.alt.ƒ'] // Find in code }; export interface ShortcutEvent { @@ -78,10 +83,6 @@ export interface ShortcutOption { keybindings: string; } -function isMacOS() { - return navigator.platform.indexOf('Mac') > -1; -} - @Injectable({ providedIn: 'root' }) @@ -99,9 +100,7 @@ export class ShortcutService { bindShortcut(option: ShortcutOption): Observable { const host = option.scope || this.element; - // `ctrlCmd` is special symbol, will be replaced `meta` in MacOS, 'control' in Windows/Linux - const keybindings = option.keybindings.replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control'); - const eventName = `keydown.${keybindings}`; + const eventName = `keydown.${option.keybindings}`; // tslint:disable-next-line:ban-types let dispose: Function; return new Observable(observer => { diff --git a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html index 81d711155d5..1621a174100 100644 --- a/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html +++ b/zeppelin-web/src/app/notebook/paragraph/paragraph-control.html @@ -141,7 +141,7 @@ - Ctrl+Shift+Enter + Ctrl+Shift+Up Run all above @@ -150,7 +150,7 @@ - Ctrl+Shift+Enter + Ctrl+Shift+Down Run all below @@ -189,7 +189,7 @@
  • - Ctrl+ {{ isMac ? 'Option' : 'Alt'}}+R + Ctrl+{{ isMac ? 'Option' : 'Alt'}}+R {{paragraph.config.enabled ? "Disable" : "Enable"}} run