liquid_feedback_frontend
view static/js/voting.js @ 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 | afd9f769c7ae |
children | 7492497005bd |
line source
1 voting_text_approval_single = "Approval"
2 voting_text_approval_multi = "Approval"
3 voting_text_first_preference_single = "Approval (first preference)"
4 voting_text_first_preference_multi = "Approval (first preference)"
5 voting_text_second_preference_single = "Approval (second preference)"
6 voting_text_second_preference_multi = "Approval (second preference)"
7 voting_text_third_preference_single = "Approval (third preference)"
8 voting_text_third_preference_multi = "Approval (third preference)"
9 voting_text_numeric_preference_single = "Approval (#th preference)"
10 voting_text_numeric_preference_multi = "Approval (#th preference)"
11 voting_text_abstention_single = "Abstention"
12 voting_text_abstention_multi = "Abstention"
13 voting_text_disapproval_above_one_single = "Disapproval (prefer to lower block)"
14 voting_text_disapproval_above_one_multi = "Disapproval (prefer to lower block)"
15 voting_text_disapproval_above_many_single = "Disapproval (prefer to lower blocks)"
16 voting_text_disapproval_above_many_multi = "Disapproval (prefer to lower blocks)"
17 voting_text_disapproval_above_last_single = "Disapproval (prefer to last block)"
18 voting_text_disapproval_above_last_multi = "Disapproval (prefer to last block)"
19 voting_text_disapproval_single = "Disapproval"
20 voting_text_disapproval_multi = "Disapproval"
22 function voting_setCategoryHeadings() {
23 var approvalCount = 0;
24 var disapprovalCount = 0;
25 var sections = document.getElementById("voting").childNodes;
26 for (var i=0; i<sections.length; i++) {
27 var section = sections[i];
28 if (section.className == "approval") approvalCount++;
29 if (section.className == "disapproval") disapprovalCount++;
30 }
31 var approvalIndex = 0;
32 var disapprovalIndex = 0;
33 for (var i=0; i<sections.length; i++) {
34 var section = sections[i];
35 if (
36 section.className == "approval" ||
37 section.className == "abstention" ||
38 section.className == "disapproval"
39 ) {
40 var setHeading = function(heading) {
41 var headingNodes = section.childNodes;
42 for (var j=0; j<headingNodes.length; j++) {
43 var headingNode = headingNodes[j];
44 if (headingNode.className == "cathead") {
45 headingNode.textContent = heading;
46 }
47 }
48 }
49 var count = 0;
50 var entries = section.childNodes;
51 for (var j=0; j<entries.length; j++) {
52 var entry = entries[j];
53 if (entry.className == "movable") count++;
54 }
55 if (section.className == "approval") {
56 if (approvalCount > 1) {
57 if (approvalIndex == 0) {
58 if (count == 1) setHeading(voting_text_first_preference_single);
59 else setHeading(voting_text_first_preference_multi);
60 } else if (approvalIndex == 1) {
61 if (count == 1) setHeading(voting_text_second_preference_single);
62 else setHeading(voting_text_second_preference_multi);
63 } else if (approvalIndex == 2) {
64 if (count == 1) setHeading(voting_text_third_preference_single);
65 else setHeading(voting_text_third_preference_multi);
66 } else {
67 var text;
68 if (count == 1) text = voting_text_numeric_preference_single;
69 else text = voting_text_numeric_preference_multi;
70 text = text.replace(/#/, "" + (approvalIndex + 1))
71 setHeading(text);
72 }
73 } else {
74 if (count == 1) setHeading(voting_text_approval_single);
75 else setHeading(voting_text_approval_multi);
76 }
77 approvalIndex++;
78 } else if (section.className == "abstention") {
79 if (count == 1) setHeading(voting_text_abstention_single);
80 else setHeading(voting_text_abstention_multi);
81 } else if (section.className == "disapproval") {
82 if (disapprovalCount > disapprovalIndex + 2) {
83 if (count == 1) setHeading(voting_text_disapproval_above_many_single);
84 else setHeading(voting_text_disapproval_above_many_multi);
85 } else if (disapprovalCount == 2 && disapprovalIndex == 0) {
86 if (count == 1) setHeading(voting_text_disapproval_above_one_single);
87 else setHeading(voting_text_disapproval_above_one_multi);
88 } else if (disapprovalIndex == disapprovalCount - 2) {
89 if (count == 1) setHeading(voting_text_disapproval_above_last_single);
90 else setHeading(voting_text_disapproval_above_last_multi);
91 } else {
92 if (count == 1) setHeading(voting_text_disapproval_single);
93 else setHeading(voting_text_disapproval_multi);
94 }
95 disapprovalIndex++;
96 }
97 }
98 }
99 }
100 function voting_move(element, up, dropX, dropY) {
101 if (typeof(element) == "string") element = document.getElementById(element);
102 var mouse = (up == null);
103 var oldParent = element.parentNode;
104 if (mouse) var centerY = dropY + element.clientHeight / 2;
105 var approvalCount = 0;
106 var disapprovalCount = 0;
107 var mainDiv = document.getElementById("voting");
108 var sections = mainDiv.childNodes;
109 for (var i=0; i<sections.length; i++) {
110 var section = sections[i];
111 if (section.className == "approval") approvalCount++;
112 if (section.className == "disapproval") disapprovalCount++;
113 }
114 if (mouse) {
115 for (var i=0; i<sections.length; i++) {
116 var section = sections[i];
117 if (
118 section.className == "approval" ||
119 section.className == "abstention" ||
120 section.className == "disapproval"
121 ) {
122 if (
123 centerY >= section.offsetTop &&
124 centerY < section.offsetTop + section.clientHeight
125 ) {
126 var entries = section.childNodes;
127 for (var j=0; j<entries.length; j++) {
128 var entry = entries[j];
129 if (entry.className == "movable") {
130 if (centerY < entry.offsetTop + entry.clientHeight / 2) {
131 if (element != entry) {
132 oldParent.removeChild(element);
133 section.insertBefore(element, entry);
134 }
135 break;
136 }
137 }
138 }
139 if (j == entries.length) {
140 oldParent.removeChild(element);
141 section.appendChild(element);
142 }
143 break;
144 }
145 }
146 }
147 if (i == sections.length) {
148 var newSection = document.createElement("div");
149 var cathead = document.createElement("div");
150 cathead.setAttribute("class", "cathead");
151 newSection.appendChild(cathead);
152 for (var i=0; i<sections.length; i++) {
153 var section = sections[i];
154 if (
155 section.className == "approval" ||
156 section.className == "abstention" ||
157 section.className == "disapproval"
158 ) {
159 if (centerY < section.offsetTop + section.clientHeight / 2) {
160 if (section.className == "disapproval") {
161 newSection.setAttribute("class", "disapproval");
162 disapprovalCount++;
163 } else {
164 newSection.setAttribute("class", "approval");
165 approvalCount++;
166 }
167 mainDiv.insertBefore(newSection, section);
168 break;
169 }
170 }
171 }
172 if (i == sections.length) {
173 newSection.setAttribute("class", "disapproval");
174 disapprovalCount++;
175 mainDiv.appendChild(newSection);
176 }
177 oldParent.removeChild(element);
178 newSection.appendChild(element);
179 }
180 } else {
181 var oldFound = false;
182 var prevSection = null;
183 var nextSection = null;
184 for (var i=0; i<sections.length; i++) {
185 var section = sections[i];
186 if (
187 section.className == "approval" ||
188 section.className == "abstention" ||
189 section.className == "disapproval"
190 ) {
191 if (oldFound) {
192 nextSection = section;
193 break;
194 } else if (section == oldParent) {
195 oldFound = true;
196 } else {
197 prevSection = section;
198 }
199 }
200 }
201 var create;
202 if (oldParent.className == "abstention") {
203 create = true;
204 } else {
205 create = false;
206 for (var i=0; i<oldParent.childNodes.length; i++) {
207 var entry = oldParent.childNodes[i];
208 if (entry.className == "movable") {
209 if (entry != element) {
210 create = true;
211 break;
212 }
213 }
214 }
215 }
216 var newSection;
217 if (create) {
218 newSection = document.createElement("div");
219 var cathead = document.createElement("div");
220 cathead.setAttribute("class", "cathead");
221 newSection.appendChild(cathead);
222 if (
223 oldParent.className == "approval" ||
224 (oldParent.className == "abstention" && up)
225 ) {
226 newSection.setAttribute("class", "approval");
227 approvalCount++;
228 } else {
229 newSection.setAttribute("class", "disapproval");
230 disapprovalCount++;
231 }
232 if (up) {
233 mainDiv.insertBefore(newSection, oldParent);
234 } else {
235 if (nextSection) mainDiv.insertBefore(newSection, nextSection);
236 else mainDiv.appendChild(newSection);
237 }
238 } else {
239 if (up) newSection = prevSection;
240 else newSection = nextSection;
241 }
242 if (newSection) {
243 oldParent.removeChild(element);
244 if (create || up) {
245 newSection.appendChild(element);
246 } else {
247 var inserted = false;
248 for (var i=0; i<newSection.childNodes.length; i++) {
249 var entry = newSection.childNodes[i];
250 if (entry.className == "movable") {
251 newSection.insertBefore(element, entry);
252 inserted = true;
253 break;
254 }
255 }
256 if (!inserted) newSection.appendChild(element);
257 }
258 }
259 }
260 // sections = mainDiv.childNodes;
261 for (i=0; i<sections.length; i++) {
262 var section = sections[i];
263 if (
264 (section.className == "approval" && approvalCount > 1) ||
265 (section.className == "disapproval" && disapprovalCount > 1)
266 ) {
267 var entries = section.childNodes;
268 for (var j=0; j<entries.length; j++) {
269 var entry = entries[j];
270 if (entry.className == "movable") break;
271 }
272 if (j == entries.length) {
273 section.parentNode.removeChild(section);
274 }
275 }
276 }
277 voting_setCategoryHeadings();
278 }
279 function elementDropped(element, dropX, dropY) {
280 voting_move(element, null, dropX, dropY);
281 }
282 window.addEventListener("load", function(event) {
283 voting_setCategoryHeadings();
284 var mainDiv = document.getElementById("voting");
285 var form = document.getElementById("voting_form");
286 var elements = document.getElementsByTagName("input");
287 for (var i=0; i<elements.length; i++) {
288 var element = elements[i];
289 if (element.className == "voting_done") {
290 element.addEventListener("click", function(event) {
291 var scoringString = "";
292 var approvalCount = 0;
293 var disapprovalCount = 0;
294 var sections = mainDiv.childNodes;
295 for (var j=0; j<sections.length; j++) {
296 var section = sections[j];
297 if (section.className == "approval") approvalCount++;
298 if (section.className == "disapproval") disapprovalCount++;
299 }
300 var approvalIndex = 0;
301 var disapprovalIndex = 0;
302 for (var j=0; j<sections.length; j++) {
303 var section = sections[j];
304 if (
305 section.className == "approval" ||
306 section.className == "abstention" ||
307 section.className == "disapproval"
308 ) {
309 var score;
310 if (section.className == "approval") {
311 score = approvalCount - approvalIndex;
312 approvalIndex++;
313 } else if (section.className == "abstention") {
314 score = 0;
315 } else if (section.className == "disapproval") {
316 score = -1 - disapprovalIndex;
317 disapprovalIndex++;
318 }
319 var entries = section.childNodes;
320 for (var k=0; k<entries.length; k++) {
321 var entry = entries[k];
322 if (entry.className == "movable") {
323 var id = entry.id.match(/[0-9]+/);
324 var field = document.createElement("input");
325 scoringString += id + ":" + score + ";";
326 }
327 }
328 }
329 }
330 var fields = form.childNodes;
331 for (var j=0; j<fields.length; j++) {
332 var field = fields[j];
333 if (field.name == "scoring") {
334 field.setAttribute("value", scoringString);
335 form.submit();
336 return;
337 }
338 }
339 alert('Hidden input field named "scoring" not found.');
340 }, false);
341 }
342 }
343 }, false);
344 function voting_moveUp(element) {
345 return voting_move(element, true);
346 }
347 function voting_moveDown(element) {
348 return voting_move(element, false);
349 }