poll.naml

=== Permission ===

<macro name="create_poll_permission">
	Create_poll
</macro>

<macro name="can_create_poll_in" requires="user" dot_parameter="node_attr">
	<n.set_local_user.this_user />
	<n.set_local_node.node_attr/>
	<n.both>
		<condition1.local_user.is_registered/>
		<condition2.either>
			<condition1.local_user.is_site_admin/>
			<condition2.local_user.has_permission node="[n.local_node/]" permission_node="[n.local_node.app_or_root/]" permission="[n.create_poll_permission/]" />
		</condition2.either>
	</n.both>
</macro>

<override_macro name="all_permissions_list">
	<n.overridden />
	<n.create_poll_permission/>,
</override_macro>

<override_macro name="permission_rows">
	<n.overridden />
	<n.permission_row
		permission = "[n.create_poll_permission/]"
		description="[t]Who can create polls.[/t]"
		administrators_cell = "true"
	/>
</override_macro>

=== Node Message ===

<override_macro name="node_message_as_html" requires="node">
	<n.overridden />

	<n.comment.>
		If this is a topic page (which calls the "message_text" command), then show the poll.
		Otherwise (email messages), print a link to the poll.
	</n.comment.>
	<n.if.is_in_command name="email_message">
		<then.poll_link/>
		<else.poll/>
	</n.if.is_in_command>
</override_macro>

<macro name="poll_link" requires="node">
	<n.if.has_poll>
		<then>
			<div style="background-color:#FFFADB;border:#EDDD79 solid 1px;margin-top:1em;padding:.5em">
				<b><t>This message has a poll</t></b> --  <t>Visit the link below if you want to participate:</t><br/>
				<a href="[n.url/]"><n.url/></a>
			</div>
		</then>
	</n.if.has_poll>
</macro>

<override_macro name="message_as_text" requires="message" unindent="true">
	<n.overridden/>

	<n.if.is_in_command name="node_message_block">
		<then.if.message_block_node.has_poll>
			<then>
				<n.crlf/>[<t>Poll</t>] <t>This message has a poll</t> / <t>Visit the link below if you want to participate:</t>
				<n.message_block_node.url/>
			</then>
		</then.if.message_block_node.has_poll>
	</n.if.is_in_command >
</override_macro>

=== New post page ===

<override_macro name="new_post_extra_fields" requires="node_page">
	<n.overridden/>

	<n.if.both condition1="[n.page_node.is_app/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
		<then>
			<div class="extra-fields">
				<img src="/images/add.png" width="12" height="12" style="margin-top:.2em"/>
				<n.add_poll_form/>
			</div>
		</then>
	</n.if.both>
</override_macro>

<override_macro name="init_new_post_custom_fields">
	<n.overridden/>
	<n.if.visitor.can_create_poll_in.page_node>
		<then>
			<n.poll_max_choices_field.set_value value="1" />
			<n.poll_allow_vote_change_field.set_value value="true" />
			<n.poll_show_results_before_vote_field.set_value value="true" />
			<n.poll_show_results_before_end_field.set_value value="true" />
		</then>
	</n.if.visitor.can_create_poll_in.page_node>
</override_macro>

<override_macro name="save_new_post_custom_fields">
	<n.overridden/>
	<n.if.visitor.can_create_poll_in.page_node>
		<then.new_node.save_new_poll/>
	</n.if.visitor.can_create_poll_in.page_node>
</override_macro>

=== Edit post page ===

<override_macro name="edit_post_extra_fields" requires="node_page">
	<n.overridden/>

	<n.if.both condition1="[n.page_node.parent_node.is_app/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
		<then>
			<div class="extra-fields">
				<img src="/images/add.png" width="12" height="12" style="margin-top:.2em"/>
				<n.if.page_node.has_poll>
					<then.edit_poll_form/>
					<else.add_poll_form/>
				</n.if.page_node.has_poll>
			</div>
		</then>
	</n.if.both>
</override_macro>

