From 4114068cb36653a92090cd2721b32d08831631b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20St=C3=B6ckel?= Date: Thu, 25 Aug 2011 15:54:15 +0000 Subject: [PATCH] Added et2_extension_nextmatch_dynheight.js which cares about resizing a div to the maximum possible height - this is needed because the new grid has to be explicitily sized to a given width and height --- etemplate/js/et2_extension_nextmatch.js | 18 +- .../js/et2_extension_nextmatch_dynheight.js | 173 ++++++++++++++++++ etemplate/js/etemplate2.js | 23 +++ etemplate/js/test/test.css | 1 + etemplate/js/test/test_xml.html | 2 + 5 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 etemplate/js/et2_extension_nextmatch_dynheight.js diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index 047a8a31b0..63a989ca39 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -20,6 +20,7 @@ et2_widget_template; et2_widget_grid; et2_widget_selectbox; + et2_extension_nextmatch_dynheight; */ /** @@ -44,7 +45,7 @@ var et2_INextmatchSortable = new Interface({ /** * Class which implements the "nextmatch" XET-Tag */ -var et2_nextmatch = et2_DOMWidget.extend({ +var et2_nextmatch = et2_DOMWidget.extend(et2_IResizeable, { attributes: { "template": { @@ -62,6 +63,10 @@ var et2_nextmatch = et2_DOMWidget.extend({ this.div = $j(document.createElement("div")) .addClass("et2_nextmatch"); + // Create the dynheight component which dynamically scales the inner + // container. + this.dynheight = new et2_dynheight(null, this.div, 150); + // Create the outer grid container this.dataviewContainer = new et2_dataview_gridContainer(this.div); @@ -70,12 +75,16 @@ var et2_nextmatch = et2_DOMWidget.extend({ }, destroy: function() { - // Destroy the dataview objects this.dataviewContainer.free(); + this.dynheight.free(); this._super.apply(this, arguments); }, + resize: function() { + this.dynheight.update(); + }, + /** * Sorts the nextmatch widget by the given ID. * @@ -297,7 +306,7 @@ var et2_nextmatch_header = et2_baseWidget.extend(et2_INextmatchHeader, { }); et2_register_widget(et2_nextmatch_header, ['nextmatch-header', - 'nextmatch-accountfilter', 'nextmatch-customfilter', 'nextmatch-customfields']); + 'nextmatch-customfilter', 'nextmatch-customfields']); var et2_nextmatch_sortheader = et2_nextmatch_header.extend(et2_INextmatchSortable, { @@ -347,5 +356,6 @@ var et2_nextmatch_filterheader = et2_selectbox.extend(et2_INextmatchHeader, { }); -et2_register_widget(et2_nextmatch_filterheader, ['nextmatch-filterheader']); +et2_register_widget(et2_nextmatch_filterheader, ['nextmatch-filterheader', + 'nextmatch-accountfilter']); diff --git a/etemplate/js/et2_extension_nextmatch_dynheight.js b/etemplate/js/et2_extension_nextmatch_dynheight.js new file mode 100644 index 0000000000..a0a3e4b606 --- /dev/null +++ b/etemplate/js/et2_extension_nextmatch_dynheight.js @@ -0,0 +1,173 @@ +/** + * eGroupWare eTemplate2 - JS Dynheight object + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package etemplate + * @subpackage api + * @link http://www.egroupware.org + * @author Andreas Stöckel + * @copyright Stylite 2011 + * @version $Id$ + */ + +"use strict" + +/*egw:use + jquery.jquery; + et2_core_inheritance; +*/ + +/** + * Object which resizes an inner node to the maximum extend of an outer node + * (without creating a scrollbar) - it achieves that by performing some very + * nasty and time consuming calculations. + */ +var et2_dynheight = Class.extend({ + + /** + * Constructor for the dynheight object + * + * @param _outerNode is the node which surrounds the _innerNode and to + * which extend the innerNode should be expanded without creating a + * scrollbar. Note: The outer node must be a parent of the inner node. + * If "null" is passed, the outer node is set to "window". + * @param _innerNode is the node which should be scaled. Call update to + * scale the node. + * @param _minHeight is the minimum height the inner node should have + */ + init: function(_outerNode, _innerNode, _minHeight) { + this.outerNode = _outerNode ? $j(_outerNode) : $j(window); + this.innerNode = $j(_innerNode); + this.minHeight = _minHeight; + + this.bottomNodes = []; + this.initialized = false; + this.innerMargin = 0; + this.outerMargin = 0; + }, + + /** + * Resizes the inner node. When this is done, the callback function is + * called. + */ + update: function(_callback, _context) { + // Check whether the inner node is actually visible - if not, don't + // trigger the callback function + if (this.innerNode.is(":visible")) + { + // Initialize the height calculation + this._initialize(); + + // Get the outer container height + var oh = this.outerNode.height(); + + // Get top and height of the inner node + var it = this.innerNode.offset().top; + + // Calculate the height of the "bottomNodes" + var bminTop = 0; + var bmaxBot = 0; + for (var i = 0; i < this.bottomNodes.length; i++) + { + // Get height, top and bottom and calculate the maximum/minimum + var bh = this.bottomNodes[i].outerHeight(true); + var bt = this.bottomNodes[i].offset().top; + var bb = bh + bt; + + if (i == 0 || bminTop > bt) + { + bminTop = bt; + } + + if (i == 0 || bmaxBot < bb) + { + bmaxBot = bb; + } + } + + // Get the height of the bottom container + var bh = bmaxBot - bminTop; + + // Calculate the new height of the inner container + var w = this.innerNode.width(); + var h = Math.max(this.minHeight, oh - it - bh - + this.innerMargin - this.outerMargin); + this.innerNode.height(h); + + // Call the callback function + if (typeof _callback != "undefined") + { + _callback.call(_context, _w, _h); + } + } + }, + + /** + * Function used internally which collects all DOM-Nodes which are located + * below this element. + */ + _collectBottomNodes: function(_node, _bottom) { + // Calculate the bottom position of the inner node + if (typeof _bottom == "undefined") + { + _bottom = this.innerNode.offset().top + this.innerNode.height(); + } + + if (_node) + { + // Accumulate the outer margin of the parent elements + var node = $j(_node); + var ooh = node.outerHeight(true); + var oh = node.height(); + this.outerMargin += (ooh - oh) / 2; // Divide by 2 as the value contains margin-top and -bottom + + // Iterate over the children of the given node and do the same + // recursively to the parent nodes until the _outerNode or body is + // reached. + var self = this; + $j(_node).children().each(function() { + var $this = $j(this); + var top = $this.offset().top; + if (this != self.innerNode[0] && top > _bottom) + { + self.bottomNodes.push($this); + } + }); + + if (_node != this.outerNode[0] && _node != $j("body")[0]) + { + this._collectBottomNodes(_node.parentNode, _bottom); + } + } + }, + + /** + * Used internally to calculate some information which will not change over + * the time. + */ + _initialize: function() { + if (!this.initialized) + { + // Collect all bottomNodes and calculates the outer margin + this.bottomNodes = []; + this.outerMargin = 0; + this._collectBottomNodes(this.innerNode[0].parentNode); + + // Calculate the inner margin + var ioh = this.innerNode.outerHeight(true); + var ih = this.innerNode.height(); + this.innerMargin = ioh - ih; + + // Calculate the outer margin + var node = this.outerNode; + if (node[0] == window) + { + node = $j("body"); + } + + this.initialized = true; + } + } + +}); + diff --git a/etemplate/js/etemplate2.js b/etemplate/js/etemplate2.js index 5dd51c540d..e7406ed84e 100644 --- a/etemplate/js/etemplate2.js +++ b/etemplate/js/etemplate2.js @@ -34,6 +34,7 @@ // Requirements for the etemplate2 object et2_core_xml; et2_core_arrayMgr; + et2_core_interfaces; */ /** @@ -57,10 +58,28 @@ function etemplate2(_container, _menuaction) // Preset the object variable this.widgetContainer = null; + // Connect to the window resize event + $j(window).resize(this, function(e) {e.data.resize()}); + // Associative array with the event listeners this.listeners = {}; } +/** + * Calls the resize event of all widgets + */ +etemplate2.prototype.resize = function() +{ + if (this.widgetContainer) + { + // Call the "resize" event of all functions which implement the + // "IResizeable" interface + this.widgetContainer.iterateOver(function(_widget) { + _widget.resize(); + }, this, et2_IResizeable); + } +} + /** * Clears the current instance. */ @@ -129,8 +148,12 @@ etemplate2.prototype.load = function(_url, _data) et2_loadXMLFromURL(_url, function(_xmldoc) { // Read the XML structure this.widgetContainer.loadFromXML(_xmldoc); + // Inform the widget tree that it has been successfully loaded. this.widgetContainer.loadingFinished(); + + // Trigger the "resize" event + this.resize(); }, this); // Clear any existing instance diff --git a/etemplate/js/test/test.css b/etemplate/js/test/test.css index 99df9f5087..32e0da3e27 100644 --- a/etemplate/js/test/test.css +++ b/etemplate/js/test/test.css @@ -9,6 +9,7 @@ body, table, td { font-family: Lucida Grande, sans-serif; font-size: 10pt; +/* overflow: hidden;*/ } #linklist a { diff --git a/etemplate/js/test/test_xml.html b/etemplate/js/test/test_xml.html index 6565b07082..4aeeac5f34 100644 --- a/etemplate/js/test/test_xml.html +++ b/etemplate/js/test/test_xml.html @@ -32,6 +32,7 @@ + @@ -79,6 +80,7 @@
ETemplate2 container:
+
[Just here to test the dynheight component...]