[Koha-patches] [PATCH] Tags AJAX and JSON for OPAC side.

Joe Atzberger joe.atzberger at liblime.com
Wed May 21 08:36:05 CEST 2008


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.
---
 .../opac-tmpl/prog/en/includes/doc-head-close.inc  |    4 +-
 koha-tmpl/opac-tmpl/prog/en/js/tags.js             |   76 ++++++++++++++++
 .../opac-tmpl/prog/en/modules/opac-results.tmpl    |    5 +-
 koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl |    2 +-
 opac/opac-tags.pl                                  |   92 ++++++++++++++++++--
 5 files changed, 166 insertions(+), 13 deletions(-)
 create mode 100644 koha-tmpl/opac-tmpl/prog/en/js/tags.js

diff --git a/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc b/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc
index a7fc971..17186d2 100644
--- a/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc
+++ b/koha-tmpl/opac-tmpl/prog/en/includes/doc-head-close.inc
@@ -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
index 0000000..62c66b2
--- /dev/null
+++ b/koha-tmpl/opac-tmpl/prog/en/js/tags.js
@@ -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.");},
+	},
+};
+
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tmpl b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tmpl
index 7200482..797240d 100644
--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tmpl
+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tmpl
@@ -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 -->
diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl b/koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl
index 491f233..447bc5e 100644
--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl
+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-tags.tmpl
@@ -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.
diff --git a/opac/opac-tags.pl b/opac/opac-tags.pl
index 9d32fe0..d085003 100755
--- a/opac/opac-tags.pl
+++ b/opac/opac-tags.pl
@@ -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
 
-- 
1.5.5.GIT




More information about the Koha-patches mailing list