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?>
+
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org