Limitation: this system is only useful for asking one question at a time (i.e., if you have N questions to ask, each with M possible answers, you need to create N separate polls).
create table polls ( poll_id integer not null primary key, name varchar(100), description varchar(4000), start_date date, end_date date, require_registration_p char(1) default 'f' check (require_registration_p in ('t','f')) );Any number of polls can be active at a time. Whether a poll is active depends on the start_date and end_date. To disable a poll, use the admin pages to set the end_date into the past or the start_date into the future. Name is a short name used to label pages and links, while description is a longer description that is displayed with the votes and results.
require_registration_p indicates whether a user has to be a registered user (have an entry in the users table) before they can vote. Making registration required implies that the user can only vote once for each poll.
If registration is not required, we can't distinguish one vote from another, so users can vote any number of times for each poll. In that case, it wouldn't be fair to let unregistered users vote any number of times and registered users vote only once, so we just let them all vote any number of times. Why not restrict by IP address then in this case? IP masquedaring hides many people behind one IP address (meaning we would prevent legal votes), and AOL users get a random IP address (meaning obnoxious folks can vote multiple times)
create table poll_choices ( choice_id integer not null primary key, poll_id references polls, label varchar(500) );This holds the choices that users can vote on.
create table poll_user_choices ( poll_id references polls, choice_id references poll_choices, user_id references users, ip_address varchar(50), choice_date date );Each user vote is recorded here. If there is no user ID (meaning that the voter is not a registered user), the user_id in this table is NULL. Even though we don't use the IP address to control user voting, we keep it around in case some obnoxious person stuffs the ballot box. We can go into SQL*Plus and undo the damage.
There are two categories of templates in use: those that display the polls, the choices, and the results; and those that say "you did something wrong".
<%= $variable >
units. There are three
functions provided that take the database-driven output (e.g. the currently
active polls) and some customization information and then return a blob of
html for inclusion. Designers would do something like
<%= [poll_display -item_start "<tr><td>" -item_end "</tr>" -style_start "<font color=white><i>" -style_end "</i></font>" $choices] %>
So why not use ad_register_styletag
and include tweakable parameters
in the tagset? ADPs have a severe limitation in that html <tags> embedded
in the styletag cause ADPs to premature end the parsing of the tagset. That is, this:
<my-tag foo="<b>" bar="<li>" baz="<font face=happy>"></my-tag>
has a tagset that consists of "foo=<b"
, and a content-string of
everything else.
To allow customization of each line of database-driven output, say whether to
arrange the available choices in an <ul>
or in
a table, not being able to include arbitrary html is major loss.
Instead, three functions are provided. Each takes optional parameterized arguments and a required blob of data which is passed to the template ADP by the Tcl pages in /poll.
poll_front_page ?optional arguments? polls
Use this function to control the display on the "index" page (the top-level page you get when going to /poll). If invoked without optional arguments, the polls are arranged in an unordered list. The "polls" variable is provided to the index template.This code:
<ul> <%= [poll_front_page $polls] %> </ul>results in this:While this:What Would Rolf Do? What's Your Favorite Color? (registration required) <table border=1 bgcolor=white> <%= [poll_front_page -item_start "<tr><td>" -style_start "<font color=green>" -style_end "</font>" -require_registration_start "<td>" -require_registration_text "<font color=green>Registration Mandatory!!!</font>" $polls] %> </table>results in this:
What Would Rolf Do? What's Your Favorite Color? Registration Mandatory!!! The arguments:
- -item_start: text to be emitted before each poll name. Usual uses are <li> or <tr><td> Defaults to <li>
- -item_end: text to be emitted after each poll name.
- -style_start: text to be emitted immediately before the poll name. Here'd you put <font> directives or other text formatting commands
- -style_end: text to be emitted immediately after the poll name. You'd put </font> tags and the like here.
- -require_registration_text: what to display if the poll requires registration. Defaults to "There are no currently active polls"
- -require_registraion_start: text to be emitted immediately before the require_registration_text. You can put text formatting and/or html structural tags (like making a new table row or column before the require_registration_text)
- -require_registration_end: text to be emitted immediately after the require_registration_text.
poll_display ?optional arguments? choices
Use this function to control the display of an individual poll. If invoked without optional arguments, the poll choices are arranged in an unordered list. The "choices" variable is provided to the one-poll template. This code:<ul> <%= [poll_display $choices] %> </ul>results in this:While this:<table border=2 text=white bgcolor=black> <%= [poll_display -item_start "<tr><td>" -item_end "</tr>" -style_start "<font color=white><i>" -style_end "</i></font>" $choices] %> </table>results in this:The arguments:
- -item_start: text to be emitted before each choice name. Usual uses are <li> or <tr><td> Defaults to <li>
- -item_end: text to be emitted after each choice name.
- -style_start: text to be emitted immediately before the choice name. Here'd you put <font> directives or other text formatting commands
- -style_end: text to be emitted immediately after the choice name. You'd put </font> tags and the like here.
- -no_choices: text to be emitted if there are no choices in the poll. This is really an adimistration/configuration problem. Defaults to "No Choices Specified"
poll_results ?optional arguments? results
Use this function to control the display on the "results" page. This function is a wrapper around gr_sieways_bar_chart which simplifies the API. This code<%= [poll_results $values] %>results in this:While this:
Eat Cheese 40 Go Skateboarding 26.7 Wait for Cable Modem installer 33.3 <table bgcolor=pink border=3> <tr> <td width=300> <%= [poll_results -bar_color purple -display_values_p "f" -display_scale_p "f" -bar_height 30 $values] %> </table>results in this:
Eat Cheese Go Skateboarding Wait for Cable Modem installer The arguments:
Note that some specific customizations aren't possible now, such as putting the total number of votes after each bar on the chart, and using multiple pictures for each bar (like what the Slashdot poll does) due to limitations in the API of gr_sideways_bar_chart. This is something that needs to be fixed eventually.
- -bar_color: what color to display the bar. Can be blue, dark-green, purple, red, black, orange, or medium-blue. Defaults to blue.
- -display_values_p: a "t" or "f" value. Should the percentages of the vote be displayed. Defaults to "t"
- -display_scale_p: a "t" or "f" value. Should the "0 to 100" scale be displayed at the top of the results. Defaults to "t"
- -bar_height: how tall to make the bars. Defaults to 15.