comparison src/nabble/modules/poll/poll.naml @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children 18cf4872fd7f
comparison
equal deleted inserted replaced
-1:000000000000 0:7ecd1a4ef557
1 === Permission ===
2
3 <macro name="create_poll_permission">
4 Create_poll
5 </macro>
6
7 <macro name="can_create_poll_in" requires="user" dot_parameter="node_attr">
8 <n.set_local_user.this_user />
9 <n.set_local_node.node_attr/>
10 <n.both>
11 <condition1.local_user.is_registered/>
12 <condition2.either>
13 <condition1.local_user.is_site_admin/>
14 <condition2.local_user.has_permission node="[n.local_node/]" permission_node="[n.local_node.app_or_root/]" permission="[n.create_poll_permission/]" />
15 </condition2.either>
16 </n.both>
17 </macro>
18
19 <override_macro name="all_permissions_list">
20 <n.overridden />
21 <n.create_poll_permission/>,
22 </override_macro>
23
24 <override_macro name="permission_rows">
25 <n.overridden />
26 <n.permission_row
27 permission = "[n.create_poll_permission/]"
28 description="[t]Who can create polls.[/t]"
29 anyone_cell = ""
30 administrators_cell = "true"
31 />
32 </override_macro>
33
34 === Node Message ===
35
36 <override_macro name="node_message_as_html" requires="node">
37 <n.overridden />
38
39 <n.comment.>
40 If this is a topic page (which calls the "message_text" command), then show the poll.
41 Otherwise (email messages), print a link to the poll.
42 </n.comment.>
43 <n.if.is_in_command name="email_message">
44 <then.poll_link/>
45 <else.poll/>
46 </n.if.is_in_command>
47 </override_macro>
48
49 <macro name="poll_link" requires="node">
50 <n.if.has_poll>
51 <then>
52 <div style="background-color:#FFFADB;border:#EDDD79 solid 1px;margin-top:1em;padding:.5em">
53 <b><t>This message has a poll</t></b> -- <t>Visit the link below if you want to participate:</t><br/>
54 <a href="[n.url/]"><n.url/></a>
55 </div>
56 </then>
57 </n.if.has_poll>
58 </macro>
59
60 <override_macro name="message_as_text" requires="message" unindent="true">
61 <n.overridden/>
62
63 <n.if.is_in_command name="node_message_block">
64 <then.if.message_block_node.has_poll>
65 <then>
66 <n.crlf/>[<t>Poll</t>] <t>This message has a poll</t> / <t>Visit the link below if you want to participate:</t>
67 <n.message_block_node.url/>
68 </then>
69 </then.if.message_block_node.has_poll>
70 </n.if.is_in_command >
71 </override_macro>
72
73 === New post page ===
74
75 <override_macro name="new_post_extra_fields" requires="node_page">
76 <n.overridden/>
77
78 <n.if.both condition1="[n.page_node.is_app/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
79 <then>
80 <div class="extra-fields">
81 <img src="/images/add.png" width="12" height="12" style="margin-top:.2em"/>
82 <n.add_poll_form/>
83 </div>
84 </then>
85 </n.if.both>
86 </override_macro>
87
88 <override_macro name="init_new_post_custom_fields">
89 <n.overridden/>
90 <n.if.visitor.can_create_poll_in.page_node>
91 <then>
92 <n.poll_max_choices_field.set_value value="1" />
93 <n.poll_allow_vote_change_field.set_value value="true" />
94 <n.poll_show_results_before_vote_field.set_value value="true" />
95 <n.poll_show_results_before_end_field.set_value value="true" />
96 </then>
97 </n.if.visitor.can_create_poll_in.page_node>
98 </override_macro>
99
100 <override_macro name="save_new_post_custom_fields">
101 <n.overridden/>
102 <n.if.visitor.can_create_poll_in.page_node>
103 <then.new_node.save_new_poll/>
104 </n.if.visitor.can_create_poll_in.page_node>
105 </override_macro>
106
107 === Edit post page ===
108
109 <override_macro name="edit_post_extra_fields" requires="node_page">
110 <n.overridden/>
111
112 <n.if.both condition1="[n.page_node.parent_node.is_app/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
113 <then>
114 <div class="extra-fields">
115 <img src="/images/add.png" width="12" height="12" style="margin-top:.2em"/>
116 <n.if.page_node.has_poll>
117 <then.edit_poll_form/>
118 <else.add_poll_form/>
119 </n.if.page_node.has_poll>
120 </div>
121 </then>
122 </n.if.both>
123 </override_macro>
124
125 <override_macro name="init_edit_post_custom_fields" requires="node_page">
126 <n.overridden/>
127 <n.if.both condition1="[n.page_node.has_poll/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
128 <then>
129 <n.poll_max_choices_field.set_value value="[n.page_node.poll_max_choices/]" />
130 <n.poll_days_left_field.set_value value="[n.page_node.poll_days_left/]" />
131 <n.poll_allow_vote_change_field.set_value value="[n.page_node.poll_allow_vote_change/]" />
132 <n.poll_show_results_before_vote_field.set_value value="[n.page_node.poll_show_results_before_vote/]" />
133 <n.poll_show_results_before_end_field.set_value value="[n.page_node.poll_show_results_before_end/]" />
134 </then>
135 </n.if.both>
136 </override_macro>
137
138 <override_macro name="save_edit_post_custom_fields" requires="node_page">
139 <n.overridden/>
140 <n.if.both condition1="[n.page_node.has_poll/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
141 <then>
142 <n.edit_poll>
143 <poll_max_choices>
144 <n.get_int. default="1" exception="max_choices_field_not_integer"><n.poll_max_choices_field.value/></n.get_int.>
145 </poll_max_choices>
146 <poll_days_left><n.to_null_if. equals=""><n.poll_days_left_field.value/></n.to_null_if.></poll_days_left>
147 <poll_allow_vote_change><n.poll_allow_vote_change_field.value/></poll_allow_vote_change>
148 <poll_show_results_before_vote><n.poll_show_results_before_vote_field.value/></poll_show_results_before_vote>
149 <poll_show_results_before_end><n.poll_show_results_before_end_field.value/></poll_show_results_before_end>
150 </n.edit_poll>
151 </then>
152 <else.page_node.save_new_poll/>
153 </n.if.both>
154 </override_macro>
155
156 === Error Handling ===
157
158 <override_macro name="custom_new_node_errors">
159 <n.overridden/>
160 <n.poll_errors/>
161 </override_macro>
162
163 <override_macro name="custom_edit_post_errors">
164 <n.overridden/>
165 <n.poll_errors/>
166 </override_macro>
167
168 <macro name="poll_errors" requires="error">
169 <n.exception. name="invalid_poll_format">
170 <t>Invalid poll parameters.</t>
171 </n.exception.>
172 <n.exception. name="days_field_not_integer">
173 <t>Poll duration must be a non-negative integer or blank.</t>
174 </n.exception.>
175 <n.exception. name="max_choices_field_not_integer">
176 <t>Poll maximum allowed choices must be a non-negative integer or blank.</t>
177 </n.exception.>
178 </macro>
179
180 === Javascript Handler ===
181
182 <override_macro name="extra_call_later_handlers">
183 <n.overridden/>
184 <n.poll_js/>
185 </override_macro>
186
187 === Other macros ===
188
189 <macro name="add_poll_form" requires="node_page">
190 <script type="text/javascript">
191 function addPoll() {
192 $('#poll').show();
193 if ( $('#poll-options div').size() == 0 ) {
194 addOption(false);
195 addOption(false);
196 } else
197 updateOptions();
198 Nabble.resizeFrames();
199 };
200 function removeOption(e) {
201 $(e).parent().remove();
202 updateOptions();
203 Nabble.resizeFrames();
204 };
205 function addOption(focus) {
206 $('#poll-options').append('<n.javascript_string_encode.poll_option_input_row/>');
207 updateOptions();
208 if (focus)
209 $('#poll-options div input').last().focus();
210 Nabble.resizeFrames();
211 };
212 function updateOptions() {
213 var c = 1;
214 $('#poll-options div').each(function() {
215 $('a,span', this).remove();
216 $(this).prepend('<span>'+c+'.</span>');
217 if (c++ > 2) {
218 $(this).append('<a class="removeOption" href="javascript:void(0)" onclick="removeOption(this)"><t>remove</t></a>');
219 }
220 });
221 };
222 function removePoll() {
223 $('input[name=poll_question]').val('');
224 $('#poll').hide();
225 };
226 <n.if.not.is_empty.poll_question_field.value>
227 <then>
228 $(document).ready(function() {
229 updateOptions();
230 });
231 </then>
232 </n.if.not.is_empty.poll_question_field.value>
233 </script>
234 <a href="javascript: void(0)" onclick="addPoll()"><t>Add new poll</t></a>
235
236 <div id="poll" class="extra-field-details medium-border-color" style="[n.if.is_empty.poll_question_field.value][then]display:none[/then][/n.if.is_empty.poll_question_field.value]">
237 <table>
238 <tr valign="top">
239 <td style="text-align:right;padding-top:.4em"><t>Question:</t></td>
240 <td style="padding-left:1.8em"><n.poll_question_field.input type="text" size="40"/></td>
241 </tr>
242 <tr valign="top">
243 <td style="text-align:right;padding-top:.4em"><t>Answers:</t></td>
244 <td style="padding-left:.7em">
245 <div id="poll-options" style="padding-bottom:.3em">
246 <n.get_parameter_values. name="poll_option">
247 <n.loop.poll_option_input_row.current_parameter_value/>
248 </n.get_parameter_values.>
249 </div>
250 <a href="javascript: void addOption(true)"><t>Add new answer</t></a>
251 </td>
252 </tr>
253 </table>
254 <n.poll_settings/>
255 <a href="javascript: void(0)" onclick="removePoll()"><t>Remove Poll</t></a>
256 </div>
257 </macro>
258
259 <macro name="edit_poll_form" requires="node_page">
260 <script type="text/javascript">
261 Nabble.deletePoll = function(nodeId) {
262 var call = '/template/NamlServlet.jtp?macro=delete_poll_js&node='+nodeId;
263 if (confirm("<t>Delete this poll, including all votes?</t>")) {
264 $.getScript(call, function() {
265 notice('<t>Poll has been deleted.</t>', 2000, 2000);
266 $('#poll').remove();
267 });
268 }
269 return false;
270 };
271 </script>
272 <n.page_node.>
273 <t>Poll</t>
274
275 <div id="poll" class="extra-field-details medium-border-color">
276 <div class="weak-color" style="padding:.3em">
277 <div class="bold"><n.encode.poll_question/></div>
278 <ul style="margin:.3em 0">
279 <n.poll_option_list.loop.>
280 <li><n.current_string/></li>
281 </n.poll_option_list.loop.>
282 </ul>
283 <n.poll_settings />
284 <a href="javascript: void(0)" onclick="Nabble.deletePoll([n.id/])"><t>Remove Poll</t></a>
285 </div>
286 </div>
287 </n.page_node.>
288 </macro>
289
290 <macro name="poll_settings">
291 <div style="margin: .5em 0 .5em 1em">
292 <t>Multiple selections allowed:</t> <n.poll_max_choices_field.input type="text" size="2" maxlength="2"/><br />
293 <t>Poll ends after <t.number.poll_days_left_field.input type="text" size="2" maxlength="3"/> days (leave blank for unlimited).</t><br />
294 <n.poll_allow_vote_change_field.checkbox/> <label for="poll_allow_vote_change"><t>Allow vote changes</t></label><br />
295 <n.poll_show_results_before_vote_field.checkbox/> <label for="poll_show_results_before_vote"><t>Allow viewing results before vote</t></label><br />
296 <n.poll_show_results_before_end_field.checkbox/> <label for="poll_show_results_before_end"><t>Allow viewing results before end date (poll creators can always view the results)</t></label>
297 </div>
298 </macro>
299
300 <macro name="save_new_poll" requires="node">
301 <n.if.not.is_empty.poll_question_field.value>
302 <then>
303 <n.set_poll>
304 <poll_question><n.poll_question_field.value/></poll_question>
305 <poll_options><n.get_parameter_values name="poll_option"/></poll_options>
306 <poll_max_choices>
307 <n.get_int. default="1" exception="max_choices_field_not_integer"><n.poll_max_choices_field.value/></n.get_int.>
308 </poll_max_choices>
309 <poll_days_left>
310 <n.get_int. default="0" exception="days_field_not_integer"><n.poll_days_left_field.value/></n.get_int.>
311 </poll_days_left>
312 <poll_allow_vote_change><n.poll_allow_vote_change_field.value/></poll_allow_vote_change>
313 <poll_show_results_before_vote><n.poll_show_results_before_vote_field.value/></poll_show_results_before_vote>
314 <poll_show_results_before_end><n.poll_show_results_before_end_field.value/></poll_show_results_before_end>
315 </n.set_poll>
316 </then>
317 </n.if.not.is_empty.poll_question_field.value>
318 </macro>
319
320 <macro name="poll_question_field" dot_parameter="do">
321 <n.field. name="poll_question"><n.do/></n.field.>
322 </macro>
323
324 <macro name="poll_max_choices_field" dot_parameter="do">
325 <n.field. name="poll_max_choices"><n.do/></n.field.>
326 </macro>
327
328 <macro name="poll_days_left_field" dot_parameter="do">
329 <n.field. name="poll_days_left"><n.do/></n.field.>
330 </macro>
331
332 <macro name="poll_allow_vote_change_field" dot_parameter="do">
333 <n.field. name="poll_allow_vote_change"><n.do/></n.field.>
334 </macro>
335
336 <macro name="poll_show_results_before_vote_field" dot_parameter="do">
337 <n.field. name="poll_show_results_before_vote"><n.do/></n.field.>
338 </macro>
339
340 <macro name="poll_show_results_before_end_field" dot_parameter="do">
341 <n.field. name="poll_show_results_before_end"><n.do/></n.field.>
342 </macro>
343
344 <macro name="poll_option_input_row" dot_parameter="poll_option">
345 <div class="nowrap">
346 <input type="text" class="poll_option" name="poll_option" size="30" value="[n.hide_null.poll_option/]" />
347 </div>
348 </macro>
349
350 <macro name="delete_poll_js">
351 <n.get_node_from_id. node_id="[n.get_parameter name='node'/]">
352 <n.delete_poll />
353 </n.get_node_from_id.>
354 </macro>
355
356 <macro name="poll" requires="node">
357 <n.comment.>
358 Builds the poll interface. Since some options depend on the current visitor, we use javascript
359 to set up some fields. Please look at the "poll_js" macro in order to understand how this poll UI is updated.
360 </n.comment.>
361 <n.if.has_poll>
362 <then>
363 <form method="POST" id="poll_form[n.id/]" onsubmit="return Nabble.vote([n.id/],[n.poll_max_choices/]);" accept-charset="UTF-8" >
364 <input type="hidden" name="node" value="[n.id/]" />
365
366 <div class="medium-border-color border2 rounded" style="margin-top:1em;padding:1em">
367 <div class="big-title second-font">
368 <n.encode.poll_question/>
369 </div>
370 <n.explain_poll_max_choices/>
371
372 <n.poll_option_list.loop.>
373 <div style="margin:.4em 0 0 1em">
374 <span id="poll-option-input[n.option_id/]"></span>
375 <label for="option[n.option_id/]"><n.encode.current_string/></label>
376 <span id="poll-vote-count[n.option_id/]" class="weak-color" style="font-size:80%"></span>
377 </div>
378 </n.poll_option_list.loop.>
379
380 <div style="margin-top:.7em">
381 <n.poll_submit_button/>
382 &nbsp;&nbsp;
383 <n.poll_total_votes/>
384 </div>
385 <n.poll_description_lines/>
386 </div>
387 </form>
388 <n.call_later value="[n.id/]" param="poll_node_id"/>
389 </then>
390 </n.if.has_poll>
391 </macro>
392
393 <macro name="poll_js" requires="servlet">
394 <n.comment.>
395 This is the javascript code that will update the poll controls and make them available to the users.
396 </n.comment.>
397 <n.param_loop. param="poll_node_id">
398 <n.get_node_from_id. node_id="[n.current_parameter_value/]">
399 <n.set_local_node.this_node />
400 <n.if.visitor.is_registered>
401 <then>
402 <n.poll_option_list.loop.>
403 var input = '<n.local_node.poll_vote_input_field field_id="option[n.option_id/]" index="[n.current_index/]"/>';
404 $('#poll-option-input<n.option_id/>').html(input);
405 </n.poll_option_list.loop.>
406
407 <n.if.poll_has_ended>
408 <then>
409 var input = '<t>This poll is closed.</t>';
410 </then>
411 <else>
412 var txt_vote = "<t>Vote</t>";
413 var input = '<input type="submit" value="' + txt_vote + '"/>';
414 if (!<n.poll_visitor_can_vote/>)
415 input = '<input type="submit" value="' + txt_vote + '" disabled="true"/>';
416 </else>
417 </n.if.poll_has_ended>
418 $('#poll-submit-button<n.id/>').html(input);
419 </then>
420 </n.if.visitor.is_registered>
421
422 <n.if.poll_visitor_can_see_votes>
423 <then>
424 var total_votes = 0;
425 <n.poll_vote_counts.loop.>
426 var text = <n.current_string/> == 1? '(<t>1 vote</t>)' : '(<t><t.number.current_string/> votes</t>)';
427 $('#poll-vote-count<n.option_id/>').html(text);
428 total_votes += <n.current_string/>;
429 </n.poll_vote_counts.loop.>
430 var text = '<t>Total votes:</t> ' + total_votes;
431 $('#poll-total-votes<n.local_node.id/>').html(text).show();
432 </then>
433 </n.if.poll_visitor_can_see_votes>
434 </n.get_node_from_id.>
435 </n.param_loop.>
436 </macro>
437
438 <macro name="poll_submit_button" requires="node">
439 <n.comment.>
440 Creates the submit button. Initially, it is just a span with some default text.
441 The content of the span is updated by javascript code (see "poll_js" macro for more info)
442 </n.comment.>
443 <span id="poll-submit-button[n.id/]" class="bold">
444 <n.if.poll_has_ended>
445 <then><t>This poll is closed.</t></then>
446 <else>
447 <n.login_link.><t>Login to vote</t></n.login_link.>
448 </else>
449 </n.if.poll_has_ended>
450 </span>
451 </macro>
452
453 <macro name="poll_total_votes" requires="node">
454 <n.comment.>
455 The span below shows the total number of votes.
456 This element is updated by javascript code (see "poll_js" macro for more info)
457 </n.comment.>
458 <span id="poll-total-votes[n.id/]" class="shaded-bg-color rounded" style="padding:.2em .4em;display:none"></span>
459 </macro>
460
461 <macro name="poll_description_lines">
462 <div class="weak-color" style="font-size:80%;margin-top:.6em">
463 <n.if.not.poll_allow_vote_change>
464 <then>
465 <t>You cannot change your vote after voting.</t><br/>
466 </then>
467 </n.if.not.poll_allow_vote_change>
468 <n.if.poll_has_end_date>
469 <then>
470 <n.if.poll_has_ended>
471 <then>
472 <t>This poll ended on <t.date.poll_end_date.long_format/>.</t><br/>
473 </then>
474 <else>
475 <t>This poll ends on <t.date.poll_end_date.long_format/>.</t><br/>
476 <n.if.not.poll_show_results_before_end>
477 <then>
478 <t>Results will be shown only after poll has ended.</t><br/>
479 </then>
480 </n.if.not.poll_show_results_before_end>
481 </else>
482 </n.if.poll_has_ended>
483 </then>
484 </n.if.poll_has_end_date>
485 <n.if.not.poll_show_results_before_vote>
486 <then>
487 <t>You have to vote before you can see the results.</t><br/>
488 </then>
489 </n.if.not.poll_show_results_before_vote>
490 </div>
491 </macro>
492
493 <macro name="explain_poll_max_choices">
494 <n.if.not.equal value1="[n.poll_max_choices/]" value2="1">
495 <then>
496 <div class="weak-color" style="font-size:80%">
497 <t>You can select up to <t.number.poll_max_choices/> options.</t>
498 </div>
499 </then>
500 </n.if.not.equal>
501 </macro>
502
503 <macro name="vote_input_type" requires="node">
504 <n.if.equal value1="[n.poll_max_choices/]" value2="1">
505 <then>radio</then>
506 <else>checkbox</else>
507 </n.if.equal>
508 </macro>
509
510 <macro name="poll_vote_input_field" parameters="field_id, index" requires="node">
511 <n.comment.>
512 Creates an input field for a poll option. There are some possibilities
513 depending on the poll configuration and who is the visitor.
514 </n.comment.>
515 <n.if.poll_visitor_has_voted.index>
516 <then>
517 <n.if.poll_visitor_can_vote>
518 <then>
519 <input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" checked="true" />
520 </then>
521 <else>
522 <input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" checked="true" disabled="true" />
523 </else>
524 </n.if.poll_visitor_can_vote>
525 </then>
526 <else>
527 <n.if.poll_visitor_can_vote>
528 <then>
529 <input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]"/>
530 </then>
531 <else>
532 <input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" disabled="true" />
533 </else>
534 </n.if.poll_visitor_can_vote>
535 </else>
536 </n.if.poll_visitor_has_voted.index>
537 </macro>
538
539 <override_macro name="javascript_library" requires="servlet">
540 <n.overridden/>
541 <n.comment.>
542 Javascript to validate and submit a poll vote.
543 </n.comment.>
544 <n.compress.>
545 Nabble.vote = function(nodeId,maxChoices) {
546 var vote_count = $('#poll_form'+nodeId+' input:checked').length;
547 <![CDATA[
548 if (vote_count > maxChoices) {
549 ]]>
550 alert('<t>Please select no more than <t.number>'+maxChoices+'</t.number> options.</t>');
551 return false;
552 } else if (vote_count == 0) {
553 alert('<t>Please select at least one option.</t>');
554 return false;
555 }
556 var params = $('#poll_form'+nodeId).serialize();
557 var call = '/template/NamlServlet.jtp?macro=vote&'+params;
558 var call2 = '/template/NamlServlet.jtp?macro=poll_js&poll_node_id='+nodeId;
559 $.getScript(call, function() {
560 notice('<t>Your vote has been submitted.</t>', 5000, 2000);
561 $.getScript(call2);
562 });
563 return false;
564 };
565 </n.compress.>
566 </override_macro>
567
568 <macro name="vote">
569 <n.get_node_from_id. node_id="[n.get_parameter name='node'/]">
570 <n.poll_vote votes="[n.get_parameter_values name='vote'/]" />
571 </n.get_node_from_id.>
572 </macro>