fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2010-09-07 03:08 am

[dw-free] AJAXify polls

[commit: http://hg.dwscoalition.org/dw-free/rev/677ac59981c5]

http://bugs.dwscoalition.org/show_bug.cgi?id=1590

Submit poll results without reloading the page.

Patch by [personal profile] jportela.

Files modified:
  • cgi-bin/LJ/Poll.pm
  • cgi-bin/ljdefaults.pl
  • htdocs/js/livejournal.js
  • htdocs/tools/endpoints/pollvote.bml
--------------------------------------------------------------------------------
diff -r 1feed31d5892 -r 677ac59981c5 cgi-bin/LJ/Poll.pm
--- a/cgi-bin/LJ/Poll.pm	Tue Sep 07 10:56:35 2010 +0800
+++ b/cgi-bin/LJ/Poll.pm	Tue Sep 07 11:08:22 2010 +0800
@@ -881,9 +881,10 @@ sub render {
             $preval{$qid} = $value;
         }
 
-        $ret .= "<form action='$LJ::SITEROOT/poll/?id=$pollid' method='post'>";
+        $ret .= "<div id='poll-$pollid-container'><form class='LJ_PollForm' action='$LJ::SITEROOT/poll/?id=$pollid' method='post'>";
         $ret .= LJ::form_auth();
         $ret .= LJ::html_hidden('pollid', $pollid);
+        $ret .= LJ::html_hidden('id', $pollid);    #for the ajax request
     }
 
     $ret .= "<b><a href='$LJ::SITEROOT/poll/?id=$pollid'>" . LJ::Lang::ml('poll.pollnum', { 'num' => $pollid }) . "</a></b> ";
@@ -1120,7 +1121,7 @@ sub render {
         $ret .= LJ::html_submit(
                                 'poll-submit',
                                 LJ::Lang::ml('poll.submit'),
-                                {class => 'LJ_PollSubmit'}) . "</form>\n";;
+                                {class => 'LJ_PollSubmit'}) . "</form></div>\n";;
     }
 
     return $ret;
diff -r 1feed31d5892 -r 677ac59981c5 cgi-bin/ljdefaults.pl
--- a/cgi-bin/ljdefaults.pl	Tue Sep 07 10:56:35 2010 +0800
+++ b/cgi-bin/ljdefaults.pl	Tue Sep 07 11:08:22 2010 +0800
@@ -272,6 +272,7 @@ no strict "vars";
                        trans_save     => "tools/endpoints/trans_save.bml",
                        dirsearch      => "tools/endpoints/directorysearch.bml",
                        poll           => "tools/endpoints/poll.bml",
+                       pollvote       => "tools/endpoints/pollvote.bml",
                        jobstatus      => "tools/endpoints/jobstatus.bml",
                        widget         => "tools/endpoints/widget.bml",
                        multisearch    => "tools/endpoints/multisearch.bml",
diff -r 1feed31d5892 -r 677ac59981c5 htdocs/js/livejournal.js
--- a/htdocs/js/livejournal.js	Tue Sep 07 10:56:35 2010 +0800
+++ b/htdocs/js/livejournal.js	Tue Sep 07 11:08:22 2010 +0800
@@ -200,6 +200,107 @@ LiveJournal.initPolls = function () {
     Array.prototype.forEach.call(pollLinks, function (pollLink) {
         DOM.addEventListener(pollLink, "click", LiveJournal.pollAnswerLinkClicked.bindEventListener(pollLink));
     });
+
+    var pollButtons = DOM.getElementsByTagAndClassName(document, 'input', "LJ_PollSubmit") || []; 
+    
+    // attaches a click handler to all poll submit buttons
+    Array.prototype.forEach.call(pollButtons, function (pollButton) {
+        DOM.addEventListener(pollButton, "click", LiveJournal.pollButtonClicked.bindEventListener(pollButton));
+    });
+    
+    var pollForms = DOM.getElementsByTagAndClassName(document, 'form', "LJ_PollForm") || []; 
+    
+    // attach submit handlers to each poll form
+    Array.prototype.forEach.call(pollForms, function (pollForm) {
+        DOM.addEventListener(pollForm, "submit", LiveJournal.pollFormSubmitted.bindEventListener(pollForm));
+    });
+};
+
+LiveJournal.pollButtonClicked = function (e) {  
+    // shows the hourglass. The submit event wouldn't update the coordinates, so the click event
+    // had to be used for this
+    if (!PollPages.hourglass) {
+        var coords = DOM.getAbsoluteCursorPosition(e);
+        PollPages.hourglass = new Hourglass();
+        PollPages.hourglass.init();
+        PollPages.hourglass.hourglass_at(coords.x, coords.y+25);    // 25 is added to the y axis, otherwise the button would cover it
+        PollPages.e = e;
+    }
+    
+    return true;
+};
+
+LiveJournal.pollFormSubmitted = function (e) {
+    Event.stop(e);
+    
+    var formObject = LiveJournal.getFormObject(this);  //gets the form ready for serialization
+
+    var opts = {
+        "url"    : LiveJournal.getAjaxUrl("pollvote"),
+        "method" : "POST",
+        "data"   : HTTPReq.formEncoded(formObject),
+        "onData" : LiveJournal.pollVoteSubmitted,
+        "onError": LiveJournal.pollVoteSubmitted
+    };
+
+    HTTPReq.getJSON(opts);
+    
+    return false;
+};
+
+LiveJournal.pollVoteSubmitted = function (results) {
+    if (! results) return false;
+
+    if (PollPages.hourglass) {
+        PollPages.hourglass.hide();
+        PollPages.hourglass = null;
+    }
+    
+    if (results.error) return LiveJournal.ajaxError(results.error);
+    
+    resultsDiv = document.getElementById("poll-"+results.pollid+"-container");
+
+    resultsDiv.innerHTML = results.results_html;
+    
+    LiveJournal.initPolls();
+};
+
+LiveJournal.getFormObject = function (form) {
+
+    var inputs = form.getElementsByTagName("input");
+    
+    var formObject = new Object();
+    
+    for (var i = 0; i < inputs.length; i++) {
+        var obj = inputs[i];
+        
+        if (obj.type == "checkbox") {
+            if (!formObject[obj.name]) {
+                formObject[obj.name] = new Array();
+            }
+            if (obj.checked)
+                formObject[obj.name].push(obj.value);
+        }
+        else if (obj.type == "radio") {
+           if (obj.checked) {
+              formObject[obj.name] = obj.value;
+           }
+        }
+        else 
+        {
+            formObject[obj.name] = obj.value;
+        }
+    }
+    
+    var selects = form.getElementsByTagName("select");
+
+    for (var i = 0; i < selects.length; i++) {
+        var sel = selects[i];
+        formObject[sel.name] = sel.options[sel.selectedIndex].value;
+    }
+    
+    return formObject;
+
 };
 
 // invocant is the pollLink from above