<override_macro name="init_edit_post_custom_fields" requires="node_page">
	<n.overridden/>
	<n.if.both condition1="[n.page_node.has_poll/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
		<then>
			<n.poll_max_choices_field.set_value value="[n.page_node.poll_max_choices/]" />
			<n.poll_days_left_field.set_value value="[n.page_node.poll_days_left/]" />
			<n.poll_allow_vote_change_field.set_value value="[n.page_node.poll_allow_vote_change/]" />
			<n.poll_show_results_before_vote_field.set_value value="[n.page_node.poll_show_results_before_vote/]" />
			<n.poll_show_results_before_end_field.set_value value="[n.page_node.poll_show_results_before_end/]" />
		</then>
	</n.if.both>
</override_macro>

<override_macro name="save_edit_post_custom_fields" requires="node_page">
	<n.overridden/>
	<n.if.both condition1="[n.page_node.has_poll/]" condition2="[n.visitor.can_create_poll_in.page_node/]">
		<then>
			<n.edit_poll>
				<poll_max_choices>
					<n.get_int. default="1" exception="max_choices_field_not_integer"><n.poll_max_choices_field.value/></n.get_int.>
				</poll_max_choices>
				<poll_days_left><n.to_null_if. equals=""><n.poll_days_left_field.value/></n.to_null_if.></poll_days_left>
				<poll_allow_vote_change><n.poll_allow_vote_change_field.value/></poll_allow_vote_change>
				<poll_show_results_before_vote><n.poll_show_results_before_vote_field.value/></poll_show_results_before_vote>
				<poll_show_results_before_end><n.poll_show_results_before_end_field.value/></poll_show_results_before_end>
			</n.edit_poll>
		</then>
		<else.page_node.save_new_poll/>
	</n.if.both>
</override_macro>

=== Error Handling ===

<override_macro name="custom_new_node_errors">
	<n.overridden/>
	<n.poll_errors/>
</override_macro>

<override_macro name="custom_edit_post_errors">
	<n.overridden/>
	<n.poll_errors/>
</override_macro>

<macro name="poll_errors" requires="error">
	<n.exception. name="invalid_poll_format">
		<t>Invalid poll parameters.</t>
	</n.exception.>
	<n.exception. name="days_field_not_integer">
		<t>Poll duration must be a non-negative integer or blank.</t>
	</n.exception.>
	<n.exception. name="max_choices_field_not_integer">
		<t>Poll maximum allowed choices must be a non-negative integer or blank.</t>
	</n.exception.>
</macro>

=== Javascript Handler ===

<override_macro name="extra_call_later_handlers">
	<n.overridden/>
	<n.poll_js/>
</override_macro>

=== Other macros ===

<macro name="add_poll_form" requires="node_page">
	<script type="text/javascript">
		function addPoll() {
			$('#poll').show();
			if ( $('#poll-options div').size() == 0 ) {
				addOption(false);
				addOption(false);
			} else
				updateOptions();
			Nabble.resizeFrames();
		};
		function removeOption(e) {
			$(e).parent().remove();
			updateOptions();
			Nabble.resizeFrames();
		};
		function addOption(focus) {
			$('#poll-options').append('<n.javascript_string_encode.poll_option_input_row/>');
			updateOptions();
			if (focus)
				$('#poll-options div input').last().focus();
			Nabble.resizeFrames();
		};
		function updateOptions() {
			var c = 1;
			$('#poll-options div').each(function() {
				$('a,span', this).remove();
				$(this).prepend('<span>'+c+'.</span>');
				if (c++ > 2) {
					$(this).append('<a class="removeOption" href="javascript:void(0)" onclick="removeOption(this)"><t>remove</t></a>');
				}
			});
		};
		function removePoll() {
			$('input[name=poll_question]').val('');
			$('#poll').hide();
		};
		<n.if.not.is_empty.poll_question_field.value>
			<then>
				$(document).ready(function() {
					updateOptions();
				});
			</then>
		</n.if.not.is_empty.poll_question_field.value>
	</script>
	<a href="javascript: void(0)" onclick="addPoll()"><t>Add new poll</t></a>

	<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]">
		<table>
			<tr valign="top">
				<td style="text-align:right;padding-top:.4em"><t>Question:</t></td>
				<td style="padding-left:1.8em"><n.poll_question_field.input type="text" size="40"/></td>
			</tr>
			<tr valign="top">
				<td style="text-align:right;padding-top:.4em"><t>Answers:</t></td>
				<td style="padding-left:.7em">
					<div id="poll-options" style="padding-bottom:.3em">
						<n.get_parameter_values. name="poll_option">
							<n.loop.poll_option_input_row.current_parameter_value/>
						</n.get_parameter_values.>
					</div>
					<a href="javascript: void addOption(true)"><t>Add new answer</t></a>
				</td>
			</tr>
		</table>
		<n.poll_settings/>
		<a href="javascript: void(0)" onclick="removePoll()"><t>Remove Poll</t></a>
	</div>
