liquid_feedback_frontend

view app/main/vote/list.lua @ 130:e1b916d2e489

better feedback on content_navigation links
author Daniel Poelzleithner <poelzi@poelzi.org>
date Tue Oct 05 05:42:20 2010 +0200 (2010-10-05)
parents 6a12fb7e4963
children 7e7d629390d5
line source
1 local issue = Issue:by_id(param.get("issue_id"), atom.integer)
3 local member_id = param.get("member_id", atom.integer)
4 local member
6 local readonly = false
7 if member_id then
8 if not issue.closed then
9 error("access denied")
10 end
11 member = Member:by_id(member_id)
12 readonly = true
13 end
15 if member then
16 slot.put_into("title", _("Ballot of '#{member_name}' for issue ##{issue_id}", {
17 member_name = member.name,
18 issue_id = issue.id
19 }))
20 else
21 member = app.session.member
22 slot.put_into("title", _"Voting")
24 slot.select("actions", function()
25 ui.link{
26 content = function()
27 ui.image{ static = "icons/16/cancel.png" }
28 slot.put(_"Cancel")
29 end,
30 module = "issue",
31 view = "show",
32 id = issue.id
33 }
34 ui.link{
35 text = _"Discard voting",
36 content = function()
37 ui.image{ static = "icons/16/email_delete.png" }
38 slot.put(_"Discard voting")
39 end,
40 module = "vote",
41 action = "update",
42 params = {
43 issue_id = issue.id,
44 discard = true
45 },
46 routing = {
47 default = {
48 mode = "redirect",
49 module = "issue",
50 view = "show",
51 id = issue.id
52 }
53 }
54 }
55 end)
56 end
59 local warning_text = _"Some JavaScript based functions (voting in particular) will not work.\nFor this beta, please use a current version of Firefox, Safari, Opera(?), Konqueror or another (more) standard compliant browser.\nAlternative access without JavaScript will be available soon."
61 ui.script{ static = "js/browser_warning.js" }
62 ui.script{ script = "checkBrowser(" .. encode.json(_"Your web browser is not fully supported yet." .. " " .. warning_text:gsub("\n", "\n\n")) .. ");" }
65 local tempvoting_string = param.get("scoring")
67 local tempvotings = {}
68 if tempvoting_string then
69 for match in tempvoting_string:gmatch("([^;]+)") do
70 for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
71 tempvotings[tonumber(initiative_id)] = tonumber(grade)
72 end
73 end
74 end
76 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
78 local min_grade = -1;
79 local max_grade = 1;
81 for i, initiative in ipairs(initiatives) do
82 -- TODO performance
83 initiative.vote = Vote:by_pk(initiative.id, member.id)
84 if tempvotings[initiative.id] then
85 initiative.vote = {}
86 initiative.vote.grade = tempvotings[initiative.id]
87 end
88 if initiative.vote then
89 if initiative.vote.grade > max_grade then
90 max_grade = initiative.vote.grade
91 end
92 if initiative.vote.grade < min_grade then
93 min_grade = initiative.vote.grade
94 end
95 end
96 end
98 local sections = {}
99 for i = min_grade, max_grade do
100 sections[i] = {}
101 for j, initiative in ipairs(initiatives) do
102 if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
103 sections[i][#(sections[i])+1] = initiative
104 end
105 end
106 end
108 local approval_count, disapproval_count = 0, 0
109 for i = min_grade, -1 do
110 if #sections[i] > 0 then
111 disapproval_count = disapproval_count + 1
112 end
113 end
114 local approval_count = 0
115 for i = 1, max_grade do
116 if #sections[i] > 0 then
117 approval_count = approval_count + 1
118 end
119 end
123 if not readonly then
124 util.help("vote.list", _"Voting")
125 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
126 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
127 end
129 ui.script{
130 script = function()
131 slot.put(
132 "voting_text_approval_single = ", encode.json(_"Approval [single entry]"), ";\n",
133 "voting_text_approval_multi = ", encode.json(_"Approval [many entries]"), ";\n",
134 "voting_text_first_preference_single = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
135 "voting_text_first_preference_multi = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
136 "voting_text_second_preference_single = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
137 "voting_text_second_preference_multi = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
138 "voting_text_third_preference_single = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
139 "voting_text_third_preference_multi = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
140 "voting_text_numeric_preference_single = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
141 "voting_text_numeric_preference_multi = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
142 "voting_text_abstention_single = ", encode.json(_"Abstention [single entry]"), ";\n",
143 "voting_text_abstention_multi = ", encode.json(_"Abstention [many entries]"), ";\n",
144 "voting_text_disapproval_above_one_single = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
145 "voting_text_disapproval_above_one_multi = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
146 "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
147 "voting_text_disapproval_above_many_multi = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
148 "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
149 "voting_text_disapproval_above_last_multi = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
150 "voting_text_disapproval_single = ", encode.json(_"Disapproval [single entry]"), ";\n",
151 "voting_text_disapproval_multi = ", encode.json(_"Disapproval [many entries]"), ";\n"
152 )
153 end
154 }
156 ui.form{
157 attr = {
158 id = "voting_form",
159 class = readonly and "voting_form_readonly" or "voting_form_active"
160 },
161 module = "vote",
162 action = "update",
163 params = { issue_id = issue.id },
164 routing = {
165 default = {
166 mode = "redirect",
167 module = "issue",
168 view = "show",
169 id = issue.id
170 }
171 },
172 content = function()
173 if not readonly then
174 local scoring = param.get("scoring")
175 if not scoring then
176 for i, initiative in ipairs(initiatives) do
177 local vote = initiative.vote
178 if vote then
179 tempvotings[initiative.id] = vote.grade
180 end
181 end
182 local tempvotings_list = {}
183 for key, val in pairs(tempvotings) do
184 tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
185 end
186 if #tempvotings_list > 0 then
187 scoring = table.concat(tempvotings_list, ";")
188 else
189 scoring = ""
190 end
191 end
192 slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
193 -- TODO abstrahieren
194 ui.tag{
195 tag = "input",
196 attr = {
197 type = "submit",
198 class = "voting_done",
199 value = _"Finish voting"
200 }
201 }
202 end
203 ui.container{
204 attr = { id = "voting" },
205 content = function()
206 local approval_index, disapproval_index = 0, 0
207 for grade = max_grade, min_grade, -1 do
208 local entries = sections[grade]
209 local class
210 if grade > 0 then
211 class = "approval"
212 elseif grade < 0 then
213 class = "disapproval"
214 else
215 class = "abstention"
216 end
217 if
218 #entries > 0 or
219 (grade == 1 and not approval_used) or
220 (grade == -1 and not disapproval_used) or
221 grade == 0
222 then
223 ui.container{
224 attr = { class = class },
225 content = function()
226 local heading
227 if class == "approval" then
228 approval_used = true
229 approval_index = approval_index + 1
230 if approval_count > 1 then
231 if approval_index == 1 then
232 if #entries == 1 then
233 heading = _"Approval (first preference) [single entry]"
234 else
235 heading = _"Approval (first preference) [many entries]"
236 end
237 elseif approval_index == 2 then
238 if #entries == 1 then
239 heading = _"Approval (second preference) [single entry]"
240 else
241 heading = _"Approval (second preference) [many entries]"
242 end
243 elseif approval_index == 3 then
244 if #entries == 1 then
245 heading = _"Approval (third preference) [single entry]"
246 else
247 heading = _"Approval (third preference) [many entries]"
248 end
249 else
250 if #entries == 1 then
251 heading = _"Approval (#th preference) [single entry]"
252 else
253 heading = _"Approval (#th preference) [many entries]"
254 end
255 end
256 else
257 if #entries == 1 then
258 heading = _"Approval [single entry]"
259 else
260 heading = _"Approval [many entries]"
261 end
262 end
263 elseif class == "abstention" then
264 if #entries == 1 then
265 heading = _"Abstention [single entry]"
266 else
267 heading = _"Abstention [many entries]"
268 end
269 elseif class == "disapproval" then
270 disapproval_used = true
271 disapproval_index = disapproval_index + 1
272 if disapproval_count > disapproval_index + 1 then
273 if #entries == 1 then
274 heading = _"Disapproval (prefer to lower blocks) [single entry]"
275 else
276 heading = _"Disapproval (prefer to lower blocks) [many entries]"
277 end
278 elseif disapproval_count == 2 and disapproval_index == 1 then
279 if #entries == 1 then
280 heading = _"Disapproval (prefer to lower block) [single entry]"
281 else
282 heading = _"Disapproval (prefer to lower block) [many entries]"
283 end
284 elseif disapproval_index == disapproval_count - 1 then
285 if #entries == 1 then
286 heading = _"Disapproval (prefer to last block) [single entry]"
287 else
288 heading = _"Disapproval (prefer to last block) [many entries]"
289 end
290 else
291 if #entries == 1 then
292 heading = _"Disapproval [single entry]"
293 else
294 heading = _"Disapproval [many entries]"
295 end
296 end
297 end
298 ui.tag {
299 tag = "div",
300 attr = { class = "cathead" },
301 content = heading
302 }
303 for i, initiative in ipairs(entries) do
304 ui.container{
305 attr = {
306 class = "movable",
307 id = "entry_" .. tostring(initiative.id)
308 },
309 content = function()
310 local initiators_selector = initiative:get_reference_selector("initiating_members")
311 :add_where("accepted")
312 local initiators = initiators_selector:exec()
313 local initiator_names = {}
314 for i, initiator in ipairs(initiators) do
315 initiator_names[#initiator_names+1] = initiator.name
316 end
317 local initiator_names_string = table.concat(initiator_names, ", ")
318 ui.container{
319 attr = { style = "float: right;" },
320 content = function()
321 ui.link{
322 attr = { class = "clickable" },
323 content = _"Show",
324 module = "initiative",
325 view = "show",
326 id = initiative.id
327 }
328 slot.put(" ")
329 ui.link{
330 attr = { class = "clickable", target = "_blank" },
331 content = _"(new window)",
332 module = "initiative",
333 view = "show",
334 id = initiative.id
335 }
336 if not readonly then
337 slot.put(" ")
338 ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
339 end
340 end
341 }
342 if not readonly then
343 ui.container{
344 attr = { style = "float: left;" },
345 content = function()
346 ui.tag{
347 tag = "input",
348 attr = {
349 onclick = "voting_moveUp(this.parentNode.parentNode); return(false);",
350 name = "move_up",
351 value = initiative.id,
352 class = not disabled and "clickable" or nil,
353 type = "image",
354 src = encode.url{ static = "icons/move_up.png" },
355 alt = _"Move up"
356 }
357 }
358 slot.put("&nbsp;")
359 ui.tag{
360 tag = "input",
361 attr = {
362 onclick = "voting_moveDown(this.parentNode.parentNode); return(false);",
363 name = "move_down",
364 value = initiative.id,
365 class = not disabled and "clickable" or nil,
366 type = "image",
367 src = encode.url{ static = "icons/move_down.png" },
368 alt = _"Move down"
369 }
370 }
371 slot.put("&nbsp;")
372 end
373 }
374 end
375 ui.container{
376 content = function()
377 slot.put(encode.html(initiative.shortened_name))
378 if #initiators > 1 then
379 ui.container{
380 attr = { style = "font-size: 80%;" },
381 content = _"Initiators" .. ": " .. initiator_names_string
382 }
383 else
384 ui.container{
385 attr = { style = "font-size: 80%;" },
386 content = _"Initiator" .. ": " .. initiator_names_string
387 }
388 end
389 end
390 }
391 end
392 }
393 end
394 end
395 }
396 end
397 end
398 end
399 }
400 if not readonly then
401 ui.tag{
402 tag = "input",
403 attr = {
404 type = "submit",
405 class = "voting_done",
406 value = _"Finish voting"
407 }
408 }
409 end
410 end
411 }

Impressum / About Us