phosphor-tabs
Advanced tools
Comparing version 0.9.8 to 1.0.0-beta
@@ -1,3 +0,2 @@ | ||
export * from './tab'; | ||
export * from './tabbar'; | ||
export * from './tabpanel'; |
@@ -12,3 +12,2 @@ /*----------------------------------------------------------------------------- | ||
} | ||
__export(require('./tab')); | ||
__export(require('./tabbar')); | ||
@@ -15,0 +14,0 @@ __export(require('./tabpanel')); |
import { Message } from 'phosphor-messaging'; | ||
import { Property } from 'phosphor-properties'; | ||
import { IObservableList } from 'phosphor-observablelist'; | ||
import { IChangedArgs, Property } from 'phosphor-properties'; | ||
import { ISignal, Signal } from 'phosphor-signaling'; | ||
import { Widget } from 'phosphor-widget'; | ||
import { Tab } from './tab'; | ||
import { Title, Widget } from 'phosphor-widget'; | ||
/** | ||
* The arguments object for the [[tabDetachRequestedSignal]]. | ||
* An object which can be added to a tab bar. | ||
*/ | ||
export interface ITabDetachArgs { | ||
export interface ITabItem { | ||
/** | ||
* The tab of interest. | ||
* The title object which provides data for the item's tab. | ||
* | ||
* #### Notes | ||
* This should be a read-only property. | ||
*/ | ||
tab: Tab; | ||
/** | ||
* The index of the tab. | ||
*/ | ||
index: number; | ||
/** | ||
* The current mouse client X position. | ||
*/ | ||
clientX: number; | ||
/** | ||
* The current mouse client Y position. | ||
*/ | ||
clientY: number; | ||
title: Title; | ||
} | ||
/** | ||
* The arguments object for various tab bar signals | ||
* A widget which displays a list of tab items as a row of tabs. | ||
*/ | ||
export interface ITabIndexArgs { | ||
export declare class TabBar<T extends ITabItem> extends Widget { | ||
/** | ||
* The index associated with the tab. | ||
*/ | ||
index: number; | ||
/** | ||
* The tab associated with the signal. | ||
*/ | ||
tab: Tab; | ||
} | ||
/** | ||
* The arguments object for the [[tabMovedSignal]]. | ||
*/ | ||
export interface ITabMoveArgs { | ||
/** | ||
* The previous index of the tab. | ||
*/ | ||
fromIndex: number; | ||
/** | ||
* The current index of the tab. | ||
*/ | ||
toIndex: number; | ||
} | ||
/** | ||
* A widget which displays a row of tabs. | ||
* | ||
* #### Notes | ||
* A `TabBar` widget does not support child widgets. Adding children | ||
* to a `TabBar` will result in undefined behavior. | ||
*/ | ||
export declare class TabBar extends Widget { | ||
/** | ||
* Create the DOM node for a tab bar. | ||
@@ -66,50 +27,25 @@ */ | ||
/** | ||
* A signal emitted when a tab is moved. | ||
* A signal emitted when the user clicks a tab item's close icon. | ||
* | ||
* **See also:** [[tabMoved]] | ||
* **See also:** [[itemCloseRequested]] | ||
*/ | ||
static tabMovedSignal: Signal<TabBar, ITabMoveArgs>; | ||
static itemCloseRequestedSignal: Signal<TabBar<ITabItem>, ITabItem>; | ||
/** | ||
* A signal emitted when a tab is selected. | ||
* The property descriptor for the currently selected tab item. | ||
* | ||
* **See also:** [[tabSelected]] | ||
* **See also:** [[currentItem]] | ||
*/ | ||
static tabSelectedSignal: Signal<TabBar, ITabIndexArgs>; | ||
static currentItemProperty: Property<TabBar<ITabItem>, ITabItem>; | ||
/** | ||
* A signal emitted when the user clicks a tab close icon. | ||
* The property descriptor for the observable list of tab items. | ||
* | ||
* **See also:** [[tabCloseRequested] | ||
* **See also:** [[items]] | ||
*/ | ||
static tabCloseRequestedSignal: Signal<TabBar, ITabIndexArgs>; | ||
static itemsProperty: Property<TabBar<ITabItem>, IObservableList<ITabItem>>; | ||
/** | ||
* A signal emitted when a tab is dragged beyond the detach threshold. | ||
* The property descriptor for whether the tabs are user-movable. | ||
* | ||
* **See also:** [[tabDetachRequested]] | ||
*/ | ||
static tabDetachRequestedSignal: Signal<TabBar, ITabDetachArgs>; | ||
/** | ||
* The property descriptor for the previous tab. | ||
* | ||
* This controls which tab is selected after if selected tab is | ||
* removed. It is typically updated automatically. | ||
* | ||
* **See also:** [[previousTab]] | ||
*/ | ||
static previousTabProperty: Property<TabBar, Tab>; | ||
/** | ||
* The property descriptor for the selected tab. | ||
* | ||
* This controls which tab is selected in the tab bar. | ||
* | ||
* **See also:** [[selectedTab]] | ||
*/ | ||
static selectedTabProperty: Property<TabBar, Tab>; | ||
/** | ||
* The property descriptor for the tabs movable property | ||
* | ||
* This controls whether tabs are movable by the user. | ||
* | ||
* **See also:** [[tabsMovable]] | ||
*/ | ||
static tabsMovableProperty: Property<TabBar, boolean>; | ||
static tabsMovableProperty: Property<TabBar<ITabItem>, boolean>; | ||
/** | ||
@@ -124,56 +60,42 @@ * Construct a new tab bar. | ||
/** | ||
* A signal emitted when a tab is moved. | ||
* A signal emitted when the user clicks a tab item's close icon. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabMovedSignal]]. | ||
* This is a pure delegate to the [[itemCloseRequestedSignal]]. | ||
*/ | ||
tabMoved: ISignal<TabBar, ITabMoveArgs>; | ||
itemCloseRequested: ISignal<TabBar<T>, T>; | ||
/** | ||
* A signal emitted when a tab is selected. | ||
* Get the currently selected tab item. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabSelectedSignal]]. | ||
* This is a pure delegate to the [[currentItemProperty]]. | ||
*/ | ||
tabSelected: ISignal<TabBar, ITabIndexArgs>; | ||
/** | ||
* A signal emitted when the user clicks a tab close icon. | ||
* Set the currently selected tab item. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabCloseRequestedSignal]]. | ||
* This is a pure delegate to the [[currentItemProperty]]. | ||
*/ | ||
tabCloseRequested: ISignal<TabBar, ITabIndexArgs>; | ||
currentItem: T; | ||
/** | ||
* A signal emitted when a tab is dragged beyond the detach threshold. | ||
* A signal emitted when the current tab item is changed. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabDetachRequestedSignal]]. | ||
* This is the notify signal for the [[currentItemProperty]]. | ||
*/ | ||
tabDetachRequested: ISignal<TabBar, ITabDetachArgs>; | ||
currentItemChanged: ISignal<TabBar<T>, IChangedArgs<T>>; | ||
/** | ||
* Get the previously selected tab. | ||
* Get the list of tab items for the tab bar. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[previousTabProperty]]. | ||
* This is a pure delegate to the [[itemsProperty]]. | ||
*/ | ||
/** | ||
* Set the previously selected tab. | ||
* Set the list tab items for the tab bar. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[previousTabProperty]]. | ||
* This is a pure delegate to the [[itemsProperty]]. | ||
*/ | ||
previousTab: Tab; | ||
items: IObservableList<T>; | ||
/** | ||
* Get the selected tab. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[selectedTabProperty]]. | ||
*/ | ||
/** | ||
* Set the selected tab. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[selectedTabProperty]]. | ||
*/ | ||
selectedTab: Tab; | ||
/** | ||
* Get whether the tabs are movable by the user. | ||
@@ -192,161 +114,78 @@ * | ||
/** | ||
* Get a shallow copy of the array of tabs. | ||
* Get the tab bar header node. | ||
* | ||
* #### Notes | ||
* When only iterating over the tabs, it can be faster to use | ||
* the tab query methods, which do not perform a copy. | ||
* | ||
* **See also:** [[tabCount]], [[tabAt]] | ||
* This can be used to add extra header content. | ||
*/ | ||
headerNode: HTMLElement; | ||
/** | ||
* Set the tabs for the tab bar. | ||
* Get the tab bar body node. | ||
* | ||
* #### Notes | ||
* This will clear the current tabs and add the specified tabs. | ||
* Depending on the desired outcome, it can be more efficient to | ||
* use one of the tab manipulation methods. | ||
* | ||
* **See also:** [[addTab]], [[insertTab]], [[removeTab]] | ||
* This can be used to add extra body content. | ||
*/ | ||
tabs: Tab[]; | ||
bodyNode: HTMLElement; | ||
/** | ||
* Get the number of tabs in the tab bar. | ||
* Get the tab bar content node. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
* | ||
* **See also:** [[tabs]], [[tabAt]] | ||
* This is the node which holds the tab nodes. Modifying the content | ||
* of this node indiscriminately can lead to undesired behavior. | ||
*/ | ||
tabCount: number; | ||
contentNode: HTMLElement; | ||
/** | ||
* Get the tab at a specific index. | ||
* Get the tab bar footer node. | ||
* | ||
* @param index - The index of the tab of interest. | ||
* | ||
* @returns The tab at the specified index, or `undefined` if the | ||
* index is out of range. | ||
* | ||
* **See also:** [[tabCount]], [[tabIndex]] | ||
* #### Notes | ||
* This can be used to add extra footer content. | ||
*/ | ||
tabAt(index: number): Tab; | ||
footerNode: HTMLElement; | ||
/** | ||
* Get the index of a specific tab. | ||
* Handle the DOM events for the tab bar. | ||
* | ||
* @param tab - The tab of interest. | ||
* @param event - The DOM event sent to the tab bar. | ||
* | ||
* @returns The index of the specified tab, or `-1` if the tab is | ||
* not contained within the tab bar. | ||
* | ||
* **See also:** [[tabCount]], [[tabAt]] | ||
*/ | ||
tabIndex(tab: Tab): number; | ||
/** | ||
* Add a tab to the end of the tab bar. | ||
* | ||
* @param tab - The tab to add to the tab bar. | ||
* | ||
* @returns The new index of the tab. | ||
* | ||
* #### Notes | ||
* If the tab is already contained within the tab bar, it will first | ||
* be removed. | ||
* | ||
* The tab *must not* be contained by any other tab bar. | ||
* | ||
* **See also:** [[insertTab]], [[moveTab]] | ||
* This method implements the DOM `EventListener` interface and is | ||
* called in response to events on the tab bar's DOM node. It should | ||
* not be called directly by user code. | ||
*/ | ||
addTab(tab: Tab): number; | ||
handleEvent(event: Event): void; | ||
/** | ||
* Insert a tab into the tab bar at the given index. | ||
* Process a message sent to the tab bar. | ||
* | ||
* @param index - The index at which to insert the tab. This will be | ||
* clamped to the bounds of the tabs. | ||
* @param msg - The message sent to the tab bar. | ||
* | ||
* @param tab - The tab to add to the tab bar. | ||
* | ||
* @returns The new index of the tab. | ||
* | ||
* #### Notes | ||
* If the tab is already contained within the tab bar, it will first | ||
* be removed. | ||
* | ||
* The tab *must not* be contained by any other tab bar. | ||
* | ||
* **See also:** [[addTab]], [[moveTab]] | ||
* Subclasses may reimplement this method as needed. | ||
*/ | ||
insertTab(index: number, tab: Tab): number; | ||
processMessage(msg: Message): void; | ||
/** | ||
* Move a tab from one index to another. | ||
* Release the mouse and restore the non-dragged tab positions. | ||
* | ||
* @param fromIndex - The index of the tab to move. | ||
* | ||
* @param toIndex - The target index of the tab. | ||
* | ||
* @returns `true` if the move was successful, or `false` if either | ||
* index is out of range. | ||
* | ||
* #### Notes | ||
* This can be more efficient than re-inserting an existing tab. | ||
* | ||
* **See also:** [[addTab]], [[insertTab]] | ||
* This will cause the tab bar to stop handling mouse events and to | ||
* restore the tabs their non-dragged positions. It is intended to | ||
* be called by subclasses which implement [[onTearOffRequest]]. | ||
*/ | ||
moveTab(fromIndex: number, toIndex: number): boolean; | ||
protected releaseMouse(): void; | ||
/** | ||
* Remove the tab at a specific index. | ||
* A message handler invoked on a `'tear-off-request'` message. | ||
* | ||
* @param index - The index of the tab of interest. | ||
* | ||
* @returns The removed tab, or `undefined` if the index is out | ||
* of range. | ||
* | ||
* **See also:** [[removeTab]], [[clearTabs]] | ||
*/ | ||
removeTabAt(index: number): Tab; | ||
/** | ||
* Remove a specific tab from the tab bar. | ||
* | ||
* @param tab - The tab of interest. | ||
* | ||
* @returns The index occupied by the tab, or `-1` if the tab is | ||
* not contained by the tab bar. | ||
* | ||
* **See also:** [[removeTabAt]], [[clearTabs]] | ||
*/ | ||
removeTab(tab: Tab): number; | ||
/** | ||
* Remove all tabs from the tab bar. | ||
* | ||
* **See also:** [[removeTab]], [[removeTabAt]] | ||
*/ | ||
clearTabs(): void; | ||
/** | ||
* Add a tab to the tab bar at the given client X position. | ||
* | ||
* @param tab - The tab to attach to the tab bar. | ||
* | ||
* @param clientX - The current client X mouse position. | ||
* | ||
* @returns `true` if the tab was attached, `false` otherwise. | ||
* | ||
* #### Notes | ||
* This method is intended for use by code which supports tear-off | ||
* tab interfaces. It will insert the tab at the specified location | ||
* and grab the mouse to continue the tab drag. It assumes that the | ||
* left mouse button is currently pressed. | ||
* This may be reimplemented by subclasses to support tear-off tabs. | ||
* | ||
* This is a no-op if the tab is already contained by the tab bar, | ||
* if the tabs are not movable, or if a tab drag is in progress. | ||
*/ | ||
attachTab(tab: Tab, clientX: number): boolean; | ||
/** | ||
* Handle the DOM events for the tab bar. | ||
* The reimplementation should take whatever action is necessary for | ||
* its use case to continue the drag from the given client position. | ||
* This will typically involve creating a new DOM node to represent | ||
* the drag item, and may or may not include removing the specified | ||
* item from the tab bar. | ||
* | ||
* @param event - The DOM event sent to the tab bar. | ||
* If the reimplementation handles the tear-off, it should call the | ||
* [[releaseMouse]] method so that the tab bar ceases its handling | ||
* of mouse events. | ||
* | ||
* #### Notes | ||
* This method implements the DOM `EventListener` interface and is | ||
* called in response to events on the tab bar's DOM node. It should | ||
* not be called directly by user code. | ||
* The default implementation of this handler is a no-op. | ||
*/ | ||
handleEvent(event: Event): void; | ||
protected onTearOffRequest(msg: TearOffMessage<T>): void; | ||
/** | ||
@@ -357,6 +196,12 @@ * A message handler invoked on an `'after-attach'` message. | ||
/** | ||
* A message handler invoked on a `'before-dettach'` message. | ||
* A message handler invoked on a `'before-detach'` message. | ||
*/ | ||
protected onBeforeDetach(msg: Message): void; | ||
/** | ||
* A message handler invoked on an `'update-request'` message. | ||
* | ||
* This handler updates the flex order and z-index of the tabs. | ||
*/ | ||
protected onUpdateRequest(msg: Message): void; | ||
/** | ||
* Handle the `'click'` event for the tab bar. | ||
@@ -378,41 +223,86 @@ */ | ||
/** | ||
* Update the drag tab position for the given mouse X position. | ||
* | ||
* This method is a no-op if an active drag is not in progress. | ||
* Release the mouse and restore the non-dragged tab positions. | ||
*/ | ||
private _updateDragPosition(clientX); | ||
private _releaseMouse(); | ||
/** | ||
* Release the mouse grab and restore the tab positions. | ||
* The coerce handler for the [[currentItemProperty]]. | ||
*/ | ||
private _releaseMouse(); | ||
private _coerceCurrentItem(item); | ||
/** | ||
* Insert a new tab into the tab bar at the given index. | ||
* | ||
* The tab should not already be contained in the tab bar. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The change handler for the [[currentItemProperty]]. | ||
*/ | ||
private _insertTab(index, tab); | ||
private _onCurrentItemChanged(oldItem, newItem); | ||
/** | ||
* Move a tab to a new index in the tab bar. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The change handler for the [[itemsProperty]]. | ||
*/ | ||
private _moveTab(fromIndex, toIndex); | ||
private _onItemsChanged(oldList, newList); | ||
/** | ||
* Remove and return the tab at the given index. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The change handler for the items list `changed` signal. | ||
*/ | ||
private _removeTab(index); | ||
private _onItemsListChanged(sender, args); | ||
/** | ||
* Update the Z-index and flex order of the tabs. | ||
* The handler invoked on a items list change of type `Add`. | ||
*/ | ||
private _updateTabOrdering(); | ||
private _onItemsListAdd(args); | ||
/** | ||
* The change handler for the [[selectedTabProperty]]. | ||
* The handler invoked on a items list change of type `Move`. | ||
*/ | ||
private _onSelectedTabChanged(old, tab); | ||
private _onItemsListMove(args); | ||
/** | ||
* The handler invoked on a items list change of type `Remove`. | ||
*/ | ||
private _onItemsListRemove(args); | ||
/** | ||
* The handler invoked on a items list change of type `Replace`. | ||
*/ | ||
private _onItemsListReplace(args); | ||
/** | ||
* The handler invoked on a items list change of type `Set`. | ||
*/ | ||
private _onItemsListSet(args); | ||
private _tabs; | ||
private _dragData; | ||
} | ||
/** | ||
* A message class for `'tear-off-request'` messages. | ||
* | ||
* #### Notes | ||
* A message of this type is sent to a tab bar when the user drags | ||
* a tab beyond the tear-off threshold which surrounds the tab bar. | ||
*/ | ||
export declare class TearOffMessage<T extends ITabItem> extends Message { | ||
/** | ||
* Construct a new tear off request message. | ||
* | ||
* @param item - The tab item being dragged by the user. | ||
* | ||
* @param clientX - The current client X position of the mouse. | ||
* | ||
* @param clientY - The current client Y position of the mouse. | ||
*/ | ||
constructor(item: T, clientX: number, clientY: number); | ||
/** | ||
* The tab item being dragged by the user. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
item: T; | ||
/** | ||
* The current client X position of the mouse. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
clientX: number; | ||
/** | ||
* The current client Y position of the mouse. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
clientY: number; | ||
private _item; | ||
private _clientX; | ||
private _clientY; | ||
} |
1183
lib/tabbar.js
@@ -16,2 +16,5 @@ /*----------------------------------------------------------------------------- | ||
var phosphor_domutil_1 = require('phosphor-domutil'); | ||
var phosphor_messaging_1 = require('phosphor-messaging'); | ||
var phosphor_nodewrapper_1 = require('phosphor-nodewrapper'); | ||
var phosphor_observablelist_1 = require('phosphor-observablelist'); | ||
var phosphor_properties_1 = require('phosphor-properties'); | ||
@@ -25,22 +28,46 @@ var phosphor_signaling_1 = require('phosphor-signaling'); | ||
/** | ||
* The class name added to the tab bar header div. | ||
* The class name added to the tab bar header node. | ||
*/ | ||
var HEADER_CLASS = 'p-TabBar-header'; | ||
/** | ||
* The class name added to the tab bar content div. | ||
* The class name added to the tab bar body node. | ||
*/ | ||
var BODY_CLASS = 'p-TabBar-body'; | ||
/** | ||
* The class name added to the tab bar content node. | ||
*/ | ||
var CONTENT_CLASS = 'p-TabBar-content'; | ||
/** | ||
* The class name added to the tab bar footer div. | ||
* The class name added to the tab bar footer node. | ||
*/ | ||
var FOOTER_CLASS = 'p-TabBar-footer'; | ||
/** | ||
* A class name added to the tab bar when dragging. | ||
* The class name added to Tab instances. | ||
*/ | ||
var TAB_CLASS = 'p-Tab'; | ||
/** | ||
* The class name added to a tab text node. | ||
*/ | ||
var TEXT_CLASS = 'p-Tab-text'; | ||
/** | ||
* The class name added to a tab icon node. | ||
*/ | ||
var ICON_CLASS = 'p-Tab-icon'; | ||
/** | ||
* The class name added to a tab close node. | ||
*/ | ||
var CLOSE_CLASS = 'p-Tab-close'; | ||
/** | ||
* The class name added to a tab bar and tab when dragging. | ||
*/ | ||
var DRAGGING_CLASS = 'p-mod-dragging'; | ||
/** | ||
* A class name added to the active drag tab. | ||
* The class name added to the current tab. | ||
*/ | ||
var ACTIVE_CLASS = 'p-mod-active'; | ||
var CURRENT_CLASS = 'p-mod-current'; | ||
/** | ||
* The class name added to a closable tab. | ||
*/ | ||
var CLOSABLE_CLASS = 'p-mod-closable'; | ||
/** | ||
* A class name added to the first tab in the tab bar. | ||
@@ -50,3 +77,3 @@ */ | ||
/** | ||
* A class name adde to the last tab in the tab bar. | ||
* A class name added to the last tab in the tab bar. | ||
*/ | ||
@@ -59,15 +86,11 @@ var LAST_CLASS = 'p-mod-last'; | ||
/** | ||
* The detach distance threshold. | ||
* The tear-off distance threshold. | ||
*/ | ||
var DETACH_THRESHOLD = 20; | ||
var TEAR_OFF_THRESHOLD = 20; | ||
/** | ||
* The tab transition duration. Keep in sync with CSS. | ||
* The tab transition duration. | ||
*/ | ||
var TRANSITION_DURATION = 150; | ||
var TRANSITION_DURATION = 150; // Keep in sync with CSS. | ||
/** | ||
* A widget which displays a row of tabs. | ||
* | ||
* #### Notes | ||
* A `TabBar` widget does not support child widgets. Adding children | ||
* to a `TabBar` will result in undefined behavior. | ||
* A widget which displays a list of tab items as a row of tabs. | ||
*/ | ||
@@ -91,9 +114,12 @@ var TabBar = (function (_super) { | ||
var header = document.createElement('div'); | ||
var content = document.createElement('div'); | ||
var body = document.createElement('div'); | ||
var content = document.createElement('ul'); | ||
var footer = document.createElement('div'); | ||
header.className = HEADER_CLASS; | ||
body.className = BODY_CLASS; | ||
content.className = CONTENT_CLASS; | ||
footer.className = FOOTER_CLASS; | ||
body.appendChild(content); | ||
node.appendChild(header); | ||
node.appendChild(content); | ||
node.appendChild(body); | ||
node.appendChild(footer); | ||
@@ -107,14 +133,15 @@ return node; | ||
this._releaseMouse(); | ||
this._tabs.forEach(function (tab) { tab.dispose(); }); | ||
this._tabs.length = 0; | ||
_super.prototype.dispose.call(this); | ||
}; | ||
Object.defineProperty(TabBar.prototype, "tabMoved", { | ||
Object.defineProperty(TabBar.prototype, "itemCloseRequested", { | ||
/** | ||
* A signal emitted when a tab is moved. | ||
* A signal emitted when the user clicks a tab item's close icon. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabMovedSignal]]. | ||
* This is a pure delegate to the [[itemCloseRequestedSignal]]. | ||
*/ | ||
get: function () { | ||
return TabBar.tabMovedSignal.bind(this); | ||
return TabBar.itemCloseRequestedSignal.bind(this); | ||
}, | ||
@@ -124,24 +151,20 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabSelected", { | ||
Object.defineProperty(TabBar.prototype, "currentItem", { | ||
/** | ||
* A signal emitted when a tab is selected. | ||
* Get the currently selected tab item. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabSelectedSignal]]. | ||
* This is a pure delegate to the [[currentItemProperty]]. | ||
*/ | ||
get: function () { | ||
return TabBar.tabSelectedSignal.bind(this); | ||
return TabBar.currentItemProperty.get(this); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabCloseRequested", { | ||
/** | ||
* A signal emitted when the user clicks a tab close icon. | ||
* Set the currently selected tab item. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabCloseRequestedSignal]]. | ||
* This is a pure delegate to the [[currentItemProperty]]. | ||
*/ | ||
get: function () { | ||
return TabBar.tabCloseRequestedSignal.bind(this); | ||
set: function (value) { | ||
TabBar.currentItemProperty.set(this, value); | ||
}, | ||
@@ -151,11 +174,11 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabDetachRequested", { | ||
Object.defineProperty(TabBar.prototype, "currentItemChanged", { | ||
/** | ||
* A signal emitted when a tab is dragged beyond the detach threshold. | ||
* A signal emitted when the current tab item is changed. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabDetachRequestedSignal]]. | ||
* This is the notify signal for the [[currentItemProperty]]. | ||
*/ | ||
get: function () { | ||
return TabBar.tabDetachRequestedSignal.bind(this); | ||
return TabBar.currentItemProperty.notify.bind(this); | ||
}, | ||
@@ -165,20 +188,20 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "previousTab", { | ||
Object.defineProperty(TabBar.prototype, "items", { | ||
/** | ||
* Get the previously selected tab. | ||
* Get the list of tab items for the tab bar. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[previousTabProperty]]. | ||
* This is a pure delegate to the [[itemsProperty]]. | ||
*/ | ||
get: function () { | ||
return TabBar.previousTabProperty.get(this); | ||
return TabBar.itemsProperty.get(this); | ||
}, | ||
/** | ||
* Set the previously selected tab. | ||
* Set the list tab items for the tab bar. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[previousTabProperty]]. | ||
* This is a pure delegate to the [[itemsProperty]]. | ||
*/ | ||
set: function (value) { | ||
TabBar.previousTabProperty.set(this, value); | ||
TabBar.itemsProperty.set(this, value); | ||
}, | ||
@@ -188,20 +211,20 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "selectedTab", { | ||
Object.defineProperty(TabBar.prototype, "tabsMovable", { | ||
/** | ||
* Get the selected tab. | ||
* Get whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[selectedTabProperty]]. | ||
* This is a pure delegate to the [[tabsMovableProperty]]. | ||
*/ | ||
get: function () { | ||
return TabBar.selectedTabProperty.get(this); | ||
return TabBar.tabsMovableProperty.get(this); | ||
}, | ||
/** | ||
* Set the selected tab. | ||
* Set whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[selectedTabProperty]]. | ||
* This is a pure delegate to the [[tabsMovableProperty]]. | ||
*/ | ||
set: function (value) { | ||
TabBar.selectedTabProperty.set(this, value); | ||
TabBar.tabsMovableProperty.set(this, value); | ||
}, | ||
@@ -211,20 +234,24 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabsMovable", { | ||
Object.defineProperty(TabBar.prototype, "headerNode", { | ||
/** | ||
* Get whether the tabs are movable by the user. | ||
* Get the tab bar header node. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabsMovableProperty]]. | ||
* This can be used to add extra header content. | ||
*/ | ||
get: function () { | ||
return TabBar.tabsMovableProperty.get(this); | ||
return this.node.getElementsByClassName(HEADER_CLASS)[0]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TabBar.prototype, "bodyNode", { | ||
/** | ||
* Set whether the tabs are movable by the user. | ||
* Get the tab bar body node. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[tabsMovableProperty]]. | ||
* This can be used to add extra body content. | ||
*/ | ||
set: function (value) { | ||
TabBar.tabsMovableProperty.set(this, value); | ||
get: function () { | ||
return this.node.getElementsByClassName(BODY_CLASS)[0]; | ||
}, | ||
@@ -234,44 +261,25 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabs", { | ||
Object.defineProperty(TabBar.prototype, "contentNode", { | ||
/** | ||
* Get a shallow copy of the array of tabs. | ||
* Get the tab bar content node. | ||
* | ||
* #### Notes | ||
* When only iterating over the tabs, it can be faster to use | ||
* the tab query methods, which do not perform a copy. | ||
* | ||
* **See also:** [[tabCount]], [[tabAt]] | ||
* This is the node which holds the tab nodes. Modifying the content | ||
* of this node indiscriminately can lead to undesired behavior. | ||
*/ | ||
get: function () { | ||
return this._tabs.slice(); | ||
return this.node.getElementsByClassName(CONTENT_CLASS)[0]; | ||
}, | ||
/** | ||
* Set the tabs for the tab bar. | ||
* | ||
* #### Notes | ||
* This will clear the current tabs and add the specified tabs. | ||
* Depending on the desired outcome, it can be more efficient to | ||
* use one of the tab manipulation methods. | ||
* | ||
* **See also:** [[addTab]], [[insertTab]], [[removeTab]] | ||
*/ | ||
set: function (tabs) { | ||
var _this = this; | ||
this.clearTabs(); | ||
tabs.forEach(function (tab) { return _this.addTab(tab); }); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TabBar.prototype, "tabCount", { | ||
Object.defineProperty(TabBar.prototype, "footerNode", { | ||
/** | ||
* Get the number of tabs in the tab bar. | ||
* Get the tab bar footer node. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
* | ||
* **See also:** [[tabs]], [[tabAt]] | ||
* This can be used to add extra footer content. | ||
*/ | ||
get: function () { | ||
return this._tabs.length; | ||
return this.node.getElementsByClassName(FOOTER_CLASS)[0]; | ||
}, | ||
@@ -282,184 +290,2 @@ enumerable: true, | ||
/** | ||
* Get the tab at a specific index. | ||
* | ||
* @param index - The index of the tab of interest. | ||
* | ||
* @returns The tab at the specified index, or `undefined` if the | ||
* index is out of range. | ||
* | ||
* **See also:** [[tabCount]], [[tabIndex]] | ||
*/ | ||
TabBar.prototype.tabAt = function (index) { | ||
return this._tabs[index | 0]; | ||
}; | ||
/** | ||
* Get the index of a specific tab. | ||
* | ||
* @param tab - The tab of interest. | ||
* | ||
* @returns The index of the specified tab, or `-1` if the tab is | ||
* not contained within the tab bar. | ||
* | ||
* **See also:** [[tabCount]], [[tabAt]] | ||
*/ | ||
TabBar.prototype.tabIndex = function (tab) { | ||
return this._tabs.indexOf(tab); | ||
}; | ||
/** | ||
* Add a tab to the end of the tab bar. | ||
* | ||
* @param tab - The tab to add to the tab bar. | ||
* | ||
* @returns The new index of the tab. | ||
* | ||
* #### Notes | ||
* If the tab is already contained within the tab bar, it will first | ||
* be removed. | ||
* | ||
* The tab *must not* be contained by any other tab bar. | ||
* | ||
* **See also:** [[insertTab]], [[moveTab]] | ||
*/ | ||
TabBar.prototype.addTab = function (tab) { | ||
return this.insertTab(this._tabs.length, tab); | ||
}; | ||
/** | ||
* Insert a tab into the tab bar at the given index. | ||
* | ||
* @param index - The index at which to insert the tab. This will be | ||
* clamped to the bounds of the tabs. | ||
* | ||
* @param tab - The tab to add to the tab bar. | ||
* | ||
* @returns The new index of the tab. | ||
* | ||
* #### Notes | ||
* If the tab is already contained within the tab bar, it will first | ||
* be removed. | ||
* | ||
* The tab *must not* be contained by any other tab bar. | ||
* | ||
* **See also:** [[addTab]], [[moveTab]] | ||
*/ | ||
TabBar.prototype.insertTab = function (index, tab) { | ||
this.removeTab(tab); | ||
return this._insertTab(index, tab); | ||
}; | ||
/** | ||
* Move a tab from one index to another. | ||
* | ||
* @param fromIndex - The index of the tab to move. | ||
* | ||
* @param toIndex - The target index of the tab. | ||
* | ||
* @returns `true` if the move was successful, or `false` if either | ||
* index is out of range. | ||
* | ||
* #### Notes | ||
* This can be more efficient than re-inserting an existing tab. | ||
* | ||
* **See also:** [[addTab]], [[insertTab]] | ||
*/ | ||
TabBar.prototype.moveTab = function (fromIndex, toIndex) { | ||
this._releaseMouse(); | ||
return this._moveTab(fromIndex, toIndex); | ||
}; | ||
/** | ||
* Remove the tab at a specific index. | ||
* | ||
* @param index - The index of the tab of interest. | ||
* | ||
* @returns The removed tab, or `undefined` if the index is out | ||
* of range. | ||
* | ||
* **See also:** [[removeTab]], [[clearTabs]] | ||
*/ | ||
TabBar.prototype.removeTabAt = function (index) { | ||
this._releaseMouse(); | ||
return this._removeTab(index); | ||
}; | ||
/** | ||
* Remove a specific tab from the tab bar. | ||
* | ||
* @param tab - The tab of interest. | ||
* | ||
* @returns The index occupied by the tab, or `-1` if the tab is | ||
* not contained by the tab bar. | ||
* | ||
* **See also:** [[removeTabAt]], [[clearTabs]] | ||
*/ | ||
TabBar.prototype.removeTab = function (tab) { | ||
this._releaseMouse(); | ||
var i = this._tabs.indexOf(tab); | ||
if (i !== -1) | ||
this._removeTab(i); | ||
return i; | ||
}; | ||
/** | ||
* Remove all tabs from the tab bar. | ||
* | ||
* **See also:** [[removeTab]], [[removeTabAt]] | ||
*/ | ||
TabBar.prototype.clearTabs = function () { | ||
while (this._tabs.length > 0) { | ||
this.removeTabAt(this._tabs.length - 1); | ||
} | ||
}; | ||
/** | ||
* Add a tab to the tab bar at the given client X position. | ||
* | ||
* @param tab - The tab to attach to the tab bar. | ||
* | ||
* @param clientX - The current client X mouse position. | ||
* | ||
* @returns `true` if the tab was attached, `false` otherwise. | ||
* | ||
* #### Notes | ||
* This method is intended for use by code which supports tear-off | ||
* tab interfaces. It will insert the tab at the specified location | ||
* and grab the mouse to continue the tab drag. It assumes that the | ||
* left mouse button is currently pressed. | ||
* | ||
* This is a no-op if the tab is already contained by the tab bar, | ||
* if the tabs are not movable, or if a tab drag is in progress. | ||
*/ | ||
TabBar.prototype.attachTab = function (tab, clientX) { | ||
// Bail if there is a drag in progress or the tabs aren't movable. | ||
if (this._dragData || !this.tabsMovable) { | ||
return false; | ||
} | ||
// Bail if the tab is already part of the tab bar. | ||
if (this._tabs.indexOf(tab) !== -1) { | ||
return false; | ||
} | ||
// Insert and select the new tab. | ||
var index = this._tabs.length; | ||
this._insertTab(index, tab); | ||
this.selectedTab = tab; | ||
// Setup the drag data object. | ||
var content = this.node.firstChild.nextSibling; | ||
var tabRect = tab.node.getBoundingClientRect(); | ||
var data = this._dragData = new DragData(); | ||
data.tab = tab; | ||
data.tabIndex = index; | ||
data.tabLeft = tab.node.offsetLeft; | ||
data.tabWidth = tabRect.width; | ||
data.pressX = tabRect.left + Math.floor(0.4 * tabRect.width); | ||
data.pressY = tabRect.top + (tabRect.height >> 1); | ||
data.tabPressX = Math.floor(0.4 * tabRect.width); | ||
data.tabLayout = snapTabLayout(this._tabs); | ||
data.contentRect = content.getBoundingClientRect(); | ||
data.cursorGrab = phosphor_domutil_1.overrideCursor('default'); | ||
data.dragActive = true; | ||
// Add the extra mouse event listeners. | ||
document.addEventListener('mouseup', this, true); | ||
document.addEventListener('mousemove', this, true); | ||
// Add the dragging style classes. | ||
tab.addClass(ACTIVE_CLASS); | ||
this.addClass(DRAGGING_CLASS); | ||
// Update the drag tab position. | ||
this._updateDragPosition(clientX); | ||
return true; | ||
}; | ||
/** | ||
* Handle the DOM events for the tab bar. | ||
@@ -491,16 +317,82 @@ * | ||
/** | ||
* Process a message sent to the tab bar. | ||
* | ||
* @param msg - The message sent to the tab bar. | ||
* | ||
* #### Notes | ||
* Subclasses may reimplement this method as needed. | ||
*/ | ||
TabBar.prototype.processMessage = function (msg) { | ||
if (msg.type === 'tear-off-request') { | ||
this.onTearOffRequest(msg); | ||
} | ||
else { | ||
_super.prototype.processMessage.call(this, msg); | ||
} | ||
}; | ||
/** | ||
* Release the mouse and restore the non-dragged tab positions. | ||
* | ||
* #### Notes | ||
* This will cause the tab bar to stop handling mouse events and to | ||
* restore the tabs their non-dragged positions. It is intended to | ||
* be called by subclasses which implement [[onTearOffRequest]]. | ||
*/ | ||
TabBar.prototype.releaseMouse = function () { | ||
this._releaseMouse(); | ||
}; | ||
/** | ||
* A message handler invoked on a `'tear-off-request'` message. | ||
* | ||
* #### Notes | ||
* This may be reimplemented by subclasses to support tear-off tabs. | ||
* | ||
* The reimplementation should take whatever action is necessary for | ||
* its use case to continue the drag from the given client position. | ||
* This will typically involve creating a new DOM node to represent | ||
* the drag item, and may or may not include removing the specified | ||
* item from the tab bar. | ||
* | ||
* If the reimplementation handles the tear-off, it should call the | ||
* [[releaseMouse]] method so that the tab bar ceases its handling | ||
* of mouse events. | ||
* | ||
* The default implementation of this handler is a no-op. | ||
*/ | ||
TabBar.prototype.onTearOffRequest = function (msg) { }; | ||
/** | ||
* A message handler invoked on an `'after-attach'` message. | ||
*/ | ||
TabBar.prototype.onAfterAttach = function (msg) { | ||
this.node.addEventListener('click', this); | ||
this.node.addEventListener('mousedown', this); | ||
this.node.addEventListener('click', this); | ||
}; | ||
/** | ||
* A message handler invoked on a `'before-dettach'` message. | ||
* A message handler invoked on a `'before-detach'` message. | ||
*/ | ||
TabBar.prototype.onBeforeDetach = function (msg) { | ||
this.node.removeEventListener('click', this); | ||
this.node.removeEventListener('mousedown', this); | ||
this.node.removeEventListener('click', this); | ||
}; | ||
/** | ||
* A message handler invoked on an `'update-request'` message. | ||
* | ||
* This handler updates the flex order and z-index of the tabs. | ||
*/ | ||
TabBar.prototype.onUpdateRequest = function (msg) { | ||
for (var i = 0, n = this._tabs.length, k = n - 1; i < n; ++i) { | ||
var tab = this._tabs[i]; | ||
var style = tab.node.style; | ||
if (tab.hasClass(CURRENT_CLASS)) { | ||
style.zIndex = n + ''; | ||
} | ||
else { | ||
style.zIndex = k-- + ''; | ||
} | ||
style.order = i + ''; | ||
tab.toggleClass(FIRST_CLASS, i === 0); | ||
tab.toggleClass(LAST_CLASS, i === n - 1); | ||
} | ||
}; | ||
/** | ||
* Handle the `'click'` event for the tab bar. | ||
@@ -521,8 +413,6 @@ */ | ||
event.stopPropagation(); | ||
// If the click was on a node contained by the close icon node | ||
// of a closable tab, emit the `tabCloseRequested` signal. | ||
// Emit the close requested signal if the close icon was clicked. | ||
var tab = this._tabs[index]; | ||
var target = event.target; | ||
if (tab.closable && tab.closeIconNode.contains(target)) { | ||
this.tabCloseRequested.emit({ index: index, tab: tab }); | ||
if (tab.closeNode.contains(event.target)) { | ||
this.itemCloseRequested.emit(tab.item); | ||
} | ||
@@ -542,3 +432,3 @@ }; | ||
} | ||
// Do nothing of the press is not on a tab. | ||
// Do nothing if the press is not on a tab. | ||
var index = hitTestTabs(this._tabs, event.clientX, event.clientY); | ||
@@ -551,5 +441,5 @@ if (index < 0) { | ||
event.stopPropagation(); | ||
// Do nothing further if the press was on the tab close icon. | ||
// Do nothing if the press was on a close icon node. | ||
var tab = this._tabs[index]; | ||
if (tab.closeIconNode.contains(event.target)) { | ||
if (tab.closeNode.contains(event.target)) { | ||
return; | ||
@@ -571,4 +461,4 @@ } | ||
} | ||
// Update the selected tab to the pressed tab. | ||
this.selectedTab = tab; | ||
// Update the current item to the pressed item. | ||
this.currentItem = tab.item; | ||
}; | ||
@@ -584,8 +474,8 @@ /** | ||
// Bail if there is no drag in progress. | ||
if (!this._dragData) { | ||
var data = this._dragData; | ||
if (!data) { | ||
return; | ||
} | ||
// Check to see if the drag threshold has been exceeded, and | ||
// start the tab drag operation the first time that occurrs. | ||
var data = this._dragData; | ||
// start the tab drag operation the first time that occurs. | ||
if (!data.dragActive) { | ||
@@ -598,22 +488,20 @@ var dx = Math.abs(event.clientX - data.pressX); | ||
// Fill in the remaining drag data. | ||
var content = this.node.firstChild.nextSibling; | ||
data.contentRect = this.contentNode.getBoundingClientRect(); | ||
data.tabLayout = snapTabLayout(this._tabs); | ||
data.contentRect = content.getBoundingClientRect(); | ||
data.cursorGrab = phosphor_domutil_1.overrideCursor('default'); | ||
data.dragActive = true; | ||
// Add the dragging style classes. | ||
data.tab.addClass(ACTIVE_CLASS); | ||
data.tab.addClass(DRAGGING_CLASS); | ||
this.addClass(DRAGGING_CLASS); | ||
} | ||
// Check to see if the detach threshold has been exceeded, and | ||
// emit the detach request signal the first time that occurrs. | ||
// If the drag data gets set to null, the mouse was released. | ||
if (!data.detachRequested && shouldDetach(data.contentRect, event)) { | ||
data.detachRequested = true; | ||
this.tabDetachRequested.emit({ | ||
tab: data.tab, | ||
index: data.tabIndex, | ||
clientX: event.clientX, | ||
clientY: event.clientY, | ||
}); | ||
// Check to see if the tear-off threshold has been exceeded. | ||
if (!data.tearOffRequested && tearOffExceeded(data.contentRect, event)) { | ||
// Only make the tear-off request once per drag action. | ||
data.tearOffRequested = true; | ||
// Send the tear-off request message to the tab bar. | ||
var item = data.tab.item; | ||
var clientX = event.clientX; | ||
var clientY = event.clientY; | ||
phosphor_messaging_1.sendMessage(this, new TearOffMessage(item, clientX, clientY)); | ||
// Do nothing further if the mouse has been released. | ||
if (!this._dragData) { | ||
@@ -623,4 +511,31 @@ return; | ||
} | ||
// Compute the target bounds of the drag tab. | ||
var offsetLeft = event.clientX - data.contentRect.left; | ||
var targetLeft = offsetLeft - data.tabPressX; | ||
var targetRight = targetLeft + data.tabWidth; | ||
// Reset the target tab index. | ||
data.tabTargetIndex = data.tabIndex; | ||
// Update the non-drag tab positions and the tab target index. | ||
var tabs = this._tabs; | ||
for (var i = 0, n = tabs.length; i < n; ++i) { | ||
var style = tabs[i].node.style; | ||
var layout = data.tabLayout[i]; | ||
var threshold = layout.left + (layout.width >> 1); | ||
if (i < data.tabIndex && targetLeft < threshold) { | ||
style.left = data.tabWidth + data.tabLayout[i + 1].margin + 'px'; | ||
data.tabTargetIndex = Math.min(data.tabTargetIndex, i); | ||
} | ||
else if (i > data.tabIndex && targetRight > threshold) { | ||
style.left = -data.tabWidth - layout.margin + 'px'; | ||
data.tabTargetIndex = i; | ||
} | ||
else if (i !== data.tabIndex) { | ||
style.left = ''; | ||
} | ||
} | ||
// Update the drag tab position. | ||
this._updateDragPosition(event.clientX); | ||
var idealLeft = event.clientX - data.pressX; | ||
var maxLeft = data.contentRect.width - (data.tabLeft + data.tabWidth); | ||
var adjustedLeft = Math.max(-data.tabLeft, Math.min(idealLeft, maxLeft)); | ||
data.tab.node.style.left = adjustedLeft + 'px'; | ||
}; | ||
@@ -641,3 +556,4 @@ /** | ||
// Bail if there is no drag in progress. | ||
if (!this._dragData) { | ||
var data = this._dragData; | ||
if (!data) { | ||
return; | ||
@@ -648,4 +564,2 @@ } | ||
document.removeEventListener('mousemove', this, true); | ||
// Store a local reference to the drag data. | ||
var data = this._dragData; | ||
// If the drag is not active, clear the reference and bail. | ||
@@ -673,4 +587,4 @@ if (!data.dragActive) { | ||
data.tab.node.style.left = adjustedLeft + 'px'; | ||
// Remove the active class from the tab so it can be transitioned. | ||
data.tab.removeClass(ACTIVE_CLASS); | ||
// Remove the dragging class from the tab so it can be transitioned. | ||
data.tab.removeClass(DRAGGING_CLASS); | ||
// Complete the release on a timer to allow the tab to transition. | ||
@@ -690,7 +604,10 @@ setTimeout(function () { | ||
data.cursorGrab.dispose(); | ||
data.tab.removeClass(ACTIVE_CLASS); | ||
_this.removeClass(DRAGGING_CLASS); | ||
// Finally, move the drag tab to its final index location. | ||
if (data.tabTargetIndex !== -1) { | ||
_this._moveTab(data.tabIndex, data.tabTargetIndex); | ||
// Finally, move the tab item to the new location. | ||
var fromIndex = data.tabIndex; | ||
var toIndex = data.tabTargetIndex; | ||
if (toIndex !== -1 && fromIndex !== toIndex) { | ||
_this.items.move(fromIndex, toIndex); | ||
// Force an update to prevent flicker on IE. | ||
phosphor_messaging_1.sendMessage(_this, phosphor_widget_1.Widget.MsgUpdateRequest); | ||
} | ||
@@ -700,55 +617,15 @@ }, TRANSITION_DURATION); | ||
/** | ||
* Update the drag tab position for the given mouse X position. | ||
* | ||
* This method is a no-op if an active drag is not in progress. | ||
* Release the mouse and restore the non-dragged tab positions. | ||
*/ | ||
TabBar.prototype._updateDragPosition = function (clientX) { | ||
// Bail if there is not an active drag. | ||
var data = this._dragData; | ||
if (!data || !data.dragActive) { | ||
return; | ||
} | ||
// Compute the target bounds of the drag tab. | ||
var offsetLeft = clientX - data.contentRect.left; | ||
var targetLeft = offsetLeft - data.tabPressX; | ||
var targetRight = targetLeft + data.tabWidth; | ||
// Reset the target tab index. | ||
data.tabTargetIndex = data.tabIndex; | ||
// Update the non-drag tab positions and the tab target index. | ||
for (var i = 0, n = this._tabs.length; i < n; ++i) { | ||
var style = this._tabs[i].node.style; | ||
var layout = data.tabLayout[i]; | ||
var threshold = layout.left + (layout.width >> 1); | ||
if (i < data.tabIndex && targetLeft < threshold) { | ||
style.left = data.tabWidth + data.tabLayout[i + 1].margin + 'px'; | ||
data.tabTargetIndex = Math.min(data.tabTargetIndex, i); | ||
} | ||
else if (i > data.tabIndex && targetRight > threshold) { | ||
style.left = -data.tabWidth - layout.margin + 'px'; | ||
data.tabTargetIndex = i; | ||
} | ||
else if (i !== data.tabIndex) { | ||
style.left = ''; | ||
} | ||
} | ||
// Update the drag tab position | ||
var idealLeft = clientX - data.pressX; | ||
var maxLeft = data.contentRect.width - (data.tabLeft + data.tabWidth); | ||
var adjustedLeft = Math.max(-data.tabLeft, Math.min(idealLeft, maxLeft)); | ||
data.tab.node.style.left = adjustedLeft + 'px'; | ||
}; | ||
/** | ||
* Release the mouse grab and restore the tab positions. | ||
*/ | ||
TabBar.prototype._releaseMouse = function () { | ||
// Bail early if there is no drag in progress. | ||
if (!this._dragData) { | ||
var data = this._dragData; | ||
if (!data) { | ||
return; | ||
} | ||
// Clear the drag data reference. | ||
this._dragData = null; | ||
// Remove the extra mouse listeners. | ||
document.removeEventListener('mouseup', this, true); | ||
document.removeEventListener('mousemove', this, true); | ||
// Clear the drag data reference. | ||
var data = this._dragData; | ||
this._dragData = null; | ||
// If the drag is not active, there's nothing left to do. | ||
@@ -764,175 +641,225 @@ if (!data.dragActive) { | ||
data.cursorGrab.dispose(); | ||
data.tab.removeClass(ACTIVE_CLASS); | ||
data.tab.removeClass(DRAGGING_CLASS); | ||
this.removeClass(DRAGGING_CLASS); | ||
}; | ||
/** | ||
* Insert a new tab into the tab bar at the given index. | ||
* | ||
* The tab should not already be contained in the tab bar. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The coerce handler for the [[currentItemProperty]]. | ||
*/ | ||
TabBar.prototype._insertTab = function (index, tab) { | ||
tab.selected = false; | ||
var i = arrays.insert(this._tabs, index, tab); | ||
var content = this.node.firstChild.nextSibling; | ||
content.appendChild(tab.node); | ||
if (!this.selectedTab) { | ||
this.selectedTab = tab; | ||
} | ||
else { | ||
this._updateTabOrdering(); | ||
} | ||
return i; | ||
TabBar.prototype._coerceCurrentItem = function (item) { | ||
var list = this.items; | ||
return (item && list && list.contains(item)) ? item : null; | ||
}; | ||
/** | ||
* Move a tab to a new index in the tab bar. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The change handler for the [[currentItemProperty]]. | ||
*/ | ||
TabBar.prototype._moveTab = function (fromIndex, toIndex) { | ||
var i = fromIndex | 0; | ||
var j = toIndex | 0; | ||
if (!arrays.move(this._tabs, i, j)) { | ||
return false; | ||
} | ||
if (i === j) { | ||
return true; | ||
} | ||
this._updateTabOrdering(); | ||
this.tabMoved.emit({ fromIndex: i, toIndex: j }); | ||
return true; | ||
TabBar.prototype._onCurrentItemChanged = function (oldItem, newItem) { | ||
var oldTab = arrays.find(this._tabs, function (tab) { return tab.item === oldItem; }); | ||
var newTab = arrays.find(this._tabs, function (tab) { return tab.item === newItem; }); | ||
if (oldTab) | ||
oldTab.removeClass(CURRENT_CLASS); | ||
if (newTab) | ||
newTab.addClass(CURRENT_CLASS); | ||
this.update(); | ||
}; | ||
/** | ||
* Remove and return the tab at the given index. | ||
* | ||
* The mouse should be released before calling this method. | ||
* The change handler for the [[itemsProperty]]. | ||
*/ | ||
TabBar.prototype._removeTab = function (index) { | ||
// Bail if the index is invalid. | ||
var i = index | 0; | ||
var tab = arrays.removeAt(this._tabs, i); | ||
if (!tab) { | ||
return void 0; | ||
TabBar.prototype._onItemsChanged = function (oldList, newList) { | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Disconnect the old list and dispose the old tabs. | ||
if (oldList) { | ||
oldList.changed.disconnect(this._onItemsListChanged, this); | ||
var content = this.contentNode; | ||
while (this._tabs.length) { | ||
var tab = this._tabs.pop(); | ||
content.removeChild(tab.node); | ||
tab.dispose(); | ||
} | ||
} | ||
// Remove the tab from the DOM and reset its style. | ||
var content = this.node.firstChild.nextSibling; | ||
content.removeChild(tab.node); | ||
tab.selected = false; | ||
tab.node.style.left = ''; | ||
tab.node.style.zIndex = ''; | ||
tab.removeClass(ACTIVE_CLASS); | ||
tab.removeClass(FIRST_CLASS); | ||
tab.removeClass(LAST_CLASS); | ||
// Update the selected tab. If the removed tab was the selected tab, | ||
// select the next best tab by starting with the previous tab, then | ||
// the next sibling, and finally the previous sibling. Otherwise, | ||
// update the state and tab ordering as appropriate. | ||
if (tab === this.selectedTab) { | ||
var next = this.previousTab || this._tabs[i] || this._tabs[i - 1]; | ||
this.selectedTab = next; | ||
this.previousTab = null; | ||
// Create the new tabs and connect the new list. | ||
if (newList) { | ||
var content = this.contentNode; | ||
for (var i = 0, n = newList.length; i < n; ++i) { | ||
var tab = new Tab(newList.get(i)); | ||
content.appendChild(tab.node); | ||
this._tabs.push(tab); | ||
} | ||
newList.changed.connect(this._onItemsListChanged, this); | ||
} | ||
else if (tab === this.previousTab) { | ||
this.previousTab = null; | ||
this._updateTabOrdering(); | ||
} | ||
else { | ||
this._updateTabOrdering(); | ||
} | ||
return tab; | ||
// Update the current item. | ||
this.currentItem = newList && newList.get(0); | ||
// Update the tab node order. | ||
this.update(); | ||
}; | ||
/** | ||
* Update the Z-index and flex order of the tabs. | ||
* The change handler for the items list `changed` signal. | ||
*/ | ||
TabBar.prototype._updateTabOrdering = function () { | ||
if (this._tabs.length === 0) { | ||
return; | ||
TabBar.prototype._onItemsListChanged = function (sender, args) { | ||
switch (args.type) { | ||
case phosphor_observablelist_1.ListChangeType.Add: | ||
this._onItemsListAdd(args); | ||
break; | ||
case phosphor_observablelist_1.ListChangeType.Move: | ||
this._onItemsListMove(args); | ||
break; | ||
case phosphor_observablelist_1.ListChangeType.Remove: | ||
this._onItemsListRemove(args); | ||
break; | ||
case phosphor_observablelist_1.ListChangeType.Replace: | ||
this._onItemsListReplace(args); | ||
break; | ||
case phosphor_observablelist_1.ListChangeType.Set: | ||
this._onItemsListSet(args); | ||
break; | ||
} | ||
var selectedTab = this.selectedTab; | ||
for (var i = 0, n = this._tabs.length, k = n - 1; i < n; ++i) { | ||
var tab = this._tabs[i]; | ||
var style = tab.node.style; | ||
tab.removeClass(FIRST_CLASS); | ||
tab.removeClass(LAST_CLASS); | ||
style.order = i + ''; | ||
if (tab === selectedTab) { | ||
style.zIndex = n + ''; | ||
} | ||
else { | ||
style.zIndex = k-- + ''; | ||
} | ||
} | ||
this._tabs[0].addClass(FIRST_CLASS); | ||
this._tabs[this._tabs.length - 1].addClass(LAST_CLASS); | ||
}; | ||
/** | ||
* The change handler for the [[selectedTabProperty]]. | ||
* The handler invoked on a items list change of type `Add`. | ||
*/ | ||
TabBar.prototype._onSelectedTabChanged = function (old, tab) { | ||
if (old) | ||
old.selected = false; | ||
if (tab) | ||
tab.selected = true; | ||
this.previousTab = old; | ||
this._updateTabOrdering(); | ||
this.tabSelected.emit({ index: this.tabIndex(tab), tab: tab }); | ||
TabBar.prototype._onItemsListAdd = function (args) { | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Create the tab for the new tab item. | ||
var tab = new Tab(args.newValue); | ||
// Add the tab to the same location in the internal array. | ||
arrays.insert(this._tabs, args.newIndex, tab); | ||
// Add the tab node to the DOM. The position is irrelevant. | ||
this.contentNode.appendChild(tab.node); | ||
// Select the tab if no tab is currently selected. | ||
if (!this.currentItem) | ||
this.currentItem = tab.item; | ||
// Update the tab node order. | ||
this.update(); | ||
}; | ||
/** | ||
* A signal emitted when a tab is moved. | ||
* | ||
* **See also:** [[tabMoved]] | ||
* The handler invoked on a items list change of type `Move`. | ||
*/ | ||
TabBar.tabMovedSignal = new phosphor_signaling_1.Signal(); | ||
TabBar.prototype._onItemsListMove = function (args) { | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Move the tab in the array. DOM position is irrelevant. | ||
arrays.move(this._tabs, args.oldIndex, args.newIndex); | ||
// Update the tab node order. | ||
this.update(); | ||
}; | ||
/** | ||
* A signal emitted when a tab is selected. | ||
* | ||
* **See also:** [[tabSelected]] | ||
* The handler invoked on a items list change of type `Remove`. | ||
*/ | ||
TabBar.tabSelectedSignal = new phosphor_signaling_1.Signal(); | ||
TabBar.prototype._onItemsListRemove = function (args) { | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Remove the tab from the internal array. | ||
var tab = arrays.removeAt(this._tabs, args.oldIndex); | ||
// Remove the tab node from the DOM. | ||
this.contentNode.removeChild(tab.node); | ||
// Patch up the current item if needed. | ||
if (this.currentItem === tab.item) { | ||
var list = this.items; | ||
this.currentItem = list.get(args.oldIndex) || list.get(-1); | ||
} | ||
// Dispose of the old tab. | ||
tab.dispose(); | ||
// Update the tab node order. | ||
this.update(); | ||
}; | ||
/** | ||
* A signal emitted when the user clicks a tab close icon. | ||
* | ||
* **See also:** [[tabCloseRequested] | ||
* The handler invoked on a items list change of type `Replace`. | ||
*/ | ||
TabBar.tabCloseRequestedSignal = new phosphor_signaling_1.Signal(); | ||
TabBar.prototype._onItemsListReplace = function (args) { | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Create the new tabs for the new tab items. | ||
var newItems = args.newValue; | ||
var newTabs = newItems.map(function (item) { return new Tab(item); }); | ||
// Replace the tabs in the internal array. | ||
var oldItems = args.oldValue; | ||
var oldTabs = (_a = this._tabs).splice.apply(_a, [args.newIndex, oldItems.length].concat(newTabs)); | ||
// Remove the old tabs from the DOM. | ||
var content = this.contentNode; | ||
oldTabs.forEach(function (tab) { content.removeChild(tab.node); }); | ||
// Add the new tabs to the DOM. Their position is irrelevant. | ||
newTabs.forEach(function (tab) { content.appendChild(tab.node); }); | ||
// Patch up the current item if needed. | ||
var curr = this.currentItem; | ||
if (oldItems.indexOf(curr) !== -1) { | ||
this.currentItem = null; | ||
if (newItems.indexOf(curr) !== -1) { | ||
this.currentItem = curr; | ||
} | ||
else { | ||
var list = this.items; | ||
this.currentItem = list.get(args.newIndex) || list.get(-1); | ||
} | ||
} | ||
// Dispose of the old tabs. | ||
oldTabs.forEach(function (tab) { tab.dispose(); }); | ||
// Update the tab node order. | ||
this.update(); | ||
var _a; | ||
}; | ||
/** | ||
* A signal emitted when a tab is dragged beyond the detach threshold. | ||
* The handler invoked on a items list change of type `Set`. | ||
*/ | ||
TabBar.prototype._onItemsListSet = function (args) { | ||
// If the item was not actually changed, there is nothing to do. | ||
if (args.oldValue === args.newValue) { | ||
return; | ||
} | ||
// Ensure the mouse is released. | ||
this._releaseMouse(); | ||
// Create the tab for the new tab item. | ||
var newTab = new Tab(args.newValue); | ||
// Swap the new tab in the internal array. | ||
var oldTab = this._tabs[args.newIndex]; | ||
this._tabs[args.newIndex] = newTab; | ||
// Swap the new tab node in the DOM. | ||
this.contentNode.replaceChild(newTab.node, oldTab.node); | ||
// Patch up the current item if needed. | ||
if (this.currentItem === oldTab.item) { | ||
this.currentItem = newTab.item; | ||
} | ||
// Dispose of the old tab. | ||
oldTab.dispose(); | ||
// Update the tab node order. | ||
this.update(); | ||
}; | ||
/** | ||
* A signal emitted when the user clicks a tab item's close icon. | ||
* | ||
* **See also:** [[tabDetachRequested]] | ||
* **See also:** [[itemCloseRequested]] | ||
*/ | ||
TabBar.tabDetachRequestedSignal = new phosphor_signaling_1.Signal(); | ||
TabBar.itemCloseRequestedSignal = new phosphor_signaling_1.Signal(); | ||
/** | ||
* The property descriptor for the previous tab. | ||
* The property descriptor for the currently selected tab item. | ||
* | ||
* This controls which tab is selected after if selected tab is | ||
* removed. It is typically updated automatically. | ||
* | ||
* **See also:** [[previousTab]] | ||
* **See also:** [[currentItem]] | ||
*/ | ||
TabBar.previousTabProperty = new phosphor_properties_1.Property({ | ||
TabBar.currentItemProperty = new phosphor_properties_1.Property({ | ||
name: 'currentItem', | ||
value: null, | ||
coerce: function (owner, val) { return (val && owner.tabIndex(val) !== -1) ? val : null; }, | ||
coerce: function (owner, value) { return owner._coerceCurrentItem(value); }, | ||
changed: function (owner, old, value) { owner._onCurrentItemChanged(old, value); }, | ||
notify: new phosphor_signaling_1.Signal(), | ||
}); | ||
/** | ||
* The property descriptor for the selected tab. | ||
* The property descriptor for the observable list of tab items. | ||
* | ||
* This controls which tab is selected in the tab bar. | ||
* | ||
* **See also:** [[selectedTab]] | ||
* **See also:** [[items]] | ||
*/ | ||
TabBar.selectedTabProperty = new phosphor_properties_1.Property({ | ||
TabBar.itemsProperty = new phosphor_properties_1.Property({ | ||
name: 'items', | ||
value: null, | ||
coerce: function (owner, val) { return (val && owner.tabIndex(val) !== -1) ? val : null; }, | ||
changed: function (owner, old, val) { return owner._onSelectedTabChanged(old, val); }, | ||
coerce: function (owner, value) { return value || null; }, | ||
changed: function (owner, old, value) { owner._onItemsChanged(old, value); }, | ||
}); | ||
/** | ||
* The property descriptor for the tabs movable property | ||
* The property descriptor for whether the tabs are user-movable. | ||
* | ||
* This controls whether tabs are movable by the user. | ||
* | ||
* **See also:** [[tabsMovable]] | ||
*/ | ||
TabBar.tabsMovableProperty = new phosphor_properties_1.Property({ | ||
value: true, | ||
name: 'tabsMovable', | ||
value: false, | ||
changed: function (owner) { owner._releaseMouse(); }, | ||
}); | ||
@@ -943,2 +870,229 @@ return TabBar; | ||
/** | ||
* A message class for `'tear-off-request'` messages. | ||
* | ||
* #### Notes | ||
* A message of this type is sent to a tab bar when the user drags | ||
* a tab beyond the tear-off threshold which surrounds the tab bar. | ||
*/ | ||
var TearOffMessage = (function (_super) { | ||
__extends(TearOffMessage, _super); | ||
/** | ||
* Construct a new tear off request message. | ||
* | ||
* @param item - The tab item being dragged by the user. | ||
* | ||
* @param clientX - The current client X position of the mouse. | ||
* | ||
* @param clientY - The current client Y position of the mouse. | ||
*/ | ||
function TearOffMessage(item, clientX, clientY) { | ||
_super.call(this, 'tear-off-request'); | ||
this._item = item; | ||
this._clientX = clientX; | ||
this._clientY = clientY; | ||
} | ||
Object.defineProperty(TearOffMessage.prototype, "item", { | ||
/** | ||
* The tab item being dragged by the user. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this._item; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TearOffMessage.prototype, "clientX", { | ||
/** | ||
* The current client X position of the mouse. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this._clientX; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TearOffMessage.prototype, "clientY", { | ||
/** | ||
* The current client Y position of the mouse. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this._clientY; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
return TearOffMessage; | ||
})(phosphor_messaging_1.Message); | ||
exports.TearOffMessage = TearOffMessage; | ||
/** | ||
* An object which manages a tab node for a tab bar. | ||
*/ | ||
var Tab = (function (_super) { | ||
__extends(Tab, _super); | ||
/** | ||
* Construct a new tab. | ||
* | ||
* @param item - The tab item to associate with the tab. | ||
*/ | ||
function Tab(item) { | ||
_super.call(this); | ||
this.addClass(TAB_CLASS); | ||
this._item = item; | ||
var title = item.title; | ||
this.textNode.textContent = title.text; | ||
this.toggleClass(CLOSABLE_CLASS, title.closable); | ||
if (title.icon) | ||
exAddClass(this.iconNode, title.icon); | ||
if (title.className) | ||
exAddClass(this.node, title.className); | ||
title.changed.connect(this._onTitleChanged, this); | ||
} | ||
/** | ||
* Create the DOM node for a tab. | ||
*/ | ||
Tab.createNode = function () { | ||
var node = document.createElement('li'); | ||
var icon = document.createElement('span'); | ||
var text = document.createElement('span'); | ||
var close = document.createElement('span'); | ||
icon.className = ICON_CLASS; | ||
text.className = TEXT_CLASS; | ||
close.className = CLOSE_CLASS; | ||
node.appendChild(icon); | ||
node.appendChild(text); | ||
node.appendChild(close); | ||
return node; | ||
}; | ||
/** | ||
* Dispose of the resources held by the tab. | ||
*/ | ||
Tab.prototype.dispose = function () { | ||
this._item = null; | ||
phosphor_signaling_1.clearSignalData(this); | ||
}; | ||
Object.defineProperty(Tab.prototype, "isDisposed", { | ||
/** | ||
* Test whether the tab is disposed. | ||
*/ | ||
get: function () { | ||
return this._item === null; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Tab.prototype, "iconNode", { | ||
/** | ||
* Get the icon node for the tab. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this.node.childNodes[0]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Tab.prototype, "textNode", { | ||
/** | ||
* Get the text node for the tab. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this.node.childNodes[1]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Tab.prototype, "closeNode", { | ||
/** | ||
* Get the close icon node for the tab. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this.node.childNodes[2]; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Tab.prototype, "item", { | ||
/** | ||
* Get the tab item associated with the tab. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
*/ | ||
get: function () { | ||
return this._item; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
/** | ||
* The handler for the title `changed` signal. | ||
*/ | ||
Tab.prototype._onTitleChanged = function (sender, args) { | ||
switch (args.name) { | ||
case 'text': | ||
this._onTitleTextChanged(args); | ||
break; | ||
case 'icon': | ||
this._onTitleIconChanged(args); | ||
break; | ||
case 'closable': | ||
this._onTitleClosableChanged(args); | ||
break; | ||
case 'className': | ||
this._onTitleClassNameChanged(args); | ||
break; | ||
} | ||
}; | ||
/** | ||
* A method invoked when the title text changes. | ||
*/ | ||
Tab.prototype._onTitleTextChanged = function (args) { | ||
this.textNode.textContent = args.newValue; | ||
}; | ||
/** | ||
* A method invoked when the title icon changes. | ||
*/ | ||
Tab.prototype._onTitleIconChanged = function (args) { | ||
var node = this.iconNode; | ||
if (args.oldValue) | ||
exRemClass(node, args.oldValue); | ||
if (args.newValue) | ||
exAddClass(node, args.newValue); | ||
}; | ||
/** | ||
* A method invoked when the title closable flag changes. | ||
*/ | ||
Tab.prototype._onTitleClosableChanged = function (args) { | ||
this.toggleClass(CLOSABLE_CLASS, args.newValue); | ||
}; | ||
/** | ||
* A method invoked when the title class name changes. | ||
*/ | ||
Tab.prototype._onTitleClassNameChanged = function (args) { | ||
var node = this.node; | ||
if (args.oldValue) | ||
exRemClass(node, args.oldValue); | ||
if (args.newValue) | ||
exAddClass(node, args.newValue); | ||
}; | ||
return Tab; | ||
})(phosphor_nodewrapper_1.NodeWrapper); | ||
/** | ||
* A struct which holds the drag data for a tab bar. | ||
@@ -949,6 +1103,10 @@ */ | ||
/** | ||
* The tab being dragged. | ||
* The tab object being dragged. | ||
*/ | ||
this.tab = null; | ||
/** | ||
* The index of the tab being dragged. | ||
*/ | ||
this.tabIndex = -1; | ||
/** | ||
* The offset left of the tab being dragged. | ||
@@ -962,8 +1120,4 @@ */ | ||
/** | ||
* The index of the tab being dragged. | ||
* The original mouse X position in tab coordinates. | ||
*/ | ||
this.tabIndex = -1; | ||
/** | ||
* The orgian mouse X position in tab coordinates. | ||
*/ | ||
this.tabPressX = -1; | ||
@@ -999,5 +1153,5 @@ /** | ||
/** | ||
* Whether the detach request signal has been emitted. | ||
* Whether a tear-off request as been made. | ||
*/ | ||
this.detachRequested = false; | ||
this.tearOffRequested = false; | ||
} | ||
@@ -1007,18 +1161,32 @@ return DragData; | ||
/** | ||
* Test if a mouse position lies outside the detach bound of a rect. | ||
* Add a whitespace separated class name to the given node. | ||
*/ | ||
function shouldDetach(rect, event) { | ||
return ((event.clientX < rect.left - DETACH_THRESHOLD) || | ||
(event.clientX >= rect.right + DETACH_THRESHOLD) || | ||
(event.clientY < rect.top - DETACH_THRESHOLD) || | ||
(event.clientY >= rect.bottom + DETACH_THRESHOLD)); | ||
function exAddClass(node, name) { | ||
var list = node.classList; | ||
var parts = name.split(/\s+/); | ||
for (var i = 0, n = parts.length; i < n; ++i) { | ||
if (parts[i]) | ||
list.add(parts[i]); | ||
} | ||
} | ||
/** | ||
* Get the index of the tab which intersect the client point, or -1. | ||
* Remove a whitespace separated class name to the given node. | ||
*/ | ||
function exRemClass(node, name) { | ||
var list = node.classList; | ||
var parts = name.split(/\s+/); | ||
for (var i = 0, n = parts.length; i < n; ++i) { | ||
if (parts[i]) | ||
list.remove(parts[i]); | ||
} | ||
} | ||
/** | ||
* Perform a client position hit test an array of tabs. | ||
* | ||
* Returns the index of the first matching node, or `-1`. | ||
*/ | ||
function hitTestTabs(tabs, clientX, clientY) { | ||
for (var i = 0, n = tabs.length; i < n; ++i) { | ||
if (phosphor_domutil_1.hitTest(tabs[i].node, clientX, clientY)) { | ||
if (phosphor_domutil_1.hitTest(tabs[i].node, clientX, clientY)) | ||
return i; | ||
} | ||
} | ||
@@ -1028,3 +1196,3 @@ return -1; | ||
/** | ||
* Snap an array of the current tab layout values. | ||
* Get a snapshot of the current tab layout values. | ||
*/ | ||
@@ -1037,3 +1205,3 @@ function snapTabLayout(tabs) { | ||
var width = node.offsetWidth; | ||
var cstyle = window.getComputedStyle(tabs[i].node); | ||
var cstyle = window.getComputedStyle(node); | ||
var margin = parseInt(cstyle.marginLeft, 10) || 0; | ||
@@ -1044,2 +1212,11 @@ layout[i] = { margin: margin, left: left, width: width }; | ||
} | ||
/** | ||
* Test if a mouse position exceeds the tear-off threshold. | ||
*/ | ||
function tearOffExceeded(rect, event) { | ||
return ((event.clientX < rect.left - TEAR_OFF_THRESHOLD) || | ||
(event.clientX >= rect.right + TEAR_OFF_THRESHOLD) || | ||
(event.clientY < rect.top - TEAR_OFF_THRESHOLD) || | ||
(event.clientY >= rect.bottom + TEAR_OFF_THRESHOLD)); | ||
} | ||
//# sourceMappingURL=tabbar.js.map |
import { BoxPanel } from 'phosphor-boxpanel'; | ||
import { Property } from 'phosphor-properties'; | ||
import { ISignal, Signal } from 'phosphor-signaling'; | ||
import { IWidgetIndexArgs } from 'phosphor-stackedpanel'; | ||
import { Widget } from 'phosphor-widget'; | ||
import { Tab } from './tab'; | ||
import { IChangedArgs } from 'phosphor-properties'; | ||
import { StackedPanel } from 'phosphor-stackedpanel'; | ||
import { IChildWidgetList, Widget } from 'phosphor-widget'; | ||
import { TabBar } from './tabbar'; | ||
/** | ||
* A panel which provides a tabbed layout for child widgets. | ||
* A panel which combines a `TabBar` and a `StackedPanel`. | ||
* | ||
* The `TabPanel` provides a convenient combination of a `TabBar` and | ||
* a `StackedPanel` which allows the user to toggle between widgets by | ||
* selecting the tab associated with a widget. | ||
* | ||
* #### Notes | ||
* Widgets should be added to a `TabPanel` using the `<prefix>Widget` | ||
* methods, **not** the `<prefix>Child` methods. The children of a | ||
* `TabPanel` should **not** be manipulated directly by user code. | ||
* Children for this panel should be added to the [[widgets]] list. | ||
*/ | ||
export declare class TabPanel extends BoxPanel { | ||
/** | ||
* A signal emitted when the current widget is changed. | ||
* | ||
* **See also:** [[currentChanged]] | ||
*/ | ||
static currentChangedSignal: Signal<TabPanel, IWidgetIndexArgs>; | ||
/** | ||
* The property descriptor for the tab attached property. | ||
* | ||
* This controls the tab used for a widget in a tab panel. | ||
* | ||
* #### Notes | ||
* If the tab for a widget is changed, the new tab will not be | ||
* reflected until the widget is re-inserted into the tab panel. | ||
* However, in-place changes to the tab's properties **will** be | ||
* reflected. | ||
* | ||
* **See also:** [[getTab]], [[setTab]] | ||
*/ | ||
static tabProperty: Property<Widget, Tab>; | ||
/** | ||
* Get the tab for the given widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @returns The tab for the given widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate for the [[tabProperty]]. | ||
*/ | ||
static getTab(widget: Widget): Tab; | ||
/** | ||
* Set the tab for the given widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @param tab - The tab to use for the widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate for the [[tabProperty]]. | ||
*/ | ||
static setTab(widget: Widget, tab: Tab): void; | ||
/** | ||
* Construct a new tab panel. | ||
@@ -71,13 +22,14 @@ */ | ||
/** | ||
* A signal emitted when the current widget is changed. | ||
* Get the currently selected widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[currentChangedSignal]]. | ||
* This is a convenience alias to the `currentItem` property of the | ||
* tab bar. | ||
*/ | ||
currentChanged: ISignal<TabPanel, IWidgetIndexArgs>; | ||
/** | ||
* Get the currently selected widget. | ||
*/ | ||
/** | ||
* Set the currently selected widget. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `currentItem` property of the | ||
* tab bar. | ||
*/ | ||
@@ -87,169 +39,67 @@ currentWidget: Widget; | ||
* Get whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `tabsMovable` property of the | ||
* tab bar. | ||
*/ | ||
/** | ||
* Set whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `tabsMovable` property of the | ||
* tab bar. | ||
*/ | ||
tabsMovable: boolean; | ||
/** | ||
* Get a shallow copy of the array of widgets. | ||
* Get the observable list of widgets for the tab panel. | ||
* | ||
* #### Notes | ||
* When only iterating over the widgets, it can be faster to use | ||
* the widget query methods, which do not perform a copy. | ||
* Widgets to arrange in the tab panel should be added to this list. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetAt]] | ||
* This is a read-only alias of the `children` property of the | ||
* stacked panel. | ||
*/ | ||
widgets: IChildWidgetList; | ||
/** | ||
* Set the widgets for the tab panel. | ||
* Get the tab bar associated with the tab panel. | ||
* | ||
* #### Notes | ||
* This will clear the current widgets and add the specified widgets. | ||
* Depending on the desired outcome, it can be more efficient to use | ||
* one of the widget manipulation methods. | ||
* The items in the tab bar are automatically synchronized with the | ||
* children of the stacked panel. | ||
* | ||
* **See also:** [[addWidget]], [[insertWidget]], [[removeWidget]] | ||
*/ | ||
widgets: Widget[]; | ||
/** | ||
* Get the number of widgets in the tab panel. | ||
* | ||
* #### Notes | ||
* This is a read-only property. | ||
* | ||
* **See also:** [[widgets]], [[widgetAt]] | ||
*/ | ||
widgetCount: number; | ||
tabs: TabBar<Widget>; | ||
/** | ||
* Get the widget at a specific index. | ||
* Get the stacked panel associated with the tab panel. | ||
* | ||
* @param index - The index of the widget of interest. | ||
* | ||
* @returns The widget widget at the specified index, or `undefined` | ||
* if the index is out of range. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetIndex]] | ||
*/ | ||
widgetAt(index: number): Widget; | ||
/** | ||
* Get the index of a specific widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @returns The index of the specified widget, or `-1` if the widget | ||
* is not contained in the tab panel. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetAt]] | ||
*/ | ||
widgetIndex(widget: Widget): number; | ||
/** | ||
* Add a widget to the end of the panel. | ||
* | ||
* @param widget - The widget to add to the panel. | ||
* | ||
* @returns The new index of the widget. | ||
* | ||
* #### Notes | ||
* If the widget already exists in the panel, it will first be | ||
* removed. | ||
* The children of the stacked panel are automatically synchronized | ||
* with the items in the tab bar. | ||
* | ||
* The `TabPanel.tab` attached property *must* be set with the | ||
* tab to use for the widget, or an error will be thrown. This | ||
* can be set via `TabPanel.setTab`. | ||
* | ||
* The `TabPanel.tab` attached property is assumed to remain | ||
* constant while the widget is contained by the tab panel. | ||
* | ||
* **See also:** [[insertWidget]], [[moveWidget]] | ||
* This is a read-only property. | ||
*/ | ||
addWidget(widget: Widget): number; | ||
stack: StackedPanel; | ||
/** | ||
* Insert a widget into the panel at the given index. | ||
* Handle the `currentItemChanged` signal from the tab bar. | ||
* | ||
* @param index - The target index for the widget. This will be | ||
* clamped to the bounds of the widgets. | ||
* | ||
* @param widget - The widget to insert into the panel. | ||
* | ||
* @returns The new index of the widget. | ||
* | ||
* #### Notes | ||
* If the widget already exists in the panel, it will first be | ||
* removed. | ||
* This can be reimplemented by subclasses as needed. | ||
* | ||
* The `TabPanel.tab` attached property *must* be set with the | ||
* tab to use for the widget, or an error will be thrown. This | ||
* can be set via `TabPanel.setTab`. | ||
* | ||
* The `TabPanel.tab` attached property is assumed to remain | ||
* constant while the widget is contained by the tab panel. | ||
* | ||
* **See also:** [[addWidget]], [[moveWidget]] | ||
* The default implementation of this method synchronizes the current | ||
* tab item with current widget of the stacked panel. | ||
*/ | ||
insertWidget(index: number, widget: Widget): number; | ||
protected onCurrentItemChanged(sender: TabBar<Widget>, args: IChangedArgs<Widget>): void; | ||
/** | ||
* Move a widget from one index to another. | ||
* Handle the `itemCloseRequested` signal from the tab bar. | ||
* | ||
* @param fromIndex - The index of the widget of interest. | ||
* | ||
* @param toIndex - The target index for the widget. | ||
* | ||
* @returns 'true' if the widget was moved, or `false` if either | ||
* of the given indices are out of range. | ||
* | ||
* #### Notes | ||
* This can be more efficient than re-inserting an existing widget. | ||
* This can be reimplemented by subclasses as needed. | ||
* | ||
* **See also:** [[addWidget]], [[insertWidget]] | ||
* The default implementation of this method closes the widget if the | ||
* widget's title object has its `closable` flag set to `true`. | ||
*/ | ||
moveWidget(fromIndex: number, toIndex: number): boolean; | ||
/** | ||
* Remove the widget at a specific index. | ||
* | ||
* @param index - The index of the widget of interest. | ||
* | ||
* @returns The removed widget, or `undefined` if the index | ||
* is out of range. | ||
* | ||
* **See also:** [[removeWidget]], [[clearWidgets]] | ||
*/ | ||
removeWidgetAt(index: number): Widget; | ||
/** | ||
* Remove a specific widget from the panel. | ||
* | ||
* @param child - The widget of interest. | ||
* | ||
* @returns The index which the widget occupied, or `-1` if the | ||
* widget is not contained in the tab panel. | ||
* | ||
* **See also:** [[removeWidgetAt]], [[clearWidgets]] | ||
*/ | ||
removeWidget(widget: Widget): number; | ||
/** | ||
* Remove all widgets from the tab panel. | ||
* | ||
* **See also:** [[removeWidget]], [[removeWidgetAt]] | ||
*/ | ||
clearWidgets(): void; | ||
/** | ||
* Handle the `tabMoved` signal from the tab bar. | ||
*/ | ||
private _onTabMoved(sender, args); | ||
/** | ||
* Handle the `tabSelected` signal from the tab bar. | ||
*/ | ||
private _onTabSelected(sender, args); | ||
/** | ||
* Handle the `tabCloseRequested` signal from the tab bar. | ||
*/ | ||
private _onTabCloseRequested(sender, args); | ||
/** | ||
* Handle the `currentChanged` signal from the stacked panel. | ||
*/ | ||
private _onCurrentChanged(sender, args); | ||
/** | ||
* Handle the `widgetRemoved` signal from the stacked panel. | ||
*/ | ||
private _onWidgetRemoved(sender, args); | ||
protected onItemCloseRequested(sender: TabBar<Widget>, args: Widget): void; | ||
private _tabs; | ||
private _stack; | ||
} |
@@ -15,4 +15,2 @@ /*----------------------------------------------------------------------------- | ||
var phosphor_boxpanel_1 = require('phosphor-boxpanel'); | ||
var phosphor_properties_1 = require('phosphor-properties'); | ||
var phosphor_signaling_1 = require('phosphor-signaling'); | ||
var phosphor_stackedpanel_1 = require('phosphor-stackedpanel'); | ||
@@ -25,12 +23,6 @@ var tabbar_1 = require('./tabbar'); | ||
/** | ||
* A panel which provides a tabbed layout for child widgets. | ||
* A panel which combines a `TabBar` and a `StackedPanel`. | ||
* | ||
* The `TabPanel` provides a convenient combination of a `TabBar` and | ||
* a `StackedPanel` which allows the user to toggle between widgets by | ||
* selecting the tab associated with a widget. | ||
* | ||
* #### Notes | ||
* Widgets should be added to a `TabPanel` using the `<prefix>Widget` | ||
* methods, **not** the `<prefix>Child` methods. The children of a | ||
* `TabPanel` should **not** be manipulated directly by user code. | ||
* Children for this panel should be added to the [[widgets]] list. | ||
*/ | ||
@@ -47,7 +39,5 @@ var TabPanel = (function (_super) { | ||
this.addClass(TAB_PANEL_CLASS); | ||
this._tabs.tabMoved.connect(this._onTabMoved, this); | ||
this._tabs.tabSelected.connect(this._onTabSelected, this); | ||
this._tabs.tabCloseRequested.connect(this._onTabCloseRequested, this); | ||
this._stack.currentChanged.connect(this._onCurrentChanged, this); | ||
this._stack.widgetRemoved.connect(this._onWidgetRemoved, this); | ||
this._tabs.items = this._stack.children; | ||
this._tabs.currentItemChanged.connect(this.onCurrentItemChanged, this); | ||
this._tabs.itemCloseRequested.connect(this.onItemCloseRequested, this); | ||
phosphor_boxpanel_1.BoxPanel.setStretch(this._tabs, 0); | ||
@@ -57,32 +47,6 @@ phosphor_boxpanel_1.BoxPanel.setStretch(this._stack, 1); | ||
this.spacing = 0; | ||
this.addChild(this._tabs); | ||
this.addChild(this._stack); | ||
this.children.add(this._tabs); | ||
this.children.add(this._stack); | ||
} | ||
/** | ||
* Get the tab for the given widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @returns The tab for the given widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate for the [[tabProperty]]. | ||
*/ | ||
TabPanel.getTab = function (widget) { | ||
return TabPanel.tabProperty.get(widget); | ||
}; | ||
/** | ||
* Set the tab for the given widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @param tab - The tab to use for the widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate for the [[tabProperty]]. | ||
*/ | ||
TabPanel.setTab = function (widget, tab) { | ||
TabPanel.tabProperty.set(widget, tab); | ||
}; | ||
/** | ||
* Dispose of the resources held by the widget. | ||
@@ -95,28 +59,22 @@ */ | ||
}; | ||
Object.defineProperty(TabPanel.prototype, "currentChanged", { | ||
Object.defineProperty(TabPanel.prototype, "currentWidget", { | ||
/** | ||
* A signal emitted when the current widget is changed. | ||
* Get the currently selected widget. | ||
* | ||
* #### Notes | ||
* This is a pure delegate to the [[currentChangedSignal]]. | ||
* This is a convenience alias to the `currentItem` property of the | ||
* tab bar. | ||
*/ | ||
get: function () { | ||
return TabPanel.currentChangedSignal.bind(this); | ||
return this._tabs.currentItem; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TabPanel.prototype, "currentWidget", { | ||
/** | ||
* Get the currently selected widget. | ||
*/ | ||
get: function () { | ||
return this._stack.currentWidget; | ||
}, | ||
/** | ||
* Set the currently selected widget. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `currentItem` property of the | ||
* tab bar. | ||
*/ | ||
set: function (widget) { | ||
var i = this._stack.childIndex(widget); | ||
this._tabs.selectedTab = this._tabs.tabAt(i); | ||
this._tabs.currentItem = widget; | ||
}, | ||
@@ -129,2 +87,6 @@ enumerable: true, | ||
* Get whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `tabsMovable` property of the | ||
* tab bar. | ||
*/ | ||
@@ -136,2 +98,6 @@ get: function () { | ||
* Set whether the tabs are movable by the user. | ||
* | ||
* #### Notes | ||
* This is a convenience alias to the `tabsMovable` property of the | ||
* tab bar. | ||
*/ | ||
@@ -146,9 +112,9 @@ set: function (movable) { | ||
/** | ||
* Get a shallow copy of the array of widgets. | ||
* Get the observable list of widgets for the tab panel. | ||
* | ||
* #### Notes | ||
* When only iterating over the widgets, it can be faster to use | ||
* the widget query methods, which do not perform a copy. | ||
* Widgets to arrange in the tab panel should be added to this list. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetAt]] | ||
* This is a read-only alias of the `children` property of the | ||
* stacked panel. | ||
*/ | ||
@@ -158,16 +124,17 @@ get: function () { | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(TabPanel.prototype, "tabs", { | ||
/** | ||
* Set the widgets for the tab panel. | ||
* Get the tab bar associated with the tab panel. | ||
* | ||
* #### Notes | ||
* This will clear the current widgets and add the specified widgets. | ||
* Depending on the desired outcome, it can be more efficient to use | ||
* one of the widget manipulation methods. | ||
* The items in the tab bar are automatically synchronized with the | ||
* children of the stacked panel. | ||
* | ||
* **See also:** [[addWidget]], [[insertWidget]], [[removeWidget]] | ||
* This is a read-only property. | ||
*/ | ||
set: function (widgets) { | ||
var _this = this; | ||
this.clearWidgets(); | ||
widgets.forEach(function (widget) { return _this.addWidget(widget); }); | ||
get: function () { | ||
return this._tabs; | ||
}, | ||
@@ -177,13 +144,14 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(TabPanel.prototype, "widgetCount", { | ||
Object.defineProperty(TabPanel.prototype, "stack", { | ||
/** | ||
* Get the number of widgets in the tab panel. | ||
* Get the stacked panel associated with the tab panel. | ||
* | ||
* #### Notes | ||
* The children of the stacked panel are automatically synchronized | ||
* with the items in the tab bar. | ||
* | ||
* This is a read-only property. | ||
* | ||
* **See also:** [[widgets]], [[widgetAt]] | ||
*/ | ||
get: function () { | ||
return this._stack.childCount; | ||
return this._stack; | ||
}, | ||
@@ -194,185 +162,26 @@ enumerable: true, | ||
/** | ||
* Get the widget at a specific index. | ||
* Handle the `currentItemChanged` signal from the tab bar. | ||
* | ||
* @param index - The index of the widget of interest. | ||
* | ||
* @returns The widget widget at the specified index, or `undefined` | ||
* if the index is out of range. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetIndex]] | ||
*/ | ||
TabPanel.prototype.widgetAt = function (index) { | ||
return this._stack.childAt(index); | ||
}; | ||
/** | ||
* Get the index of a specific widget. | ||
* | ||
* @param widget - The widget of interest. | ||
* | ||
* @returns The index of the specified widget, or `-1` if the widget | ||
* is not contained in the tab panel. | ||
* | ||
* **See also:** [[widgetCount]], [[widgetAt]] | ||
*/ | ||
TabPanel.prototype.widgetIndex = function (widget) { | ||
return this._stack.childIndex(widget); | ||
}; | ||
/** | ||
* Add a widget to the end of the panel. | ||
* | ||
* @param widget - The widget to add to the panel. | ||
* | ||
* @returns The new index of the widget. | ||
* | ||
* #### Notes | ||
* If the widget already exists in the panel, it will first be | ||
* removed. | ||
* This can be reimplemented by subclasses as needed. | ||
* | ||
* The `TabPanel.tab` attached property *must* be set with the | ||
* tab to use for the widget, or an error will be thrown. This | ||
* can be set via `TabPanel.setTab`. | ||
* | ||
* The `TabPanel.tab` attached property is assumed to remain | ||
* constant while the widget is contained by the tab panel. | ||
* | ||
* **See also:** [[insertWidget]], [[moveWidget]] | ||
* The default implementation of this method synchronizes the current | ||
* tab item with current widget of the stacked panel. | ||
*/ | ||
TabPanel.prototype.addWidget = function (widget) { | ||
return this.insertWidget(this.widgetCount, widget); | ||
TabPanel.prototype.onCurrentItemChanged = function (sender, args) { | ||
this._stack.currentWidget = args.newValue; | ||
}; | ||
/** | ||
* Insert a widget into the panel at the given index. | ||
* Handle the `itemCloseRequested` signal from the tab bar. | ||
* | ||
* @param index - The target index for the widget. This will be | ||
* clamped to the bounds of the widgets. | ||
* | ||
* @param widget - The widget to insert into the panel. | ||
* | ||
* @returns The new index of the widget. | ||
* | ||
* #### Notes | ||
* If the widget already exists in the panel, it will first be | ||
* removed. | ||
* This can be reimplemented by subclasses as needed. | ||
* | ||
* The `TabPanel.tab` attached property *must* be set with the | ||
* tab to use for the widget, or an error will be thrown. This | ||
* can be set via `TabPanel.setTab`. | ||
* | ||
* The `TabPanel.tab` attached property is assumed to remain | ||
* constant while the widget is contained by the tab panel. | ||
* | ||
* **See also:** [[addWidget]], [[moveWidget]] | ||
* The default implementation of this method closes the widget if the | ||
* widget's title object has its `closable` flag set to `true`. | ||
*/ | ||
TabPanel.prototype.insertWidget = function (index, widget) { | ||
var tab = TabPanel.getTab(widget); | ||
if (!tab) | ||
throw new Error('`TabPanel.tab` property not set'); | ||
var i = this._stack.insertChild(index, widget); | ||
return this._tabs.insertTab(i, tab); | ||
TabPanel.prototype.onItemCloseRequested = function (sender, args) { | ||
if (args.title.closable) | ||
args.close(); | ||
}; | ||
/** | ||
* Move a widget from one index to another. | ||
* | ||
* @param fromIndex - The index of the widget of interest. | ||
* | ||
* @param toIndex - The target index for the widget. | ||
* | ||
* @returns 'true' if the widget was moved, or `false` if either | ||
* of the given indices are out of range. | ||
* | ||
* #### Notes | ||
* This can be more efficient than re-inserting an existing widget. | ||
* | ||
* **See also:** [[addWidget]], [[insertWidget]] | ||
*/ | ||
TabPanel.prototype.moveWidget = function (fromIndex, toIndex) { | ||
return this._tabs.moveTab(fromIndex, toIndex); | ||
}; | ||
/** | ||
* Remove the widget at a specific index. | ||
* | ||
* @param index - The index of the widget of interest. | ||
* | ||
* @returns The removed widget, or `undefined` if the index | ||
* is out of range. | ||
* | ||
* **See also:** [[removeWidget]], [[clearWidgets]] | ||
*/ | ||
TabPanel.prototype.removeWidgetAt = function (index) { | ||
return this._stack.removeChildAt(index); | ||
}; | ||
/** | ||
* Remove a specific widget from the panel. | ||
* | ||
* @param child - The widget of interest. | ||
* | ||
* @returns The index which the widget occupied, or `-1` if the | ||
* widget is not contained in the tab panel. | ||
* | ||
* **See also:** [[removeWidgetAt]], [[clearWidgets]] | ||
*/ | ||
TabPanel.prototype.removeWidget = function (widget) { | ||
return this._stack.removeChild(widget); | ||
}; | ||
/** | ||
* Remove all widgets from the tab panel. | ||
* | ||
* **See also:** [[removeWidget]], [[removeWidgetAt]] | ||
*/ | ||
TabPanel.prototype.clearWidgets = function () { | ||
this._stack.clearChildren(); | ||
}; | ||
/** | ||
* Handle the `tabMoved` signal from the tab bar. | ||
*/ | ||
TabPanel.prototype._onTabMoved = function (sender, args) { | ||
this._stack.moveChild(args.fromIndex, args.toIndex); | ||
}; | ||
/** | ||
* Handle the `tabSelected` signal from the tab bar. | ||
*/ | ||
TabPanel.prototype._onTabSelected = function (sender, args) { | ||
this._stack.currentWidget = this._stack.childAt(args.index); | ||
}; | ||
/** | ||
* Handle the `tabCloseRequested` signal from the tab bar. | ||
*/ | ||
TabPanel.prototype._onTabCloseRequested = function (sender, args) { | ||
this._stack.childAt(args.index).close(); | ||
}; | ||
/** | ||
* Handle the `currentChanged` signal from the stacked panel. | ||
*/ | ||
TabPanel.prototype._onCurrentChanged = function (sender, args) { | ||
this.currentChanged.emit(args); | ||
}; | ||
/** | ||
* Handle the `widgetRemoved` signal from the stacked panel. | ||
*/ | ||
TabPanel.prototype._onWidgetRemoved = function (sender, args) { | ||
this._tabs.removeTabAt(args.index); | ||
}; | ||
/** | ||
* A signal emitted when the current widget is changed. | ||
* | ||
* **See also:** [[currentChanged]] | ||
*/ | ||
TabPanel.currentChangedSignal = new phosphor_signaling_1.Signal(); | ||
/** | ||
* The property descriptor for the tab attached property. | ||
* | ||
* This controls the tab used for a widget in a tab panel. | ||
* | ||
* #### Notes | ||
* If the tab for a widget is changed, the new tab will not be | ||
* reflected until the widget is re-inserted into the tab panel. | ||
* However, in-place changes to the tab's properties **will** be | ||
* reflected. | ||
* | ||
* **See also:** [[getTab]], [[setTab]] | ||
*/ | ||
TabPanel.tabProperty = new phosphor_properties_1.Property({ | ||
value: null, | ||
coerce: function (owner, value) { return value || null; }, | ||
}); | ||
return TabPanel; | ||
@@ -379,0 +188,0 @@ })(phosphor_boxpanel_1.BoxPanel); |
{ | ||
"name": "phosphor-tabs", | ||
"version": "0.9.8", | ||
"version": "1.0.0-beta", | ||
"description": "Phosphor widgets for creating tab bars and tab panels.", | ||
@@ -8,12 +8,13 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"phosphor-arrays": "^1.0.5", | ||
"phosphor-boxpanel": "^0.9.7", | ||
"phosphor-disposable": "^1.0.4", | ||
"phosphor-domutil": "^0.9.5", | ||
"phosphor-arrays": "^1.0.6", | ||
"phosphor-boxpanel": "^1.0.0-beta", | ||
"phosphor-disposable": "^1.0.5", | ||
"phosphor-domutil": "^1.0.1", | ||
"phosphor-messaging": "^1.0.5", | ||
"phosphor-nodewrapper": "^1.0.4", | ||
"phosphor-properties": "^1.3.0", | ||
"phosphor-observablelist": "^1.0.0-beta", | ||
"phosphor-properties": "^2.0.0", | ||
"phosphor-signaling": "^1.1.2", | ||
"phosphor-stackedpanel": "^0.9.6", | ||
"phosphor-widget": "^0.9.13" | ||
"phosphor-stackedpanel": "^1.0.0-beta.1", | ||
"phosphor-widget": "^1.0.0-beta.1" | ||
}, | ||
@@ -62,11 +63,5 @@ "devDependencies": { | ||
"files": [ | ||
"lib/index.css", | ||
"lib/index.d.ts", | ||
"lib/index.js", | ||
"lib/tab.d.ts", | ||
"lib/tab.js", | ||
"lib/tabbar.d.ts", | ||
"lib/tabbar.js", | ||
"lib/tabpanel.d.ts", | ||
"lib/tabpanel.js" | ||
"lib/*.css", | ||
"lib/*.d.ts", | ||
"lib/*.js" | ||
], | ||
@@ -73,0 +68,0 @@ "browserify": { |
@@ -111,1 +111,32 @@ phosphor-tabs | ||
omit the type declarations when using a language other than TypeScript. | ||
```typescript | ||
import { | ||
TabPanel | ||
} from 'phosphor-tabs'; | ||
import { | ||
Widget | ||
} from 'phosphor-widget'; | ||
function main(): void { | ||
let one = new Widget(); | ||
one.title.text = 'One'; | ||
let two = new Widget(); | ||
two.title.text = 'Two'; | ||
let three = new Widget(); | ||
three.title.text = 'Three'; | ||
// Note: A `TabBar` can also be used independently of a `TabPanel`. | ||
let panel = new TabPanel(); | ||
panel.tabsMovable = true; | ||
panel.widgets.assign([one, two, three]); | ||
Widget.attach(panel, document.body); | ||
window.onresize = () => panel.update(); | ||
} | ||
``` |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
0
142
69057
11
10
1861
1
+ Addedphosphor-boxengine@1.0.1(transitive)
+ Addedphosphor-boxpanel@1.0.0-rc.0(transitive)
+ Addedphosphor-domutil@1.2.0(transitive)
+ Addedphosphor-observablelist@1.0.0-beta(transitive)
+ Addedphosphor-panel@1.0.0-rc.1(transitive)
+ Addedphosphor-properties@2.0.0(transitive)
+ Addedphosphor-stackedpanel@1.0.0-rc.0(transitive)
+ Addedphosphor-widget@1.0.0-rc.1(transitive)
- Removedphosphor-boxengine@0.9.4(transitive)
- Removedphosphor-boxpanel@0.9.7(transitive)
- Removedphosphor-domutil@0.9.6(transitive)
- Removedphosphor-properties@1.3.0(transitive)
- Removedphosphor-stackedpanel@0.9.6(transitive)
- Removedphosphor-widget@0.9.13(transitive)
Updatedphosphor-arrays@^1.0.6
Updatedphosphor-disposable@^1.0.5
Updatedphosphor-domutil@^1.0.1
Updatedphosphor-properties@^2.0.0