</macro>

<macro name="edit_poll_form" requires="node_page">
	<script type="text/javascript">
		Nabble.deletePoll = function(nodeId) {
			var call = '/template/NamlServlet.jtp?macro=delete_poll_js&node='+nodeId;
			if (confirm("<t>Delete this poll, including all votes?</t>")) {
				$.getScript(call, function() {
					notice('<t>Poll has been deleted.</t>', 2000, 2000);
					$('#poll').remove();
				});
			}
			return false;
		};
	</script>
	<n.page_node.>
		<t>Poll</t>

		<div id="poll" class="extra-field-details medium-border-color">
			<div class="weak-color" style="padding:.3em">
				<div class="bold"><n.encode.poll_question/></div>
				<ul style="margin:.3em 0">
					<n.poll_option_list.loop.>
						<li><n.current_string/></li>
					</n.poll_option_list.loop.>
				</ul>
				<n.poll_settings />
				<a href="javascript: void(0)" onclick="Nabble.deletePoll([n.id/])"><t>Remove Poll</t></a>
			</div>
		</div>
	</n.page_node.>
</macro>

<macro name="poll_settings">
	<div style="margin: .5em 0 .5em 1em">
		<t>Multiple selections allowed:</t> <n.poll_max_choices_field.input type="text" size="2" maxlength="2"/><br />
		<t>Poll ends after <t.number.poll_days_left_field.input type="text" size="2" maxlength="3"/> days (leave blank for unlimited).</t><br />
		<n.poll_allow_vote_change_field.checkbox/> <label for="poll_allow_vote_change"><t>Allow vote changes</t></label><br />
		<n.poll_show_results_before_vote_field.checkbox/> <label for="poll_show_results_before_vote"><t>Allow viewing results before vote</t></label><br />
		<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>
	</div>
</macro>

<macro name="save_new_poll" requires="node">
	<n.if.not.is_empty.poll_question_field.value>
		<then>
			<n.set_poll>
				<poll_question><n.poll_question_field.value/></poll_question>
				<poll_options><n.get_parameter_values name="poll_option"/></poll_options>
				<poll_max_choices>
					<n.get_int. default="1" exception="max_choices_field_not_integer"><n.poll_max_choices_field.value/></n.get_int.>
				</poll_max_choices>
				<poll_days_left>
					<n.get_int. default="0" exception="days_field_not_integer"><n.poll_days_left_field.value/></n.get_int.>
				</poll_days_left>
				<poll_allow_vote_change><n.poll_allow_vote_change_field.value/></poll_allow_vote_change>
				<poll_show_results_before_vote><n.poll_show_results_before_vote_field.value/></poll_show_results_before_vote>
				<poll_show_results_before_end><n.poll_show_results_before_end_field.value/></poll_show_results_before_end>
			</n.set_poll>
		</then>
	</n.if.not.is_empty.poll_question_field.value>
</macro>

<macro name="poll_question_field" dot_parameter="do">
	<n.field. name="poll_question"><n.do/></n.field.>
</macro>

<macro name="poll_max_choices_field" dot_parameter="do">
	<n.field. name="poll_max_choices"><n.do/></n.field.>
</macro>

<macro name="poll_days_left_field" dot_parameter="do">
	<n.field. name="poll_days_left"><n.do/></n.field.>
</macro>

<macro name="poll_allow_vote_change_field" dot_parameter="do">
	<n.field. name="poll_allow_vote_change"><n.do/></n.field.>
</macro>

<macro name="poll_show_results_before_vote_field" dot_parameter="do">
	<n.field. name="poll_show_results_before_vote"><n.do/></n.field.>
</macro>

<macro name="poll_show_results_before_end_field" dot_parameter="do">
	<n.field. name="poll_show_results_before_end"><n.do/></n.field.>
</macro>

