SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-1 0 16 16" enable-background="new -1 0 16 16"><path fill="#424242" d="M14 1v9h-1v-8h-8v-1h9zm-11 2v1h8v8h1v-9h-9zm7 2v9h-9v-9h9zm-2 2h-5v5h5v-5z"/><rect x="4" y="9" fill="#00539C" width="3" height="1"/></svg>

After

Width:  |  Height:  |  Size: 281 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-1 0 16 16" enable-background="new -1 0 16 16"><path fill="#C5C5C5" d="M14 1v9h-1v-8h-8v-1h9zm-11 2v1h8v8h1v-9h-9zm7 2v9h-9v-9h9zm-2 2h-5v5h5v-5z"/><rect x="4" y="9" fill="#75BEFF" width="3" height="1"/></svg>

After

Width:  |  Height:  |  Size: 281 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#E8E8E8" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>

After

Width:  |  Height:  |  Size: 139 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="M6 4v8l4-4-4-4zm1 2.414l1.586 1.586-1.586 1.586v-3.172z"/></svg>

After

Width:  |  Height:  |  Size: 148 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M6 4v8l4-4-4-4zm1 2.414L8.586 8 7 9.586V6.414z"/></svg>

After

Width:  |  Height:  |  Size: 139 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#E8E8E8" d="M11 10H5.344L11 4.414V10z"/></svg>

After

Width:  |  Height:  |  Size: 118 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fff" d="M11 10.07h-5.656l5.656-5.656v5.656z"/></svg>

After

Width:  |  Height:  |  Size: 128 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="#646465" d="M11 10H5.344L11 4.414V10z"/></svg>

After

Width:  |  Height:  |  Size: 118 B

View File

@@ -0,0 +1,31 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g style="fill:grey;">
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,31 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g style="fill:white;">
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,31 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g>
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,121 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-tree {
height: 100%;
width: 100%;
white-space: nowrap;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
position: relative;
}
.monaco-tree > .monaco-scrollable-element {
height: 100%;
}
.monaco-tree > .monaco-scrollable-element > .monaco-tree-wrapper {
height: 100%;
width: 100%;
position: relative;
}
.monaco-tree .monaco-tree-rows {
position: absolute;
width: 100%;
height: 100%;
}
.monaco-tree .monaco-tree-rows > .monaco-tree-row {
-moz-box-sizing: border-box;
-o-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
cursor: pointer;
overflow: hidden;
width: 100%;
touch-action: none;
}
.monaco-tree .monaco-tree-rows > .monaco-tree-row > .content {
position: relative;
height: 100%;
}
.monaco-tree-drag-image {
display: inline-block;
padding: 1px 7px;
border-radius: 10px;
font-size: 12px;
position: absolute;
}
/* for OS X ballistic scrolling */
.monaco-tree .monaco-tree-rows > .monaco-tree-row.scrolling {
display: none;
}
/* Expansion */
.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
content: ' ';
position: absolute;
display: block;
background: url('collapsed.svg') 50% 50% no-repeat;
width: 16px;
height: 100%;
top: 0;
left: -16px;
}
.monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before {
background-image: url('expanded.svg');
}
.monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before {
background-image: url('loading.svg');
}
/* Highlighted */
.monaco-tree.highlighted .monaco-tree-rows > .monaco-tree-row:not(.highlighted) {
opacity: 0.3;
}
.vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
background-image: url('collapsed-dark.svg');
}
.vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before {
background-image: url('expanded-dark.svg');
}
.vs-dark .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before {
background-image: url('loading-dark.svg');
}
.hc-black .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before {
background-image: url('collapsed-hc.svg');
}
.hc-black .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before {
background-image: url('expanded-hc.svg');
}
.hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before {
background-image: url('loading-hc.svg');
}
.monaco-tree-action.collapse-all {
background: url('CollapseAll.svg') center center no-repeat;
}
.hc-black .monaco-tree-action.collapse-all,
.vs-dark .monaco-tree-action.collapse-all {
background: url('CollapseAll_inverse.svg') center center no-repeat;
}

View File

