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