<macro name="poll_option_input_row" dot_parameter="poll_option">
	<div class="nowrap">
		<input type="text" class="poll_option" name="poll_option" size="30" value="[n.hide_null.poll_option/]" />
	</div>
</macro>

<macro name="delete_poll_js">
	<n.get_node_from_id. node_id="[n.get_parameter name='node'/]">
		<n.delete_poll />
	</n.get_node_from_id.>
</macro>

<macro name="poll" requires="node">
	<n.comment.>
		Builds the poll interface. Since some options depend on the current visitor, we use javascript
		to set up some fields. Please look at the "poll_js" macro in order to understand how this poll UI is updated.
	</n.comment.>
	<n.if.has_poll>
		<then>
			<form method="POST" id="poll_form[n.id/]" onsubmit="return Nabble.vote([n.id/],[n.poll_max_choices/]);" accept-charset="UTF-8" >
				<input type="hidden" name="node" value="[n.id/]" />

				<div class="medium-border-color border2 rounded" style="margin-top:1em;padding:1em">
					<div class="big-title second-font">
						<n.encode.poll_question/>
					</div>
					<n.explain_poll_max_choices/>

					<n.poll_option_list.loop.>
						<div style="margin:.4em 0 0 1em">
							<span id="poll-option-input[n.option_id/]"></span>
							<label for="option[n.option_id/]"><n.encode.current_string/></label>
							<span id="poll-vote-count[n.option_id/]" class="weak-color" style="font-size:80%"></span>
						</div>
					</n.poll_option_list.loop.>

					<div style="margin-top:.7em">
						<n.poll_submit_button/>
						&nbsp;&nbsp;
						<n.poll_total_votes/>
					</div>
					<n.poll_description_lines/>
				</div>
			</form>
			<n.call_later value="[n.id/]" param="poll_node_id"/>
		</then>
	</n.if.has_poll>
</macro>

<macro name="poll_js" requires="servlet">
	<n.comment.>
		This is the javascript code that will update the poll controls and make them available to the users.
	</n.comment.>
	<n.param_loop. param="poll_node_id">
		<n.get_node_from_id. node_id="[n.current_parameter_value/]">
			<n.set_local_node.this_node />
			<n.if.visitor.is_registered>
				<then>
					<n.poll_option_list.loop.>
						var input = '<n.local_node.poll_vote_input_field field_id="option[n.option_id/]" index="[n.current_index/]"/>';
						$('#poll-option-input<n.option_id/>').html(input);
					</n.poll_option_list.loop.>

					<n.if.poll_has_ended>
						<then>
							var input = '<t>This poll is closed.</t>';
						</then>
						<else>
							var txt_vote = "<t>Vote</t>";
							var input = '<input type="submit" value="' + txt_vote + '"/>';
							if (!<n.poll_visitor_can_vote/>)
								input = '<input type="submit" value="' + txt_vote + '" disabled="true"/>';
						</else>
					</n.if.poll_has_ended>
					$('#poll-submit-button<n.id/>').html(input);
				</then>
			</n.if.visitor.is_registered>

			<n.if.poll_visitor_can_see_votes>
				<then>
					var total_votes = 0;
					<n.poll_vote_counts.loop.>
						var text = <n.current_string/> == 1? '(<t>1 vote</t>)' : '(<t><t.number.current_string/> votes</t>)';
						$('#poll-vote-count<n.option_id/>').html(text);
						total_votes += <n.current_string/>;
					</n.poll_vote_counts.loop.>
					var text = '<t>Total votes:</t> ' + total_votes;
					$('#poll-total-votes<n.local_node.id/>').html(text).show();
				</then>
			</n.if.poll_visitor_can_see_votes>
		</n.get_node_from_id.>
	</n.param_loop.>
</macro>

<macro name="poll_submit_button" requires="node">
	<n.comment.>
		Creates the submit button. Initially, it is just a span with some default text.
		The content of the span is updated by javascript code (see "poll_js" macro for more info)
	</n.comment.>
	<span id="poll-submit-button[n.id/]" class="bold">
		<n.if.poll_has_ended>
			<then><t>This poll is closed.</t></then>
			<else>
				<n.login_link.><t>Login to vote</t></n.login_link.>
			</else>
		</n.if.poll_has_ended>
	</span>