diff -r 1feed31d5892 -r 677ac59981c5 htdocs/tools/endpoints/pollvote.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/tools/endpoints/pollvote.bml	Tue Sep 07 11:08:22 2010 +0800
@@ -0,0 +1,89 @@
+<?_c
+#
+# /tools/endpoints/pollvote.bml
+#
+# Submits a poll vote using AJAX, rendering the results
+#
+# Authors:
+#      Joao Portela <agnorpt@gmail.com>
+#
+# Copyright (c) 2010 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+#
+_c?>
+<?_code # -*-bml-*-
+{
+    use strict;
+    use vars qw(%POST);
+    use JSON;
+
+    my $ret = {};
+
+    my $err = sub {
+        my $msg = shift;
+        return JSON::objToJson({
+            error => "Error: $msg",
+        });
+    };
+
+    BML::set_content_type('text/javascript; charset=utf-8');
+    BML::finish();
+    BML::noparse();
+
+    foreach (values %POST) {
+        s/\0/,/g;
+    }
+    
+    my $remote = LJ::get_remote();
+
+    my $pollid = $POST{pollid}  or return $err->("No pollid");
+
+    my $poll = LJ::Poll->new($pollid);
+
+    unless ($poll && $poll->valid) {
+        return $err->("Poll not found");
+    }
+
+    my $u = $poll->journal;
+
+    # load the item being shown
+    my $entry = $poll->entry;
+    unless ($entry) {
+        return $err->("Post was deleted");
+    }
+
+    unless ($entry->visible_to($remote)) {
+        return $err->("You don't have the permissions to view this poll");
+    }
+    
+    unless (LJ::did_post()) {
+        return $err->("Post is required");
+    }
+
+    unless (LJ::check_form_auth()) {
+        return $err->("Form is invalid");
+    }
+    
+    my $error;
+    LJ::Poll->process_submission(\%POST, \$error);
+    if ($error) {
+        return $err->($error);
+    }
+
+    $ret->{results_html} = $poll->render(mode => "results");
+
+    $ret = {
+        %$ret,
+        pollid  => $pollid
+    };
+    
+    sleep(1.5) if $LJ::IS_DEV_SERVER;
+
+    return LJ::js_dumper($ret);
+}
+
+_code?>
+
--------------------------------------------------------------------------------
yvi: Kaylee half-smiling, looking very pretty (Default)

[personal profile] yvi 2010-09-07 07:07 am (UTC)(link)
!!!
denise: Image: Me, facing away from camera, on top of the Castel Sant'Angelo in Rome (Default)

[staff profile] denise 2010-09-07 07:12 am (UTC)(link)
I KNOW.
gchick: Small furry animal wearing a tin-foil hat (Default)

[personal profile] gchick 2010-09-07 11:44 am (UTC)(link)
OMG A POLL SYSTEM THAT DOESN'T SUCK! The ticky boxes will rejoice!
turlough: The Girl & Party Poison (Grace Jeanette & Gerard Way) high-fiveing, on the set of Na Na Na, Sept 2011 ((mcr) yeah!)

[personal profile] turlough 2010-09-07 02:54 pm (UTC)(link)
FABULOUS!!!