From 49f30140378ac44d1c69a9511359cde47f65a214 Mon Sep 17 00:00:00 2001 From: nathangray Date: Wed, 29 Jan 2020 16:05:01 -0700 Subject: [PATCH] Work on getting nextmatch loading --- api/js/etemplate/et2_dataview.js | 18 +- api/js/etemplate/et2_dataview.ts | 15 +- .../etemplate/et2_dataview_model_columns.js | 799 ++++++++---------- .../etemplate/et2_dataview_model_columns.ts | 509 +++++++++++ .../etemplate/et2_dataview_view_resizeable.js | 385 ++++----- .../etemplate/et2_dataview_view_resizeable.ts | 230 +++++ api/js/etemplate/et2_extension_nextmatch.js | 3 +- api/js/etemplate/et2_extension_nextmatch.ts | 5 +- 8 files changed, 1300 insertions(+), 664 deletions(-) create mode 100755 api/js/etemplate/et2_dataview_model_columns.ts create mode 100644 api/js/etemplate/et2_dataview_view_resizeable.ts diff --git a/api/js/etemplate/et2_dataview.js b/api/js/etemplate/et2_dataview.js index d7b71b3aef..bdb70885af 100644 --- a/api/js/etemplate/et2_dataview.js +++ b/api/js/etemplate/et2_dataview.js @@ -20,6 +20,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); et2_dataview_view_grid; et2_dataview_view_resizeable; */ +var et2_dataview_model_columns_1 = require("./et2_dataview_model_columns"); +var et2_dataview_view_resizeable_1 = require("./et2_dataview_view_resizeable"); /** * The et2_dataview class is the main class for displaying a dataview. The * dataview class manages the creation of the outer html nodes (like the table, @@ -98,7 +100,7 @@ var et2_dataview = /** @class */ (function () { // Free all column objects which have been created till this moment this._clearHeader(); // Copy the given column data - this.columnMgr = new et2_dataview_columns(_columnData); + this.columnMgr = new et2_dataview_model_columns_1.et2_dataview_columns(_columnData); // Create the stylesheets this.updateColumns(); // Build the header row @@ -189,7 +191,7 @@ var et2_dataview = /** @class */ (function () { */ et2_dataview.prototype._clearHeader = function () { if (this.columnMgr) { - this.columnMgr.free(); + this.columnMgr.destroy(); this.columnMgr = null; } // Remove dynamic CSS, @@ -305,16 +307,16 @@ var et2_dataview = /** @class */ (function () { .attr("align", "left") .append(cont) .appendTo(this.headTr); - if (this.columnMgr && this.columnMgr.columns[i]) { - column.addClass(this.columnMgr.columns[i].fixedWidth ? 'fixedWidth' : 'relativeWidth'); - if (this.columnMgr.columns[i].visibility === et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT) { + if (this.columnMgr && this.columnMgr.getColumnById(i)) { + column.addClass(this.columnMgr.getColumnById(i).fixedWidth ? 'fixedWidth' : 'relativeWidth'); + if (this.columnMgr.getColumnById(i).visibility === et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT) { column.addClass('noResize'); } } // make column resizable var enc_column = self.columnMgr.getColumnById(col.id); if (enc_column.visibility !== et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT) { - et2_dataview_view_resizable.makeResizeable(column, function (_w) { + et2_dataview_view_resizeable_1.et2_dataview_view_resizable.makeResizeable(column, function (_w) { // User wants the column to stay where they put it, even for relative // width columns, so set it explicitly first and adjust other relative // columns to match. @@ -328,10 +330,10 @@ var et2_dataview = /** @class */ (function () { var relative = self.columnMgr.totalWidth - self.columnMgr.totalFixed + _w; this.set_width(_w / relative); for (var i = 0; i < self.columnMgr.columns.length; i++) { - var col = self.columnMgr.columns[i]; + var col = self.columnMgr.getColumnById(i); if (col == this || col.fixedWidth) continue; - col.set_width(self.columnMgr.columnWidths[i] / relative); + col.set_width(self.columnMgr.getColumnWidth(i) / relative); } // Triggers column change callback, which saves self.updateColumns(); diff --git a/api/js/etemplate/et2_dataview.ts b/api/js/etemplate/et2_dataview.ts index 6598a7261e..86ac1f303b 100644 --- a/api/js/etemplate/et2_dataview.ts +++ b/api/js/etemplate/et2_dataview.ts @@ -20,6 +20,9 @@ et2_dataview_view_resizeable; */ +import {et2_dataview_columns} from './et2_dataview_model_columns'; +import {et2_dataview_view_resizable} from "./et2_dataview_view_resizeable"; + /** * The et2_dataview class is the main class for displaying a dataview. The * dataview class manages the creation of the outer html nodes (like the table, @@ -290,7 +293,7 @@ export class et2_dataview { if (this.columnMgr) { - this.columnMgr.free(); + this.columnMgr.destroy(); this.columnMgr = null; } @@ -443,10 +446,10 @@ export class et2_dataview .append(cont) .appendTo(this.headTr); - if(this.columnMgr && this.columnMgr.columns[i]) + if(this.columnMgr && this.columnMgr.getColumnById(i)) { - column.addClass(this.columnMgr.columns[i].fixedWidth ? 'fixedWidth' : 'relativeWidth'); - if(this.columnMgr.columns[i].visibility === et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT) + column.addClass(this.columnMgr.getColumnById(i).fixedWidth ? 'fixedWidth' : 'relativeWidth'); + if(this.columnMgr.getColumnById(i).visibility === et2_dataview_column.ET2_COL_VISIBILITY_ALWAYS_NOSELECT) { column.addClass('noResize'); } @@ -474,9 +477,9 @@ export class et2_dataview this.set_width(_w / relative); for(var i = 0; i < self.columnMgr.columns.length; i++) { - var col = self.columnMgr.columns[i]; + var col = self.columnMgr.getColumnById(i); if(col == this || col.fixedWidth) continue; - col.set_width(self.columnMgr.columnWidths[i] / relative); + col.set_width(self.columnMgr.getColumnWidth(i) / relative); } // Triggers column change callback, which saves self.updateColumns(); diff --git a/api/js/etemplate/et2_dataview_model_columns.js b/api/js/etemplate/et2_dataview_model_columns.js index 0acdb4ca42..42ddad6482 100755 --- a/api/js/etemplate/et2_dataview_model_columns.js +++ b/api/js/etemplate/et2_dataview_model_columns.js @@ -1,3 +1,4 @@ +"use strict"; /** * EGroupware eTemplate2 - Class which contains a the columns model * @@ -9,451 +10,391 @@ * @copyright Stylite 2011 * @version $Id$ */ - +Object.defineProperty(exports, "__esModule", { value: true }); /*egw:uses - et2_inheritance; + et2_core_inheritance; + 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; var ET2_COL_VISIBILITY_DISABLED = 4; - /** * Class which stores the data of a single column. * * @augments Class */ -var et2_dataview_column = (function(){ "use strict"; return ClassWithAttributes.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": "80px", - "description": "Width of the column." - }, - "minWidth": { - "name": "Minimum width", - "type": "integer", - "default": 20, - "description": "Minimum width of the column, in pixels. Values below this are rejected." - }, - "maxWidth": { - "name": "Maximum width", - "type": "integer", - "default": 0, - "description": "Maximum width of the column" - } - }, - - /** - * Constructor - * - * @param _attrs - * @memberOf et2_dataview_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 the column width - * - * Posible value types are: - * 1. "100" => fixedWidth 100px - * 2. "100px" => fixedWidth 100px - * 3. "50%" => relativeWidth 50% - * 4. 0.5 => relativeWidth 50% - * - * @param {float|string} _value - */ - set_width: function(_value) { - // Parse the width parameter. - this.relativeWidth = false; - this.fixedWidth = false; - var w = _value; - - if (typeof w == 'number') - { - this.relativeWidth = parseFloat(w.toFixed(3)); - } - else 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)); - } - else if (typeof w == 'string' && !isNaN(w)) - { - this.fixedWidth = parseInt(w); - } - }, - - set_visibility: function(_value) { - // If visibility is always, don't turn it off - if(this.visibility == ET2_COL_VISIBILITY_ALWAYS || this.visibility == ET2_COL_VISIBILITY_ALWAYS_NOSELECT) return; - - if(_value === true) - { - this.visibility = ET2_COL_VISIBILITY_VISIBLE; - } - else if (_value === false) - { - this.visibility = ET2_COL_VISIBILITY_INVISIBLE; - } - else if (typeof _value == "number") - { - this.visibility = _value; - } - else - { - this.egw().debug("warn", "Invalid visibility option for column: ", _value); - } - } -});}).call(this); - +var et2_dataview_column = /** @class */ (function () { + /** + * Constructor + */ + function et2_dataview_column(_attrs) { + /** + * Defines the visibility state of this column. + */ + this.visibility = ET2_COL_VISIBILITY_VISIBLE; + this.caption = ''; + /** + * Column type - Type of the column + * + * One of ET2_COL_TYPE_DEFAULT or ET2_COL_TYPE_NAME_ICON_FIXED + */ + this.type = ET2_COL_TYPE_DEFAULT; + /** + * Width of the column + */ + this.width = 80; + /** + * Maximum width of the column + */ + this.maxWidth = 0; + /** + * Minimum width of the column, in pixels. Values below this are rejected. + */ + this.minWidth = 20; + } + /** + * Set the column width + * + * Posible value types are: + * 1. "100" => fixedWidth 100px + * 2. "100px" => fixedWidth 100px + * 3. "50%" => relativeWidth 50% + * 4. 0.5 => relativeWidth 50% + * + * @param {float|string} _value + */ + et2_dataview_column.prototype.set_width = function (_value) { + // Parse the width parameter. + this.relativeWidth = false; + this.fixedWidth = false; + var w = _value; + if (typeof w == 'number') { + this.relativeWidth = parseFloat(w.toFixed(3)); + } + else 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)); + } + else if (typeof w == 'string' && !isNaN(parseFloat(w))) { + this.fixedWidth = parseInt(w); + } + }; + et2_dataview_column.prototype.set_visibility = function (_value) { + // If visibility is always, don't turn it off + if (this.visibility == ET2_COL_VISIBILITY_ALWAYS || this.visibility == ET2_COL_VISIBILITY_ALWAYS_NOSELECT) + return; + if (_value === true) { + this.visibility = ET2_COL_VISIBILITY_VISIBLE; + } + else if (_value === false) { + this.visibility = ET2_COL_VISIBILITY_INVISIBLE; + } + else if (typeof _value == "number") { + this.visibility = _value; + } + else { + egw().debug("warn", "Invalid visibility option for column: ", _value); + } + }; + et2_dataview_column._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": "80px", + "description": "Width of the column." + }, + "minWidth": { + "name": "Minimum width", + "type": "integer", + "default": 20, + "description": "Minimum width of the column, in pixels. Values below this are rejected." + }, + "maxWidth": { + "name": "Maximum width", + "type": "integer", + "default": 0, + "description": "Maximum width of the column" + } + }; + return et2_dataview_column; +}()); +exports.et2_dataview_column = et2_dataview_column; /** * 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 = (function(){ "use strict"; return Class.extend({ - - init: function(_columnData) { - // Initialize some variables - this.totalWidth = 0; - this.totalFixed = 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 - * - * @param {(string|number)} _width - */ - 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 - * - * @param {string} _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 - * - * @param {string} _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 - * - * @param {number} _idx - */ - 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 && - this.columns[i].visibility !== ET2_COL_VISIBILITY_DISABLED - - }); - } - - 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].visibility != ET2_COL_VISIBILITY_DISABLED) && - (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 - * - * @param {object} _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 totalRelative = 0; - var fixedCount = 0; - this.totalFixed = 0; - - for (var i = 0; i < this.columns.length; i++) - { - var col = this.columns[i]; - if (col.visibility !== ET2_COL_VISIBILITY_INVISIBLE && - col.visibility !== ET2_COL_VISIBILITY_DISABLED - ) - { - // Some bounds sanity checking - if(col.fixedWidth > tw || col.fixedWidth < 0) - { - col.fixedWidth = false; - } - else if (col.relativeWidth > 1 || col.relativeWidth < 0) - { - col.relativeWidth = false; - } - if (col.relativeWidth) - { - totalRelative += col.relativeWidth; - } - else if (col.fixedWidth) - { - this.totalFixed += col.fixedWidth; - fixedCount++; - } - } - } - - // Now calculate the absolute width of the columns in pixels - var usedTotal = 0; - 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 && - col.visibility !== ET2_COL_VISIBILITY_DISABLED - ) - { - if (col._larger) - { - w = col.maxWidth; - } - else if (col.fixedWidth) - { - w = col.fixedWidth; - } - else if (col.relativeWidth) - { - // Reset relative to an actual percentage (of 1.00) or - // resizing eventually sends them to 0 - col.relativeWidth = col.relativeWidth / totalRelative; - w = Math.round((tw-this.totalFixed) * col.relativeWidth); - } - if (w > tw || (col.maxWidth && w > col.maxWidth)) - { - w = Math.min(tw - usedTotal, col.maxWidth); - } - if (w < 0 || w < col.minWidth) - { - w = Math.max(0, col.minWidth); - } - } - this.columnWidths.push(w); - usedTotal += w; - } - - // Deal with any accumulated rounding errors - if(usedTotal != tw) - { - var column, columnIndex; - var remaining_width = (usedTotal - tw); - - // Pick the first relative column and use it - for(columnIndex = 0; columnIndex < this.columns.length; columnIndex++) - { - if(this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_INVISIBLE || - this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_DISABLED || - this.columnWidths[columnIndex] <= 0 || - remaining_width > 0 && this.columnWidths[columnIndex] <= this.columns[columnIndex].minWidth) - { - continue; - } - - var col = this.columns[columnIndex]; - if(col.relativeWidth || !col.fixedWidth) - { - column = col; - break; - } - else if (!col.fixedWidth) - { - column = col; - } - } - if(!column) - { - // Distribute shortage over all fixed width columns - var diff = Math.round(remaining_width / fixedCount); - for(var i = 0; i < this.columns.length; i++) - { - var col = this.columns[i]; - var col_diff = (diff < 0 ? - Math.max(remaining_width, diff) : - Math.min(remaining_width, diff) - ); - if(!col.fixedWidth) continue; - var new_width = this.columnWidths[i] - col_diff; - remaining_width -= col_diff; - this.columnWidths[i] = Math.max(0, Math.min(new_width,tw)); - } - } - else - { - this.columnWidths[columnIndex] = Math.max(column.minWidth, this.columnWidths[columnIndex] - remaining_width); - } - } - } - -});}).call(this); - +var et2_dataview_columns = /** @class */ (function () { + function et2_dataview_columns(_columnData) { + // Initialize some variables + this._totalWidth = 0; + this.totalFixed = 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; + } + et2_dataview_columns.prototype.destroy = function () { + // Free all column objects + for (var i = 0; i < this.columns.length; i++) { + this.columns[i] = null; + } + }; + Object.defineProperty(et2_dataview_columns.prototype, "totalWidth", { + get: function () { + return this._totalWidth; + }, + enumerable: true, + configurable: true + }); + /** + * Set the total width of the header row + * + * @param {(string|number)} _width + */ + et2_dataview_columns.prototype.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 + * + * @param {string} _id + */ + et2_dataview_columns.prototype.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 + * + * @param {string} _id + */ + et2_dataview_columns.prototype.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 + * + * @param {number} _idx + */ + et2_dataview_columns.prototype.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. + */ + et2_dataview_columns.prototype.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 && + this.columns[i].visibility !== ET2_COL_VISIBILITY_DISABLED + }); + } + return result; + }; + /** + * Returns an associative array which contains data about the visibility + * state of the columns. + */ + et2_dataview_columns.prototype.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].visibility != ET2_COL_VISIBILITY_DISABLED) && + (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 + * + * @param {object} _set + */ + et2_dataview_columns.prototype.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. + */ + et2_dataview_columns.prototype._calculateWidths = function () { + // Reset some values which are used during the calculation + var _larger = Array(this.columns.length); + for (var i = 0; i < this.columns.length; i++) { + _larger[i] = 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 totalRelative = 0; + var fixedCount = 0; + this.totalFixed = 0; + for (var i = 0; i < this.columns.length; i++) { + var col = this.columns[i]; + if (col.visibility !== ET2_COL_VISIBILITY_INVISIBLE && + col.visibility !== ET2_COL_VISIBILITY_DISABLED) { + // Some bounds sanity checking + if (col.fixedWidth > tw || col.fixedWidth < 0) { + col.fixedWidth = false; + } + else if (col.relativeWidth > 1 || col.relativeWidth < 0) { + col.relativeWidth = false; + } + if (col.relativeWidth) { + totalRelative += col.relativeWidth; + } + else if (col.fixedWidth) { + this.totalFixed += col.fixedWidth; + fixedCount++; + } + } + } + // Now calculate the absolute width of the columns in pixels + var usedTotal = 0; + 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 && + col.visibility !== ET2_COL_VISIBILITY_DISABLED) { + if (_larger[i]) { + w = col.maxWidth; + } + else if (col.fixedWidth) { + w = col.fixedWidth; + } + else if (col.relativeWidth) { + // Reset relative to an actual percentage (of 1.00) or + // resizing eventually sends them to 0 + col.relativeWidth = col.relativeWidth / totalRelative; + w = Math.round((tw - this.totalFixed) * col.relativeWidth); + } + if (w > tw || (col.maxWidth && w > col.maxWidth)) { + w = Math.min(tw - usedTotal, col.maxWidth); + } + if (w < 0 || w < col.minWidth) { + w = Math.max(0, col.minWidth); + } + } + this.columnWidths.push(w); + usedTotal += w; + } + // Deal with any accumulated rounding errors + if (usedTotal != tw) { + var column, columnIndex; + var remaining_width = (usedTotal - tw); + // Pick the first relative column and use it + for (columnIndex = 0; columnIndex < this.columns.length; columnIndex++) { + if (this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_INVISIBLE || + this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_DISABLED || + this.columnWidths[columnIndex] <= 0 || + remaining_width > 0 && this.columnWidths[columnIndex] <= this.columns[columnIndex].minWidth) { + continue; + } + var col = this.columns[columnIndex]; + if (col.relativeWidth || !col.fixedWidth) { + column = col; + break; + } + else if (!col.fixedWidth) { + column = col; + } + } + if (!column) { + // Distribute shortage over all fixed width columns + var diff = Math.round(remaining_width / fixedCount); + for (var i = 0; i < this.columns.length; i++) { + var col = this.columns[i]; + var col_diff = (diff < 0 ? + Math.max(remaining_width, diff) : + Math.min(remaining_width, diff)); + if (!col.fixedWidth) + continue; + var new_width = this.columnWidths[i] - col_diff; + remaining_width -= col_diff; + this.columnWidths[i] = Math.max(0, Math.min(new_width, tw)); + } + } + else { + this.columnWidths[columnIndex] = Math.max(column.minWidth, this.columnWidths[columnIndex] - remaining_width); + } + } + }; + return et2_dataview_columns; +}()); +exports.et2_dataview_columns = et2_dataview_columns; +//# sourceMappingURL=et2_dataview_model_columns.js.map \ No newline at end of file diff --git a/api/js/etemplate/et2_dataview_model_columns.ts b/api/js/etemplate/et2_dataview_model_columns.ts new file mode 100755 index 0000000000..7828ea0072 --- /dev/null +++ b/api/js/etemplate/et2_dataview_model_columns.ts @@ -0,0 +1,509 @@ +/** + * 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$ + */ + +/*egw:uses + et2_core_inheritance; + 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; +var ET2_COL_VISIBILITY_DISABLED = 4; + +/** + * Class which stores the data of a single column. + * + * @augments Class + */ +export class et2_dataview_column +{ + + static readonly _attributes: any = { + "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": "80px", + "description": "Width of the column." + }, + "minWidth": { + "name": "Minimum width", + "type": "integer", + "default": 20, + "description": "Minimum width of the column, in pixels. Values below this are rejected." + }, + "maxWidth": { + "name": "Maximum width", + "type": "integer", + "default": 0, + "description": "Maximum width of the column" + } + }; + + fixedWidth: number | boolean; + relativeWidth: number | boolean; + + /** + * Unique identifier for this column. It is used to store changed column widths or visibilities. + */ + public id: string; + + /** + * Defines the visibility state of this column. + */ + public visibility: number = ET2_COL_VISIBILITY_VISIBLE; + + public caption: string = ''; + + /** + * Column type - Type of the column + * + * One of ET2_COL_TYPE_DEFAULT or ET2_COL_TYPE_NAME_ICON_FIXED + */ + public type: number = ET2_COL_TYPE_DEFAULT; + + /** + * Width of the column + */ + public width: number = 80; + + /** + * Maximum width of the column + */ + public maxWidth: number = 0; + + /** + * Minimum width of the column, in pixels. Values below this are rejected. + */ + public minWidth: number = 20; + + /** + * Constructor + */ + constructor(_attrs) + { + } + + /** + * Set the column width + * + * Posible value types are: + * 1. "100" => fixedWidth 100px + * 2. "100px" => fixedWidth 100px + * 3. "50%" => relativeWidth 50% + * 4. 0.5 => relativeWidth 50% + * + * @param {float|string} _value + */ + set_width(_value) + { + // Parse the width parameter. + this.relativeWidth = false; + this.fixedWidth = false; + var w = _value; + + if (typeof w == 'number') + { + this.relativeWidth = parseFloat(w.toFixed(3)); + } + else 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)); + } + else if (typeof w == 'string' && !isNaN(parseFloat(w))) + { + this.fixedWidth = parseInt(w); + } + } + + set_visibility(_value) + { + // If visibility is always, don't turn it off + if(this.visibility == ET2_COL_VISIBILITY_ALWAYS || this.visibility == ET2_COL_VISIBILITY_ALWAYS_NOSELECT) return; + + if(_value === true) + { + this.visibility = ET2_COL_VISIBILITY_VISIBLE; + } + else if (_value === false) + { + this.visibility = ET2_COL_VISIBILITY_INVISIBLE; + } + else if (typeof _value == "number") + { + this.visibility = _value; + } + else + { + egw().debug("warn", "Invalid visibility option for column: ", _value); + } + } +} + +/** + * 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. + */ + +export class et2_dataview_columns +{ + private _totalWidth: number; + private totalFixed: number | boolean; + private columnWidths: any[]; + private columns: et2_dataview_column[]; + private updated: boolean; + + constructor(_columnData) + { + // Initialize some variables + this._totalWidth = 0; + this.totalFixed = 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() { + // Free all column objects + for (var i = 0; i < this.columns.length; i++) + { + this.columns[i] = null; + } + } + + get totalWidth(): number { + return this._totalWidth; + } + /** + * Set the total width of the header row + * + * @param {(string|number)} _width + */ + setTotalWidth(_width) + { + if (_width != this._totalWidth && _width > 0) + { + this._totalWidth = _width; + this.updated = true; + } + } + + /** + * Returns the index of the colum with the given id + * + * @param {string} _id + */ + getColumnIndexById( _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 + * + * @param {string} _id + */ + getColumnById( _id) + { + var idx = this.getColumnIndexById(_id); + return (idx == -1) ? null : this.columns[idx]; + } + + /** + * Returns the width of the column with the given index + * + * @param {number} _idx + */ + getColumnWidth( _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( ) + { + 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 && + this.columns[i].visibility !== ET2_COL_VISIBILITY_DISABLED + + }); + } + + return result; + } + + /** + * Returns an associative array which contains data about the visibility + * state of the columns. + */ + getColumnVisibilitySet() + { + 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].visibility != ET2_COL_VISIBILITY_DISABLED) && + (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 + * + * @param {object} _set + */ + setColumnVisibilitySet( _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() + { + // Reset some values which are used during the calculation + let _larger = Array(this.columns.length); + for (var i = 0; i < this.columns.length; i++) + { + _larger[i] = 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 totalRelative: number = 0; + var fixedCount = 0; + this.totalFixed = 0; + + for (var i = 0; i < this.columns.length; i++) + { + var col = this.columns[i]; + if (col.visibility !== ET2_COL_VISIBILITY_INVISIBLE && + col.visibility !== ET2_COL_VISIBILITY_DISABLED + ) + { + // Some bounds sanity checking + if(col.fixedWidth > tw || col.fixedWidth < 0) + { + col.fixedWidth = false; + } + else if (col.relativeWidth > 1 || col.relativeWidth < 0) + { + col.relativeWidth = false; + } + if (col.relativeWidth) + { + totalRelative += col.relativeWidth; + } + else if (col.fixedWidth) + { + this.totalFixed += col.fixedWidth; + fixedCount++; + } + } + } + + // Now calculate the absolute width of the columns in pixels + var usedTotal = 0; + 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 && + col.visibility !== ET2_COL_VISIBILITY_DISABLED + ) + { + if (_larger[i]) + { + w = col.maxWidth; + } + else if (col.fixedWidth) + { + w = col.fixedWidth; + } + else if (col.relativeWidth) + { + // Reset relative to an actual percentage (of 1.00) or + // resizing eventually sends them to 0 + col.relativeWidth = col.relativeWidth / totalRelative; + w = Math.round((tw-this.totalFixed) * col.relativeWidth); + } + if (w > tw || (col.maxWidth && w > col.maxWidth)) + { + w = Math.min(tw - usedTotal, col.maxWidth); + } + if (w < 0 || w < col.minWidth) + { + w = Math.max(0, col.minWidth); + } + } + this.columnWidths.push(w); + usedTotal += w; + } + + // Deal with any accumulated rounding errors + if(usedTotal != tw) + { + var column, columnIndex; + var remaining_width = (usedTotal - tw); + + // Pick the first relative column and use it + for(columnIndex = 0; columnIndex < this.columns.length; columnIndex++) + { + if(this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_INVISIBLE || + this.columns[columnIndex].visibility === ET2_COL_VISIBILITY_DISABLED || + this.columnWidths[columnIndex] <= 0 || + remaining_width > 0 && this.columnWidths[columnIndex] <= this.columns[columnIndex].minWidth) + { + continue; + } + + var col = this.columns[columnIndex]; + if(col.relativeWidth || !col.fixedWidth) + { + column = col; + break; + } + else if (!col.fixedWidth) + { + column = col; + } + } + if(!column) + { + // Distribute shortage over all fixed width columns + var diff = Math.round(remaining_width / fixedCount); + for(var i = 0; i < this.columns.length; i++) + { + var col = this.columns[i]; + var col_diff = (diff < 0 ? + Math.max(remaining_width, diff) : + Math.min(remaining_width, diff) + ); + if(!col.fixedWidth) continue; + var new_width = this.columnWidths[i] - col_diff; + remaining_width -= col_diff; + this.columnWidths[i] = Math.max(0, Math.min(new_width,tw)); + } + } + else + { + this.columnWidths[columnIndex] = Math.max(column.minWidth, this.columnWidths[columnIndex] - remaining_width); + } + } + } + +} diff --git a/api/js/etemplate/et2_dataview_view_resizeable.js b/api/js/etemplate/et2_dataview_view_resizeable.js index 3a7e28870b..f05f2ae732 100644 --- a/api/js/etemplate/et2_dataview_view_resizeable.js +++ b/api/js/etemplate/et2_dataview_view_resizeable.js @@ -1,3 +1,4 @@ +"use strict"; /** * EGroupware eTemplate2 - Functions which allow resizing of table headers * @@ -9,222 +10,174 @@ * @copyright Stylite 2011 * @version $Id$ */ - +Object.defineProperty(exports, "__esModule", { value: true }); /** * This set of functions is currently only supporting resizing in ew-direction */ - -(function() -{ - "use strict"; - - // Define some constants - var RESIZE_BORDER = 12; - var RESIZE_MIN_WIDTH = 25; - var RESIZE_ADD = 2; // Used to ensure mouse is under the resize element after resizing has finished - - // In resize region returns whether the mouse is currently in the - // "resizeRegion" - function inResizeRegion(_x, _elem) - { - var ol = _x - _elem.offset().left; - return (ol > (_elem.outerWidth(true) - RESIZE_BORDER)); - } - - var helper = null; - var overlay = null; - var didResize = false; - var resizeWidth = 0; - - function startResize(_outerElem, _elem, _callback, _column) - { - if (overlay == null || helper == null) - { - // Prevent text selection - // FireFox handles highlight prevention (text selection) different than other browsers - if (typeof _elem[0].style.MozUserSelect !="undefined") - { - _elem[0].style.MozUserSelect = "none"; - } - else - { - _elem[0].onselectstart = function() { - return false; - }; - } - - // Indicate resizing is in progress - jQuery(_outerElem).addClass('egwResizing'); - - // Reset the "didResize" flag - didResize = false; - - // Create the resize helper - var left = _elem.offset().left; - helper = jQuery(document.createElement("div")) - .addClass("egwResizeHelper") - .appendTo("body") - .css("top", _elem.offset().top + "px") - .css("left", left + "px") - .css("height", _outerElem.outerHeight(true) + "px"); - - // Create the overlay which will be catching the mouse movements - overlay = jQuery(document.createElement("div")) - .addClass("egwResizeOverlay") - - .bind("mousemove", function(e) { - didResize = true; - resizeWidth = Math.max(e.pageX - left + RESIZE_ADD, - _column && _column.minWidth ? _column.minWidth : RESIZE_MIN_WIDTH - ); - helper.css("width", resizeWidth + "px"); - }) - - .bind("mouseup", function() { - stopResize(_outerElem); - - // Reset text selection - _elem[0].onselectstart = null; - - // Call the callback if the user actually performed a resize - if (didResize) - { - _callback(resizeWidth); - } - }) - .appendTo("body"); - } - } - - function stopResize(_outerElem) - { - - jQuery(_outerElem).removeClass('egwResizing'); - if (helper != null) - { - helper.remove(); - helper = null; - } - - if (overlay != null) - { - overlay.remove(); - overlay = null; - } - } - - this.et2_dataview_makeResizeable = function(_elem, _callback, _context) - { - // Get the table surrounding the given element - this element is used to - // align the helper properly - var outerTable = _elem.closest("table"); - - // Bind the "mousemove" event in the "resize" namespace - _elem.bind("mousemove.resize", function(e) { - var stopResize = false; - // Stop switch to resize cursor if the mouse position - // is more intended for scrollbar not the resize edge - // 8pixel is an arbitary number for scrolbar area - if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) - { - stopResize = true; - } - _elem.css("cursor", inResizeRegion(e.pageX, _elem) && !stopResize? "ew-resize" : "auto"); - }); - - // Bind the "mousedown" event in the "resize" namespace - _elem.bind("mousedown.resize", function(e) { - var stopResize = false; - // Stop resize if the mouse position is more intended - // for scrollbar not the resize edge - // 8pixel is an arbitary number for scrolbar area - if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) - { - stopResize = true; - } - // Do not triger startResize if clicked element is select-tag, as it may causes conflict in some browsers - if (inResizeRegion(e.pageX, _elem) && e.target.tagName != 'SELECT' && !stopResize) - { - // Start the resizing - startResize(outerTable, _elem, function(_w) { - _callback.call(_context, _w); - }, _context); - } - - }); - - // Bind double click for auto-size - _elem.dblclick(function(e) { - // Just show message for relative width columns - if(_context && _context.relativeWidth) - { - return egw.message(egw.lang('You tried to automatically size a flex column, which always takes the rest of the space','info')); - } - // Find column class - it's usually the first one - var col_class = ''; - for(var i = 0; i < this.classList.length; i++) - { - if(this.classList[i].indexOf('gridCont') === 0) - { - col_class = this.classList[i]; - break; - } - } - - // Find widest part, including header - var column = jQuery(this); - column.children().css('width','auto'); - var max_width = column.children().children().innerWidth(); - var padding = column.outerWidth(true) - max_width; - - var resize = jQuery(this).closest('.egwGridView_outer') - .find('tbody td.'+col_class+'> div:first-child') - .add(column.children()) - // Set column width to auto to allow space for everything to flow - .css('width','auto'); - resize.children() - .css({'white-space':'nowrap'}) - .each(function() - { - var col = jQuery(this); - // Find visible (text) children and force them to not wrap - var children = col.find('span:visible, time:visible, label:visible') - .css({'white-space':'nowrap'}) - this.offsetWidth; - children.each(function() - { - var child = jQuery(this); - this.offsetWidth; - if(child.outerWidth() > max_width) - { - max_width = child.outerWidth(); - } - window.getComputedStyle(this).width; - }); - this.offsetWidth; - if(col.innerWidth() > max_width) - { - max_width = col.innerWidth(); - } - - // Reset children - children.css('white-space',''); - children.css('display',''); - } - ) - .css({'white-space':''}); - - // Reset column - column.children().css('width',''); - resize.css('width',''); - _callback.call(_context, max_width+padding); - }); - }; - - this.et2_dataview_resetResizeable = function(_elem) - { - // Remove all events in the ".resize" namespace from the element - _elem.unbind(".resize"); - }; -}).call(window); - +var et2_dataview_view_resizable = /** @class */ (function () { + function et2_dataview_view_resizable() { + } + // In resize region returns whether the mouse is currently in the + // "resizeRegion" + et2_dataview_view_resizable.inResizeRegion = function (_x, _elem) { + var ol = _x - _elem.offset().left; + return (ol > (_elem.outerWidth(true) - et2_dataview_view_resizable.RESIZE_BORDER)); + }; + et2_dataview_view_resizable.startResize = function (_outerElem, _elem, _callback, _column) { + if (this.overlay == null || this.helper == null) { + // Prevent text selection + // FireFox handles highlight prevention (text selection) different than other browsers + if (typeof _elem[0].style.MozUserSelect != "undefined") { + _elem[0].style.MozUserSelect = "none"; + } + else { + _elem[0].onselectstart = function () { + return false; + }; + } + // Indicate resizing is in progress + jQuery(_outerElem).addClass('egwResizing'); + // Reset the "didResize" flag + this.didResize = false; + // Create the resize helper + var left = _elem.offset().left; + this.helper = jQuery(document.createElement("div")) + .addClass("egwResizeHelper") + .appendTo("body") + .css("top", _elem.offset().top + "px") + .css("left", left + "px") + .css("height", _outerElem.outerHeight(true) + "px"); + // Create the overlay which will be catching the mouse movements + this.overlay = jQuery(document.createElement("div")) + .addClass("egwResizeOverlay") + .bind("mousemove", function (e) { + this.didResize = true; + this.resizeWidth = Math.max(e.pageX - left + et2_dataview_view_resizable.RESIZE_ADD, _column && _column.minWidth ? _column.minWidth : et2_dataview_view_resizable.RESIZE_MIN_WIDTH); + this.helper.css("width", this.resizeWidth + "px"); + }.bind(this)) + .bind("mouseup", function () { + this.stopResize(_outerElem); + // Reset text selection + _elem[0].onselectstart = null; + // Call the callback if the user actually performed a resize + if (this.didResize) { + _callback(this.resizeWidth); + } + }.bind(this)) + .appendTo("body"); + } + }; + et2_dataview_view_resizable.stopResize = function (_outerElem) { + jQuery(_outerElem).removeClass('egwResizing'); + if (this.helper != null) { + this.helper.remove(); + this.helper = null; + } + if (this.overlay != null) { + this.overlay.remove(); + this.overlay = null; + } + }; + // Define some constants + et2_dataview_view_resizable.RESIZE_BORDER = 12; + et2_dataview_view_resizable.RESIZE_MIN_WIDTH = 25; + et2_dataview_view_resizable.RESIZE_ADD = 2; // Used to ensure mouse is under the resize element after resizing has finished + et2_dataview_view_resizable.helper = null; + et2_dataview_view_resizable.overlay = null; + et2_dataview_view_resizable.didResize = false; + et2_dataview_view_resizable.resizeWidth = 0; + et2_dataview_view_resizable.makeResizeable = function (_elem, _callback, _context) { + // Get the table surrounding the given element - this element is used to + // align the helper properly + var outerTable = _elem.closest("table"); + // Bind the "mousemove" event in the "resize" namespace + _elem.bind("mousemove.resize", function (e) { + var stopResize = false; + // Stop switch to resize cursor if the mouse position + // is more intended for scrollbar not the resize edge + // 8pixel is an arbitary number for scrolbar area + if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) { + stopResize = true; + } + _elem.css("cursor", et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && !stopResize ? "ew-resize" : "auto"); + }); + // Bind the "mousedown" event in the "resize" namespace + _elem.bind("mousedown.resize", function (e) { + var stopResize = false; + // Stop resize if the mouse position is more intended + // for scrollbar not the resize edge + // 8pixel is an arbitary number for scrolbar area + if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) { + stopResize = true; + } + // Do not triger startResize if clicked element is select-tag, as it may causes conflict in some browsers + if (et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && e.target.tagName != 'SELECT' && !stopResize) { + // Start the resizing + et2_dataview_view_resizable.startResize(outerTable, _elem, function (_w) { + _callback.call(_context, _w); + }, _context); + } + }); + // Bind double click for auto-size + _elem.dblclick(function (e) { + // Just show message for relative width columns + if (_context && _context.relativeWidth) { + return egw.message(egw.lang('You tried to automatically size a flex column, which always takes the rest of the space', 'info')); + } + // Find column class - it's usually the first one + var col_class = ''; + for (var i = 0; i < this.classList.length; i++) { + if (this.classList[i].indexOf('gridCont') === 0) { + col_class = this.classList[i]; + break; + } + } + // Find widest part, including header + var column = jQuery(this); + column.children().css('width', 'auto'); + var max_width = column.children().children().innerWidth(); + var padding = column.outerWidth(true) - max_width; + var resize = jQuery(this).closest('.egwGridView_outer') + .find('tbody td.' + col_class + '> div:first-child') + .add(column.children()) + // Set column width to auto to allow space for everything to flow + .css('width', 'auto'); + resize.children() + .css({ 'white-space': 'nowrap' }) + .each(function () { + var col = jQuery(this); + // Find visible (text) children and force them to not wrap + var children = col.find('span:visible, time:visible, label:visible') + .css({ 'white-space': 'nowrap' }); + this.offsetWidth; + children.each(function () { + var child = jQuery(this); + this.offsetWidth; + if (child.outerWidth() > max_width) { + max_width = child.outerWidth(); + } + window.getComputedStyle(this).width; + }); + this.offsetWidth; + if (col.innerWidth() > max_width) { + max_width = col.innerWidth(); + } + // Reset children + children.css('white-space', ''); + children.css('display', ''); + }) + .css({ 'white-space': '' }); + // Reset column + column.children().css('width', ''); + resize.css('width', ''); + _callback.call(_context, max_width + padding); + }); + }; + et2_dataview_view_resizable.et2_dataview_resetResizeable = function (_elem) { + // Remove all events in the ".resize" namespace from the element + _elem.unbind(".resize"); + }; + return et2_dataview_view_resizable; +}()); +exports.et2_dataview_view_resizable = et2_dataview_view_resizable; +//# sourceMappingURL=et2_dataview_view_resizeable.js.map \ No newline at end of file diff --git a/api/js/etemplate/et2_dataview_view_resizeable.ts b/api/js/etemplate/et2_dataview_view_resizeable.ts new file mode 100644 index 0000000000..97813ac782 --- /dev/null +++ b/api/js/etemplate/et2_dataview_view_resizeable.ts @@ -0,0 +1,230 @@ +/** + * EGroupware eTemplate2 - Functions which allow resizing of table headers + * + * @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$ + */ + +/** + * This set of functions is currently only supporting resizing in ew-direction + */ + +export class et2_dataview_view_resizable +{ + + // Define some constants + public static readonly RESIZE_BORDER = 12; + public static readonly RESIZE_MIN_WIDTH = 25; + public static readonly RESIZE_ADD = 2; // Used to ensure mouse is under the resize element after resizing has finished + + + public static helper : JQuery = null; + public static overlay : JQuery = null; + public static didResize = false; + public static resizeWidth = 0; + + // In resize region returns whether the mouse is currently in the + // "resizeRegion" + public static inResizeRegion(_x, _elem) + { + var ol = _x - _elem.offset().left; + return (ol > (_elem.outerWidth(true) - et2_dataview_view_resizable.RESIZE_BORDER)); + } + + public static startResize(_outerElem, _elem, _callback, _column) + { + if (this.overlay == null || this.helper == null) + { + // Prevent text selection + // FireFox handles highlight prevention (text selection) different than other browsers + if (typeof _elem[0].style.MozUserSelect !="undefined") + { + _elem[0].style.MozUserSelect = "none"; + } + else + { + _elem[0].onselectstart = function() { + return false; + }; + } + + // Indicate resizing is in progress + jQuery(_outerElem).addClass('egwResizing'); + + // Reset the "didResize" flag + this.didResize = false; + + // Create the resize helper + var left = _elem.offset().left; + this.helper = jQuery(document.createElement("div")) + .addClass("egwResizeHelper") + .appendTo("body") + .css("top", _elem.offset().top + "px") + .css("left", left + "px") + .css("height", _outerElem.outerHeight(true) + "px"); + + // Create the overlay which will be catching the mouse movements + this.overlay = jQuery(document.createElement("div")) + .addClass("egwResizeOverlay") + + .bind("mousemove", function(e) { + this.didResize = true; + this.resizeWidth = Math.max(e.pageX - left + et2_dataview_view_resizable.RESIZE_ADD, + _column && _column.minWidth ? _column.minWidth : et2_dataview_view_resizable.RESIZE_MIN_WIDTH + ); + this.helper.css("width", this.resizeWidth + "px"); + }.bind(this)) + + .bind("mouseup", function() { + this.stopResize(_outerElem); + + // Reset text selection + _elem[0].onselectstart = null; + + // Call the callback if the user actually performed a resize + if (this.didResize) + { + _callback(this.resizeWidth); + } + }.bind(this)) + .appendTo("body"); + } + } + + public static stopResize(_outerElem) + { + + jQuery(_outerElem).removeClass('egwResizing'); + if (this.helper != null) + { + this.helper.remove(); + this.helper = null; + } + + if (this.overlay != null) + { + this.overlay.remove(); + this.overlay = null; + } + } + + public static makeResizeable = function(_elem, _callback, _context) + { + // Get the table surrounding the given element - this element is used to + // align the helper properly + var outerTable = _elem.closest("table"); + + // Bind the "mousemove" event in the "resize" namespace + _elem.bind("mousemove.resize", function(e) { + var stopResize = false; + // Stop switch to resize cursor if the mouse position + // is more intended for scrollbar not the resize edge + // 8pixel is an arbitary number for scrolbar area + if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) + { + stopResize = true; + } + _elem.css("cursor", et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && !stopResize? "ew-resize" : "auto"); + }); + + // Bind the "mousedown" event in the "resize" namespace + _elem.bind("mousedown.resize", function(e) { + var stopResize = false; + // Stop resize if the mouse position is more intended + // for scrollbar not the resize edge + // 8pixel is an arbitary number for scrolbar area + if (e.target.clientHeight < e.target.scrollHeight && e.target.offsetWidth - e.offsetX <= 8) + { + stopResize = true; + } + // Do not triger startResize if clicked element is select-tag, as it may causes conflict in some browsers + if (et2_dataview_view_resizable.inResizeRegion(e.pageX, _elem) && e.target.tagName != 'SELECT' && !stopResize) + { + // Start the resizing + et2_dataview_view_resizable.startResize(outerTable, _elem, function(_w) { + _callback.call(_context, _w); + }, _context); + } + + }); + + // Bind double click for auto-size + _elem.dblclick(function(e) { + // Just show message for relative width columns + if(_context && _context.relativeWidth) + { + return egw.message(egw.lang('You tried to automatically size a flex column, which always takes the rest of the space','info')); + } + // Find column class - it's usually the first one + var col_class = ''; + for(var i = 0; i < this.classList.length; i++) + { + if(this.classList[i].indexOf('gridCont') === 0) + { + col_class = this.classList[i]; + break; + } + } + + // Find widest part, including header + var column = jQuery(this); + column.children().css('width','auto'); + var max_width = column.children().children().innerWidth(); + var padding = column.outerWidth(true) - max_width; + + var resize = jQuery(this).closest('.egwGridView_outer') + .find('tbody td.'+col_class+'> div:first-child') + .add(column.children()) + // Set column width to auto to allow space for everything to flow + .css('width','auto'); + resize.children() + .css({'white-space':'nowrap'}) + .each(function() + { + var col = jQuery(this); + // Find visible (text) children and force them to not wrap + var children = col.find('span:visible, time:visible, label:visible') + .css({'white-space':'nowrap'}); + this.offsetWidth; + children.each(function() + { + var child = jQuery(this); + this.offsetWidth; + if(child.outerWidth() > max_width) + { + max_width = child.outerWidth(); + } + window.getComputedStyle(this).width; + }); + this.offsetWidth; + if(col.innerWidth() > max_width) + { + max_width = col.innerWidth(); + } + + // Reset children + children.css('white-space',''); + children.css('display',''); + } + ) + .css({'white-space':''}); + + // Reset column + column.children().css('width',''); + resize.css('width',''); + _callback.call(_context, max_width+padding); + }); + }; + + public static et2_dataview_resetResizeable = function(_elem) + { + // Remove all events in the ".resize" namespace from the element + _elem.unbind(".resize"); + } +} + diff --git a/api/js/etemplate/et2_extension_nextmatch.js b/api/js/etemplate/et2_extension_nextmatch.js index 7a6a4ad1bd..58655257dc 100644 --- a/api/js/etemplate/et2_extension_nextmatch.js +++ b/api/js/etemplate/et2_extension_nextmatch.js @@ -537,7 +537,6 @@ var et2_nextmatch = /** @class */ (function (_super_1) { }; /** * Nextmatch needs a namespace - * @private */ et2_nextmatch.prototype._createNamespace = function () { return true; @@ -909,7 +908,7 @@ var et2_nextmatch = /** @class */ (function (_super_1) { _colData.splice(remove_action_index, remove_action_index); } // Create the column manager and update the grid container - // TODO this.dataview.setColumns(columnData); + this.dataview.setColumns(columnData); for (var x = 0; x < _row.length; x++) { // Append the widget to this container this.addChild(_row[x].widget); diff --git a/api/js/etemplate/et2_extension_nextmatch.ts b/api/js/etemplate/et2_extension_nextmatch.ts index a42badb71b..1939518c3a 100644 --- a/api/js/etemplate/et2_extension_nextmatch.ts +++ b/api/js/etemplate/et2_extension_nextmatch.ts @@ -799,7 +799,6 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2 /** * Nextmatch needs a namespace - * @private */ protected _createNamespace(): boolean { @@ -1269,7 +1268,7 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2 } // Create the column manager and update the grid container - // TODO this.dataview.setColumns(columnData); + this.dataview.setColumns(columnData); for (var x = 0; x < _row.length; x++) { @@ -2613,7 +2612,7 @@ export class et2_nextmatch extends et2_DOMWidget implements et2_IResizeable, et2 } // Restore columns - var pref = []; + var pref: string | object | boolean = []; var app = this.getInstanceManager().app; if(this.options.settings.columnselection_pref.indexOf('nextmatch') == 0) {