[dw-free] Display how a person answered all questions of a poll
[commit: http://hg.dwscoalition.org/dw-free/rev/154dd52a7a64]
http://bugs.dwscoalition.org/show_bug.cgi?id=26
Add a "View respondents" link (for non-anonymous polls) which lists all
users who have voted in the poll; this list can be further expanded to see
what each user's vote is.
Patch by
yvi.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=26
Add a "View respondents" link (for non-anonymous polls) which lists all
users who have voted in the poll; this list can be further expanded to see
what each user's vote is.
Patch by
Files modified:
- bin/upgrading/en.dat
- cgi-bin/LJ/Poll.pm
- cgi-bin/LJ/Poll/Question.pm
- htdocs/js/jquery.poll.js
- htdocs/js/livejournal.js
- htdocs/tools/endpoints/poll.bml
--------------------------------------------------------------------------------
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat Wed Nov 30 23:53:06 2011 -0600
+++ b/bin/upgrading/en.dat Thu Dec 01 14:25:15 2011 +0800
@@ -2172,6 +2172,8 @@
poll.pollnum=Poll #[[num]]
+poll.respondents.user=[[user]] answered:
+
poll.scaleanswers=<strong>Mean:</strong> [[mean]] <strong>Median:</strong> [[median]] <strong>Std. Dev</strong> [[stddev]]
poll.security=Open to <strong>[[whovote]]</strong>. Results viewable to <strong>[[whoview]]</strong>
@@ -2200,6 +2202,8 @@
poll.viewanswers=View Answers
+poll.viewrespondents=View Respondents
+
portal.bdays.count.des=By default, the 5 friends with the soonest birthdays are shown.
portal.bdays.count.name=Birthdays to Display
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 cgi-bin/LJ/Poll.pm
--- a/cgi-bin/LJ/Poll.pm Wed Nov 30 23:53:06 2011 -0600
+++ b/cgi-bin/LJ/Poll.pm Thu Dec 01 14:25:15 2011 +0800
@@ -676,6 +676,7 @@
$self->_load;
return $self->{name};
}
+# returns "yes" if the poll is anonymous
sub isanon {
my $self = $_[0];
$self->_load;
@@ -884,7 +885,7 @@
my @qs = $self->questions;
### view answers to a particular question in a poll
- if ($mode eq "ans") {
+ if ( $mode eq "ans" ) {
return "<b>[" . LJ::Lang::ml('poll.error.cantview') . "]</b>"
unless $self->can_view;
my $q = $self->question($qid)
@@ -898,6 +899,22 @@
my $pages = $q->answers_pages($self->journalid, $pagesize);
$ret .= '<div>' . $q->paging_bar_as_html($page, $pages, $pagesize, $self->journalid, $pollid, $qid, no_class => 1) . '</div>';
return $ret;
+ } elsif ( $mode eq "ans_extended" ) {
+ # view detailed answers for every user
+ return "<b>[" . LJ::Lang::ml( 'poll.error.cantview' ) . "]</b>"
+ unless $self->can_view;
+
+ my @userids;
+
+ my $respondents = $self->journal->selectall_arrayref(
+ "SELECT DISTINCT(userid) FROM pollresult2 WHERE pollid=? AND journalid=? ",
+ undef, $pollid, $self->journalid );
+
+ foreach my $userid ( @$respondents ) {
+ $ret .= "<div class='useranswer'>" . $self->user_answers_as_html( $userid ) . "</div><br />";
+ }
+
+ return $ret;
}
# Users cannot vote unless they are logged in
@@ -957,6 +974,11 @@
$ret .= "<br />\n";
# change vote link
$ret .= "[ <a href='$LJ::SITEROOT/poll/?id=$pollid&mode=enter' class='LJ_PollChangeLink' id='LJ_PollChangeLink_${pollid}' lj_pollid='$pollid' >" . LJ::Lang::ml( 'poll.changevote' ) . "</a> ]" if $self->can_vote( $remote ) && !$self->is_closed;
+ if ( $self->can_view && $self->isanon ne "yes" ) {
+ $ret .= "<br /><br /><div class='respondents'><a href='$LJ::SITEROOT/poll/?id=$pollid&mode=ans_extended' class='LJ_PollRespondentsLink' " .
+ "id='LJ_PollRespondentsLink_${pollid}' " .
+ "lj_pollid='$pollid' >" . LJ::Lang::ml( 'poll.viewrespondents' ) . "</a></div><br />"
+ }
} else {
$ret .= "<br />\n";
}
@@ -1299,6 +1321,50 @@
return @qs;
}
+# returns a string with the html of how a user answered all questions of this poll
+sub user_answers_as_html {
+ my ( $self, $userid ) = @_;
+
+ my $ret;
+ my $u = LJ::load_userid( $userid );
+
+ $ret = "<span class='useranswer' id='useranswer_" . $u->userid . "'>" . LJ::Lang::ml( 'poll.respondents.user', { user => $u->ljuser_display } ) . "\n";
+
+ my @qs = $self->questions;
+
+ foreach my $q ( @qs ) {
+ $ret .= $q->user_answer_as_html( $userid );
+ }
+ $ret .= "</span>";
+
+ return $ret;
+ }
+
+# returns a string with the html of the people who responded to this poll
+sub respondents_as_html {
+ my ( $self ) = @_;
+ my $pollid = $self->pollid;
+
+ my @res = @{ $self->journal->selectall_arrayref(
+ "SELECT DISTINCT(userid) FROM pollresult2 WHERE pollid=? AND journalid=? ",
+ undef, $pollid, $self->journalid ) };
+ my @respondents = map { $_->[0] } @res;
+
+ my $users = LJ::load_userids( @respondents );
+
+ my $ret;
+ foreach my $userid ( @respondents ) {
+ my $u = $users->{$userid};
+ next unless $u;
+
+ $ret .= "<div> <a href='$LJ::SITEROOT/poll/?id=$pollid&mode=ans_extended'" .
+ "class='LJ_PollUserAnswerLink'" .
+ "lj_pollid='$pollid' lj_userid='$userid'" .
+ "id='LJ_PollUserAnswerLink_${pollid}_$userid'>[+]</a>" .
+ "<span class='polluser' id='LJ_PollUserAnswerRes_${pollid}_$userid'>" . $u->ljuser_display . "</span></div>\n";
+ }
+ return $ret;
+}
########## Props
# get the typemap for pollprop2
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 cgi-bin/LJ/Poll/Question.pm
--- a/cgi-bin/LJ/Poll/Question.pm Wed Nov 30 23:53:06 2011 -0600
+++ b/cgi-bin/LJ/Poll/Question.pm Thu Dec 01 14:25:15 2011 +0800
@@ -307,6 +307,51 @@
return $ret;
}
+#returns how a user answered this question
+sub user_answer_as_html {
+ my $self = shift;
+ my $userid = shift;
+ my $isanon = shift;
+
+ my $ret = '';
+
+ # Get data
+ my $sth = $self->poll->journal->prepare(
+ "SELECT value FROM pollresult2 " .
+ "WHERE pollid=? AND pollqid=? AND userid=? " );
+
+ $sth->execute( $self->pollid, $self->pollqid, $userid );
+ die $sth->errstr if $sth->err;
+
+ my ( $pollid, $pollqid ) = ( $self->pollid, $self->pollqid );
+
+ my $qtext = $self->qtext;
+ my @res;
+ push @res, $_ while $_ = $sth->fetchrow_hashref;
+
+ foreach my $res ( @res ) {
+ my $value = $res->{value};
+ my @items = $self->items;
+
+ my %it;
+ $it{$_->{pollitid}} = $_->{item} foreach @items;
+
+ # some question types need translation; type 'text' doesn't.
+ if ( $self->type eq "radio" || $self->type eq "drop" ) {
+ $value = $it{$value};
+ } elsif ( $self->type eq "check" ) {
+ $value = join( ", ", map { $it{$_} } split( /,/, $value ) );
+ }
+
+ LJ::Poll->clean_poll( \$value );
+ LJ::Poll->clean_poll( \$qtext );
+
+ $ret .= '<b>' . $qtext . "</b> -- " . $value . "<br/>\n";
+ }
+
+ return $ret;
+}
+
sub paging_bar_as_html {
my $self = shift;
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 htdocs/js/jquery.poll.js
--- a/htdocs/js/jquery.poll.js Wed Nov 30 23:53:06 2011 -0600
+++ b/htdocs/js/jquery.poll.js Thu Dec 01 14:25:15 2011 +0800
@@ -84,6 +84,35 @@
}
});
}).end()
+ .filter(".respondents").children("a.LJ_PollRespondentsLink").click(function(e){
+ e.stopPropagation();
+ e.preventDefault();
+
+ var $clicked = $(this);
+ var pollid = $clicked.attr("lj_pollid");
+
+ $clicked
+ .ajaxtip({namespace: "pollanswer"})
+ .ajaxtip("load", {
+ endpoint: "poll",
+ context: self,
+ data: {
+ pollid : pollid,
+ action : "get_respondents"
+ },
+ success: function( data, status, jqxhr ) {
+ if ( data.error ) {
+ $clicked.ajaxtip( "error", data.error )
+ } else {
+ $clicked.ajaxtip( "cancel" ).hide();
+ $clicked.closest("div").append(data.answer_html);
+ $clicked.closest("div").parent().trigger( "updatedcontent.poll" );
+ }
+ self._trigger( "complete" );
+ }
+ });
+
+ }).end()
.filter("a.LJ_PollChangeLink").click(function(e){
e.stopPropagation();
e.preventDefault();
@@ -106,7 +135,60 @@
self._trigger( "complete" );
}
});
- }).end()
+ }).end();
+
+ $("a.LJ_PollUserAnswerLink").click(function(e){
+ e.stopImmediatePropagation();
+ e.preventDefault();
+
+ var $clicked = $(this);
+
+ var pollid = $clicked.attr("lj_pollid");
+ var userid = $clicked.attr("lj_userid");
+
+ if ( ! pollid || ! userid ) return;
+
+ if ( $clicked.attr('innerHTML') === "[-]" ) {
+ $clicked.siblings(".useranswer").remove()
+ .end().siblings(".polluser").show();
+ $clicked.html("[+]");
+ } else {
+ $clicked
+ .ajaxtip({namespace: "polluseranswer"})
+ .ajaxtip("load", {
+ endpoint: "poll",
+ context: self,
+ data: {
+ pollid : pollid,
+ userid : userid,
+ action : "get_user_answers"
+ },
+ success: function( data, status, jqxhr ) {
+ if ( data.error ) {
+ $clicked.ajaxtip( "error", data.error )
+ } else {
+ var pollid = data.pollid;
+ var userid = data.userid;
+ if ( ! pollid || ! userid ) {
+ $clicked.ajaxtip( "error", "Error fetching poll results." );
+ } else {
+ $clicked.ajaxtip( "cancel" );
+
+ $clicked.html("[-]");
+ $clicked.siblings(".polluser").hide()
+ .closest("div").append(data.answer_html);
+ }
+ }
+
+ self._trigger( "complete" );
+ },
+ error: function( jqxhr, status, error ) {
+ $clicked.ajaxtip( "error", "Error contacting server. " + error);
+ self._trigger( "complete" );
+ }
+ });
+ }
+ });
},
_initForm: function() {
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 htdocs/js/livejournal.js
--- a/htdocs/js/livejournal.js Wed Nov 30 23:53:06 2011 -0600
+++ b/htdocs/js/livejournal.js Thu Dec 01 14:25:15 2011 +0800
@@ -236,6 +236,20 @@
Array.prototype.forEach.call(pollForms, function (pollForm) {
DOM.addEventListener(pollForm, "submit", LiveJournal.pollFormSubmitted.bindEventListener(pollForm));
});
+
+ var pollRespondentsLinks = DOM.getElementsByTagAndClassName(document, 'a', "LJ_PollRespondentsLink") || [];
+
+ // attach click handlers to each link to show respondents to a poll
+ Array.prototype.forEach.call(pollRespondentsLinks, function (pollRes) {
+ DOM.addEventListener(pollRes, "click", LiveJournal.pollRespondentsLinkClicked.bindEventListener(pollRes));
+ });
+
+ var pollUserLinks = DOM.getElementsByTagAndClassName(document, 'a', "LJ_PollUserAnswerLink") || [];
+
+ // attach click handlers to each answer link
+ Array.prototype.forEach.call(pollUserLinks, function (pollLink) {
+ DOM.addEventListener(pollLink, "click", LiveJournal.pollUserAnswerLinkClicked.bindEventListener(pollLink));
+ });
};
LiveJournal.pollButtonClicked = function (e) {
@@ -478,6 +492,146 @@
LiveJournal.initPolls();
};
+LiveJournal.pollRespondentsLinkClicked = function (e) {
+ Event.stop(e);
+
+ if (! this || ! this.tagName || this.tagName.toLowerCase() != "a")
+ return true;
+
+ var pollid = this.getAttribute("lj_pollid");
+ if (! pollid) return true;
+
+ var action = "get_respondents";
+
+ answerEle = $("LJ_PollRespondentsLink_" + pollid);
+ if (! answerEle) return false;
+
+ var params = {
+ "pollid" : pollid,
+ "action" : action
+ };
+
+ var opts = {
+ "url" : LiveJournal.getAjaxUrl("poll"),
+ "method" : "POST",
+ "data" : HTTPReq.formEncoded(params),
+ "onData" : LiveJournal.pollRespondentsReceived,
+ "onError": LiveJournal.ajaxError
+ };
+
+ HTTPReq.getJSON(opts);
+
+ if (!PollPages.hourglass) {
+ var coords = DOM.getAbsoluteCursorPosition(e);
+ PollPages.hourglass = new Hourglass();
+ PollPages.hourglass.init();
+ PollPages.hourglass.hourglass_at(coords.x, coords.y);
+ PollPages.e = e;
+ }
+
+ return false;
+}
+
+LiveJournal.pollRespondentsReceived = function (answers) {
+ if (! answers) return false;
+
+ if (PollPages.hourglass) {
+ PollPages.hourglass.hide();
+ PollPages.hourglass = null;
+ }
+
+ if (answers.error) return LiveJournal.ajaxError(answers.error);
+
+ var pollid = answers.pollid;
+ if (! pollid) return false;
+
+ answerEle = $("LJ_PollRespondentsLink_" + pollid);
+ if (! answerEle) return false;
+
+ var answer = answers.answer_html ? answers.answer_html : "(No answers)";
+ var newAnswerEle = document.createElement("span");
+ newAnswerEle.innerHTML = answer;
+ answerEle.parentNode.replaceChild(newAnswerEle, answerEle);
+
+ if (typeof ContextualPopup != "undefined")
+ ContextualPopup.setup();
+
+ LiveJournal.initPolls();
+};
+
+
+LiveJournal.pollUserAnswerLinkClicked = function (e) {
+ Event.stop(e);
+
+ if (! this || ! this.tagName || this.tagName.toLowerCase() != "a")
+ return true;
+
+ var pollid = this.getAttribute("lj_pollid");
+ if (! pollid) return true;
+
+ var userid = this.getAttribute("lj_userid");
+ if (! userid) return true;
+
+ var action = "get_user_answers";
+
+ answerEle = $("LJ_PollUserAnswerLink_" + pollid + "_" + userid);
+ if (! answerEle) return false;
+
+ // Do ajax request to replace the link with the answers
+ var params = {
+ "pollid" : pollid,
+ "userid" : userid,
+ "action" : action
+ };
+
+ var opts = {
+ "url" : LiveJournal.getAjaxUrl("poll"),
+ "method" : "POST",
+ "data" : HTTPReq.formEncoded(params),
+ "onData" : LiveJournal.pollUserAnswersReceived,
+ "onError": LiveJournal.ajaxError
+ };
+
+ HTTPReq.getJSON(opts);
+
+ if (!PollPages.hourglass) {
+ var coords = DOM.getAbsoluteCursorPosition(e);
+ PollPages.hourglass = new Hourglass();
+ PollPages.hourglass.init();
+ PollPages.hourglass.hourglass_at(coords.x, coords.y);
+ PollPages.e = e;
+ }
+ return false;
+};
+
+LiveJournal.pollUserAnswersReceived = function (answers) {
+ if (! answers) return false;
+
+ if (PollPages.hourglass) {
+ PollPages.hourglass.hide();
+ PollPages.hourglass = null;
+ }
+
+ if (answers.error) return LiveJournal.ajaxError(answers.error);
+
+ var pollid = answers.pollid;
+ var userid = answers.userid;
+ if (! pollid || ! userid) return false;
+
+ var linkEle = $("LJ_PollUserAnswerLink_" + pollid + "_" + userid);
+ if (! linkEle) return false;
+
+ answerEle = $("LJ_PollUserAnswerRes_" + pollid + "_" + userid);
+ if (! answerEle) return false;
+
+ answerEle.innerHTML = answers.answer_html ? answers.answer_html : "(No answers)";
+ linkEle.innerHTML = "";
+ answerEle.style.display = "block";
+
+ if (typeof ContextualPopup != "undefined")
+ ContextualPopup.setup();
+};
+
// gets a url for doing ajax requests
LiveJournal.getAjaxUrl = function (action) {
// if we are on a journal subdomain then our url will be
diff -r 1cb6ed2d70b0 -r 154dd52a7a64 htdocs/tools/endpoints/poll.bml
--- a/htdocs/tools/endpoints/poll.bml Wed Nov 30 23:53:06 2011 -0600
+++ b/htdocs/tools/endpoints/poll.bml Thu Dec 01 14:25:15 2011 +0800
@@ -32,7 +32,8 @@
BML::noparse();
my $pollid = $POST{pollid} or return $err->("No pollid");
- my $pollqid = $POST{pollqid} or return $err->("No pollqid");
+ my $pollqid = $POST{pollqid} || 0;
+ my $userid = $POST{userid} || 0;
my $action = $POST{action};
my $page = $POST{page};
my $pagesize = $POST{pagesize} || 2000;
@@ -46,10 +47,18 @@
}
if ($action eq 'get_answers') {
+ return $err->( "No pollqid" ) unless $pollqid;
+
my $question = $poll->question($pollqid) or return $err->("Error loading question $pollqid");
my $pages = $question->answers_pages($poll->journalid, $pagesize);
$ret->{paging_html} = $question->paging_bar_as_html($page, $pages, $pagesize, $poll->journalid, $pollid, $pollqid);
$ret->{answer_html} = $question->answers_as_html($poll->journalid, $poll->isanon, $page, $pagesize, $pages);
+ } elsif ( $action eq 'get_respondents' ) {
+ $ret->{answer_html} = $poll->respondents_as_html;
+ } elsif ($action eq 'get_user_answers') {
+ return $err->( "No userid" ) unless $userid;
+
+ $ret->{answer_html} = $poll->user_answer_as_html( $userid );
} else {
return $err->("Invalid action $action");
}
@@ -58,6 +67,7 @@
%$ret,
pollid => $pollid,
pollqid => $pollqid,
+ userid => $userid,
page => $page,
};
--------------------------------------------------------------------------------

no subject