Skip to content

Commit c80f26a

Browse files
committed
History navigation for Find Widget in webview. Fix #29708.
1 parent d347d59 commit c80f26a

File tree

6 files changed

+148
-6
lines changed

6 files changed

+148
-6
lines changed

src/vs/workbench/parts/extensions/browser/extensionEditor.ts

+63-2
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,18 @@ import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLa
5151
import { attachListStyler } from 'vs/platform/theme/common/styler';
5252
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
5353
import { IContextKeyService, RawContextKey, ContextKeyExpr, IContextKey } from 'vs/platform/contextkey/common/contextkey';
54-
import { Command } from 'vs/editor/common/editorCommonExtensions';
54+
import { Command, ICommandOptions } from 'vs/editor/common/editorCommonExtensions';
5555
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
5656
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
5757

5858
/** A context key that is set when an extension editor webview has focus. */
5959
export const KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS = new RawContextKey<boolean>('extensionEditorWebviewFocus', undefined);
6060
/** A context key that is set when an extension editor webview not have focus. */
6161
export const KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS.toNegated();
62+
/** A context key that is set when the find widget find input in extension editor webview is focused. */
63+
export const KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED = new RawContextKey<boolean>('extensionEditorFindWidgetInputFocused', false);
64+
/** A context key that is set when the find widget find input in extension editor webview is not focused. */
65+
export const KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED.toNegated();
6266

