/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'vs/css!./media/extensionEditor';
import { localize } from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { marked } from 'vs/base/common/marked/marked';
import { IDisposable, empty, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { Builder } from 'vs/base/browser/builder';
import { append, emmet as $, addClass, removeClass, finalHandler } from 'vs/base/browser/dom';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IRequestService } from 'vs/platform/request/common/request';
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IThemeService } from 'vs/workbench/services/themes/common/themeService';
import { ExtensionsInput } from './extensionsInput';
import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID } from './extensions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITemplateData } from './extensionsList';
import { RatingsWidget, InstallWidget } from './extensionsWidgets';
import { EditorOptions } from 'vs/workbench/common/editor';
import { shell } from 'electron';
import product from 'vs/platform/product';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { CombinedInstallAction, UpdateAction, EnableAction } from './extensionsActions';
import WebView from 'vs/workbench/parts/html/browser/webview';
function renderBody(body: string): string {
return `
${ body }
`;
}
export class ExtensionEditor extends BaseEditor {
static ID: string = 'workbench.editor.extension';
private icon: HTMLElement;
private name: HTMLAnchorElement;
private license: HTMLAnchorElement;
private publisher: HTMLAnchorElement;
private installCount: HTMLElement;
private rating: HTMLAnchorElement;
private description: HTMLElement;
private actionBar: ActionBar;
private body: HTMLElement;
private _highlight: ITemplateData;
private highlightDisposable: IDisposable;
private transientDisposables: IDisposable[];
private disposables: IDisposable[];
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IExtensionGalleryService private galleryService: IExtensionGalleryService,
@IConfigurationService private configurationService: IConfigurationService,
@IInstantiationService private instantiationService: IInstantiationService,
@IRequestService private requestService: IRequestService,
@IViewletService private viewletService: IViewletService,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@IThemeService private themeService: IThemeService
) {
super(ExtensionEditor.ID, telemetryService);
this._highlight = null;
this.highlightDisposable = empty;
this.disposables = [];
}
createEditor(parent: Builder): void {
const container = parent.getHTMLElement();
const root = append(container, $('.extension-editor'));
const header = append(root, $('.header'));
this.icon = append(header, $('.icon'));
const details = append(header, $('.details'));
const title = append(details, $('.title'));
this.name = append(title, $('a.name'));
this.name.href = '#';
this.license = append(title, $('a.license'));
this.license.href = '#';
this.license.textContent = localize('license', 'License');
const subtitle = append(details, $('.subtitle'));
this.publisher = append(subtitle, $('a.publisher'));
this.publisher.href = '#';
this.installCount = append(subtitle, $('span.install'));
this.rating = append(subtitle, $('a.rating'));
this.rating.href = '#';
this.description = append(details, $('.description'));
const actions = append(details, $('.actions'));
this.actionBar = new ActionBar(actions, { animated: false });
this.disposables.push(this.actionBar);
this.body = append(root, $('.body'));
}
setInput(input: ExtensionsInput, options: EditorOptions): TPromise {
this.transientDisposables = dispose(this.transientDisposables);
const extension = input.extension;
this.icon.style.backgroundImage = `url("${ extension.iconUrl }")`;
this.name.textContent = extension.displayName;
this.publisher.textContent = extension.publisherDisplayName;
this.description.textContent = extension.description;
if (product.extensionsGallery) {
const extensionUrl = `${ product.extensionsGallery.itemUrl }?itemName=${ extension.publisher }.${ extension.name }`;
const licenseUrl = `${ product.extensionsGallery.itemUrl }/${ extension.publisher }.${ extension.name }/license`;
this.name.onclick = finalHandler(() => shell.openExternal(extensionUrl));
this.license.onclick = finalHandler(() => shell.openExternal(licenseUrl));
this.rating.onclick = finalHandler(() => shell.openExternal(`${ extensionUrl }#review-details`));
this.publisher.onclick = finalHandler(() => {
this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet)
.done(viewlet => viewlet.search(`publisher:"${ extension.publisherDisplayName }"`, true));
});
}
const install = this.instantiationService.createInstance(InstallWidget, this.installCount, extension, {});
this.transientDisposables.push(install);
const ratings = this.instantiationService.createInstance(RatingsWidget, this.rating, extension, {});
this.transientDisposables.push(ratings);
const installAction = this.instantiationService.createInstance(CombinedInstallAction, extension);
const updateAction = this.instantiationService.createInstance(UpdateAction, extension);
const enableAction = this.instantiationService.createInstance(EnableAction, extension);
this.actionBar.clear();
this.actionBar.push([enableAction, updateAction, installAction], { icon: true, label: true });
this.transientDisposables.push(enableAction, updateAction, installAction);
this.body.innerHTML = '';
let promise: TPromise = super.setInput(input, options);
if (extension.readmeUrl) {
promise = promise
.then(() => addClass(this.body, 'loading'))
.then(() => this.requestService.makeRequest({ url: extension.readmeUrl }))
.then(response => response.responseText)
.then(marked.parse)
.then(body => {
const webview = new WebView(
this.body,
document.querySelector('.monaco-editor-background'),
link => shell.openExternal(link.toString())
);
webview.style(this.themeService.getTheme());
webview.contents = [renderBody(body)];
const listener = this.themeService.onDidThemeChange(themeId => webview.style(themeId));
this.transientDisposables.push(webview, listener);
})
.then(null, () => null)
.then(() => removeClass(this.body, 'loading'));
} else {
promise = promise
.then(() => append(this.body, $('p')))
.then(p => p.textContent = localize('noReadme', "No README available."));
}
this.transientDisposables.push(toDisposable(() => promise.cancel()));
return TPromise.as(null);
}
layout(): void {
return;
}
dispose(): void {
this._highlight = null;
this.transientDisposables = dispose(this.transientDisposables);
this.disposables = dispose(this.disposables);
super.dispose();
}
}