extensionsViewlet.ts 6.3 KB
Newer Older
J
Joao Moreno 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

J
Joao Moreno 已提交
8
import 'vs/css!./media/extensionsViewlet';
J
Joao Moreno 已提交
9 10
import { localize } from 'vs/nls';
import { ThrottledDelayer, always } from 'vs/base/common/async';
J
Joao Moreno 已提交
11 12 13
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Builder, Dimension } from 'vs/base/browser/builder';
J
Joao Moreno 已提交
14 15
import { mapEvent, filterEvent } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
J
Joao Moreno 已提交
16 17
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
J
Joao Moreno 已提交
18
import { Viewlet } from 'vs/workbench/browser/viewlet';
J
Joao Moreno 已提交
19
import { append, emmet as $ } from 'vs/base/browser/dom';
J
Joao Moreno 已提交
20
import { PagedModel, SinglePagePagedModel } from 'vs/base/common/paging';
J
Joao Moreno 已提交
21
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
J
Joao Moreno 已提交
22 23
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
J
Joao Moreno 已提交
24
import { Delegate, Renderer } from './extensionsList';
J
Joao Moreno 已提交
25
import { ExtensionsModel, IExtension } from './extensionsModel';
J
Joao Moreno 已提交
26
import { IExtensionsViewlet } from './extensions';
J
Joao Moreno 已提交
27
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
J
Joao Moreno 已提交
28
import { ExtensionsInput } from '../common/extensionsInput';
J
Joao Moreno 已提交
29
import { IProgressService } from 'vs/platform/progress/common/progress';
J
Joao Moreno 已提交
30
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Joao Moreno 已提交
31

J
Joao Moreno 已提交
32
export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
J
Joao Moreno 已提交
33 34 35

	static ID: string = 'workbench.viewlet.extensions';

J
Joao Moreno 已提交
36
	private searchDelayer: ThrottledDelayer<any>;
J
Joao Moreno 已提交
37
	private root: HTMLElement;
J
Joao Moreno 已提交
38 39
	private searchBox: HTMLInputElement;
	private extensionsBox: HTMLElement;
J
Joao Moreno 已提交
40 41
	private model: ExtensionsModel;
	private list: PagedList<IExtension>;
J
Joao Moreno 已提交
42
	private disposables: IDisposable[] = [];
J
Joao Moreno 已提交
43

J
Joao Moreno 已提交
44 45
	constructor(
		@ITelemetryService telemetryService: ITelemetryService,
46
		@IExtensionGalleryService private galleryService: IExtensionGalleryService,
J
Joao Moreno 已提交
47
		@IExtensionManagementService private extensionService: IExtensionManagementService,
J
Joao Moreno 已提交
48
		@IProgressService private progressService: IProgressService,
J
Joao Moreno 已提交
49 50
		@IInstantiationService private instantiationService: IInstantiationService,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService
J
Joao Moreno 已提交
51
	) {
J
Joao Moreno 已提交
52
		super(ExtensionsViewlet.ID, telemetryService);
J
Joao Moreno 已提交
53
		this.searchDelayer = new ThrottledDelayer(500);
J
Joao Moreno 已提交
54
		this.model = instantiationService.createInstance(ExtensionsModel);
J
Joao Moreno 已提交
55 56 57 58
	}

	create(parent: Builder): TPromise<void> {
		super.create(parent);
J
Joao Moreno 已提交
59 60 61
		parent.addClass('extensions-viewlet');
		this.root = parent.getHTMLElement();

J
Joao Moreno 已提交
62 63 64
		const header = append(this.root, $('.header'));

		this.searchBox = append(header, $<HTMLInputElement>('input.search-box'));
J
Joao Moreno 已提交
65
		this.searchBox.type = 'search';
J
Joao Moreno 已提交
66
		this.searchBox.placeholder = localize('searchExtensions', "Search Extensions in Marketplace");
J
Joao Moreno 已提交
67 68 69
		this.extensionsBox = append(this.root, $('.extensions'));

		const delegate = new Delegate();
J
Joao Moreno 已提交
70
		const renderer = this.instantiationService.createInstance(Renderer, this.model);
J
Joao Moreno 已提交
71
		this.list = new PagedList(this.extensionsBox, delegate, [renderer]);
J
Joao Moreno 已提交
72

J
Joao Moreno 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		const onRawKeyDown = domEvent(this.searchBox, 'keydown');
		const onKeyDown = mapEvent(onRawKeyDown, e => new StandardKeyboardEvent(e));
		const onEnter = filterEvent(onKeyDown, e => e.keyCode === KeyCode.Enter);
		const onEscape = filterEvent(onKeyDown, e => e.keyCode === KeyCode.Escape);
		const onUpArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.UpArrow);
		const onDownArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.DownArrow);

		onEnter(() => this.onEnter(), null, this.disposables);
		onEscape(() => this.onEscape(), null, this.disposables);
		onUpArrow(() => this.onUpArrow(), null, this.disposables);
		onDownArrow(() => this.onDownArrow(), null, this.disposables);

		const onInput = domEvent(this.searchBox, 'input');
		onInput(() => this.triggerSearch(), null, this.disposables);

		this.list.onDOMFocus(() => this.searchBox.focus(), null, this.disposables);