@@ -0,0 +1,730 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
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';
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';
export interface ITree extends Events.IEventEmitter {
emit(eventType: string, data?: any): void;
onDOMFocus: Event<void>;
onDOMBlur: Event<void>;
onHighlightChange: Event<void>;
onDispose: Event<void>;
/**
* Returns the tree's DOM element.
*/
getHTMLElement(): HTMLElement;
/**
* Lays out the tree.
* Provide a specific height to save an (expensive) height computation.
*/
layout(height?: number): void;
/**
* Notifies the tree that is has become visible.
*/
onVisible(): void;
/**
* Notifies the tree that is has become hidden.
*/
onHidden(): void;
/**
* Sets the input of the tree.
*/
setInput(element: any): WinJS.Promise;
/**
* Returns the tree's input.
*/
getInput(): any;
/**
* Sets DOM focus on the tree.
*/
DOMFocus(): void;
/**
* Returns whether the tree has DOM focus.
*/
isDOMFocused(): boolean;
/**
* Removes DOM focus from the tree.
*/
DOMBlur(): void;
/**
* Refreshes an element.
* Provide no arguments and it will refresh the input element.
*/
refresh(element?: any, recursive?: boolean): WinJS.Promise;
/**
* Expands an element.
* The returned promise returns a boolean for whether the element was expanded or not.
*/
expand(element: any): WinJS.Promise;
/**
* Expands several elements.
* The returned promise returns a boolean array for whether the elements were expanded or not.
*/
expandAll(elements?: any[]): WinJS.Promise;
/**
* Collapses an element.
* The returned promise returns a boolean for whether the element was collapsed or not.
*/
collapse(element: any, recursive?: boolean): WinJS.Promise;
/**
* Collapses several elements.
* Provide no arguments and it will recursively collapse all elements in the tree
* The returned promise returns a boolean for whether the elements were collapsed or not.
*/
collapseAll(elements?: any[], recursive?: boolean): WinJS.Promise;
/**
* Toggles an element's expansion state.
*/
toggleExpansion(element: any, recursive?: boolean): WinJS.Promise;
/**
* Toggles several element's expansion state.
*/
toggleExpansionAll(elements: any[]): WinJS.Promise;
/**
* Returns whether an element is expanded or not.
*/
isExpanded(element: any): boolean;
/**
* Returns a list of the currently expanded elements.
*/
getExpandedElements(): any[];
/**
* Reveals an element in the tree. The relativeTop is a value between 0 and 1. The closer to 0 the more the
* element will scroll up to the top.
*/
reveal(element: any, relativeTop?: number): WinJS.Promise;
/**
* Returns the relative top position of any given element, if visible.
* If not visible, returns a negative number or a number > 1.
* Useful when calling `reveal(element, relativeTop)`.
*/
getRelativeTop(element: any): number;
/**
* Returns a number between 0 and 1 representing how much the tree is scroll down. 0 means all the way
* to the top; 1 means all the way down.
*/
getScrollPosition(): number;
/**
* Sets the scroll position with a number between 0 and 1 representing how much the tree is scroll down. 0 means all the way
* to the top; 1 means all the way down.
*/
setScrollPosition(pos: number): void;
/**
* Returns the total height of the tree's content.
*/
getContentHeight(): number;
/**
* Sets the tree's highlight to be the given element.
* Provide no arguments and it clears the tree's highlight.
*/
setHighlight(element?: any, eventPayload?: any): void;
/**
* Returns the currently highlighted element.
*/
getHighlight(includeHidden?: boolean): any;
/**
* Returns whether an element is highlighted or not.
*/
isHighlighted(element: any): boolean;
/**
* Clears the highlight.
*/
clearHighlight(eventPayload?: any): void;
/**
* Selects an element.
*/
select(element: any, eventPayload?: any): void;
/**
* Selects a range of elements.
*/
selectRange(fromElement: any, toElement: any, eventPayload?: any): void;
/**
* Deselects a range of elements.
*/
deselectRange(fromElement: any, toElement: any, eventPayload?: any): void;
/**
* Selects several elements.
*/
selectAll(elements: any[], eventPayload?: any): void;
/**
* Deselects an element.
*/
deselect(element: any, eventPayload?: any): void;
/**
* Deselects several elements.
*/
deselectAll(elements: any[], eventPayload?: any): void;
/**
* Replaces the current selection with the given elements.
*/
setSelection(elements: any[], eventPayload?: any): void;
/**
* Toggles the element's selection.
*/
toggleSelection(element: any, eventPayload?: any): void;
/**
* Returns the currently selected elements.
*/
getSelection(includeHidden?: boolean): any[];
/**
* Returns whether an element is selected or not.
*/
isSelected(element: any): boolean;
/**
* Selects the next `count`-nth element, in visible order.
*/
selectNext(count?: number, clearSelection?: boolean, eventPayload?: any): void;
/**
* Selects the previous `count`-nth element, in visible order.
*/
selectPrevious(count?: number, clearSelection?: boolean, eventPayload?: any): void;
/**
* Selects the currently selected element's parent.
*/
selectParent(clearSelection?: boolean, eventPayload?: any): void;
/**
* Clears the selection.
*/
clearSelection(eventPayload?: any): void;
/**
* Sets the focused element.
*/
setFocus(element?: any, eventPayload?: any): void;
/**
* Returns whether an element is focused or not.
*/
isFocused(element: any): boolean;
/**
* Returns focused element.
*/
getFocus(includeHidden?: boolean): any;
/**
* Focuses the next `count`-nth element, in visible order.
*/
focusNext(count?: number, eventPayload?: any): void;
/**
* Focuses the previous `count`-nth element, in visible order.
*/
focusPrevious(count?: number, eventPayload?: any): void;
/**
* Focuses the currently focused element's parent.
*/
focusParent(eventPayload?: any): void;
/**
* Focuses the first child of the currently focused element.
*/
focusFirstChild(eventPayload?: any): void;
/**
* Focuses the second element, in visible order. Will focus the first
* child from the provided element's parent if any.
*/
focusFirst(eventPayload?: any, from?: any): void;
/**
* Focuses the nth element, in visible order.
*/
focusNth(index: number, eventPayload?: any): void;
/**
* Focuses the last element, in visible order. Will focus the last
* child from the provided element's parent if any.
*/
focusLast(eventPayload?: any, from?: any): void;
/**
* Focuses the element at the end of the next page, in visible order.
*/
focusNextPage(eventPayload?: any): void;
/**
* Focuses the element at the beginning of the previous page, in visible order.
*/
focusPreviousPage(eventPayload?: any): void;
/**
* Clears the focus.
*/
clearFocus(eventPayload?: any): void;
/**
* Adds the trait to elements.
*/
addTraits(trait: string, elements: any[]): void;
/**
* Removes the trait from elements.
*/
removeTraits(trait: string, elements: any[]): void;
/**
* Toggles the element's trait.
*/
toggleTrait(trait: string, element: any): void;
/**
* Returns whether the element has the trait or not.
*/
hasTrait(trait: string, element: any): boolean;
/**
* Returns a navigator which allows to discover the visible and
* expanded elements in the tree.
*/
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any>;
/**
* Apply styles to the tree.
*/
style(styles: ITreeStyles): void;
/**
* Disposes the tree
*/
dispose(): void;
}
export interface IDataSource {
/**
* Returns the unique identifier of the given element.
* No more than one element may use a given identifier.
*/
getId(tree: ITree, element: any): string;
/**
* Returns a boolean value indicating whether the element has children.
*/
hasChildren(tree: ITree, element: any): boolean;
/**
* Returns the element's children as an array in a promise.
*/
getChildren(tree: ITree, element: any): WinJS.Promise;
/**
* Returns the element's parent in a promise.
*/
getParent(tree: ITree, element: any): WinJS.Promise;
/**
* Returns whether an element should be expanded when first added to the tree.
*/
shouldAutoexpand?(tree: ITree, element: any): boolean;
}
export interface IRenderer {
/**
* Returns the element's height in the tree, in pixels.
*/
getHeight(tree: ITree, element: any): number;
/**
* Returns a template ID for a given element. This will be used as an identifier
* for the next 3 methods.
*/
getTemplateId(tree: ITree, element: any): string;
/**
* Renders the template in a DOM element. This method should render all the DOM
* structure for an hypothetical element leaving its contents blank. It should
* return an object bag which will be passed along to `renderElement` and used
* to fill in those blanks.
*
* You should do all DOM creating and object allocation in this method. It
* will be called only a few times.
*/
renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any;
/**
* Renders an element, given an object bag returned by `renderTemplate`.
* This method should do as little as possible and ideally it should only fill
* in the blanks left by `renderTemplate`.
*
* Try to make this method do as little possible, since it will be called very
* often.
*/
renderElement(tree: ITree, element: any, templateId: string, templateData: any): void;
/**
* Disposes a template that was once rendered.
*/
disposeTemplate(tree: ITree, templateId: string, templateData: any): void;
}
export interface IAccessibilityProvider {
/**
* Given an element in the tree, return the ARIA label that should be associated with the
* item. This helps screen readers to provide a meaningful label for the currently focused
* tree element.
*
* Returning null will not disable ARIA for the element. Instead it is up to the screen reader
* to compute a meaningful label based on the contents of the element in the DOM
*
* See also: https://www.w3.org/TR/wai-aria/states_and_properties#aria-label
*/
getAriaLabel(tree: ITree, element: any): string;
/**
* Given an element in the tree return its aria-posinset. Should be between 1 and aria-setsize
* https://www.w3.org/TR/wai-aria/states_and_properties#aria-posinset
*/
getPosInSet?(tree: ITree, element: any): string;
/**
* Return the aria-setsize of the tree.
* https://www.w3.org/TR/wai-aria/states_and_properties#aria-setsize
*/
getSetSize?(): string;
}
export /* abstract */ class ContextMenuEvent {
private _posx: number;
private _posy: number;
private _target: HTMLElement;
constructor(posx: number, posy: number, target: HTMLElement) {
this._posx = posx;
this._posy = posy;
this._target = target;
}
public preventDefault(): void {
// no-op
}
public stopPropagation(): void {
// no-op
}
public get posx(): number {
return this._posx;
}
public get posy(): number {
return this._posy;
}
public get target(): HTMLElement {
return this._target;
}
}
export class MouseContextMenuEvent extends ContextMenuEvent {
private originalEvent: Mouse.IMouseEvent;
constructor(originalEvent: Mouse.IMouseEvent) {
super(originalEvent.posx, originalEvent.posy, originalEvent.target);
this.originalEvent = originalEvent;
}
public preventDefault(): void {
this.originalEvent.preventDefault();
}
public stopPropagation(): void {
this.originalEvent.stopPropagation();
}
}
export class KeyboardContextMenuEvent extends ContextMenuEvent {
private originalEvent: Keyboard.IKeyboardEvent;
constructor(posx: number, posy: number, originalEvent: Keyboard.IKeyboardEvent) {
super(posx, posy, originalEvent.target);
this.originalEvent = originalEvent;
}
public preventDefault(): void {
this.originalEvent.preventDefault();
}
public stopPropagation(): void {
this.originalEvent.stopPropagation();
}
}
export interface IController {
/**
* Called when an element is clicked.
*/
onClick(tree: ITree, element: any, event: Mouse.IMouseEvent): boolean;
/**
* Called when an element is requested for a context menu.
*/
onContextMenu(tree: ITree, element: any, event: ContextMenuEvent): boolean;
/**
* Called when an element is tapped.
*/
onTap(tree: ITree, element: any, event: Touch.GestureEvent): boolean;
/**
* Called when a key is pressed down while selecting elements.
*/
onKeyDown(tree: ITree, event: Keyboard.IKeyboardEvent): boolean;
/**
* Called when a key is released while selecting elements.
*/
onKeyUp(tree: ITree, event: Keyboard.IKeyboardEvent): boolean;
/**
* Called when a mouse button is pressed down on an element.
*/
onMouseDown?(tree: ITree, element: any, event: Mouse.IMouseEvent): boolean;
/**
* Called when a mouse button goes up on an element.
*/
onMouseUp?(tree: ITree, element: any, event: Mouse.IMouseEvent): boolean;
}
export enum DragOverEffect {
COPY,
MOVE
}
export enum DragOverBubble {
BUBBLE_DOWN,
BUBBLE_UP
}
export interface IDragOverReaction {
accept: boolean;
effect?: DragOverEffect;
bubble?: DragOverBubble;
autoExpand?: boolean;
}
export const DRAG_OVER_REJECT: IDragOverReaction = { accept: false };
export const DRAG_OVER_ACCEPT: IDragOverReaction = { accept: true };
export const DRAG_OVER_ACCEPT_BUBBLE_UP: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP };
export const DRAG_OVER_ACCEPT_BUBBLE_DOWN = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, autoExpand });
export const DRAG_OVER_ACCEPT_BUBBLE_UP_COPY: IDragOverReaction = { accept: true, bubble: DragOverBubble.BUBBLE_UP, effect: DragOverEffect.COPY };
export const DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY = (autoExpand = false) => ({ accept: true, bubble: DragOverBubble.BUBBLE_DOWN, effect: DragOverEffect.COPY, autoExpand });
export interface IDragAndDropData {
update(event: Mouse.DragMouseEvent): void;
getData(): any;
}
export interface IDragAndDrop {
/**
* Returns a uri if the given element should be allowed to drag.
* Returns null, otherwise.
*/
getDragURI(tree: ITree, element: any): string;
/**
* Returns a label to display when dragging the element.
*/
getDragLabel?(tree: ITree, elements: any[]): string;
/**
* Sent when the drag operation is starting.
*/
onDragStart(tree: ITree, data: IDragAndDropData, originalEvent: Mouse.DragMouseEvent): void;
/**
* Returns a DragOverReaction indicating whether sources can be
* dropped into target or some parent of the target.
*/
onDragOver(tree: ITree, data: IDragAndDropData, targetElement: any, originalEvent: Mouse.DragMouseEvent): IDragOverReaction;
/**
* Handles the action of dropping sources into target.
*/
drop(tree: ITree, data: IDragAndDropData, targetElement: any, originalEvent: Mouse.DragMouseEvent): void;
// {{SQL CARBON EDIT}}
/**
* Handles the action of canceled drag-and-drop activities
*/
dropAbort(tree: ITree, data: IDragAndDropData): void;
}
export interface IFilter {
/**
* Returns whether the given element should be visible.
*/
isVisible(tree: ITree, element: any): boolean;
}
export interface IElementCallback {
(tree: ITree, element: any): void;
}
export type ICallback = () => void;
export interface ISorter {
/**
* Compare two elements in the viewer to define the sorting order.
*/
compare(tree: ITree, element: any, otherElement: any): number;
}
// Events
export interface ISelectionEvent {
selection: any[];
payload?: any;
}
export interface IFocusEvent {
focus: any;
payload?: any;
}
export interface IHighlightEvent {
highlight: any;
payload?: any;
}
// Options
export interface ITreeConfiguration {
dataSource: IDataSource;
renderer?: IRenderer;
controller?: IController;
dnd?: IDragAndDrop;
filter?: IFilter;
sorter?: ISorter;
accessibilityProvider?: IAccessibilityProvider;
}
export interface ITreeOptions extends ITreeStyles {
twistiePixels?: number;
showTwistie?: boolean;
indentPixels?: number;
verticalScrollMode?: ScrollbarVisibility;
alwaysFocused?: boolean;
autoExpandSingleChildren?: boolean;
useShadows?: boolean;
paddingOnRow?: boolean;
ariaLabel?: string;
keyboardSupport?: boolean;
preventRootFocus?: boolean;
}
export interface ITreeStyles {
listFocusBackground?: Color;
listFocusForeground?: Color;
listActiveSelectionBackground?: Color;
listActiveSelectionForeground?: Color;
listFocusAndSelectionBackground?: Color;
listFocusAndSelectionForeground?: Color;
listInactiveSelectionBackground?: Color;
listInactiveSelectionForeground?: Color;
listHoverBackground?: Color;
listHoverForeground?: Color;
listDropBackground?: Color;
listFocusOutline?: Color;
}
export interface ITreeContext extends ITreeConfiguration {
tree: ITree;
options: ITreeOptions;
}
export interface IActionProvider {
/**
* Returns whether or not the element has actions. These show up in place right to the element in the tree.
*/
hasActions(tree: ITree, element: any): boolean;
/**
* Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree.
*/
getActions(tree: ITree, element: any): WinJS.TPromise<IAction[]>;
/**
* Returns whether or not the element has secondary actions. These show up once the user has expanded the element's action bar.
*/
hasSecondaryActions(tree: ITree, element: any): boolean;
/**
* Returns a promise of an array with the secondary actions of the element that should show up once the user has expanded the element's action bar.
*/
getSecondaryActions(tree: ITree, element: any): WinJS.TPromise<IAction[]>;
/**
* Returns an action item to render an action.
*/
getActionItem(tree: ITree, element: any, action: IAction): IActionItem;
}

