mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-30 20:04:30 +01:00
590 lines
13 KiB
JavaScript
590 lines
13 KiB
JavaScript
/**
|
|
* eGroupWare egw_action framework - egw action framework
|
|
*
|
|
* @link http://www.egroupware.org
|
|
* @author Andreas Stöckel <as@stylite.de>
|
|
* @copyright 2011 by Andreas Stöckel
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
* @package egw_action
|
|
* @version $Id$
|
|
*/
|
|
|
|
/*egw:uses
|
|
egw_action_common;
|
|
*/
|
|
|
|
/**
|
|
* Contains logic for the column class. The column class represents the unique set
|
|
* of columns a grid view owns. The parameters of the columns (except for visibility)
|
|
* di normaly not change.
|
|
*/
|
|
|
|
var EGW_COL_TYPE_DEFAULT = 0;
|
|
var EGW_COL_TYPE_NAME_ICON_FIXED = 1;
|
|
var EGW_COL_TYPE_CHECKBOX = 2;
|
|
|
|
var EGW_COL_VISIBILITY_ALWAYS = 0;
|
|
var EGW_COL_VISIBILITY_VISIBLE = 1;
|
|
var EGW_COL_VISIBILITY_INVISIBLE = 2;
|
|
var EGW_COL_VISIBILITY_ALWAYS_NOSELECT = 3;
|
|
|
|
var EGW_COL_SORTABLE_NONE = 0;
|
|
var EGW_COL_SORTABLE_ALPHABETIC = 1;
|
|
var EGW_COL_SORTABLE_NUMERICAL = 2;
|
|
var EGW_COL_SORTABLE_NATURAL = 3;
|
|
var EGW_COL_SORTABLE_EXTERNAL = 4;
|
|
|
|
|
|
var EGW_COL_SORTMODE_NONE = 0;
|
|
var EGW_COL_SORTMODE_ASC = 1;
|
|
var EGW_COL_SORTMODE_DESC = 2;
|
|
|
|
var EGW_COL_DEFAULT_FETCH = -10000;
|
|
|
|
|
|
/**
|
|
* Class representing a single grid column.
|
|
*/
|
|
function egwGridColumn(_context, _visiblityChangeCallback, _sortmodeChangeCallback)
|
|
{
|
|
if (typeof _context == "undefined")
|
|
{
|
|
_context = null;
|
|
}
|
|
|
|
if (typeof _visiblityChangeCallback == "undefined")
|
|
{
|
|
_visiblityChangeCallback == null;
|
|
}
|
|
|
|
this.id = "";
|
|
this.fixedWidth = false;
|
|
this.relativeWidth = false;
|
|
this.maxWidth = false;
|
|
this.caption = "";
|
|
this.type = EGW_COL_TYPE_DEFAULT;
|
|
this.visibility = EGW_COL_VISIBILITY_VISIBLE;
|
|
this.sortable = EGW_COL_SORTABLE_NONE;
|
|
this.sortmode = EGW_COL_SORTMODE_NONE;
|
|
this["default"] = EGW_COL_DEFAULT_FETCH;
|
|
|
|
this.context = _context;
|
|
this.visibilityChangeCallback = _visiblityChangeCallback;
|
|
this.sortmodeChangeCallback = _sortmodeChangeCallback;
|
|
}
|
|
|
|
egwGridColumn.prototype.loadData = function(_data)
|
|
{
|
|
egwActionStoreJSON(_data, this, true);
|
|
}
|
|
|
|
egwGridColumn.prototype.set_width = function(_value)
|
|
{
|
|
// Parse the width parameter. Posible values are:
|
|
// 1. "100" => fixedWidth 100px
|
|
// 2. "100px" => fixedWidth 100px
|
|
// 3. "50%" => relativeWidth 50%
|
|
if (_value)
|
|
{
|
|
if (typeof _value == "string")
|
|
{
|
|
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));
|
|
}
|
|
else if (!isNaN(w))
|
|
{
|
|
this.fixedWidth = parseInt(w);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
egwGridColumn.prototype.set_maxWidth = function(_value)
|
|
{
|
|
if (!isNaN(_value) && _value > 0)
|
|
{
|
|
this.maxWidth = _value;
|
|
}
|
|
}
|
|
|
|
egwGridColumn.prototype.set_default = function(_value)
|
|
{
|
|
if (typeof _value == "string")
|
|
{
|
|
this["default"] = _value;
|
|
}
|
|
else if (typeof _value == "number" && (_value == EGW_COL_DEFAULT_FETCH))
|
|
{
|
|
this["default"] = _value;
|
|
}
|
|
}
|
|
|
|
egwGridColumn.prototype.set_id = function(_value)
|
|
{
|
|
this.id = _value;
|
|
}
|
|
|
|
/**
|
|
* Setter for the column type.
|
|
*/
|
|
egwGridColumn.prototype.set_type = function(_value)
|
|
{
|
|
if (typeof _value == "number" && (_value == EGW_COL_TYPE_DEFAULT ||
|
|
_value == EGW_COL_TYPE_NAME_ICON_FIXED || _value == EGW_COL_TYPE_CHECKBOX))
|
|
{
|
|
this.type = _value;
|
|
|
|
if (this.type == EGW_COL_TYPE_CHECKBOX)
|
|
{
|
|
this.set_width("23px");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setter for the visibility of the column. Checks whether the given value is in
|
|
* the allowed range and calls the visibilityChangeCallback.
|
|
*/
|
|
egwGridColumn.prototype.set_visibility = function(_value)
|
|
{
|
|
if (typeof _value == "number" && (_value == EGW_COL_VISIBILITY_ALWAYS ||
|
|
_value == EGW_COL_VISIBILITY_INVISIBLE || _value == EGW_COL_VISIBILITY_VISIBLE ||
|
|
_value == EGW_COL_VISIBILITY_ALWAYS_NOSELECT))
|
|
{
|
|
if (_value != this.visibility)
|
|
{
|
|
this.visibility = _value;
|
|
|
|
if (this.visibilityChangeCallback)
|
|
{
|
|
this.visibilityChangeCallback.call(this.context, this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the sortmode of the column and informs the parent about it.
|
|
*/
|
|
egwGridColumn.prototype.set_sortmode = function(_value)
|
|
{
|
|
if (typeof _value == "number" && (_value == EGW_COL_SORTMODE_NONE ||
|
|
_value == EGW_COL_SORTMODE_ASC || _value == EGW_COL_SORTMODE_DESC))
|
|
{
|
|
if (this.sortable == EGW_COL_SORTABLE_NONE)
|
|
{
|
|
this.sortmode = EGW_COL_SORTMODE_NONE;
|
|
}
|
|
else
|
|
{
|
|
if (_value != this.sortmode)
|
|
{
|
|
if (this.sortmodeChangeCallback)
|
|
{
|
|
this.sortmodeChangeCallback.call(this.context, this);
|
|
}
|
|
this.sortmode = _value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
egwGridColumn.prototype.set_sortable = function(_value)
|
|
{
|
|
if (typeof _value == "number" && (_value == EGW_COL_SORTABLE_ALPHABETIC ||
|
|
_value == EGW_COL_SORTABLE_NONE || _value == EGW_COL_SORTABLE_NATURAL ||
|
|
_value == EGW_COL_SORTABLE_NUMERICAL || _value == EGW_COL_SORTABLE_EXTERNAL))
|
|
{
|
|
if (_value == EGW_COL_SORTABLE_NONE)
|
|
{
|
|
this.sortmode = EGW_COL_SORTABLE_NONE;
|
|
}
|
|
|
|
this.sortable = _value;
|
|
}
|
|
}
|
|
|
|
|
|
egwGridColumn.prototype.set_caption = function(_value)
|
|
{
|
|
this.caption = _value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Object which is used inside egwGrid to manage the grid columns.
|
|
*/
|
|
function egwGridColumns(_columns, _updateCallback, _context, _columnSpace)
|
|
{
|
|
// Default the coulumn padding value to two
|
|
if (typeof _columnSpace == "undefined")
|
|
{
|
|
this.columnSpace = 2;
|
|
}
|
|
else
|
|
{
|
|
this.columnSpace = _columnSpace;
|
|
}
|
|
|
|
this.totalWidth = false;
|
|
this.inUpdate = false;
|
|
this.sortChanged = null;
|
|
this.visibilityChanged = false;
|
|
this.columnWidths = [];
|
|
|
|
this.context = _context;
|
|
this.updateCallback = _updateCallback;
|
|
|
|
this._beginUpdate();
|
|
|
|
this.columns = [];
|
|
for (var i = 0; i < _columns.length; i++)
|
|
{
|
|
var column = new egwGridColumn(this, this._visibilityCallback, this._sortCallback);
|
|
column.loadData(_columns[i]);
|
|
|
|
this.columns.push(column);
|
|
}
|
|
|
|
this._endUpdate();
|
|
}
|
|
|
|
egwGridColumns.prototype._beginUpdate = function()
|
|
{
|
|
this.inUpdate = true;
|
|
this.sortChanged = null;
|
|
this.visibilityChanged = false;
|
|
}
|
|
|
|
egwGridColumns.prototype._endUpdate = function()
|
|
{
|
|
this.inUpdate = false;
|
|
|
|
// Call the sort update again in order to update the other columns
|
|
if (this.sortChanged)
|
|
{
|
|
this._sortCallback(this.sortCallback);
|
|
}
|
|
|
|
if (this.visibilityChanged || this.sortChanged)
|
|
{
|
|
this.updateCallback.call(this.context, this);
|
|
}
|
|
|
|
this.sortChanged = null;
|
|
this.visibilityChanged = false;
|
|
}
|
|
|
|
egwGridColumns.prototype._visibilityCallback = function(_elem)
|
|
{
|
|
if (this.inUpdate)
|
|
{
|
|
this.visibilityChanged = true;
|
|
}
|
|
else
|
|
{
|
|
this.updateCallback.call(this.context, this);
|
|
}
|
|
}
|
|
|
|
egwGridColumns.prototype._sortCallback = function(_elem)
|
|
{
|
|
if (this.inUpdate)
|
|
{
|
|
this.sortChanged = _elem;
|
|
}
|
|
else
|
|
{
|
|
// Reset the sortmode of all other elements.
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
if (this.columns[i] != _elem)
|
|
{
|
|
this.columns[i].sortmode = EGW_COL_SORTMODE_NONE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
egwGridColumns.prototype._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;// - (Math.max(this.getVisibleCount() - 1, 0)) * this.columnSpace;
|
|
|
|
// 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 != EGW_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 = true;
|
|
do
|
|
{
|
|
done = true;
|
|
|
|
var noWidth = remRelWidth / noWidthCount;
|
|
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
var col = this.columns[i];
|
|
|
|
if (col.visibility != EGW_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 != EGW_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 != EGW_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);
|
|
}
|
|
}
|
|
|
|
egwGridColumns.prototype.setTotalWidth = function(_value)
|
|
{
|
|
if (_value < 100)
|
|
{
|
|
_value = 100;
|
|
}
|
|
|
|
this.totalWidth = _value;
|
|
this._calculateWidths();
|
|
}
|
|
|
|
egwGridColumns.prototype.getColumnIndexById = function(_id)
|
|
{
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
if (this.columns[i].id == _id)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
egwGridColumns.prototype.getColumnById = function(_id)
|
|
{
|
|
var idx = this.getColumnIndexById(_id);
|
|
return (idx == -1) ? null : this.columns[idx];
|
|
}
|
|
|
|
egwGridColumns.prototype.getVisibleCount = function()
|
|
{
|
|
var cnt = 0;
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
if (this.columns[i].visibility != EGW_COL_VISIBILITY_INVISIBLE)
|
|
{
|
|
cnt++;
|
|
}
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
egwGridColumns.prototype.getColumnVisibilitySet = function()
|
|
{
|
|
var result = {};
|
|
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
if (this.columns[i].visibility != EGW_COL_VISIBILITY_ALWAYS_NOSELECT)
|
|
{
|
|
result[this.columns[i].id] = {
|
|
"caption": this.columns[i].caption,
|
|
"enabled": (this.columns[i].visibility != EGW_COL_VISIBILITY_ALWAYS) &&
|
|
(this.columns[i].type != EGW_COL_TYPE_NAME_ICON_FIXED),
|
|
"visible": this.columns[i].visibility != EGW_COL_VISIBILITY_INVISIBLE
|
|
};
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
egwGridColumns.prototype.setColumnVisibilitySet = function(_set)
|
|
{
|
|
this._beginUpdate();
|
|
|
|
for (var k in _set)
|
|
{
|
|
var col = this.getColumnById(k);
|
|
if (col)
|
|
{
|
|
col.set_visibility(_set[k].visible ? EGW_COL_VISIBILITY_VISIBLE :
|
|
EGW_COL_VISIBILITY_INVISIBLE);
|
|
}
|
|
}
|
|
|
|
if (this.visibilityChanged)
|
|
{
|
|
this._calculateWidths();
|
|
}
|
|
|
|
this._endUpdate();
|
|
}
|
|
|
|
egwGridColumns.prototype.getColumnData = function()
|
|
{
|
|
var result = [];
|
|
|
|
for (var i = 0; i < this.columns.length; i++)
|
|
{
|
|
result.push(
|
|
{
|
|
"id": this.columns[i].id,
|
|
"caption": this.columns[i].caption,
|
|
"sortable": this.columns[i].sortable,
|
|
"sortmode": this.columns[i].sortmode,
|
|
"default": this.columns[i]["default"],
|
|
"width": this.columnWidths[i],
|
|
"type": this.columns[i].type,
|
|
"visible": this.columns[i].visibility != EGW_COL_VISIBILITY_INVISIBLE,
|
|
"element": this.columns[i]
|
|
}
|
|
);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
egwGridColumns.prototype.sortBy = function(_id, _mode)
|
|
{
|
|
// Fetch the column and set its sortmode. If the column supports sorting,
|
|
// it will call the callback function.
|
|
var col = this.getColumnById(_id);
|
|
if (col)
|
|
{
|
|
col.set_sortmode(_mode);
|
|
}
|
|
}
|
|
|
|
|