From 7411037a7258870038b81186e1fa36cf8242add0 Mon Sep 17 00:00:00 2001 From: Mason James Date: Wed, 14 Mar 2012 18:42:25 +1300 Subject: [PATCH] Bug 5668 - Star ratings in the opac Content-Type: text/plain; charset="utf-8" http://koha-community.org applied to commit 49c387cddf6de083343fe6c88ad9f167844521b4 --- C4/Auth.pm | 4 +- C4/Output.pm | 31 ++- C4/Ratings.pm | 249 +++++++++++++ installer/data/mysql/kohastructure.sql | 14 + installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 20 + koha-tmpl/intranet-tmpl/prog/en/modules/about.tt | 6 + .../prog/en/modules/admin/preferences/opac.pref | 8 + koha-tmpl/opac-tmpl/prog/en/css/jquery.rating.css | 12 + .../prog/en/lib/jquery/plugins/jquery.rating.js | 392 ++++++++++++++++++++ koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt | 86 +++++- .../opac-tmpl/prog/en/modules/opac-results.tt | 33 ++- koha-tmpl/opac-tmpl/prog/images/delete.gif | Bin 0 -> 752 bytes koha-tmpl/opac-tmpl/prog/images/star.gif | Bin 0 -> 815 bytes opac/opac-detail.pl | 24 +- opac/opac-ratings-ajax.pl | 115 ++++++ opac/opac-ratings.pl | 65 ++++ opac/opac-search.pl | 32 ++- t/db_dependent/Ratings.t | 60 +++ 19 files changed, 1125 insertions(+), 27 deletions(-) create mode 100644 C4/Ratings.pm create mode 100644 koha-tmpl/opac-tmpl/prog/en/css/jquery.rating.css create mode 100644 koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.rating.js create mode 100755 koha-tmpl/opac-tmpl/prog/images/delete.gif create mode 100644 koha-tmpl/opac-tmpl/prog/images/star.gif create mode 100755 opac/opac-ratings-ajax.pl create mode 100755 opac/opac-ratings.pl create mode 100755 t/db_dependent/Ratings.t diff --git a/C4/Auth.pm b/C4/Auth.pm index 38bbd5e..3e0730c 100644 --- a/C4/Auth.pm +++ b/C4/Auth.pm @@ -41,8 +41,7 @@ BEGIN { if ( psgi_env ) { die 'psgi:exit' } else { exit } } - - $VERSION = 3.02; # set version for version checking + $VERSION = 3.02; # set version for version checking $debug = $ENV{DEBUG}; @ISA = qw(Exporter); @EXPORT = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions); @@ -1648,6 +1647,7 @@ sub getborrowernumber { return 0; } + END { } # module clean-up code here (global destructor) 1; __END__ diff --git a/C4/Output.pm b/C4/Output.pm index 9087075..e33212a 100644 --- a/C4/Output.pm +++ b/C4/Output.pm @@ -39,19 +39,22 @@ BEGIN { # set the version for version checking $VERSION = 3.03; require Exporter; + @ISA = qw(Exporter); - @EXPORT_OK = qw(&is_ajax ajax_fail); # More stuff should go here instead - %EXPORT_TAGS = ( all =>[qw(&pagination_bar - &output_with_http_headers &output_html_with_http_headers)], - ajax =>[qw(&output_with_http_headers is_ajax)], - html =>[qw(&output_with_http_headers &output_html_with_http_headers)] - ); + @EXPORT_OK = qw(&is_ajax ajax_fail); # More stuff should go here instead + %EXPORT_TAGS = ( all =>[qw(&themelanguage &gettemplate setlanguagecookie pagination_bar + &output_with_http_headers &output_ajax_with_http_headers &output_html_with_http_headers)], + ajax =>[qw(&output_with_http_headers &output_ajax_with_http_headers is_ajax)], + html =>[qw(&output_with_http_headers &output_html_with_http_headers)] + ); + push @EXPORT, qw( + &themelanguage &gettemplate setlanguagecookie getlanguagecookie pagination_bar + ); push @EXPORT, qw( - &output_html_with_http_headers &output_with_http_headers FormatData FormatNumber pagination_bar + &output_html_with_http_headers &output_ajax_with_http_headers &output_with_http_headers FormatData FormatNumber ); } - =head1 NAME C4::Output - Functions for managing output, is slowly being deprecated @@ -306,6 +309,18 @@ sub output_html_with_http_headers ($$$;$) { output_with_http_headers( $query, $cookie, $data, 'html', $status ); } + +sub output_ajax_with_http_headers ($$) { + my ( $query, $js ) = @_; + print $query->header( + -type => 'text/javascript', + -charset => 'UTF-8', + -Pragma => 'no-cache', + -'Cache-Control' => 'no-cache', + -expires => '-1d', + ), $js; +} + sub is_ajax () { my $x_req = $ENV{HTTP_X_REQUESTED_WITH}; return ( $x_req and $x_req =~ /XMLHttpRequest/i ) ? 1 : 0; diff --git a/C4/Ratings.pm b/C4/Ratings.pm new file mode 100644 index 0000000..a01182b --- /dev/null +++ b/C4/Ratings.pm @@ -0,0 +1,249 @@ +package C4::Ratings; + +# Copyright 2011 KohaAloha, NZ +# Parts copyright 2011, Catalyst IT, NZ. +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use strict; +use warnings; +use Carp; +use Exporter; +use POSIX; +use C4::Debug; +use C4::Context; + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +BEGIN { + $VERSION = 3.00; + @ISA = qw(Exporter); + + @EXPORT = qw( + &GetRating + &AddRating + &ModRating + &DelRating + ); +} + +=head1 NAME + +C4::Ratings - a module to manage user ratings of Koha biblios + +=head1 DESCRIPTION + +Ratings.pm provides simple functionality for a user to 'rate' a biblio, and to retrieve a biblio's rating info + +the 4 subroutines allow a user to add, delete modify and retrieve rating info for a biblio. + +The rating can be from 1 to 5 stars, (5 stars being the highest rating) + +=head1 SYNOPSIS + +Get a rating for a bib + my $rating_hashref = GetRating( $biblionumber, undef ); + my $rating_hashref = GetRating( $biblionumber, $borrowernumber ); + +Add a rating for a bib + my $rating_hashref = AddRating( $biblionumber, $borrowernumber, $rating_value ); + +Mod a rating for a bib + my $rating_hashref = ModRating( $biblionumber, $borrowernumber, $rating_value ); + +Delete a rating for a bib + my $rating_hashref = DelRating( $biblionumber, $borrowernumber ); + + +All subroutines in Ratings.pm return a hashref which contain 4 keys + +for example, after executing this statment below... + + my $rating_hashref = GetRating ( $biblionumber, $borrowernumber ) ; + +$rating_hashref now contains a hashref that looks like this... + + $rating = { + rating_avg => '2', + rating_avg_int => '2.3', + rating_total => '432', + rating_value => '5' + } + +they 4 keys returned in the hashref are... + + rating_avg: average rating of a biblio + rating_avg_int: average rating of a biblio, rounded to 1dp + rating_total: total number of ratings of a biblio + rating_value: logged-in user's rating of a biblio + +=head1 BUGS + +Please use bugs.koha-community.org for tracking bugs. + +=head1 SOURCE AVAILABILITY + +The source is available from the koha-community.org git server +L + +=head1 AUTHOR + +Original code: Mason James + +=head1 COPYRIGHT + +Copyright (c) 2011 Mason James + +=head1 LICENSE + +C4::Ratings is free software. You can redistribute it and/or +modify it under the same terms as Koha itself. + +=head1 CREDITS + + Mason James + Koha Dev Team + + +=head2 GetRating + + GetRating($biblionumber, [$borrowernumber]) + +Get a rating for a bib + my $rating_hashref = GetRating( $biblionumber, undef ); + my $rating_hashref = GetRating( $biblionumber, $borrowernumber ); + +This returns the rating for the supplied biblionumber. It will also return +the rating that the supplied user gave to the provided biblio. If a particular +value can't be supplied, '0' is returned for that value. + +=head3 RETURNS + +A hashref containing: + +=over + +=item * rating_avg - average rating of a biblio +=item * rating_avg_int - average rating of a biblio, rounded to 1dp +=item * rating_total - total number of ratings of a biblio +=item * rating_value - logged-in user's rating of a biblio + +=back + +=cut + +sub GetRating { + my ( $biblionumber, $borrowernumber ) = @_; + my $query = qq| SELECT COUNT(*) AS total, SUM(rating_value) AS sum +FROM ratings WHERE biblionumber = ? |; + + my $sth = C4::Context->dbh->prepare($query); + $sth->execute($biblionumber); + my $res = $sth->fetchrow_hashref(); + + my ( $avg, $avg_int ) = 0; + + if ( $res->{sum} and $res->{total} ) { + eval { $avg = $res->{sum} / $res->{total} }; + } + + $avg_int = sprintf( "%.1f", $avg ); + $avg = sprintf( "%.0f", $avg ); + + my %rating_hash; + $rating_hash{rating_total} = $res->{total} || 0; + $rating_hash{rating_avg} = $avg || 0; + $rating_hash{rating_avg_int} = $avg_int ||0; + + if ($borrowernumber) { + my $q2 = qq| +SELECT rating_value FROM ratings WHERE biblionumber = ? AND borrowernumber = ?|; + my $sth1 = C4::Context->dbh->prepare($q2); + $sth1->execute( $biblionumber, $borrowernumber ); + my $res1 = $sth1->fetchrow_hashref(); + $rating_hash{'rating_value'} = $res1->{"rating_value"}; + } + else { + $rating_hash{rating_borrowernumber} = undef; + $rating_hash{rating_value} = undef; + } + +#### %rating_hash + return \%rating_hash; +} + +=head2 AddRating + + my $rating_hashref = AddRating( $biblionumber, $borrowernumber, $rating_value ); + +Add a rating for a bib + +This adds or updates a rating for a particular user on a biblio. If the value +is 0, then the rating will be deleted. If the value is out of the range of +0-5, nothing will happen. + +=cut + +sub AddRating { + my ( $biblionumber, $borrowernumber, $rating_value ) = @_; + my $query = + qq| INSERT INTO ratings (borrowernumber,biblionumber,rating_value) + VALUES (?,?,?)|; + my $sth = C4::Context->dbh->prepare($query); + $sth->execute( $borrowernumber, $biblionumber, $rating_value ); + my $rating = GetRating( $biblionumber, $borrowernumber ); + return $rating; +} + +=head2 ModRating + + my $rating_hashref = ModRating( $biblionumber, $borrowernumber, $rating_value ); + +Mod a rating for a bib + +=cut + +sub ModRating { + my ( $biblionumber, $borrowernumber, $rating_value ) = @_; + my $query = +qq|UPDATE ratings SET rating_value = ? WHERE borrowernumber = ? AND biblionumber = ?|; + my $sth = C4::Context->dbh->prepare($query); + $sth->execute( $rating_value, $borrowernumber, $biblionumber ); + my $rating = GetRating( $biblionumber, $borrowernumber ); + return $rating; +} + +=head2 DelRating + + my $rating_hashref = DelRating( $biblionumber, $borrowernumber ); + +Delete a rating for a bib + +=cut + +sub DelRating { + my ( $biblionumber, $borrowernumber ) = @_; + my $dbh = C4::Context->dbh; + my $query = + "delete from ratings where borrowernumber = ? and biblionumber = ?"; + my $sth = C4::Context->dbh->prepare($query); + my $rv = $sth->execute( $borrowernumber, $biblionumber ); + my $rating = GetRating( $biblionumber, undef ); + return $rating; +} + +1; +__END__ diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index 153e17b..9c9ac5d 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2710,6 +2710,20 @@ CREATE TABLE `biblioimages` ( CONSTRAINT `bibliocoverimage_fk1` FOREIGN KEY (`biblionumber`) REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- 'Ratings' table. This tracks the star ratings set by borrowers. +-- + +DROP TABLE IF EXISTS ratings; +CREATE TABLE ratings ( + borrowernumber int(11) NOT NULL, --- the borrower this rating is for + biblionumber int(11) NOT NULL, --- the biblio it's for + rating_value tinyint(1) NOT NULL, --- the rating, from 1-5 + timestamp timestamp NOT NULL default CURRENT_TIMESTAMP, + PRIMARY KEY (borrowernumber,biblionumber), + CONSTRAINT ratings_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT ratings_ibfk_2 FOREIGN KEY (biblionumber) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index d16ff81..cfaead4 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -348,3 +348,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES(' INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('CatalogModuleRelink',0,'If OFF the linker will never replace the authids that are set in the cataloging module.',NULL,'YesNo'); INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('ExpireReservesMaxPickUpDelay', '0', '', 'Enabling this allows holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay', 'YesNo'); INSERT INTO systempreferences` (variable,value,options,explanation,type) VALUES ('ExpireReservesMaxPickUpDelayCharge', '0', NULL , 'If ExpireReservesMaxPickUpDelay is enabled, and this field has a non-zero value, than a borrower whose waiting hold has expired will be charged this amount.', 'free') +INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacStarRatings','0',NULL,'yes|no|details','Choice'); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 3ade8bf..d311ced 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4908,6 +4908,26 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { ); print "Upgrade to $DBversion done (Correct table name for local cover images [please disregard the following error messages: \"Unknown table 'bibliocoverimage'...\" and \"Table 'biblioimages' already exists...\"])\n"; SetVersion($DBversion); + +$DBversion = "3.07.00.XXX"; +if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { + $dbh->do( + q | CREATE TABLE ratings ( + borrowernumber int(11) NOT NULL, + biblionumber int(11) NOT NULL, + rating_value tinyint(1) NOT NULL, + timestamp timestamp NOT NULL default CURRENT_TIMESTAMP, + PRIMARY KEY (borrowernumber,biblionumber), + CONSTRAINT ratings_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT ratings_ibfk_2 FOREIGN KEY (biblionumber) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 | + ); + $dbh->do( +q /INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacStarRatings','0',NULL,'yes|no|details','Choice') / + ); + print +"Upgrade to $DBversion done (Add 'ratings' table and 'OpacStarRatings' syspref)\n"; + SetVersion($DBversion); } =head1 FUNCTIONS diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt index 8f6e340..16aab93 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt @@ -340,6 +340,12 @@ Creative Commons Attribution-ShareAlike 2.5 License by the Bridge Consortium of Carleton College and St. Olaf College. + +