View File

@@ -0,0 +1,441 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import platform = require('vs/base/common/platform');
import touch = require('vs/base/browser/touch');
import errors = require('vs/base/common/errors');
import dom = require('vs/base/browser/dom');
import mouse = require('vs/base/browser/mouseEvent');
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import _ = require('vs/base/parts/tree/browser/tree');
import { KeyCode, KeyMod, Keybinding, createKeybinding, SimpleKeybinding } from 'vs/base/common/keyCodes';
export interface IKeyBindingCallback {
(tree: _.ITree, event: IKeyboardEvent): void;
}
export interface ICancelableEvent {
preventDefault(): void;
stopPropagation(): void;
}
export enum ClickBehavior {
/**
* Handle the click when the mouse button is pressed but not released yet.
*/
ON_MOUSE_DOWN,
/**
* Handle the click when the mouse button is released.
*/
ON_MOUSE_UP
}
export interface IControllerOptions {
clickBehavior?: ClickBehavior;
keyboardSupport?: boolean;
}
interface IKeybindingDispatcherItem {
keybinding: Keybinding;
callback: IKeyBindingCallback;
}
export class KeybindingDispatcher {
private _arr: IKeybindingDispatcherItem[];
constructor() {
this._arr = [];
}
public set(keybinding: number, callback: IKeyBindingCallback) {
this._arr.push({
keybinding: createKeybinding(keybinding, platform.OS),
callback: callback
});
}
public dispatch(keybinding: SimpleKeybinding): IKeyBindingCallback {
// Loop from the last to the first to handle overwrites
for (let i = this._arr.length - 1; i >= 0; i--) {
let item = this._arr[i];
if (keybinding.equals(item.keybinding)) {
return item.callback;
}
}
return null;
}
}
export class DefaultController implements _.IController {
protected downKeyBindingDispatcher: KeybindingDispatcher;
protected upKeyBindingDispatcher: KeybindingDispatcher;
private options: IControllerOptions;
constructor(options: IControllerOptions = { clickBehavior: ClickBehavior.ON_MOUSE_UP, keyboardSupport: true }) {
this.options = options;
this.downKeyBindingDispatcher = new KeybindingDispatcher();
this.upKeyBindingDispatcher = new KeybindingDispatcher();
if (typeof options.keyboardSupport !== 'boolean' || options.keyboardSupport) {
this.downKeyBindingDispatcher.set(KeyCode.UpArrow, (t, e) => this.onUp(t, e));
this.downKeyBindingDispatcher.set(KeyCode.DownArrow, (t, e) => this.onDown(t, e));
this.downKeyBindingDispatcher.set(KeyCode.LeftArrow, (t, e) => this.onLeft(t, e));
this.downKeyBindingDispatcher.set(KeyCode.RightArrow, (t, e) => this.onRight(t, e));
if (platform.isMacintosh) {
this.downKeyBindingDispatcher.set(KeyMod.CtrlCmd | KeyCode.UpArrow, (t, e) => this.onLeft(t, e));
this.downKeyBindingDispatcher.set(KeyMod.WinCtrl | KeyCode.KEY_N, (t, e) => this.onDown(t, e));
this.downKeyBindingDispatcher.set(KeyMod.WinCtrl | KeyCode.KEY_P, (t, e) => this.onUp(t, e));
}
this.downKeyBindingDispatcher.set(KeyCode.PageUp, (t, e) => this.onPageUp(t, e));
this.downKeyBindingDispatcher.set(KeyCode.PageDown, (t, e) => this.onPageDown(t, e));
this.downKeyBindingDispatcher.set(KeyCode.Home, (t, e) => this.onHome(t, e));
this.downKeyBindingDispatcher.set(KeyCode.End, (t, e) => this.onEnd(t, e));
this.downKeyBindingDispatcher.set(KeyCode.Space, (t, e) => this.onSpace(t, e));
this.downKeyBindingDispatcher.set(KeyCode.Escape, (t, e) => this.onEscape(t, e));
this.upKeyBindingDispatcher.set(KeyCode.Enter, this.onEnter.bind(this));
this.upKeyBindingDispatcher.set(KeyMod.CtrlCmd | KeyCode.Enter, this.onEnter.bind(this));
}
}
public onMouseDown(tree: _.ITree, element: any, event: mouse.IMouseEvent, origin: string = 'mouse'): boolean {
if (this.options.clickBehavior === ClickBehavior.ON_MOUSE_DOWN && (event.leftButton || event.middleButton)) {
if (event.target) {
if (event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
return false; // Ignore event if target is a form input field (avoids browser specific issues)
}
if (dom.findParentWithClass(event.target, 'monaco-action-bar', 'row')) { // TODO@Joao not very nice way of checking for the action bar (implicit knowledge)
return false; // Ignore event if target is over an action bar of the row
}
}
// Propagate to onLeftClick now
return this.onLeftClick(tree, element, event, origin);
}
return false;
}
public onClick(tree: _.ITree, element: any, event: mouse.IMouseEvent): boolean {
var isMac = platform.isMacintosh;
// A Ctrl click on the Mac is a context menu event
if (isMac && event.ctrlKey) {
event.preventDefault();
event.stopPropagation();
return false;
}
if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
return false; // Ignore event if target is a form input field (avoids browser specific issues)
}
if (this.options.clickBehavior === ClickBehavior.ON_MOUSE_DOWN && (event.leftButton || event.middleButton)) {
return false; // Already handled by onMouseDown
}
return this.onLeftClick(tree, element, event);
}
protected onLeftClick(tree: _.ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
var payload = { origin: origin, originalEvent: eventish };
if (tree.getInput() === element) {
tree.clearFocus(payload);
tree.clearSelection(payload);
} else {
var isMouseDown = eventish && (<mouse.IMouseEvent>eventish).browserEvent && (<mouse.IMouseEvent>eventish).browserEvent.type === 'mousedown';
if (!isMouseDown) {
eventish.preventDefault(); // we cannot preventDefault onMouseDown because this would break DND otherwise
}
eventish.stopPropagation();
tree.DOMFocus();
tree.setSelection([element], payload);
tree.setFocus(element, payload);
if (tree.isExpanded(element)) {
tree.collapse(element).done(null, errors.onUnexpectedError);
} else {
tree.expand(element).done(null, errors.onUnexpectedError);
}
}
return true;
}
public onContextMenu(tree: _.ITree, element: any, event: _.ContextMenuEvent): boolean {
if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') {
return false; // allow context menu on input fields
}
// Prevent native context menu from showing up
if (event) {
event.preventDefault();
event.stopPropagation();
}
return false;
}
public onTap(tree: _.ITree, element: any, event: touch.GestureEvent): boolean {
var target = <HTMLElement>event.initialTarget;
if (target && target.tagName && target.tagName.toLowerCase() === 'input') {
return false; // Ignore event if target is a form input field (avoids browser specific issues)
}
return this.onLeftClick(tree, element, event, 'touch');
}
public onKeyDown(tree: _.ITree, event: IKeyboardEvent): boolean {
return this.onKey(this.downKeyBindingDispatcher, tree, event);
}
public onKeyUp(tree: _.ITree, event: IKeyboardEvent): boolean {
return this.onKey(this.upKeyBindingDispatcher, tree, event);
}
private onKey(bindings: KeybindingDispatcher, tree: _.ITree, event: IKeyboardEvent): boolean {
var handler = bindings.dispatch(event.toKeybinding());
if (handler) {
if (handler(tree, event)) {
event.preventDefault();
event.stopPropagation();
return true;
}
}
return false;
}
protected onUp(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusPrevious(1, payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onPageUp(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusPreviousPage(payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onDown(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusNext(1, payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onPageDown(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusNextPage(payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onHome(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusFirst(payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onEnd(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
tree.focusLast(payload);
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
protected onLeft(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
var focus = tree.getFocus();
tree.collapse(focus).then(didCollapse => {
if (focus && !didCollapse) {
tree.focusParent(payload);
return tree.reveal(tree.getFocus());
}
return undefined;
}).done(null, errors.onUnexpectedError);
}
return true;
}
protected onRight(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
} else {
var focus = tree.getFocus();
tree.expand(focus).then(didExpand => {
if (focus && !didExpand) {
tree.focusFirstChild(payload);
return tree.reveal(tree.getFocus());
}
return undefined;
}).done(null, errors.onUnexpectedError);
}
return true;
}
protected onEnter(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
return false;
}
var focus = tree.getFocus();
if (focus) {
tree.setSelection([focus], payload);
}
return true;
}
protected onSpace(tree: _.ITree, event: IKeyboardEvent): boolean {
if (tree.getHighlight()) {
return false;
}
var focus = tree.getFocus();
if (focus) {
tree.toggleExpansion(focus);
}
return true;
}
protected onEscape(tree: _.ITree, event: IKeyboardEvent): boolean {
var payload = { origin: 'keyboard', originalEvent: event };
if (tree.getHighlight()) {
tree.clearHighlight(payload);
return true;
}
if (tree.getSelection().length) {
tree.clearSelection(payload);
return true;
}
if (tree.getFocus()) {
tree.clearFocus(payload);
return true;
}
return false;
}
}
export class DefaultDragAndDrop implements _.IDragAndDrop {
public getDragURI(tree: _.ITree, element: any): string {
return null;
}
public onDragStart(tree: _.ITree, data: _.IDragAndDropData, originalEvent: mouse.DragMouseEvent): void {
return;
}
public onDragOver(tree: _.ITree, data: _.IDragAndDropData, targetElement: any, originalEvent: mouse.DragMouseEvent): _.IDragOverReaction {
return null;
}
public drop(tree: _.ITree, data: _.IDragAndDropData, targetElement: any, originalEvent: mouse.DragMouseEvent): void {
return;
}
// {{SQL CARBON EDIT}}
public dropAbort(tree: _.ITree, data: _.IDragAndDropData): void { }
}
export class DefaultFilter implements _.IFilter {
public isVisible(tree: _.ITree, element: any): boolean {
return true;
}
}
export class DefaultSorter implements _.ISorter {
public compare(tree: _.ITree, element: any, otherElement: any): number {
return 0;
}
}
export class DefaultAccessibilityProvider implements _.IAccessibilityProvider {
getAriaLabel(tree: _.ITree, element: any): string {
return null;
}
}
export class CollapseAllAction extends Action {
constructor(private viewer: _.ITree, enabled: boolean) {
super('vs.tree.collapse', nls.localize('collapse', "Collapse"), 'monaco-tree-action collapse-all', enabled);
}
public run(context?: any): TPromise<any> {
if (this.viewer.getHighlight()) {
return TPromise.as(null); // Global action disabled if user is in edit mode from another action
}
this.viewer.collapseAll();
this.viewer.clearSelection();
this.viewer.clearFocus();
this.viewer.DOMFocus();
this.viewer.focusFirst();
return TPromise.as(null);
}
}

View File

@@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import _ = require('vs/base/parts/tree/browser/tree');
import Mouse = require('vs/base/browser/mouseEvent');
import { DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import URI from 'vs/base/common/uri';
import { basename } from 'vs/base/common/paths';
import { getPathLabel } from 'vs/base/common/labels';
export class ElementsDragAndDropData implements _.IDragAndDropData {
private elements: any[];
constructor(elements: any[]) {
this.elements = elements;
}
public update(event: Mouse.DragMouseEvent): void {
// no-op
}
public getData(): any {
return this.elements;
}
}
export class ExternalElementsDragAndDropData implements _.IDragAndDropData {
private elements: any[];
constructor(elements: any[]) {
this.elements = elements;
}
public update(event: Mouse.DragMouseEvent): void {
// no-op
}
public getData(): any {
return this.elements;
}
}
export class DesktopDragAndDropData implements _.IDragAndDropData {
private types: any[];
private files: any[];
constructor() {
this.types = [];
this.files = [];
}
public update(event: Mouse.DragMouseEvent): void {
if (event.dataTransfer.types) {
this.types = [];
Array.prototype.push.apply(this.types, event.dataTransfer.types);
}
if (event.dataTransfer.files) {
this.files = [];
Array.prototype.push.apply(this.files, event.dataTransfer.files);
this.files = this.files.filter(f => f.size || f.type);
}
}
public getData(): any {
return {
types: this.types,
files: this.files
};
}
}
export class SimpleFileResourceDragAndDrop extends DefaultDragAndDrop {
constructor(private toResource: (obj: any) => URI) {
super();
}
public getDragURI(tree: _.ITree, obj: any): string {
const resource = this.toResource(obj);
if (resource) {
return resource.toString();
}
return void 0;
}
public getDragLabel(tree: _.ITree, elements: any[]): string {
if (elements.length > 1) {
return String(elements.length);
}
const resource = this.toResource(elements[0]);
if (resource) {
return basename(resource.fsPath);
}
return void 0;
}
public onDragStart(tree: _.ITree, data: _.IDragAndDropData, originalEvent: Mouse.DragMouseEvent): void {
const sources: object[] = data.getData();
let source: object = null;
if (sources.length > 0) {
source = sources[0];
}
// Apply some datatransfer types to allow for dragging the element outside of the application
const resource = this.toResource(source);
if (resource) {
originalEvent.dataTransfer.setData('text/plain', getPathLabel(resource));
}
}
}

View File

@@ -0,0 +1,387 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
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 { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
export class TreeContext implements _.ITreeContext {
public tree: _.ITree;
public configuration: _.ITreeConfiguration;
public options: _.ITreeOptions;
public dataSource: _.IDataSource;
public renderer: _.IRenderer;
public controller: _.IController;
public dnd: _.IDragAndDrop;
public filter: _.IFilter;
public sorter: _.ISorter;
public accessibilityProvider: _.IAccessibilityProvider;
constructor(tree: _.ITree, configuration: _.ITreeConfiguration, options: _.ITreeOptions = {}) {
this.tree = tree;
this.configuration = configuration;
this.options = options;
if (!configuration.dataSource) {
throw new Error('You must provide a Data Source to the tree.');
}
this.dataSource = configuration.dataSource;
this.renderer = configuration.renderer;
this.controller = configuration.controller || new TreeDefaults.DefaultController({ clickBehavior: TreeDefaults.ClickBehavior.ON_MOUSE_UP, keyboardSupport: typeof options.keyboardSupport !== 'boolean' || options.keyboardSupport });
this.dnd = configuration.dnd || new TreeDefaults.DefaultDragAndDrop();
this.filter = configuration.filter || new TreeDefaults.DefaultFilter();
this.sorter = configuration.sorter || null;
this.accessibilityProvider = configuration.accessibilityProvider || new TreeDefaults.DefaultAccessibilityProvider();
}
}
const defaultStyles: _.ITreeStyles = {
listFocusBackground: Color.fromHex('#073655'),
listActiveSelectionBackground: Color.fromHex('#3062D6'),
listActiveSelectionForeground: Color.fromHex('#FFFFFF'),
listFocusAndSelectionBackground: Color.fromHex('#094771'),
listFocusAndSelectionForeground: Color.fromHex('#FFFFFF'),
listInactiveSelectionBackground: Color.fromHex('#C8C8C8'),
listHoverBackground: Color.fromHex('#DCDCDC'),
listDropBackground: Color.fromHex('#383B3D')
};
export class Tree extends Events.EventEmitter 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[];
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);
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;
this.context = new TreeContext(this, configuration, options);
this.model = new Model.TreeModel(this.context);
this.view = new View.TreeView(this.context, this.container);
this.view.setModel(this.model);
this.addEmitter(this.model);
this.addEmitter(this.view);
this.toDispose.push(this.model.addListener('highlight', () => this._onHighlightChange.fire()));
}
public style(styles: _.ITreeStyles): void {
this.view.applyStyles(styles);
}
get onDOMFocus(): Event<void> {
return this.view && this.view.onDOMFocus;
}
get onDOMBlur(): 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();
}
public layout(height?: number): void {
this.view.layout(height);
}
public DOMFocus(): void {
this.view.focus();
}
public isDOMFocused(): boolean {
return this.view.isFocused();
}
public DOMBlur(): void {
this.view.blur();
}
public onVisible(): void {
this.view.onVisible();
}
public onHidden(): void {
this.view.onHidden();
}
public setInput(element: any): WinJS.Promise {
return this.model.setInput(element);
}
public getInput(): any {
return this.model.getInput();
}
public refresh(element: any = null, recursive = true): WinJS.Promise {
return this.model.refresh(element, recursive);
}
public expand(element: any): WinJS.Promise {
return this.model.expand(element);
}
public expandAll(elements: any[]): WinJS.Promise {
return this.model.expandAll(elements);
}
public collapse(element: any, recursive: boolean = false): WinJS.Promise {
return this.model.collapse(element, recursive);
}
public collapseAll(elements: any[] = null, recursive: boolean = false): WinJS.Promise {
return this.model.collapseAll(elements, recursive);
}
public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise {
return this.model.toggleExpansion(element, recursive);
}
public toggleExpansionAll(elements: any[]): WinJS.Promise {
return this.model.toggleExpansionAll(elements);
}
public isExpanded(element: any): boolean {
return this.model.isExpanded(element);
}
public getExpandedElements(): any[] {
return this.model.getExpandedElements();
}
public reveal(element: any, relativeTop: number = null): WinJS.Promise {
return this.model.reveal(element, relativeTop);
}
public getRelativeTop(element: any): number {
let item = this.model.getItem(element);
return this.view.getRelativeTop(item);
}
public getScrollPosition(): number {
return this.view.getScrollPosition();
}
public setScrollPosition(pos: number): void {
this.view.setScrollPosition(pos);
}
getContentHeight(): number {
return this.view.getTotalHeight();
}
public setHighlight(element?: any, eventPayload?: any): void {
this.model.setHighlight(element, eventPayload);
}
public getHighlight(): any {
return this.model.getHighlight();
}
public isHighlighted(element: any): boolean {
return this.model.isFocused(element);
}
public clearHighlight(eventPayload?: any): void {
this.model.setHighlight(null, eventPayload);
}
public select(element: any, eventPayload?: any): void {
this.model.select(element, eventPayload);
}
public selectRange(fromElement: any, toElement: any, eventPayload?: any): void {
this.model.selectRange(fromElement, toElement, eventPayload);
}
public deselectRange(fromElement: any, toElement: any, eventPayload?: any): void {
this.model.deselectRange(fromElement, toElement, eventPayload);
}
public selectAll(elements: any[], eventPayload?: any): void {
this.model.selectAll(elements, eventPayload);
}
public deselect(element: any, eventPayload?: any): void {
this.model.deselect(element, eventPayload);
}
public deselectAll(elements: any[], eventPayload?: any): void {
this.model.deselectAll(elements, eventPayload);
}
public setSelection(elements: any[], eventPayload?: any): void {
this.model.setSelection(elements, eventPayload);
}
public toggleSelection(element: any, eventPayload?: any): void {
this.model.toggleSelection(element, eventPayload);
}
public isSelected(element: any): boolean {
return this.model.isSelected(element);
}
public getSelection(): any[] {
return this.model.getSelection();
}
public clearSelection(eventPayload?: any): void {
this.model.setSelection([], eventPayload);
}
public selectNext(count?: number, clearSelection?: boolean, eventPayload?: any): void {
this.model.selectNext(count, clearSelection, eventPayload);
}
public selectPrevious(count?: number, clearSelection?: boolean, eventPayload?: any): void {
this.model.selectPrevious(count, clearSelection, eventPayload);
}
public selectParent(clearSelection?: boolean, eventPayload?: any): void {
this.model.selectParent(clearSelection, eventPayload);
}
public setFocus(element?: any, eventPayload?: any): void {
this.model.setFocus(element, eventPayload);
}
public isFocused(element: any): boolean {
return this.model.isFocused(element);
}
public getFocus(): any {
return this.model.getFocus();
}
public focusNext(count?: number, eventPayload?: any): void {
this.model.focusNext(count, eventPayload);
}
public focusPrevious(count?: number, eventPayload?: any): void {
this.model.focusPrevious(count, eventPayload);
}
public focusParent(eventPayload?: any): void {
this.model.focusParent(eventPayload);
}
public focusFirstChild(eventPayload?: any): void {
this.model.focusFirstChild(eventPayload);
}
public focusFirst(eventPayload?: any, from?: any): void {
this.model.focusFirst(eventPayload, from);
}
public focusNth(index: number, eventPayload?: any): void {
this.model.focusNth(index, eventPayload);
}
public focusLast(eventPayload?: any, from?: any): void {
this.model.focusLast(eventPayload, from);
}
public focusNextPage(eventPayload?: any): void {
this.view.focusNextPage(eventPayload);
}
public focusPreviousPage(eventPayload?: any): void {
this.view.focusPreviousPage(eventPayload);
}
public clearFocus(eventPayload?: any): void {
this.model.setFocus(null, eventPayload);
}
public addTraits(trait: string, elements: any[]): void {
this.model.addTraits(trait, elements);
}
public removeTraits(trait: string, elements: any[]): void {
this.model.removeTraits(trait, elements);
}
public toggleTrait(trait: string, element: any): void {
this.model.hasTrait(trait, element) ? this.model.removeTraits(trait, [element])
: this.model.addTraits(trait, [element]);
}
public hasTrait(trait: string, element: any): boolean {
return this.model.hasTrait(trait, element);
}
getNavigator(fromElement?: any, subTreeOnly?: boolean): INavigator<any> {
return new MappedNavigator(this.model.getNavigator(fromElement, subTreeOnly), i => i && i.getElement());
}
public dispose(): void {
this._onDispose.fire();
if (this.model !== null) {
this.model.dispose();
this.model = null;
}
if (this.view !== null) {
this.view.dispose();
this.view = null;
}
this.toDispose = Lifecycle.dispose(this.toDispose);
super.dispose();
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { EventEmitter } from 'vs/base/common/eventEmitter';
import { IIterator, ArrayIterator } from 'vs/base/common/iterator';
import { Item } from './treeModel';
export interface IViewItem {
model: Item;
top: number;
height: number;
}
export class HeightMap extends EventEmitter {
private heightMap: IViewItem[];
private indexes: { [item: string]: number; };
constructor() {
super();
this.heightMap = [];
this.indexes = {};
}
public getTotalHeight(): number {
var last = this.heightMap[this.heightMap.length - 1];
return !last ? 0 : last.top + last.height;
}
public onInsertItems(iterator: IIterator<Item>, afterItemId: string = null): number {
var item: Item;
var viewItem: IViewItem;
var i: number, j: number;
var totalSize: number;
var sizeDiff = 0;
if (afterItemId === null) {
i = 0;
totalSize = 0;
} else {
i = this.indexes[afterItemId] + 1;
viewItem = this.heightMap[i - 1];
if (!viewItem) {
console.error('view item doesnt exist');
return undefined;
}
totalSize = viewItem.top + viewItem.height;
}
var boundSplice = this.heightMap.splice.bind(this.heightMap, i, 0);
var itemsToInsert: IViewItem[] = [];
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);
sizeDiff += viewItem.height;
}
boundSplice.apply(this.heightMap, itemsToInsert);
for (j = i; j < this.heightMap.length; j++) {
viewItem = this.heightMap[j];
viewItem.top += sizeDiff;
this.indexes[viewItem.model.id] = j;
}
for (j = itemsToInsert.length - 1; j >= 0; j--) {
this.onInsertItem(itemsToInsert[j]);
}
for (j = this.heightMap.length - 1; j >= i; j--) {
this.onRefreshItem(this.heightMap[j]);
}
return sizeDiff;
}
public onInsertItem(item: IViewItem): void {
// noop
}
// Contiguous items
public onRemoveItems(iterator: IIterator<string>): void {
var itemId: string;
var viewItem: IViewItem;
var startIndex: number = null;
var i: number;
var sizeDiff = 0;
while (itemId = iterator.next()) {
i = this.indexes[itemId];
viewItem = this.heightMap[i];
if (!viewItem) {
console.error('view item doesnt exist');
return;
}
sizeDiff -= viewItem.height;
delete this.indexes[itemId];
this.onRemoveItem(viewItem);
if (startIndex === null) {
startIndex = i;
}
}
if (sizeDiff === 0) {
return;
}
this.heightMap.splice(startIndex, i - startIndex + 1);
for (i = startIndex; i < this.heightMap.length; i++) {
viewItem = this.heightMap[i];
viewItem.top += sizeDiff;
this.indexes[viewItem.model.id] = i;
this.onRefreshItem(viewItem);
}
}
public onRemoveItem(item: IViewItem): void {
// noop
}
public onRefreshItemSet(items: Item[]): void {
var sortedItems = items.sort((a, b) => this.indexes[a.id] - this.indexes[b.id]);
this.onRefreshItems(new ArrayIterator(sortedItems));
}
// Ordered, but not necessarily contiguous items
public onRefreshItems(iterator: IIterator<Item>): void {
var item: Item;
var viewItem: IViewItem;
var newHeight: number;
var i: number, j: number = null;
var cummDiff = 0;
while (item = iterator.next()) {
i = this.indexes[item.id];
for (; cummDiff !== 0 && j !== null && j < i; j++) {
viewItem = this.heightMap[j];
viewItem.top += cummDiff;
this.onRefreshItem(viewItem);
}
viewItem = this.heightMap[i];
newHeight = item.getHeight();
viewItem.top += cummDiff;
cummDiff += newHeight - viewItem.height;
viewItem.height = newHeight;
this.onRefreshItem(viewItem, true);
j = i + 1;
}
if (cummDiff !== 0 && j !== null) {
for (; j < this.heightMap.length; j++) {
viewItem = this.heightMap[j];
viewItem.top += cummDiff;
this.onRefreshItem(viewItem);
}
}
}
public onRefreshItem(item: IViewItem, needsRender: boolean = false): void {
// noop
}
public itemsCount(): number {
return this.heightMap.length;
}
public itemAt(position: number): string {
return this.heightMap[this.indexAt(position)].model.id;
}
public withItemsInRange(start: number, end: number, fn: (item: string) => void): void {
start = this.indexAt(start);
end = this.indexAt(end);
for (var i = start; i <= end; i++) {
fn(this.heightMap[i].model.id);
}
}
public indexAt(position: number): number {
var left = 0;
var right = this.heightMap.length;
var center: number;
var item: IViewItem;
// Binary search
while (left < right) {
center = Math.floor((left + right) / 2);
item = this.heightMap[center];
if (position < item.top) {
right = center;
} else if (position >= item.top + item.height) {
if (left === center) {
break;
}
left = center;
} else {
return center;
}
}
return this.heightMap.length;
}
public indexAfter(position: number): number {
return Math.min(this.indexAt(position) + 1, this.heightMap.length);
}
public itemAtIndex(index: number): IViewItem {
return this.heightMap[index];
}
public itemAfter(item: IViewItem): IViewItem {
return this.heightMap[this.indexes[item.model.id] + 1] || null;
}
protected createViewItem(item: Item): IViewItem {
throw new Error('not implemented');
}
public dispose(): void {
this.heightMap = null;
this.indexes = null;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,253 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import assert = require('assert');
import { ArrayIterator } from 'vs/base/common/iterator';
import { HeightMap, IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
function makeItem(id, height): any {
return {
id: id,
getHeight: function () { return height; },
isExpanded: function () { return false; },
getAllTraits: () => []
};
}
function makeItems(...args: any[]) {
var r = [];
for (var i = 0; i < args.length; i += 2) {
r.push(makeItem(args[i], args[i + 1]));
}
return r;
}
function makeNavigator(...args: any[]): any {
var items = makeItems.apply(null, args);
var i = 0;
return {
next: function () {
return items[i++] || null;
}
};
}
class TestHeightMap extends HeightMap {
protected createViewItem(item: any): IViewItem {
return {
model: item,
top: 0,
height: item.getHeight()
};
}
}
suite('TreeView - HeightMap', () => {
var rangeMap: HeightMap;
setup(() => {
rangeMap = new TestHeightMap();
rangeMap.onInsertItems(makeNavigator('a', 3, 'b', 30, 'c', 25, 'd', 2));
});
teardown(() => {
rangeMap.dispose();
rangeMap = null;
});
test('simple', () => {
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(32), 'b');
assert.equal(rangeMap.itemAt(33), 'c');
assert.equal(rangeMap.itemAt(40), 'c');
assert.equal(rangeMap.itemAt(57), 'c');
assert.equal(rangeMap.itemAt(58), 'd');
assert.equal(rangeMap.itemAt(59), 'd');
assert.throws(() => rangeMap.itemAt(60));
});
test('onInsertItems at beginning', () => {
var navigator = makeNavigator('x', 4, 'y', 20, 'z', 8);
rangeMap.onInsertItems(navigator);
assert.equal(rangeMap.itemAt(0), 'x');
assert.equal(rangeMap.itemAt(3), 'x');
assert.equal(rangeMap.itemAt(4), 'y');
assert.equal(rangeMap.itemAt(23), 'y');
assert.equal(rangeMap.itemAt(24), 'z');
assert.equal(rangeMap.itemAt(31), 'z');
assert.equal(rangeMap.itemAt(32), 'a');
assert.equal(rangeMap.itemAt(34), 'a');
assert.equal(rangeMap.itemAt(35), 'b');
assert.equal(rangeMap.itemAt(64), 'b');
assert.equal(rangeMap.itemAt(65), 'c');
assert.equal(rangeMap.itemAt(89), 'c');
assert.equal(rangeMap.itemAt(90), 'd');
assert.equal(rangeMap.itemAt(91), 'd');
assert.throws(() => rangeMap.itemAt(92));
});
test('onInsertItems in middle', () => {
var navigator = makeNavigator('x', 4, 'y', 20, 'z', 8);
rangeMap.onInsertItems(navigator, 'a');
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'x');
assert.equal(rangeMap.itemAt(6), 'x');
assert.equal(rangeMap.itemAt(7), 'y');
assert.equal(rangeMap.itemAt(26), 'y');
assert.equal(rangeMap.itemAt(27), 'z');
assert.equal(rangeMap.itemAt(34), 'z');
assert.equal(rangeMap.itemAt(35), 'b');
assert.equal(rangeMap.itemAt(64), 'b');
assert.equal(rangeMap.itemAt(65), 'c');
assert.equal(rangeMap.itemAt(89), 'c');
assert.equal(rangeMap.itemAt(90), 'd');
assert.equal(rangeMap.itemAt(91), 'd');
assert.throws(() => rangeMap.itemAt(92));
});
test('onInsertItems at end', () => {
var navigator = makeNavigator('x', 4, 'y', 20, 'z', 8);
rangeMap.onInsertItems(navigator, 'd');
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(32), 'b');
assert.equal(rangeMap.itemAt(33), 'c');
assert.equal(rangeMap.itemAt(57), 'c');
assert.equal(rangeMap.itemAt(58), 'd');
assert.equal(rangeMap.itemAt(59), 'd');
assert.equal(rangeMap.itemAt(60), 'x');
assert.equal(rangeMap.itemAt(63), 'x');
assert.equal(rangeMap.itemAt(64), 'y');
assert.equal(rangeMap.itemAt(83), 'y');
assert.equal(rangeMap.itemAt(84), 'z');
assert.equal(rangeMap.itemAt(91), 'z');
assert.throws(() => rangeMap.itemAt(92));
});
test('onRemoveItems at beginning', () => {
rangeMap.onRemoveItems(new ArrayIterator(['a', 'b']));
assert.equal(rangeMap.itemAt(0), 'c');
assert.equal(rangeMap.itemAt(24), 'c');
assert.equal(rangeMap.itemAt(25), 'd');
assert.equal(rangeMap.itemAt(26), 'd');
assert.throws(() => rangeMap.itemAt(27));
});
test('onRemoveItems in middle', () => {
rangeMap.onRemoveItems(new ArrayIterator(['c']));
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(32), 'b');
assert.equal(rangeMap.itemAt(33), 'd');
assert.equal(rangeMap.itemAt(34), 'd');
assert.throws(() => rangeMap.itemAt(35));
});
test('onRemoveItems at end', () => {
rangeMap.onRemoveItems(new ArrayIterator(['c', 'd']));
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(32), 'b');
assert.throws(() => rangeMap.itemAt(33));
});
test('onRefreshItems at beginning', () => {
var navigator = makeNavigator('a', 1, 'b', 1);
rangeMap.onRefreshItems(navigator);
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(1), 'b');
assert.equal(rangeMap.itemAt(2), 'c');
assert.equal(rangeMap.itemAt(26), 'c');
assert.equal(rangeMap.itemAt(27), 'd');
assert.equal(rangeMap.itemAt(28), 'd');
assert.throws(() => rangeMap.itemAt(29));
});
test('onRefreshItems in middle', () => {
var navigator = makeNavigator('b', 40, 'c', 4);
rangeMap.onRefreshItems(navigator);
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(42), 'b');
assert.equal(rangeMap.itemAt(43), 'c');
assert.equal(rangeMap.itemAt(46), 'c');
assert.equal(rangeMap.itemAt(47), 'd');
assert.equal(rangeMap.itemAt(48), 'd');
assert.throws(() => rangeMap.itemAt(49));
});
test('onRefreshItems at end', () => {
var navigator = makeNavigator('d', 22);
rangeMap.onRefreshItems(navigator);
assert.equal(rangeMap.itemAt(0), 'a');
assert.equal(rangeMap.itemAt(2), 'a');
assert.equal(rangeMap.itemAt(3), 'b');
assert.equal(rangeMap.itemAt(32), 'b');
assert.equal(rangeMap.itemAt(33), 'c');
assert.equal(rangeMap.itemAt(57), 'c');
assert.equal(rangeMap.itemAt(58), 'd');
assert.equal(rangeMap.itemAt(79), 'd');
assert.throws(() => rangeMap.itemAt(80));
});
test('withItemsInRange', () => {
var i = 0;
var itemsInRange = ['a', 'b'];
rangeMap.withItemsInRange(2, 27, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['a', 'b'];
rangeMap.withItemsInRange(0, 3, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['a'];
rangeMap.withItemsInRange(0, 2, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['a'];
rangeMap.withItemsInRange(0, 2, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['b', 'c'];
rangeMap.withItemsInRange(15, 39, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['a', 'b', 'c', 'd'];
rangeMap.withItemsInRange(1, 58, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
i = 0;
itemsInRange = ['c', 'd'];
rangeMap.withItemsInRange(45, 58, function (item) { assert.equal(item, itemsInRange[i++]); });
assert.equal(i, itemsInRange.length);
});
});