liquid_feedback_frontend
view app/main/vote/list.lua @ 522:a930d2ab9e76
Fixed error in fixed voting form
author | bsw |
---|---|
date | Mon Apr 16 23:47:55 2012 +0200 (2012-04-16) |
parents | 7492497005bd |
children | c4144daf6906 |
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
8 if member_id then
9 if not issue.closed then
10 error("access denied")
11 end
12 member = Member:by_id(member_id)
13 readonly = true
14 end
16 if issue.closed then
17 if not member then
18 slot.put_into("error", _"This issue is already closed.")
19 end
20 if not member then
21 member = app.session.member
22 end
23 readonly = true
24 end
26 if member then
27 local str = _("Ballot of '#{member_name}' for issue ##{issue_id}",
28 {member_name = string.format('<a href="%s">%s</a>',
29 encode.url{
30 module = "member",
31 view = "show",
32 id = member.id,
33 },
34 encode.html(member.name)),
35 issue_id = string.format('<a href="%s">%s</a>',
36 encode.url{
37 module = "issue",
38 view = "show",
39 id = issue.id,
40 },
41 encode.html(tostring(issue.id)))
42 }
43 )
44 slot.put_into("title", str)
45 else
46 member = app.session.member
47 slot.put_into("title", _"Voting")
49 slot.select("actions", function()
50 ui.link{
51 content = function()
52 ui.image{ static = "icons/16/cancel.png" }
53 slot.put(_"Cancel")
54 end,
55 module = "issue",
56 view = "show",
57 id = issue.id
58 }
59 ui.link{
60 text = _"Discard voting",
61 content = function()
62 ui.image{ static = "icons/16/email_delete.png" }
63 slot.put(_"Discard voting")
64 end,
65 module = "vote",
66 action = "update",
67 params = {
68 issue_id = issue.id,
69 discard = true
70 },
71 routing = {
72 default = {
73 mode = "redirect",
74 module = "issue",
75 view = "show",
76 id = issue.id
77 }
78 }
79 }
80 end)
81 end
84 local tempvoting_string = param.get("scoring")
86 local tempvotings = {}
87 if tempvoting_string then
88 for match in tempvoting_string:gmatch("([^;]+)") do
89 for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
90 tempvotings[tonumber(initiative_id)] = tonumber(grade)
91 end
92 end
93 end
95 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
97 local min_grade = -1;
98 local max_grade = 1;
100 for i, initiative in ipairs(initiatives) do
101 -- TODO performance
102 initiative.vote = Vote:by_pk(initiative.id, member.id)
103 if tempvotings[initiative.id] then
104 initiative.vote = {}
105 initiative.vote.grade = tempvotings[initiative.id]
106 end
107 if initiative.vote then
108 if initiative.vote.grade > max_grade then
109 max_grade = initiative.vote.grade
110 end
111 if initiative.vote.grade < min_grade then
112 min_grade = initiative.vote.grade
113 end
114 end
115 end
117 local sections = {}
118 for i = min_grade, max_grade do
119 sections[i] = {}
120 for j, initiative in ipairs(initiatives) do
121 if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
122 sections[i][#(sections[i])+1] = initiative
123 end
124 end
125 end
127 local approval_count, disapproval_count = 0, 0
128 for i = min_grade, -1 do
129 if #sections[i] > 0 then
130 disapproval_count = disapproval_count + 1
131 end
132 end
133 local approval_count = 0
134 for i = 1, max_grade do
135 if #sections[i] > 0 then
136 approval_count = approval_count + 1
137 end
138 end
142 if not readonly then
143 util.help("vote.list", _"Voting")
144 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
145 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
146 end
148 ui.script{
149 script = function()
150 slot.put(
151 "voting_text_approval_single = ", encode.json(_"Approval [single entry]"), ";\n",
152 "voting_text_approval_multi = ", encode.json(_"Approval [many entries]"), ";\n",
153 "voting_text_first_preference_single = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
154 "voting_text_first_preference_multi = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
155 "voting_text_second_preference_single = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
156 "voting_text_second_preference_multi = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
157 "voting_text_third_preference_single = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
158 "voting_text_third_preference_multi = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
159 "voting_text_numeric_preference_single = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
160 "voting_text_numeric_preference_multi = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
161 "voting_text_abstention_single = ", encode.json(_"Abstention [single entry]"), ";\n",
162 "voting_text_abstention_multi = ", encode.json(_"Abstention [many entries]"), ";\n",
163 "voting_text_disapproval_above_one_single = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
164 "voting_text_disapproval_above_one_multi = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
165 "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
166 "voting_text_disapproval_above_many_multi = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
167 "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
168 "voting_text_disapproval_above_last_multi = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
169 "voting_text_disapproval_single = ", encode.json(_"Disapproval [single entry]"), ";\n",
170 "voting_text_disapproval_multi = ", encode.json(_"Disapproval [many entries]"), ";\n"
171 )
172 end
173 }
175 ui.form{
176 attr = {
177 id = "voting_form",
178 class = readonly and "voting_form_readonly" or "voting_form_active"
179 },
180 module = "vote",
181 action = "update",
182 params = { issue_id = issue.id },
183 routing = {
184 default = {
185 mode = "redirect",
186 module = "issue",
187 view = "show",
188 id = issue.id
189 }
190 },
191 content = function()
192 if not readonly then
193 local scoring = param.get("scoring")
194 if not scoring then
195 for i, initiative in ipairs(initiatives) do
196 local vote = initiative.vote
197 if vote then
198 tempvotings[initiative.id] = vote.grade
199 else
200 tempvotings[initiative.id] = 0
201 end
202 end
203 local tempvotings_list = {}
204 for key, val in pairs(tempvotings) do
205 tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
206 end
207 if #tempvotings_list > 0 then
208 scoring = table.concat(tempvotings_list, ";")
209 else
210 scoring = ""
211 end
212 end
213 slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
214 -- TODO abstrahieren
215 ui.tag{
216 tag = "input",
217 attr = {
218 type = "submit",
219 class = "voting_done",
220 value = _"Finish voting"
221 }
222 }
223 end
224 ui.container{
225 attr = { id = "voting" },
226 content = function()
227 local approval_index, disapproval_index = 0, 0
228 for grade = max_grade, min_grade, -1 do
229 local entries = sections[grade]
230 local class
231 if grade > 0 then
232 class = "approval"
233 elseif grade < 0 then
234 class = "disapproval"
235 else
236 class = "abstention"
237 end
238 if
239 #entries > 0 or
240 (grade == 1 and not approval_used) or
241 (grade == -1 and not disapproval_used) or
242 grade == 0
243 then
244 ui.container{
245 attr = { class = class },
246 content = function()
247 local heading
248 if class == "approval" then
249 approval_used = true
250 approval_index = approval_index + 1
251 if approval_count > 1 then
252 if approval_index == 1 then
253 if #entries == 1 then
254 heading = _"Approval (first preference) [single entry]"
255 else
256 heading = _"Approval (first preference) [many entries]"
257 end
258 elseif approval_index == 2 then
259 if #entries == 1 then
260 heading = _"Approval (second preference) [single entry]"
261 else
262 heading = _"Approval (second preference) [many entries]"
263 end
264 elseif approval_index == 3 then
265 if #entries == 1 then
266 heading = _"Approval (third preference) [single entry]"
267 else
268 heading = _"Approval (third preference) [many entries]"
269 end
270 else
271 if #entries == 1 then
272 heading = _"Approval (#th preference) [single entry]"
273 else
274 heading = _"Approval (#th preference) [many entries]"
275 end
276 end
277 else
278 if #entries == 1 then
279 heading = _"Approval [single entry]"
280 else
281 heading = _"Approval [many entries]"
282 end
283 end
284 elseif class == "abstention" then
285 if #entries == 1 then
286 heading = _"Abstention [single entry]"
287 else
288 heading = _"Abstention [many entries]"
289 end
290 elseif class == "disapproval" then
291 disapproval_used = true
292 disapproval_index = disapproval_index + 1
293 if disapproval_count > disapproval_index + 1 then
294 if #entries == 1 then
295 heading = _"Disapproval (prefer to lower blocks) [single entry]"
296 else
297 heading = _"Disapproval (prefer to lower blocks) [many entries]"
298 end
299 elseif disapproval_count == 2 and disapproval_index == 1 then
300 if #entries == 1 then
301 heading = _"Disapproval (prefer to lower block) [single entry]"
302 else
303 heading = _"Disapproval (prefer to lower block) [many entries]"
304 end
305 elseif disapproval_index == disapproval_count - 1 then
306 if #entries == 1 then
307 heading = _"Disapproval (prefer to last block) [single entry]"
308 else
309 heading = _"Disapproval (prefer to last block) [many entries]"
310 end
311 else
312 if #entries == 1 then
313 heading = _"Disapproval [single entry]"
314 else
315 heading = _"Disapproval [many entries]"
316 end
317 end
318 end
319 ui.tag {
320 tag = "div",
321 attr = { class = "cathead" },
322 content = heading
323 }
324 for i, initiative in ipairs(entries) do
325 ui.container{
326 attr = {
327 class = "movable",
328 id = "entry_" .. tostring(initiative.id)
329 },
330 content = function()
331 local initiators_selector = initiative:get_reference_selector("initiating_members")
332 :add_where("accepted")
333 local initiators = initiators_selector:exec()
334 local initiator_names = {}
335 for i, initiator in ipairs(initiators) do
336 initiator_names[#initiator_names+1] = initiator.name
337 end
338 local initiator_names_string = table.concat(initiator_names, ", ")
339 ui.container{
340 attr = { style = "float: right; position: relative;" },
341 content = function()
342 ui.link{
343 attr = { class = "clickable" },
344 content = _"Show",
345 module = "initiative",
346 view = "show",
347 id = initiative.id
348 }
349 slot.put(" ")
350 ui.link{
351 attr = { class = "clickable", target = "_blank" },
352 content = _"(new window)",
353 module = "initiative",
354 view = "show",
355 id = initiative.id
356 }
357 if not readonly then
358 slot.put(" ")
359 ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
360 end
361 end
362 }
363 if not readonly then
364 ui.container{
365 attr = { style = "float: left; position: relative;" },
366 content = function()
367 ui.tag{
368 tag = "input",
369 attr = {
370 onclick = "if (jsFail) return true; voting_moveUp(this.parentNode.parentNode); return(false);",
371 name = "move_up_" .. tostring(initiative.id),
372 class = not disabled and "clickable" or nil,
373 type = "image",
374 src = encode.url{ static = "icons/move_up.png" },
375 alt = _"Move up"
376 }
377 }
378 slot.put(" ")
379 ui.tag{
380 tag = "input",
381 attr = {
382 onclick = "if (jsFail) return true; voting_moveDown(this.parentNode.parentNode); return(false);",
383 name = "move_down_" .. tostring(initiative.id),
384 class = not disabled and "clickable" or nil,
385 type = "image",
386 src = encode.url{ static = "icons/move_down.png" },
387 alt = _"Move down"
388 }
389 }
390 slot.put(" ")
391 end
392 }
393 end
394 ui.container{
395 content = function()
396 ui.tag{ content = "i" .. initiative.id .. ": " }
397 ui.tag{ content = initiative.shortened_name }
398 slot.put("<br />")
399 for i, initiator in ipairs(initiators) do
400 ui.link{
401 attr = { class = "clickable" },
402 content = function ()
403 execute.view{
404 module = "member_image",
405 view = "_show",
406 params = {
407 member = initiator,
408 image_type = "avatar",
409 show_dummy = true,
410 class = "micro_avatar",
411 popup_text = text
412 }
413 }
414 end,
415 module = "member", view = "show", id = initiator.id
416 }
417 slot.put(" ")
418 ui.tag{ content = initiator.name }
419 slot.put(" ")
420 end
421 end
422 }
423 end
424 }
425 end
426 end
427 }
428 end
429 end
430 end
431 }
432 if not readonly then
433 ui.tag{
434 tag = "input",
435 attr = {
436 type = "submit",
437 class = "voting_done",
438 value = _"Finish voting"
439 }
440 }
441 end
442 end
443 }