/** * eGroupWare eTemplate2 - Class which contains a the columns model * * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @package etemplate * @subpackage dataview * @link http://www.egroupware.org * @author Andreas Stöckel * @copyright Stylite 2011 * @version $Id$ */ "use strict" /*egw:uses et2_inheritance; */ var ET2_COL_TYPE_DEFAULT = 0; var ET2_COL_TYPE_NAME_ICON_FIXED = 1; var ET2_COL_VISIBILITY_ALWAYS = 0; var ET2_COL_VISIBILITY_VISIBLE = 1; var ET2_COL_VISIBILITY_INVISIBLE = 2; var ET2_COL_VISIBILITY_ALWAYS_NOSELECT = 3; /** * Class which stores the data of a single column. */ var et2_dataview_column = Class.extend({ attributes: { "id": { "name": "ID", "type": "string", "description": "Unique identifier for this column. It is used to " + "store changed column widths or visibilities." }, "visibility": { "name": "Visibility", "type": "integer", "default": ET2_COL_VISIBILITY_VISIBLE, "description": "Defines the visibility state of this column." }, "caption": { "name": "Caption", "type": "string", "description": "Caption of the column as it is displayed in the " + "select columns popup." }, "type": { "name": "Column type", "type": "integer", "default": ET2_COL_TYPE_DEFAULT, "description": "Type of the column" }, "width": { "name": "Width", "type": "dimension", "default": "auto", "description": "Width of the column." }, "maxWidth": { "name": "Maximum width", "type": "integer", "default": 0, "description": "Maximum width of the column" } }, init: function(_attrs) { this.fixedWidth = false; this.relativeWidth = false; // Do the sanity check on the attributes and load them this.generateAttributeSet(_attrs); this.initAttributes(_attrs); }, set_width: function(_value) { // Parse the width parameter. Posible values are: // 1. "100" => fixedWidth 100px // 2. "100px" => fixedWidth 100px // 3. "50%" => relativeWidth 50% // 4. "auto" => fixedWidth false, relativeWidth false this.relativeWidth = false; this.fixedWidth = false; var w = _value; if (w.charAt(w.length - 1) == "%" && !isNaN(w.substr(0, w.length - 1))) { this.relativeWidth = parseInt(w.substr(0, w.length - 1)) / 100; // Relative widths with more than 100% are not allowed! if (this.relativeWidth > 1) { this.relativeWidth = false; } } else if (w.substr(w.length - 2, 2) == "px" && !isNaN(w.substr(0, w.length - 2))) { this.fixedWidth = parseInt(w.substr(0, w.length - 2)); } } }); /** * Contains logic for the columns class. The columns class represents the unique set * of columns a grid view owns. The parameters of the columns (except for visibility) * do normaly not change. */ var et2_dataview_columns = Class.extend({ init: function(_columnData) { // Initialize some variables this.totalWidth = 0; this.columnWidths = []; // Create the columns object this.columns = new Array(_columnData.length); for (var i = 0; i < _columnData.length; i++) { this.columns[i] = new et2_dataview_column(_columnData[i]); } this.updated = true; }, destroy: function() { // Free all column objects for (var i = 0; i < this.columns.length; i++) { this.columns[i].free(); } }, /** * Set the total width of the header row */ setTotalWidth: function(_width) { if (_width != this.totalWidth && _width > 0) { this.totalWidth = _width; this.updated = true; } }, /** * Returns the index of the colum with the given id */ getColumnIndexById: function(_id) { for (var i = 0; i < this.columns.length; i++) { if (this.columns[i].id == _id) { return i; } } return -1; }, /** * Returns the column with the given id */ getColumnById: function(_id) { var idx = this.getColumnIndexById(_id); return (idx == -1) ? null : this.columns[idx]; }, /** * Returns the width of the column with the given index */ getColumnWidth: function(_idx) { if (this.totalWidth > 0 && _idx >= 0 && _idx < this.columns.length) { // Recalculate the column widths if something has changed. if (this.updated) { this._calculateWidths(); this.updated = false; } // Return the calculated width for the column with the given index. return this.columnWidths[_idx]; } return 0; }, /** * Returns an array containing the width of the column and its visibility * state. */ getColumnData: function() { var result = []; for (var i = 0; i < this.columns.length; i++) { result.push({ "id": this.columns[i].id, "width": this.getColumnWidth(i), "visible": this.columns[i].visibility != ET2_COL_VISIBILITY_INVISIBLE }); } return result; }, /** * Returns an associative array which contains data about the visibility * state of the columns. */ getColumnVisibilitySet: function() { var result = {}; for (var i = 0; i < this.columns.length; i++) { if (this.columns[i].visibility != ET2_COL_VISIBILITY_ALWAYS_NOSELECT) { result[this.columns[i].id] = { "caption": this.columns[i].caption, "enabled": (this.columns[i].visibility != ET2_COL_VISIBILITY_ALWAYS) && (this.columns[i].type != ET2_COL_TYPE_NAME_ICON_FIXED), "visible": this.columns[i].visibility != ET2_COL_VISIBILITY_INVISIBLE }; } } return result; }, /** * Sets a column visiblity set */ setColumnVisibilitySet: function(_set) { for (var k in _set) { var col = this.getColumnById(k); if (col) { col.set_visibility(_set[k].visible ? ET2_COL_VISIBILITY_VISIBLE : ET2_COL_VISIBILITY_INVISIBLE); } } this.updated = true; }, /* ---- PRIVATE FUNCTIONS ---- */ /** * Calculates the absolute column width depending on the previously set * "totalWidth" value. The calculated values are stored in the columnWidths * array. */ _calculateWidths: function() { // Reset some values which are used during the calculation for (var i = 0; i < this.columns.length; i++) { this.columns[i]._larger = false; this.columns[i]._newWidth = false; } // Remove the spacing between the columns from the total width var tw = this.totalWidth; // Calculate how many space is - relatively - not occupied with columns with // relative or fixed width var remRelWidth = 1; var noWidthCount = 0 for (var i = 0; i < this.columns.length; i++) { var col = this.columns[i]; if (col.visibility != ET2_COL_VISIBILITY_INVISIBLE) { if (col.relativeWidth) { remRelWidth -= col.relativeWidth; } else if (col.fixedWidth) { remRelWidth -= col.fixedWidth / tw; } else { noWidthCount++; } } } // Check whether the width of columns with relative width is larger than their // maxWidth var done; do { done = true; var noWidth = remRelWidth / noWidthCount; for (var i = 0; i < this.columns.length; i++) { var col = this.columns[i]; if (col.visibility != ET2_COL_VISIBILITY_INVISIBLE) { if (col.maxWidth && !col._larger) { if (col.relativeWidth) { var w = col.relativeWidth * tw; col._larger = w > col.maxWidth; if (col._larger) { // Recalculate the remaining relative width: // col.maxWidth / w is the relative amount of space p which // is remaining for the element. E.g. an element with // w = 150px and maxWidth = 100px => p = 2/3 // The space which got removed is 1 - p => 1/3 // ==> we have to add 1/3 * oldRelWidth to the remRelWidth // variable. remRelWidth += col.relativeWidth * (1 - col.maxWidth / w); done = false; break; } } else { col._larger = noWidth * tw > col.maxWidth; if (col._larger) { remRelWidth -= col.maxWidth / tw; noWidthCount--; done = false; break; } } } } } // As some columns take their max width, new space might come available, which // requires other columns to take their maximum width. } while (!done); // Check whether the columns where a relative width is specified have more // space than the remaining columns - if yes, make the relative ones larger for (var i = 0; i < this.columns.length; i++) { var col = this.columns[i]; if (col.visibility != ET2_COL_VISIBILITY_INVISIBLE) { if (col.relativeWidth && !col._larger) { if (col.relativeWidth < noWidth) { noWidthCount++; remRelWidth += col.relativeWidth; col._newWidth = true; } else { col._newWidth = false; } } } } // Now calculate the absolute width of the columns in pixels this.columnWidths = []; for (var i = 0; i < this.columns.length; i++) { var w = 0; var col = this.columns[i]; if (col.visibility != ET2_COL_VISIBILITY_INVISIBLE) { if (col._larger) { w = col.maxWidth; } else if (col.fixedWidth) { w = col.fixedWidth; } else if (col.relativeWidth && !col._newWidth) { w = Math.round(tw * col.relativeWidth); } else { w = Math.round(tw * (remRelWidth / noWidthCount)); } if (w < 0) { w = 0; } } this.columnWidths.push(w); } } });