jQuery Star Rating Plugin

+

jQuery Star Rating Plugin v3.14 by Fyneworks.com is licensed under the MIT License and the GPL License.

+ +

Copyright © 2008 Fyneworks.com

+
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref index 1acc414..ac563ea 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref @@ -22,6 +22,14 @@ OPAC: no: Disable - "Koha OPAC as public. Private OPAC requires authentification before accessing the OPAC." - + - "Show star-ratings on" + - pref: OpacStarRatings + choices: + yes: "results and details" + no: "no" + details: "only details" + - "pages." + - - pref: OpacMaintenance choices: yes: Show diff --git a/koha-tmpl/opac-tmpl/prog/en/css/jquery.rating.css b/koha-tmpl/opac-tmpl/prog/en/css/jquery.rating.css new file mode 100644 index 0000000..18c0f3e --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/css/jquery.rating.css @@ -0,0 +1,12 @@ +/* jQuery.Rating Plugin CSS - http://www.fyneworks.com/jquery/star-rating/ */ +div.rating-cancel,div.star-rating{float:left;width:15px;height:15px;text-indent:-999em;cursor:pointer;display:block;background:transparent;overflow:hidden} +div.rating-cancel,div.rating-cancel a{background:url(../../images/delete.gif) no-repeat 0 -16px} +div.star-rating,div.star-rating a{background:url(../../images/star.gif) no-repeat 0 0px} +div.rating-cancel a,div.star-rating a{display:block;width:16px;height:100%;background-position:0 0px;border:0} +div.star-rating-on a{background-position:0 -32px!important} +div.star-rating-hover a{background-position:0 -16px} +/* Read Only CSS */ +div.star-rating-readonly a{cursor:default !important} +/* Partial Star CSS */ +div.star-rating{background:transparent!important;overflow:hidden!important} +/* END jQuery.Rating Plugin CSS */ diff --git a/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.rating.js b/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.rating.js new file mode 100644 index 0000000..46c49a4 --- /dev/null +++ b/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.rating.js @@ -0,0 +1,392 @@ +/* + ### jQuery Star Rating Plugin v3.14 - 2012-01-26 ### + * Home: http://www.fyneworks.com/jquery/star-rating/ + * Code: http://code.google.com/p/jquery-star-rating-plugin/ + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + ### +*/ + +/*# AVOID COLLISIONS #*/ +;if(window.jQuery) (function($){ +/*# AVOID COLLISIONS #*/ + + // IE6 Background Image Fix + if ($.browser.msie) try { document.execCommand("BackgroundImageCache", false, true)} catch(e) { }; + // Thanks to http://www.visualjquery.com/rating/rating_redux.html + + // plugin initialization + $.fn.rating = function(options){ + if(this.length==0) return this; // quick fail + + // Handle API methods + if(typeof arguments[0]=='string'){ + // Perform API methods on individual elements + if(this.length>1){ + var args = arguments; + return this.each(function(){ + $.fn.rating.apply($(this), args); + }); + }; + // Invoke API method handler + $.fn.rating[arguments[0]].apply(this, $.makeArray(arguments).slice(1) || []); + // Quick exit... + return this; + }; + + // Initialize options for this call + var options = $.extend( + {}/* new object */, + $.fn.rating.options/* default options */, + options || {} /* just-in-time options */ + ); + + // Allow multiple controls with the same name by making each call unique + $.fn.rating.calls++; + + // loop through each matched element + this + .not('.star-rating-applied') + .addClass('star-rating-applied') + .each(function(){ + + // Load control parameters / find context / etc + var control, input = $(this); + var eid = (this.name || 'unnamed-rating').replace(/\[|\]/g, '_').replace(/^\_+|\_+$/g,''); + var context = $(this.form || document.body); + + // FIX: http://code.google.com/p/jquery-star-rating-plugin/issues/detail?id=23 + var raters = context.data('rating'); + if(!raters || raters.call!=$.fn.rating.calls) raters = { count:0, call:$.fn.rating.calls }; + var rater = raters[eid]; + + // if rater is available, verify that the control still exists + if(rater) control = rater.data('rating'); + + if(rater && control)//{// save a byte! + // add star to control if rater is available and the same control still exists + control.count++; + + //}// save a byte! + else{ + // create new control if first star or control element was removed/replaced + + // Initialize options for this rater + control = $.extend( + {}/* new object */, + options || {} /* current call options */, + ($.metadata? input.metadata(): ($.meta?input.data():null)) || {}, /* metadata options */ + { count:0, stars: [], inputs: [] } + ); + + // increment number of rating controls + control.serial = raters.count++; + + // create rating element + rater = $(''); + input.before(rater); + + // Mark element for initialization (once all stars are ready) + rater.addClass('rating-to-be-drawn'); + + // Accept readOnly setting from 'disabled' property + if(input.attr('disabled') || input.hasClass('disabled')) control.readOnly = true; + + // Accept required setting from class property (class='required') + if(input.hasClass('required')) control.required = true; + + // Create 'cancel' button + rater.append( + control.cancel = $('') + .mouseover(function(){ + $(this).rating('drain'); + $(this).addClass('star-rating-hover'); + //$(this).rating('focus'); + }) + .mouseout(function(){ + $(this).rating('draw'); + $(this).removeClass('star-rating-hover'); + //$(this).rating('blur'); + }) + .click(function(){ + $(this).rating('select'); + }) + .data('rating', control) + ); + + }; // first element of group + + // insert rating star + var star = $(''); + rater.append(star); + + // inherit attributes from input element + if(this.id) star.attr('id', this.id); + if(this.className) star.addClass(this.className); + + // Half-stars? + if(control.half) control.split = 2; + + // Prepare division control + if(typeof control.split=='number' && control.split>0){ + var stw = ($.fn.width ? star.width() : 0) || control.starWidth; + var spi = (control.count % control.split), spw = Math.floor(stw/control.split); + star + // restrict star's width and hide overflow (already in CSS) + .width(spw) + // move the star left by using a negative margin + // this is work-around to IE's stupid box model (position:relative doesn't work) + .find('a').css({ 'margin-left':'-'+ (spi*spw) +'px' }) + }; + + // readOnly? + if(control.readOnly)//{ //save a byte! + // Mark star as readOnly so user can customize display + star.addClass('star-rating-readonly'); + //} //save a byte! + else//{ //save a byte! + // Enable hover css effects + star.addClass('star-rating-live') + // Attach mouse events + .mouseover(function(){ + $(this).rating('fill'); + $(this).rating('focus'); + }) + .mouseout(function(){ + $(this).rating('draw'); + $(this).rating('blur'); + }) + .click(function(){ + $(this).rating('select'); + }) + ; + //}; //save a byte! + + // set current selection + if(this.checked) control.current = star; + + // set current select for links + if(this.nodeName=="A"){ + if($(this).hasClass('selected')) + control.current = star; + }; + + // hide input element + input.hide(); + + // backward compatibility, form element to plugin + input.change(function(){ + $(this).rating('select'); + }); + + // attach reference to star to input element and vice-versa + star.data('rating.input', input.data('rating.star', star)); + + // store control information in form (or body when form not available) + control.stars[control.stars.length] = star[0]; + control.inputs[control.inputs.length] = input[0]; + control.rater = raters[eid] = rater; + control.context = context; + + input.data('rating', control); + rater.data('rating', control); + star.data('rating', control); + context.data('rating', raters); + }); // each element + + // Initialize ratings (first draw) + $('.rating-to-be-drawn').rating('draw').removeClass('rating-to-be-drawn'); + + return this; // don't break the chain... + }; + + /*--------------------------------------------------------*/ + + /* + ### Core functionality and API ### + */ + $.extend($.fn.rating, { + // Used to append a unique serial number to internal control ID + // each time the plugin is invoked so same name controls can co-exist + calls: 0, + + focus: function(){ + var control = this.data('rating'); if(!control) return this; + if(!control.focus) return this; // quick fail if not required + // find data for event + var input = $(this).data('rating.input') || $( this.tagName=='INPUT' ? this : null ); + // focus handler, as requested by focusdigital.co.uk + if(control.focus) control.focus.apply(input[0], [input.val(), $('a', input.data('rating.star'))[0]]); + }, // $.fn.rating.focus + + blur: function(){ + var control = this.data('rating'); if(!control) return this; + if(!control.blur) return this; // quick fail if not required + // find data for event + var input = $(this).data('rating.input') || $( this.tagName=='INPUT' ? this : null ); + // blur handler, as requested by focusdigital.co.uk + if(control.blur) control.blur.apply(input[0], [input.val(), $('a', input.data('rating.star'))[0]]); + }, // $.fn.rating.blur + + fill: function(){ // fill to the current mouse position. + var control = this.data('rating'); if(!control) return this; + // do not execute when control is in read-only mode + if(control.readOnly) return; + // Reset all stars and highlight them up to this element + this.rating('drain'); + this.prevAll().andSelf().filter('.rater-'+ control.serial).addClass('star-rating-hover'); + },// $.fn.rating.fill + + drain: function() { // drain all the stars. + var control = this.data('rating'); if(!control) return this; + // do not execute when control is in read-only mode + if(control.readOnly) return; + // Reset all stars + control.rater.children().filter('.rater-'+ control.serial).removeClass('star-rating-on').removeClass('star-rating-hover'); + },// $.fn.rating.drain + + draw: function(){ // set value and stars to reflect current selection + var control = this.data('rating'); if(!control) return this; + // Clear all stars + this.rating('drain'); + // Set control value + if(control.current){ + control.current.data('rating.input').attr('checked','checked'); + control.current.prevAll().andSelf().filter('.rater-'+ control.serial).addClass('star-rating-on'); + } + else + $(control.inputs).removeAttr('checked'); + // Show/hide 'cancel' button + control.cancel[control.readOnly || control.required?'hide':'show'](); + // Add/remove read-only classes to remove hand pointer + this.siblings()[control.readOnly?'addClass':'removeClass']('star-rating-readonly'); + },// $.fn.rating.draw + + + + + + select: function(value,wantCallBack){ // select a value + + // ***** MODIFICATION ***** + // Thanks to faivre.thomas - http://code.google.com/p/jquery-star-rating-plugin/issues/detail?id=27 + // + // ***** LIST OF MODIFICATION ***** + // ***** added Parameter wantCallBack : false if you don't want a callback. true or undefined if you want postback to be performed at the end of this method' + // ***** recursive calls to this method were like : ... .rating('select') it's now like .rating('select',undefined,wantCallBack); (parameters are set.) + // ***** line which is calling callback + // ***** /LIST OF MODIFICATION ***** + + var control = this.data('rating'); if(!control) return this; + // do not execute when control is in read-only mode + if(control.readOnly) return; + // clear selection + control.current = null; + // programmatically (based on user input) + if(typeof value!='undefined'){ + // select by index (0 based) + if(typeof value=='number') + return $(control.stars[value]).rating('select',undefined,wantCallBack); + // select by literal value (must be passed as a string + if(typeof value=='string') + //return + $.each(control.stars, function(){ + if($(this).data('rating.input').val()==value) $(this).rating('select',undefined,wantCallBack); + }); + } + else + control.current = this[0].tagName=='INPUT' ? + this.data('rating.star') : + (this.is('.rater-'+ control.serial) ? this : null); + + // Update rating control state + this.data('rating', control); + // Update display + this.rating('draw'); + // find data for event + var input = $( control.current ? control.current.data('rating.input') : null ); + // click callback, as requested here: http://plugins.jquery.com/node/1655 + + // **** MODIFICATION ***** + // Thanks to faivre.thomas - http://code.google.com/p/jquery-star-rating-plugin/issues/detail?id=27 + // + //old line doing the callback : + //if(control.callback) control.callback.apply(input[0], [input.val(), $('a', control.current)[0]]);// callback event + // + //new line doing the callback (if i want :) + if((wantCallBack ||wantCallBack == undefined) && control.callback) control.callback.apply(input[0], [input.val(), $('a', control.current)[0]]);// callback event + //to ensure retro-compatibility, wantCallBack must be considered as true by default + // **** /MODIFICATION ***** + + },// $.fn.rating.select + + + + + + readOnly: function(toggle, disable){ // make the control read-only (still submits value) + var control = this.data('rating'); if(!control) return this; + // setread-only status + control.readOnly = toggle || toggle==undefined ? true : false; + // enable/disable control value submission + if(disable) $(control.inputs).attr("disabled", "disabled"); + else $(control.inputs).removeAttr("disabled"); + // Update rating control state + this.data('rating', control); + // Update display + this.rating('draw'); + },// $.fn.rating.readOnly + + disable: function(){ // make read-only and never submit value + this.rating('readOnly', true, true); + },// $.fn.rating.disable + + enable: function(){ // make read/write and submit value + this.rating('readOnly', false, false); + }// $.fn.rating.select + + }); + + /*--------------------------------------------------------*/ + + /* + ### Default Settings ### + eg.: You can override default control like this: + $.fn.rating.options.cancel = 'Clear'; + */ + $.fn.rating.options = { //$.extend($.fn.rating, { options: { + cancel: 'Cancel Rating', // advisory title for the 'cancel' link + cancelValue: '', // value to submit when user click the 'cancel' link + split: 0, // split the star into how many parts? + + // Width of star image in case the plugin can't work it out. This can happen if + // the jQuery.dimensions plugin is not available OR the image is hidden at installation + starWidth: 16//, + + //NB.: These don't need to be pre-defined (can be undefined/null) so let's save some code! + //half: false, // just a shortcut to control.split = 2 + //required: false, // disables the 'cancel' button so user can only select one of the specified values + //readOnly: false, // disable rating plugin interaction/ values cannot be changed + //focus: function(){}, // executed when stars are focused + //blur: function(){}, // executed when stars are focused + //callback: function(){}, // executed when a star is clicked + }; //} }); + + /*--------------------------------------------------------*/ + + /* + ### Default implementation ### + The plugin will attach itself to file inputs + with the class 'multi' when the page loads + */ + $(function(){ + $('input[type=radio].star').rating(); + }); + + + +/*# AVOID COLLISIONS #*/ +})(jQuery); +/*# AVOID COLLISIONS #*/ diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt index 7af60a0..21ed517 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt @@ -1,6 +1,9 @@ [% INCLUDE 'doc-head-open.inc' %][% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha Online[% END %] Catalog › Details for: [% title |html %][% FOREACH subtitl IN subtitle %], [% subtitl.subfield |html %][% END %] [% INCLUDE 'doc-head-close.inc' %] + + + [% IF ( opacuserlogin ) %][% IF ( loggedinusername ) %][% IF ( TagsEnabled ) %]