Tags AJAX and JSON for OPAC side.
authorJoe Atzberger <joe.atzberger@liblime.com>
Wed, 21 May 2008 06:36:05 +0000 (01:36 -0500)
committerJoshua Ferraro <jmf@liblime.com>
Thu, 29 May 2008 11:25:17 +0000 (06:25 -0500)
Note, all Tags js will live under KOHA.Tags namespace.
See opac-tags.pl perldoc for AJAX/JSON examples.  The capability is already
there to be very web-servicey, even moreso than the current OPAC implementation
will utilize.

Signed-off-by: Joshua Ferraro <jmf@liblime.com>
koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc
koha-tmpl/opac-tmpl/prog/en/js/tags.js [new file with mode: 0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tmpl [changed mode: 0755->0644]
koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl
opac/opac-tags.pl

index a7fc971..17186d2 100644 (file)
@@ -16,7 +16,9 @@
 <script type="text/javascript" src="<!-- TMPL_VAR name="themelang" -->/lib/jquery/plugins/ui.tabs.js"></script>
 <!-- TMPL_IF NAME="AmazonContent" --><script type="text/javascript" language="javascript" src="<!-- TMPL_VAR NAME="themelang" -->/js/amazonimages.js"></script><!-- /TMPL_IF -->
 <script type="text/javascript" language="javascript" src="<!-- TMPL_VAR NAME="themelang" -->/js/script.js"></script>
-<!-- TMPL_IF NAME="opacbookbag" --><script type="text/javascript" language="javascript" src="<!-- TMPL_VAR NAME="themelang" -->/js/basket.js"></script><!-- /TMPL_IF -->
+<script type="text/javascript" language="javascript"
+<!-- TMPL_IF NAME="opacbookbag" -->src="<!-- TMPL_VAR NAME="themelang" -->/js/basket.js"><!-- TMPL_ELSE -->>var readCookie;<!-- /TMPL_IF --></script>
+<!-- TMPL_IF NAME="TagsEnabled" --><script type="text/javascript" language="javascript" src="<!-- TMPL_VAR NAME="themelang" -->/js/tags.js"></script><!-- /TMPL_IF -->
 <!-- TMPL_IF NAME="GoogleJackets" -->
 <script type="text/javascript" language="javascript" src="<!-- TMPL_VAR NAME="themelang" -->/js/google-jackets.js"></script>
 <!-- /TMPL_IF -->
diff --git a/koha-tmpl/opac-tmpl/prog/en/js/tags.js b/koha-tmpl/opac-tmpl/prog/en/js/tags.js
new file mode 100644 (file)
index 0000000..62c66b2
--- /dev/null
@@ -0,0 +1,76 @@
+if (typeof KOHA == "undefined" || !KOHA) {
+    var KOHA = {};
+}
+
+/**
+* A namespace for Tags related functions.
+* readCookie is expected to already be declared.  That's why the assignment below is unscoped.
+* readCookie should be from basket.js or undefined.
+
+$.ajaxSetup({
+       url: "/cgi-bin/koha/opac-tags.pl",
+       type: "POST",
+       dataType: "script"
+});
+*/
+if (typeof(readCookie) == "undefined") {
+       readCookie = function (name) { // from http://www.quirksmode.org/js/cookies.html
+               var nameEQ = name + "=";
+               var ca = document.cookie.split(';');
+               for(var i=0;i < ca.length;i++) {
+                       var c = ca[i];
+                       while (c.charAt(0)==' '){ c = c.substring(1,c.length); }
+                       if (c.indexOf(nameEQ) == 0){ return c.substring(nameEQ.length,c.length); }
+               }
+               return null;
+       }
+}
+KOHA.Tags = {
+       add_tag_button: function(){
+               var mybibnum = $(this).attr("title");
+               var mynewtag = "newtag" + mybibnum;
+               var mytagid = "#" + mynewtag;
+               var mydata = {CGISESSID: readCookie('CGISESSID')};      // Someday this should be OPACSESSID
+               mydata[mynewtag] = $(mytagid).val();    // need [bracket] for variable property id
+               var response;   // AJAX from server will assign value to response.
+               $.post(
+                       "/cgi-bin/koha/opac-tags.pl",
+                       mydata,
+                       function(data){
+                               // alert("AJAX Response: " + data);
+                               eval(data);
+                               // alert("counts: " + response["added"] + response["deleted"] + response["errors"]);
+                               KOHA.Tags.set_tag_status(
+                                       mytagid + "_status",
+                                       KOHA.Tags.common_status(response["added"], response["deleted"], response["errors"])
+                               );
+                               if (response.alerts) {
+                                       alert(response.alerts.join("\n\n"));
+                               }
+                       },
+                       'script'
+               );
+               return false;
+       },
+       common_status : function(addcount, delcount, errcount) {
+           var cstat = "";
+           if (addcount && addcount > 0) {cstat += "Added "   + addcount + (addcount==1 ? " tag" : " tags") + ".  " ;}
+           if (delcount && delcount > 0) {cstat += "Deleted " + delcount + (delcount==1 ? " tag" : " tags") + ".  " ;}
+           if (errcount && errcount > 0) {cstat += (errcount==1 ? "ERROR" : errcount + " ERRORS") + " during operation.";}
+           return cstat;
+       },
+       set_tag_status : function(tagid, newstatus) {
+               $(tagid).html(newstatus);
+               $(tagid).css({display:"inline"});
+       },
+
+       tag_message: {
+       tagsdisabled : function(arg) {return ("Sorry, tags are not enabled on this system.");},
+       scrubbed_all_bad : function(arg) {return ("Error! Your tag was entirely markup code.  It was NOT added.  Please try again with plain text.");},
+       badparam : function(arg) {return ("Error! Illegal parameter '" +arg+ "'.");},
+       scrubbed : function(arg) {return ("Note: your tag contained markup code that was removed. The tag was added as '" +arg+ "'.");},
+    failed_add_tag : function(arg) {return ("Error! The add_tag operation failed on '" +arg+ "'.");},
+    failed_delete  : function(arg) {return ("Error! You cannot delete the tag '" +arg+ "'.  Note: you can only delete your own tags.");},
+       },
+};
+
old mode 100755 (executable)
new mode 100644 (file)
index 7200482..797240d
@@ -53,6 +53,7 @@ $(document).ready(function(){
         $("#bookbag_form").unCheckCheckboxes();
         return false;
     }); 
+       <!-- TMPL_IF NAME="TagsEnabled" -->$(".tagbutton").click(KOHA.Tags.add_tag_button);<!-- /TMPL_IF -->
     <!-- TMPL_IF NAME="GoogleJackets" -->KOHA.Google.GetCoverFromIsbn();<!-- /TMPL_IF -->
 });
 //]]>
