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