liquid_feedback_frontend
annotate app/main/vote/list.lua @ 19:00d1004545f1
Dynamic interface using XMLHttpRequests, and many other changes
Bugfixes:
- Only allow voting on admitted initiatives
- Repaired issue search
- Don't display delegations for closed issues on member page
- Don't show revoke link in initiative, when issue is already half_frozen
- Localization for voting JavaScript
- Display author of suggestions
Disclosure of voting data after voting is finished:
- Possibility to inspect every ballot including preferences
- Show number of voters preferring one initiative to another initiative
Interface behaviour changes:
- Reversed default order of drafts
- Default order of suggestions changed
- Show new drafts of initiatives only once per day in timeline
Accessibility:
- Barrier-free voting implemented
- POST links are now accessible without JavaScript
- Changed gray for unsatisfied supporters in bar graph to a lighter gray
Other interface improvements:
- Optical enhancements
- Dynamic interface using XMLHttpRequests
- Show usage terms in about section
- Show own membership in area listing
- Show uninformed supporters greyed out and marked with yellow question mark
- Warning box in non-admitted initiatives
- When voted, don't display voting notice and change label of voting link
- Show object counts in more tabulator heads
- Enlarged member statement input field
Miscellaneous:
- Code cleanup
- Added README file containing installation instructions
- Use new WebMCP function ui.filters{...} instead of own ui.filter and ui.order functions
Bugfixes:
- Only allow voting on admitted initiatives
- Repaired issue search
- Don't display delegations for closed issues on member page
- Don't show revoke link in initiative, when issue is already half_frozen
- Localization for voting JavaScript
- Display author of suggestions
Disclosure of voting data after voting is finished:
- Possibility to inspect every ballot including preferences
- Show number of voters preferring one initiative to another initiative
Interface behaviour changes:
- Reversed default order of drafts
- Default order of suggestions changed
- Show new drafts of initiatives only once per day in timeline
Accessibility:
- Barrier-free voting implemented
- POST links are now accessible without JavaScript
- Changed gray for unsatisfied supporters in bar graph to a lighter gray
Other interface improvements:
- Optical enhancements
- Dynamic interface using XMLHttpRequests
- Show usage terms in about section
- Show own membership in area listing
- Show uninformed supporters greyed out and marked with yellow question mark
- Warning box in non-admitted initiatives
- When voted, don't display voting notice and change label of voting link
- Show object counts in more tabulator heads
- Enlarged member statement input field
Miscellaneous:
- Code cleanup
- Added README file containing installation instructions
- Use new WebMCP function ui.filters{...} instead of own ui.filter and ui.order functions
| author | bsw/jbe | 
|---|---|
| date | Sat Feb 20 22:10:31 2010 +0100 (2010-02-20) | 
| parents | 77d58efe99fd | 
| children | 3036f2732b83 | 
| rev | line source | 
|---|---|
| bsw/jbe@19 | 1 local issue = Issue:by_id(param.get("issue_id"), atom.integer) | 
| bsw/jbe@19 | 2 | 
| bsw/jbe@19 | 3 local member_id = param.get("member_id", atom.integer) | 
| bsw/jbe@19 | 4 local member | 
| bsw/jbe@19 | 5 | 
| bsw/jbe@19 | 6 local readonly = false | 
| bsw/jbe@19 | 7 if member_id then | 
| bsw/jbe@19 | 8 if not issue.closed then | 
| bsw/jbe@19 | 9 error("access denied") | 
| bsw/jbe@19 | 10 end | 
| bsw/jbe@19 | 11 member = Member:by_id(member_id) | 
| bsw/jbe@19 | 12 readonly = true | 
| bsw/jbe@19 | 13 end | 
| bsw/jbe@19 | 14 | 
| bsw/jbe@19 | 15 if member then | 
| bsw/jbe@19 | 16 slot.put_into("title", _("Ballot of '#{member_name}' for issue ##{issue_id}", { | 
| bsw/jbe@19 | 17 member_name = member.name, | 
| bsw/jbe@19 | 18 issue_id = issue.id | 
| bsw/jbe@19 | 19 })) | 
| bsw/jbe@19 | 20 else | 
| bsw/jbe@19 | 21 member = app.session.member | 
| bsw/jbe@19 | 22 slot.put_into("title", _"Voting") | 
| bsw/jbe@19 | 23 | 
| bsw/jbe@19 | 24 slot.select("actions", function() | 
| bsw/jbe@19 | 25 ui.link{ | 
| bsw/jbe@19 | 26 content = function() | 
| bsw/jbe@19 | 27 ui.image{ static = "icons/16/cancel.png" } | 
| bsw/jbe@19 | 28 slot.put(_"Cancel") | 
| bsw/jbe@19 | 29 end, | 
| bsw/jbe@19 | 30 module = "issue", | 
| bsw/jbe@19 | 31 view = "show", | 
| bsw/jbe@19 | 32 id = issue.id | 
| bsw/jbe@19 | 33 } | 
| bsw/jbe@19 | 34 end) | 
| bsw/jbe@19 | 35 | 
| bsw/jbe@19 | 36 end | 
| bsw/jbe@19 | 37 | 
| bsw/jbe@19 | 38 | 
| bsw/jbe@5 | 39 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." | 
| bsw/jbe@5 | 40 | 
| bsw/jbe@5 | 41 ui.script{ static = "js/browser_warning.js" } | 
| bsw/jbe@5 | 42 ui.script{ script = "checkBrowser(" .. encode.json(_"Your web browser is not fully supported yet." .. " " .. warning_text:gsub("\n", "\n\n")) .. ");" } | 
| bsw/jbe@5 | 43 | 
| bsw/jbe@19 | 44 | 
| bsw/jbe@19 | 45 local tempvoting_string = param.get("scoring") | 
| bsw/jbe@19 | 46 | 
| bsw/jbe@19 | 47 local tempvotings = {} | 
| bsw/jbe@19 | 48 if tempvoting_string then | 
| bsw/jbe@19 | 49 for match in tempvoting_string:gmatch("([^;]+)") do | 
| bsw/jbe@19 | 50 for initiative_id, grade in match:gmatch("([^:;]+):([^:;]+)") do | 
| bsw/jbe@19 | 51 tempvotings[tonumber(initiative_id)] = tonumber(grade) | 
| bsw/jbe@19 | 52 end | 
| bsw/jbe@5 | 53 end | 
| bsw/jbe@19 | 54 end | 
| bsw/jbe@5 | 55 | 
| bsw/jbe@19 | 56 local initiatives = issue:get_reference_selector("initiatives"):add_where("initiative.admitted"):exec() | 
| bsw/jbe@5 | 57 | 
| bsw/jbe@5 | 58 local min_grade = -1; | 
| bsw/jbe@5 | 59 local max_grade = 1; | 
| bsw/jbe@5 | 60 | 
| bsw/jbe@5 | 61 for i, initiative in ipairs(initiatives) do | 
| bsw/jbe@5 | 62 -- TODO performance | 
| bsw/jbe@19 | 63 initiative.vote = Vote:by_pk(initiative.id, member.id) | 
| bsw/jbe@19 | 64 if tempvotings[initiative.id] then | 
| bsw/jbe@19 | 65 initiative.vote = {} | 
| bsw/jbe@19 | 66 initiative.vote.grade = tempvotings[initiative.id] | 
| bsw/jbe@19 | 67 end | 
| bsw/jbe@5 | 68 if initiative.vote then | 
| bsw/jbe@5 | 69 if initiative.vote.grade > max_grade then | 
| bsw/jbe@5 | 70 max_grade = initiative.vote.grade | 
| bsw/jbe@5 | 71 end | 
| bsw/jbe@5 | 72 if initiative.vote.grade < min_grade then | 
| bsw/jbe@5 | 73 min_grade = initiative.vote.grade | 
| bsw/jbe@5 | 74 end | 
| bsw/jbe@5 | 75 end | 
| bsw/jbe@5 | 76 end | 
| bsw/jbe@5 | 77 | 
| bsw/jbe@5 | 78 local sections = {} | 
| bsw/jbe@5 | 79 for i = min_grade, max_grade do | 
| bsw/jbe@5 | 80 sections[i] = {} | 
| bsw/jbe@5 | 81 for j, initiative in ipairs(initiatives) do | 
| bsw/jbe@5 | 82 if (initiative.vote and initiative.vote.grade == i) or (not initiative.vote and i == 0) then | 
| bsw/jbe@5 | 83 sections[i][#(sections[i])+1] = initiative | 
| bsw/jbe@5 | 84 end | 
| bsw/jbe@5 | 85 end | 
| bsw/jbe@5 | 86 end | 
| bsw/jbe@5 | 87 | 
| bsw/jbe@19 | 88 local approval_count, disapproval_count = 0, 0 | 
| bsw/jbe@19 | 89 for i = min_grade, -1 do | 
| bsw/jbe@19 | 90 if #sections[i] > 0 then | 
| bsw/jbe@19 | 91 disapproval_count = disapproval_count + 1 | 
| bsw/jbe@19 | 92 end | 
| bsw/jbe@19 | 93 end | 
| bsw/jbe@19 | 94 local approval_count = 0 | 
| bsw/jbe@19 | 95 for i = 1, max_grade do | 
| bsw/jbe@19 | 96 if #sections[i] > 0 then | 
| bsw/jbe@19 | 97 approval_count = approval_count + 1 | 
| bsw/jbe@19 | 98 end | 
| bsw/jbe@19 | 99 end | 
| bsw/jbe@5 | 100 | 
| bsw/jbe@5 | 101 | 
| bsw/jbe@5 | 102 | 
| bsw/jbe@19 | 103 if not readonly then | 
| bsw/jbe@19 | 104 util.help("vote.list", _"Voting") | 
| bsw/jbe@19 | 105 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/dragdrop.js"></script>') | 
| bsw/jbe@19 | 106 slot.put('<script src="' .. request.get_relative_baseurl() .. 'static/js/voting.js"></script>') | 
| bsw/jbe@19 | 107 end | 
| bsw/jbe@19 | 108 | 
| bsw/jbe@19 | 109 ui.script{ | 
| bsw/jbe@19 | 110 script = function() | 
| bsw/jbe@19 | 111 slot.put( | 
| bsw/jbe@19 | 112 "voting_text_approval_single = ", encode.json(_"Approval [single entry]"), ";\n", | 
| bsw/jbe@19 | 113 "voting_text_approval_multi = ", encode.json(_"Approval [many entries]"), ";\n", | 
| bsw/jbe@19 | 114 "voting_text_first_preference_single = ", encode.json(_"Approval (first preference) [single entry]"), ";\n", | 
| bsw/jbe@19 | 115 "voting_text_first_preference_multi = ", encode.json(_"Approval (first preference) [many entries]"), ";\n", | 
| bsw/jbe@19 | 116 "voting_text_second_preference_single = ", encode.json(_"Approval (second preference) [single entry]"), ";\n", | 
| bsw/jbe@19 | 117 "voting_text_second_preference_multi = ", encode.json(_"Approval (second preference) [many entries]"), ";\n", | 
| bsw/jbe@19 | 118 "voting_text_third_preference_single = ", encode.json(_"Approval (third preference) [single entry]"), ";\n", | 
| bsw/jbe@19 | 119 "voting_text_third_preference_multi = ", encode.json(_"Approval (third preference) [many entries]"), ";\n", | 
| bsw/jbe@19 | 120 "voting_text_numeric_preference_single = ", encode.json(_"Approval (#th preference) [single entry]"), ";\n", | 
| bsw/jbe@19 | 121 "voting_text_numeric_preference_multi = ", encode.json(_"Approval (#th preference) [many entries]"), ";\n", | 
| bsw/jbe@19 | 122 "voting_text_abstention_single = ", encode.json(_"Abstention [single entry]"), ";\n", | 
| bsw/jbe@19 | 123 "voting_text_abstention_multi = ", encode.json(_"Abstention [many entries]"), ";\n", | 
| bsw/jbe@19 | 124 "voting_text_disapproval_above_one_single = ", encode.json(_"Disapproval (prefer to lower block) [single entry]"), ";\n", | 
| bsw/jbe@19 | 125 "voting_text_disapproval_above_one_multi = ", encode.json(_"Disapproval (prefer to lower block) [many entries]"), ";\n", | 
| bsw/jbe@19 | 126 "voting_text_disapproval_above_many_single = ", encode.json(_"Disapproval (prefer to lower blocks) [single entry]"), ";\n", | 
| bsw/jbe@19 | 127 "voting_text_disapproval_above_many_multi = ", encode.json(_"Disapproval (prefer to lower blocks) [many entries]"), ";\n", | 
| bsw/jbe@19 | 128 "voting_text_disapproval_above_last_single = ", encode.json(_"Disapproval (prefer to last block) [single entry]"), ";\n", | 
| bsw/jbe@19 | 129 "voting_text_disapproval_above_last_multi = ", encode.json(_"Disapproval (prefer to last block) [many entries]"), ";\n", | 
| bsw/jbe@19 | 130 "voting_text_disapproval_single = ", encode.json(_"Disapproval [single entry]"), ";\n", | 
| bsw/jbe@19 | 131 "voting_text_disapproval_multi = ", encode.json(_"Disapproval [many entries]"), ";\n" | 
| bsw/jbe@19 | 132 ) | 
| bsw/jbe@19 | 133 end | 
| bsw/jbe@19 | 134 } | 
| bsw/jbe@5 | 135 | 
| bsw/jbe@5 | 136 ui.form{ | 
| bsw/jbe@19 | 137 attr = { | 
| bsw/jbe@19 | 138 id = "voting_form", | 
| bsw/jbe@19 | 139 class = readonly and "voting_form_readonly" or "voting_form_active" | 
| bsw/jbe@19 | 140 }, | 
| bsw/jbe@5 | 141 module = "vote", | 
| bsw/jbe@5 | 142 action = "update", | 
| bsw/jbe@5 | 143 params = { issue_id = issue.id }, | 
| bsw/jbe@5 | 144 routing = { | 
| bsw/jbe@5 | 145 default = { | 
| bsw/jbe@5 | 146 mode = "redirect", | 
| bsw/jbe@5 | 147 module = "issue", | 
| bsw/jbe@5 | 148 view = "show", | 
| bsw/jbe@5 | 149 id = issue.id | 
| bsw/jbe@5 | 150 } | 
| bsw/jbe@5 | 151 }, | 
| bsw/jbe@5 | 152 content = function() | 
| bsw/jbe@19 | 153 if not readonly then | 
| bsw/jbe@19 | 154 local scoring = param.get("scoring") | 
| bsw/jbe@19 | 155 if not scoring then | 
| bsw/jbe@19 | 156 for i, initiative in ipairs(initiatives) do | 
| bsw/jbe@19 | 157 local vote = initiative.vote | 
| bsw/jbe@19 | 158 if vote then | 
| bsw/jbe@19 | 159 tempvotings[initiative.id] = vote.grade | 
| bsw/jbe@19 | 160 end | 
| bsw/jbe@19 | 161 end | 
| bsw/jbe@19 | 162 local tempvotings_list = {} | 
| bsw/jbe@19 | 163 for key, val in pairs(tempvotings) do | 
| bsw/jbe@19 | 164 tempvotings_list[#tempvotings_list+1] = tostring(key) .. ":" .. tostring(val) | 
| bsw/jbe@19 | 165 end | 
| bsw/jbe@19 | 166 if #tempvotings_list > 0 then | 
| bsw/jbe@19 | 167 scoring = table.concat(tempvotings_list, ";") | 
| bsw/jbe@19 | 168 else | 
| bsw/jbe@19 | 169 scoring = "" | 
| bsw/jbe@19 | 170 end | 
| bsw/jbe@19 | 171 end | 
| bsw/jbe@19 | 172 slot.put('<input type="hidden" name="scoring" value="' .. scoring .. '"/>') | 
| bsw/jbe@19 | 173 -- TODO abstrahieren | 
| bsw/jbe@19 | 174 ui.tag{ | 
| bsw/jbe@19 | 175 tag = "input", | 
| bsw/jbe@19 | 176 attr = { | 
| bsw/jbe@19 | 177 type = "button", | 
| bsw/jbe@19 | 178 class = "voting_done", | 
| bsw/jbe@19 | 179 value = _"Finish voting" | 
| bsw/jbe@19 | 180 } | 
| bsw/jbe@5 | 181 } | 
| bsw/jbe@19 | 182 end | 
| bsw/jbe@5 | 183 ui.container{ | 
| bsw/jbe@5 | 184 attr = { id = "voting" }, | 
| bsw/jbe@5 | 185 content = function() | 
| bsw/jbe@19 | 186 local approval_index, disapproval_index = 0, 0 | 
| bsw/jbe@5 | 187 for grade = max_grade, min_grade, -1 do | 
| bsw/jbe@19 | 188 local entries = sections[grade] | 
| bsw/jbe@5 | 189 local class | 
| bsw/jbe@5 | 190 if grade > 0 then | 
| bsw/jbe@5 | 191 class = "approval" | 
| bsw/jbe@5 | 192 elseif grade < 0 then | 
| bsw/jbe@5 | 193 class = "disapproval" | 
| bsw/jbe@5 | 194 else | 
| bsw/jbe@5 | 195 class = "abstention" | 
| bsw/jbe@5 | 196 end | 
| bsw/jbe@19 | 197 if | 
| bsw/jbe@19 | 198 #entries > 0 or | 
| bsw/jbe@19 | 199 (grade == 1 and not approval_used) or | 
| bsw/jbe@19 | 200 (grade == -1 and not disapproval_used) or | 
| bsw/jbe@19 | 201 grade == 0 | 
| bsw/jbe@19 | 202 then | 
| bsw/jbe@19 | 203 ui.container{ | 
| bsw/jbe@19 | 204 attr = { class = class }, | 
| bsw/jbe@19 | 205 content = function() | 
| bsw/jbe@19 | 206 local heading | 
| bsw/jbe@19 | 207 if class == "approval" then | 
| bsw/jbe@19 | 208 approval_used = true | 
| bsw/jbe@19 | 209 approval_index = approval_index + 1 | 
| bsw/jbe@19 | 210 if approval_count > 1 then | 
| bsw/jbe@19 | 211 if approval_index == 1 then | 
| bsw/jbe@19 | 212 if #entries == 1 then | 
| bsw/jbe@19 | 213 heading = _"Approval (first preference) [single entry]" | 
| bsw/jbe@19 | 214 else | 
| bsw/jbe@19 | 215 heading = _"Approval (first preference) [many entries]" | 
| bsw/jbe@19 | 216 end | 
| bsw/jbe@19 | 217 elseif approval_index == 2 then | 
| bsw/jbe@19 | 218 if #entries == 1 then | 
| bsw/jbe@19 | 219 heading = _"Approval (second preference) [single entry]" | 
| bsw/jbe@19 | 220 else | 
| bsw/jbe@19 | 221 heading = _"Approval (second preference) [many entries]" | 
| bsw/jbe@19 | 222 end | 
| bsw/jbe@19 | 223 elseif approval_index == 3 then | 
| bsw/jbe@19 | 224 if #entries == 1 then | 
| bsw/jbe@19 | 225 heading = _"Approval (third preference) [single entry]" | 
| bsw/jbe@19 | 226 else | 
| bsw/jbe@19 | 227 heading = _"Approval (third preference) [many entries]" | 
| bsw/jbe@19 | 228 end | 
| bsw/jbe@19 | 229 else | 
| bsw/jbe@19 | 230 if #entries == 1 then | 
| bsw/jbe@19 | 231 heading = _"Approval (#th preference) [single entry]" | 
| bsw/jbe@19 | 232 else | 
| bsw/jbe@19 | 233 heading = _"Approval (#th preference) [many entries]" | 
| bsw/jbe@19 | 234 end | 
| bsw/jbe@19 | 235 end | 
| bsw/jbe@19 | 236 else | 
| bsw/jbe@19 | 237 if #entries == 1 then | 
| bsw/jbe@19 | 238 heading = _"Approval [single entry]" | 
| bsw/jbe@19 | 239 else | 
| bsw/jbe@19 | 240 heading = _"Approval [many entries]" | 
| bsw/jbe@19 | 241 end | 
| bsw/jbe@19 | 242 end | 
| bsw/jbe@19 | 243 elseif class == "abstention" then | 
| bsw/jbe@19 | 244 if #entries == 1 then | 
| bsw/jbe@19 | 245 heading = _"Abstention [single entry]" | 
| bsw/jbe@19 | 246 else | 
| bsw/jbe@19 | 247 heading = _"Abstention [many entries]" | 
| bsw/jbe@19 | 248 end | 
| bsw/jbe@19 | 249 elseif class == "disapproval" then | 
| bsw/jbe@19 | 250 disapproval_used = true | 
| bsw/jbe@19 | 251 disapproval_index = disapproval_index + 1 | 
| bsw/jbe@19 | 252 if disapproval_count > disapproval_index + 1 then | 
| bsw/jbe@19 | 253 if #entries == 1 then | 
| bsw/jbe@19 | 254 heading = _"Disapproval (prefer to lower blocks) [single entry]" | 
| bsw/jbe@19 | 255 else | 
| bsw/jbe@19 | 256 heading = _"Disapproval (prefer to lower blocks) [many entries]" | 
| bsw/jbe@19 | 257 end | 
| bsw/jbe@19 | 258 elseif disapproval_count == 2 and disapproval_index == 1 then | 
| bsw/jbe@19 | 259 if #entries == 1 then | 
| bsw/jbe@19 | 260 heading = _"Disapproval (prefer to lower block) [single entry]" | 
| bsw/jbe@19 | 261 else | 
| bsw/jbe@19 | 262 heading = _"Disapproval (prefer to lower block) [many entries]" | 
| bsw/jbe@19 | 263 end | 
| bsw/jbe@19 | 264 elseif disapproval_index == disapproval_count - 1 then | 
| bsw/jbe@19 | 265 if #entries == 1 then | 
| bsw/jbe@19 | 266 heading = _"Disapproval (prefer to last block) [single entry]" | 
| bsw/jbe@19 | 267 else | 
| bsw/jbe@19 | 268 heading = _"Disapproval (prefer to last block) [many entries]" | 
| bsw/jbe@19 | 269 end | 
| bsw/jbe@19 | 270 else | 
| bsw/jbe@19 | 271 if #entries == 1 then | 
| bsw/jbe@19 | 272 heading = _"Disapproval [single entry]" | 
| bsw/jbe@19 | 273 else | 
| bsw/jbe@19 | 274 heading = _"Disapproval [many entries]" | 
| bsw/jbe@6 | 275 end | 
| bsw/jbe@19 | 276 end | 
| bsw/jbe@19 | 277 end | 
| bsw/jbe@19 | 278 ui.tag { | 
| bsw/jbe@19 | 279 tag = "div", | 
| bsw/jbe@19 | 280 attr = { class = "cathead" }, | 
| bsw/jbe@19 | 281 content = heading | 
| bsw/jbe@19 | 282 } | 
| bsw/jbe@19 | 283 for i, initiative in ipairs(entries) do | 
| bsw/jbe@19 | 284 ui.container{ | 
| bsw/jbe@19 | 285 attr = { | 
| bsw/jbe@19 | 286 class = "movable", | 
| bsw/jbe@19 | 287 id = "entry_" .. tostring(initiative.id) | 
| bsw/jbe@19 | 288 }, | 
| bsw/jbe@19 | 289 content = function() | 
| bsw/jbe@19 | 290 local initiators_selector = initiative:get_reference_selector("initiating_members") | 
| bsw/jbe@19 | 291 :add_where("accepted") | 
| bsw/jbe@19 | 292 local initiators = initiators_selector:exec() | 
| bsw/jbe@19 | 293 local initiator_names = {} | 
| bsw/jbe@19 | 294 for i, initiator in ipairs(initiators) do | 
| bsw/jbe@19 | 295 initiator_names[#initiator_names+1] = initiator.name | 
| bsw/jbe@19 | 296 end | 
| bsw/jbe@19 | 297 local initiator_names_string = table.concat(initiator_names, ", ") | 
| bsw/jbe@19 | 298 ui.container{ | 
| bsw/jbe@19 | 299 attr = { style = "float: right;" }, | 
| bsw/jbe@19 | 300 content = function() | 
| bsw/jbe@19 | 301 ui.link{ | 
| bsw/jbe@19 | 302 attr = { class = "clickable" }, | 
| bsw/jbe@19 | 303 content = _"Show", | 
| bsw/jbe@19 | 304 module = "initiative", | 
| bsw/jbe@19 | 305 view = "show", | 
| bsw/jbe@19 | 306 id = initiative.id | 
| bsw/jbe@19 | 307 } | 
| bsw/jbe@19 | 308 slot.put(" ") | 
| bsw/jbe@19 | 309 ui.link{ | 
| bsw/jbe@19 | 310 attr = { class = "clickable", target = "_blank" }, | 
| bsw/jbe@19 | 311 content = _"(new window)", | 
| bsw/jbe@19 | 312 module = "initiative", | 
| bsw/jbe@19 | 313 view = "show", | 
| bsw/jbe@19 | 314 id = initiative.id | 
| bsw/jbe@19 | 315 } | 
| bsw/jbe@19 | 316 if not readonly then | 
| bsw/jbe@19 | 317 slot.put(" ") | 
| bsw/jbe@19 | 318 ui.image{ attr = { class = "grabber" }, static = "icons/grabber.png" } | 
| bsw/jbe@19 | 319 end | 
| bsw/jbe@19 | 320 end | 
| bsw/jbe@19 | 321 } | 
| bsw/jbe@19 | 322 if not readonly then | 
| bsw/jbe@19 | 323 ui.container{ | 
| bsw/jbe@19 | 324 attr = { style = "float: left;" }, | 
| bsw/jbe@19 | 325 content = function() | 
| bsw/jbe@19 | 326 ui.tag{ | 
| bsw/jbe@19 | 327 tag = "input", | 
| bsw/jbe@19 | 328 attr = { | 
| bsw/jbe@19 | 329 onclick = "voting_moveUp(this.parentNode.parentNode); return(false);", | 
| bsw/jbe@19 | 330 name = "move_up", | 
| bsw/jbe@19 | 331 value = initiative.id, | 
| bsw/jbe@19 | 332 class = not disabled and "clickable" or nil, | 
| bsw/jbe@19 | 333 type = "image", | 
| bsw/jbe@19 | 334 src = encode.url{ static = "icons/move_up.png" }, | 
| bsw/jbe@19 | 335 alt = _"Move up" | 
| bsw/jbe@19 | 336 } | 
| bsw/jbe@19 | 337 } | 
| bsw/jbe@19 | 338 slot.put(" ") | 
| bsw/jbe@19 | 339 ui.tag{ | 
| bsw/jbe@19 | 340 tag = "input", | 
| bsw/jbe@19 | 341 attr = { | 
| bsw/jbe@19 | 342 onclick = "voting_moveDown(this.parentNode.parentNode); return(false);", | 
| bsw/jbe@19 | 343 name = "move_down", | 
| bsw/jbe@19 | 344 value = initiative.id, | 
| bsw/jbe@19 | 345 class = not disabled and "clickable" or nil, | 
| bsw/jbe@19 | 346 type = "image", | 
| bsw/jbe@19 | 347 src = encode.url{ static = "icons/move_down.png" }, | 
| bsw/jbe@19 | 348 alt = _"Move down" | 
| bsw/jbe@19 | 349 } | 
| bsw/jbe@19 | 350 } | 
| bsw/jbe@19 | 351 slot.put(" ") | 
| bsw/jbe@19 | 352 end | 
| bsw/jbe@6 | 353 } | 
| bsw/jbe@6 | 354 end | 
| bsw/jbe@6 | 355 ui.container{ | 
| bsw/jbe@19 | 356 content = function() | 
| bsw/jbe@19 | 357 slot.put(encode.html(initiative.shortened_name)) | 
| bsw/jbe@19 | 358 if #initiators > 1 then | 
| bsw/jbe@19 | 359 ui.container{ | 
| bsw/jbe@19 | 360 attr = { style = "font-size: 80%;" }, | 
| bsw/jbe@19 | 361 content = _"Initiators" .. ": " .. initiator_names_string | 
| bsw/jbe@19 | 362 } | 
| bsw/jbe@19 | 363 else | 
| bsw/jbe@19 | 364 ui.container{ | 
| bsw/jbe@19 | 365 attr = { style = "font-size: 80%;" }, | 
| bsw/jbe@19 | 366 content = _"Initiator" .. ": " .. initiator_names_string | 
| bsw/jbe@19 | 367 } | 
| bsw/jbe@19 | 368 end | 
| bsw/jbe@19 | 369 end | 
| bsw/jbe@6 | 370 } | 
| bsw/jbe@6 | 371 end | 
| bsw/jbe@19 | 372 } | 
| bsw/jbe@19 | 373 end | 
| bsw/jbe@5 | 374 end | 
| bsw/jbe@19 | 375 } | 
| bsw/jbe@19 | 376 end | 
| bsw/jbe@5 | 377 end | 
| bsw/jbe@5 | 378 end | 
| bsw/jbe@5 | 379 } | 
| bsw/jbe@19 | 380 if not readonly then | 
| bsw/jbe@19 | 381 ui.tag{ | 
| bsw/jbe@19 | 382 tag = "input", | 
| bsw/jbe@19 | 383 attr = { | 
| bsw/jbe@19 | 384 type = "button", | 
| bsw/jbe@19 | 385 class = "voting_done", | 
| bsw/jbe@19 | 386 value = _"Finish voting" | 
| bsw/jbe@19 | 387 } | 
| bsw/jbe@5 | 388 } | 
| bsw/jbe@19 | 389 end | 
| bsw/jbe@5 | 390 end | 
| bsw/jbe@5 | 391 } | 
| bsw/jbe@5 | 392 | 
| bsw/jbe@5 | 393 |