Template:Simplepoll

Table of contents
No headers
// SimplePoll
//    by neilw, 2009
//
//    Version history:
//        1.00    20-August-2009        First published version
//        1.01    26-August-2009        Each poll uses a different channel and __request arg so
//                                          multiple polls can coexist on the same page
//                                      Changed display style of poll results a bit
//                                      Added "bar" argument
//
// Usage:  SimplePoll(question:str, answers:list of str, name:str?, path:str?, closed:str? or bool?, bar:str?)
//    question:  The poll question
//    answers:   List of possible answers
//    name:      (optional) Unique name for the poll, in case you want to store multiple poll results
//                on the same page properties
//    path:      (optional) Path to page where properties will be stored.  Must be readable/writable
//                by voters!
//    closed:    (optional) Either "true" to close the poll, or a valid date (GMT!!!!) string indicating
//                when the poll should close
//    bar:       (optional) color of results bars (default: "#B00000")
//

//
// get initialized
//
var question = $0 ?? $question ?? "";
if (question is not str && question is not xml) <p>"WARNING: question must be string or xml"</p>;

var answers = $1 ?? $answers ?? [];
if (#answers == 0) <p>"WARNING: You have provided no answers.  Not much of a poll!"</p>;

var poll_name = $2 ?? $name ?? "polldata";
if (poll_name is not str) {
    <p>"ERROR: name must be a string.  Reverting to 'polldata'"</p>;
    let poll_name = "polldata";
}
var poll_arg = "poll_"..poll_name;

var path = $3 ?? $path;
var p = (path == nil ? page : wiki.getpage(path));
if (p == nil) <p>"ERROR: can't find page with data store"</p>;

var closed = $4 ?? $closed ?? false;
var closing_time = false;
if (closed is not bool) {
    if (!date.isvalid(closed)) {
        <p>"ERROR: 'closed' is not a valid date; assuming poll is open"</p>;
        let closed = false;
    }
    else {      // convert to local time
        let closing_time = date.format(closed,"r");
        let closed = date.compare(date.now, closing_time) > 0;
    }
}

var bar = $5 ?? $bar ?? "#B00000";

var viewURI = page.uri & { (poll_arg):"view" };
var editURI = page.uri & { (poll_arg):"edit" };

// Fetch the data store
var data = json.parse(p.properties[poll_name].text ?? '{}');
if (data is not map)
    <p>"ERROR: poll data store exists but has the wrong type ('"..typeof(data).."' instead of 'map')"</p>;

// Now figure out what to show
var vote = (data[user.name] ?? {}).poll;
var can_vote = !closed && !user.anonymous && wiki.pagepermissions(path).update;
var has_voted = (vote != nil);
var showform = can_vote && (!has_voted || __request.args[poll_arg] == "edit") && __request.args[poll_arg] != "view";
<table align="center" cellpadding="5" style="background-color:#F4F4F4; border:2px solid #808080">
    <tr><td align="center" style="font-weight:bold; padding-bottom:10px"> question </td></tr>;
    if (showform) {     // Allow user to enter or edit poll response(s)
        <tr><td align="center"><form id=(@form)>
            <ul style="text-align:left">
                foreach (var opt in answers) <li style="list-style:none">
                    <input type="radio" name="poll"
                        value=(__index) checked=(has_voted && vote==__index ? 'checked' : nil)> " "..opt.." " </input>
                </li>;
            </ul>
            <span style="text-align:center; padding-top:10px">
                <input type="button" value="투표" ctor="when($this.click) {
                    var m = { };
                    Deki.$('form#' + {{@form}} + ' input').each(function() {
                        if ($(this).attr('name') == 'poll' && $(this).attr('checked')) m['poll'] = Deki.$(this).val();
                    });
                    Deki.publish({{@channel}}, { {{user.name}}:m }); }"/>; " ";
                <a href=(viewURI)> <span style="font-size:smaller">"결과보기"</span> </a>
            </span>
            if (closing_time) {
                <br />;
                <span style="font-size:smaller"> "Poll closes on "..
                    date.format(string.substr(date.changetimezone(closing_time, user.timezone),0,-6),"MMM d, yyyy, h:mm tt");
                </span>;
            }
        </form></td></tr>;
    }
    else {              // Display poll results
        // Calculate results
        var total = #data;
        <tr><td align="center">
            <span style="font-size:smaller"> total .. " votes counted" </span>;
            <table>
                foreach (var i in num.series(0,#answers-1)) {
                    var result = #map.select(data, "$.value.poll == "..i);
                    var pct = num.round(100*result/num.max(total,1),1);
                    var width = num.round(2 * pct, 0);
                    <tr>
                        <td> answers[i] </td>
                        <td>
                            <img src="/skins/common/icons/icon-trans.gif" style=("background-color:"..bar) height="10" width=(width) />
                            <img src="/skins/common/icons/icon-trans.gif" style="background-color:#C0C0C0" height="10" width=(200-width) />
                            " " .. pct .. "% (" .. result .. ")"
                        </td>
                    </tr>;
                }
            </table>
            <span style="text-align:center; padding-top:10px; font-size:smaller">
                if (can_vote) <a href=(editURI)> has_voted ? "change my vote" : "vote in this poll" </a>;
                else if (closed) "this poll is closed";
            </span>;
        </td></tr>;
    }
</table>;
// Code to update the page properties, largely cribbed from SteveB's "UpdateStore" template
dekiapi();
var store = poll_name;
<script type="text/javascript"> "
    Deki.subscribe('"..@channel.."', null, function(c, m, d) {
        var closed = " .. json.emit(closed) .. ";
        var closing_time = " .. json.emit(closing_time) .. ";
        var d = new Date();
        if (closed || (closing_time && d.getTime() > Date.parse(closing_time))) {
            alert('Poll is now closed, sorry!');
            window.location.href = '" .. page.uri .. "';
            return;
        }
        var prop = 'urn:custom.mindtouch.com#'  + '"..store.."';
        Deki.Api.ReadPageProperty(null, prop, function(result) {
            var data = eval('(' + (result.value || '{}') + ')');
            for (var k in m) data[k] = m[k];
            if(result.etag)
                Deki.Api.UpdatePageProperty(result.href, YAHOO.lang.JSON.stringify(data), result.etag,
                    function() { window.location.href = '" .. page.uri .. "'; },
                    function(result) { alert('Error updating store (status: '+result.status+' - '+result.text+')'); }
                );
            else
                Deki.Api.CreatePageProperty(null, prop, YAHOO.lang.JSON.stringify(data),
                    function() { window.location.href = '" .. page.uri .. "'; },
                    function(result) { alert('Error creating store (status: '+result.status+' - '+result.text+')'); }
                );
        },
        function(result) { alert('An error occurred reading the store (status: ' +
            result.status + ' - ' + result.text + ')'); }
        );
    }, null);
" </script>
Tag page