From e7abee8804fa0a7591e0f255dfbea0e374c6cefe Mon Sep 17 00:00:00 2001 From: Mason James Date: Fri, 30 Mar 2012 16:35:29 +1300 Subject: [PATCH] Bug 5668 - Star ratings in the opac Content-Type: text/plain; charset="utf-8" http://koha-community.org patch applied to commit eb3dc448d2378e01a524d082fc6389484b0cc7d8 Signed-off-by: Nicole C. Engard Turned on star ratings in the opac on details and results Searched for titles - saw the stars Clicked on a title Clicked on the stars Clicked on the stars to change my rating Logged out Tried to click on stars Logged in as different user Rated items that were rated already and saw average change Changed preference to show only on detail and repeated tests Changed preference to now show stars All above tests passed. Signing off. Rebased 3-19-12 by Ian Walls --- C4/Auth.pm | 4 +- C4/Output.pm | 34 ++- C4/Ratings.pm | 249 +++++++++++++ installer/data/mysql/kohastructure.sql | 15 + installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 22 ++ koha-tmpl/intranet-tmpl/prog/en/modules/about.tt | 6 + .../prog/en/modules/admin/preferences/opac.pref | 12 + 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 | 81 ++++- .../opac-tmpl/prog/en/modules/opac-results.tt | 40 ++- 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 | 22 +- opac/opac-ratings-ajax.pl | 115 ++++++ opac/opac-ratings.pl | 65 ++++ opac/opac-search.pl | 24 ++- t/db_dependent/Ratings.t | 63 ++++ 19 files changed, 1137 insertions(+), 20 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 0b737e7..e22da24 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); @@ -1665,6 +1664,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..359662a 100644 --- a/C4/Output.pm +++ b/C4/Output.pm @@ -39,18 +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)] - ); + + @ISA = qw(Exporter); + @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( - &output_html_with_http_headers &output_with_http_headers FormatData FormatNumber pagination_bar + &themelanguage &gettemplate setlanguagecookie getlanguagecookie pagination_bar + ); + push @EXPORT, qw( + &output_html_with_http_headers &output_ajax_with_http_headers &output_with_http_headers FormatData FormatNumber ); -} +} =head1 NAME @@ -306,6 +310,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 fda0bac..2b4de74 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -2809,6 +2809,21 @@ CREATE TABLE IF NOT EXISTS `social_data` ( PRIMARY KEY (`isbn`) ) 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 e8c22ee..e106fb1 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -360,3 +360,4 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('SocialNetworks','1','Enable/Disable social networks links in opac detail pages','','YesNo'); INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES('SubscriptionDuplicateDroppedInput','','','List of fields which must not be rewritten when a subscription is duplicated (Separated by pipe |)','Free'); INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('AutoResumeSuspendedHolds', '1', NULL , 'Allow suspended holds to be automatically resumed by a set date.', 'YesNo'); +INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacStarRatings','all',NULL,'disable|all|details','Choice'); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index ddc288c..fba0031 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -4929,6 +4929,28 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) { INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('AllowPKIAuth','None','Use the field from a client-side SSL certificate to look a user in the Koha database','None|Common Name|emailAddress','Choice'); }); print "Upgrade to $DBversion done (Bug 6296 New System preference AllowPKIAuth)\n"; +} + +$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','disable',NULL,'disable|all|details','Choice') / + ); + + print +"Upgrade to $DBversion done (Add 'ratings' table and 'OpacStarRatings' syspref)\n"; SetVersion($DBversion); } diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt index 302e7bd..a3d5248 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/about.tt @@ -342,6 +342,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 ae6b620..8083e4d 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 @@ -6,6 +6,10 @@ OPAC: choices: opac-templates - theme on the OPAC. - + + + + - "The OPAC is located at http://" - pref: OPACBaseURL class: url @@ -22,6 +26,14 @@ OPAC: no: Disable - "Koha OPAC as public. Private OPAC requires authentification before accessing the OPAC." - + - "Show star-ratings on" + - pref: OpacStarRatings + choices: + all: "results and details" + disable: "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..e89096b --- /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..a500e2c --- /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 a5be324..f44133e 100644 --- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt +++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-detail.tt @@ -9,6 +9,9 @@ {lang: '[% lang %]'} [% END %] + + + [% IF ( opacuserlogin ) %][% IF ( loggedinusername ) %][% IF ( TagsEnabled ) %]