diff --git a/phpgwapi/inc/class.egw_grid_columns.inc.php b/phpgwapi/inc/class.egw_grid_columns.inc.php index 30fdb5d30f..c3a51da9e9 100644 --- a/phpgwapi/inc/class.egw_grid_columns.inc.php +++ b/phpgwapi/inc/class.egw_grid_columns.inc.php @@ -163,6 +163,7 @@ class egw_json_object */ define("EGW_COL_TYPE_DEFAULT", 0); define("EGW_COL_TYPE_NAME_ICON_FIXED", 1); +define("EGW_COL_TYPE_CHECKBOX", 2); define("EGW_COL_VISIBILITY_ALWAYS", 0); define("EGW_COL_VISIBILITY_VISIBLE", 1); @@ -211,7 +212,8 @@ class egw_grid_column extends egw_json_object public function set_visible($val) { - if ($this->visibility != EGW_COL_VISIBILITY_ALWAYS && $this->visibility != EGW_COL_VISIBILITY_ALWAYS_NOSELECT) + if ($this->visibility != EGW_COL_VISIBILITY_ALWAYS && + $this->visibility != EGW_COL_VISIBILITY_ALWAYS_NOSELECT) { $this->visibility = $val ? EGW_COL_VISIBILITY_VISIBLE : EGW_COL_VISIBILITY_INVISIBLE; } diff --git a/phpgwapi/js/egw_action/egw_action.js b/phpgwapi/js/egw_action/egw_action.js index 5f8a6a289b..378ac5dee4 100644 --- a/phpgwapi/js/egw_action/egw_action.js +++ b/phpgwapi/js/egw_action/egw_action.js @@ -581,6 +581,7 @@ function egwActionObject(_id, _parent, _iface, _manager, _flags) this.manager = _manager; this.flags = _flags; this.data = null; + this.setSelectedCallback = null; this.registeredImpls = []; @@ -1118,7 +1119,7 @@ egwActionObject.prototype.setAllSelected = function(_selected, _informParent) egwActionObject.prototype.updateSelectedChildren = function(_child, _selected) { var id = this.selectedChildren.indexOf(_child); // TODO Replace by binary search, insert children sorted by index! - var wasEmpty = this.selectedChildren.length == 0; + var wasEmpty = this.selectedChildren.length == 0; // Add or remove the given child from the selectedChildren list if (_selected && id == -1) @@ -1136,6 +1137,11 @@ egwActionObject.prototype.updateSelectedChildren = function(_child, _selected) { this.parent.updateSelectedChildren(this, wasEmpty); } + + if (this.setSelectedCallback) + { + this.setSelectedCallback.call(this); //TODO: Not called, when non-selected elements are made visible (treeview) + } } /** diff --git a/phpgwapi/js/egw_action/egw_grid.js b/phpgwapi/js/egw_action/egw_grid.js index a2dfe6a2d9..4b83733b3b 100644 --- a/phpgwapi/js/egw_action/egw_grid.js +++ b/phpgwapi/js/egw_action/egw_grid.js @@ -38,11 +38,19 @@ function egwGrid(_parentNode, _columns, _objectManager, _fetchCallback, _columnC // Create the root data element this.dataRoot = new egwGridDataElement("", null, this.columns, this.readQueue, _objectManager); + var self = this; + this.dataRoot.actionObject.setSelectedCallback = function() { + if (self.gridOuter.checkbox) + { + self.gridOuter.checkbox.attr("checked", this.getAllSelected()) + } + }; // Create the outer view component and pass the dataRoot element so that // the grid outer element will be capable of fetching the root data and // can create a spacer for that. - this.gridOuter = new egwGridViewOuter(_parentNode, this.dataRoot, this.selectcolsClick, this); + this.gridOuter = new egwGridViewOuter(_parentNode, this.dataRoot, + this.selectcolsClick, this.toggleAllClick, this); this.gridOuter.updateColumns(this.columns.getColumnData()); } @@ -159,6 +167,14 @@ egwGrid.prototype.selectcolsClick = function(_at) menu.showAt(_at.offset().left, _at.offset().top); } +/** + * Handles the toggle all click + */ +egwGrid.prototype.toggleAllClick = function(_checked) +{ + this.dataRoot.actionObject.toggleAllSelected(_checked); +} + /** * Emptys the grid */ diff --git a/phpgwapi/js/egw_action/egw_grid_columns.js b/phpgwapi/js/egw_action/egw_grid_columns.js index 117467ea7e..78319ba2ad 100644 --- a/phpgwapi/js/egw_action/egw_grid_columns.js +++ b/phpgwapi/js/egw_action/egw_grid_columns.js @@ -22,6 +22,7 @@ uses 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; @@ -140,9 +141,14 @@ egwGridColumn.prototype.set_id = function(_value) 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_NAME_ICON_FIXED || _value == EGW_COL_TYPE_CHECKBOX)) { this.type = _value; + + if (this.type == EGW_COL_TYPE_CHECKBOX) + { + this.set_width("30px"); + } } } diff --git a/phpgwapi/js/egw_action/egw_grid_data.js b/phpgwapi/js/egw_action/egw_grid_data.js index bd67b39ea2..8211540a95 100644 --- a/phpgwapi/js/egw_action/egw_grid_data.js +++ b/phpgwapi/js/egw_action/egw_grid_data.js @@ -517,6 +517,21 @@ egwGridDataElement.prototype.hasColumn = function(_columnId, _returnData) res = true; } } + else if (col.type == EGW_COL_TYPE_CHECKBOX) + { + if (!_returnData) + { + res = true; // Tell the loader that the checkbox data is always available + } + else + { + var dataSet = (typeof this.data[_columnId] != "undefined"); + res = { + "data": dataSet ? this.data[_columnId].data : 0, + "time": dataSet ? this.data[_columnId].time : this.capColTime + } + } + } else { // Check whether the column data of this column has been read, diff --git a/phpgwapi/js/egw_action/egw_grid_view.js b/phpgwapi/js/egw_action/egw_grid_view.js index 76d6ef2abd..dd88c6a167 100644 --- a/phpgwapi/js/egw_action/egw_grid_view.js +++ b/phpgwapi/js/egw_action/egw_grid_view.js @@ -76,7 +76,7 @@ var EGW_UNIQUE_COUNTER = 0; * @param object _data is the data-provider object which contains/loads the grid rows * and contains their data. */ -function egwGridViewOuter(_parentNode, _dataRoot, _selectColsCallback, _context) +function egwGridViewOuter(_parentNode, _dataRoot, _selectColsCallback, _toggleAllCallback, _context) { this.parentNode = $(_parentNode); this.dataRoot = _dataRoot; @@ -99,10 +99,13 @@ function egwGridViewOuter(_parentNode, _dataRoot, _selectColsCallback, _context) this.visibleColumnCount = 0; + this.checkbox = null; + this.uniqueId = 'grid_outer_' + EGW_UNIQUE_COUNTER; this.headerColumns = []; this.selectColsCallback = _selectColsCallback; + this.toggleAllCallback = _toggleAllCallback; this.context = _context; this.buildBase(); @@ -307,7 +310,25 @@ egwGridViewOuter.prototype.buildBaseHeader = function() var cont = $(document.createElement("div")); cont.addClass("innerContainer"); cont.addClass(col.divClass); - cont.html(col.caption); + + if (col.type == EGW_COL_TYPE_CHECKBOX) + { + this.checkbox = $(document.createElement("input")); + this.checkbox.attr("type", "checkbox"); + this.checkbox.change(this, function(e) { + // Call the toggle all callback + if (e.data.toggleAllCallback) + { + e.data.toggleAllCallback.call(e.data.context, $(this).is(":checked")); + } + }); + + cont.append(this.checkbox); + } + else + { + cont.html(col.caption); + } column.append(cont); this.outer_head_tr.append(column); @@ -1289,6 +1310,7 @@ function egwGridViewRow(_grid, _heightChangeProc, _item) container.aoiSetup = egwGridViewRow_aoiSetup; container.getAOI = egwGridViewRow_getAOI; container._columnClick = egwGridViewRow__columnClick; + container._checkboxClick = egwGridViewRow__checkboxClick; container.setOpen = egwGridViewRow_setOpen; container.reloadChildren = egwGridViewRow_reloadChildren; container.tdObjects = []; @@ -1296,6 +1318,7 @@ function egwGridViewRow(_grid, _heightChangeProc, _item) container.childGrid = null; container.opened = false; container.rowClass = ""; + container.checkbox = null; // Overwrite the inherited abstract functions container.doInsertIntoDOM = egwGridViewRow_doInsertIntoDOM; @@ -1325,10 +1348,16 @@ function egwGridViewRow_aoiSetState(_state, _shiftState) { if (this.row.parentNode) { - this.row.parentNode.toggleClass("selected", egwBitIsSet(_state, - EGW_AO_STATE_SELECTED)); + var selected = egwBitIsSet(_state, EGW_AO_STATE_SELECTED); + this.row.parentNode.toggleClass("selected", selected); this.row.parentNode.toggleClass("focused", egwBitIsSet(_state, EGW_AO_STATE_FOCUSED)); + + // Set the checkbox checked-state with the selected state + if (this.row.checkbox) + { + this.row.checkbox.attr("checked", selected); + } } } @@ -1368,6 +1397,14 @@ function egwGridViewRow__columnClick(_shiftState, _column) _shiftState); } +function egwGridViewRow__checkboxClick() +{ + this.aoi.updateState(EGW_AO_STATE_SELECTED, this.checkbox.is(":checked"), + EGW_AO_SHIFT_STATE_MULTI); + + return false; +} + var EGW_GRID_VIEW_ROW_BORDER = false; @@ -1398,10 +1435,29 @@ function egwGridViewRow_doInsertIntoDOM() // Assign the click event to the column // td.mousedown(egwPreventSelect); - td.click({"item": this, "col": col.id}, function(e) { -// this.onselectstart = null; - e.data.item._columnClick(egwGetShiftState(e), e.data.col); - }); + if (col.type == EGW_COL_TYPE_CHECKBOX) + { + this.checkbox = $(document.createElement("input")); + this.checkbox.attr("type", "checkbox"); + this.checkbox.attr("checked", egwBitIsSet(this.aoi.getState(), + EGW_AO_STATE_SELECTED)); + this.checkbox.change(this, function(e) { + e.data._checkboxClick(); + return false; + }); + + cont.append(this.checkbox); + } + else + { + td.click({"item": this, "col": col.id}, function(e) { +// this.onselectstart = null; + if (!e.data.item.checkbox || this != e.data.item.checkbox.context) + { + e.data.item._columnClick(egwGetShiftState(e), e.data.col); + } + }); + } td.append(cont); @@ -1468,10 +1524,9 @@ function egwGridViewRow_doUpdateData(_immediate) // Update the timestamp this.tdObjects[i].ts = data[col.id].time; - cont.empty(); - if (col.type == EGW_COL_TYPE_NAME_ICON_FIXED) { + cont.empty(); // Insert the indentation spacer var depth = this.item.getDepth() - 1; if (depth > 0) @@ -1567,8 +1622,16 @@ function egwGridViewRow_doUpdateData(_immediate) cont.append(caption); } } + else if (col.type == EGW_COL_TYPE_CHECKBOX) + { + this.checkbox.attr("checked", + (data[col.id].data == 0) ? + egwBitIsSet(this.aoi.getState(), EGW_AO_STATE_SELECTED) : + data[col.id].data); + } else { + cont.empty(); cont.html(data[col.id].data); } cont.toggleClass("queued", false);