// vim: et:ts=4:sw=4:sts=4:ft=js /** options: elements: [{ array of one, two or three elements collapsible: false, collapsible or not (only for outer elements) collapsed: false, collapsed or not (only for collapsible elements) element: {}, OxElement (if any element is resizable or collapsible, all OxElements must have an id) resizable: false, resizable or not (only for outer elements) resize: [], array of sizes (only for resizable elements, first value is min, last value is max, other values are 'snappy' points in between) size: 0 size in px (one element must have no size) }], orientation: '' 'horizontal' or 'vertical' events: resize toggle */ Ox.SplitPanel = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) // fixme: Container .defaults({ elements: [], orientation: 'horizontal' }) .options(options || {}) .addClass('OxSplitPanel'); $.extend(self, { dimensions: Ox.UI.DIMENSIONS[self.options.orientation], edges: Ox.UI.EDGES[self.options.orientation], length: self.options.elements.length, resizebarElements: [], $resizebars: [] }); // create elements that.$elements = []; self.options.elements.forEach(function(v, i) { self.options.elements[i] = $.extend({ collapsible: false, collapsed: false, resizable: false, resize: [], size: 'auto' }, v); that.$elements[i] = v.element .css(self.edges[2], (parseInt(v.element.css(self.edges[2])) || 0) + 'px') .css(self.edges[3], (parseInt(v.element.css(self.edges[3])) || 0) + 'px'); //alert(v.element.css(self.edges[3])) }); // create resizebars self.options.elements.forEach(function(v, i) { //that.append(element) //Ox.print('V: ', v, that.$elements[i]) var index = i == 0 ? 0 : 1; that.$elements[i].appendTo(that.$element); // fixme: that.$content if (v.collapsible || v.resizable) { //Ox.print('v.size', v.size) self.resizebarElements[index] = i < 2 ? [0, 1] : [1, 2]; self.$resizebars[index] = new Ox.Resizebar({ collapsible: v.collapsible, edge: self.edges[index], elements: [ that.$elements[self.resizebarElements[index][0]], that.$elements[self.resizebarElements[index][1]] ], id: v.element.options('id'), orientation: self.options.orientation == 'horizontal' ? 'vertical' : 'horizontal', parent: that, // fixme: that.$content resizable: v.resizable, resize: v.resize, size: v.size }); self.$resizebars[index][i == 0 ? 'insertAfter' : 'insertBefore'](that.$elements[i]); } }); self.options.elements.forEach(function(v, i) { v.collapsed && that.css( self.edges[i == 0 ? 0 : 1], -self.options.elements[i].size + 'px' ); }); setSizes(true); function getPositionById(id) { var position = -1; Ox.forEach(self.options.elements, function(element, i) { if (element.element.options('id') == id) { position = i; return false; } }); //Ox.print('getPositionById', id, position); return position; } function getSize(element) { return element.size + (element.collapsible || element.resizable); //return (element.size + (element.collapsible || element.resizable)) * !element.collapsed; } function getVisibleSize(element) { return getSize(element) * !element.collapsed; } function setSizes(init) { self.options.elements.forEach(function(v, i) { // fixme: maybe we can add a conditional here, since init // is about elements that are collapsed splitpanels var edges = [ (init && parseInt(that.$elements[i].css(self.edges[0]))) || 0, (init && parseInt(that.$elements[i].css(self.edges[1]))) || 0 ]; v.size != 'auto' && that.$elements[i].css(self.dimensions[0], v.size + 'px'); if (i == 0) { that.$elements[i].css( self.edges[0], edges[0] + 'px' ); that.$elements[i].css( self.edges[1], (getSize(self.options.elements[1]) + (length == 3 ? getSize(self.options.elements[2]) : 0)) + 'px' ); } else if (i == 1) { that.$elements[i].css( self.edges[0], self.options.elements[0].size == 'auto' ? 'auto' : edges[0] + getSize(self.options.elements[0]) + 'px' ); (self.options.elements[0].size != 'auto' || v.size != 'auto') && that.$elements[i].css( self.edges[1], (self.length == 3 ? getSize(self.options.elements[2]) : 0) + 'px' ); } else { that.$elements[i].css( self.edges[0], (self.options.elements[1].size == 'auto' || v.size == 'auto') ? 'auto' : (getVisibleSize(self.options.elements[0]) + getVisibleSize(self.options.elements[1])) + 'px' ); that.$elements[i].css( self.edges[1], edges[1] + 'px' ); } if (v.collapsible || v.resizable) { self.$resizebars[i == 0 ? 0 : 1].css(self.edges[i == 0 ? 0 : 1], v.size); } }); } that.isCollapsed = function(id) { var pos = Ox.isNumber(id) ? id : getPositionById(id); return self.options.elements[pos].collapsed; }; that.replaceElement = function(id, element) { // one can pass pos instead of id var pos = Ox.isNumber(id) ? id : getPositionById(id); //Ox.print('replace', pos, element); //Ox.print('element', self.options.elements[pos].element, element) that.$elements[pos] = element .css(self.edges[2], (parseInt(element.css(self.edges[2])) || 0) + 'px') .css(self.edges[3], (parseInt(element.css(self.edges[3])) || 0) + 'px'); //alert(element.css(self.edges[3])) self.options.elements[pos].element.replaceWith(element.$element.$element || element.$element); self.options.elements[pos].element = element; setSizes(); self.$resizebars.forEach(function($resizebar, i) { $resizebar.options({ elements: [ that.$elements[self.resizebarElements[i][0]], that.$elements[self.resizebarElements[i][1]] ] }); }); //Ox.print(self.options.elements[pos]) return that; }; that.replaceElements = function(elements) { elements.forEach(function(element, i) { if (Ox.isNumber(element.size)) { that.size(i, element.size); if (element.collapsible || element.resizable) { self.$resizebars[i == 0 ? 0 : 1].options({ collapsible: element.collapsible, resizable: element.resizable, size: element.size }); } } that.replace(i, element.element); }); self.options.elements = elements; self.$resizebars.forEach(function($resizebar, i) { $resizebar.options({ elements: [ that.$elements[self.resizebarElements[i][0]], that.$elements[self.resizebarElements[i][1]] ] }); }); return that; } that.size = function(id, size) { // one can pass pos instead of id var pos = Ox.isNumber(id) ? id : getPositionById(id), element = self.options.elements[pos]; if (arguments.length == 1) { return element.element[self.dimensions[0]]() * !that.isCollapsed(pos); } else { element.size = size; setSizes(); return that; } }; that.toggle = function(id) { // one can pass pos instead of id var pos = Ox.isNumber(id) ? id : getPositionById(id), element = self.options.elements[pos], value = parseInt(that.css(self.edges[pos == 0 ? 0 : 1])) + element.element[self.dimensions[0]]() * (element.collapsed ? 1 : -1), animate = {}; animate[self.edges[pos == 0 ? 0 : 1]] = value; that.animate(animate, 200, function() { // fixme: 250? element.collapsed = !element.collapsed; element.element.triggerEvent('toggle', { 'collapsed': element.collapsed }); element = self.options.elements[pos == 0 ? 1 : pos - 1]; element.element.triggerEvent( 'resize', element.element[self.dimensions[0]]() ); }); }; that.updateSize = function(pos, size) { // this is called from resizebar var pos = pos == 0 ? 0 : self.options.elements.length - 1; // fixme: silly that 0 or 1 is passed, and not pos self.options.elements[pos].size = size; } return that; }; Ox.SplitPanel_ = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .defaults({ elements: [], orientation: 'horizontal' }) .options(options) .addClass( 'OxSplitPanel_ Ox' + Ox.toTitleCase(self.options.orientation) ); Ox.extend(self, { $separators: [], clientXY: self.options.orientation == 'horizontal' ? 'clientX' : 'clientY', dimensions: Ox.UI.DIMENSIONS[self.options.orientation], edges: Ox.UI.EDGES[self.options.orientation] }); self.options.elements.forEach(function(element, i) { self.options.elements[i] = Ox.extend({ collapsible: false, collapsed: false, resizable: false, resize: [], size: 'auto' }, element); }); self.autoPercent = (100 - self.options.elements.reduce(function(val, element) { return val + (Ox.endsWith(element.size, '%') ? parseFloat(element.size) : 0); }, 0)) / self.options.elements.filter(function(element) { return element.size == 'auto'; }).length + '%'; self.options.elements.forEach(function(element, i) { var flex, index = i == 0 ? 0 : 1; if (Ox.isNumber(element.size)) { element.element.css(self.dimensions[0], element.size + 'px'); } else { flex = ( element.size == 'auto' ? self.autoPercent : element.size ).replace('%', ''); element.element.css({ boxFlex: flex, MozBoxFlex: flex, WebkitBoxFlex: flex }); } element.element.appendTo(that); if (element.collapsible || element.resizable) { self.$separators.push( Ox.Element() .addClass('OxSeparator') .bindEvent({ anyclick: function() { that.toggle(i); }, dragstart: function(event, e) { dragstart(i, e); }, drag: function(event, e) { drag(i, e); }, dragend: function(event, e) { dragend(i, e); }, }) .append($('