728 lines
20 KiB
JavaScript
Executable File
728 lines
20 KiB
JavaScript
Executable File
/*
|
|
The public interface for the docking panel, it contains a layout that can be filled with custom
|
|
elements and a number of convenience functions for use.
|
|
*/
|
|
function wcPanel(type, options) {
|
|
this.$container = null;
|
|
this._parent = null;
|
|
this.$icon = null;
|
|
|
|
if (options.icon) {
|
|
this.icon(options.icon);
|
|
}
|
|
if (options.faicon) {
|
|
this.faicon(options.faicon);
|
|
}
|
|
|
|
this._panelObject = null;
|
|
this._initialized = false;
|
|
|
|
this._type = type;
|
|
this._title = type;
|
|
this._titleVisible = true;
|
|
|
|
this._layout = null;
|
|
|
|
this._buttonList = [];
|
|
|
|
this._actualPos = {
|
|
x: 0.5,
|
|
y: 0.5,
|
|
};
|
|
|
|
this._actualSize = {
|
|
x: 0,
|
|
y: 0,
|
|
};
|
|
|
|
this._resizeData = {
|
|
time: -1,
|
|
timeout: false,
|
|
delta: 150,
|
|
};
|
|
|
|
this._pos = {
|
|
x: 0.5,
|
|
y: 0.5,
|
|
};
|
|
|
|
this._moveData = {
|
|
time: -1,
|
|
timeout: false,
|
|
delta: 150,
|
|
};
|
|
|
|
this._size = {
|
|
x: -1,
|
|
y: -1,
|
|
};
|
|
|
|
this._minSize = {
|
|
x: 100,
|
|
y: 100,
|
|
};
|
|
|
|
this._maxSize = {
|
|
x: Infinity,
|
|
y: Infinity,
|
|
};
|
|
|
|
this._scroll = {
|
|
x: 0,
|
|
y: 0,
|
|
};
|
|
|
|
this._scrollable = {
|
|
x: true,
|
|
y: true,
|
|
};
|
|
|
|
this._overflowVisible = false;
|
|
this._moveable = true;
|
|
this._closeable = true;
|
|
this._resizeVisible = true;
|
|
this._isVisible = false;
|
|
|
|
this._events = {};
|
|
|
|
this.__init();
|
|
};
|
|
|
|
wcPanel.prototype = {
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Public Functions
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Finds the main Docker window.
|
|
docker: function() {
|
|
var parent = this._parent;
|
|
while (parent && !(parent instanceof wcDocker)) {
|
|
parent = parent._parent;
|
|
}
|
|
return parent;
|
|
},
|
|
|
|
// Gets, or Sets the title for this dock widget.
|
|
title: function(title) {
|
|
if (typeof title !== 'undefined') {
|
|
if (title === false) {
|
|
this._titleVisible = false;
|
|
} else {
|
|
this._title = title;
|
|
}
|
|
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__updateTabs();
|
|
}
|
|
}
|
|
|
|
return this._title;
|
|
},
|
|
|
|
// Retrieves the registration info of the panel.
|
|
info: function() {
|
|
return this.docker().panelTypeInfo(this._type);
|
|
},
|
|
|
|
// Retrieves the main widget container for this dock widget.
|
|
layout: function() {
|
|
return this._layout;
|
|
},
|
|
|
|
// Brings this widget into focus.
|
|
// Params:
|
|
// flash Optional, if true will flash the window.
|
|
focus: function(flash) {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
docker.__focus(this._parent, flash);
|
|
for (var i = 0; i < this._parent._panelList.length; ++i) {
|
|
if (this._parent._panelList[i] === this) {
|
|
this._parent.panel(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Retrieves whether this panel is within view.
|
|
isVisible: function() {
|
|
return this._isVisible;
|
|
},
|
|
|
|
// Creates a new custom button that will appear in the title bar of the panel.
|
|
// Params:
|
|
// name The name of the button, to identify it.
|
|
// className A class name to apply to the button.
|
|
// text Text to apply to the button.
|
|
// tip Tooltip text.
|
|
// isTogglable If true, will make the button toggle on and off per click.
|
|
// toggleClassName If this button is toggleable, you can designate an
|
|
// optional class name that will replace the original class name.
|
|
addButton: function(name, className, text, tip, isTogglable, toggleClassName) {
|
|
this._buttonList.push({
|
|
name: name,
|
|
className: className,
|
|
toggleClassName: toggleClassName,
|
|
text: text,
|
|
tip: tip,
|
|
isTogglable: isTogglable,
|
|
isToggled: false,
|
|
});
|
|
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__update();
|
|
}
|
|
|
|
return this._buttonList.length-1;
|
|
},
|
|
|
|
// Removes a button from the panel.
|
|
// Params:
|
|
// name The name identifier for this button.
|
|
removeButton: function(name) {
|
|
for (var i = 0; i < this._buttonList.length; ++i) {
|
|
if (this._buttonList[i].name === name) {
|
|
this._buttonList.splice(i, 1);
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__onTabChange();
|
|
}
|
|
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__update();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
// Gets, or Sets the current toggle state of a custom button that was
|
|
// added using addButton().
|
|
// Params:
|
|
// name The name identifier of the button.
|
|
// isToggled If supplied, will assign a new toggle state to the button.
|
|
// Returns:
|
|
// Boolean The current toggle state of the button.
|
|
buttonState: function(name, isToggled) {
|
|
for (var i = 0; i < this._buttonList.length; ++i) {
|
|
if (this._buttonList[i].name === name) {
|
|
if (typeof isToggled !== 'undefined') {
|
|
this._buttonList[i].isToggled = isToggled;
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__onTabChange();
|
|
}
|
|
}
|
|
|
|
if (this._parent instanceof wcFrame) {
|
|
this._parent.__update();
|
|
}
|
|
|
|
return this._buttonList[i].isToggled;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
// Gets, or Sets the default position of the widget if it is floating.
|
|
// Params:
|
|
// x, y If supplied, sets the position of the floating panel.
|
|
// Can be a pixel position, or a string with a 'px' or '%' suffix.
|
|
// Returns:
|
|
// An object with the current percentage position is returned.
|
|
initPos: function(x, y) {
|
|
if (typeof x !== 'undefined') {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
this._pos.x = this.__stringToPercent(x, docker.$container.width());
|
|
this._pos.y = this.__stringToPercent(y, docker.$container.height());
|
|
} else {
|
|
this._pos.x = x;
|
|
this._pos.y = y;
|
|
}
|
|
}
|
|
|
|
return {x: this._pos.x, y: this._pos.y};
|
|
},
|
|
|
|
// Gets, or Sets the desired size of the widget.
|
|
// Params:
|
|
// x, y If supplied, sets the desired initial size of the panel.
|
|
// Can be a pixel position, or a string with a 'px' or '%' suffix.
|
|
// Returns:
|
|
// An object with the current pixel size is returned.
|
|
initSize: function(x, y) {
|
|
if (typeof x !== 'undefined') {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
this._size.x = this.__stringToPixel(x, docker.$container.width());
|
|
this._size.y = this.__stringToPixel(y, docker.$container.height());
|
|
} else {
|
|
this._size.x = x;
|
|
this._size.y = y;
|
|
}
|
|
}
|
|
return {x: this._size.x, y: this._size.y};
|
|
},
|
|
|
|
// Gets, or Sets the minimum size of the widget.
|
|
// Params:
|
|
// x, y If supplied, sets the desired minimum size of the panel.
|
|
// Can be a pixel position, or a string with a 'px' or '%' suffix.
|
|
// Returns:
|
|
// An object with the current minimum pixel size is returned.
|
|
minSize: function(x, y) {
|
|
if (typeof x !== 'undefined') {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
this._minSize.x = this.__stringToPixel(x, docker.$container.width());
|
|
this._minSize.y = this.__stringToPixel(y, docker.$container.height());
|
|
} else {
|
|
this._minSize.x = x;
|
|
this._minSize.y = y;
|
|
}
|
|
}
|
|
return this._minSize;
|
|
},
|
|
|
|
// Gets, or Sets the maximum size of the widget.
|
|
// Params:
|
|
// x, y If supplied, sets the desired maximum size of the panel.
|
|
// Can be a pixel position, or a string with a 'px' or '%' suffix.
|
|
// Returns:
|
|
// An object with the current maximum pixel size is returned.
|
|
maxSize: function(x, y) {
|
|
if (typeof x !== 'undefined') {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
this._maxSize.x = this.__stringToPixel(x, docker.$container.width());
|
|
this._maxSize.y = this.__stringToPixel(y, docker.$container.height());
|
|
} else {
|
|
this._maxSize.x = x;
|
|
this._maxSize.y = y;
|
|
}
|
|
}
|
|
return this._maxSize;
|
|
},
|
|
|
|
// Retrieves the width of the panel contents.
|
|
width: function() {
|
|
if (this.$container) {
|
|
return this.$container.width();
|
|
}
|
|
return 0.0;
|
|
},
|
|
|
|
// Retrieves the height of the panel contents.
|
|
height: function() {
|
|
if (this.$container) {
|
|
return this.$container.height();
|
|
}
|
|
return 0.0;
|
|
},
|
|
|
|
// Sets the icon for the panel, shown in the panels tab widget.
|
|
// Must be a css class name that contains the image.
|
|
icon: function(icon) {
|
|
if (!this.$icon) {
|
|
this.$icon = $('<div>');
|
|
}
|
|
|
|
this.$icon.removeClass();
|
|
this.$icon.addClass('wcTabIcon ' + icon);
|
|
},
|
|
|
|
// Sets the icon for the panel, shown in the panels tab widget,
|
|
// to an icon defined from the font-awesome library.
|
|
faicon: function(icon) {
|
|
if (!this.$icon) {
|
|
this.$icon = $('<div>');
|
|
}
|
|
|
|
this.$icon.removeClass();
|
|
this.$icon.addClass('fa fa-fw fa-' + icon);
|
|
},
|
|
|
|
// Gets, or Sets the scroll position of the window (if it is scrollable).
|
|
// Params:
|
|
// x, y If supplied, sets the scroll position of the window.
|
|
// duration If setting a scroll position, you can supply a time duration
|
|
// to animate the scroll (in milliseconds).
|
|
// Returns:
|
|
// object The scroll position of the window.
|
|
scroll: function(x, y, duration) {
|
|
if (!this.$container) {
|
|
return {x: 0, y: 0};
|
|
}
|
|
|
|
if (typeof x !== 'undefined') {
|
|
if (duration) {
|
|
this.$container.parent().stop().animate({
|
|
scrollLeft: x,
|
|
scrollTop: y,
|
|
}, duration);
|
|
} else {
|
|
this.$container.parent().scrollLeft(x);
|
|
this.$container.parent().scrollTop(y);
|
|
}
|
|
}
|
|
|
|
return {
|
|
x: this.$container.parent().scrollLeft(),
|
|
y: this.$container.parent().scrollTop(),
|
|
};
|
|
},
|
|
|
|
// Gets, or Sets whether overflow on this panel is visible.
|
|
// Params:
|
|
// visible If supplied, assigns whether overflow is visible.
|
|
//
|
|
// Returns:
|
|
// boolean The current overflow visibility.
|
|
overflowVisible: function(visible) {
|
|
if (typeof visible !== 'undefined') {
|
|
this._overflowVisible = visible? true: false;
|
|
}
|
|
|
|
return this._overflowVisible;
|
|
},
|
|
|
|
// Gets, or Sets whether the contents of the panel are visible on resize.
|
|
// Params:
|
|
// visible If supplied, assigns whether panel contents are visible.
|
|
//
|
|
// Returns:
|
|
// boolean The current resize visibility.
|
|
resizeVisible: function(visible) {
|
|
if (typeof visible !== 'undefined') {
|
|
this._resizeVisible = visible? true: false;
|
|
}
|
|
|
|
return this._resizeVisible;
|
|
},
|
|
|
|
// Gets, or Sets whether the window is scrollable.
|
|
// Params:
|
|
// x, y If supplied, assigns whether the window is scrollable
|
|
// for each axis.
|
|
// Returns:
|
|
// object The current scrollable status.
|
|
scrollable: function(x, y) {
|
|
if (typeof x !== 'undefined') {
|
|
this._scrollable.x = x? true: false;
|
|
this._scrollable.y = y? true: false;
|
|
}
|
|
|
|
return {x: this._scrollable.x, y: this._scrollable.y};
|
|
},
|
|
|
|
// Sets, or Gets the moveable status of the window.
|
|
moveable: function(enabled) {
|
|
if (typeof enabled !== 'undefined') {
|
|
this._moveable = enabled? true: false;
|
|
}
|
|
|
|
return this._moveable;
|
|
},
|
|
|
|
// Gets, or Sets whether this dock window can be closed.
|
|
// Params:
|
|
// enabled If supplied, toggles whether it can be closed.
|
|
// Returns:
|
|
// bool The current closeable status.
|
|
closeable: function(enabled) {
|
|
if (typeof enabled !== 'undefined') {
|
|
this._closeable = enabled? true: false;
|
|
if (this._parent) {
|
|
this._parent.__update();
|
|
}
|
|
}
|
|
|
|
return this._closeable;
|
|
},
|
|
|
|
// Forces the window to close.
|
|
close: function() {
|
|
if (this._parent) {
|
|
this._parent.$close.click();
|
|
}
|
|
},
|
|
|
|
// Registers an event.
|
|
// Params:
|
|
// eventType The event type, as defined by wcDocker.EVENT_...
|
|
// handler A handler function to be called for the event.
|
|
// Params:
|
|
// panel The panel invoking the event.
|
|
// Returns:
|
|
// true The event was added.
|
|
// false The event failed to add.
|
|
on: function(eventType, handler) {
|
|
if (!eventType) {
|
|
return false;
|
|
}
|
|
|
|
if (!this._events[eventType]) {
|
|
this._events[eventType] = [];
|
|
}
|
|
|
|
if (this._events[eventType].indexOf(handler) !== -1) {
|
|
return false;
|
|
}
|
|
|
|
this._events[eventType].push(handler);
|
|
return true;
|
|
},
|
|
|
|
// Unregisters an event.
|
|
// Params:
|
|
// eventType The event type to remove, if omitted, all events are removed.
|
|
// handler The handler function to remove, if omitted, all events of
|
|
// the above type are removed.
|
|
off: function(eventType, handler) {
|
|
if (typeof eventType === 'undefined') {
|
|
this._events = {};
|
|
return;
|
|
} else {
|
|
if (this._events[eventType]) {
|
|
if (typeof handler === 'undefined') {
|
|
this._events[eventType] = [];
|
|
} else {
|
|
for (var i = 0; i < this._events[eventType].length; ++i) {
|
|
if (this._events[eventType][i] === handler) {
|
|
this._events[eventType].splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// Triggers an event of a given type to all panels.
|
|
// Params:
|
|
// eventType The event to trigger.
|
|
// data A custom data object to pass into all handlers.
|
|
trigger: function(eventType, data) {
|
|
var docker = this.docker();
|
|
if (docker) {
|
|
docker.trigger(eventType, data);
|
|
}
|
|
},
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Private Functions
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Initialize
|
|
__init: function() {
|
|
this._layout = new wcLayout(this.$container, this);
|
|
},
|
|
|
|
// Updates the size of the layout.
|
|
__update: function() {
|
|
this._layout.__update();
|
|
if (!this.$container) {
|
|
return;
|
|
}
|
|
|
|
if ( this._resizeVisible ) {
|
|
this._parent.$frame.removeClass('wcHideOnResize');
|
|
} else {
|
|
this._parent.$frame.addClass('wcHideOnResize');
|
|
}
|
|
|
|
if (!this._initialized) {
|
|
this._initialized = true;
|
|
var self = this;
|
|
setTimeout(function() {
|
|
self.__trigger(wcDocker.EVENT_INIT);
|
|
}, 0);
|
|
}
|
|
|
|
this.__trigger(wcDocker.EVENT_UPDATED);
|
|
|
|
var width = this.$container.width();
|
|
var height = this.$container.height();
|
|
if (this._actualSize.x !== width || this._actualSize.y !== height) {
|
|
this._actualSize.x = width;
|
|
this._actualSize.y = height;
|
|
|
|
this._resizeData.time = new Date();
|
|
if (!this._resizeData.timeout) {
|
|
this._resizeData.timeout = true;
|
|
setTimeout(this.__resizeEnd.bind(this), this._resizeData.delta);
|
|
this.__trigger(wcDocker.EVENT_RESIZE_STARTED);
|
|
}
|
|
this.__trigger(wcDocker.EVENT_RESIZED);
|
|
}
|
|
|
|
var offset = this.$container.offset();
|
|
if (this._actualPos.x !== offset.left || this._actualPos.y !== offset.top) {
|
|
this._actualPos.x = offset.left;
|
|
this._actualPos.y = offset.top;
|
|
|
|
this._moveData.time = new Date();
|
|
if (!this._moveData.timeout) {
|
|
this._moveData.timeout = true;
|
|
setTimeout(this.__moveEnd.bind(this), this._moveData.delta);
|
|
this.__trigger(wcDocker.EVENT_MOVE_STARTED);
|
|
}
|
|
this.__trigger(wcDocker.EVENT_MOVED);
|
|
}
|
|
},
|
|
|
|
__resizeEnd: function() {
|
|
if (new Date() - this._resizeData.time < this._resizeData.delta) {
|
|
setTimeout(this.__resizeEnd.bind(this), this._resizeData.delta);
|
|
} else {
|
|
this._resizeData.timeout = false;
|
|
this.__trigger(wcDocker.EVENT_RESIZE_ENDED);
|
|
}
|
|
},
|
|
|
|
__moveEnd: function() {
|
|
if (new Date() - this._moveData.time < this._moveData.delta) {
|
|
setTimeout(this.__moveEnd.bind(this), this._moveData.delta);
|
|
} else {
|
|
this._moveData.timeout = false;
|
|
this.__trigger(wcDocker.EVENT_MOVE_ENDED);
|
|
}
|
|
},
|
|
|
|
__isVisible: function(inView) {
|
|
if (this._isVisible !== inView) {
|
|
this._isVisible = inView;
|
|
|
|
this.__trigger(wcDocker.EVENT_VISIBILITY_CHANGED);
|
|
}
|
|
},
|
|
|
|
// Saves the current panel configuration into a meta
|
|
// object that can be used later to restore it.
|
|
__save: function() {
|
|
var data = {};
|
|
data.type = 'wcPanel';
|
|
data.panelType = this._type;
|
|
// data.title = this._title;
|
|
// data.minSize = {
|
|
// x: this._minSize.x,
|
|
// y: this._minSize.y,
|
|
// };
|
|
// data.maxSize = {
|
|
// x: this._maxSize.x,
|
|
// y: this._maxSize.y,
|
|
// };
|
|
// data.scrollable = {
|
|
// x: this._scrollable.x,
|
|
// y: this._scrollable.y,
|
|
// };
|
|
// data.moveable = this._moveable;
|
|
// data.closeable = this._closeable;
|
|
// data.resizeVisible = this.resizeVisible();
|
|
data.customData = {};
|
|
this.__trigger(wcDocker.EVENT_SAVE_LAYOUT, data.customData);
|
|
return data;
|
|
},
|
|
|
|
// Restores a previously saved configuration.
|
|
__restore: function(data, docker) {
|
|
// this._title = data.title;
|
|
// this._minSize.x = data.minSize.x;
|
|
// this._minSize.y = data.minSize.y;
|
|
// this._maxSize.x = data.maxSize.x;
|
|
// this._maxSize.y = data.maxSize.y;
|
|
// this._scrollable.x = data.scrollable.x;
|
|
// this._scrollable.y = data.scrollable.y;
|
|
// this._moveable = data.moveable;
|
|
// this._closeable = data.closeable;
|
|
// this.resizeVisible(data.resizeVisible)
|
|
this.__trigger(wcDocker.EVENT_RESTORE_LAYOUT, data.customData);
|
|
},
|
|
|
|
// Triggers an event of a given type onto this current panel.
|
|
// Params:
|
|
// eventType The event to trigger.
|
|
// data A custom data object to pass into all handlers.
|
|
__trigger: function(eventType, data) {
|
|
if (!eventType) {
|
|
return false;
|
|
}
|
|
|
|
if (this._events[eventType]) {
|
|
for (var i = 0; i < this._events[eventType].length; ++i) {
|
|
this._events[eventType][i].call(this, data);
|
|
}
|
|
}
|
|
},
|
|
|
|
// Converts a potential string value to a percentage.
|
|
__stringToPercent: function(value, size) {
|
|
if (typeof value === 'string') {
|
|
if (value.indexOf('%', value.length - 1) !== -1) {
|
|
return parseFloat(value)/100;
|
|
} else if (value.indexOf('px', value.length - 2) !== -1) {
|
|
return parseFloat(value) / size;
|
|
}
|
|
}
|
|
return parseFloat(value);
|
|
},
|
|
|
|
// Converts a potential string value to a pixel value.
|
|
__stringToPixel: function(value, size) {
|
|
if (typeof value === 'string') {
|
|
if (value.indexOf('%', value.length - 1) !== -1) {
|
|
return (parseFloat(value)/100) * size;
|
|
} else if (value.indexOf('px', value.length - 2) !== -1) {
|
|
return parseFloat(value);
|
|
}
|
|
}
|
|
return parseFloat(value);
|
|
},
|
|
|
|
// Retrieves the bounding rect for this widget.
|
|
__rect: function() {
|
|
var offset = this.$container.offset();
|
|
var width = this.$container.width();
|
|
var height = this.$container.height();
|
|
|
|
return {
|
|
x: offset.left,
|
|
y: offset.top,
|
|
w: width,
|
|
h: height,
|
|
};
|
|
},
|
|
|
|
// Gets, or Sets a new container for this layout.
|
|
// Params:
|
|
// $container If supplied, sets a new container for this layout.
|
|
// parent If supplied, sets a new parent for this layout.
|
|
// Returns:
|
|
// JQuery collection The current container.
|
|
__container: function($container) {
|
|
if (typeof $container === 'undefined') {
|
|
return this.$container;
|
|
}
|
|
|
|
this.$container = $container;
|
|
|
|
if (this.$container) {
|
|
this._layout.__container(this.$container);
|
|
} else {
|
|
this._layout.__container(null);
|
|
}
|
|
return this.$container;
|
|
},
|
|
|
|
// Destroys this panel.
|
|
__destroy: function() {
|
|
this._panelObject = null;
|
|
this.off();
|
|
|
|
this.__container(null);
|
|
this._parent = null;
|
|
},
|
|
}; |