Index: resources/js/xwiki/table/livetable.js =================================================================== --- resources/js/xwiki/table/livetable.js (revision 27358) +++ resources/js/xwiki/table/livetable.js (working copy) @@ -39,7 +39,7 @@ if (!options) { var options = {}; } - + // id of the root element that encloses this livetable this.domNodeName = domNodeName; @@ -54,6 +54,9 @@ // Array of nodes under which pagination for this livetable will be displayed. this.paginationNodes = options.paginationNodes || $(this.domNodeName).select(".xwiki-livetable-pagination"); + // Remember which fields should send back distinct value with JSON results + this.distinct = options.distinct || []; + if (typeof options == "undefined") { options = {}; } @@ -65,7 +68,7 @@ if (typeof this.paginationNodes != "undefined") { this.paginator = new LiveTablePagination(this, this.paginationNodes, options.maxPages || 10); } - // Initialize filters + // Initialize filters if (this.filtersNode) { this.filter = new LiveTableFilter(this, this.filtersNode); } @@ -86,11 +89,53 @@ this.observeSortableColumns(); + this.currentOffset = (this.getPageFromLocationHash() - 1) * this.limit + 1; + // Show initial rows - this.showRows(1, this.limit); + this.showRows(this.currentOffset, this.limit); }, + + updateLocationHash: function() + { + var currentHash = window.location.hash.substring(1); + var shouldUpdate = !(this.lastoffset == 1 && currentHash.blank()); + + if (shouldUpdate) { + var tables = currentHash.split("|"), newHash = "", foundThisTable = false; + for (var i=0;i 0) { + this.distinct.each(function(field) { + url += ("&distinct=" + field); + }); + } + url += this.getSortURLFragment(); var self = this; @@ -145,11 +198,22 @@ } self.updateFetchedRows(res); + self.updateDistinctFilters(res); self.displayRows(displayOffset, displayLimit); } }); }, + updateDistinctFilters: function(json) + { + for (var i=0; i\n'; @@ -474,6 +541,23 @@ } }, + updateFilter: function(filterName, values) + { + var filterInput = this.filterNode.down("input[name='" + filterName + "']"); + var tdContainer = filterInput.up('td'); + filterInput.remove(); + + var select = new Element("select", {'name': filterName}); + select.insert(new Element("option", {'value':'',}).update('none')); + for (var i=0;i 0) { - this.tags = tags; + this.tags = tags; this.map = this.buildPopularityMap(this.tags); this.hasTags = true; this.domNode.removeClassName("hidden"); Index: templates/macros.vm =================================================================== --- templates/macros.vm (revision 27358) +++ templates/macros.vm (working copy) @@ -1587,6 +1587,7 @@ + #set($distinct = $util.arrayList) #foreach($colname in $collist) #set($colprop = $colprops.get($colname)) #if(("$!colprop.filterable" == "" || $colprop.filterable != false) && "$!colname" != "_actions") @@ -1646,6 +1647,16 @@ #end + #elseif("$!colprop.type" == "distinct" && $isFilterable) + ## First, add the field to the list of distinct fields (they will be passed later on to + ## the javascript livetable object, so that they can be sent as AJAX parameters to the JSON source) + #set($discard = $distinct.add($colname)) + #elseif( ("$!colprop.type"=="text"||"$!colprop.type"=="number") && $isFilterable) #elseif("$!colprop.type"=="hidden") @@ -1678,9 +1689,19 @@
+ ## This input field will be replaced dynamically by a select list as soon as a livetable AJAX request + ## returns results. + ## It is need to keep a reference on the column name (attribute "name" of the input) + +