J
Joao Moreno 已提交
89

J
Joao Moreno 已提交
90
		this.list.onSelectionChange(e => {
J
Joao Moreno 已提交
91
			const [extension] = e.elements;
J
Joao Moreno 已提交
92

J
Joao Moreno 已提交
93
			if (!extension) {
J
Joao Moreno 已提交
94 95 96
				return;
			}

J
Joao Moreno 已提交
97
			return this.editorService.openEditor(new ExtensionsInput(this.model, extension));
J
Joao Moreno 已提交
98 99
		}, null, this.disposables);

J
Joao Moreno 已提交
100 101 102 103
		return TPromise.as(null);
	}

	setVisible(visible:boolean): TPromise<void> {
J
Joao Moreno 已提交
104 105
		return super.setVisible(visible).then(() => {
			if (visible) {
J
Joao Moreno 已提交
106 107
				this.searchBox.focus();
				this.searchBox.setSelectionRange(0,this.searchBox.value.length);
J
Joao Moreno 已提交
108
				this.triggerSearch(true);
J
Joao Moreno 已提交
109 110
			} else {
				this.list.model = new SinglePagePagedModel([]);
J
Joao Moreno 已提交
111 112
			}
		});
J
Joao Moreno 已提交
113 114 115
	}

	focus(): void {
J
Joao Moreno 已提交
116
		this.searchBox.focus();
J
Joao Moreno 已提交
117 118
	}

J
Joao Moreno 已提交
119
	layout({ height }: Dimension):void {
J
Joao Moreno 已提交
120
		this.list.layout(height - 38);
J
Joao Moreno 已提交
121 122
	}

J
Joao Moreno 已提交
123 124 125 126 127 128
	search(text: string, immediate = false): void {
		this.searchBox.value = text;
		this.triggerSearch(immediate);
	}

	private triggerSearch(immediate = false): void {
J
Joao Moreno 已提交
129
		const text = this.searchBox.value;
J
Joao Moreno 已提交
130
		this.searchDelayer.trigger(() => this.doSearch(text), immediate || !text ? 0 : 500);
J
Joao Moreno 已提交
131 132 133
	}

	private doSearch(text: string = ''): TPromise<any> {
J
Joao Moreno 已提交
134
		const progressRunner = this.progressService.show(true);
J
Joao Moreno 已提交
135
		let promise: TPromise<PagedModel<IExtension>>;
J
Joao Moreno 已提交
136

J
Joao Moreno 已提交
137 138 139 140
		if (!text) {
			promise = this.model.getLocal()
				.then(result => new SinglePagePagedModel(result));
		} else if (/@outdated/i.test(text)) {
J
Joao Moreno 已提交
141
			promise = this.model.getLocal()
J
Joao Moreno 已提交
142
				.then(result => result.filter(e => e.outdated))
J
Joao Moreno 已提交
143
				.then(result => new SinglePagePagedModel(result));
J
Joao Moreno 已提交
144 145 146
		} else {
			promise = this.model.queryGallery({ text })
				.then(result => new PagedModel(result));
J
Joao Moreno 已提交
147 148 149
		}

		return always(promise, () => progressRunner.done())
J
Joao Moreno 已提交
150
			.then(model => this.list.model = model);
J
Joao Moreno 已提交
151 152
	}

J
Joao Moreno 已提交
153 154 155 156 157 158
	private onEnter(): void {
		this.list.setSelection(...this.list.getFocus());
	}

	private onEscape(): void {
		this.searchBox.value = '';
J
Joao Moreno 已提交
159
		this.triggerSearch(true);
J
Joao Moreno 已提交
160 161 162 163 164 165 166 167
	}

	private onUpArrow(): void {
		this.list.focusPrevious();
	}

	private onDownArrow(): void {
		this.list.focusNext();
J
Joao Moreno 已提交
168 169
	}

J
Joao Moreno 已提交
170
	dispose(): void {
J
Joao Moreno 已提交
171
		this.disposables = dispose(this.disposables);
J
Joao Moreno 已提交
172 173 174
		super.dispose();
	}
}