oxjs/source/UI/js/Panel/SplitPanel.js

317 lines
12 KiB
JavaScript
Raw Permalink Normal View History

2011-11-05 16:46:53 +00:00
'use strict';
2012-05-21 10:38:18 +00:00
2011-05-16 08:24:46 +00:00
/*@
2012-05-31 10:32:54 +00:00
Ox.SplitPanel <f> SpliPanel Object
2011-05-16 08:24:46 +00:00
options <o> Options object
elements <[o]|[]> Array of two or three element objects
collapsible <b|false> If true, can be collapsed (if outer element)
collapsed <b|false> If true, is collapsed (if collapsible)
2014-08-21 10:14:30 +00:00
defaultSize <n|s|"auto"> Default size in px (restorable via reset)
element <o> Any Ox.Element
If any element is collapsible or resizable, all elements must
have an id.
2014-08-21 10:14:30 +00:00
resettable <b|false> If true, can be resetted (if outer element)
Note that reset fires on doubleclick, and if the element is also
collapsible, toggle now fires on singleclick, no longer on click.
Singleclick happens 250 ms later.
resizable <b|false> If true, can be resized (if outer element)
resize <[n]|[]> Min size, optional snappy points, and max size
size <n|s|"auto"> Size in px (one element must be "auto")
tooltip <b|s|false> If true, show tooltip, if string, append it
orientation <s|"horizontal"> orientation ("horizontal" or "vertical")
self <o> Shared private variable
([options[, self]]) -> <o:Ox.Element> SpliPanel Object
resize <!> resize
Fires on resize, on both elements being resized
2014-08-21 10:14:30 +00:00
resizeend <!> resizeend
Fires on resize, on both elements being resized
resizepause <!> resizepause
Fires on resize, on both elements being resized
toggle <!> toggle
Fires on collapse or expand, on the element being toggled
2011-05-16 08:24:46 +00:00
@*/
2011-04-22 22:03:10 +00:00
Ox.SplitPanel = function(options, self) {
self = self || {};
2013-12-06 16:26:35 +00:00
var that = Ox.Element({}, self)
2011-04-22 22:03:10 +00:00
.defaults({
elements: [],
orientation: 'horizontal'
})
.options(options || {})
.addClass('OxSplitPanel');
2014-08-21 10:14:30 +00:00
self.defaultSize = self.options.elements.map(function(element) {
return !Ox.isUndefined(element.defaultSize)
? element.defaultSize : element.size;
2011-04-22 22:03:10 +00:00
});
2014-08-21 10:14:30 +00:00
self.dimensions = Ox.UI.DIMENSIONS[self.options.orientation];
self.edges = Ox.UI.EDGES[self.options.orientation];
self.initialized = false;
self.length = self.options.elements.length;
2011-04-22 22:03:10 +00:00
2014-08-21 10:14:30 +00:00
self.$elements = [];
self.$resizebars = [];
self.options.elements.forEach(function(element, index) {
var elementIndices = index == 0 ? [0, 1] : index == 1 ? [1, 0] : [2, 1],
resizebarIndex = self.$resizebars.length;
self.options.elements[index] = Ox.extend({
2011-04-22 22:03:10 +00:00
collapsible: false,
collapsed: false,
2014-08-21 10:14:30 +00:00
defaultSize: 'auto',
resettable: false,
2011-04-22 22:03:10 +00:00
resizable: false,
resize: [],
2014-08-21 10:14:30 +00:00
size: 'auto',
tooltip: false
}, element);
2013-12-06 16:26:35 +00:00
// top and bottom (horizontal) or left and right (vertical)
self.edges.slice(2).forEach(function(edge) {
2014-09-02 11:23:06 +00:00
element.element.css(
edge, (parseInt(element.element.css(edge)) || 0) + 'px'
);
2013-12-06 16:26:35 +00:00
});
2014-08-21 10:14:30 +00:00
if (element.collapsed) {
// left/right (horizontal) or top/bottom (vertical)
that.css(self.edges[index == 0 ? 0 : 1], -element.size + 'px');
}
self.$elements[index] = element.element.appendTo(that);
if (element.collapsible || element.resizable) {
2014-08-21 10:14:30 +00:00
self.$resizebars[resizebarIndex] = Ox.Resizebar({
collapsed: element.collapsed,
collapsible: element.collapsible,
2014-08-21 10:14:30 +00:00
edge: self.edges[index == 0 ? 0 : 1],
2013-12-06 16:26:35 +00:00
orientation: self.options.orientation == 'horizontal'
? 'vertical' : 'horizontal',
2014-08-21 10:14:30 +00:00
resettable: element.resettable,
resizable: element.resizable,
resize: element.resize,
size: element.size,
2014-08-21 10:14:30 +00:00
tooltip: element.tooltip === true ? '' : element.tooltip
})
.bindEvent({
reset: function() {
that.resetElement(index);
},
resize: function(data) {
onResize(elementIndices, data.size);
triggerEvents(elementIndices, 'resize', data);
},
resizepause: function(data) {
triggerEvents(elementIndices, 'resizepause', data);
},
resizeend: function(data) {
triggerEvents(elementIndices, 'resizeend', data);
},
toggle: function(data) {
that.toggleElement(index);
}
})
[index == 0 ? 'insertAfter' : 'insertBefore'](self.$elements[index]);
2011-04-22 22:03:10 +00:00
}
});
2014-08-21 10:14:30 +00:00
setSizes();
2011-04-22 22:03:10 +00:00
2013-12-06 16:26:35 +00:00
function getSize(index) {
var element = self.options.elements[index];
2011-04-22 22:03:10 +00:00
return element.size + (element.collapsible || element.resizable);
}
2013-12-06 16:26:35 +00:00
function getVisibleSize(index) {
var element = self.options.elements[index];
2014-01-17 11:17:27 +00:00
return getSize(index) * !element.collapsed;
2011-04-22 22:03:10 +00:00
}
2014-08-21 10:14:30 +00:00
function onResize(elementIndices, size) {
var dimension = self.dimensions[0],
edge = self.edges[elementIndices[0] == 0 ? 0 : 1];
self.options.elements[elementIndices[0]].size = size;
elementIndices.forEach(function(elementIndex, index) {
self.$elements[elementIndex].css(
index == 0 ? dimension : edge,
2014-09-20 10:31:05 +00:00
(index == 0 ? size : size + 1) + 'px'
2014-08-21 10:14:30 +00:00
);
});
}
function setSizes(animate) {
2012-05-27 19:32:39 +00:00
// will animate if animate is truthy and call animate if it's a function
2014-08-21 10:14:30 +00:00
self.options.elements.forEach(function(element, index) {
var $resizebar,
css = {},
2013-12-06 16:26:35 +00:00
edges = self.edges.slice(0, 2).map(function(edge) {
// left/right (horizontal) or top/bottom (vertical)
2014-08-21 10:14:30 +00:00
var value = parseInt(self.$elements[index].css(edge));
return !self.initialized && value || 0;
2013-12-06 16:26:35 +00:00
});
if (element.size != 'auto') {
2013-12-06 16:26:35 +00:00
// width (horizontal) or height (vertical)
css[self.dimensions[0]] = element.size + 'px';
}
2014-08-21 10:14:30 +00:00
if (index == 0) {
2013-12-06 16:26:35 +00:00
// left (horizontal) or top (vertical)
css[self.edges[0]] = edges[0] + 'px';
2013-12-06 16:26:35 +00:00
// right (horizontal) or bottom (vertical)
if (element.size == 'auto') {
2014-08-21 10:14:30 +00:00
css[self.edges[1]] = getSize(1) + (
2013-12-06 16:26:35 +00:00
self.length == 3 ? getVisibleSize(2) : 0
) + 'px';
}
2014-08-21 10:14:30 +00:00
} else if (index == 1) {
2013-12-06 16:26:35 +00:00
// left (horizontal) or top (vertical)
if (self.options.elements[0].size != 'auto') {
2014-08-21 10:14:30 +00:00
css[self.edges[0]] = edges[0] + getSize(0) + 'px';
} else {
css[self.edges[0]] = 'auto'; // fixme: why is this needed?
}
2013-12-06 16:26:35 +00:00
// right (horizontal) or bottom (vertical)
2014-08-21 10:14:30 +00:00
css[self.edges[1]] = (self.length == 3 ? getSize(2) : 0) + 'px';
} else {
2013-12-06 16:26:35 +00:00
// left (horizontal) or top (vertical)
if (element.size == 'auto') {
2014-01-17 11:17:27 +00:00
css[self.edges[0]] = getVisibleSize(0) + getSize(1) + 'px';
} else {
css[self.edges[0]] = 'auto'; // fixme: why is this needed?
}
2013-12-06 16:26:35 +00:00
// right (horizontal) or bottom (vertical)
css[self.edges[1]] = edges[1] + 'px';
}
if (animate) {
2014-08-21 10:14:30 +00:00
self.$elements[index].animate(css, 250, function() {
index == 0 && Ox.isFunction(animate) && animate();
});
2011-04-22 22:03:10 +00:00
} else {
2014-08-21 10:14:30 +00:00
self.$elements[index].css(css);
2011-04-22 22:03:10 +00:00
}
if (element.collapsible || element.resizable) {
2014-08-21 10:14:30 +00:00
$resizebar = self.$resizebars[
index < 2 ? 0 : self.$resizebars.length - 1
];
2013-12-06 16:26:35 +00:00
// left or right (horizontal) or top or bottom (vertical)
2014-08-21 10:14:30 +00:00
css = Ox.extend(
{}, self.edges[index == 0 ? 0 : 1], element.size + 'px'
);
if (animate) {
2014-08-21 10:14:30 +00:00
$resizebar.animate(css, 250);
} else {
2014-08-21 10:14:30 +00:00
$resizebar.css(css);
}
2014-08-21 10:14:30 +00:00
$resizebar.options({size: element.size});
2011-04-22 22:03:10 +00:00
}
});
2014-08-21 10:14:30 +00:00
self.initialized = true;
2011-04-22 22:03:10 +00:00
}
2014-08-21 10:14:30 +00:00
function triggerEvents(elementIndices, event, data) {
elementIndices.forEach(function(elementIndex, index) {
var $element = self.$elements[elementIndex],
size = index == 0 ? data.size : $element[self.dimensions[0]]();
$element.triggerEvent(event, {size: size});
});
}
2011-09-05 12:42:37 +00:00
/*@
2014-08-21 10:14:30 +00:00
isCollapsed <f> Tests if an outer element is collapsed
(index) -> <b> True if collapsed
index <i> The element's index
2011-09-05 12:42:37 +00:00
@*/
2014-08-21 10:14:30 +00:00
that.isCollapsed = function(index) {
2013-12-06 16:26:35 +00:00
return self.options.elements[index].collapsed;
2011-04-22 22:03:10 +00:00
};
2011-09-05 12:42:37 +00:00
/*@
2014-08-21 10:14:30 +00:00
replaceElement <f> Replaces an element
(index, element) -> <f> replace element
index <n> The element's index
2013-12-06 16:26:35 +00:00
element <o> New element
2011-09-05 12:42:37 +00:00
@*/
2014-08-21 10:14:30 +00:00
that.replaceElement = function(index, element) {
2013-12-06 16:26:35 +00:00
// top and bottom (horizontal) or left and right (vertical)
self.edges.slice(2).forEach(function(edge) {
2014-01-17 11:23:22 +00:00
element.css(edge, (parseInt(element.css(edge)) || 0) + 'px');
2013-12-06 16:26:35 +00:00
});
2014-08-21 10:14:30 +00:00
self.$elements[index] = element;
2013-12-06 16:26:35 +00:00
self.options.elements[index].element.replaceWith(
self.options.elements[index].element = element
);
2011-04-22 22:03:10 +00:00
setSizes();
return that;
};
2011-09-05 12:42:37 +00:00
/*@
2014-08-21 10:14:30 +00:00
resetElement <f> Resets an outer element to its initial size
2011-09-05 12:42:37 +00:00
@*/
2014-08-21 10:14:30 +00:00
that.resetElement = function(index) {
var element = self.options.elements[index];
2013-12-06 16:26:35 +00:00
element.size = self.defaultSize[index];
2014-08-21 10:14:30 +00:00
setSizes(function() {
2012-08-29 15:41:40 +00:00
element.element.triggerEvent('resize', {
size: element.size
});
2013-12-06 16:26:35 +00:00
element = self.options.elements[index == 0 ? 1 : index - 1];
element.element.triggerEvent('resize', {
2012-08-29 15:41:40 +00:00
size: element.element[self.dimensions[0]]()
});
});
2014-08-21 10:14:30 +00:00
return that;
};
2011-09-05 12:42:37 +00:00
/*@
size <f> Get or set size of an element
2014-08-21 10:14:30 +00:00
(index) -> <i> Returns size
(index, size) -> <o> Sets size, returns SplitPanel
(index, size, callback) -> <o> Sets size with animation, returns SplitPanel
index <i> The element's index
size <i> New size, in px
callback <b|f> Callback function (passing true animates w/o callback)
2011-09-05 12:42:37 +00:00
@*/
2014-08-21 10:14:30 +00:00
that.resizeElement = that.size = function(index, size, callback) {
var element = self.options.elements[index];
2012-08-29 15:41:40 +00:00
if (arguments.length == 1) {
2014-08-21 10:14:30 +00:00
return element.element[self.dimensions[0]]()
* !that.isCollapsed(index);
2012-08-29 15:41:40 +00:00
} else {
element.size = size;
2014-08-21 10:14:30 +00:00
setSizes(callback);
2011-04-22 22:03:10 +00:00
return that;
2012-08-29 15:41:40 +00:00
}
2011-04-22 22:03:10 +00:00
};
2011-09-05 12:42:37 +00:00
/*@
2014-08-21 10:14:30 +00:00
toggleElement <f> Toggles collapsed state of an outer element
(index) -> <o> The SplitPanel
index <s|i> The element's index
2011-09-05 12:42:37 +00:00
@*/
2014-08-21 10:14:30 +00:00
that.toggleElement = function(index) {
if (self.toggling) {
2014-08-21 10:14:30 +00:00
return that;
}
2014-08-21 10:14:30 +00:00
var element = self.options.elements[index],
value = parseInt(that.css(self.edges[index == 0 ? 0 : 1]))
+ element.element[self.dimensions[0]]()
* (element.collapsed ? 1 : -1),
animate = Ox.extend({}, self.edges[index == 0 ? 0 : 1], value);
self.toggling = true;
that.animate(animate, 250, function() {
2011-04-22 22:03:10 +00:00
element.collapsed = !element.collapsed;
element.element.triggerEvent('toggle', {
collapsed: element.collapsed
2011-04-22 22:03:10 +00:00
});
2014-08-21 10:14:30 +00:00
self.$resizebars[index < 2 ? 0 : self.$resizebars.length - 1].options({
collapsed: element.collapsed
});
2013-12-06 16:26:35 +00:00
element = self.options.elements[index == 0 ? 1 : index - 1];
element.element.triggerEvent('resize', {
2012-08-29 15:41:40 +00:00
size: element.element[self.dimensions[0]]()
});
self.toggling = false;
2011-04-22 22:03:10 +00:00
});
2014-08-21 10:14:30 +00:00
return that;
};
2011-04-22 22:03:10 +00:00
return that;
2012-05-21 10:38:18 +00:00
};