@@ -257,9 +258,9 @@ $(document).ready(function(){
                     <form name="tagform<!-- TMPL_VAR NAME="biblionumber" -->" method="post" action="/cgi-bin/koha/opac-tags.pl">
                         <label for="newtag<!-- TMPL_VAR NAME="biblionumber" -->">New tag:</label>
                         <input name="newtag<!-- TMPL_VAR NAME="biblionumber" -->" id="newtag<!-- TMPL_VAR NAME="biblionumber" -->" maxlength="100" />
-                        <input name="tagbutton" class="tagbutton" type="submit" value="Add" />
+                        <input name="tagbutton" class="tagbutton" title="<!-- TMPL_VAR NAME="biblionumber" -->" type="submit" value="Add" />
                     </form>
-                    <span id="tagstatus<!-- TMPL_VAR NAME="biblionumber" -->" class="tagstatus" style="display:none;">
+                    <span id="newtag<!-- TMPL_VAR NAME="biblionumber" -->_status" class="tagstatus" style="display:none;">
                         Tag status here.
                     </span>
                 <!-- /TMPL_IF -->
index 491f233..447bc5e 100644 (file)
@@ -13,7 +13,7 @@
        <!-- TMPL_LOOP NAME="ERRORS" -->
                <div class="error">There was a problem with this operation:
                <!-- TMPL_IF NAME="tagsdisabled" -->Sorry, tags are not enabled on this system.
-               <!-- TMPL_ELSIF NAME="badparam" -->ERROR: illegal paramter <!-- TMPL_VAR NAME="badparam" -->
+               <!-- TMPL_ELSIF NAME="badparam" -->ERROR: illegal parameter <!-- TMPL_VAR NAME="badparam" -->
                <!-- TMPL_ELSIF NAME="login"    -->ERROR: You must log in to complete that action.
                <!-- TMPL_ELSIF NAME="failed_delete" -->ERROR: You cannot delete the tag <!-- TMPL_VAR NAME="failed_delete" -->.
                                        <br />Note: you can only delete your own tags.
index 9d32fe0..d085003 100755 (executable)
@@ -31,7 +31,7 @@ use warnings;
 use CGI;
 use CGI::Cookie; # need to check cookies before having CGI parse the POST request
 
-use C4::Auth;
+use C4::Auth qw(:DEFAULT check_cookie_auth);
 use C4::Context;
 use C4::Debug;
 use C4::Output 3.02 qw(:html :ajax pagination_bar);
@@ -45,14 +45,34 @@ my @deltags = ();
 my %counts  = ();
 my @errors  = ();
 
+sub ajax_auth_cgi ($) {     # returns CGI object
+    my $needed_flags = shift;
+       my %cookies = fetch CGI::Cookie;
+       my $input = CGI->new;
+       my $sessid = $cookies{'CGISESSID'}->value || $input->param('CGISESSID');
+       my ($auth_status, $auth_sessid) = check_cookie_auth($sessid, $needed_flags);
+       $debug and
+       print STDERR "($auth_status, $auth_sessid) = check_cookie_auth($sessid," . Dumper($needed_flags) . ")\n";
+       if ($auth_status ne "ok") {
+               output_ajax_with_http_headers $input,
+               "window.alert('Your CGI session cookie ($sessid) is not current.  " .
+               "Please refresh the page and try again.');\n";
+               exit 0;
+       }
+       $debug and print STDERR "AJAX request: " . Dumper($input),
+               "\n(\$auth_status,\$auth_sessid) = ($auth_status,$auth_sessid)\n";
+       return $input;
+}
+
 # The trick here is to support multiple tags added to multiple bilbios in one POST.
 # The HTML might not use this, but it makes it more web-servicey from the start.
 # So the name of param has to have biblionumber built in.
 # For lack of anything more compelling, we just use "newtag[biblionumber]"
 # We split the value into tags at comma and semicolon
 
+my $is_ajax = is_ajax();
 my $openadds = C4::Context->preference('TagsModeration') ? 0 : 1;
-my $query = new CGI;
+my $query = ($is_ajax) ? &ajax_auth_cgi({}) : CGI->new();
 unless (C4::Context->preference('TagsEnabled')) {
        push @errors, {+ tagsdisabled=>1 };
 } else {
@@ -72,13 +92,19 @@ unless (C4::Context->preference('TagsEnabled')) {
 }
 
 my $add_op = (scalar(keys %newtags) + scalar(@deltags)) ? 1 : 0;
-my ($template, $loggedinuser, $cookie) = get_template_and_user({
-       template_name   => "opac-tags.tmpl",
-       query           => $query,
-       type            => "opac",
-       authnotrequired => ($add_op ? 0 : 1),   # auth required to add tags
-       debug           => 1,
-});
+my ($template, $loggedinuser, $cookie);
+if ($is_ajax) {
+       $loggedinuser = C4::Context->userenv->{'number'};  # must occur AFTER auth
+       $debug and print STDERR "op: $loggedinuser\n";
+} else {
+       ($template, $loggedinuser, $cookie) = get_template_and_user({
+               template_name   => "opac-tags.tmpl",
+               query           => $query,
+               type            => "opac",
+               authnotrequired => ($add_op ? 0 : 1),   # auth required to add tags
+               debug           => 1,
+       });
+}
 
 if ($add_op) {
        unless ($loggedinuser) {
@@ -111,6 +137,7 @@ if (scalar @newtags_keys) {
                        if ($result) {
                                $counts{$biblionumber}++;
                        } else {
+                               push @errors, {failed_add_tag=>$clean_tag};
                                warn "add_tag($biblionumber,$clean_tag,$loggedinuser...) returned bad result ($result)";
                        }
                }
@@ -125,6 +152,23 @@ foreach (@deltags) {
        }
 }
 
+if ($is_ajax) {
+       my $sum = 0;
+       foreach (values %counts) {$sum += $_;}
+       my $js_reply = sprintf("response = {\n\tadded: %d,\n\tdeleted: %d,\n\terrors: %d,",$sum,$dels,scalar @errors);
+       my $err_string = '';
+       if (scalar @errors) {
+               $err_string = "\n\talerts: [";  # open response_function
+               foreach (@errors) {
+                       my $key = (keys %$_)[0];
+                       $err_string .= "\n\t\t KOHA.Tags.tag_message.$key(\"" . $_->{$key} . '"),';
+               }
+               $err_string .= "\n\t],\n";      # close response_function
+       }
+       output_ajax_with_http_headers($query, "$js_reply\n$err_string};");
+       exit;
+}
+
 my $results = [];
 my $my_tags = [];
 
@@ -172,4 +216,34 @@ if ($add_op) {
 (scalar @$my_tags) and $template->param(MY_TAGS => $my_tags);
 
 output_html_with_http_headers $query, $cookie, $template->output;
+__END__
+
+=head1 EXAMPLE AJAX POST PARAMETERS
+
+CGISESSID      7c6288263107beb320f70f78fd767f56
+newtag396      fire,+<a+href="foobar.html">foobar</a>,+<img+src="foo.jpg"+/>
+
+So this request is trying to add 3 tags to biblio #396.  The CGISESSID is the same as that the browser would
+typically communicate using cookies.  If it is valid, the server will split the value of "newtag396" and 
+process the components for addition.  In this case the intended tags are:
+       fire
+       <a+href="foobar.html">foobar</a>
+       <img src="foo.jpg" />
+
+The first tag is acceptable.  The second will be scrubbed of markup, resulting in the tag "foobar".  
+The third tag is all markup, and will be rejected.  
+
+=head1 EXAMPLE AJAX JSON response
+
+response = {
+       added: 2,
+       deleted: 0,
+       errors: 2,
+       alerts: [
+                KOHA.Tags.tag_message.scrubbed("foobar"),
+                KOHA.Tags.tag_message.scrubbed_all_bad("1"),
+       ],
+};
+
+=cut