</macro>

<macro name="poll_total_votes" requires="node">
	<n.comment.>
		The span below shows the total number of votes.
		This element is updated by javascript code (see "poll_js" macro for more info)
	</n.comment.>
	<span id="poll-total-votes[n.id/]" class="shaded-bg-color rounded" style="padding:.2em .4em;display:none"></span>
</macro>

<macro name="poll_description_lines">
	<div class="weak-color" style="font-size:80%;margin-top:.6em">
		<n.if.not.poll_allow_vote_change>
			<then>
				<t>You cannot change your vote after voting.</t><br/>
			</then>
		</n.if.not.poll_allow_vote_change>
		<n.if.poll_has_end_date>
			<then>
				<n.if.poll_has_ended>
					<then>
						<t>This poll ended on <t.date.poll_end_date.long_format/>.</t><br/>
					</then>
					<else>
						<t>This poll ends on <t.date.poll_end_date.long_format/>.</t><br/>
						<n.if.not.poll_show_results_before_end>
							<then>
								<t>Results will be shown only after poll has ended.</t><br/>
							</then>
						</n.if.not.poll_show_results_before_end>
					</else>
				</n.if.poll_has_ended>
			</then>
		</n.if.poll_has_end_date>
		<n.if.not.poll_show_results_before_vote>
			<then>
				<t>You have to vote before you can see the results.</t><br/>
			</then>
		</n.if.not.poll_show_results_before_vote>
	</div>
</macro>

<macro name="explain_poll_max_choices">
	<n.if.not.equal value1="[n.poll_max_choices/]" value2="1">
		<then>
			<div class="weak-color" style="font-size:80%">
				<t>You can select up to <t.number.poll_max_choices/> options.</t>
			</div>
		</then>
	</n.if.not.equal>
</macro>

<macro name="vote_input_type" requires="node">
	<n.if.equal value1="[n.poll_max_choices/]" value2="1">
		<then>radio</then>
		<else>checkbox</else>
	</n.if.equal>
</macro>

<macro name="poll_vote_input_field" parameters="field_id, index" requires="node">
	<n.comment.>
		Creates an input field for a poll option. There are some possibilities
		depending on the poll configuration and who is the visitor.
	</n.comment.>
	<n.if.poll_visitor_has_voted.index>
		<then>
			<n.if.poll_visitor_can_vote>
				<then>
					<input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" checked="true" />
				</then>
				<else>
					<input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" checked="true" disabled="true" />
				</else>
			</n.if.poll_visitor_can_vote>
		</then>
		<else>
			<n.if.poll_visitor_can_vote>
				<then>
					<input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]"/>
				</then>
				<else>
					<input id="[n.field_id/]" type="[n.vote_input_type/]" name="vote" value="[n.index/]" disabled="true" />
				</else>
			</n.if.poll_visitor_can_vote>
		</else>
	</n.if.poll_visitor_has_voted.index>
</macro>

<override_macro name="javascript_library" requires="servlet">
	<n.overridden/>
	<n.comment.>
		Javascript to validate and submit a poll vote.
	</n.comment.>
	<n.compress.>
		Nabble.vote = function(nodeId,maxChoices) {
			var vote_count = $('#poll_form'+nodeId+' input:checked').length;
			<![CDATA[
			if (vote_count > maxChoices) {
			]]>
				alert('<t>Please select no more than <t.number>'+maxChoices+'</t.number> options.</t>');
				return false;
			} else if (vote_count == 0) {
				alert('<t>Please select at least one option.</t>');
				return false;
			}
			var params = $('#poll_form'+nodeId).serialize();
			var call = '/template/NamlServlet.jtp?macro=vote&'+params;
			var call2 = '/template/NamlServlet.jtp?macro=poll_js&poll_node_id='+nodeId;
			$.getScript(call, function() {
				notice('<t>Your vote has been submitted.</t>', 5000, 2000);
				$.getScript(call2);
			});
			return false;
		};
	</n.compress.>
</override_macro>

<macro name="vote">
	<n.get_node_from_id. node_id="[n.get_parameter name='node'/]">
		<n.poll_vote votes="[n.get_parameter_values name='vote'/]" />
	</n.get_node_from_id.>
</macro>