New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

phosphor-tabs

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

phosphor-tabs - npm Package Compare versions

Comparing version 1.0.0-beta.4 to 1.0.0-rc.0

190

lib/tabbar.d.ts
import { Message } from 'phosphor-messaging';
import { IChangedArgs } from 'phosphor-properties';
import { ISignal } from 'phosphor-signaling';
import { Title, Widget } from 'phosphor-widget';
/**
* An object which can be added to a tab bar.
*/
export interface ITabItem {
/**
* The title object which supplies the data for a tab.
*/
title: Title;
}
/**
* The arguments object for various tab bar signals.
*/
export interface ITabIndexArgs {
/**
* The index of the tab.
*/
index: number;
/**
* The tab item for the tab.
*/
item: ITabItem;
}
/**
* The arguments object for a `tabMoved` signal.

@@ -17,2 +38,6 @@ */

toIndex: number;
/**
* The tab item for the tab.
*/
item: ITabItem;
}

@@ -22,12 +47,4 @@ /**

*/
export interface ITabDetachArgs {
export interface ITabDetachArgs extends ITabIndexArgs {
/**
* The title being dragged by the user.
*/
title: Title;
/**
* The DOM node for the tab being dragged.
*/
node: HTMLElement;
/**
* The current client X position of the mouse.

@@ -42,3 +59,3 @@ */

/**
* A widget which displays titles as a row of selectable tabs.
* A widget which displays tab items as a row of tabs.
*/

@@ -51,2 +68,49 @@ export declare class TabBar extends Widget {

/**
* Create and initialize a tab node for a tab bar.
*
* @param title - The title to use for the initial tab state.
*
* @returns A new DOM node to use as a tab in a tab bar.
*
* #### Notes
* It is not necessary to subscribe to the `changed` signal of the
* title. The tab bar subscribes to that signal and will call the
* [[updateTab]] static method automatically as needed.
*
* This method may be reimplemented to create custom tabs.
*/
static createTab(title: Title): HTMLElement;
/**
* Update a tab node to reflect the current state of a title.
*
* @param tab - A tab node created by a call to [[createTab]].
*
* @param title - The title object to use for the tab state.
*
* #### Notes
* This is called automatically when the title state changes.
*
* If the [[createTab]] method is reimplemented, this method should
* also be reimplemented so that the tab state is properly updated.
*/
static updateTab(tab: HTMLElement, title: Title): void;
/**
* Get the close icon node for a given tab node.
*
* @param tab - A tab node created by a call to [[createTab]].
*
* @returns The close icon node for the tab node.
*
* #### Notes
* The close icon node is used to correctly process click events.
*
* If the [[createTab]] method is reimplemented, this method should
* also be reimplemented so that the correct icon node is returned.
*/
static tabCloseIcon(tab: HTMLElement): HTMLElement;
/**
* The static type of the constructor.
*/
'constructor': typeof TabBar;
/**
* Construct a new tab bar.

@@ -60,2 +124,6 @@ */

/**
* A signal emitted when the current tab is changed.
*/
currentChanged: ISignal<TabBar, ITabIndexArgs>;
/**
* A signal emitted when a tab is moved by the user.

@@ -67,3 +135,3 @@ */

*/
tabCloseRequested: ISignal<TabBar, Title>;
tabCloseRequested: ISignal<TabBar, ITabIndexArgs>;
/**

@@ -74,13 +142,9 @@ * A signal emitted when a tab is dragged beyond the detach threshold.

/**
* A signal emitted when the current title is changed.
* Get the currently selected tab item.
*/
currentChanged: ISignal<TabBar, IChangedArgs<Title>>;
/**
* Get the currently selected title.
* Set the currently selected tab item.
*/
currentItem: ITabItem;
/**
* Set the currently selected title.
*/
currentTitle: Title;
/**
* Get whether the tabs are movable by the user.

@@ -93,15 +157,6 @@ */

/**
* Get the tab bar header node.
*
* #### Notes
* This can be used to add extra header content.
*
* This is a read-only property.
*/
headerNode: HTMLElement;
/**
* Get the tab bar body node.
*
* #### Notes
* This can be used to add extra body content.
* This node can be used to add extra content to the tab bar.
*

@@ -115,4 +170,6 @@ * This is a read-only property.

* #### Notes
* Modifying this node can lead to undefined behavior.
* This is the node which holds the tab nodes.
*
* Modifying this node directly can lead to undefined behavior.
*
* This is a read-only property.

@@ -122,61 +179,60 @@ */

/**
* Get the tab bar footer node.
* Get the number of tab items in the tab bar.
*
* #### Notes
* This can be used to add extra footer content.
*
* This is a read-only property.
* @returns The number of tab items in the tab bar.
*/
footerNode: HTMLElement;
itemCount(): number;
/**
* Get the number of title objects in the tab bar.
* Get the tab item at the specified index.
*
* @returns The number of title objects in the tab bar.
* @param index - The index of the tab item of interest.
*
* @returns The tab item at the specified index, or `undefined`.
*/
titleCount(): number;
itemAt(index: number): ITabItem;
/**
* Get the title object at the specified index.
* Get the index of the specified tab item.
*
* @param index - The index of the title object of interest.
* @param item - The tab item of interest.
*
* @returns The title at the specified index, or `undefined`.
* @returns The index of the specified item, or `-1`.
*/
titleAt(index: number): Title;
itemIndex(item: ITabItem): number;
/**
* Get the index of the specified title object.
* Add a tab item to the end of the tab bar.
*
* @param title - The title object of interest.
* @param item - The tab item to add to the tab bar.
*
* @returns The index of the specified title, or `-1`.
* #### Notes
* If the item is already added to the tab bar, it will be moved.
*/
titleIndex(title: Title): number;
addItem(item: ITabItem): void;
/**
* Add a title object to the end of the tab bar.
* Insert a tab item at the specified index.
*
* @param title - The title object to add to the tab bar.
* @param index - The index at which to insert the item.
*
* @param item - The tab item to insert into the tab bar.
*
* #### Notes
* If the title is already added to the tab bar, it will be moved.
* If the item is already added to the tab bar, it will be moved.
*/
addTitle(title: Title): void;
insertItem(index: number, item: ITabItem): void;
/**
* Insert a title object at the specified index.
* Remove a tab item from the tab bar.
*
* @param index - The index at which to insert the title.
* @param item - The tab item to remove from the tab bar.
*
* @param title - The title object to insert into to the tab bar.
*
* #### Notes
* If the title is already added to the tab bar, it will be moved.
* If the item is not in the tab bar, this is a no-op.
*/
insertTitle(index: number, title: Title): void;
removeItem(item: ITabItem): void;
/**
* Remove a title object from the tab bar.
* Get the tab node for the item at the given index.
*
* @param title - The title object to remove from the tab bar.
* @param index - The index of the tab item of interest.
*
* #### Notes
* If the title is not in the tab bar, this is a no-op.
* @returns The tab node for the item, or `undefined`.
*/
removeTitle(title: Title): void;
tabAt(index: number): HTMLElement;
/**

@@ -238,13 +294,11 @@ * Release the mouse and restore the non-dragged tab positions.

/**
* Move a tab from one index to another.
*/
private _moveTab(i, j);
/**
* Handle the `changed` signal of a title object.
*/
private _onTitleChanged(sender);
private _dirty;
private _tabsMovable;
private _titles;
private _items;
private _tabs;
private _dirtySet;
private _currentItem;
private _dragData;
}

@@ -16,6 +16,4 @@ /*-----------------------------------------------------------------------------

var phosphor_domutil_1 = require('phosphor-domutil');
var phosphor_properties_1 = require('phosphor-properties');
var phosphor_signaling_1 = require('phosphor-signaling');
var phosphor_widget_1 = require('phosphor-widget');
// TODO - need better solution for storing these class names
/**

@@ -26,20 +24,12 @@ * The class name added to TabBar instances.

/**
* The class name added to the tab bar header node.
* The class name added to a tab bar body node.
*/
var HEADER_CLASS = 'p-TabBar-header';
/**
* 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.
* The class name added to a tab bar content node.
*/
var CONTENT_CLASS = 'p-TabBar-content';
/**
* The class name added to the tab bar footer node.
* The class name added to a tab bar tab.
*/
var FOOTER_CLASS = 'p-TabBar-footer';
/**
* The class name added to a tab.
*/
var TAB_CLASS = 'p-TabBar-tab';

@@ -49,11 +39,11 @@ /**

*/
var TEXT_CLASS = 'p-TabBar-tab-text';
var TEXT_CLASS = 'p-TabBar-tabText';
/**
* The class name added to a tab icon node.
*/
var ICON_CLASS = 'p-TabBar-tab-icon';
var ICON_CLASS = 'p-TabBar-tabIcon';
/**
* The class name added to a tab close node.
* The class name added to a tab close icon node.
*/
var CLOSE_CLASS = 'p-TabBar-tab-close';
var CLOSE_CLASS = 'p-TabBar-tabCloseIcon';
/**

@@ -84,3 +74,3 @@ * The class name added to a tab bar and tab when dragging.

/**
* A widget which displays titles as a row of selectable tabs.
* A widget which displays tab items as a row of tabs.
*/

@@ -94,5 +84,7 @@ var TabBar = (function (_super) {

_super.call(this);
this._dirty = false;
this._tabsMovable = false;
this._titles = [];
this._items = [];
this._tabs = [];
this._dirtySet = new Set();
this._currentItem = null;
this._dragData = null;

@@ -106,17 +98,79 @@ this.addClass(TAB_BAR_CLASS);

var node = document.createElement('div');
var header = 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(body);
node.appendChild(footer);
return node;
};
/**
* Create and initialize a tab node for a tab bar.
*
* @param title - The title to use for the initial tab state.
*
* @returns A new DOM node to use as a tab in a tab bar.
*
* #### Notes
* It is not necessary to subscribe to the `changed` signal of the
* title. The tab bar subscribes to that signal and will call the
* [[updateTab]] static method automatically as needed.
*
* This method may be reimplemented to create custom tabs.
*/
TabBar.createTab = function (title) {
var node = document.createElement('li');
var icon = document.createElement('span');
var text = document.createElement('span');
var close = document.createElement('span');
node.className = TAB_CLASS;
icon.className = ICON_CLASS;
text.className = TEXT_CLASS;
close.className = CLOSE_CLASS;
node.appendChild(icon);
node.appendChild(text);
node.appendChild(close);
this.updateTab(node, title);
return node;
};
/**
* Update a tab node to reflect the current state of a title.
*
* @param tab - A tab node created by a call to [[createTab]].
*
* @param title - The title object to use for the tab state.
*
* #### Notes
* This is called automatically when the title state changes.
*
* If the [[createTab]] method is reimplemented, this method should
* also be reimplemented so that the tab state is properly updated.
*/
TabBar.updateTab = function (tab, title) {
var tabInfix = title.className ? ' ' + title.className : '';
var tabSuffix = title.closable ? ' ' + CLOSABLE_CLASS : '';
var iconSuffix = title.icon ? ' ' + title.icon : '';
var icon = tab.firstChild;
var text = icon.nextSibling;
tab.className = TAB_CLASS + tabInfix + tabSuffix;
icon.className = ICON_CLASS + iconSuffix;
text.textContent = title.text;
};
/**
* Get the close icon node for a given tab node.
*
* @param tab - A tab node created by a call to [[createTab]].
*
* @returns The close icon node for the tab node.
*
* #### Notes
* The close icon node is used to correctly process click events.
*
* If the [[createTab]] method is reimplemented, this method should
* also be reimplemented so that the correct icon node is returned.
*/
TabBar.tabCloseIcon = function (tab) {
return tab.lastChild;
};
/**
* Dispose of the resources held by the widget.

@@ -126,5 +180,18 @@ */

this._releaseMouse();
this._titles.length = 0;
this._tabs.length = 0;
this._items.length = 0;
this._dirtySet.clear();
this._currentItem = null;
_super.prototype.dispose.call(this);
};
Object.defineProperty(TabBar.prototype, "currentChanged", {
/**
* A signal emitted when the current tab is changed.
*/
get: function () {
return TabBarPrivate.currentChangedSignal.bind(this);
},
enumerable: true,
configurable: true
});
Object.defineProperty(TabBar.prototype, "tabMoved", {

@@ -160,24 +227,25 @@ /**

});
Object.defineProperty(TabBar.prototype, "currentChanged", {
Object.defineProperty(TabBar.prototype, "currentItem", {
/**
* A signal emitted when the current title is changed.
* Get the currently selected tab item.
*/
get: function () {
return TabBarPrivate.currentChangedSignal.bind(this);
return this._currentItem;
},
enumerable: true,
configurable: true
});
Object.defineProperty(TabBar.prototype, "currentTitle", {
/**
* Get the currently selected title.
* Set the currently selected tab item.
*/
get: function () {
return TabBarPrivate.currentTitleProperty.get(this);
},
/**
* Set the currently selected title.
*/
set: function (value) {
TabBarPrivate.currentTitleProperty.set(this, value);
var item = value || null;
if (this._currentItem === item) {
return;
}
var index = item ? this._items.indexOf(item) : -1;
if (item && index === -1) {
console.warn('Tab item not contained in tab bar.');
return;
}
this._currentItem = item;
this.currentChanged.emit({ index: index, item: item });
this.update();
},

@@ -203,17 +271,2 @@ enumerable: true,

});
Object.defineProperty(TabBar.prototype, "headerNode", {
/**
* Get the tab bar header node.
*
* #### Notes
* This can be used to add extra header content.
*
* This is a read-only property.
*/
get: function () {
return this.node.getElementsByClassName(HEADER_CLASS)[0];
},
enumerable: true,
configurable: true
});
Object.defineProperty(TabBar.prototype, "bodyNode", {

@@ -224,3 +277,3 @@ /**

* #### Notes
* This can be used to add extra body content.
* This node can be used to add extra content to the tab bar.
*

@@ -240,4 +293,6 @@ * This is a read-only property.

* #### Notes
* Modifying this node can lead to undefined behavior.
* This is the node which holds the tab nodes.
*
* Modifying this node directly can lead to undefined behavior.
*
* This is a read-only property.

@@ -251,72 +306,55 @@ */

});
Object.defineProperty(TabBar.prototype, "footerNode", {
/**
* Get the tab bar footer node.
*
* #### Notes
* This can be used to add extra footer content.
*
* This is a read-only property.
*/
get: function () {
return this.node.getElementsByClassName(FOOTER_CLASS)[0];
},
enumerable: true,
configurable: true
});
/**
* Get the number of title objects in the tab bar.
* Get the number of tab items in the tab bar.
*
* @returns The number of title objects in the tab bar.
* @returns The number of tab items in the tab bar.
*/
TabBar.prototype.titleCount = function () {
return this._titles.length;
TabBar.prototype.itemCount = function () {
return this._items.length;
};
/**
* Get the title object at the specified index.
* Get the tab item at the specified index.
*
* @param index - The index of the title object of interest.
* @param index - The index of the tab item of interest.
*
* @returns The title at the specified index, or `undefined`.
* @returns The tab item at the specified index, or `undefined`.
*/
TabBar.prototype.titleAt = function (index) {
return this._titles[index];
TabBar.prototype.itemAt = function (index) {
return this._items[index];
};
/**
* Get the index of the specified title object.
* Get the index of the specified tab item.
*
* @param title - The title object of interest.
* @param item - The tab item of interest.
*
* @returns The index of the specified title, or `-1`.
* @returns The index of the specified item, or `-1`.
*/
TabBar.prototype.titleIndex = function (title) {
return this._titles.indexOf(title);
TabBar.prototype.itemIndex = function (item) {
return this._items.indexOf(item);
};
/**
* Add a title object to the end of the tab bar.
* Add a tab item to the end of the tab bar.
*
* @param title - The title object to add to the tab bar.
* @param item - The tab item to add to the tab bar.
*
* #### Notes
* If the title is already added to the tab bar, it will be moved.
* If the item is already added to the tab bar, it will be moved.
*/
TabBar.prototype.addTitle = function (title) {
this.insertTitle(this.titleCount(), title);
TabBar.prototype.addItem = function (item) {
this.insertItem(this.itemCount(), item);
};
/**
* Insert a title object at the specified index.
* Insert a tab item at the specified index.
*
* @param index - The index at which to insert the title.
* @param index - The index at which to insert the item.
*
* @param title - The title object to insert into to the tab bar.
* @param item - The tab item to insert into the tab bar.
*
* #### Notes
* If the title is already added to the tab bar, it will be moved.
* If the item is already added to the tab bar, it will be moved.
*/
TabBar.prototype.insertTitle = function (index, title) {
// Release the mouse before making changes.
TabBar.prototype.insertItem = function (index, item) {
this._releaseMouse();
// Insert the new title or move an existing title.
var n = this.titleCount();
var i = this.titleIndex(title);
var n = this._items.length;
var i = this._items.indexOf(item);
var j = Math.max(0, Math.min(index | 0, n));

@@ -328,41 +366,52 @@ if (i !== -1) {

return;
arrays.move(this._titles, i, j);
arrays.move(this._tabs, i, j);
arrays.move(this._items, i, j);
this.contentNode.insertBefore(this._tabs[j], this._tabs[j + 1]);
}
else {
arrays.insert(this._titles, j, title);
title.changed.connect(this._onTitleChanged, this);
if (!this.currentTitle)
this.currentTitle = title;
var tab = this.constructor.createTab(item.title);
arrays.insert(this._tabs, j, tab);
arrays.insert(this._items, j, item);
this.contentNode.insertBefore(tab, this._tabs[j + 1]);
item.title.changed.connect(this._onTitleChanged, this);
if (!this.currentItem)
this.currentItem = item;
}
// Flip the dirty flag and schedule a full update.
this._dirty = true;
this.update();
};
/**
* Remove a title object from the tab bar.
* Remove a tab item from the tab bar.
*
* @param title - The title object to remove from the tab bar.
* @param item - The tab item to remove from the tab bar.
*
* #### Notes
* If the title is not in the tab bar, this is a no-op.
* If the item is not in the tab bar, this is a no-op.
*/
TabBar.prototype.removeTitle = function (title) {
// Release the mouse before making changes.
TabBar.prototype.removeItem = function (item) {
this._releaseMouse();
// Remove the specified title, or bail if it doesn't exist.
var i = arrays.remove(this._titles, title);
var i = arrays.remove(this._items, item);
if (i === -1) {
return;
}
// Disconnect the title changed handler.
title.changed.disconnect(this._onTitleChanged, this);
// Selected the next best tab if removing the current tab.
if (this.currentTitle === title) {
this.currentTitle = this._titles[i] || this._titles[i - 1];
this._dirtySet.delete(item.title);
item.title.changed.disconnect(this._onTitleChanged, this);
this.contentNode.removeChild(arrays.removeAt(this._tabs, i));
if (this.currentItem === item) {
var next = this._items[i];
var prev = this._items[i - 1];
this.currentItem = next || prev;
}
// Flip the dirty flag and schedule a full update.
this._dirty = true;
this.update();
};
/**
* Get the tab node for the item at the given index.
*
* @param index - The index of the tab item of interest.
*
* @returns The tab node for the item, or `undefined`.
*/
TabBar.prototype.tabAt = function (index) {
return this._tabs[index];
};
/**
* Release the mouse and restore the non-dragged tab positions.

@@ -421,5 +470,5 @@ *

TabBar.prototype.onBeforeDetach = function (msg) {
this._releaseMouse();
this.node.removeEventListener('click', this);
this.node.removeEventListener('mousedown', this);
this._releaseMouse();
};

@@ -430,9 +479,23 @@ /**

TabBar.prototype.onUpdateRequest = function (msg) {
if (this._dirty) {
this._dirty = false;
TabBarPrivate.updateTabs(this);
var tabs = this._tabs;
var items = this._items;
var dirty = this._dirtySet;
var current = this._currentItem;
var constructor = this.constructor;
for (var i = 0, n = tabs.length; i < n; ++i) {
var tab = tabs[i];
var item = items[i];
if (dirty.has(item.title)) {
constructor.updateTab(tab, item.title);
}
if (item === current) {
tab.classList.add(CURRENT_CLASS);
tab.style.zIndex = "" + n;
}
else {
tab.classList.remove(CURRENT_CLASS);
tab.style.zIndex = "" + (n - i - 1);
}
}
else {
TabBarPrivate.updateZOrder(this);
}
dirty.clear();
};

@@ -463,3 +526,5 @@ /**

// Do nothing if the click is not on a tab.
var i = TabBarPrivate.hitTestTabs(this, event.clientX, event.clientY);
var x = event.clientX;
var y = event.clientY;
var i = arrays.findIndex(this._tabs, function (tab) { return phosphor_domutil_1.hitTest(tab, x, y); });
if (i < 0) {

@@ -472,8 +537,8 @@ return;

// Ignore the click if the title is not closable.
var title = this._titles[i];
if (!title.closable) {
var item = this._items[i];
if (!item.title.closable) {
return;
}
// Ignore the click if the close icon wasn't clicked.
var icon = TabBarPrivate.closeIconNode(this, i);
// Ignore the click if it was not on a close icon.
var icon = this.constructor.tabCloseIcon(this._tabs[i]);
if (!icon.contains(event.target)) {

@@ -483,3 +548,3 @@ return;

// Emit the tab close requested signal.
this.tabCloseRequested.emit(title);
this.tabCloseRequested.emit({ index: i, item: item });
};

@@ -499,3 +564,5 @@ /**

// Do nothing if the press is not on a tab.
var i = TabBarPrivate.hitTestTabs(this, event.clientX, event.clientY);
var x = event.clientX;
var y = event.clientY;
var i = arrays.findIndex(this._tabs, function (tab) { return phosphor_domutil_1.hitTest(tab, x, y); });
if (i < 0) {

@@ -508,3 +575,3 @@ return;

// Ignore the press if it was on a close icon.
var icon = TabBarPrivate.closeIconNode(this, i);
var icon = this.constructor.tabCloseIcon(this._tabs[i]);
if (icon.contains(event.target)) {

@@ -515,3 +582,7 @@ return;

if (this._tabsMovable) {
this._dragData = TabBarPrivate.initDrag(i, event);
this._dragData = new TabBarPrivate.DragData();
this._dragData.index = i;
this._dragData.tab = this._tabs[i];
this._dragData.pressX = event.clientX;
this._dragData.pressY = event.clientY;
document.addEventListener('mousemove', this, true);

@@ -522,4 +593,4 @@ document.addEventListener('mouseup', this, true);

}
// Update the current title.
this.currentTitle = this._titles[i];
// Update the current item to the pressed item.
this.currentItem = this._items[i];
};

@@ -537,4 +608,37 @@ /**

event.stopPropagation();
// Update the tab drag positions.
TabBarPrivate.moveDrag(this, this._dragData, event);
// Ensure the drag threshold is exceeded before moving the tab.
var data = this._dragData;
if (!data.dragActive) {
var dx = Math.abs(event.clientX - data.pressX);
var dy = Math.abs(event.clientY - data.pressY);
if (dx < DRAG_THRESHOLD && dy < DRAG_THRESHOLD) {
return;
}
// Fill in the rest of the drag data measurements.
var tabRect = data.tab.getBoundingClientRect();
data.tabLeft = data.tab.offsetLeft;
data.tabWidth = tabRect.width;
data.tabPressX = data.pressX - tabRect.left;
data.tabLayout = TabBarPrivate.snapTabLayout(this._tabs);
data.contentRect = this.contentNode.getBoundingClientRect();
data.override = phosphor_domutil_1.overrideCursor('default');
// Add the dragging classes and mark the drag as active.
data.tab.classList.add(DRAGGING_CLASS);
this.addClass(DRAGGING_CLASS);
data.dragActive = true;
}
// Emit the detach request signal if the threshold is exceeded.
if (!data.detachRequested && TabBarPrivate.detachExceeded(data, event)) {
data.detachRequested = true;
var index = data.index;
var item = this._items[index];
var clientX = event.clientX;
var clientY = event.clientY;
this.tabDetachRequested.emit({ index: index, item: item, clientX: clientX, clientY: clientY });
if (data.dragAborted) {
return;
}
}
// Update the tab layout and computed target index.
TabBarPrivate.layoutTabs(this._tabs, data, event);
};

@@ -562,7 +666,39 @@ /**

document.removeEventListener('contextmenu', this, true);
// End the drag operation.
TabBarPrivate.endDrag(this, this._dragData, event, {
clear: function () { _this._dragData = null; },
move: function (i, j) { _this._moveTab(i, j); },
});
// Bail early if the drag is not active.
var data = this._dragData;
if (!data.dragActive) {
this._dragData = null;
return;
}
// Position the tab at its final resting position.
TabBarPrivate.finalizeTabPosition(data);
// Remove the dragging class from the tab so it can be transitioned.
data.tab.classList.remove(DRAGGING_CLASS);
// Complete the release on a timer to allow the tab to transition.
setTimeout(function () {
// Do nothing if the drag has been aborted.
if (data.dragAborted) {
return;
}
// Clear the drag data reference.
_this._dragData = null;
// Reset the positions of the tabs.
TabBarPrivate.resetTabPositions(_this._tabs);
// Clear the cursor grab and drag styles.
data.override.dispose();
_this.removeClass(DRAGGING_CLASS);
// If the tab was not moved, there is nothing else to do.
var i = data.index;
var j = data.targetIndex;
if (j === -1 || i === j) {
return;
}
// Move the tab and related tab item to the new location.
arrays.move(_this._tabs, i, j);
arrays.move(_this._items, i, j);
_this.contentNode.insertBefore(_this._tabs[j], _this._tabs[j + 1]);
// Emit the tab moved signal and schedule a render update.
_this.tabMoved.emit({ fromIndex: i, toIndex: j, item: _this._items[j] });
_this.update();
}, TRANSITION_DURATION);
};

@@ -582,23 +718,24 @@ /**

document.removeEventListener('contextmenu', this, true);
// Abort the drag operation and clear the drag data.
TabBarPrivate.abortDrag(this, this._dragData);
// Clear the drag data reference.
var data = this._dragData;
this._dragData = null;
// Indicate the drag has been aborted. This allows the mouse
// event handlers to return early when the drag is canceled.
data.dragAborted = true;
// If the drag is not active, there's nothing more to do.
if (!data.dragActive) {
return;
}
// Reset the tabs to their non-dragged positions.
TabBarPrivate.resetTabPositions(this._tabs);
// Clear the cursor override and extra styling classes.
data.override.dispose();
data.tab.classList.remove(DRAGGING_CLASS);
this.removeClass(DRAGGING_CLASS);
};
/**
* Move a tab from one index to another.
*/
TabBar.prototype._moveTab = function (i, j) {
var k = j < i ? j : j + 1;
var content = this.contentNode;
var children = content.children;
arrays.move(this._titles, i, j);
content.insertBefore(children[i], children[k]);
this.tabMoved.emit({ fromIndex: i, toIndex: j });
this.update();
};
/**
* Handle the `changed` signal of a title object.
*/
TabBar.prototype._onTitleChanged = function (sender) {
this._dirty = true;
this._dirtySet.add(sender);
this.update();

@@ -610,66 +747,2 @@ };

/**
* A struct which holds the drag data for a tab bar.
*/
var DragData = (function () {
function DragData() {
/**
* The tab node being dragged.
*/
this.tab = null;
/**
* The index of the tab being dragged.
*/
this.tabIndex = -1;
/**
* The offset left of the tab being dragged.
*/
this.tabLeft = -1;
/**
* The offset width of the tab being dragged.
*/
this.tabWidth = -1;
/**
* The original mouse X position in tab coordinates.
*/
this.tabPressX = -1;
/**
* The tab target index upon mouse release.
*/
this.targetIndex = -1;
/**
* The array of tab layout objects snapped at drag start.
*/
this.tabLayout = null;
/**
* The mouse press client X position.
*/
this.pressX = -1;
/**
* The mouse press client Y position.
*/
this.pressY = -1;
/**
* The bounding client rect of the tab bar content node.
*/
this.contentRect = null;
/**
* The disposable to clean up the cursor override.
*/
this.cursorGrab = null;
/**
* Whether the drag is currently active.
*/
this.dragActive = false;
/**
* Whether the drag has been aborted.
*/
this.dragAborted = false;
/**
* Whether a detach request as been made.
*/
this.detachRequested = false;
}
return DragData;
})();
/**
* The namespace for the `TabBar` class private data.

@@ -680,3 +753,3 @@ */

/**
* A signal emitted when the current title is changed.
* A signal emitted when the current tab item is changed.
*/

@@ -697,315 +770,154 @@ TabBarPrivate.currentChangedSignal = new phosphor_signaling_1.Signal();

/**
* The property descriptor for the currently selected title.
* A struct which holds the drag data for a tab bar.
*/
TabBarPrivate.currentTitleProperty = new phosphor_properties_1.Property({
name: 'currentTitle',
value: null,
coerce: coerceCurrentTitle,
changed: onCurrentTitleChanged,
notify: TabBarPrivate.currentChangedSignal,
});
/**
* Get the close icon node for the tab at the specified index.
*/
function closeIconNode(owner, index) {
return owner.contentNode.children[index].lastChild;
}
TabBarPrivate.closeIconNode = closeIconNode;
/**
* Get the index of the tab node at a client position, or `-1`.
*/
function hitTestTabs(owner, x, y) {
var nodes = owner.contentNode.children;
for (var i = 0, n = nodes.length; i < n; ++i) {
if (phosphor_domutil_1.hitTest(nodes[i], x, y))
return i;
var DragData = (function () {
function DragData() {
/**
* The tab node being dragged.
*/
this.tab = null;
/**
* The index of the tab being dragged.
*/
this.index = -1;
/**
* The offset left of the tab being dragged.
*/
this.tabLeft = -1;
/**
* The offset width of the tab being dragged.
*/
this.tabWidth = -1;
/**
* The original mouse X position in tab coordinates.
*/
this.tabPressX = -1;
/**
* The tab target index upon mouse release.
*/
this.targetIndex = -1;
/**
* The array of tab layout objects snapped at drag start.
*/
this.tabLayout = null;
/**
* The mouse press client X position.
*/
this.pressX = -1;
/**
* The mouse press client Y position.
*/
this.pressY = -1;
/**
* The bounding client rect of the tab bar content node.
*/
this.contentRect = null;
/**
* The disposable to clean up the cursor override.
*/
this.override = null;
/**
* Whether the drag is currently active.
*/
this.dragActive = false;
/**
* Whether the drag has been aborted.
*/
this.dragAborted = false;
/**
* Whether a detach request as been made.
*/
this.detachRequested = false;
}
return -1;
}
TabBarPrivate.hitTestTabs = hitTestTabs;
return DragData;
})();
TabBarPrivate.DragData = DragData;
/**
* Update the tab bar tabs to match the current titles.
*
* This is a full update which also updates the tab Z order.
* Get a snapshot of the current tab layout values.
*/
function updateTabs(owner) {
var count = owner.titleCount();
var content = owner.contentNode;
var children = content.children;
var current = owner.currentTitle;
while (children.length > count) {
content.removeChild(content.lastChild);
function snapTabLayout(tabs) {
var layout = new Array(tabs.length);
for (var i = 0, n = tabs.length; i < n; ++i) {
var node = tabs[i];
var left = node.offsetLeft;
var width = node.offsetWidth;
var cstyle = window.getComputedStyle(node);
var margin = parseInt(cstyle.marginLeft, 10) || 0;
layout[i] = { margin: margin, left: left, width: width };
}
while (children.length < count) {
content.appendChild(createTabNode());
}
for (var i = 0; i < count; ++i) {
var node = children[i];
updateTabNode(node, owner.titleAt(i));
}
updateZOrder(owner);
return layout;
}
TabBarPrivate.updateTabs = updateTabs;
TabBarPrivate.snapTabLayout = snapTabLayout;
/**
* Update the Z order of the tabs to match the current titles.
*
* This is a partial update which updates the Z order and the current
* tab class. It assumes the tab count is the same as the title count.
* Test if the event exceeds the drag detach threshold.
*/
function updateZOrder(owner) {
var count = owner.titleCount();
var content = owner.contentNode;
var children = content.children;
var current = owner.currentTitle;
for (var i = 0; i < count; ++i) {
var node = children[i];
if (owner.titleAt(i) === current) {
node.classList.add(CURRENT_CLASS);
node.style.zIndex = count + '';
}
else {
node.classList.remove(CURRENT_CLASS);
node.style.zIndex = count - i - 1 + '';
}
}
function detachExceeded(data, event) {
var rect = data.contentRect;
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));
}
TabBarPrivate.updateZOrder = updateZOrder;
TabBarPrivate.detachExceeded = detachExceeded;
/**
* Initialize a new drag data object for a tab bar.
*
* This should be called on 'mousedown' event.
* Update the relative tab positions and computed target index.
*/
function initDrag(tabIndex, event) {
var data = new DragData();
data.tabIndex = tabIndex;
data.pressX = event.clientX;
data.pressY = event.clientY;
return data;
}
TabBarPrivate.initDrag = initDrag;
/**
* Update the drag positions of the tabs for a tab bar.
*
* This should be called on a `'mousemove'` event.
*/
function moveDrag(owner, data, event) {
// Ensure the drag threshold is exceeded before moving the tab.
if (!data.dragActive) {
var dx = Math.abs(event.clientX - data.pressX);
var dy = Math.abs(event.clientY - data.pressY);
if (dx < DRAG_THRESHOLD && dy < DRAG_THRESHOLD) {
return;
}
// Fill in the missing drag data measurements.
var content = owner.contentNode;
var tab = content.children[data.tabIndex];
var tabRect = tab.getBoundingClientRect();
data.tab = tab;
data.tabLeft = tab.offsetLeft;
data.tabWidth = tabRect.width;
data.tabPressX = data.pressX - tabRect.left;
data.contentRect = content.getBoundingClientRect();
data.tabLayout = snapTabLayout(owner);
data.cursorGrab = phosphor_domutil_1.overrideCursor('default');
// Style the tab bar and tab for relative position dragging.
tab.classList.add(DRAGGING_CLASS);
owner.addClass(DRAGGING_CLASS);
data.dragActive = true;
}
// Emit the detach request signal if the threshold is exceeded.
if (!data.detachRequested && detachExceeded(data.contentRect, event)) {
var node = data.tab;
var clientX = event.clientX;
var clientY = event.clientY;
var title = owner.titleAt(data.tabIndex);
owner.tabDetachRequested.emit({ title: title, node: node, clientX: clientX, clientY: clientY });
data.detachRequested = true;
if (data.dragAborted) {
return;
}
}
// Compute the target bounds of the drag tab.
var offsetLeft = event.clientX - data.contentRect.left;
var targetLeft = offsetLeft - data.tabPressX;
function layoutTabs(tabs, data, event) {
var targetIndex = data.index;
var targetLeft = event.clientX - data.contentRect.left - data.tabPressX;
var targetRight = targetLeft + data.tabWidth;
// Reset the target tab index.
data.targetIndex = data.tabIndex;
// Update the non-drag tab positions and the tab target index.
var tabs = owner.contentNode.children;
for (var i = 0, n = tabs.length; i < n; ++i) {
var style = tabs[i].style;
var layout = data.tabLayout[i];
var style = tabs[i].style;
var threshold = layout.left + (layout.width >> 1);
if (i < data.tabIndex && targetLeft < threshold) {
if (i < data.index && targetLeft < threshold) {
style.left = data.tabWidth + data.tabLayout[i + 1].margin + 'px';
data.targetIndex = Math.min(data.targetIndex, i);
targetIndex = Math.min(targetIndex, i);
}
else if (i > data.tabIndex && targetRight > threshold) {
else if (i > data.index && targetRight > threshold) {
style.left = -data.tabWidth - layout.margin + 'px';
data.targetIndex = i;
targetIndex = Math.max(targetIndex, i);
}
else if (i !== data.tabIndex) {
else if (i === data.index) {
var ideal = event.clientX - data.pressX;
var limit = data.contentRect.width - (data.tabLeft + data.tabWidth);
style.left = Math.max(-data.tabLeft, Math.min(ideal, limit)) + 'px';
}
else {
style.left = '';
}
}
// Update the drag tab position.
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.style.left = adjustedLeft + 'px';
data.targetIndex = targetIndex;
}
TabBarPrivate.moveDrag = moveDrag;
TabBarPrivate.layoutTabs = layoutTabs;
/**
* End the drag operation for a tab bar.
*
* This should be called on a `'mouseup'` event.
* Position the drag tab at its final resting relative position.
*/
function endDrag(owner, data, event, handler) {
// Bail early if the drag is not active.
if (!data.dragActive) {
handler.clear();
return;
function finalizeTabPosition(data) {
var ideal;
if (data.targetIndex === data.index) {
ideal = 0;
}
// Compute the approximate final relative tab offset.
var idealLeft;
if (data.targetIndex === data.tabIndex) {
idealLeft = 0;
else if (data.targetIndex > data.index) {
var tgt = data.tabLayout[data.targetIndex];
ideal = tgt.left + tgt.width - data.tabWidth - data.tabLeft;
}
else if (data.targetIndex > data.tabIndex) {
var tl = data.tabLayout[data.targetIndex];
idealLeft = tl.left + tl.width - data.tabWidth - data.tabLeft;
}
else {
var tl = data.tabLayout[data.targetIndex];
idealLeft = tl.left - data.tabLeft;
var tgt = data.tabLayout[data.targetIndex];
ideal = tgt.left - data.tabLeft;
}
// Position the tab to its final position, subject to limits.
var maxLeft = data.contentRect.width - (data.tabLeft + data.tabWidth);
var adjustedLeft = Math.max(-data.tabLeft, Math.min(idealLeft, maxLeft));
data.tab.style.left = adjustedLeft + 'px';
// Remove the dragging class from the tab so it can be transitioned.
data.tab.classList.remove(DRAGGING_CLASS);
// Complete the release on a timer to allow the tab to transition.
setTimeout(function () {
// Do nothing if the drag has been aborted.
if (data.dragAborted) {
return;
}
// Clear the drag data reference.
handler.clear();
// Reset the positions of the tabs.
resetTabPositions(owner);
// Clear the cursor grab and drag styles.
data.cursorGrab.dispose();
owner.removeClass(DRAGGING_CLASS);
// Finally, move the tab to its new location.
if (data.targetIndex !== -1 && data.tabIndex !== data.targetIndex) {
handler.move(data.tabIndex, data.targetIndex);
}
}, TRANSITION_DURATION);
var style = data.tab.style;
var limit = data.contentRect.width - (data.tabLeft + data.tabWidth);
style.left = Math.max(-data.tabLeft, Math.min(ideal, limit)) + 'px';
}
TabBarPrivate.endDrag = endDrag;
TabBarPrivate.finalizeTabPosition = finalizeTabPosition;
/**
* Abort the drag operation for a tab bar.
*
* This should be called to cancel a drag immediately.
* Reset the relative positions of the given tabs.
*/
function abortDrag(owner, data) {
// Indicate the drag has been aborted, which allows the drag
// end handler and detach request emitter to return early.
data.dragAborted = true;
// If the drag is not active, there's nothing more to do.
if (!data.dragActive) {
return;
function resetTabPositions(tabs) {
for (var i = 0, n = tabs.length; i < n; ++i) {
tabs[i].style.left = '';
}
// Reset the tabs to their non-dragged positions.
resetTabPositions(owner);
// Clear the cursor override and extra styling classes.
data.cursorGrab.dispose();
data.tab.classList.remove(DRAGGING_CLASS);
owner.removeClass(DRAGGING_CLASS);
}
TabBarPrivate.abortDrag = abortDrag;
/**
* The coerce handler for the `currentTitle` property.
*/
function coerceCurrentTitle(owner, value) {
return (value && owner.titleIndex(value) !== -1) ? value : null;
}
/**
* The change handler for the `currentTitle` property.
*/
function onCurrentTitleChanged(owner) {
owner.update();
}
/**
* Create an uninitialized DOM node for a tab.
*/
function createTabNode() {
var node = document.createElement('li');
var icon = document.createElement('span');
var text = document.createElement('span');
var close = document.createElement('span');
text.className = TEXT_CLASS;
close.className = CLOSE_CLASS;
node.appendChild(icon);
node.appendChild(text);
node.appendChild(close);
return node;
}
/**
* Update a tab node to reflect the state of a title.
*/
function updateTabNode(node, title) {
var icon = node.firstChild;
var text = icon.nextSibling;
var suffix = title.closable ? ' ' + CLOSABLE_CLASS : '';
if (title.className) {
node.className = TAB_CLASS + ' ' + title.className + suffix;
}
else {
node.className = TAB_CLASS + suffix;
}
if (title.icon) {
icon.className = ICON_CLASS + ' ' + title.icon;
}
else {
icon.className = ICON_CLASS;
}
text.textContent = title.text;
}
/**
* Reset the tabs to their unadjusted positions.
*/
function resetTabPositions(owner) {
var children = owner.contentNode.children;
for (var i = 0, n = children.length; i < n; ++i) {
children[i].style.left = '';
}
}
/**
* Get a snapshot of the current tab layout values.
*/
function snapTabLayout(owner) {
var layout = [];
var children = owner.contentNode.children;
for (var i = 0, n = children.length; i < n; ++i) {
var node = children[i];
var left = node.offsetLeft;
var width = node.offsetWidth;
var cstyle = window.getComputedStyle(node);
var margin = parseInt(cstyle.marginLeft, 10) || 0;
layout.push({ margin: margin, left: left, width: width });
}
return layout;
}
/**
* Test if a mouse position exceeds the detach threshold.
*/
function detachExceeded(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));
}
TabBarPrivate.resetTabPositions = resetTabPositions;
})(TabBarPrivate || (TabBarPrivate = {}));

@@ -1,5 +0,4 @@

import { IChangedArgs } from 'phosphor-properties';
import { StackedPanel } from 'phosphor-stackedpanel';
import { Title, Widget } from 'phosphor-widget';
import { ITabMovedArgs, TabBar } from './tabbar';
import { Widget } from 'phosphor-widget';
import { TabBar } from './tabbar';
/**

@@ -20,6 +19,6 @@ * A widget which combines a `TabBar` and a `StackedPanel`.

*
* @returns The tab bar to use with a new tab panel.
* @returns A new tab bar to use with a tab panel.
*
* #### Notes
* This may be reimplemented by a subclass as needed.
* This may be reimplemented by subclasses for custom tab bars.
*/

@@ -30,9 +29,13 @@ static createTabBar(): TabBar;

*
* @returns The stacked panel to use with a new tab panel.
* @returns A new stacked panel to use with a tab panel.
*
* #### Notes
* This may be reimplemented by a subclass as needed.
* This may be reimplemented by subclasses for custom stacks.
*/
static createStackedPanel(): StackedPanel;
/**
* The static type of the constructor.
*/
'constructor': typeof TabPanel;
/**
* Construct a new tab panel.

@@ -63,3 +66,3 @@ */

* #### Notes
* Modifying the tab bar titles can lead to undefined behavior.
* Modifying the tab bar directly can lead to undefined behavior.
*

@@ -73,3 +76,3 @@ * This is a read-only property.

* #### Notes
* Modifying the panel children can lead to undefined behavior.
* Modifying the stack directly can lead to undefined behavior.
*

@@ -85,3 +88,3 @@ * This is a read-only property.

* #### Notes
* This delegates to `childCount` of the internal stacked panel.
* This delegates to the `childCount` method of the stacked panel.
*/

@@ -97,3 +100,3 @@ childCount(): number;

* #### Notes
* This delegates to `childAt` of the internal stacked panel.
* This delegates to the `childAt` method of the stacked panel.
*/

@@ -109,3 +112,3 @@ childAt(index: number): Widget;

* #### Notes
* This delegates to `childIndex` of the internal stacked panel.
* This delegates to the `childIndex` method of the stacked panel.
*/

@@ -120,5 +123,2 @@ childIndex(child: Widget): number;

* If the child is already contained in the panel, it will be moved.
*
* This adds the widget's title object to the internal tab bar, and
* adds the widget itself to the internal stacked panel.
*/

@@ -135,46 +135,23 @@ addChild(child: Widget): void;

* If the child is already contained in the panel, it will be moved.
*
* This adds the widget's title object to the internal tab bar, and
* adds the widget itself to the internal stacked panel.
*/
insertChild(index: number, child: Widget): void;
/**
* Find the widget which owns the given title.
*
* @param title - The title object of interest.
*
* @returns The widget which owns the title, or `null` if no such
* widget is contained within the internal stacked panel.
* Handle the `currentChanged` signal from the tab bar.
*/
protected findWidgetByTitle(title: Title): Widget;
private _onCurrentChanged(sender, args);
/**
* Handle the `currentChanged` signal from the tab bar.
*
* #### Notes
* The default implementation updates the current stack widget.
* Handle the `tabCloseRequested` signal from the tab bar.
*/
protected onCurrentChanged(sender: TabBar, args: IChangedArgs<Title>): void;
private _onTabCloseRequested(sender, args);
/**
* Handle the `tabMoved` signal from the tab bar.
*
* #### Notes
* The default implementation moves the widget in the stack.
*/
protected onTabMoved(sender: TabBar, args: ITabMovedArgs): void;
private _onTabMoved(sender, args);
/**
* Handle the `tabCloseRequested` signal from the tab bar.
*
* #### Notes
* The default implementation closes the respective widget.
*/
protected onTabCloseRequested(sender: TabBar, title: Title): void;
/**
* Handle the `widgetRemoved` signal from the stacked panel.
*
* #### Notes
* The default implementation removes the title from the tab bar.
*/
protected onWidgetRemoved(sender: StackedPanel, widget: Widget): void;
private _onWidgetRemoved(sender, widget);
private _tabBar;
private _stackedPanel;
private _currentWidget;
}

@@ -18,3 +18,2 @@ /*-----------------------------------------------------------------------------

var tabbar_1 = require('./tabbar');
// TODO - need better solution for storing these class names
/**

@@ -25,2 +24,10 @@ * The class name added to TabPanel instances.

/**
* The class name added to a TabPanel's tab bar.
*/
var TAB_BAR_CLASS = 'p-TabPanel-tabBar';
/**
* The class name added to a TabPanel's stacked panel.
*/
var STACKED_PANEL_CLASS = 'p-TabPanel-stackedPanel';
/**
* A widget which combines a `TabBar` and a `StackedPanel`.

@@ -43,15 +50,15 @@ *

_super.call(this);
this._currentWidget = null;
this.addClass(TAB_PANEL_CLASS);
var type = this.constructor;
this._tabBar = type.createTabBar();
this._stackedPanel = type.createStackedPanel();
this._tabBar.tabMoved.connect(this.onTabMoved, this);
this._tabBar.currentChanged.connect(this.onCurrentChanged, this);
this._tabBar.tabCloseRequested.connect(this.onTabCloseRequested, this);
this._stackedPanel.widgetRemoved.connect(this.onWidgetRemoved, this);
phosphor_boxpanel_1.BoxLayout.setStretch(this._tabBar, 0);
phosphor_boxpanel_1.BoxLayout.setStretch(this._stackedPanel, 1);
this._tabBar = this.constructor.createTabBar();
this._stackedPanel = this.constructor.createStackedPanel();
this._tabBar.tabMoved.connect(this._onTabMoved, this);
this._tabBar.currentChanged.connect(this._onCurrentChanged, this);
this._tabBar.tabCloseRequested.connect(this._onTabCloseRequested, this);
this._stackedPanel.widgetRemoved.connect(this._onWidgetRemoved, this);
var layout = new phosphor_boxpanel_1.BoxLayout();
layout.direction = phosphor_boxpanel_1.BoxLayout.TopToBottom;
layout.spacing = 0;
phosphor_boxpanel_1.BoxLayout.setStretch(this._tabBar, 0);
phosphor_boxpanel_1.BoxLayout.setStretch(this._stackedPanel, 1);
layout.addChild(this._tabBar);

@@ -64,9 +71,11 @@ layout.addChild(this._stackedPanel);

*
* @returns The tab bar to use with a new tab panel.
* @returns A new tab bar to use with a tab panel.
*
* #### Notes
* This may be reimplemented by a subclass as needed.
* This may be reimplemented by subclasses for custom tab bars.
*/
TabPanel.createTabBar = function () {
return new tabbar_1.TabBar();
var tabBar = new tabbar_1.TabBar();
tabBar.addClass(TAB_BAR_CLASS);
return tabBar;
};

@@ -76,9 +85,11 @@ /**

*
* @returns The stacked panel to use with a new tab panel.
* @returns A new stacked panel to use with a tab panel.
*
* #### Notes
* This may be reimplemented by a subclass as needed.
* This may be reimplemented by subclasses for custom stacks.
*/
TabPanel.createStackedPanel = function () {
return new phosphor_stackedpanel_1.StackedPanel();
var stackedPanel = new phosphor_stackedpanel_1.StackedPanel();
stackedPanel.addClass(STACKED_PANEL_CLASS);
return stackedPanel;
};

@@ -91,2 +102,3 @@ /**

this._stackedPanel = null;
this._currentWidget = null;
_super.prototype.dispose.call(this);

@@ -99,3 +111,3 @@ };

get: function () {
return this._stackedPanel.currentWidget;
return this._tabBar.currentItem;
},

@@ -105,4 +117,4 @@ /**

*/
set: function (widget) {
this._tabBar.currentTitle = widget && widget.title;
set: function (value) {
this._tabBar.currentItem = value;
},

@@ -122,4 +134,4 @@ enumerable: true,

*/
set: function (movable) {
this._tabBar.tabsMovable = movable;
set: function (value) {
this._tabBar.tabsMovable = value;
},

@@ -134,3 +146,3 @@ enumerable: true,

* #### Notes
* Modifying the tab bar titles can lead to undefined behavior.
* Modifying the tab bar directly can lead to undefined behavior.
*

@@ -150,3 +162,3 @@ * This is a read-only property.

* #### Notes
* Modifying the panel children can lead to undefined behavior.
* Modifying the stack directly can lead to undefined behavior.
*

@@ -167,3 +179,3 @@ * This is a read-only property.

* #### Notes
* This delegates to `childCount` of the internal stacked panel.
* This delegates to the `childCount` method of the stacked panel.
*/

@@ -181,3 +193,3 @@ TabPanel.prototype.childCount = function () {

* #### Notes
* This delegates to `childAt` of the internal stacked panel.
* This delegates to the `childAt` method of the stacked panel.
*/

@@ -195,3 +207,3 @@ TabPanel.prototype.childAt = function (index) {

* #### Notes
* This delegates to `childIndex` of the internal stacked panel.
* This delegates to the `childIndex` method of the stacked panel.
*/

@@ -208,9 +220,5 @@ TabPanel.prototype.childIndex = function (child) {

* If the child is already contained in the panel, it will be moved.
*
* This adds the widget's title object to the internal tab bar, and
* adds the widget itself to the internal stacked panel.
*/
TabPanel.prototype.addChild = function (child) {
this._stackedPanel.addChild(child);
this._tabBar.addTitle(child.title);
this.insertChild(this.childCount(), child);
};

@@ -226,65 +234,42 @@ /**

* If the child is already contained in the panel, it will be moved.
*
* This adds the widget's title object to the internal tab bar, and
* adds the widget itself to the internal stacked panel.
*/
TabPanel.prototype.insertChild = function (index, child) {
if (child !== this._currentWidget)
child.hide();
this._stackedPanel.insertChild(index, child);
this._tabBar.insertTitle(index, child.title);
this._tabBar.insertItem(index, child);
};
/**
* Find the widget which owns the given title.
*
* @param title - The title object of interest.
*
* @returns The widget which owns the title, or `null` if no such
* widget is contained within the internal stacked panel.
* Handle the `currentChanged` signal from the tab bar.
*/
TabPanel.prototype.findWidgetByTitle = function (title) {
var panel = this._stackedPanel;
for (var i = 0, n = panel.childCount(); i < n; ++i) {
var child = panel.childAt(i);
if (child.title === title)
return child;
}
return null;
TabPanel.prototype._onCurrentChanged = function (sender, args) {
var oldWidget = this._currentWidget;
var newWidget = args.item;
if (oldWidget === newWidget)
return;
this._currentWidget = newWidget;
if (oldWidget)
oldWidget.hide();
if (newWidget)
newWidget.show();
};
/**
* Handle the `currentChanged` signal from the tab bar.
*
* #### Notes
* The default implementation updates the current stack widget.
* Handle the `tabCloseRequested` signal from the tab bar.
*/
TabPanel.prototype.onCurrentChanged = function (sender, args) {
this._stackedPanel.currentWidget = this.findWidgetByTitle(args.newValue);
TabPanel.prototype._onTabCloseRequested = function (sender, args) {
args.item.close();
};
/**
* Handle the `tabMoved` signal from the tab bar.
*
* #### Notes
* The default implementation moves the widget in the stack.
*/
TabPanel.prototype.onTabMoved = function (sender, args) {
var child = this._stackedPanel.childAt(args.fromIndex);
this._stackedPanel.insertChild(args.toIndex, child);
TabPanel.prototype._onTabMoved = function (sender, args) {
this._stackedPanel.insertChild(args.toIndex, args.item);
};
/**
* Handle the `tabCloseRequested` signal from the tab bar.
*
* #### Notes
* The default implementation closes the respective widget.
*/
TabPanel.prototype.onTabCloseRequested = function (sender, title) {
var widget = this.findWidgetByTitle(title);
if (widget)
widget.close();
};
/**
* Handle the `widgetRemoved` signal from the stacked panel.
*
* #### Notes
* The default implementation removes the title from the tab bar.
*/
TabPanel.prototype.onWidgetRemoved = function (sender, widget) {
this._tabBar.removeTitle(widget.title);
TabPanel.prototype._onWidgetRemoved = function (sender, widget) {
if (this._currentWidget === widget)
this._currentWidget = null;
this._tabBar.removeItem(widget);
};

@@ -291,0 +276,0 @@ return TabPanel;

{
"name": "phosphor-tabs",
"version": "1.0.0-beta.4",
"version": "1.0.0-rc.0",
"description": "Phosphor widgets for creating tab bars and tab panels.",

@@ -9,10 +9,9 @@ "main": "lib/index.js",

"phosphor-arrays": "^1.0.6",
"phosphor-boxpanel": "^1.0.0-beta.3",
"phosphor-boxpanel": "^1.0.0-rc.0",
"phosphor-disposable": "^1.0.5",
"phosphor-domutil": "^1.2.0",
"phosphor-messaging": "^1.0.6",
"phosphor-properties": "^2.0.0",
"phosphor-signaling": "^1.2.0",
"phosphor-stackedpanel": "^1.0.0-beta.5",
"phosphor-widget": "^1.0.0-beta.6"
"phosphor-stackedpanel": "^1.0.0-rc.0",
"phosphor-widget": "^1.0.0-rc.0"
},

@@ -77,4 +76,3 @@ "devDependencies": {

"ui",
"widget",
"widgets"
"widget"
],

@@ -81,0 +79,0 @@ "author": "S. Chris Colbert <sccolbert@gmail.com>",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc