vsc-material-but-i-wont-sue.../src/webviews/Webview.ts
Alessio Occhipinti d9ea7c2ea6 Feat/release note webview (#248)
* chore(deps): update dependencies

* chore: renamed custom-settings interface

* WIP: added new Webview handler main class

* WIP: added support for Settings webview

* WIP (webview): added gulp command for copying ui files

* WIP (preview): scripts for building updated

* chore: gitignore

* chore: switched to babel-preset-env and added browserify for bundling

* chore: small changes to webviews (added external interfaces file)

* chore: added new task on task explorer and small fix copy ui task

* WIP: webview HTML, JS and CSS added and ready to be developed

* chore: Test native elements

* chore(release): 2.3.0

* chore: init added release notes webview

* chore: Removed unused import

* chore: fixed build release-notes

* chore: Add release notes template

* chore: Update release notes

* chore: Update release notes template

* chore: Update release notes style

* Create stale.yml

* chore: Update release notes

* chore: Removed show-changelog command
2018-08-29 21:30:40 +02:00

157 lines
4 KiB
TypeScript

import * as path from 'path';
import {
workspace as Workspace,
Disposable,
ExtensionContext,
WebviewPanel,
ViewColumn,
window,
WebviewPanelOnDidChangeViewStateEvent,
Uri
} from 'vscode';
import {getCustomSettings} from '../../extensions/helpers/settings';
import {Invalidates, Message, SettingsChangedMessage} from './interfaces';
export abstract class WebviewController<TBootstrap> extends Disposable {
private panel: WebviewPanel | undefined;
private disposablePanel: Disposable | undefined;
private invalidateOnVisible: Invalidates;
private context: ExtensionContext;
constructor(context: ExtensionContext) {
// Applying dispose callback for our disposable function
super(() => this.dispose());
this.context = context;
}
abstract get filename(): string;
abstract get id(): string;
abstract get title(): string;
abstract getBootstrap(): TBootstrap;
dispose() {
if (this.disposablePanel) {
this.disposablePanel.dispose();
}
}
private async getHtml(): Promise<string> {
const doc = await Workspace
.openTextDocument(this.context.asAbsolutePath(path.join('ui', this.filename)));
return doc.getText();
}
private postMessage(message: Message, invalidates: Invalidates = 'all') {
if (this.panel === undefined) {
return false;
}
const result = this.panel.webview.postMessage(message);
// If post was ok, update invalidateOnVisible if different than default
if (!result && this.invalidateOnVisible !== 'all') {
this.invalidateOnVisible = invalidates;
}
return result;
}
private postUpdatedConfiguration() {
// Post full raw configuration
return this.postMessage({
type: 'settingsChanged',
config: getCustomSettings()
} as SettingsChangedMessage, 'config');
}
private onPanelDisposed() {
if (this.disposablePanel) {
this.disposablePanel.dispose();
}
this.panel = undefined;
}
private onViewStateChanged(event: WebviewPanelOnDidChangeViewStateEvent) {
console.log('WebviewEditor.onViewStateChanged', event.webviewPanel.visible);
if (!this.invalidateOnVisible || !event.webviewPanel.visible) {
return;
}
// Update the view since it can be outdated
const invalidContext = this.invalidateOnVisible;
this.invalidateOnVisible = undefined;
switch (invalidContext) {
case 'config':
// Post the new configuration to the view
return this.postUpdatedConfiguration();
default:
return this.show();
}
}
protected async onMessageReceived(event: Message) {
if (event === null) {
return;
}
console.log(`WebviewEditor.onMessageReceived: type=${event.type}, data=${JSON.stringify(event)}`);
switch (event.type) {
case 'saveSettings':
// TODO: update settings
return;
default:
return;
}
}
async show(): Promise<void> {
const html = await this.getHtml();
const rootPath = Uri
.file(this.context.asAbsolutePath('.'))
.with({scheme: 'vscode-resource'}).toString();
// Replace placeholders in html content for assets and adding configurations as `window.bootstrap`
const fullHtml = html
.replace(/{{root}}/g, rootPath)
.replace('\'{{bootstrap}}\'', JSON.stringify(this.getBootstrap()));
// If panel already opened just reveal
if (this.panel !== undefined) {
this.panel.webview.html = fullHtml;
return this.panel.reveal(ViewColumn.Active);
}
this.panel = window.createWebviewPanel(
this.id,
this.title,
ViewColumn.Active,
{
retainContextWhenHidden: true,
enableFindWidget: true,
enableCommandUris: true,
enableScripts: true
}
);
// Applying listeners
this.disposablePanel = Disposable.from(
this.panel,
this.panel.onDidDispose(this.onPanelDisposed, this),
this.panel.onDidChangeViewState(this.onViewStateChanged, this),
this.panel.webview.onDidReceiveMessage(this.onMessageReceived, this)
);
this.panel.webview.html = fullHtml;
}
}