提交 d5dac808 编写于 作者: J Joao Moreno

remove event emitter from focus tracker

上级 aac483aa
...@@ -8,13 +8,14 @@ import * as platform from 'vs/base/common/platform'; ...@@ -8,13 +8,14 @@ import * as platform from 'vs/base/common/platform';
import { TPromise } from 'vs/base/common/winjs.base'; import { TPromise } from 'vs/base/common/winjs.base';
import { TimeoutTimer } from 'vs/base/common/async'; import { TimeoutTimer } from 'vs/base/common/async';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
import { EventEmitter } from 'vs/base/common/eventEmitter'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { isObject } from 'vs/base/common/types'; import { isObject } from 'vs/base/common/types';
import * as browser from 'vs/base/browser/browser'; import * as browser from 'vs/base/browser/browser';
import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { CharCode } from 'vs/base/common/charCode'; import { CharCode } from 'vs/base/common/charCode';
import Event, { Emitter } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
export function clearNode(node: HTMLElement) { export function clearNode(node: HTMLElement) {
while (node.firstChild) { while (node.firstChild) {
...@@ -417,12 +418,17 @@ export interface IEventMerger<R, E> { ...@@ -417,12 +418,17 @@ export interface IEventMerger<R, E> {
(lastEvent: R, currentEvent: E): R; (lastEvent: R, currentEvent: E): R;
} }
export interface DOMEvent {
preventDefault(): void;
stopPropagation(): void;
}
const MINIMUM_TIME_MS = 16; const MINIMUM_TIME_MS = 16;
const DEFAULT_EVENT_MERGER: IEventMerger<Event, Event> = function (lastEvent: Event, currentEvent: Event) { const DEFAULT_EVENT_MERGER: IEventMerger<DOMEvent, DOMEvent> = function (lastEvent: DOMEvent, currentEvent: DOMEvent) {
return currentEvent; return currentEvent;
}; };
class TimeoutThrottledDomListener<R, E extends Event> extends Disposable { class TimeoutThrottledDomListener<R, E extends DOMEvent> extends Disposable {
constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger<R, E> = <any>DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) { constructor(node: any, type: string, handler: (event: R) => void, eventMerger: IEventMerger<R, E> = <any>DEFAULT_EVENT_MERGER, minimumTimeMs: number = MINIMUM_TIME_MS) {
super(); super();
...@@ -452,7 +458,7 @@ class TimeoutThrottledDomListener<R, E extends Event> extends Disposable { ...@@ -452,7 +458,7 @@ class TimeoutThrottledDomListener<R, E extends Event> extends Disposable {
} }
} }
export function addDisposableThrottledListener<R, E extends Event = Event>(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger<R, E>, minimumTimeMs?: number): IDisposable { export function addDisposableThrottledListener<R, E extends DOMEvent = DOMEvent>(node: any, type: string, handler: (event: R) => void, eventMerger?: IEventMerger<R, E>, minimumTimeMs?: number): IDisposable {
return new TimeoutThrottledDomListener<R, E>(node, type, handler, eventMerger, minimumTimeMs); return new TimeoutThrottledDomListener<R, E>(node, type, handler, eventMerger, minimumTimeMs);
} }
...@@ -813,8 +819,8 @@ export const EventHelper = { ...@@ -813,8 +819,8 @@ export const EventHelper = {
}; };
export interface IFocusTracker { export interface IFocusTracker {
addBlurListener(fn: () => void): IDisposable; onDidFocus: Event<void>;
addFocusListener(fn: () => void): IDisposable; onDidBlur: Event<void>;
dispose(): void; dispose(): void;
} }
...@@ -836,49 +842,49 @@ export function restoreParentsScrollTop(node: Element, state: number[]): void { ...@@ -836,49 +842,49 @@ export function restoreParentsScrollTop(node: Element, state: number[]): void {
} }
} }
class FocusTracker extends Disposable implements IFocusTracker { class FocusTracker implements IFocusTracker {
private _eventEmitter: EventEmitter; private _onDidFocus = new Emitter<void>();
readonly onDidFocus: Event<void> = this._onDidFocus.event;
constructor(element: HTMLElement | Window) { private _onDidBlur = new Emitter<void>();
super(); readonly onDidBlur: Event<void> = this._onDidBlur.event;
private disposables: IDisposable[] = [];
constructor(element: HTMLElement | Window) {
let hasFocus = false; let hasFocus = false;
let loosingFocus = false; let loosingFocus = false;
this._eventEmitter = this._register(new EventEmitter()); let onFocus = () => {
let onFocus = (event: Event) => {
loosingFocus = false; loosingFocus = false;
if (!hasFocus) { if (!hasFocus) {
hasFocus = true; hasFocus = true;
this._eventEmitter.emit('focus', {}); this._onDidFocus.fire();
} }
}; };
let onBlur = (event: Event) => { let onBlur = () => {
if (hasFocus) { if (hasFocus) {
loosingFocus = true; loosingFocus = true;
window.setTimeout(() => { window.setTimeout(() => {
if (loosingFocus) { if (loosingFocus) {
loosingFocus = false; loosingFocus = false;
hasFocus = false; hasFocus = false;
this._eventEmitter.emit('blur', {}); this._onDidBlur.fire();
} }
}, 0); }, 0);
} }
}; };
this._register(addDisposableListener(element, EventType.FOCUS, onFocus, true)); domEvent(element, EventType.FOCUS, true)(onFocus, null, this.disposables);
this._register(addDisposableListener(element, EventType.BLUR, onBlur, true)); domEvent(element, EventType.BLUR, true)(onBlur, null, this.disposables);
}
public addFocusListener(fn: () => void): IDisposable {
return this._eventEmitter.addListener('focus', fn);
} }
public addBlurListener(fn: () => void): IDisposable { dispose(): void {
return this._eventEmitter.addListener('blur', fn); this.disposables = dispose(this.disposables);
this._onDidFocus.dispose();
this._onDidBlur.dispose();
} }
} }
...@@ -1007,7 +1013,7 @@ export function getElementsByTagName(tag: string): HTMLElement[] { ...@@ -1007,7 +1013,7 @@ export function getElementsByTagName(tag: string): HTMLElement[] {
return Array.prototype.slice.call(document.getElementsByTagName(tag), 0); return Array.prototype.slice.call(document.getElementsByTagName(tag), 0);
} }
export function finalHandler<T extends Event>(fn: (event: T) => any): (event: T) => any { export function finalHandler<T extends DOMEvent>(fn: (event: T) => any): (event: T) => any {
return e => { return e => {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
......
...@@ -487,14 +487,14 @@ export class ActionBar implements IActionRunner { ...@@ -487,14 +487,14 @@ export class ActionBar implements IActionRunner {
}); });
this.focusTracker = DOM.trackFocus(this.domNode); this.focusTracker = DOM.trackFocus(this.domNode);
this.focusTracker.addBlurListener(() => { this.toDispose.push(this.focusTracker.onDidBlur(() => {
if (document.activeElement === this.domNode || !DOM.isAncestor(document.activeElement, this.domNode)) { if (document.activeElement === this.domNode || !DOM.isAncestor(document.activeElement, this.domNode)) {
this._onDidBlur.fire(); this._onDidBlur.fire();
this.focusedItem = undefined; this.focusedItem = undefined;
} }
}); }));
this.focusTracker.addFocusListener(() => this.updateFocusedItem()); this.toDispose.push(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));
this.actionsList = document.createElement('ul'); this.actionsList = document.createElement('ul');
this.actionsList.className = 'actions-container'; this.actionsList.className = 'actions-container';
......
...@@ -146,8 +146,8 @@ export abstract class Panel implements IView { ...@@ -146,8 +146,8 @@ export abstract class Panel implements IView {
this.renderHeader(this.header); this.renderHeader(this.header);
const focusTracker = trackFocus(this.header); const focusTracker = trackFocus(this.header);
focusTracker.addFocusListener(() => addClass(this.header, 'focused')); focusTracker.onDidFocus(() => addClass(this.header, 'focused'));
focusTracker.addBlurListener(() => removeClass(this.header, 'focused')); focusTracker.onDidBlur(() => removeClass(this.header, 'focused'));
this.updateHeader(); this.updateHeader();
......
...@@ -485,8 +485,8 @@ export class TreeView extends HeightMap { ...@@ -485,8 +485,8 @@ export class TreeView extends HeightMap {
} }
var focusTracker = DOM.trackFocus(this.domNode); var focusTracker = DOM.trackFocus(this.domNode);
focusTracker.addFocusListener(() => this.onFocus()); this.viewListeners.push(focusTracker.onDidFocus(() => this.onFocus()));
focusTracker.addBlurListener(() => this.onBlur()); this.viewListeners.push(focusTracker.onDidBlur(() => this.onBlur()));
this.viewListeners.push(focusTracker); this.viewListeners.push(focusTracker);
this.viewListeners.push(DOM.addDisposableListener(this.domNode, 'keydown', (e) => this.onKeyDown(e))); this.viewListeners.push(DOM.addDisposableListener(this.domNode, 'keydown', (e) => this.onKeyDown(e)));
......
...@@ -468,14 +468,14 @@ class CodeEditorWidgetFocusTracker extends Disposable { ...@@ -468,14 +468,14 @@ class CodeEditorWidgetFocusTracker extends Disposable {
this._hasFocus = false; this._hasFocus = false;
this._domFocusTracker = this._register(dom.trackFocus(domElement)); this._domFocusTracker = this._register(dom.trackFocus(domElement));
this._domFocusTracker.addFocusListener(() => { this._register(this._domFocusTracker.onDidFocus(() => {
this._hasFocus = true; this._hasFocus = true;
this._onChange.fire(void 0); this._onChange.fire(void 0);
}); }));
this._domFocusTracker.addBlurListener(() => { this._register(this._domFocusTracker.onDidBlur(() => {
this._hasFocus = false; this._hasFocus = false;
this._onChange.fire(void 0); this._onChange.fire(void 0);
}); }));
} }
public hasFocus(): boolean { public hasFocus(): boolean {
......
...@@ -193,7 +193,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas ...@@ -193,7 +193,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
})); }));
this._findInputFocused = CONTEXT_FIND_INPUT_FOCUSED.bindTo(contextKeyService); this._findInputFocused = CONTEXT_FIND_INPUT_FOCUSED.bindTo(contextKeyService);
this._focusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement)); this._focusTracker = this._register(dom.trackFocus(this._findInput.inputBox.inputElement));
this._focusTracker.addFocusListener(() => { this._register(this._focusTracker.onDidFocus(() => {
this._findInputFocused.set(true); this._findInputFocused.set(true);
if (this._toggleSelectionFind.checked) { if (this._toggleSelectionFind.checked) {
...@@ -209,10 +209,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas ...@@ -209,10 +209,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
} }
} }
} }
}); }));
this._focusTracker.addBlurListener(() => { this._register(this._focusTracker.onDidBlur(() => {
this._findInputFocused.set(false); this._findInputFocused.set(false);
}); }));
this._codeEditor.addOverlayWidget(this); this._codeEditor.addOverlayWidget(this);
this._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line. this._viewZone = new FindWidgetViewZone(0); // Put it before the first line then users can scroll beyond the first line.
......
...@@ -113,12 +113,12 @@ export abstract class SimpleFindWidget extends Widget { ...@@ -113,12 +113,12 @@ export abstract class SimpleFindWidget extends Widget {
}); });
this._focusTracker = this._register(dom.trackFocus(this._innerDomNode)); this._focusTracker = this._register(dom.trackFocus(this._innerDomNode));
this._register(this._focusTracker.addFocusListener(this.onFocusTrackerFocus.bind(this))); this._register(this._focusTracker.onDidFocus(this.onFocusTrackerFocus.bind(this)));
this._register(this._focusTracker.addBlurListener(this.onFocusTrackerBlur.bind(this))); this._register(this._focusTracker.onDidBlur(this.onFocusTrackerBlur.bind(this)));
this._findInputFocusTracker = this._register(dom.trackFocus(this._findInput.domNode)); this._findInputFocusTracker = this._register(dom.trackFocus(this._findInput.domNode));
this._register(this._findInputFocusTracker.addFocusListener(this.onFindInputFocusTrackerFocus.bind(this))); this._register(this._findInputFocusTracker.onDidFocus(this.onFindInputFocusTrackerFocus.bind(this)));
this._register(this._findInputFocusTracker.addBlurListener(this.onFindInputFocusTrackerBlur.bind(this))); this._register(this._findInputFocusTracker.onDidBlur(this.onFindInputFocusTrackerBlur.bind(this)));
this._register(dom.addDisposableListener(this._innerDomNode, 'click', (event) => { this._register(dom.addDisposableListener(this._innerDomNode, 'click', (event) => {
event.stopPropagation(); event.stopPropagation();
......
...@@ -424,7 +424,9 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro ...@@ -424,7 +424,9 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
// Track focus on editor container // Track focus on editor container
this.visibleEditorFocusTrackers[position] = DOM.trackFocus(editor.getContainer().getHTMLElement()); this.visibleEditorFocusTrackers[position] = DOM.trackFocus(editor.getContainer().getHTMLElement());
this.visibleEditorFocusTrackers[position].addFocusListener(() => {
// TODO@ben: when is this listener disposed?
this.visibleEditorFocusTrackers[position].onDidFocus(() => {
this.onFocusGained(editor); this.onFocusGained(editor);
}); });
} }
......
...@@ -70,7 +70,7 @@ export abstract class ViewletPanel extends Panel { ...@@ -70,7 +70,7 @@ export abstract class ViewletPanel extends Panel {
const focusTracker = trackFocus(container); const focusTracker = trackFocus(container);
this.disposables.push(focusTracker); this.disposables.push(focusTracker);
this.disposables.push(focusTracker.addFocusListener(() => this._onDidFocus.fire())); this.disposables.push(focusTracker.onDidFocus(() => this._onDidFocus.fire()));
} }
protected renderHeader(container: HTMLElement): void { protected renderHeader(container: HTMLElement): void {
......
...@@ -227,9 +227,8 @@ export class MarkersPanel extends Panel { ...@@ -227,9 +227,8 @@ export class MarkersPanel extends Panel {
})); }));
const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement())); const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement()));
focusTracker.addBlurListener(() => { this._register(focusTracker.onDidBlur(() => this.markerFocusContextKey.set(false)));
this.markerFocusContextKey.set(false); this._register(focusTracker);
});
this.toUnbind.push(this.listService.register(this.tree)); this.toUnbind.push(this.listService.register(this.tree));
} }
......
...@@ -132,8 +132,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor ...@@ -132,8 +132,8 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
this.createBody(keybindingsEditorElement); this.createBody(keybindingsEditorElement);
const focusTracker = this._register(DOM.trackFocus(parentElement)); const focusTracker = this._register(DOM.trackFocus(parentElement));
this._register(focusTracker.addFocusListener(() => this.keybindingsEditorContextKey.set(true))); this._register(focusTracker.onDidFocus(() => this.keybindingsEditorContextKey.set(true)));
this._register(focusTracker.addBlurListener(() => this.keybindingsEditorContextKey.reset())); this._register(focusTracker.onDidBlur(() => this.keybindingsEditorContextKey.reset()));
} }
setInput(input: KeybindingsEditorInput): TPromise<void> { setInput(input: KeybindingsEditorInput): TPromise<void> {
......
...@@ -662,7 +662,7 @@ class SideBySidePreferencesWidget extends Widget { ...@@ -662,7 +662,7 @@ class SideBySidePreferencesWidget extends Widget {
})); }));
const focusTracker = this._register(DOM.trackFocus(parentElement)); const focusTracker = this._register(DOM.trackFocus(parentElement));
this._register(focusTracker.addFocusListener(() => this._onFocus.fire())); this._register(focusTracker.onDidFocus(() => this._onFocus.fire()));
} }
public setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options?: EditorOptions): TPromise<{ defaultPreferencesRenderer: IPreferencesRenderer<ISetting>, editablePreferencesRenderer: IPreferencesRenderer<ISetting> }> { public setInput(defaultPreferencesEditorInput: DefaultPreferencesEditorInput, editablePreferencesEditorInput: EditorInput, options?: EditorOptions): TPromise<{ defaultPreferencesRenderer: IPreferencesRenderer<ISetting>, editablePreferencesRenderer: IPreferencesRenderer<ISetting> }> {
......
...@@ -179,8 +179,9 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone { ...@@ -179,8 +179,9 @@ export class SettingsGroupTitleWidget extends Widget implements IViewZone {
this.onclick(this.titleContainer, () => this.toggle()); this.onclick(this.titleContainer, () => this.toggle());
this.onkeydown(this.titleContainer, (e) => this.onKeyDown(e)); this.onkeydown(this.titleContainer, (e) => this.onKeyDown(e));
const focusTracker = this._register(DOM.trackFocus(this.titleContainer)); const focusTracker = this._register(DOM.trackFocus(this.titleContainer));
focusTracker.addFocusListener(() => this.toggleFocus(true));
focusTracker.addBlurListener(() => this.toggleFocus(false)); this._register(focusTracker.onDidFocus(() => this.toggleFocus(true)));
this._register(focusTracker.onDidBlur(() => this.toggleFocus(false)));
this.icon = DOM.append(this.titleContainer, DOM.$('.expand-collapse-icon')); this.icon = DOM.append(this.titleContainer, DOM.$('.expand-collapse-icon'));
this.title = DOM.append(this.titleContainer, DOM.$('.title')); this.title = DOM.append(this.titleContainer, DOM.$('.title'));
...@@ -499,11 +500,11 @@ export class SearchWidget extends Widget { ...@@ -499,11 +500,11 @@ export class SearchWidget extends Widget {
this.inputBox.inputElement.setAttribute('aria-live', 'assertive'); this.inputBox.inputElement.setAttribute('aria-live', 'assertive');
const focusTracker = this._register(DOM.trackFocus(this.inputBox.inputElement)); const focusTracker = this._register(DOM.trackFocus(this.inputBox.inputElement));
this._register(focusTracker.addFocusListener(() => this._onFocus.fire())); this._register(focusTracker.onDidFocus(() => this._onFocus.fire()));
if (this.options.focusKey) { if (this.options.focusKey) {
this._register(focusTracker.addFocusListener(() => this.options.focusKey.set(true))); this._register(focusTracker.onDidFocus(() => this.options.focusKey.set(true)));
this._register(focusTracker.addBlurListener(() => this.options.focusKey.set(false))); this._register(focusTracker.onDidBlur(() => this.options.focusKey.set(false)));
} }
} }
......
...@@ -561,7 +561,7 @@ export class RepositoryPanel extends ViewletPanel { ...@@ -561,7 +561,7 @@ export class RepositoryPanel extends ViewletPanel {
protected renderBody(container: HTMLElement): void { protected renderBody(container: HTMLElement): void {
const focusTracker = trackFocus(container); const focusTracker = trackFocus(container);
this.disposables.push(focusTracker.addFocusListener(() => this.repository.focus())); this.disposables.push(focusTracker.onDidFocus(() => this.repository.focus()));
this.disposables.push(focusTracker); this.disposables.push(focusTracker);
// Input // Input
......
...@@ -317,13 +317,13 @@ export class SearchViewlet extends Viewlet { ...@@ -317,13 +317,13 @@ export class SearchViewlet extends Viewlet {
} }
private trackInputBox(inputFocusTracker: dom.IFocusTracker, contextKey?: IContextKey<boolean>): void { private trackInputBox(inputFocusTracker: dom.IFocusTracker, contextKey?: IContextKey<boolean>): void {
this.toUnbind.push(inputFocusTracker.addFocusListener(() => { this.toUnbind.push(inputFocusTracker.onDidFocus(() => {
this.inputBoxFocused.set(true); this.inputBoxFocused.set(true);
if (contextKey) { if (contextKey) {
contextKey.set(true); contextKey.set(true);
} }
})); }));
this.toUnbind.push(inputFocusTracker.addBlurListener(() => { this.toUnbind.push(inputFocusTracker.onDidBlur(() => {
this.inputBoxFocused.set(this.searchWidget.searchInputHasFocus() this.inputBoxFocused.set(this.searchWidget.searchInputHasFocus()
|| this.searchWidget.replaceInputHasFocus() || this.searchWidget.replaceInputHasFocus()
|| this.inputPatternIncludes.inputHasFocus() || this.inputPatternIncludes.inputHasFocus()
......
...@@ -241,12 +241,8 @@ export class SearchWidget extends Widget { ...@@ -241,12 +241,8 @@ export class SearchWidget extends Widget {
})); }));
this.searchInputFocusTracker = this._register(dom.trackFocus(this.searchInput.inputBox.inputElement)); this.searchInputFocusTracker = this._register(dom.trackFocus(this.searchInput.inputBox.inputElement));
this._register(this.searchInputFocusTracker.addFocusListener(() => { this._register(this.searchInputFocusTracker.onDidFocus(() => this.searchInputBoxFocused.set(true)));
this.searchInputBoxFocused.set(true); this._register(this.searchInputFocusTracker.onDidBlur(() => this.searchInputBoxFocused.set(false)));
}));
this._register(this.searchInputFocusTracker.addBlurListener(() => {
this.searchInputBoxFocused.set(false);
}));
} }
private renderReplaceInput(parent: HTMLElement): void { private renderReplaceInput(parent: HTMLElement): void {
...@@ -268,12 +264,8 @@ export class SearchWidget extends Widget { ...@@ -268,12 +264,8 @@ export class SearchWidget extends Widget {
this.replaceActionBar.push([this.replaceAllAction], { icon: true, label: false }); this.replaceActionBar.push([this.replaceAllAction], { icon: true, label: false });
this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputElement)); this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputElement));
this._register(this.replaceInputFocusTracker.addFocusListener(() => { this._register(this.replaceInputFocusTracker.onDidFocus(() => this.replaceInputBoxFocused.set(true)));
this.replaceInputBoxFocused.set(true); this._register(this.replaceInputFocusTracker.onDidBlur(() => this.replaceInputBoxFocused.set(false)));
}));
this._register(this.replaceInputFocusTracker.addBlurListener(() => {
this.replaceInputBoxFocused.set(false);
}));
} }
triggerReplaceAll(): TPromise<any> { triggerReplaceAll(): TPromise<any> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册