liquid_feedback_frontend

view app/main/vote/list.lua @ 885:e81f35cdc088

Fixed error in vote form
author bsw
date Mon Aug 20 02:38:34 2012 +0200 (2012-08-20)
parents 23e12fe721d4
children b865f87ea810
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 preview = param.get("preview") or param.get("preview2") == "1" and true or 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 member = app.session.member
19 end
20 readonly = true
21 end
23 local submit_button_text = _"Finish voting"
25 if issue.closed then
26 submit_button_text = _"Update voting comment"
27 end
29 local direct_voter
31 if member then
32 direct_voter = DirectVoter:by_pk(issue.id, member.id)
33 local str = _("Ballot of '#{member_name}' for issue ##{issue_id}",
34 {member_name = string.format('<a href="%s">%s</a>',
35 encode.url{
36 module = "member",
37 view = "show",
38 id = member.id,
39 },
40 encode.html(member.name)),
41 issue_id = string.format('<a href="%s">%s</a>',
42 encode.url{
43 module = "issue",
44 view = "show",
45 id = issue.id,
46 },
47 encode.html(tostring(issue.id)))
48 }
49 )
50 ui.raw_title(str)
51 else
52 member = app.session.member
54 direct_voter = DirectVoter:by_pk(issue.id, member.id)
56 ui.title(_"Voting")
58 ui.actions(function()
59 ui.link{
60 text = _"Cancel",
61 module = "issue",
62 view = "show",
63 id = issue.id
64 }
65 if direct_voter then
66 slot.put(" &middot; ")
67 ui.link{
68 text = _"Discard voting",
69 module = "vote",
70 action = "update",
71 params = {
72 issue_id = issue.id,
73 discard = true
74 },
75 routing = {
76 default = {
77 mode = "redirect",
78 module = "issue",
79 view = "show",
80 id = issue.id
81 }
82 }
83 }
84 end
85 end)
86 end
90 local tempvoting_string = param.get("scoring")
92 local tempvotings = {}
93 if tempvoting_string then
94 for match in tempvoting_string:gmatch("([^;]+)") do
95 for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do
96 tempvotings[tonumber(initiative_id)] = tonumber(grade)
97 end
98 end
99 end
101 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):add_order_by("initiative.satisfied_supporter_count DESC"):exec()
103 local min_grade = -1;
104 local max_grade = 1;
106 for i, initiative in ipairs(initiatives) do
107 -- TODO performance
108 initiative.vote = Vote:by_pk(initiative.id, member.id)
109 if tempvotings[initiative.id] then
110 initiative.vote = {}
111 initiative.vote.grade = tempvotings[initiative.id]
112 end
113 if initiative.vote then
114 if initiative.vote.grade > max_grade then
115 max_grade = initiative.vote.grade
116 end
117 if initiative.vote.grade < min_grade then
118 min_grade = initiative.vote.grade
119 end
120 end
121 end
123 local sections = {}
124 for i = min_grade, max_grade do
125 sections[i] = {}
126 for j, initiative in ipairs(initiatives) do
127 if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then
128 sections[i][#(sections[i])+1] = initiative
129 end
130 end
131 end
133 local approval_count, disapproval_count = 0, 0
134 for i = min_grade, -1 do
135 if #sections[i] > 0 then
136 disapproval_count = disapproval_count + 1
137 end
138 end
139 local approval_count = 0
140 for i = 1, max_grade do
141 if #sections[i] > 0 then
142 approval_count = approval_count + 1
143 end
144 end
148 if not readonly then
149 util.help("vote.list", _"Voting")
150 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>')
151 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>')
152 end
154 ui.script{
155 script = function()
156 slot.put(
157 "voting_text_approval_single = ", encode.json(_"Approval [single entry]"), ";\n",
158 "voting_text_approval_multi = ", encode.json(_"Approval [many entries]"), ";\n",
159 "voting_text_first_preference_single = ", encode.json(_"Approval (first preference) [single entry]"), ";\n",
160 "voting_text_first_preference_multi = ", encode.json(_"Approval (first preference) [many entries]"), ";\n",
161 "voting_text_second_preference_single = ", encode.json(_"Approval (second preference) [single entry]"), ";\n",
162 "voting_text_second_preference_multi = ", encode.json(_"Approval (second preference) [many entries]"), ";\n",
163 "voting_text_third_preference_single = ", encode.json(_"Approval (third preference) [single entry]"), ";\n",
164 "voting_text_third_preference_multi = ", encode.json(_"Approval (third preference) [many entries]"), ";\n",
165 "voting_text_numeric_preference_single = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n",
166 "voting_text_numeric_preference_multi = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n",
167 "voting_text_abstention_single = ", encode.json(_"Abstention [single entry]"), ";\n",
168 "voting_text_abstention_multi = ", encode.json(_"Abstention [many entries]"), ";\n",
169 "voting_text_disapproval_above_one_single = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n",
170 "voting_text_disapproval_above_one_multi = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n",
171 "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n",
172 "voting_text_disapproval_above_many_multi = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n",
173 "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n",
174 "voting_text_disapproval_above_last_multi = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n",
175 "voting_text_disapproval_single = ", encode.json(_"Disapproval [single entry]"), ";\n",
176 "voting_text_disapproval_multi = ", encode.json(_"Disapproval [many entries]"), ";\n"
177 )
178 end
179 }
181 ui.form{
182 record = direct_voter,
183 attr = {
184 id = "voting_form",
185 class = readonly and "voting_form_readonly" or "voting_form_active"
186 },
187 module = "vote",
188 action = "update",
189 params = { issue_id = issue.id },
190 content = function()
191 if not readonly or preview then
192 local scoring = param.get("scoring")
193 if not scoring then
194 for i, initiative in ipairs(initiatives) do
195 local vote = initiative.vote
196 if vote then
197 tempvotings[initiative.id] = vote.grade
198 else
199 tempvotings[initiative.id] = 0
200 end
201 end
202 local tempvotings_list = {}
203 for key, val in pairs(tempvotings) do
204 tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val)
205 end
206 if #tempvotings_list > 0 then
207 scoring = table.concat(tempvotings_list, ";")
208 else
209 scoring = ""
210 end
211 end
212 slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>')
213 -- TODO abstrahieren
214 ui.tag{
215 tag = "input",
216 attr = {
217 type = "submit",
218 class = "voting_done1",
219 value = submit_button_text
220 }
221 }
222 end
223 ui.container{
224 attr = { id = "voting" },
225 content = function()
226 local approval_index, disapproval_index = 0, 0
227 for grade = max_grade, min_grade, -1 do
228 local entries = sections[grade]
229 local class
230 if grade > 0 then
231 class = "approval"
232 elseif grade < 0 then
233 class = "disapproval"
234 else
235 class = "abstention"
236 end
237 if
238 #entries > 0 or
239 (grade == 1 and not approval_used) or
240 (grade == -1 and not disapproval_used) or
241 grade == 0
242 then
243 ui.container{
244 attr = { class = class },
245 content = function()
246 local heading
247 if class == "approval" then
248 approval_used = true
249 approval_index = approval_index + 1
250 if approval_count > 1 then
251 if approval_index == 1 then
252 if #entries == 1 then
253 heading = _"Approval (first preference) [single entry]"
254 else
255 heading = _"Approval (first preference) [many entries]"
256 end
257 elseif approval_index == 2 then
258 if #entries == 1 then
259 heading = _"Approval (second preference) [single entry]"
260 else
261 heading = _"Approval (second preference) [many entries]"
262 end
263 elseif approval_index == 3 then
264 if #entries == 1 then
265 heading = _"Approval (third preference) [single entry]"
266 else
267 heading = _"Approval (third preference) [many entries]"
268 end
269 else
270 if #entries == 1 then
271 heading = _"Approval (#th preference) [single entry]"
272 else
273 heading = _"Approval (#th preference) [many entries]"
274 end
275 end
276 else
277 if #entries == 1 then
278 heading = _"Approval [single entry]"
279 else
280 heading = _"Approval [many entries]"
281 end
282 end
283 elseif class == "abstention" then
284 if #entries == 1 then
285 heading = _"Abstention [single entry]"
286 else
287 heading = _"Abstention [many entries]"
288 end
289 elseif class == "disapproval" then
290 disapproval_used = true
291 disapproval_index = disapproval_index + 1
292 if disapproval_count > disapproval_index + 1 then
293 if #entries == 1 then
294 heading = _"Disapproval (prefer to lower blocks) [single entry]"
295 else
296 heading = _"Disapproval (prefer to lower blocks) [many entries]"
297 end
298 elseif disapproval_count == 2 and disapproval_index == 1 then
299 if #entries == 1 then
300 heading = _"Disapproval (prefer to lower block) [single entry]"
301 else
302 heading = _"Disapproval (prefer to lower block) [many entries]"
303 end
304 elseif disapproval_index == disapproval_count - 1 then
305 if #entries == 1 then
306 heading = _"Disapproval (prefer to last block) [single entry]"
307 else
308 heading = _"Disapproval (prefer to last block) [many entries]"
309 end
310 else
311 if #entries == 1 then
312 heading = _"Disapproval [single entry]"
313 else
314 heading = _"Disapproval [many entries]"
315 end
316 end
317 end
318 ui.tag {
319 tag = "div",
320 attr = { class = "cathead" },
321 content = heading
322 }
323 for i, initiative in ipairs(entries) do
324 ui.container{
325 attr = {
326 class = "movable",
327 id = "entry_" .. tostring(initiative.id)
328 },
329 content = function()
330 local initiators_selector = initiative:get_reference_selector("initiating_members")
331 :add_where("accepted")
332 local initiators = initiators_selector:exec()
333 local initiator_names = {}
334 for i, initiator in ipairs(initiators) do
335 initiator_names[#initiator_names+1] = initiator.name
336 end
337 local initiator_names_string = table.concat(initiator_names, ", ")
338 ui.container{
339 attr = { style = "float: right; position: relative;" },
340 content = function()
341 ui.link{
342 attr = { class = "clickable" },
343 content = _"Show",
344 module = "initiative",
345 view = "show",
346 id = initiative.id
347 }
348 slot.put(" ")
349 ui.link{
350 attr = { class = "clickable", target = "_blank" },
351 content = _"(new window)",
352 module = "initiative",
353 view = "show",
354 id = initiative.id
355 }
356 if not readonly then
357 slot.put(" ")
358 ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" }
359 end
360 end
361 }
362 if not readonly then
363 ui.container{
364 attr = { style = "float: left; position: relative;" },
365 content = function()
366 ui.tag{
367 tag = "input",
368 attr = {
369 onclick = "if (jsFail) return true; voting_moveUp(this.parentNode.parentNode); return(false);",
370 name = "move_up_" .. tostring(initiative.id),
371 class = not disabled and "clickable" or nil,
372 type = "image",
373 src = encode.url{ static = "icons/move_up.png" },
374 alt = _"Move up"
375 }
376 }
377 slot.put("&nbsp;")
378 ui.tag{
379 tag = "input",
380 attr = {
381 onclick = "if (jsFail) return true; voting_moveDown(this.parentNode.parentNode); return(false);",
382 name = "move_down_" .. tostring(initiative.id),
383 class = not disabled and "clickable" or nil,
384 type = "image",
385 src = encode.url{ static = "icons/move_down.png" },
386 alt = _"Move down"
387 }
388 }
389 slot.put("&nbsp;")
390 end
391 }
392 end
393 ui.container{
394 content = function()
395 ui.tag{ content = "i" .. initiative.id .. ": " }
396 ui.tag{ content = initiative.shortened_name }
397 slot.put("<br />")
398 for i, initiator in ipairs(initiators) do
399 ui.link{
400 attr = { class = "clickable" },
401 content = function ()
402 execute.view{
403 module = "member_image",
404 view = "_show",
405 params = {
406 member = initiator,
407 image_type = "avatar",
408 show_dummy = true,
409 class = "micro_avatar",
410 popup_text = text
411 }
412 }
413 end,
414 module = "member", view = "show", id = initiator.id
415 }
416 slot.put(" ")
417 ui.tag{ content = initiator.name }
418 slot.put(" ")
419 end
420 end
421 }
422 end
423 }
424 end
425 end
426 }
427 end
428 end
429 end
430 }
431 if app.session.member_id and preview then
432 local formatting_engine = param.get("formatting_engine")
433 local comment = param.get("comment")
434 local rendered_comment = format.wiki_text(comment, formatting_engine)
435 slot.put(rendered_comment)
436 end
437 if (readonly or direct_voter and direct_voter.comment) and not preview then
438 local text
439 if direct_voter and direct_voter.comment_changed then
440 text = _("Voting comment (last updated: #{timestamp})", { timestamp = format.timestamp(direct_voter.comment_changed) })
441 elseif direct_voter and direct_voter.comment then
442 text = _"Voting comment"
443 end
444 if text then
445 ui.heading{ level = "2", content = text }
446 end
447 if direct_voter and direct_voter.comment then
448 local rendered_comment = direct_voter:get_content('html')
449 ui.container{ attr = { class = "member_statement" }, content = function()
450 slot.put(rendered_comment)
451 end }
452 slot.put("<br />")
453 end
454 end
455 if app.session.member_id and app.session.member_id == member.id then
456 if not readonly or direct_voter then
457 ui.field.hidden{ name = "update_comment", value = param.get("update_comment") or issue.closed and "1" }
458 ui.field.select{
459 label = _"Wiki engine for statement",
460 name = "formatting_engine",
461 foreign_records = {
462 { id = "rocketwiki", name = "RocketWiki" },
463 { id = "compat", name = _"Traditional wiki syntax" }
464 },
465 attr = {id = "formatting_engine"},
466 foreign_id = "id",
467 foreign_name = "name",
468 value = param.get("formatting_engine") or direct_voter and direct_voter.formatting_engine
469 }
470 ui.field.text{
471 label = _"Voting comment (optional)",
472 name = "comment",
473 multiline = true,
474 value = param.get("comment") or direct_voter and direct_voter.comment,
475 attr = { style = "height: 20ex;" },
476 }
477 ui.field.hidden{ name = "preview2", attr = { id = "preview2" }, value = "0" }
478 ui.submit{
479 name = "preview",
480 value = _"Preview voting comment",
481 attr = { class = "preview" }
482 }
483 end
484 if not readonly or preview or direct_voter then
485 slot.put(" ")
486 ui.tag{
487 tag = "input",
488 attr = {
489 type = "submit",
490 class = "voting_done2",
491 value = submit_button_text
492 }
493 }
494 end
495 end
496 end
497 }

Impressum / About Us