Wiki source code of Live Table
Last modified by Sergei Kulagin on 2024/04/23
Hide last authors
author | version | line-number | content |
---|---|---|---|
![]() |
134.3 | 1 | {{box cssClass="floatinginfobox" title="**Contents**"}} |
2 | {{toc/}} | ||
3 | {{/box}} | ||
![]() |
125.2 | 4 | |
![]() |
134.3 | 5 | = Summary = |
![]() |
27.1 | 6 | |
![]() |
131.2 | 7 | The **"Livetable"** component is a dynamic table loading data lazily using ajax requests as the user browse the table, in order to scale easily the display of very large amounts of data. Users can browse the table thanks to a pagination system. Filters on columns are available to search for specific entries. Columns can be made sortable in both direction. For a demonstration of the main capabilities, check out the [[XWiki livetable component video>>http://vimeo.com/4474332]]. |
![]() |
65.1 | 8 | |
![]() |
134.3 | 9 | = How to use = |
![]() |
27.1 | 10 | |
![]() |
138.3 | 11 | The Livetable component is made available in several ways to [[Extensions>>extensions:Main.WebHome]] developers and developers of the [[XWiki platform and products>>dev:Main.WebHome]], depending on their specific needs. The simplest and most of the times preferred way to embed a Livetable component is to use the ##livetable## velocity macro, available in all pages of your wiki. With only one call to this macro you will be able to display a Livetable of the data of your choice! For more specific needs, in the cases you need more control on the table behavior or to build another component on top of the Livetable, it is possible to instantiate the Livetable from JavaScript. In this case you, as opposed to the velocity macro, will need to construct the HTML elements yourself that the JavaScript component expects, either from JavaScript or writing the [[HTML directly in your wiki page>>xwiki:Documentation.UserGuide.Features.XWikiSyntax]]. |
![]() |
27.1 | 12 | |
![]() |
134.3 | 13 | == Using the Velocity Livetable macro == |
![]() |
27.1 | 14 | |
![]() |
131.2 | 15 | Please refer to [[XWiki Livetable Macro>>extensions:Extension.Livetable Macro]] reference. |
![]() |
27.1 | 16 | |
![]() |
134.3 | 17 | == HTML + JavaScript == |
![]() |
27.1 | 18 | |
![]() |
134.3 | 19 | This is a dynamic component which must be used carefully because of performance issues. The HTML content of the Livetable is automatically updated using Javascript and [[JSON>>http://www.json.org]] code generated with the [[Livetable Macro>>extensions:Extension.Livetable Macro]]. |
![]() |
131.2 | 20 | The Livetable component is build using the Prototype library as a class representing an AJAX-populated Livetable: |
![]() |
134.3 | 21 | |
![]() |
136.1 | 22 | * The default variable name generated in XWiki is **livetable** and you can use it, for example to manipulate the display of the component's rows by calling ##livetable.showRows()## or to refresh it ##livetable.refresh()##(older versions of the livetable use the default variable name **ta**). |
![]() |
135.1 | 23 | {{comment}}FIXME: Page has been moved/removed. |
24 | * Take a look at the [[code snippet>>extensions:Extension.Refresh Livetable With Changed URL]] for refreshing the Livetable.{{/comment}} | ||
![]() |
138.1 | 25 | * For more details, check the Javascript file **livetable.js** [[on your wiki>>http://localhost:8080/xwiki/bin/skin/resources/js/xwiki/table/livetable.js]] or {{scm path="xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/js/xwiki/table/livetable.js"}}on GitHub{{/scm}}. |
![]() |
27.1 | 26 | |
![]() |
134.3 | 27 | == Example == |
![]() |
123.1 | 28 | |
![]() |
134.3 | 29 | {{warning}} |
30 | You need the [[Ratings Application>>extensions:Extension.Ratings Application]] in your wiki to make the most of the example below. | ||
31 | {{/warning}} | ||
![]() |
103.1 | 32 | |
![]() |
131.2 | 33 | The Livetable component could be extended with a special column containing the ratings of some documents from the wiki. |
34 | The first step would be to generate the JSON code of the column we want to add. In order to achieve this goal we need to modify the result page of the velocity Livetable macro with our custom page **TutorialsCode.LiveTableRatings**: | ||
![]() |
32.1 | 35 | |
![]() |
125.2 | 36 | {{code language="none"}} |
![]() |
55.1 | 37 | #set($collist = ["doc.name", "_ratings", "doc.date", "doc.author", "_actions"]) |
![]() |
57.1 | 38 | #set($colprops = { |
![]() |
32.1 | 39 | "doc.name" : { "type" : "text" , "size" : 30, "sortable":true, "filterable":true}, |
40 | "_ratings" : { "sortable":false}, | ||
41 | "doc.date" : { "type" : "date" }, | ||
42 | "doc.author" : { "type" : "text", "link" : "author"}, | ||
![]() |
51.1 | 43 | "_actions" : { "actions": ["copy","delete","rename","rights"]} |
![]() |
57.1 | 44 | }) |
45 | #set($options = { "resultPage":"TutorialsCode.LiveTableRatings", | ||
46 | "tagCloud" : true, | ||
47 | "translationPrefix" : "xe.index.", | ||
48 | "rowCount": 10 }) | ||
49 | #set($ok = $xwiki.ssx.use("TutorialsCode.LiveTableRatings")) | ||
50 | #set($ok = $xwiki.jsx.use("TutorialsCode.LiveTableRatings")) | ||
![]() |
122.1 | 51 | #livetable("alldocs" $collist $colprops $options) |
![]() |
58.1 | 52 | {{/code}} |
![]() |
32.1 | 53 | |
![]() |
125.2 | 54 | If we want to display the rated documents from a certain space, e.g. **Tutorials**, the last parameter of the ###gridresultwithfilter## must contain the query we need. |
![]() |
34.1 | 55 | |
![]() |
125.2 | 56 | {{code language="none"}} |
![]() |
34.1 | 57 | #includeMacros("TutorialsCode.LiveTableResultsMacros") |
![]() |
59.1 | 58 | |
![]() |
126.1 | 59 | #gridresultwithfilter("" $request.collist.split(",") "" "and doc.space='Tutorials' and doc.name<>'WebHome' and doc.name<>'WebPreferences'") |
![]() |
60.1 | 60 | {{/code}} |
![]() |
73.1 | 61 | |
![]() |
131.2 | 62 | The page at **TutorialsCode.LiveTableResultsMacros** should contain a copy of the default code (the page is located at **XWiki.LiveTableResultsMacro**) for the Livetable result page. The next step implies extracting the rating information from the wiki pages located the **Tutorials** space. We add a new velocity macro which will test the presence of the rating object with class **XWiki.AverageRatingsClass** and extract the rating value. |
![]() |
90.1 | 63 | |
![]() |
125.2 | 64 | {{code language="none"}} |
![]() |
81.1 | 65 | ## |
66 | ## list ratings | ||
67 | ## | ||
![]() |
73.1 | 68 | #macro(grid_ratings $udoc) |
69 | #set($ratings = "") | ||
70 | #set($ratingObj = "") | ||
71 | #set($ratingObj = $udoc.getObject("XWiki.AverageRatingsClass")) | ||
72 | #if("$!ratingObj" != "") | ||
73 | #set($ratings = $ratingObj.get("averagevote")) | ||
74 | #end | ||
75 | #end | ||
![]() |
74.1 | 76 | {{/code}} |
![]() |
90.1 | 77 | |
![]() |
134.3 | 78 | To continue our extension of this component, we need to add a test for the presence of our custom column to call the ##grid_ratings## macro when generating the JSON: |
![]() |
93.1 | 79 | |
![]() |
125.2 | 80 | {{code language="none"}} |
![]() |
75.1 | 81 | ... |
![]() |
134.2 | 82 | #elseif($colname == '_images') , |
83 | #livetable_getImagesList($itemDoc) | ||
84 | "$escapetool.javascript(${colname})" : "$escapetool.javascript(${imagesList})" | ||
![]() |
75.1 | 85 | #elseif($colname=="_ratings"), |
![]() |
134.2 | 86 | #grid_ratings($itemDoc) |
![]() |
75.1 | 87 | "${colname}" : "${ratings}" |
![]() |
79.1 | 88 | #else , |
![]() |
75.1 | 89 | ... |
90 | {{/code}} | ||
![]() |
87.1 | 91 | |
![]() |
134.3 | 92 | {{info}} |
93 | Firebug can be a useful tool when testing the JSON code generated. | ||
94 | {{/info}} | ||
![]() |
134.2 | 95 | |
![]() |
107.1 | 96 | Transforming the rating information to a nice star display requires using Javascript to replace the content of that column with the proper HTML. Attach the image below to your **TutorialsCode.LiveTableRatings** page to change the default white background when hovering on the stars. |
![]() |
75.1 | 97 | |
![]() |
138.1 | 98 | [[image:star-table.gif||style="margin-right:1em"]] |
![]() |
108.1 | 99 | |
![]() |
107.1 | 100 | Add an on-demand Javascript Extension with a content which can be parsed and use the code below to enrich your component: |
101 | |||
![]() |
125.2 | 102 | {{code language="javascript"}} |
![]() |
131.2 | 103 | /** Display ratings in the Livetable on row event */ |
![]() |
98.1 | 104 | document.observe("xwiki:livetable:newrow", function(ev) { |
105 | $$('._ratings').each(function (el) { | ||
106 | // update content | ||
107 | var avgvote = 0.0; | ||
108 | if (el.innerHTML !== "") { | ||
109 | avgvote = parseFloat(el.innerHTML); | ||
110 | } | ||
111 | var wstyle = 0; | ||
112 | if (avgvote > 0) { | ||
113 | wstyle = avgvote * 20; | ||
114 | el.innerHTML="<div class='avg-rating'><div class='rating-stars'><ul class='small-star-rating'><li style='width: " + wstyle +"%;' class='current-rating'/><li><a class='one-star' href='#' onclick='return false;'>1</a></li><li><a class='two-stars' href='#' onclick='return false;'>2</a></li><li><a class='three-stars' href='#' onclick='return false;'>3</a></li><li><a class='four-stars' href='#' onclick='return false;'>4</a></li><li><a class='five-stars' href='#' onclick='return false;'>5</a></li></ul></div></div>"; | ||
115 | } else if(el.innerHTML === ""){ | ||
116 | el.innerHTML="<div class='avg-rating'><div class='rating-stars'><ul class='small-star-rating'><li style='width: 0%;' class='current-rating'/><li><a class='one-star' href='#' onclick='return false;'>1</a></li> <li><a class='two-stars' href='#' onclick='return false;'>2</a></li><li><a class='three-stars' href='#' onclick='return false;'>3</a></li><li><a class='four-stars' href='#' onclick='return false;'>4</a></li><li><a class='five-stars' href='#' onclick='return false;'>5</a></li></ul></div></div>"; | ||
117 | } | ||
118 | }); | ||
119 | document.fire("xwiki:livetable:ready", { | ||
120 | }); | ||
121 | }); | ||
122 | /** Update ratings images on hover event aka mouse over and mouse out.*/ | ||
123 | document.observe("xwiki:livetable:ready", function(levent) { | ||
124 | $$('.xwiki-livetable-display-body tr').each(function (elem) { | ||
125 | Event.observe(elem, 'mouseover', function (ev) { | ||
126 | var ratings = elem.down('._ratings'); | ||
127 | if(ratings) { | ||
128 | // update default white stars background | ||
129 | var elt = ratings.down(2); | ||
130 | elt.setStyle({ | ||
131 | backgroundImage: 'url($xwiki.getDocument("TutorialsCode.LiveTableRatings").getAttachmentURL("star-table.gif"))', | ||
132 | backgroundPosition: '0% 0%' | ||
133 | }); | ||
134 | // update votes background | ||
135 | elt = ratings.down(3); | ||
136 | elt.setStyle({ | ||
137 | backgroundImage: 'url($xwiki.getDocument("TutorialsCode.LiveTableRatings").getAttachmentURL("star-table.gif"))', | ||
138 | backgroundPosition: '0% 50%' | ||
139 | }); | ||
140 | } | ||
141 | }); | ||
142 | Event.observe(elem, 'mouseout', function (ev) { | ||
143 | var ratings = elem.down('._ratings'); | ||
144 | if(ratings) { | ||
145 | // restore default white stars background | ||
146 | var elt = ratings.down(2); | ||
147 | elt.setStyle({ | ||
148 | backgroundImage: 'url($xwiki.getDocument("XWiki.Ratings").getAttachmentURL("star.gif"))', | ||
149 | backgroundPosition: '0% 0%' | ||
150 | }); | ||
151 | // restore votes background | ||
152 | elt = elem.down('._ratings').down(3); | ||
153 | elt.setStyle({ | ||
154 | backgroundImage: 'url($xwiki.getDocument("XWiki.Ratings").getAttachmentURL("star.gif"))', | ||
155 | backgroundPosition: '0% 50%' | ||
156 | }); | ||
157 | } | ||
158 | }); | ||
![]() |
75.1 | 159 | |
![]() |
98.1 | 160 | }); |
161 | }); | ||
162 | {{/code}} | ||
163 | |||
![]() |
110.1 | 164 | Also, add some CSS in an on-demand Stylesheet extension with a content which can be parsed to polish the custom column display: |
![]() |
121.2 | 165 | |
![]() |
125.2 | 166 | {{code language="none"}} |
![]() |
131.2 | 167 | /* ratings for Livetable */ |
![]() |
98.1 | 168 | .small-star-rating, |
169 | .small-star-rating .current-rating { | ||
170 | background: url($xwiki.getDocument("XWiki.Ratings").getAttachmentURL("star.gif")) left -1000px repeat-x; | ||
171 | } | ||
172 | .small-star-rating{ | ||
173 | position:relative; | ||
174 | width:125px; | ||
175 | height:25px; | ||
176 | overflow:hidden; | ||
177 | list-style:none; | ||
178 | margin:0px !important; | ||
179 | padding:0px !important; | ||
180 | background-position: left top; | ||
181 | } | ||
182 | .small-star-rating li{ | ||
183 | display: inline; | ||
184 | } | ||
185 | .small-star-rating a, | ||
186 | .small-star-rating .current-rating{ | ||
187 | position:absolute; | ||
188 | top:0; | ||
189 | left:0; | ||
190 | text-indent:-1000em; | ||
191 | height:25px; | ||
192 | line-height:25px; | ||
193 | outline:none; | ||
194 | overflow:hidden; | ||
195 | border: none; | ||
196 | } | ||
197 | .small-star-rating .current-rating{ | ||
198 | z-index:1; | ||
199 | background-position: left center; | ||
200 | } | ||
201 | .small-star-rating:hover, | ||
202 | .small-star-rating:active, | ||
203 | .small-star-rating:focus { | ||
204 | background-image: url($xwiki.getDocument("TutorialsCode.LiveTableRatings").getAttachmentURL("star-table.gif")); | ||
205 | background-repeat: repeat-x; | ||
206 | background-position: top left; | ||
207 | } | ||
208 | .small-star-rating a.one-star{ | ||
209 | width:20%; | ||
210 | z-index:6; | ||
211 | } | ||
212 | .small-star-rating a.two-stars{ | ||
213 | width:40%; | ||
214 | z-index:5; | ||
215 | } | ||
216 | .small-star-rating a.three-stars{ | ||
217 | width:60%; | ||
218 | z-index:4; | ||
219 | } | ||
220 | .small-star-rating a.four-stars{ | ||
221 | width:80%; | ||
222 | z-index:3; | ||
223 | } | ||
224 | .small-star-rating a.five-stars{ | ||
225 | width:100%; | ||
226 | z-index:2; | ||
227 | } | ||
228 | .rating-stars { | ||
229 | display: inline; | ||
230 | float: left; | ||
231 | clear: none; | ||
232 | } | ||
233 | {{/code}} | ||
![]() |
111.1 | 234 | |
235 | The final result should look like this: | ||
![]() |
114.1 | 236 | |
![]() |
138.1 | 237 | [[image:livetabel.png||style="margin-right:1em"]] |