Wiki source code of Livetable Pagination Size

Last modified by Vincent Massol on 2024/11/19 16:12

Show last authors
1 == Community Feedback ==
2
3 {{info}}
4 Discussed: Support choosing pagination size in livetable UI: http://xwiki.markmail.org/thread/3sychusbsijj2jny
5 {{/info}}
6
7 == Description ==
8
9 (((
10 Currently the number of rows displayed in a livetable is fixed at creation time.
11
12 (((
13 I propose to add an UI controls (currently select) that allows to change the pagination size freely.
14 )))
15
16 (((
17 (% class="Apple-style-span" style="line-height: 19px;" %)This patch is both a change in livetable.js to support these controls (one or more), and a change in the livetable macro to allow displaying them.
18 )))
19
20 (% style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-family: sans-serif; font-size: 14px; font-style: inherit; font-weight: inherit; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; vertical-align: baseline; line-height: normal;" %)
21 (((
22 (% style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 1px; border-left-width: 0px; border-style: initial; border-color: initial; font-family: sans-serif; font-size: 1.61em; font-style: inherit; font-weight: 400; margin-top: 20px; margin-right: 0px; margin-bottom: 20px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; vertical-align: baseline; line-height: 1.2em; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); color: rgb(0, 0, 0); display: block; overflow-x: hidden; overflow-y: hidden;" %)
23 == (% style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-family: sans-serif; font-size: 23px; font-style: inherit; font-weight: inherit; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; vertical-align: baseline; line-height: 1.2em; border-bottom-style: none; border-bottom-color: initial; display: inline; position: static;" %)#livetable macro changes improvements(%%) ==
24 )))
25
26 (% style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-family: sans-serif; font-size: 14px; font-style: inherit; font-weight: inherit; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; vertical-align: baseline; line-height: normal;" %)
27 (((
28 The #livetable macro default to display a pageSize control. It a select control placed where the ajax-loader bar is located. It is hidden during loading, so that it swaps with the ajax-loader bar. The control is prefixed by a label "per page of". (see screenshots below)
29
30 You can disable this new feature by setting options.pageSize to false.
31
32 (% style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-family: sans-serif; font-size: 14px; font-style: inherit; font-weight: inherit; margin-top: 0.5em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; outline-width: 0px; outline-style: initial; outline-color: initial; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; vertical-align: baseline; line-height: 1.4em;" %)
33 A new options.pageSizeBounds, that should be a valid code to initialize an array of 3 numbers (not sure this is the best option, you may have your own ideas). If this options is present, the necessary markup is added to the table.
34 )))
35
36 = (% class="Apple-style-span" style="font-size: 23px; line-height: 27px;" %)Livetable.js improvements(%%) =
37
38 (((
39 The added feature work similarly to the pagination feature. It defaults to add its controls in nodes styled ".xwiki-livetable-pagesize-content" under nodes styled ".xwiki-livetable-pagesize" which can be customized with options.pageSizeNodes.
40 )))
41
42 (((
43 The added controls are select nodes styled ".pagesizeselect". These select nodes contains options from options.pageSizeBounds[0] (defaults to 10) to options.pageSizeBounds[1] (default to 100), by step of options.pageSizeBounds[2] (default to 10). If the current size is not in these options, it is also inserted properly between the correct steps.
44 )))
45
46 (((
47 When an options is selected by the user, the livetable cache is cleared, and the user returned to the first page with the new pagination in place (this could be improved, not so easy however, I am investigating).
48 )))
49
50 (((
51 == Colateral improvements ==
52 )))
53
54 (((
55 To support hiding the control during loading, I had to add a loadingComplete custom even on the livetable. My feeling is that is was missing, since it was impossible to pair the loadingEntries events in case of failure. I have also adapted the livetable stylesheet for proper display and also improve the display when no pagesize select is used.
56
57 == Screenshots ==
58
59 [[image:screenshot01.png]]
60 )))
61
62 [[image:screenshot02.png]]
63
64 [[image:screenshot03.png]]
65
66 [[image:screenshot04.png]]
67
68 == Current Patch ==
69
70 {{code language="diff"}}
71 Index: web/standard/src/main/webapp/resources/js/xwiki/table/livetable.js
72 ===================================================================
73 --- web/standard/src/main/webapp/resources/js/xwiki/table/livetable.js (revision 28668)
74 +++ web/standard/src/main/webapp/resources/js/xwiki/table/livetable.js (revision )
75 @@ -60,10 +60,13 @@
76 || $(options.filtersNode) // Deprecated option (kept for backward compatibility)
77 || $(domNodeName).down(".xwiki-livetable-display-filters") // Default filter node when none precised
78 ].flatten().compact();
79 -
80 +
81 // Array of nodes under which pagination for this livetable will be displayed.
82 this.paginationNodes = options.paginationNodes || $(this.domNodeName).select(".xwiki-livetable-pagination");
83
84 + // Array of nodes under which a page size control will be displayed
85 + this.pageSizeNodes = options.pageSizeNodes || $(this.domNodeName).select(".xwiki-livetable-pagesize");
86 +
87 if (typeof options == "undefined") {
88 options = {};
89 }
90 @@ -73,6 +76,11 @@
91
92 this.permalinks = options.permalinks || true;
93
94 + // Initialize page size control bounds
95 + if (typeof this.pageSizeNodes != "undefined") {
96 + this.pageSizer = new LiveTablePageSizer(this, this.pageSizeNodes, options.pageSizeBounds, this.limit);
97 + }
98 +
99 // Initialize pagination
100 if (typeof this.paginationNodes != "undefined") {
101 this.paginator = new LiveTablePagination(this, this.paginationNodes, options.maxPages || 10);
102 @@ -106,8 +114,19 @@
103 // Show initial rows
104 this.showRows(this.currentOffset, this.limit);
105 },
106 -
107 +
108 /**
109 + * Set the page size of the table and refresh the display
110 + * @param pageSize The new maximum number of rows to display per page
111 + **/
112 + setPageSize: function(pageSize)
113 + {
114 + this.limit = pageSize;
115 + this.clearCache();
116 + this.showRows(1, parseInt(this.limit));
117 + },
118 +
119 + /**
120 * Re-write location hash with current page and filters values
121 */
122 updateLocationHash: function()
123 @@ -225,6 +244,17 @@
124 {
125 method: 'get',
126 onComplete: function( transport ) {
127 + // Let code know loading is finished
128 + // 1. Named event (for code interested by that table only)
129 + document.fire("xwiki:livetable:" + self.domNodeName + ":loadingComplete", {
130 + "status" : transport.status
131 + });
132 + // 2. Generic event (for code potentially interested in any livetable)
133 + document.fire("xwiki:livetable:loadingComplete", {
134 + "status" : transport.status,
135 + "tableId" : self.domNodeName
136 + });
137 +
138 self.loadingStatus.addClassName("hidden");
139 },
140
141 @@ -573,7 +603,67 @@
142 }
143 });
144
145 +/**
146 + * Helper class to display the page size control
147 + **/
148 + var LiveTablePageSizer = Class.create({
149 + /**
150 + * Create a new instance
151 + * @param table The LiveTable
152 + * @param domNodes An array of nodes indicating where the controls will be created
153 + * @param pageSizeBounds The bounds specification for acceptable values (an array of min, max, step)
154 + * @param currentPageSize The currently selected page size.
155 + **/
156 + initialize: function(table, domNodes, pageSizeBounds, currentPageSize) {
157 + this.table = table;
158 + this.currentValue = currentPageSize;
159 + var bounds = pageSizeBounds || [];
160 + this.startValue = bounds[0] || 10;
161 + this.step = bounds[2] || 10;
162 + this.maxValue = bounds[1] || 100;
163 -
164 +
165 + var self = this;
166 + this.pageSizeNodes = [];
167 + domNodes.each(function(elem) {
168 + self.pageSizeNodes.push(elem.down(".xwiki-livetable-pagesize-content"));
169 + });
170 +
171 + this.pageSizeNodes.each(function(elem) {
172 + elem.insert(self.createPageSizeSelectControl());
173 + });
174 + },
175 +
176 + /**
177 + * Create the page size control using a select node and returns it
178 + * @return an Element containing the select
179 + **/
180 + createPageSizeSelectControl: function() {
181 + var select = new Element('select', {'class':'pagesizeselect'});
182 + for (var i=this.startValue; i<=this.maxValue; i += this.step) {
183 + var attrs = {'value':i, 'text':i}
184 + if (i == this.currentValue)
185 + attrs.selected = true;
186 + else {
187 + var prevStep = i - this.step;
188 + if (this.currentValue > prevStep && this.currentValue < i) {
189 + select.appendChild(new Element('option', {'value':this.currentValue, 'text':this.currentValue, selected:true}).update(this.currentValue));
190 + }
191 + }
192 + select.appendChild(new Element('option', attrs).update(i));
193 + }
194 + select.observe("change", this.changePageSize.bind(this));
195 + return select;
196 + },
197 +
198 + /**
199 + * Change the page size of the table
200 + **/
201 + changePageSize: function(event) {
202 + var newLimit = parseInt($F(Event.element(event)));
203 + this.table.setPageSize(newLimit);
204 + }
205 +});
206 +
207 /*
208 * The class that deals with the filtering in a table
209 */
210 @@ -879,4 +969,3 @@
211 }
212
213 })();
214 -
215 Index: web/standard/src/main/webapp/resources/js/xwiki/table/livetable.css
216 ===================================================================
217 --- web/standard/src/main/webapp/resources/js/xwiki/table/livetable.css (revision 28561)
218 +++ web/standard/src/main/webapp/resources/js/xwiki/table/livetable.css (revision )
219 @@ -8,13 +8,19 @@
220 }
221 .xwiki-livetable-loader , .xwiki-livetable-loader img {
222 float: left;
223 + line-height: 22px;
224 }
225 .xwiki-livetable-pagination .xwiki-livetable-limits {
226 float: left;
227 + line-height: 22px;
228 }
229 .xwiki-livetable-pagination .xwiki-livetable-limits strong {
230 font-weight: normal;
231 }
232 +.xwiki-livetable-pagination .xwiki-livetable-pagesize {
233 + line-height: 22px;
234 + margin-left: 5px;
235 +}
236 .xwiki-livetable-pagination .xwiki-livetable-pagination-content, .xwiki-livetable-pagination .xwiki-livetable-pagination-text {
237 display: inline;
238 }
239 @@ -37,6 +43,7 @@
240 .pagination {
241 float: right;
242 margin-right: 10px;
243 + line-height: 22px;
244 }
245 .controlPagination {
246 position: relative;
247 Index: web/standard/src/main/webapp/templates/macros.vm
248 ===================================================================
249 --- web/standard/src/main/webapp/templates/macros.vm (revision 28545)
250 +++ web/standard/src/main/webapp/templates/macros.vm (revision )
251 @@ -1521,6 +1521,7 @@
252 #if("$!options.tagCloud" == '' || $options.tagCloud == false) #set($tagcloud=false) #else #set($tagcloud = true) #end
253 #if("$!options.javascriptName" != '') #set($jsName = $options.javascriptName) #else #set($jsName = 'livetable') #end
254 #if("$!options.topFilters" != '') #set($topfilters = $options.topFilters) #end
255 + #if("$!options.pageSizeBounds" != '') #set($pageSizeBounds = $options.pageSizeBounds) #end
256 #set($classname = "$!options.className")
257 #set($extraparams = "$!options.extraParams")
258 ##
259 @@ -1553,6 +1554,7 @@
260 ##
261 <div class="xwiki-livetable-container">
262 #if("$!topfilters" !='') #set($hasTopFilters = true) #else #set($hasTopFilters = false) #end
263 + #if("$!pageSizeBounds" !='') #set($hasPageSize = true) #else #set($hasPageSize = false) #end
264 #if($tagcloud || $hasTopFilters)
265 <div class="tipfilters">
266 #end
267 @@ -1591,6 +1593,12 @@
268 <tr>
269 <td class="xwiki-livetable-pagination">
270 <span id="${divid}-limits" class="xwiki-livetable-limits"></span>
271 + #if($hasPageSize)
272 + <span id="${divid}-pagesize" class="xwiki-livetable-pagesize">
273 + <span>$msg.get('xe.livetable.pagesize.label')</span>
274 + <span class="xwiki-livetable-pagesize-content" ></span>
275 + </span>
276 + #end
277 <span id="${divid}-ajax-loader" class="xwiki-livetable-loader hidden">
278 <img src="$xwiki.getSkinFile('icons/xwiki/ajax-loader-large.gif')" alt="$msg.get('xe.livetable.loading')" title="" />
279 </span>
280 @@ -1713,14 +1721,20 @@
281 "maxPages":$maxPages
282 ,"limit":$count
283 #if($hasTopFilters),"filterNodes" : [$("${divid}").down(".xwiki-livetable-display-filters"), $('${divid}-topfilters')]#end
284 + #if($hasPageSize),"pageSizeBounds" : $pageSizeBounds#end
285 });
286 #else
287 $jsName = new XWiki.widgets.LiveTable("$dataurl", "${divid}", #livetablecallback($divid $collist $colprops $transprefix), {
288 "maxPages":$maxPages
289 ,"limit":$count
290 #if($hasTopFilters),"filterNodes" : [$("${divid}").down(".xwiki-livetable-display-filters"), $('${divid}-topfilters')]#end
291 + #if($hasPageSize),"pageSizeBounds" : $pageSizeBounds#end
292 });
293 #end
294 + #if($!hasPageSize)
295 + document.observe("xwiki:livetable:${divid}:loadingEntries", function() { $('${divid}-pagesize').addClassName("hidden"); } );
296 + document.observe("xwiki:livetable:${divid}:loadingComplete", function() { $('${divid}-pagesize').removeClassName("hidden"); } );
297 + #end
298 }
299 //]]>
300 </script>
301
302 {{/code}}
303 )))

Get Connected