6367
function renderBody(body: string): string {
6468
return `<!DOCTYPE html>
@@ -168,6 +172,7 @@ export class ExtensionEditor extends BaseEditor {
168172
private extensionDependencies: Cache<IExtensionDependencies>;
169173

170174
private contextKey: IContextKey<boolean>;
175+
private findInputFocusContextKey: IContextKey<boolean>;
171176
private layoutParticipants: ILayoutParticipant[] = [];
172177
private contentDisposables: IDisposable[] = [];
173178
private transientDisposables: IDisposable[] = [];
@@ -199,6 +204,7 @@ export class ExtensionEditor extends BaseEditor {
199204
this.extensionManifest = null;
200205
this.extensionDependencies = null;
201206
this.contextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_WEBVIEW_FOCUS.bindTo(contextKeyService);
207+
this.findInputFocusContextKey = KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(contextKeyService);
202208
}
203209

204210
createEditor(parent: Builder): void {
@@ -346,6 +352,18 @@ export class ExtensionEditor extends BaseEditor {
346352
}
347353
}
348354

355+
public showNextFindTerm() {
356+
if (this.activeWebview) {
357+
this.activeWebview.showNextFindTerm();
358+
}
359+
}
360+
361+
public showPreviousFindTerm() {
362+
if (this.activeWebview) {
363+
this.activeWebview.showPreviousFindTerm();
364+
}
365+
}
366+
349367
private onNavbarChange(extension: IExtension, id: string): void {
350368
this.contentDisposables = dispose(this.contentDisposables);
351369
this.content.innerHTML = '';
@@ -366,7 +384,7 @@ export class ExtensionEditor extends BaseEditor {
366384
.then<void>(body => {
367385
const allowedBadgeProviders = this.extensionsWorkbenchService.allowedBadgeProviders;
368386
const webViewOptions = allowedBadgeProviders.length > 0 ? { allowScripts: false, allowSvgs: false, svgWhiteList: allowedBadgeProviders } : undefined;
369-
this.activeWebview = new WebView(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.contextViewService, this.contextKey, webViewOptions);
387+
this.activeWebview = new WebView(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.contextViewService, this.contextKey, this.findInputFocusContextKey, webViewOptions);
370388
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, this.activeWebview);
371389
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
372390

@@ -847,3 +865,46 @@ const hideCommand = new ShowExtensionEditorFindCommand({
847865
}
848866
});
849867
KeybindingsRegistry.registerCommandAndKeybindingRule(hideCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
868+
869+
class ShowExtensionEditorFindTermCommand extends Command {
870+
constructor(opts: ICommandOptions, private _next: boolean) {
871+
super(opts);
872+
}
873+
874+
public runCommand(accessor: ServicesAccessor, args: any): void {
875+
const extensionEditor = this.getExtensionEditor(accessor);
876+
if (extensionEditor) {
877+
if (this._next) {
878+
extensionEditor.showNextFindTerm();
879+
} else {
880+
extensionEditor.showPreviousFindTerm();
881+
}
882+
}
883+
}
884+
885+
private getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor {
886+
const activeEditor = accessor.get(IWorkbenchEditorService).getActiveEditor() as ExtensionEditor;
887+
if (activeEditor instanceof ExtensionEditor) {
888+
return activeEditor;
889+
}
890+
return null;
891+
}
892+
}
893+
894+
const showNextFindTermCommand = new ShowExtensionEditorFindTermCommand({
895+
id: 'editor.action.extensioneditor.showNextFindTerm',
896+
precondition: KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED,
897+
kbOpts: {
898+
primary: KeyMod.Alt | KeyCode.DownArrow
899+
}
900+
}, true);
901+
KeybindingsRegistry.registerCommandAndKeybindingRule(showNextFindTermCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
902+
903+
const showPreviousFindTermCommand = new ShowExtensionEditorFindTermCommand({
904+
id: 'editor.action.extensioneditor.showPreviousFindTerm',
905+
precondition: KEYBINDING_CONTEXT_EXTENSIONEDITOR_FIND_WIDGET_INPUT_FOCUSED,
906+
kbOpts: {
907+
primary: KeyMod.Alt | KeyCode.UpArrow
908+
}
909+
}, false);
910+
KeybindingsRegistry.registerCommandAndKeybindingRule(showPreviousFindTermCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));

src/vs/workbench/parts/html/browser/htmlPreviewPart.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export class HtmlPreviewPart extends WebviewEditor {
8484
webviewOptions = this.input.options;
8585
}
8686

87-
this._webview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this._contextViewService, this.contextKey, webviewOptions);
87+
this._webview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this._contextViewService, this.contextKey, this.findInputFocusContextKey, webviewOptions);
8888
if (this.input && this.input instanceof HtmlInput) {
8989
const state = this.loadViewState(this.input.getResource());
9090
this.scrollYPercentage = state ? state.scrollYPercentage : 0;

src/vs/workbench/parts/html/browser/webview.ts

+13
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export default class Webview {
7474
private _styleElement: Element,
7575
@IContextViewService private _contextViewService: IContextViewService,
7676
private _contextKey: IContextKey<boolean>,
77+
private _findInputContextKey: IContextKey<boolean>,
7778
private _options: WebviewOptions = {},
7879
) {
7980
this._webview = <any>document.createElement('webview');
@@ -205,6 +206,10 @@ export default class Webview {
205206
this._contextKey.set(isFocused || document.activeElement === this._webview);
206207
}
207208

209+
public notifyFindWidgetInputFocusChanged(isFocused: boolean) {
210+
this._findInputContextKey.set(isFocused);
211+
}
212+
208213
dispose(): void {
209214
this._onDidClickLink.dispose();
210215
this._disposables = dispose(this._disposables);
@@ -450,4 +455,12 @@ export default class Webview {
450455
public hideFind() {
451456
this._webviewFindWidget.hide();
452457
}
458+
459+
public showNextFindTerm() {
460+
this._webviewFindWidget.showNextFindTerm();
461+
}
462+
463+
public showPreviousFindTerm() {
464+
this._webviewFindWidget.showPreviousFindTerm();
465+
}
453466
}

src/vs/workbench/parts/html/browser/webviewEditor.ts

+63-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { BaseWebviewEditor } from 'vs/workbench/browser/parts/editor/webviewEdit
99
import { IStorageService } from 'vs/platform/storage/common/storage';
1010

1111
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
12-
import { Command } from 'vs/editor/common/editorCommonExtensions';
12+
import { Command, ICommandOptions } from 'vs/editor/common/editorCommonExtensions';
1313
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
1414
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
1515
import { ContextKeyExpr, IContextKey, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -26,6 +26,10 @@ export interface HtmlPreviewEditorViewState {
2626
export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey<boolean>('webviewEditorFocus', undefined);
2727
/** A context key that is set when a webview editor does not have focus. */
2828
export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.toNegated();
29+
/** A context key that is set when the find widget find input in webview editor webview is focused. */
30+
export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED = new RawContextKey<boolean>('webviewEditorFindWidgetInputFocused', false);
31+
/** A context key that is set when the find widget find input in webview editor webview is not focused. */
32+
export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.toNegated();
2933

3034
/**
3135
* This class is only intended to be subclassed and not instantiated.
@@ -36,6 +40,7 @@ export abstract class WebviewEditor extends BaseWebviewEditor {
3640
protected _webview: WebView;
3741
protected content: HTMLElement;
3842
protected contextKey: IContextKey<boolean>;
43+
protected findInputFocusContextKey: IContextKey<boolean>;
3944

4045
constructor(
4146
id: string,
@@ -47,6 +52,7 @@ export abstract class WebviewEditor extends BaseWebviewEditor {
4752
super(id, telemetryService, themeService, storageService);
4853
if (contextKeyService) {
4954
this.contextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS.bindTo(contextKeyService);
55+
this.findInputFocusContextKey = KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED.bindTo(contextKeyService);
5056
}
5157
}
5258

@@ -62,6 +68,18 @@ export abstract class WebviewEditor extends BaseWebviewEditor {
6268
}
6369
}
6470

71+
public showNextFindTerm() {
72+
if (this._webview) {
73+
this._webview.showNextFindTerm();
74+
}
75+
}
76+
77+
public showPreviousFindTerm() {
78+
if (this._webview) {
79+
this._webview.showPreviousFindTerm();
80+
}
81+
}
82+
6583
public updateStyles() {
6684
super.updateStyles();
6785
if (this._webview) {
@@ -124,4 +142,47 @@ const hideCommand = new HideWebViewEditorFindCommand({
124142
primary: KeyCode.Escape
125143
}
126144
});
127-
KeybindingsRegistry.registerCommandAndKeybindingRule(hideCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
145+
KeybindingsRegistry.registerCommandAndKeybindingRule(hideCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
146+
147+
class ShowWebViewEditorFindTermCommand extends Command {
148+
constructor(opts: ICommandOptions, private _next: boolean) {
149+
super(opts);
150+
}
151+
152+
public runCommand(accessor: ServicesAccessor, args: any): void {
153+
const webViewEditor = this.getWebViewEditor(accessor);
154+
if (webViewEditor) {
155+
if (this._next) {
156+
webViewEditor.showNextFindTerm();
157+
} else {
158+
webViewEditor.showPreviousFindTerm();
159+
}
160+
}
161+
}
162+
163+
private getWebViewEditor(accessor: ServicesAccessor): WebviewEditor {
164+
const activeEditor = accessor.get(IWorkbenchEditorService).getActiveEditor() as WebviewEditor;
165+
if (activeEditor.isWebviewEditor) {
166+
return activeEditor;
167+
}
168+
return null;
169+
}
170+
}
171+
172+
const showNextFindTermCommand = new ShowWebViewEditorFindTermCommand({
173+
id: 'editor.action.webvieweditor.showNextFindTerm',
174+
precondition: KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED,
175+
kbOpts: {
176+
primary: KeyMod.Alt | KeyCode.DownArrow
177+
}
178+
}, true);
179+
KeybindingsRegistry.registerCommandAndKeybindingRule(showNextFindTermCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
180+
181+
const showPreviousFindTermCommand = new ShowWebViewEditorFindTermCommand({
182+
id: 'editor.action.webvieweditor.showPreviousFindTerm',
183+
precondition: KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED,
184+
kbOpts: {
185+
primary: KeyMod.Alt | KeyCode.UpArrow
186+
}
187+
}, false);
188+
KeybindingsRegistry.registerCommandAndKeybindingRule(showPreviousFindTermCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));

src/vs/workbench/parts/html/browser/webviewFindWidget.ts

+7
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,11 @@ export class WebviewFindWidget extends SimpleFindWidget {
5454
this.webview.notifyFindWidgetFocusChanged(false);
5555
}
5656

57+
protected onFindInputFocusTrackerFocus() {
58+
this.webview.notifyFindWidgetInputFocusChanged(true);
59+
}
60+
61+
protected onFindInputFocusTrackerBlur() {
62+
this.webview.notifyFindWidgetInputFocusChanged(false);
63+
}
5764
}

src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class ReleaseNotesEditor extends WebviewEditor {
9191
};
9292

9393
const body = renderBody(marked(text, { renderer }));
94-
this._webview = new WebView(this.content, this.partService.getContainer(Parts.EDITOR_PART), this._contextViewService, this.contextKey);
94+
this._webview = new WebView(this.content, this.partService.getContainer(Parts.EDITOR_PART), this._contextViewService, this.contextKey, this.findInputFocusContextKey);
9595
if (this.input && this.input instanceof ReleaseNotesInput) {
9696
const state = this.loadViewState(this.input.version);
9797
if (state) {

0 commit comments

Comments
 (0)