/*!
* Web Cabin Docker - Docking Layout Interface.
*
* Dependancies:
* JQuery 1.11.1
* JQuery-contextMenu 1.6.6
* font-awesome 4.2.0
*
* Author: Jeff Houde (Lochemage@gmail.com)
* Web: http://docker.webcabin.org/
*
* Licensed under
* MIT License http://www.opensource.org/licenses/mit-license
* GPL v3 http://opensource.org/licenses/GPL-3.0
*
*/
// Provide backward compatibility for IE8 and other such older browsers.
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
/*
The main window instance. This manages all of the docking panels and user input.
There should only be one instance of this, although it is not enforced.
options allows overriding default options for docker. The current fields are:
allowContextMenu: boolean (default true) - Create the right click menu for adding/removing panels.
hideOnResize: boolean (default false) - If true, panels will hide their content as they are being resized.
*/
function wcDocker(container, options) {
this.$container = $(container).addClass('wcDocker');
this.$transition = $('
');
this.$container.append(this.$transition);
this._events = {};
this._root = null;
this._frameList = [];
this._floatingList = [];
this._modalList = [];
this._focusFrame = null;
this._splitterList = [];
this._tabList = [];
this._dockPanelTypeList = [];
this._draggingSplitter = null;
this._draggingFrame = null;
this._draggingFrameSizer = null;
this._draggingFrameTab = null;
this._draggingCustomTabFrame = null;
this._ghost = null;
this._menuTimer = 0;
this._resizeData = {
time: -1,
timeout: false,
delta: 150,
};
this._defaultOptions = {
allowContextMenu: true
};
this._options = {};
for( var prop in this._defaultOptions ) {
this._options[prop] = this._defaultOptions[prop];
}
for( var prop in options ) {
this._options[prop] = options[prop];
}
this.__init();
};
// Docking positions.
wcDocker.DOCK_MODAL = 'modal';
wcDocker.DOCK_FLOAT = 'float';
wcDocker.DOCK_TOP = 'top';
wcDocker.DOCK_LEFT = 'left';
wcDocker.DOCK_RIGHT = 'right';
wcDocker.DOCK_BOTTOM = 'bottom';
wcDocker.DOCK_STACKED = 'stacked';
// Internal events.
wcDocker.EVENT_INIT = 'panelInit';
wcDocker.EVENT_UPDATED = 'panelUpdated';
wcDocker.EVENT_VISIBILITY_CHANGED = 'panelVisibilityChanged';
wcDocker.EVENT_BEGIN_DOCK = 'panelBeginDock';
wcDocker.EVENT_END_DOCK = 'panelEndDock';
wcDocker.EVENT_GAIN_FOCUS = 'panelGainFocus';
wcDocker.EVENT_LOST_FOCUS = 'panelLostFocus';
wcDocker.EVENT_CLOSED = 'panelClosed';
wcDocker.EVENT_BUTTON = 'panelButton';
wcDocker.EVENT_ATTACHED = 'panelAttached';
wcDocker.EVENT_DETACHED = 'panelDetached';
wcDocker.EVENT_MOVE_STARTED = 'panelMoveStarted';
wcDocker.EVENT_MOVE_ENDED = 'panelMoveEnded';
wcDocker.EVENT_MOVED = 'panelMoved';
wcDocker.EVENT_RESIZE_STARTED = 'panelResizeStarted';
wcDocker.EVENT_RESIZE_ENDED = 'panelResizeEnded';
wcDocker.EVENT_RESIZED = 'panelResized';
wcDocker.EVENT_SCROLLED = 'panelScrolled';
wcDocker.EVENT_SAVE_LAYOUT = 'layoutSave';
wcDocker.EVENT_RESTORE_LAYOUT = 'layoutRestore';
wcDocker.EVENT_CUSTOM_TAB_CHANGED = 'customTabChanged';
wcDocker.EVENT_CUSTOM_TAB_CLOSED = 'customTabClosed';
// Used for the splitter bar orientation.
wcDocker.ORIENTATION_VERTICAL = false;
wcDocker.ORIENTATION_HORIZONTAL = true;
wcDocker.prototype = {
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Public Functions
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Registers a new docking panel type to be used later.
// Params:
// name The name for this new type.
// options An optional object that defines various options
// to initialize the panel with.
// createFunc The function that populates the contents of
// a newly created dock panel of this type.
// Params:
// panel The dock panel to populate.
// isPrivate If true, this type will not appear to the user
// as a window type to create.
// Returns:
// true The new type has been added successfully.
// false Failure, the type name already exists.
registerPanelType: function(name, optionsOrCreateFunc, isPrivate) {
var options = optionsOrCreateFunc;
if (typeof options === 'function') {
options = {
onCreate: optionsOrCreateFunc,
};
}
if (typeof isPrivate != 'undefined') {
options.isPrivate = isPrivate;
}
if ($.isEmptyObject(options)) {
options = null;
}
for (var i = 0; i < this._dockPanelTypeList.length; ++i) {
if (this._dockPanelTypeList[i].name === name) {
return false;
}
}
this._dockPanelTypeList.push({
name: name,
options: options,
});
var $menu = $('menu').find('menu');
$menu.append($('