• Developing new Poll Module for MODx [Now Ready for testing]#

  • banal Reply #1, 4 years ago

    Reply
    Hi all.

    I'm in desperate need for a Poll Module for MODx. I installed the Poll Module by garryn but it doesn't meet my requirements, since i will use it primarily on multilingual sites. I can't see any other alternative, so i started to develop a new Poll Module, loosely based on the work by garryn.
    Let me list the planned features so that you might add ideas/wishes while it's hot...

    Administration (Module for MODX, work in progress)
      [list]
    • A unlimited amount of polls can be created. done
    • Polls can be limited to a certain date-range (by setting a start- and end-date). done
    • Polls can be set active/inactive. done
    • Polls may consist of a variable amount of possible answers. done
    • The user may setup different languages inside the PollManager. done
    • PollManager will keep track of the current "translation status" by looking up if question and answers are translated for all the poll-languages (if a language isn't completely translated, it won't be accessible by the snippet thats responsible for output). done
    [/list]

    Output This is basically where i started.. developing a AJAX based replacement for garryns "PollResults" and "PollVote" Snippets. Now it's just a single snippet, that shows a poll and sends your vote and updates the results via AJAX. This will be extended to work with multiple languages (not too much additional work to do to get there...)
      [list]
    • Voting and displaying of the results using AJAX. done
    • Degrades/works nicely on a browser without JavaScript. done
    • Works with friendly urls (garryns snippet only worked without the "alias-path"). done
    • Very easy to integrate. Just one Snippet that does all. done
    • Hard-coded text can easily be translated to different languages due to external language-files. done
    • Custom JavaScript callback function to build your own "transition" from vote-screen to the results-screen. done
    • Support for multi-language Polls. done
    • Limiting user to one vote per Poll by setting a cookie and/or logging the IP (same as in garryns module). done
    • Complete customization of Poll appearance with own chunks and css stylesheet. done
    [/list]

    Planned features for later release...
      [list]
    • Poll Archive
    [/list]

    Dependencies/Requirements
      [list]
    • MODx 0.9.5 (thats the platform i'm currently developing and testing on)
    • mootools for AJAX functionality
    • PHP5 or higher
    • MySQL Version 4.1 or higher
    [/list]

    Hope this will help somebody when it's done.
    Cheers -- banal

    Edit (2008-01-29)
    Added some features and the Requirements/Dependencies section.

    Edit (2008-02-01)
    Added some snippet features and changed MySQL Requirements

    Edit (2008-02-05)
    The EasyPoll Module is ready for testing. Have a look at the development thread.
    http://modxcms.com/forums/index.php/topic,22457.0.html


  • pixelchutes Reply #2, 4 years ago

    Reply
    @banal,

    I am excited to see what you have come up with! It sounds like a great addition for the community.


  • dflock Reply #3, 4 years ago

    Reply
    This sounds awesome - and saves me the trouble of doing it!!

    I started using the old polls module for a site the other day and decided it needed a re-write but unfortunately I'm totally swamped at the moment. I got as far as re-writing the 2 snippets to output more reasonable markup, adding HTML+CSS bar-chart results and re-doing the CSS.

    This is what the modified poll looks like, if you use my CSS:


    The rounded corners are provided by jQuery and this plugin: http://blue-anvil.com/archives/anti-aliased-rounded-corners-with-jquery
    I'm posting my mods here, in case they're any use to you:

    pollvote snippet:
    <?php
    // +----------------------------------------------------------------------+
    // | Polls Vote Snippet                                                   |
    // +----------------------------------------------------------------------+
    // | Created: February 2006 Version: 3                                    |
    // +----------------------------------------------------------------------+
    //
    // &pollid	- Poll ID to be used
    // &redirect - Document ID to redirect to (eg Results page)
    // &onevote - Boolean value, if true, uses a cookie to allow only one vote per visitor
    // &useip - Boolean value, if true, logs IP addresses and a user can only have a single vote
    // &ovtime - Time limit to set the cookie time, by default expires in a week
    // &ovmessage - Message to display if a user tries to vote more than once if $onevote/$useip is enabled                     |
    // &resultsbutton - Boolean value, if true, show a 'Results' button - MUST have &redirect defined
    //
    // +----------------------------------------------------------------------+
    
    //-- Try to get poll id, if no poll id then no point carrying on
    if (!isset ($pollid))
    	return false;
    
    $pageID = (isset($_GET['id'])) ? intval($_GET['id']) : $modx->config['site_start'];
    
    //-- set form placeholder
    $cur_url = $modx->makeURL($pageID,$modx->getDocumentIdentifier('alias'),'');
    $modx->setPlaceholder('formaction', $cur_url);
    
    //-- setup initial variables
    $output = '';
    $pollid = intval($pollid);
    $redirect = (isset ($redirect)) ? intval($redirect) : '';
    $onevote = (isset ($onevote)) ? $onevote : 1;
    $ovtime = (isset ($ovtime)) ? $ovtime : 608400; // default: expires in one week
    $useip = (isset ($useip)) ? $useip : 0;
    $ovmessage = (isset ($ovmessage)) ? $ovmessage : 'You are only allowed to vote once';
    $resultsbutton = (isset ($resultsbutton)) ? $resultsbutton : 0;
    $fields = array ();
    
    //-- make url for redirect if required
    if ($redirect <> '') {
    	$doc = $modx->getDocument($redirect);
    	$r_id = $doc['id'];
    	$r_alias = $doc['alias'];
    	$url = $modx->makeURL($r_id, $r_alias,'');
    }
    
    //-- setup DB table names
    $polltable = $modx->getFullTableName("polls");
    $choicetable = $modx->getFullTableName("poll_choices");
    $iptable = $modx->getFullTableName("pollip");
    
    //-- if 'Results' button has been selected
    if (isset ($_POST['results'])) {
    	$modx->sendRedirect($url);
    }
    /*
    	// Debug stuff
    	echo '<h1>onevote: '.print_r($onevote).'</h1>';
    	echo '<h1>poll_pollid: '.$_POST['poll_pollid'].'</h1>';
    	echo '<h1>poll_choice_id: '.$_POST['poll_choice_id()'].'</h1>';
    	echo print_r($_POST);
    */
    //-- if vote was submitted increment polls and poll_choices vote counts
    if (isset ($_POST['vote']) && isset ($_POST['poll_choice_id()'])) {
    
    	//-- cookie check - if $onevote, check if visitor is allowed to vote
    	if ($onevote == true) {
    		if (isset ($_COOKIE['poll' . $_POST['poll_pollid']])) {
    			$novote = true;
    		} else {
    			//-- set cookie
    			setcookie('poll' . $_POST['poll_pollid'], 'novote', time() + $ovtime);
    		}
    	}
    
    	//-- ip check, if $useip, check if visitor is allowed to vote
    	if ($useip == true) {
    		$useraddy = userIP();
    		$results = $modx->db->select('*', $iptable, 'ipaddress=\'' . $useraddy . '\' AND pollid=' . $_POST['poll_pollid'], '');
    		if ($modx->db->getRecordCount($results) > 0) {
    			$novote = true;
    		}
    	}
    	if (!isset ($novote)) {
    		$sql = "UPDATE " . $polltable . " SET votes=votes+1 WHERE id=" . $_POST['poll_pollid'] . ";";
    		$modx->db->query($sql);
    		$sql = "UPDATE " . $choicetable . " SET votes=votes+1 WHERE id=" . $_POST['poll_choice_id()'] . ";";
    		$modx->db->query($sql);
    		//-- log ip address if required
    		if ($useip) {
    			$ipsql = 'INSERT INTO ' . $iptable . ' (pollid,ipaddress) VALUES (' . $pollid . ',\'' . $useraddy . '\')';
    			$modx->db->query($ipsql);
    		}
    		//-- send redirect if required
    		if ($redirect <> '') {
    			$modx->sendRedirect($url);
    		} else {
    			//echo '<h1>Results go here</h1>';
    		}
    	}
    	
    }
    
    //-- query for the poll to be displayed and assign local variables
    $where = "id=" . $pollid;
    $rs = $modx->db->select("*", $polltable, $where, "id ASC", "");
    $limit = $modx->db->getRecordCount($rs);
    if ($limit > 0) {
    	$poll = $modx->db->getRow($rs);
    }
    
    //-- query for poll choice results
    $where = "pollid=" . $pollid;
    $choices_rs = $modx->db->select("*", $choicetable, $where, "id ASC", "");
    $limit2 = $modx->db->getRecordCount($choices_rs);
    
    if ($limit > 0) {
    
    	//-- start the CSS poll voting display
    	$output .= '
    					<form class="poll" name="pollvote" method="post" action="[+formaction+]">
    						<input type="hidden" name="poll_pollid" value="' . $poll['id'] . '" />
    							<h3>' . stripslashes($poll['question']).'</h3>
    							<div>
    					';
    
    	//-- loop through choice results
    	for ($i = 0; $i < $limit2; $i++) {
    		$row = $modx->db->getRow($choices_rs);
    
    		//-- display each poll choice
    		$output .= '
    					<input type="radio" id="poll_choice_'.$i.'" name="poll_choice_id()" value="' . $row['id'] . '" />
    					<label for="poll_choice_id">' . stripslashes($row['choice']) . '</label><br />';
    	}
    
    	//-- display buttons
    	$output .= '</div>'."\n".'<input type="submit" name="vote" value="Vote" class="vote" />';
    	if ($resultsbutton == true && $redirect <> '') {
    		$output .= '<input type="submit" name="results" value="Results" class="vote" />';
    	}
    	if (isset ($novote)) {
    		$output .= '<h3 class="poll_reject">' . $ovmessage . '</h3>';
    	}
    
    	$output .= '</form>';
    }
    
    return $output;
    
    //-- gets the visitors ip address
    function userIP() {
    	// This returns the True IP of the client calling the requested page
    	// Checks to see if HTTP_X_FORWARDED_FOR 
    	// has a value then the client is operating via a proxy
    	if ($_SERVER['HTTP_CLIENT_IP'] <> '') {
    		$userIP = $_SERVER['HTTP_CLIENT_IP'];
    	}
    	elseif ($_SERVER['HTTP_X_FORWARDED_FOR'] <> '') {
    		$userIP = $_SERVER['HTTP_X_FORWARDED_FOR'];
    	}
    	elseif ($_SERVER['HTTP_X_FORWARDED'] <> '') {
    		$userIP = $_SERVER['HTTP_X_FORWARDED'];
    	}
    	elseif ($_SERVER['HTTP_FORWARDED_FOR'] <> '') {
    		$userIP = $_SERVER['HTTP_FORWARDED_FOR'];
    	}
    	elseif ($_SERVER['HTTP_FORWARDED_FOR'] <> '') {
    		$userIP = $_SERVER['HTTP_FORWARDED_FOR'];
    	} else {
    		$userIP = $_SERVER['REMOTE_ADDR'];
    	}
    	// return the IP we've figured out:
    	return $userIP;
    }
    ?>


    pollresults snippet:
    <?php
    // +----------------------------------------------------------------------+
    // | Polls Results Snippet                                                |
    // +----------------------------------------------------------------------+
    // | Created: January 2006 Version: 1                                     |
    // +----------------------------------------------------------------------+
    //
    // &pollid  - Poll ID to be used
    // &decimal - Display decimal places, (number is how many dp's to display)
    //
    // +----------------------------------------------------------------------+
    
    //-- Try to get poll id, if no poll id then no point carrying on
    if (!isset ($pollid))
    	return false;
    
    $output = '';
    $pollid = intval($pollid);
    
    $decimal = (isset ($decimal)) ? intval($decimal) : 1;
    
    //-- Setup DB table names
    $polltable = $modx->getFullTableName("polls");
    $choicetable = $modx->getFullTableName("poll_choices");
    //$resultstable = $modx->getFullTableName('poll_results');
    
    //-- Query for the poll to be displayed and assign local variables
    $where = "id=" . $pollid;
    $rs = $modx->db->select("*", $polltable, $where, "id ASC", "");
    $limit = $modx->db->getRecordCount($rs);
    
    
    if ($limit > 0) {
    	$poll = $modx->db->getRow($rs);
    	$name = $poll['name'];
    	$question = $poll['question'];
    	$totalvotes = $poll['votes'];
    }
    
    //-- Query for poll choice results
    $where = "pollid=" . $pollid;
    $choices_rs = $modx->db->select("*", $choicetable, $where, "id ASC", "");
    $climit = $modx->db->getRecordCount($choices_rs);
    
    
    if ($limit > 0) {
    	//-- Start the CSS poll results display
    	$output .= '
    	<div class="corner poll">
    		<h3>' . stripslashes($question) . '</h3>
    		<hr />
    		<dl class="complex_bar">
    		';
    
    	//-- Loop through choice results
    	for ($i = 0; $i < $climit; $i++) {
    		$row = $modx->db->getRow($choices_rs);
    		$choice = $row['choice'];
    		$votes = $row['votes'];
    
    		if (($votes < 1) || ($totalvotes < 1)) {
    			$percent = 0;
    		} else {
    			$percent = ($votes / $totalvotes) * 100;
    		}
    
    		if ($percent > 0) {
    			$percent = number_format($percent, $decimal, '.', '');
    		}
    
    		//-- Display the details of each poll choice
    		$output .= '<dt>'.stripslashes($choice).'</dt>'."\n";
    		$output .= '<dd><div style="width:'.$percent.'%;"><strong>'.$percent.'%</strong></div></dd>'."\n";
    	}
    
    	//-- Display total votes for the poll so far and close the table
    	$output .= '</dl>
    			<br class="clear" />
    			<h4>Total Votes: [' . $totalvotes . ']</h4>
    		</div>
    	';
    }
    
    return $output;
    ?>


    and here is the CSS (which hasn't has much cross browser testing and mostly came from here: http://applestooranges.com/blog/post/css-for-bar-graphs/?id=55:)

    /*
    
    	Poll Styles
    
    */
    
    div.corner {
    	width: 50%;
    	padding: 0 1em;
    	background-color: #e5f3ff;
    	border: 1px solid #CBE7FF;
    }
    .poll input[type="radio"] {
    	margin-bottom: 0.25em;
    }
    .poll h3 {
    	font-size: 100%;
    	line-height: 1.2;
    	margin: 0 auto 0.3em auto;
    }
    .poll h4 {
    	font-size: 85%;
    	line-height: 1.1;
    	margin: 0 auto 0.3em auto;
    }
    div.corner form.poll {
    	margin-bottom: 1em;
    }
    
    /* Basic Bar Graph */
    .graph { 
    	position: relative; /* IE is dumb */
    	width: 200px; 
    	border: 1px solid #B1D632; 
    	padding: 2px; 
    	margin-bottom: .5em;
    }
    .graph .bar { 
    	display: block;	
    	position: relative;
    	background: #B1D632; 
    	text-align: center; 
    	color: #333; 
    	height: 2em; 
    	line-height: 2em;
    }
    /* This extra markup is necessary because IE doesn't want to follow the rules for overflow: visible */
    .graph .bar span { position: absolute; left: 1em; }
    
    /* Complex Bar Graph */
    
    dl.complex_bar dt { 
    	position: relative; /* IE is dumb */
    	clear: both;
    	display: block;
    	height: 20px;
    	font-weight: normal;
    }
    dl.complex_bar dd { 
    	position: relative; /* IE is dumb */
    	display: block;
    	float: left;
    	width: 95%;
    	height: 20px;
    	margin: 0 0 5px;
    	background: #fff;
    	border: 1px solid #CBE7FF;
    }
    
    dl.complex_bar dd div { 
    	background-color: #2A567A;
    	background-color: #8AB1CE;
    	position: relative;
    	height: 20px;
    	width: 75%; 
    	text-align:right;
    }
    dl.complex_bar dd div strong { 
    	position: relative;
    	text-align: left;
    	top: -2px;
    	font-size: 80%;
    	margin-right: 0.5em;
    }
    


    Hope this helps, in some small way
    Cheers,
    Dunc


  • plavet Reply #4, 4 years ago

    Reply
    Wow, thats great banal! I have one wish -to be compatible with PHP 4 if that is not too much trouble Great news about your poll,cant wait to try it out!


  • banal Reply #5, 4 years ago

    Reply
    Hi pixelchutes, dunc and plavet

    Thanks for your replies. The module is coming along nicely. I hope to release a test-version very soon... got other stuff to do at the moment as well.
    I already did a re-write of the Poll Vote Snippet. I'm going to change that in order that the people may customize it's appearance by chunk-templates and own css. So everybody may style it his own way.

    PHP4 is considered deprecated (no longer supported/maintained by the php developers) and i'm not sure if it makes sense to further develop stuff for php4?


  • banal Reply #6, 4 years ago

    Reply
    Hello readers of this post

    I released the EasyPoll Module for testing.
    Read my post in the Development forum to run your own tests
    Please post feedback in the other thread as well!
    http://modxcms.com/forums/index.php/topic,22457.0.html