Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -77,14 +77,6 @@
background-image: url('expanded.svg');
}
.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children.selected.expanded > .content:before {
background-image: url('expanded-hc.svg');
}
.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children.selected > .content:before {
background-image: url('collapsed-hc.svg');
}
.monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before {
background-image: url('loading.svg');
}

View File

@@ -6,7 +6,6 @@
import WinJS = require('vs/base/common/winjs.base');
import Touch = require('vs/base/browser/touch');
import Events = require('vs/base/common/eventEmitter');
import Mouse = require('vs/base/browser/mouseEvent');
import Keyboard = require('vs/base/browser/keyboardEvent');
import { INavigator } from 'vs/base/common/iterator';
@@ -14,15 +13,18 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import Event from 'vs/base/common/event';
import { IAction, IActionItem } from 'vs/base/common/actions';
import { Color } from 'vs/base/common/color';
import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel';
export interface ITree extends Events.IEventEmitter {
export interface ITree {
emit(eventType: string, data?: any): void;
onDOMFocus: Event<void>;
onDOMBlur: Event<void>;
onHighlightChange: Event<void>;
onDispose: Event<void>;
onDidFocus: Event<void>;
onDidBlur: Event<void>;
onDidChangeFocus: Event<IFocusEvent>;
onDidChangeSelection: Event<ISelectionEvent>;
onDidChangeHighlight: Event<IHighlightEvent>;
onDidExpandItem: Event<IItemExpandEvent>;
onDidCollapseItem: Event<IItemCollapseEvent>;
onDidDispose: Event<void>;
/**
* Returns the tree's DOM element.
@@ -101,6 +103,13 @@ export interface ITree extends Events.IEventEmitter {
*/
collapseAll(elements?: any[], recursive?: boolean): WinJS.Promise;
/**
* Collapses several elements.
* Collapses all elements at the greatest tree depth that has expanded elements.
* The returned promise returns a boolean for whether the elements were collapsed or not.
*/
collapseDeepestExpandedLevel(): WinJS.Promise;
/**
* Toggles an element's expansion state.
*/

View File

@@ -7,15 +7,15 @@
import 'vs/css!./tree';
import WinJS = require('vs/base/common/winjs.base');
import TreeDefaults = require('vs/base/parts/tree/browser/treeDefaults');
import Events = require('vs/base/common/eventEmitter');
import Model = require('vs/base/parts/tree/browser/treeModel');
import View = require('./treeView');
import _ = require('vs/base/parts/tree/browser/tree');
import { INavigator, MappedNavigator } from 'vs/base/common/iterator';
import Event, { Emitter } from 'vs/base/common/event';
import Lifecycle = require('vs/base/common/lifecycle');
import Event, { Emitter, Relay } from 'vs/base/common/event';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
import { ISelectionEvent, IFocusEvent, IHighlightEvent } from 'vs/base/parts/tree/browser/tree';
import { IItemCollapseEvent, IItemExpandEvent } from 'vs/base/parts/tree/browser/treeModel';
export class TreeContext implements _.ITreeContext {
@@ -61,42 +61,37 @@ const defaultStyles: _.ITreeStyles = {
listDropBackground: Color.fromHex('#383B3D')
};
export class Tree extends Events.EventEmitter implements _.ITree {
export class Tree implements _.ITree {
private container: HTMLElement;
private configuration: _.ITreeConfiguration;
private options: _.ITreeOptions;
private context: _.ITreeContext;
private model: Model.TreeModel;
private view: View.TreeView;
private _onDispose: Emitter<void>;
private _onHighlightChange: Emitter<void>;
private toDispose: Lifecycle.IDisposable[];
private _onDidChangeFocus = new Relay<IFocusEvent>();
readonly onDidChangeFocus: Event<IFocusEvent> = this._onDidChangeFocus.event;
private _onDidChangeSelection = new Relay<ISelectionEvent>();
readonly onDidChangeSelection: Event<ISelectionEvent> = this._onDidChangeSelection.event;
private _onHighlightChange = new Relay<IHighlightEvent>();
readonly onDidChangeHighlight: Event<IHighlightEvent> = this._onHighlightChange.event;
private _onDidExpandItem = new Relay<IItemExpandEvent>();
readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event;
private _onDidCollapseItem = new Relay<IItemCollapseEvent>();
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
private _onDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDispose.event;
constructor(container: HTMLElement, configuration: _.ITreeConfiguration, options: _.ITreeOptions = {}) {
super();
this.toDispose = [];
this._onDispose = new Emitter<void>();
this._onHighlightChange = new Emitter<void>();
this.toDispose.push(this._onDispose, this._onHighlightChange);
this.container = container;
this.configuration = configuration;
this.options = options;
mixin(this.options, defaultStyles, false);
mixin(options, defaultStyles, false);
this.options.twistiePixels = typeof this.options.twistiePixels === 'number' ? this.options.twistiePixels : 32;
this.options.showTwistie = this.options.showTwistie === false ? false : true;
this.options.indentPixels = typeof this.options.indentPixels === 'number' ? this.options.indentPixels : 12;
this.options.alwaysFocused = this.options.alwaysFocused === true ? true : false;
this.options.useShadows = this.options.useShadows === false ? false : true;
this.options.paddingOnRow = this.options.paddingOnRow === false ? false : true;
options.twistiePixels = typeof options.twistiePixels === 'number' ? options.twistiePixels : 32;
options.showTwistie = options.showTwistie === false ? false : true;
options.indentPixels = typeof options.indentPixels === 'number' ? options.indentPixels : 12;
options.alwaysFocused = options.alwaysFocused === true ? true : false;
options.useShadows = options.useShadows === false ? false : true;
options.paddingOnRow = options.paddingOnRow === false ? false : true;
this.context = new TreeContext(this, configuration, options);
this.model = new Model.TreeModel(this.context);
@@ -104,32 +99,25 @@ export class Tree extends Events.EventEmitter implements _.ITree {
this.view.setModel(this.model);
this.addEmitter(this.model);
this.addEmitter(this.view);
this.toDispose.push(this.model.addListener('highlight', () => this._onHighlightChange.fire()));
this._onDidChangeFocus.input = this.model.onDidFocus;
this._onDidChangeSelection.input = this.model.onDidSelect;
this._onHighlightChange.input = this.model.onDidHighlight;
this._onDidExpandItem.input = this.model.onDidExpandItem;
this._onDidCollapseItem.input = this.model.onDidCollapseItem;
}
public style(styles: _.ITreeStyles): void {
this.view.applyStyles(styles);
}
get onDOMFocus(): Event<void> {
get onDidFocus(): Event<void> {
return this.view && this.view.onDOMFocus;
}
get onDOMBlur(): Event<void> {
get onDidBlur(): Event<void> {
return this.view && this.view.onDOMBlur;
}
get onHighlightChange(): Event<void> {
return this._onHighlightChange && this._onHighlightChange.event;
}
get onDispose(): Event<void> {
return this._onDispose && this._onDispose.event;
}
public getHTMLElement(): HTMLElement {
return this.view.getHTMLElement();
}
@@ -186,6 +174,10 @@ export class Tree extends Events.EventEmitter implements _.ITree {
return this.model.collapseAll(elements, recursive);
}
public collapseDeepestExpandedLevel(): WinJS.Promise {
return this.model.collapseDeepestExpandedLevel();
}
public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise {
return this.model.toggleExpansion(element, recursive);
}
@@ -380,8 +372,11 @@ export class Tree extends Events.EventEmitter implements _.ITree {
this.view = null;
}
this.toDispose = Lifecycle.dispose(this.toDispose);
super.dispose();
this._onDidChangeFocus.dispose();
this._onDidChangeSelection.dispose();
this._onHighlightChange.dispose();
this._onDidExpandItem.dispose();
this._onDidCollapseItem.dispose();
this._onDispose.dispose();
}
}

View File

@@ -9,31 +9,34 @@ import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import arrays = require('vs/base/common/arrays');
import { INavigator } from 'vs/base/common/iterator';
import Events = require('vs/base/common/eventEmitter');
import WinJS = require('vs/base/common/winjs.base');
import _ = require('./tree');
import Event, { Emitter, once, EventMultiplexer, Relay } from 'vs/base/common/event';
interface IMap<T> { [id: string]: T; }
interface IItemMap extends IMap<Item> { }
interface ITraitMap extends IMap<IItemMap> { }
export class LockData extends Events.EventEmitter {
export class LockData {
private _item: Item;
private _onDispose = new Emitter<void>();
readonly onDispose: Event<void> = this._onDispose.event;
constructor(item: Item) {
super();
this._item = item;
}
public get item(): Item {
get item(): Item {
return this._item;
}
public dispose(): void {
this.emit('unlock');
super.dispose();
dispose(): void {
if (this._onDispose) {
this._onDispose.fire();
this._onDispose.dispose();
this._onDispose = null;
}
}
}
@@ -84,7 +87,7 @@ export class Lock {
var unbindListener: IDisposable;
return new WinJS.TPromise((c, e) => {
unbindListener = lock.addOneTimeListener('unlock', () => {
unbindListener = once(lock.onDispose)(() => {
return this.run(item, fn).then(c, e);
});
}, () => { unbindListener.dispose(); });
@@ -126,19 +129,56 @@ export class Lock {
}
}
export class ItemRegistry extends Events.EventEmitter {
export class ItemRegistry {
private _isDisposed = false;
private items: IMap<{ item: Item; disposable: IDisposable; }>;
private _onDidRevealItem = new EventMultiplexer<IItemRevealEvent>();
readonly onDidRevealItem: Event<IItemRevealEvent> = this._onDidRevealItem.event;
private _onExpandItem = new EventMultiplexer<IItemExpandEvent>();
readonly onExpandItem: Event<IItemExpandEvent> = this._onExpandItem.event;
private _onDidExpandItem = new EventMultiplexer<IItemExpandEvent>();
readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event;
private _onCollapseItem = new EventMultiplexer<IItemCollapseEvent>();
readonly onCollapseItem: Event<IItemCollapseEvent> = this._onCollapseItem.event;
private _onDidCollapseItem = new EventMultiplexer<IItemCollapseEvent>();
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
private _onDidAddTraitItem = new EventMultiplexer<IItemTraitEvent>();
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
private _onDidRemoveTraitItem = new EventMultiplexer<IItemCollapseEvent>();
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
private _onDidRefreshItem = new EventMultiplexer<Item>();
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
private _onRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>();
readonly onRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshItemChildren.event;
private _onDidRefreshItemChildren = new EventMultiplexer<IItemChildrenRefreshEvent>();
readonly onDidRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshItemChildren.event;
private _onDidDisposeItem = new EventMultiplexer<Item>();
readonly onDidDisposeItem: Event<Item> = this._onDidDisposeItem.event;
constructor() {
super();
this.items = {};
}
public register(item: Item): void {
Assert.ok(!this.isRegistered(item.id), 'item already registered: ' + item.id);
this.items[item.id] = { item, disposable: this.addEmitter(item) };
const disposable = combinedDisposable([
this._onDidRevealItem.add(item.onDidReveal),
this._onExpandItem.add(item.onExpand),
this._onDidExpandItem.add(item.onDidExpand),
this._onCollapseItem.add(item.onCollapse),
this._onDidCollapseItem.add(item.onDidCollapse),
this._onDidAddTraitItem.add(item.onDidAddTrait),
this._onDidRemoveTraitItem.add(item.onDidRemoveTrait),
this._onDidRefreshItem.add(item.onDidRefresh),
this._onRefreshItemChildren.add(item.onRefreshChildren),
this._onDidRefreshItemChildren.add(item.onDidRefreshChildren),
this._onDidDisposeItem.add(item.onDidDispose)
]);
this.items[item.id] = { item, disposable };
}
public deregister(item: Item): void {
@@ -157,8 +197,19 @@ export class ItemRegistry extends Events.EventEmitter {
}
public dispose(): void {
super.dispose();
this.items = null;
this._onDidRevealItem.dispose();
this._onExpandItem.dispose();
this._onDidExpandItem.dispose();
this._onCollapseItem.dispose();
this._onDidCollapseItem.dispose();
this._onDidAddTraitItem.dispose();
this._onDidRemoveTraitItem.dispose();
this._onDidRefreshItem.dispose();
this._onRefreshItemChildren.dispose();
this._onDidRefreshItemChildren.dispose();
this._isDisposed = true;
}
@@ -174,7 +225,6 @@ export interface IBaseItemEvent {
export interface IItemRefreshEvent extends IBaseItemEvent { }
export interface IItemExpandEvent extends IBaseItemEvent { }
export interface IItemCollapseEvent extends IBaseItemEvent { }
export interface IItemDisposeEvent extends IBaseItemEvent { }
export interface IItemTraitEvent extends IBaseItemEvent {
trait: string;
@@ -188,7 +238,7 @@ export interface IItemChildrenRefreshEvent extends IBaseItemEvent {
isNested: boolean;
}
export class Item extends Events.EventEmitter {
export class Item {
private registry: ItemRegistry;
private context: _.ITreeContext;
@@ -206,8 +256,6 @@ export class Item extends Events.EventEmitter {
public firstChild: Item;
public lastChild: Item;
private userContent: HTMLElement;
private height: number;
private depth: number;
@@ -216,11 +264,34 @@ export class Item extends Events.EventEmitter {
private traits: { [trait: string]: boolean; };
private _onDidCreate = new Emitter<Item>();
readonly onDidCreate: Event<Item> = this._onDidCreate.event;
private _onDidReveal = new Emitter<IItemRevealEvent>();
readonly onDidReveal: Event<IItemRevealEvent> = this._onDidReveal.event;
private _onExpand = new Emitter<IItemExpandEvent>();
readonly onExpand: Event<IItemExpandEvent> = this._onExpand.event;
private _onDidExpand = new Emitter<IItemExpandEvent>();
readonly onDidExpand: Event<IItemExpandEvent> = this._onDidExpand.event;
private _onCollapse = new Emitter<IItemCollapseEvent>();
readonly onCollapse: Event<IItemCollapseEvent> = this._onCollapse.event;
private _onDidCollapse = new Emitter<IItemCollapseEvent>();
readonly onDidCollapse: Event<IItemCollapseEvent> = this._onDidCollapse.event;
private _onDidAddTrait = new Emitter<IItemTraitEvent>();
readonly onDidAddTrait: Event<IItemTraitEvent> = this._onDidAddTrait.event;
private _onDidRemoveTrait = new Emitter<IItemCollapseEvent>();
readonly onDidRemoveTrait: Event<IItemCollapseEvent> = this._onDidRemoveTrait.event;
private _onDidRefresh = new Emitter<Item>();
readonly onDidRefresh: Event<Item> = this._onDidRefresh.event;
private _onRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
readonly onRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshChildren.event;
private _onDidRefreshChildren = new Emitter<IItemChildrenRefreshEvent>();
readonly onDidRefreshChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshChildren.event;
private _onDidDispose = new Emitter<Item>();
readonly onDidDispose: Event<Item> = this._onDidDispose.event;
private _isDisposed: boolean;
constructor(id: string, registry: ItemRegistry, context: _.ITreeContext, lock: Lock, element: any) {
super();
this.registry = registry;
this.context = context;
this.lock = lock;
@@ -238,12 +309,11 @@ export class Item extends Events.EventEmitter {
this.firstChild = null;
this.lastChild = null;
this.userContent = null;
this.traits = {};
this.depth = 0;
this.expanded = this.context.dataSource.shouldAutoexpand && this.context.dataSource.shouldAutoexpand(this.context.tree, element);
this.emit('item:create', { item: this });
this._onDidCreate.fire(this);
this.visible = this._isVisible();
this.height = this._getHeight();
@@ -281,7 +351,7 @@ export class Item extends Events.EventEmitter {
public reveal(relativeTop: number = null): void {
var eventData: IItemRevealEvent = { item: this, relativeTop: relativeTop };
this.emit('item:reveal', eventData);
this._onDidReveal.fire(eventData);
}
public expand(): WinJS.Promise {
@@ -292,7 +362,7 @@ export class Item extends Events.EventEmitter {
var result = this.lock.run(this, () => {
var eventData: IItemExpandEvent = { item: this };
var result: WinJS.Promise;
this.emit('item:expanding', eventData);
this._onExpand.fire(eventData);
if (this.needsChildrenRefresh) {
result = this.refreshChildren(false, true, true);
@@ -302,7 +372,7 @@ export class Item extends Events.EventEmitter {
return result.then(() => {
this._setExpanded(true);
this.emit('item:expanded', eventData);
this._onDidExpand.fire(eventData);
return true;
});
});
@@ -337,9 +407,9 @@ export class Item extends Events.EventEmitter {
return this.lock.run(this, () => {
var eventData: IItemCollapseEvent = { item: this };
this.emit('item:collapsing', eventData);
this._onCollapse.fire(eventData);
this._setExpanded(false);
this.emit('item:collapsed', eventData);
this._onDidCollapse.fire(eventData);
return WinJS.TPromise.as(true);
});
@@ -349,13 +419,13 @@ export class Item extends Events.EventEmitter {
public addTrait(trait: string): void {
var eventData: IItemTraitEvent = { item: this, trait: trait };
this.traits[trait] = true;
this.emit('item:addTrait', eventData);
this._onDidAddTrait.fire(eventData);
}
public removeTrait(trait: string): void {
var eventData: IItemTraitEvent = { item: this, trait: trait };
delete this.traits[trait];
this.emit('item:removeTrait', eventData);
this._onDidRemoveTrait.fire(eventData);
}
public hasTrait(trait: string): boolean {
@@ -387,7 +457,7 @@ export class Item extends Events.EventEmitter {
var doRefresh = () => {
var eventData: IItemChildrenRefreshEvent = { item: this, isNested: safe };
this.emit('item:childrenRefreshing', eventData);
this._onRefreshChildren.fire(eventData);
var childrenPromise: WinJS.Promise;
if (this.doesHaveChildren) {
@@ -443,20 +513,18 @@ export class Item extends Events.EventEmitter {
return result
.then(null, onUnexpectedError)
.then(() => this.emit('item:childrenRefreshed', eventData));
.then(() => this._onDidRefreshChildren.fire(eventData));
};
return safe ? doRefresh() : this.lock.run(this, doRefresh);
}
private doRefresh(recursive: boolean, safe: boolean = false): WinJS.Promise {
var eventData: IItemRefreshEvent = { item: this };
this.doesHaveChildren = this.context.dataSource.hasChildren(this.context.tree, this.element);
this.height = this._getHeight();
this.setVisible(this._isVisible());
this.emit('item:refresh', eventData);
this._onDidRefresh.fire(this);
return this.refreshChildren(recursive, safe);
}
@@ -486,6 +554,17 @@ export class Item extends Events.EventEmitter {
return result;
}
public getChildren(): Item[] {
var child = this.firstChild;
var results = [];
while (child) {
results.push(child);
child = child.next;
}
return results;
}
private isAncestorOf(item: Item): boolean {
while (item) {
if (item.id === this.id) {
@@ -594,11 +673,22 @@ export class Item extends Events.EventEmitter {
this.firstChild = null;
this.lastChild = null;
var eventData: IItemDisposeEvent = { item: this };
this.emit('item:dispose', eventData);
this._onDidDispose.fire(this);
this.registry.deregister(this);
super.dispose();
this._onDidCreate.dispose();
this._onDidReveal.dispose();
this._onExpand.dispose();
this._onDidExpand.dispose();
this._onCollapse.dispose();
this._onDidCollapse.dispose();
this._onDidAddTrait.dispose();
this._onDidRemoveTrait.dispose();
this._onDidRefresh.dispose();
this._onRefreshChildren.dispose();
this._onDidRefreshChildren.dispose();
this._onDidDispose.dispose();
this._isDisposed = true;
}
@@ -647,13 +737,21 @@ export class TreeNavigator implements INavigator<Item> {
static lastDescendantOf(item: Item): Item {
if (!item) {
return null;
} else {
if (!(item instanceof RootItem) && (!item.isVisible() || !item.isExpanded() || item.lastChild === null)) {
return item;
} else {
return TreeNavigator.lastDescendantOf(item.lastChild);
}
}
if (item instanceof RootItem) {
return TreeNavigator.lastDescendantOf(item.lastChild);
}
if (!item.isVisible()) {
return TreeNavigator.lastDescendantOf(item.previous);
}
if (!item.isExpanded() || item.lastChild === null) {
return item;
}
return TreeNavigator.lastDescendantOf(item.lastChild);
}
constructor(item: Item, subTreeOnly: boolean = true) {
@@ -772,7 +870,7 @@ export interface IRefreshEvent extends IBaseEvent {
recursive: boolean;
}
export class TreeModel extends Events.EventEmitter {
export class TreeModel {
private context: _.ITreeContext;
private lock: Lock;
@@ -781,9 +879,45 @@ export class TreeModel extends Events.EventEmitter {
private registryDisposable: IDisposable;
private traitsToItems: ITraitMap;
constructor(context: _.ITreeContext) {
super();
private _onSetInput = new Emitter<IInputEvent>();
readonly onSetInput: Event<IInputEvent> = this._onSetInput.event;
private _onDidSetInput = new Emitter<IInputEvent>();
readonly onDidSetInput: Event<IInputEvent> = this._onDidSetInput.event;
private _onRefresh = new Emitter<IRefreshEvent>();
readonly onRefresh: Event<IRefreshEvent> = this._onRefresh.event;
private _onDidRefresh = new Emitter<IRefreshEvent>();
readonly onDidRefresh: Event<IRefreshEvent> = this._onDidRefresh.event;
private _onDidHighlight = new Emitter<_.IHighlightEvent>();
readonly onDidHighlight: Event<_.IHighlightEvent> = this._onDidHighlight.event;
private _onDidSelect = new Emitter<_.ISelectionEvent>();
readonly onDidSelect: Event<_.ISelectionEvent> = this._onDidSelect.event;
private _onDidFocus = new Emitter<_.IFocusEvent>();
readonly onDidFocus: Event<_.IFocusEvent> = this._onDidFocus.event;
private _onDidRevealItem = new Relay<IItemRevealEvent>();
readonly onDidRevealItem: Event<IItemRevealEvent> = this._onDidRevealItem.event;
private _onExpandItem = new Relay<IItemExpandEvent>();
readonly onExpandItem: Event<IItemExpandEvent> = this._onExpandItem.event;
private _onDidExpandItem = new Relay<IItemExpandEvent>();
readonly onDidExpandItem: Event<IItemExpandEvent> = this._onDidExpandItem.event;
private _onCollapseItem = new Relay<IItemCollapseEvent>();
readonly onCollapseItem: Event<IItemCollapseEvent> = this._onCollapseItem.event;
private _onDidCollapseItem = new Relay<IItemCollapseEvent>();
readonly onDidCollapseItem: Event<IItemCollapseEvent> = this._onDidCollapseItem.event;
private _onDidAddTraitItem = new Relay<IItemTraitEvent>();
readonly onDidAddTraitItem: Event<IItemTraitEvent> = this._onDidAddTraitItem.event;
private _onDidRemoveTraitItem = new Relay<IItemCollapseEvent>();
readonly onDidRemoveTraitItem: Event<IItemCollapseEvent> = this._onDidRemoveTraitItem.event;
private _onDidRefreshItem = new Relay<Item>();
readonly onDidRefreshItem: Event<Item> = this._onDidRefreshItem.event;
private _onRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
readonly onRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onRefreshItemChildren.event;
private _onDidRefreshItemChildren = new Relay<IItemChildrenRefreshEvent>();
readonly onDidRefreshItemChildren: Event<IItemChildrenRefreshEvent> = this._onDidRefreshItemChildren.event;
private _onDidDisposeItem = new Relay<Item>();
readonly onDidDisposeItem: Event<Item> = this._onDidDisposeItem.event;
constructor(context: _.ITreeContext) {
this.context = context;
this.input = null;
this.traitsToItems = {};
@@ -791,7 +925,7 @@ export class TreeModel extends Events.EventEmitter {
public setInput(element: any): WinJS.Promise {
var eventData: IInputEvent = { item: this.input };
this.emit('clearingInput', eventData);
this._onSetInput.fire(eventData);
this.setSelection([]);
this.setFocus();
@@ -810,18 +944,25 @@ export class TreeModel extends Events.EventEmitter {
this.registry = new ItemRegistry();
this.registryDisposable = combinedDisposable([
this.addEmitter(this.registry),
this.registry.addListener('item:dispose', (event: IItemDisposeEvent) => {
event.item.getAllTraits()
.forEach(trait => delete this.traitsToItems[trait][event.item.id]);
})
]);
this._onDidRevealItem.input = this.registry.onDidRevealItem;
this._onExpandItem.input = this.registry.onExpandItem;
this._onDidExpandItem.input = this.registry.onDidExpandItem;
this._onCollapseItem.input = this.registry.onCollapseItem;
this._onDidCollapseItem.input = this.registry.onDidCollapseItem;
this._onDidAddTraitItem.input = this.registry.onDidAddTraitItem;
this._onDidRemoveTraitItem.input = this.registry.onDidRemoveTraitItem;
this._onDidRefreshItem.input = this.registry.onDidRefreshItem;
this._onRefreshItemChildren.input = this.registry.onRefreshItemChildren;
this._onDidRefreshItemChildren.input = this.registry.onDidRefreshItemChildren;
this._onDidDisposeItem.input = this.registry.onDidDisposeItem;
this.registryDisposable = this.registry
.onDidDisposeItem(item => item.getAllTraits().forEach(trait => delete this.traitsToItems[trait][item.id]));
var id = this.context.dataSource.getId(this.context.tree, element);
this.input = new RootItem(id, this.registry, this.context, this.lock, element);
eventData = { item: this.input };
this.emit('setInput', eventData);
this._onDidSetInput.fire(eventData);
return this.refresh(this.input);
}
@@ -837,9 +978,9 @@ export class TreeModel extends Events.EventEmitter {
}
var eventData: IRefreshEvent = { item: item, recursive: recursive };
this.emit('refreshing', eventData);
this._onRefresh.fire(eventData);
return item.refresh(recursive).then(() => {
this.emit('refreshed', eventData);
this._onDidRefresh.fire(eventData);
});
}
@@ -894,6 +1035,27 @@ export class TreeModel extends Events.EventEmitter {
return WinJS.Promise.join(promises);
}
public collapseDeepestExpandedLevel(): WinJS.Promise {
var levelToCollapse = this.findDeepestExpandedLevel(this.input, 0);
var items = [this.input];
for (var i = 0; i < levelToCollapse; i++) {
items = arrays.flatten(items.map(node => node.getChildren()));
}
var promises = items.map(child => this.collapse(child, false));
return WinJS.Promise.join(promises);
}
private findDeepestExpandedLevel(item: Item, currentLevel: number): number {
var expandedChildren = item.getChildren().filter(child => child.isExpanded());
if (!expandedChildren.length) {
return currentLevel;
}
return Math.max(...expandedChildren.map(child => this.findDeepestExpandedLevel(child, currentLevel + 1)));
}
public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise {
return this.isExpanded(element) ? this.collapse(element, recursive) : this.expand(element);
}
@@ -964,7 +1126,7 @@ export class TreeModel extends Events.EventEmitter {
public setHighlight(element?: any, eventPayload?: any): void {
this.setTraits('highlighted', element ? [element] : []);
var eventData: _.IHighlightEvent = { highlight: this.getHighlight(), payload: eventPayload };
this.emit('highlight', eventData);
this._onDidHighlight.fire(eventData);
}
public getHighlight(includeHidden?: boolean): any {
@@ -1011,7 +1173,7 @@ export class TreeModel extends Events.EventEmitter {
public selectAll(elements: any[], eventPayload?: any): void {
this.addTraits('selected', elements);
var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
this.emit('selection', eventData);
this._onDidSelect.fire(eventData);
}
public deselect(element: any, eventPayload?: any): void {
@@ -1021,19 +1183,19 @@ export class TreeModel extends Events.EventEmitter {
public deselectAll(elements: any[], eventPayload?: any): void {
this.removeTraits('selected', elements);
var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
this.emit('selection', eventData);
this._onDidSelect.fire(eventData);
}
public setSelection(elements: any[], eventPayload?: any): void {
this.setTraits('selected', elements);
var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
this.emit('selection', eventData);
this._onDidSelect.fire(eventData);
}
public toggleSelection(element: any, eventPayload?: any): void {
this.toggleTrait('selected', element);
var eventData: _.ISelectionEvent = { selection: this.getSelection(), payload: eventPayload };
this.emit('selection', eventData);
this._onDidSelect.fire(eventData);
}
public isSelected(element: any): boolean {
@@ -1077,7 +1239,7 @@ export class TreeModel extends Events.EventEmitter {
previousItem: Item = null;
if (selection.length === 0) {
var nav = this.getNavigator(this.input);
let nav = this.getNavigator(this.input);
while (item = nav.next()) {
previousItem = item;
@@ -1087,7 +1249,7 @@ export class TreeModel extends Events.EventEmitter {
} else {
item = selection[0];
var nav = this.getNavigator(item, false);
let nav = this.getNavigator(item, false);
for (var i = 0; i < count; i++) {
previousItem = nav.previous();
@@ -1123,7 +1285,7 @@ export class TreeModel extends Events.EventEmitter {
public setFocus(element?: any, eventPayload?: any): void {
this.setTraits('focused', element ? [element] : []);
var eventData: _.IFocusEvent = { focus: this.getFocus(), payload: eventPayload };
this.emit('focus', eventData);
this._onDidFocus.fire(eventData);
}
public isFocused(element: any): boolean {
@@ -1320,7 +1482,7 @@ export class TreeModel extends Events.EventEmitter {
var items: { [id: string]: Item; } = {};
var item: Item;
for (var i = 0, len = elements.length; i < len; i++) {
for (let i = 0, len = elements.length; i < len; i++) {
item = this.getItem(elements[i]);
if (item) {
@@ -1342,7 +1504,7 @@ export class TreeModel extends Events.EventEmitter {
}
}
for (var i = 0, len = itemsToRemoveTrait.length; i < len; i++) {
for (let i = 0, len = itemsToRemoveTrait.length; i < len; i++) {
item = itemsToRemoveTrait[i];
item.removeTrait(trait);
delete traitItems[item.id];
@@ -1378,6 +1540,23 @@ export class TreeModel extends Events.EventEmitter {
this.registry = null;
}
super.dispose();
this._onSetInput.dispose();
this._onDidSetInput.dispose();
this._onRefresh.dispose();
this._onDidRefresh.dispose();
this._onDidHighlight.dispose();
this._onDidSelect.dispose();
this._onDidFocus.dispose();
this._onDidRevealItem.dispose();
this._onExpandItem.dispose();
this._onDidExpandItem.dispose();
this._onCollapseItem.dispose();
this._onDidCollapseItem.dispose();
this._onDidAddTraitItem.dispose();
this._onDidRemoveTraitItem.dispose();
this._onDidRefreshItem.dispose();
this._onRefreshItemChildren.dispose();
this._onDidRefreshItemChildren.dispose();
this._onDidDisposeItem.dispose();
}
}

View File

@@ -23,7 +23,7 @@ import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
import _ = require('vs/base/parts/tree/browser/tree');
import { KeyCode } from 'vs/base/common/keyCodes';
import Event, { Emitter } from 'vs/base/common/event';
import { EmitterEvent } from 'vs/base/common/eventEmitter';
import { IDomNodePagePosition } from 'vs/base/browser/dom';
export interface IRow {
element: HTMLElement;
@@ -379,7 +379,6 @@ export class TreeView extends HeightMap {
private styleElement: HTMLStyleElement;
private rowsContainer: HTMLElement;
private scrollableElement: ScrollableElement;
private wrapperGesture: Touch.Gesture;
private msGesture: MSGesture;
private lastPointerType: string;
private lastClickTimeStamp: number = 0;
@@ -392,8 +391,6 @@ export class TreeView extends HeightMap {
private isRefreshing = false;
private refreshingPreviousChildrenIds: { [id: string]: string[] } = {};
private dragAndDropListeners: { (): void; }[];
private currentDragAndDropData: _.IDragAndDropData;
private currentDropElement: any;
private currentDropElementReaction: _.IDragOverReaction;
@@ -437,7 +434,6 @@ export class TreeView extends HeightMap {
this.modelListeners = [];
this.viewListeners = [];
this.dragAndDropListeners = [];
this.model = null;
this.items = {};
@@ -473,14 +469,13 @@ export class TreeView extends HeightMap {
});
this.scrollableElement.onScroll((e) => {
this.render(e.scrollTop, e.height);
this.emit('scroll', e); // TODO@Joao: is anyone interested in this event?
});
if (Browser.isIE) {
this.wrapper.style.msTouchAction = 'none';
this.wrapper.style.msContentZooming = 'none';
} else {
this.wrapperGesture = new Touch.Gesture(this.wrapper);
Touch.Gesture.addTarget(this.wrapper);
}
this.rowsContainer = document.createElement('div');
@@ -490,8 +485,8 @@ export class TreeView extends HeightMap {
}
var focusTracker = DOM.trackFocus(this.domNode);
focusTracker.addFocusListener(() => this.onFocus());
focusTracker.addBlurListener(() => this.onBlur());
this.viewListeners.push(focusTracker.onDidFocus(() => this.onFocus()));
this.viewListeners.push(focusTracker.onDidBlur(() => this.onBlur()));
this.viewListeners.push(focusTracker);
this.viewListeners.push(DOM.addDisposableListener(this.domNode, 'keydown', (e) => this.onKeyDown(e)));
@@ -718,65 +713,21 @@ export class TreeView extends HeightMap {
this.releaseModel();
this.model = newModel;
this.modelListeners.push(this.model.addBulkListener((e) => this.onModelEvents(e)));
}
this.model.onRefresh(this.onRefreshing, this, this.modelListeners);
this.model.onDidRefresh(this.onRefreshed, this, this.modelListeners);
this.model.onSetInput(this.onClearingInput, this, this.modelListeners);
this.model.onDidSetInput(this.onSetInput, this, this.modelListeners);
this.model.onDidFocus(this.onModelFocusChange, this, this.modelListeners);
private onModelEvents(events: EmitterEvent[]): void {
var elementsToRefresh: Model.Item[] = [];
for (var i = 0, len = events.length; i < len; i++) {
var event = events[i];
var data = event.data;
switch (event.type) {
case 'refreshing':
this.onRefreshing();
break;
case 'refreshed':
this.onRefreshed();
break;
case 'clearingInput':
this.onClearingInput(data);
break;
case 'setInput':
this.onSetInput(data);
break;
case 'item:childrenRefreshing':
this.onItemChildrenRefreshing(data);
break;
case 'item:childrenRefreshed':
this.onItemChildrenRefreshed(data);
break;
case 'item:refresh':
elementsToRefresh.push(data.item);
break;
case 'item:expanding':
this.onItemExpanding(data);
break;
case 'item:expanded':
this.onItemExpanded(data);
break;
case 'item:collapsing':
this.onItemCollapsing(data);
break;
case 'item:reveal':
this.onItemReveal(data);
break;
case 'item:addTrait':
this.onItemAddTrait(data);
break;
case 'item:removeTrait':
this.onItemRemoveTrait(data);
break;
case 'focus':
this.onModelFocusChange();
break;
}
}
if (elementsToRefresh.length > 0) {
this.onItemsRefresh(elementsToRefresh);
}
this.model.onRefreshItemChildren(this.onItemChildrenRefreshing, this, this.modelListeners);
this.model.onDidRefreshItemChildren(this.onItemChildrenRefreshed, this, this.modelListeners);
this.model.onDidRefreshItem(this.onItemRefresh, this, this.modelListeners);
this.model.onExpandItem(this.onItemExpanding, this, this.modelListeners);
this.model.onDidExpandItem(this.onItemExpanded, this, this.modelListeners);
this.model.onCollapseItem(this.onItemCollapsing, this, this.modelListeners);
this.model.onDidRevealItem(this.onItemReveal, this, this.modelListeners);
this.model.onDidAddTraitItem(this.onItemAddTrait, this, this.modelListeners);
this.model.onDidRemoveTraitItem(this.onItemRemoveTrait, this, this.modelListeners);
}
private onRefreshing(): void {
@@ -895,7 +846,6 @@ export class TreeView extends HeightMap {
private onSetInput(e: Model.IInputEvent): void {
this.context.cache.garbageCollect();
this.inputItem = new RootViewItem(this.context, <Model.Item>e.item, this.wrapper);
this.emit('viewItem:create', { item: this.inputItem.model });
}
private onItemChildrenRefreshing(e: Model.IItemChildrenRefreshEvent): void {
@@ -1005,6 +955,10 @@ export class TreeView extends HeightMap {
}
}
private onItemRefresh(item: Model.Item): void {
this.onItemsRefresh([item]);
}
private onItemsRefresh(items: Model.Item[]): void {
this.onRefreshItemSet(items.filter(item => this.items.hasOwnProperty(item.id)));
this.onRowsChanged();
@@ -1146,10 +1100,7 @@ export class TreeView extends HeightMap {
public onRemoveItem(item: ViewItem): void {
this.removeItemFromDOM(item);
item.dispose();
this.emit('viewItem:dispose', { item: this.inputItem.model });
delete this.items[item.id];
}
@@ -1270,13 +1221,16 @@ export class TreeView extends HeightMap {
var keyboardEvent = new Keyboard.StandardKeyboardEvent(<KeyboardEvent>event);
element = this.model.getFocus();
if (!element) {
return;
}
var position: IDomNodePagePosition;
var id = this.context.dataSource.getId(this.context.tree, element);
var viewItem = this.items[id];
var position = DOM.getDomNodePagePosition(viewItem.element);
if (!element) {
element = this.model.getInput();
position = DOM.getDomNodePagePosition(this.inputItem.element);
} else {
var id = this.context.dataSource.getId(this.context.tree, element);
var viewItem = this.items[id];
position = DOM.getDomNodePagePosition(viewItem.element);
}
resultEvent = new _.KeyboardContextMenuEvent(position.left + position.width, position.top, keyboardEvent);
@@ -1697,11 +1651,6 @@ export class TreeView extends HeightMap {
}
this.domNode = null;
if (this.wrapperGesture) {
this.wrapperGesture.dispose();
this.wrapperGesture = null;
}
if (this.context.cache) {
this.context.cache.dispose();
this.context.cache = null;

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { INextIterator, ArrayIterator } from 'vs/base/common/iterator';
import { Item } from './treeModel';
@@ -13,14 +12,12 @@ export interface IViewItem {
height: number;
}
export class HeightMap extends EventEmitter {
export class HeightMap {
private heightMap: IViewItem[];
private indexes: { [item: string]: number; };
constructor() {
super();
this.heightMap = [];
this.indexes = {};
}
@@ -59,7 +56,6 @@ export class HeightMap extends EventEmitter {
while (item = iterator.next()) {
viewItem = this.createViewItem(item);
viewItem.top = totalSize + sizeDiff;
this.emit('viewItem:create', { item: viewItem.model });
this.indexes[item.id] = i++;
itemsToInsert.push(viewItem);

View File

@@ -9,9 +9,9 @@ import assert = require('assert');
import lifecycle = require('vs/base/common/lifecycle');
import _ = require('vs/base/parts/tree/browser/tree');
import WinJS = require('vs/base/common/winjs.base');
import Events = require('vs/base/common/eventEmitter');
import model = require('vs/base/parts/tree/browser/treeModel');
import TreeDefaults = require('vs/base/parts/tree/browser/treeDefaults');
import Event, { Emitter } from 'vs/base/common/event';
export class FakeRenderer {
@@ -74,11 +74,11 @@ class EventCounter {
this._count = 0;
}
public listen(emitter: Events.IEventEmitter, event: string, fn: (e) => void = null): () => void {
let r = emitter.addListener(event, (e) => {
public listen<T>(event: Event<T>, fn: (e: T) => void = null): () => void {
let r = event(data => {
this._count++;
if (fn) {
fn(e);
fn(data);
}
});
@@ -203,11 +203,11 @@ suite('TreeModel', () => {
test('refresh() refreshes all', (done) => {
model.setInput(SAMPLE.AB).then(() => {
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh'); // 4
counter.listen(model, 'item:childrenRefreshing'); // 1
counter.listen(model, 'item:childrenRefreshed'); // 1
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem); // 4
counter.listen(model.onRefreshItemChildren); // 1
counter.listen(model.onDidRefreshItemChildren); // 1
return model.refresh(null);
}).done(() => {
assert.equal(counter.count, 8);
@@ -217,11 +217,11 @@ suite('TreeModel', () => {
test('refresh(root) refreshes all', (done) => {
model.setInput(SAMPLE.AB).then(() => {
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh'); // 4
counter.listen(model, 'item:childrenRefreshing'); // 1
counter.listen(model, 'item:childrenRefreshed'); // 1
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem); // 4
counter.listen(model.onRefreshItemChildren); // 1
counter.listen(model.onDidRefreshItemChildren); // 1
return model.refresh(SAMPLE.AB);
}).done(() => {
assert.equal(counter.count, 8);
@@ -231,11 +231,11 @@ suite('TreeModel', () => {
test('refresh(root, false) refreshes the root', (done) => {
model.setInput(SAMPLE.AB).then(() => {
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh'); // 1
counter.listen(model, 'item:childrenRefreshing'); // 1
counter.listen(model, 'item:childrenRefreshed'); // 1
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem); // 1
counter.listen(model.onRefreshItemChildren); // 1
counter.listen(model.onDidRefreshItemChildren); // 1
return model.refresh(SAMPLE.AB, false);
}).done(() => {
assert.equal(counter.count, 5);
@@ -245,11 +245,11 @@ suite('TreeModel', () => {
test('refresh(collapsed element) does not refresh descendants', (done) => {
model.setInput(SAMPLE.AB).then(() => {
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh'); // 1
counter.listen(model, 'item:childrenRefreshing'); // 0
counter.listen(model, 'item:childrenRefreshed'); // 0
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem); // 1
counter.listen(model.onRefreshItemChildren); // 0
counter.listen(model.onDidRefreshItemChildren); // 0
return model.refresh(SAMPLE.AB.children[0]);
}).done(() => {
assert.equal(counter.count, 3);
@@ -261,11 +261,11 @@ suite('TreeModel', () => {
model.setInput(SAMPLE.AB).then(() => {
model.expand(SAMPLE.AB.children[0]);
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh'); // 3
counter.listen(model, 'item:childrenRefreshing'); // 1
counter.listen(model, 'item:childrenRefreshed'); // 1
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem); // 3
counter.listen(model.onRefreshItemChildren); // 1
counter.listen(model.onDidRefreshItemChildren); // 1
return model.refresh(SAMPLE.AB.children[0]);
}).done(() => {
assert.equal(counter.count, 7);
@@ -277,14 +277,14 @@ suite('TreeModel', () => {
model.setInput(SAMPLE.AB).then(() => {
model.expand(SAMPLE.AB.children[0]);
counter.listen(model, 'refreshing'); // 1
counter.listen(model, 'refreshed'); // 1
counter.listen(model, 'item:refresh', (e) => { // 1
assert.equal(e.item.id, 'a');
counter.listen(model.onRefresh); // 1
counter.listen(model.onDidRefresh); // 1
counter.listen(model.onDidRefreshItem, item => { // 1
assert.equal(item.id, 'a');
counter.up();
});
counter.listen(model, 'item:childrenRefreshing'); // 1
counter.listen(model, 'item:childrenRefreshed'); // 1
counter.listen(model.onRefreshItemChildren); // 1
counter.listen(model.onDidRefreshItemChildren); // 1
return model.refresh(SAMPLE.AB.children[0], false);
}).done(() => {
assert.equal(counter.count, 6);
@@ -296,16 +296,16 @@ suite('TreeModel', () => {
model.setInput(SAMPLE.AB).then(() => {
model.expandAll(['a', 'c']);
counter.listen(model, 'item:refresh', (e) => {
switch (e.item.id) {
case 'ROOT': assert.equal(e.item.getDepth(), 0); break;
case 'a': assert.equal(e.item.getDepth(), 1); break;
case 'aa': assert.equal(e.item.getDepth(), 2); break;
case 'ab': assert.equal(e.item.getDepth(), 2); break;
case 'b': assert.equal(e.item.getDepth(), 1); break;
case 'c': assert.equal(e.item.getDepth(), 1); break;
case 'ca': assert.equal(e.item.getDepth(), 2); break;
case 'cb': assert.equal(e.item.getDepth(), 2); break;
counter.listen(model.onDidRefreshItem, item => {
switch (item.id) {
case 'ROOT': assert.equal(item.getDepth(), 0); break;
case 'a': assert.equal(item.getDepth(), 1); break;
case 'aa': assert.equal(item.getDepth(), 2); break;
case 'ab': assert.equal(item.getDepth(), 2); break;
case 'b': assert.equal(item.getDepth(), 1); break;
case 'c': assert.equal(item.getDepth(), 1); break;
case 'ca': assert.equal(item.getDepth(), 2); break;
case 'cb': assert.equal(item.getDepth(), 2); break;
default: return;
}
counter.up();
@@ -548,13 +548,13 @@ suite('TreeModel - Expansion', () => {
test('collapse, expand', (done) => {
model.setInput(SAMPLE.AB).done(() => {
counter.listen(model, 'item:expanding', (e) => {
counter.listen(model.onExpandItem, (e) => {
assert.equal(e.item.id, 'a');
var nav = model.getNavigator(e.item);
assert.equal(nav.next() && false, null);
});
counter.listen(model, 'item:expanded', (e) => {
counter.listen(model.onDidExpandItem, (e) => {
assert.equal(e.item.id, 'a');
var nav = model.getNavigator(e.item);
assert.equal(nav.next().id, 'aa');
@@ -635,6 +635,24 @@ suite('TreeModel - Expansion', () => {
});
});
test('collapseDeepestExpandedLevel', (done) => {
model.setInput(SAMPLE.DEEP2).done(() => {
model.expand(SAMPLE.DEEP2.children[0]).done(() => {
model.expand(SAMPLE.DEEP2.children[0].children[0]).done(() => {
assert(model.isExpanded(SAMPLE.DEEP2.children[0]));
assert(model.isExpanded(SAMPLE.DEEP2.children[0].children[0]));
model.collapseDeepestExpandedLevel().done(() => {
assert(model.isExpanded(SAMPLE.DEEP2.children[0]));
assert(!model.isExpanded(SAMPLE.DEEP2.children[0].children[0]));
done();
});
});
});
});
});
test('auto expand single child folders', (done) => {
model.setInput(SAMPLE.DEEP).done(() => {
model.expand(SAMPLE.DEEP.children[0]).done(() => {
@@ -657,12 +675,12 @@ suite('TreeModel - Expansion', () => {
assert.equal(nav.next().id, 'c');
assert.equal(nav.next() && false, null);
var f: () => void = counter.listen(model, 'item:childrenRefreshing', (e) => {
var f: () => void = counter.listen(model.onRefreshItemChildren, (e) => {
assert.equal(e.item.id, 'a');
f();
});
var g: () => void = counter.listen(model, 'item:childrenRefreshed', (e) => {
var g: () => void = counter.listen(model.onDidRefreshItemChildren, (e) => {
assert.equal(e.item.id, 'a');
g();
});
@@ -1120,13 +1138,18 @@ suite('TreeModel - Traits', () => {
});
});
class DynamicModel extends Events.EventEmitter implements _.IDataSource {
class DynamicModel implements _.IDataSource {
private data: any;
public promiseFactory: { (): WinJS.Promise; };
private _onGetChildren = new Emitter<any>();
readonly onGetChildren: Event<any> = this._onGetChildren.event;
private _onDidGetChildren = new Emitter<any>();
readonly onDidGetChildren: Event<any> = this._onDidGetChildren.event;
constructor() {
super();
this.data = { root: [] };
this.promiseFactory = null;
}
@@ -1164,10 +1187,10 @@ class DynamicModel extends Events.EventEmitter implements _.IDataSource {
}
public getChildren(tree, element): WinJS.Promise {
this.emit('getChildren', element);
this._onGetChildren.fire(element);
var result = this.promiseFactory ? this.promiseFactory() : WinJS.TPromise.as(null);
return result.then(() => {
this.emit('gotChildren', element);
this._onDidGetChildren.fire(element);
return WinJS.TPromise.as(this.data[element]);
});
}
@@ -1208,8 +1231,8 @@ suite('TreeModel - Dynamic data model', () => {
var items = ['baby', 'son', 'daughter', 'father'];
var times = 0;
counter.listen(model, 'item:dispose', (e) => {
assert.equal(items[times++], e.item.id);
counter.listen(model.onDidDisposeItem, item => {
assert.equal(items[times++], item.id);
});
model.refresh().done(() => {
@@ -1320,7 +1343,7 @@ suite('TreeModel - Dynamic data model', () => {
model.collapse('father');
var times = 0;
var listener = dataModel.addListener('getChildren', (element) => {
var listener = dataModel.onGetChildren((element) => {
times++;
assert.equal(element, 'grandfather');
});
@@ -1329,7 +1352,7 @@ suite('TreeModel - Dynamic data model', () => {
assert.equal(times, 1);
listener.dispose();
listener = dataModel.addListener('getChildren', (element) => {
listener = dataModel.onGetChildren((element) => {
times++;
assert.equal(element, 'father');
});
@@ -1369,8 +1392,8 @@ suite('TreeModel - Dynamic data model', () => {
var getTimes = 0;
var gotTimes = 0;
var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; });
var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; });
var getListener = dataModel.onGetChildren((element) => { getTimes++; });
var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; });
var p1 = model.refresh('father');
assert.equal(getTimes, 1);
@@ -1414,20 +1437,18 @@ suite('TreeModel - Dynamic data model', () => {
assert.equal(nav.next() && false, null);
var refreshTimes = 0;
counter.listen(model, 'item:refresh', (e) => { refreshTimes++; });
counter.listen(model.onDidRefreshItem, (e) => { refreshTimes++; });
var getTimes = 0;
var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; });
var getListener = dataModel.onGetChildren((element) => { getTimes++; });
var gotTimes = 0;
var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; });
var p1, p2;
var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; });
var p1Completes = [];
dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Completes.push(c); }); };
p1 = model.refresh('grandfather');
model.refresh('grandfather');
// just a single get
assert.equal(refreshTimes, 1); // (+1) grandfather
@@ -1444,7 +1465,7 @@ suite('TreeModel - Dynamic data model', () => {
var p2Complete;
dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p2Complete = c; }); };
p2 = model.refresh('father');
var p2 = model.refresh('father');
// same situation still
assert.equal(refreshTimes, 3); // (+1) second father refresh
@@ -1497,15 +1518,14 @@ suite('TreeModel - Dynamic data model', () => {
var getTimes = 0;
var gotTimes = 0;
var getListener = dataModel.addListener('getChildren', (element) => { getTimes++; });
var gotListener = dataModel.addListener('gotChildren', (element) => { gotTimes++; });
var p1, p2;
var getListener = dataModel.onGetChildren((element) => { getTimes++; });
var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; });
var p2;
var p1Complete;
dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Complete = c; }); };
p1 = model.refresh('father');
model.refresh('father');
assert.equal(getTimes, 1);
assert.equal(gotTimes, 0);
@@ -1695,8 +1715,8 @@ suite('TreeModel - bugs', () => {
var getBartChildren = getGetBartChildren(0);
// item expanding should not exist!
counter.listen(model, 'item:expanding', () => { assert(false, 'should never receive item:expanding event'); });
counter.listen(model, 'item:expanded', () => { assert(false, 'should never receive item:expanded event'); });
counter.listen(model.onExpandItem, () => { assert(false, 'should never receive item:expanding event'); });
counter.listen(model.onDidExpandItem, () => { assert(false, 'should never receive item:expanded event'); });
model.setInput('root').then(() => {
@@ -1723,7 +1743,7 @@ suite('TreeModel - bugs', () => {
}).done(() => {
// teardown
while (listeners.length > 0) { listeners.pop()(); };
while (listeners.length > 0) { listeners.pop()(); }
listeners = null;
model.dispose();
model = null;