Simple polling

Overview

This rule provides a very simple widget that can be added to any container, presenting users with a question and list of options then displaying the results after they choose.

The Rule Component

The component is placed in /packages/rules/ in your project or plugin.

rulePoll.cfc
<cfcomponent displayname="Utility: Poll" hint="A simple polling rule" extends="farcry.core.packages.rules.rules" output="false">
	<cfproperty ftSeq="1" ftWizardStep="" ftFieldset="Question" name="question" type="longchar" ftLabel="Question" hint="The poll question" ftType="string" />
	
	<cfproperty ftSeq="11" ftWizardStep="" ftFieldset="Option 1" name="answer1" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="12" ftWizardStep="" ftFieldset="Option 1" name="result1" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="13" ftWizardStep="" ftFieldset="Option 2" name="answer2" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="14" ftWizardStep="" ftFieldset="Option 2" name="result2" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="15" ftWizardStep="" ftFieldset="Option 3" name="answer3" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="16" ftWizardStep="" ftFieldset="Option 3" name="result3" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="17" ftWizardStep="" ftFieldset="Option 4" name="answer4" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="18" ftWizardStep="" ftFieldset="Option 4" name="result4" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="19" ftWizardStep="" ftFieldset="Option 5" name="answer5" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="20" ftWizardStep="" ftFieldset="Option 5" name="result5" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="21" ftWizardStep="" ftFieldset="Option 6" name="answer6" type="longchar" ftLabel="Answer" hint="Poll answer" ftType="string" />
	<cfproperty ftSeq="22" ftWizardStep="" ftFieldset="Option 6" name="result6" type="string" ftLabel="Result" hint="Poll result" ftType="integer" ftDefault="0" />
	
	<cfproperty ftSeq="31" ftWizardStep="" ftFieldset="Submitting" name="submitlabel" type="string" ftLabel="Submit button label" hint="The label used for the poll submit button" ftType="string" ftDefault="Submit" />
	
</cfcomponent>

The Webskin

The webskin is placed in /webskin/rulePoll/ in your project or plugin.

execute.cfm
<cfsetting enablecfoutputonly="true" />
<!--- @@displayname: Execute Poll --->
<!--- @@description:  --->

<cfimport taglib="/farcry/core/tags/formtools" prefix="ft" />
<cfimport taglib="/farcry/core/tags/webskin" prefix="skin" />

<cfset pollid = replace(stObj.objectid,'-','','ALL') />

<cfparam name="url.showresult" default="" />


<!--- Process poll --->
<ft:processform action="#stObj.submitlabel#">
	<cfif structkeyexists(form,pollid)>
		<cfset stObj["result#form[pollid]#"] = stObj["result#form[pollid]#"]+1 />
		<!--- 
		set user to anonymous; 
		otherwise setData() will try and pick up the active session requiring users to login 
		--->
		<cfset setData(stProperties=stObj,user="anonymous") />
		
		<cfparam name="session.polls" default="#structnew()#" />
		<cfset session.polls[pollid] = true />
	</cfif>
</ft:processform>

<ft:processform action="View Results #pollid#">
	<cfset url.showresult = pollid />
</ft:processform>


<!--- View poll --->
<cfif url.showresult eq pollid or structkeyexists(session,"polls") and structkeyexists(session.polls,pollid) and session.polls[pollid]>
	<!--- User has already answered the poll, show results --->
	
	<!--- Calculate total --->
	<cfset total = 0 />
	<cfloop from="1" to="6" index="i">
		<cfset total = total + stObj["result#i#"] />
	</cfloop>
	
	<cfoutput>
		<div class="poll">
			<p class="pollquestion">#stObj.question#</p>
	</cfoutput>
	
	<cfloop from="1" to="6" index="i">
		<cfif len(trim(stObj["answer#i#"]))>
			<cfoutput>
				<table class="pollresult">
					<tr>
						<td class="pollanswer" colspan="2">#stObj["answer#i#"]#</td>
					</tr>
					<tr>
						<td class="resultbar" width="#round(stObj['result#i#']/total*70)#%"></td>
						<td class="resultlabel">#round(stObj['result#i#']/total*100)#%</td>
					</tr>
				</table>
			</cfoutput>
		</cfif>
	</cfloop>
	
	<cfif url.showresult eq pollid>
		<skin:buildLink objectid="#request.stObj.objectid#"><cfoutput>Return to Poll</cfoutput></skin:buildLink>
	</cfif>
	
	<cfoutput>
		</div>
	</cfoutput>
<cfelse>
	<!--- User has not answered the poll, show the poll form --->
	
	<ft:form>
		<cfoutput>
			<div class="poll">
				<p class="pollquestion">#stObj.question#</p>
				<table class="pollanswers">
		</cfoutput>
		
		<cfloop from="1" to="6" index="i">
			
			<cfif len(trim(stObj["answer#i#"]))>
				<cfoutput>
					<tr class="pollanswer">
						<td class="answerradio" valign="top"><input class="answerinput" type="radio" value="#i#" name="#pollid#" value="#i#" id="#pollid#_#i#" /></td>
						<td class="answerlabel"><label class="answerlabel" for="#pollid#_#i#">#stObj["answer#i#"]#</label></td>
					</tr>
				</cfoutput>
			</cfif>
		</cfloop>
		
		<cfoutput>
				</table>
		</cfoutput>
		
		<skin:buildLink objectid="#request.stObj.objectid#" urlParameters="showresult=#pollid#"><cfoutput>View Results</cfoutput></skin:buildLink>
		<ft:button value="#stObj.submitlabel#" size="small" />
		
		<cfoutput>
			</div>
		</cfoutput>
	</ft:form>
</cfif>


<cfsetting enablecfoutputonly="false" />

The CSS

The css can be placed in /www/css/ in your project or plugin. If you put it in your plugin you should have a virtual directory named after the plugin pointing to the plugin's /www/ directory. Add a link to this stylesheet to your template header.

style.css
/*
rulePoll
*/
div.poll { font-size:93%; }
	p.pollquestion { margin:0; font-size:93%; font-weight:bold; }
	
	table.pollresult {}
		td.pollanswer { padding-top: 5px; }
		td.resultbar { background-color:#CE171F; }
		td.resultlabel { padding-left:3px; }
	
	table.pollanswers
		tr.pollanswer td { padding-top:5px; }
			td.answerradio {}
			td.answerlabel {}
				td.answerlabel label.answerlabel { width:auto; text-align:left; }