liquid_feedback_frontend

view app/main/vote/list.lua @ 47:8e9436ea3017

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

Impressum / About Us