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); } @@ -85,11 +88,12 @@ this.recvReqNo = 0; this.observeSortableColumns(); - + // Show initial rows this.showRows(1, this.limit); }, + /** * Initializes an AJAX request for retrieving some table data. Uses two ranges, one defines the * range that must be retrieved from the server, and one defines the range that should be @@ -117,6 +121,12 @@ }); } + if (typeof this.distinct != "undefined" && this.distinct.length > 0) { + this.distinct.each(function(field) { + url += ("&distinct=" + field); + }); + } + url += this.getSortURLFragment(); var self = this; @@ -145,11 +155,22 @@ } self.updateFetchedRows(res); + self.updateDistinctFilters(res); self.displayRows(displayOffset, displayLimit); } }); }, + updateDistinctFilters: function(json) + { + for (var i=0; i\n'; @@ -474,6 +496,27 @@ } }, + updateFilter: function(filterName, values) + { + var filterInput = this.filterNode.down("select[name='" + filterName + "']"); + var previouslySelected = filterInput.value; + if (typeof filterInput != "undefined") { + var tdContainer = filterInput.up('td'); + var select = new Element("select", {'name': filterName, 'class':'distinct'}); + 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) @@ -1557,7 +1557,7 @@

$msg.get("xe.livetable.tags.help") - $msg.get("xe.livetable.tags.help.cancel") + $msg.get("xe.livetable.tags.help.cancel")

@@ -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,17 @@
+ ## 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) + +