Bugzilla – Attachment 21991 Details for
Bug 9055
Mandumah.com's multiple branch search, multiple branch security mod
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Multibranch search/security patch
0001-Bug-9055-Mandumah.com-s-multiple-branch-search-multi.patch (text/plain), 51.08 KB, created by
Waylon Robertson
on 2013-10-15 05:08:48 UTC
(
hide
)
Description:
Multibranch search/security patch
Filename:
MIME Type:
Creator:
Waylon Robertson
Created:
2013-10-15 05:08:48 UTC
Size:
51.08 KB
patch
obsolete
>From cce4d5b5c02275f0214e74db752ce07184a6ee87 Mon Sep 17 00:00:00 2001 >From: Waylon Robertson <wrobertson1981@yahoo.co.nz> >Date: Mon, 14 Oct 2013 09:27:17 -0500 >Subject: [PATCH 1/2] Bug 9055 - Mandumah.com's multiple branch search, multiple branch security mod > This mod creates the ability to search multiple branches using a jquery dropdown, instead of just one or all branches. > >This mod also replaces SearchMyLibraryFirst preference, giving three options. >All = no change from standard koha setup. >Preferhome = Prefers patron's home library (others may be searched), koha's current functionality of SearchMyLibraryFirst. >Securehome = Only patrons' home library and other assigned libraries (if any) can be searched. >With multiple instances of branchcode inside Borrower extended attributes, a patron can be given multiple branches to search within. The Securehome concept also includes the branch given in the apache enviroment of the host/virtualhost contacted, from OPAC_SEARCH_LIMIT = "branch: blah" > >This patch not only filters the GetBranches results, filtering the patrons ability to see other branches other than the ones given, it also filters the branches given in the limit branch: search options, so that even if a user manually inputted a branch, they are still only getting what they are ment to get. > >This enhancement would be useful for big libraries, in which its members would be restricted to searching and borrowing from a subset of its books. > >Overall, the multiple branch search dropdown should prove useful, even with unsecure installations. What is not included yet, is a method to decide what branches to show to a guest, not-logged-in, user. > >To use this patch, you need to create a branchcode Patron Extended Attribute, and have the patron your working with, have one or more branchcode extended attributes. >So, total branches that patron will get: >OPAC_SEARCH_LIMIT branch + Patron record home branch + whatever branchcodes you put into Borrower_attributes. >You also need to set the preferences, >In opac, set SearchableBranches >In Patrons, set multibranch. >In Searching, set MultiBranchSelect >--- > C4/Auth.pm | 6 +- > C4/Branch.pm | 26 +- > C4/Koha.pm | 4 +- > C4/Members/Attributes.pm | 14 +- > installer/data/mysql/sysprefs.sql | 4 +- > installer/data/mysql/updatedatabase.pl | 17 + > .../prog/en/modules/admin/preferences/opac.pref | 12 +- > .../prog/en/modules/admin/preferences/patrons.pref | 6 + > .../en/modules/admin/preferences/searching.pref | 7 + > .../lib/jquery/plugins/css/jquery.multiSelect.css | 85 +++ > .../jquery/plugins/images/dropdown.blue.active.png | Bin 0 -> 390 bytes > .../jquery/plugins/images/dropdown.blue.hover.png | Bin 0 -> 389 bytes > .../lib/jquery/plugins/images/dropdown.blue.png | Bin 0 -> 298 bytes > .../lib/jquery/plugins/images/dropdown.gif | Bin 0 -> 61 bytes > .../lib/jquery/plugins/images/dropdown_active.gif | Bin 0 -> 61 bytes > .../lib/jquery/plugins/images/dropdown_hover.gif | Bin 0 -> 61 bytes > .../lib/jquery/plugins/jquery.bgiframe.min.js | 7 + > .../lib/jquery/plugins/jquery.multiSelect.js | 554 ++++++++++++++++++++ > .../opac-tmpl/prog/en/modules/opac-advsearch.tt | 12 + > opac/opac-search.pl | 63 ++- > 20 files changed, 794 insertions(+), 23 deletions(-) > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/css/jquery.multiSelect.css > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.active.png > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.hover.png > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.png > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.gif > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_active.gif > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_hover.gif > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.bgiframe.min.js > create mode 100644 koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.multiSelect.js > >diff --git a/C4/Auth.pm b/C4/Auth.pm >index d73edaf..8bac25d 100644 >--- a/C4/Auth.pm >+++ b/C4/Auth.pm >@@ -382,9 +382,7 @@ sub get_template_and_user { > my $opac_name = ''; > if (($opac_search_limit && $opac_search_limit =~ /branch:(\w+)/ && $opac_limit_override) || ($in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:(\w+)/)){ > $opac_name = $1; # opac_search_limit is a branch, so we use it. >- } elsif ( $in->{'query'}->param('multibranchlimit') ) { >- $opac_name = $in->{'query'}->param('multibranchlimit'); >- } elsif (C4::Context->preference("SearchMyLibraryFirst") && C4::Context->userenv && C4::Context->userenv->{'branch'}) { >+ } elsif (C4::Context->preference("SearchableBranches") ne "all" && C4::Context->userenv && C4::Context->userenv->{'branch'}) { > $opac_name = C4::Context->userenv->{'branch'}; > } > $template->param( >@@ -430,7 +428,7 @@ sub get_template_and_user { > RequestOnOpac => C4::Context->preference("RequestOnOpac"), > 'Version' => C4::Context->preference('Version'), > hidelostitems => C4::Context->preference("hidelostitems"), >- mylibraryfirst => (C4::Context->preference("SearchMyLibraryFirst") && C4::Context->userenv) ? C4::Context->userenv->{'branch'} : '', >+ mylibraryfirst => (C4::Context->preference("SearchableBranches") ne 'all' && C4::Context->userenv) ? C4::Context->userenv->{'branch'} : '', > opaclayoutstylesheet => "" . C4::Context->preference("opaclayoutstylesheet"), > opacbookbag => "" . C4::Context->preference("opacbookbag"), > opaccredits => "" . C4::Context->preference("opaccredits"), >diff --git a/C4/Branch.pm b/C4/Branch.pm >index bdc01dc..4971bd6 100644 >--- a/C4/Branch.pm >+++ b/C4/Branch.pm >@@ -20,6 +20,8 @@ use strict; > #use warnings; FIXME - Bug 2505 > require Exporter; > use C4::Context; >+use C4::Members::Attributes; >+use C4::Members; > > use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); > >@@ -113,11 +115,33 @@ sub GetBranches { > my $sth; > my $query="SELECT * FROM branches"; > my @bind_parameters; >+ my $borrowernumber; >+ if(C4::Context->userenv){$borrowernumber = C4::Context->userenv->{number}}; >+ > if ($onlymine && C4::Context->userenv && C4::Context->userenv->{branch}){ > $query .= ' WHERE branchcode = ? '; > push @bind_parameters, C4::Context->userenv->{branch}; >+ } elsif(C4::Context->preference("SearchableBranches") eq 'securehome' && C4::Context->userenv && $borrowernumber !=0) { # Preference is set to search only the branches specified in patron record. >+ my %borrower_branches; >+ if(C4::Context->preference("multibranch")) { >+ my $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, "branchcode",1); #calling for an arrayref with all values. >+ foreach my $branchcode (@{$value}) { >+ $borrower_branches{$$branchcode[0]} = 1; >+ } >+ } >+ my $members = GetMember( 'borrowernumber' => $borrowernumber ); >+ my $homebranch = $members->{'branchcode'}; >+ $borrower_branches{$homebranch} = 1 if $homebranch; >+ if($ENV{'OPAC_SEARCH_LIMIT'} =~ m/^branch:(.*)/){ >+ $borrower_branches{$1} = 1; >+ } >+ my @allowedbranches; >+ foreach my $branch (keys %borrower_branches) { >+ push @allowedbranches, $branch; >+ } >+ $query .= ' WHERE branchcode in (\''.join('\',\'',@allowedbranches).'\')';; > } >- $query.=" ORDER BY branchname"; >+ $query.=" ORDER BY branchname"; > $sth = $dbh->prepare($query); > $sth->execute( @bind_parameters ); > >diff --git a/C4/Koha.pm b/C4/Koha.pm >index c5b32a6..69c7b90 100644 >--- a/C4/Koha.pm >+++ b/C4/Koha.pm >@@ -711,7 +711,7 @@ sub getFacets { > ]; > > my $library_facet; >- unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) { >+ unless ( C4::Context->preference("singleBranchMode") || C4::Branch::GetBranchesCount() == 1 ) { > $library_facet = { > idx => 'branch', > label => 'Libraries', >@@ -773,7 +773,7 @@ sub getFacets { > ]; > > my $library_facet; >- unless ( C4::Context->preference("singleBranchMode") || GetBranchesCount() == 1 ) { >+ unless ( C4::Context->preference("singleBranchMode") || C4::Branch::GetBranchesCount() == 1 ) { > $library_facet = { > idx => 'branch', > label => 'Libraries', >diff --git a/C4/Members/Attributes.pm b/C4/Members/Attributes.pm >index f0ec07f..eeca1d9 100644 >--- a/C4/Members/Attributes.pm >+++ b/C4/Members/Attributes.pm >@@ -120,24 +120,28 @@ sub GetAttributes { > > =head2 GetBorrowerAttributeValue > >- my $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, $attribute_code); >+ my $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, $attribute_code, $as_array); > > Retrieve the value of an extended attribute C<$attribute_code> associated with the >-patron specified by C<$borrowernumber>. >+patron specified by C<$borrowernumber>. If $as_array is true, gets all available values, and returns it as an arrayref. > > =cut > > sub GetBorrowerAttributeValue { > my $borrowernumber = shift; > my $code = shift; >- >+ my $as_array = shift; > my $dbh = C4::Context->dbh(); > my $query = "SELECT attribute > FROM borrower_attributes > WHERE borrowernumber = ? > AND code = ?"; >- my $value = $dbh->selectrow_array($query, undef, $borrowernumber, $code); >- return $value; >+ if ($as_array){ >+ return $dbh->selectall_arrayref($query,undef, $borrowernumber, $code); >+ } else { >+ my $value = $dbh->selectrow_array($query, undef, $borrowernumber, $code); >+ return $value; >+ } > } > > =head2 SearchIdMatchingAttribute >diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql >index 71513ce..91a7aa9 100644 >--- a/installer/data/mysql/sysprefs.sql >+++ b/installer/data/mysql/sysprefs.sql >@@ -180,6 +180,8 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('maxreserves','50','','Define maximum number of holds a patron can place','Integer'), > ('memberofinstitution','0',NULL,'If ON, patrons can be linked to institutions','YesNo'), > ('minPasswordLength','3',NULL,'Specify the minimum length of a patron/staff password','free'), >+('multibranch',0,NULL,'If ON, patrons having borrower_attribute's of branchcode, will have them added to their branches allowed, list. Filters all branch lists and opac searches.','YesNo'), >+('MultiBranchSelect',0,NULL,'If ON, Shows a muiltibranch dropdown instead of a single branch, in advanced search by branch','YesNo'), > ('NewItemsDefaultLocation','','','If set, all new items will have a location of the given Location Code ( Authorized Value type LOC )',''), > ('noissuescharge','5','','Define maximum amount withstanding before check outs are blocked','Integer'), > ('noItemTypeImages','0',NULL,'If ON, disables item-type images','YesNo'), >@@ -326,7 +328,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('RoutingSerials','1',NULL,'If ON, serials routing is enabled','YesNo'), > ('SCOUserCSS','',NULL,'Add CSS to be included in the SCO module in an embedded <style> tag.','free'), > ('SCOUserJS','',NULL,'Define custom javascript for inclusion in the SCO module','free'), >-('SearchMyLibraryFirst','0',NULL,'If ON, OPAC searches return results limited by the user\'s library by default if they are logged in','YesNo'), >+('SearchableBranches','all','all|preferhome|securehome','Sets level of security, and search preference. all - default koha search all, or one specified library, all libraries is the default. preferhome - sets the patrons home library as the default search limit. securehome - Only patrons home library, and others specified by enviroment, and borrower extended attributes (If Patron - Multibranch is enabled), can be searched. Home library set by default.','Choice'), > ('SelfCheckHelpMessage','','70|10','Enter HTML to include under the basic Web-based Self Checkout instructions on the Help page','Textarea'), > ('SelfCheckTimeout','120','','Define the number of seconds before the Web-based Self Checkout times out a patron','Integer'), > ('SeparateHoldings','0',NULL,'Separate current branch holdings from other holdings','YesNo'), >diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl >index d5015ea..8daaa3f 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -7215,7 +7215,24 @@ if ( CheckVersion($DBversion) ) { > print "Upgrade to $DBversion done (Bug 10854: Add the default CSV profile for claiming issues)\n"; > SetVersion($DBversion); > } >+$DBversion = "XXX"; >+if ( CheckVersion($DBversion) ) { >+ $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MultiBranchSelect',0,'If ON, Shows a muiltibranch dropdown instead of a single branch, in advanced search by branch',NULL,'YesNo');"); >+ print "Upgrade to $DBversion done (Bug 9055, Added MultiBranchSelect syspref)"; >+ SetVersion($DBversion); >+} >+ >+$DBversion = "XXX"; >+if ( CheckVersion($DBversion) ) { >+ $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('SearchableBranches','all','Sets level of security, and search preference. all - default koha search all, or one specified library, all libraries is the default. preferhome - sets the patrons home library as the default search limit. securehome - Only patrons home library, and others specified by enviroment, and borrower extended attributes (If Patron - Multibranch is enabled), can be searched. Home library set by default.','all|preferhome|securehome','Choice');"); >+ print "Upgrade to $DBversion done (Bug 9055, Added SearchableBranches syspref)"; >+ SetVersion($DBversion); >+} > >+$DBversion = "XXX"; >+if ( CheckVersion($DBversion) ) { >+ $dbh->do("INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('multibranch',0,'If ON, patrons having borrower_attribute's of branchcode, will have them added to their branches allowed, list. Filters all branch lists and opac searches.',NULL,'YesNo');"); >+ print "Upgrade to $DBversion done (Bug 9055, Added multibranch syspref"; > > > =head1 FUNCTIONS >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 a75c7ef..f7c51a1 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 >@@ -434,11 +434,13 @@ OPAC: > no: Allow > - patrons to select their branch on the OPAC or show branch names with callnumbers. > - >- - pref: SearchMyLibraryFirst >- choices: >- yes: Limit >- no: "Don't limit" >- - "patrons' searches to the library they are registered at." >+ - Search >+ - pref: SearchableBranches >+ choices: >+ all: All libraries >+ preferhome: Prefers patrons' home library (others may be searched) >+ securehome: Only patrons' home library and other assigned libraries (if any) can be searched >+ - Note, Other assigned libraries are only accessable by logged-in users. Otherwise, in Only mode, Home library is set via virtualhost option, and no other libraries are available. Multiple libraries can only be assigned when Multibranch is enabled, found in the Patron syspref page. > # - > # This system preference does not actually affect anything > # - pref: OpacBrowser >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >index 74d14af..9675465 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >@@ -91,6 +91,12 @@ Patrons: > class: integer > - characters long. > - >+ - pref: multibranch >+ choices: >+ yes: "ON" >+ no: "off" >+ - If ON, patrons having borrower_attribute's of branchcode, will have them added to their branches allowed, list. Filters all branch lists and opac searches. >+ - > - Show a notice that a patron is about to expire > - pref: NotifyBorrowerDeparture > class: integer >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref >index 29da64e..4a77a3b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/searching.pref >@@ -79,6 +79,13 @@ Searching: > - "fields (separate values with |). Tabs appear in the order listed.<br/>" > - "<em>Currently supported values</em>: Item types (<strong>itemtypes</strong>), Collection Codes (<strong>ccode</strong>) and Shelving Location (<strong>loc</strong>)." > - >+ - pref: MultiBranchSelect >+ type: boolean >+ choices: >+ yes: Show >+ no: "Don't show" >+ - 'a multibranch dropdown instead of single branch.' >+ - > - By default, > - pref: expandedSearchOption > type: boolean >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/css/jquery.multiSelect.css b/koha-tmpl/opac-tmpl/lib/jquery/plugins/css/jquery.multiSelect.css >new file mode 100644 >index 0000000..bd1291e >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/lib/jquery/plugins/css/jquery.multiSelect.css >@@ -0,0 +1,85 @@ >+a.multiSelect { >+ background: #FFF url(../images/dropdown.blue.png) right center no-repeat; >+ border: solid 1px #BBB; >+ padding-right: 20px; >+ position: relative; >+ cursor: default; >+ text-decoration: none; >+ color: black; >+ display: -moz-inline-stack; >+ display: inline-block; >+ vertical-align: top; >+} >+ >+a.multiSelect:link, a.multiSelect:visited, a.multiSelect:hover, a.multiSelect:active { >+ color: black; >+ text-decoration: none; >+} >+ >+a.multiSelect span >+{ >+ margin: 1px 0px 1px 3px; >+ overflow: hidden; >+ display: -moz-inline-stack; >+ display: inline-block; >+ white-space: nowrap; >+} >+ >+a.multiSelect.hover { >+ background-image: url(../images/dropdown.blue.hover.png); >+} >+ >+a.multiSelect.active, >+a.multiSelect.focus { >+ border: inset 1px #000; >+} >+ >+a.multiSelect.active { >+ background-image: url(../images/dropdown.blue.active.png); >+} >+ >+.multiSelectOptions { >+ margin-top: -1px; >+ overflow-y: auto; >+ overflow-x: hidden; >+ border: solid 1px #B2B2B2; >+ background: #FFF; >+} >+ >+.multiSelectOptions LABEL { >+ padding: 0px 2px; >+ display: block; >+ white-space: nowrap; >+} >+ >+.multiSelectOptions LABEL.optGroup >+{ >+ font-weight: bold; >+} >+ >+.multiSelectOptions .optGroupContainer LABEL >+{ >+ padding-left: 10px; >+} >+ >+.multiSelectOptions.optGroupHasCheckboxes .optGroupContainer LABEL >+{ >+ padding-left: 18px; >+} >+ >+.multiSelectOptions input{ >+ vertical-align: middle; >+} >+ >+.multiSelectOptions LABEL.checked { >+ background-color: #dce5f8; >+} >+ >+.multiSelectOptions LABEL.selectAll { >+ border-bottom: dotted 1px #CCC; >+} >+ >+.multiSelectOptions LABEL.hover { >+ background-color: #3399ff; >+ color: white; >+} >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.active.png b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.active.png >new file mode 100644 >index 0000000000000000000000000000000000000000..fac4ca59f96b821289471265cdb6fac7f42e4244 >GIT binary patch >literal 390 >zcmV;10eSw3P)<h;3K|Lk000e1NJLTq000mG000vR0ssI276lrZ0000PbVXQnQ*UN; >zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzC`m*?RCwBAC|q#&KPiBTfkZ&E1{MhQ >z@83V7jAvqkYWVY?uxg-@9B>=H|0c@$9L#VH#JK1m13w!~!?)igdiv*ID4&g)ftQt$ >zof$<DQ1<ih|G)ksX?XbJ7la|s%iK9(78fTwFpl25{dD)i^T$tL{r&T8`>y3LKmXMf >z;$T6u@yoA&T`id&fn}e+{`m0W!|xv-|Nj1Z_xhg8&wiss93wLm1bzF%c;&_49qYSa >zzkK-P)01CcU);UE7bpT0XJTYRXkcYxf}>x57;n7#cjwZkKR-V{x_1i528sa1Sy-45 >zegK+|;>$k_H(&ibcHu0L1hOHr{~7)xG_auih2htKhF?GbBTM~fU_@wOWMm{51B}S= >kU?s;ytK?0x27mwq0Qp+3&)Uv<Qvd(}07*qoM6N<$f?RB|KL7v# > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.hover.png b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.hover.png >new file mode 100644 >index 0000000000000000000000000000000000000000..148420be350079f9d3b435fe966f5fcea6c280f7 >GIT binary patch >literal 389 >zcmV;00eb$4P)<h;3K|Lk000e1NJLTq000mG000vR0ssI276lrZ0000PbVXQnQ*UN; >zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzCrLy>RCwBAC|q#&KPiBTfkZ&E1{MhQ >z@83V7jAvqkYWVY?uxg-@9B>=H|0c@$9L#VH#JK1m13w!~!#A)EtV|5ttc<Lv0rC4E >z!`I*cfB!@E^v}N_l8u?MqIwz^Cp$2_-@N^F_rdeWPhb80^X<&()j$9KN73-`#V;Vq >z&Cb}>lIamx_WA3N4<A1K{_*ke@2_{S@45W!*VmsQ4Vpq6DAof-FF*UeV|~}_mk)n@ >zdh+Y*3$W_n5Y;FV$H>eCLEru`UU~8N*2PVKetvv#_Y{x~6oE)FF)|^X#L9%Q>enBJ >z8?XKyIe!L7{`vz914d-Sp&FRsqL487143xx{~7)xG_bG`j)wmXj0g>kjEn>|Fd_%5 >jl^heTk~hg300ImE3>>eCISlV200000NkvXXu0mjf+ZnKq > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.png b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.blue.png >new file mode 100644 >index 0000000000000000000000000000000000000000..8cd370cd8613218d30207a4aecb0869bf5d80471 >GIT binary patch >literal 298 >zcmV+_0oDGAP)<h;3K|Lk000e1NJLTq000mG000vR0ssI276lrZ0000PbVXQnQ*UN; >zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy%t=H+RCwBAn7RAKe^LMw1Brn48dxCI >z-~WV_0+p~Z!ZiH)ON8M-)y!}W|A=xACo@SlAp7Ar%!Uaw&Tw)t|NqbM_T$fo&%Qi; >z@$vVMce_@lqHB2d;SYon6=6`*cHrx`Kkq+&`uXX}uWzr{u5O0QN^!Gb3D%Y>hZj$- >ze|moA^Xtn%)!5^Kk%<u*tyq-z<MWfPJLVt@0ttkZn86%muxrl}%wR>*z{E&I#QjHT >wU}7RBrjeY)$jC@UL?by#O?dDmZ-4*;0E$d_BR;<G8UO$Q07*qoM6N<$f{0&&cmMzZ > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.gif b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown.gif >new file mode 100644 >index 0000000000000000000000000000000000000000..7b6ffd7514be70605f1a0d481c700b92f7a36835 >GIT binary patch >literal 61 >zcmZ?wbhEHb6krfwXkcWRIdkU!|Nj+#vM@3*Ff!;c00Bsbfk~vNf92`7{K?E)E@d9v >O{P7fj+oK8*25SHywiDq1 > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_active.gif b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_active.gif >new file mode 100644 >index 0000000000000000000000000000000000000000..582130f70095645d3d8902da7c36f2c4877f481d >GIT binary patch >literal 61 >zcmZ?wbhEHb6krfwXkcUjg8%>jEB<5wG8q|kKzxu41CvNk|H{*E`4_h=xOGdf%={f^ >K+oA{t25SJ!N)cQD > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_hover.gif b/koha-tmpl/opac-tmpl/lib/jquery/plugins/images/dropdown_hover.gif >new file mode 100644 >index 0000000000000000000000000000000000000000..3c007412afad01ddb9fd3394f8471e19e6c2cec6 >GIT binary patch >literal 61 >zcmZ?wbhEHb6krfwXkcUjg8%>jEB<5wG8q|kKzxu41CvNk|H{*E`IDKqT*^GS`Qs`6 >Kwnr5r4Aub5ViFbr > >literal 0 >HcmV?d00001 > >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.bgiframe.min.js b/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.bgiframe.min.js >new file mode 100644 >index 0000000..36be59d >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.bgiframe.min.js >@@ -0,0 +1,7 @@ >+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) >+ * Licensed under the MIT License (LICENSE.txt). >+ * >+ * Version 2.1.3-pre >+ */ >+ >+(function($){$.fn.bgiframe=($.browser.msie&&/msie 6\.0/i.test(navigator.userAgent)?function(s){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s);var html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($(this).children('iframe.bgiframe').length===0)this.insertBefore(document.createElement(html),this.firstChild)})}:function(){return this});$.fn.bgIframe=$.fn.bgiframe;function prop(n){return n&&n.constructor===Number?n+'px':n}})(jQuery); >\ No newline at end of file >diff --git a/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.multiSelect.js b/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.multiSelect.js >new file mode 100644 >index 0000000..0de0a44 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/lib/jquery/plugins/jquery.multiSelect.js >@@ -0,0 +1,554 @@ >+/* >+// jQuery multiSelect >+// >+// Version 1.2.2 beta >+// >+// Cory S.N. LaViska >+// A Beautiful Site (http://abeautifulsite.net/) >+// 09 September 2009 >+// >+// Visit http://abeautifulsite.net/notebook/62 for more information >+// >+// (Amended by Andy Richmond, Letters & Science Deans' Office, University of California, Davis) >+// >+// Usage: $('#control_id').multiSelect( options, callback ) >+// >+// Options: selectAll - whether or not to display the Select All option; true/false, default = true >+// selectAllText - text to display for selecting/unselecting all options simultaneously >+// noneSelected - text to display when there are no selected items in the list >+// oneOrMoreSelected - text to display when there are one or more selected items in the list >+// (note: you can use % as a placeholder for the number of items selected). >+// Use * to show a comma separated list of all selected; default = '% selected' >+// optGroupSelectable - whether or not optgroups are selectable if you use them; true/false, default = false >+// listHeight - the max height of the droptdown options >+// >+// Dependencies: jQuery 1.2.6 or higher (http://jquery.com/) >+// >+// Change Log: >+// >+// 1.0.1 - Updated to work with jQuery 1.2.6+ (no longer requires the dimensions plugin) >+// - Changed $(this).offset() to $(this).position(), per James' and Jono's suggestions >+// >+// 1.0.2 - Fixed issue where dropdown doesn't scroll up/down with keyboard shortcuts >+// - Changed '$' in setTimeout to use 'jQuery' to support jQuery.noConflict >+// - Renamed from jqueryMultiSelect.* to jquery.multiSelect.* per the standard recommended at >+// http://docs.jquery.com/Plugins/Authoring (does not affect API methods) >+// >+// 1.0.3 - Now uses the bgiframe plugin (if it exists) to fix the IE6 layering bug. >+// - Forces IE6 to use a min-height of 200px (this needs to be added to the options) >+// >+// 1.1.0 - Added the ability to update the options dynamically via javascript: multiSelectOptionsUpdate(JSON) >+// - Added a title that displays the whole comma delimited list when using oneOrMoreSelected = * >+// - Moved some of the functions to be closured to make them private >+// - Changed the way the keyboard navigation worked to more closely match how a standard dropdown works >+// - ** by Andy Richmond ** >+// >+// 1.2.0 - Added support for optgroups >+// - Added the ability for selectable optgroups (i.e. select all for an optgroup) >+// - ** by Andy Richmond ** >+// >+// 1.2.1 - Fixed bug where input text overlapped dropdown arrow in IE (i.e. when using oneOrMoreSelected = *) >+// - Added option "listHeight" for min-height of the dropdown >+// - Fixed bug where bgiframe was causing a horizontal scrollbar and on short lists extra whitespace below the options >+// - ** by Andy Richmond ** >+// >+// 1.2.2 - Fixed bug where the keypress stopped showing the dropdown because in jQuery 1.3.2 they changed the way ':visible' works >+// - Fixed some other bugs in the way the keyboard interface worked >+// - Changed the main textbox to an <a> tag (with 'display: inline-block') to prevent the display text from being selected/highlighted >+// - Added the ability to jump to an option by typing the first character of that option (simular to a normal drop down) >+// - ** by Andy Richmond ** >+// - Added [] to make each control submit an HTML array so $.serialize() works properly >+// >+// Licensing & Terms of Use >+// >+// This plugin is dual-licensed under the GNU General Public License and the MIT License and >+// is copyright 2008 A Beautiful Site, LLC. >+// >+*/ >+if(jQuery) (function($){ >+ >+ // render the html for a single option >+ function renderOption(id, option) >+ { >+ var html = '<label><input type="checkbox" name="' + id + '[]" value="' + option.value + '"'; >+ if( option.selected ){ >+ html += ' checked="checked"'; >+ } >+ html += ' />' + option.text + '</label>'; >+ >+ return html; >+ } >+ >+ // render the html for the options/optgroups >+ function renderOptions(id, options, o) >+ { >+ var html = ""; >+ >+ for(var i = 0; i < options.length; i++) { >+ if(options[i].optgroup) { >+ html += '<label class="optGroup">'; >+ >+ if(o.optGroupSelectable) { >+ html += '<input type="checkbox" class="optGroup" />' + options[i].optgroup; >+ } >+ else { >+ html += options[i].optgroup; >+ } >+ >+ html += '</label><div class="optGroupContainer">'; >+ >+ html += renderOptions(id, options[i].options, o); >+ >+ html += '</div>'; >+ } >+ else { >+ html += renderOption(id, options[i]); >+ } >+ } >+ >+ return html; >+ } >+ >+ // Building the actual options >+ function buildOptions(options) >+ { >+ var multiSelect = $(this); >+ var multiSelectOptions = multiSelect.next('.multiSelectOptions'); >+ var o = multiSelect.data("config"); >+ var callback = multiSelect.data("callback"); >+ >+ // clear the existing options >+ multiSelectOptions.html(""); >+ var html = ""; >+ >+ // if we should have a select all option then add it >+ if( o.selectAll ) { >+ html += '<label class="selectAll"><input type="checkbox" class="selectAll" />' + o.selectAllText + '</label>'; >+ } >+ >+ // generate the html for the new options >+ html += renderOptions(multiSelect.attr('id'), options, o); >+ >+ multiSelectOptions.html(html); >+ >+ // variables needed to account for width changes due to a scrollbar >+ var initialWidth = multiSelectOptions.width(); >+ var hasScrollbar = false; >+ >+ // set the height of the dropdown options >+ if(multiSelectOptions.height() > o.listHeight) { >+ multiSelectOptions.css("height", o.listHeight + 'px'); >+ hasScrollbar = true; >+ } else { >+ multiSelectOptions.css("height", ''); >+ } >+ >+ // if the there is a scrollbar and the browser did not already handle adjusting the width (i.e. Firefox) then we will need to manaually add the scrollbar width >+ var scrollbarWidth = hasScrollbar && (initialWidth == multiSelectOptions.width()) ? 17 : 0; >+ >+ // set the width of the dropdown options >+ if((multiSelectOptions.width() + scrollbarWidth) < multiSelect.outerWidth()) { >+ multiSelectOptions.css("width", multiSelect.outerWidth() - 2/*border*/ + 'px'); >+ } else { >+ multiSelectOptions.css("width", (multiSelectOptions.width() + scrollbarWidth) + 'px'); >+ } >+ >+ // Apply bgiframe if available on IE6 >+ if( $.fn.bgiframe ) multiSelect.next('.multiSelectOptions').bgiframe( { width: multiSelectOptions.width(), height: multiSelectOptions.height() }); >+ >+ // Handle selectAll oncheck >+ if(o.selectAll) { >+ multiSelectOptions.find('INPUT.selectAll').click( function() { >+ // update all the child checkboxes >+ multiSelectOptions.find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked')); >+ }); >+ } >+ >+ // Handle OptGroup oncheck >+ if(o.optGroupSelectable) { >+ multiSelectOptions.addClass('optGroupHasCheckboxes'); >+ >+ multiSelectOptions.find('INPUT.optGroup').click( function() { >+ // update all the child checkboxes >+ $(this).parent().next().find('INPUT:checkbox').attr('checked', $(this).attr('checked')).parent("LABEL").toggleClass('checked', $(this).attr('checked')); >+ }); >+ } >+ >+ // Handle all checkboxes >+ multiSelectOptions.find('INPUT:checkbox').click( function() { >+ // set the label checked class >+ $(this).parent("LABEL").toggleClass('checked', $(this).attr('checked')); >+ >+ updateSelected.call(multiSelect); >+ multiSelect.focus(); >+ if($(this).parent().parent().hasClass('optGroupContainer')) { >+ updateOptGroup.call(multiSelect, $(this).parent().parent().prev()); >+ } >+ if( callback ) { >+ callback($(this)); >+ } >+ }); >+ >+ // Initial display >+ multiSelectOptions.each( function() { >+ $(this).find('INPUT:checked').parent().addClass('checked'); >+ }); >+ >+ // Initialize selected and select all >+ updateSelected.call(multiSelect); >+ >+ // Initialize optgroups >+ if(o.optGroupSelectable) { >+ multiSelectOptions.find('LABEL.optGroup').each( function() { >+ updateOptGroup.call(multiSelect, $(this)); >+ }); >+ } >+ >+ // Handle hovers >+ multiSelectOptions.find('LABEL:has(INPUT)').hover( function() { >+ $(this).parent().find('LABEL').removeClass('hover'); >+ $(this).addClass('hover'); >+ }, function() { >+ $(this).parent().find('LABEL').removeClass('hover'); >+ }); >+ >+ // Keyboard >+ multiSelect.keydown( function(e) { >+ >+ var multiSelectOptions = $(this).next('.multiSelectOptions'); >+ >+ // Is dropdown visible? >+ if( multiSelectOptions.css('visibility') != 'hidden' ) { >+ // Dropdown is visible >+ // Tab >+ if( e.keyCode == 9 ) { >+ $(this).addClass('focus').trigger('click'); // esc, left, right - hide >+ $(this).focus().next(':input').focus(); >+ return true; >+ } >+ >+ // ESC, Left, Right >+ if( e.keyCode == 27 || e.keyCode == 37 || e.keyCode == 39 ) { >+ // Hide dropdown >+ $(this).addClass('focus').trigger('click'); >+ } >+ // Down || Up >+ if( e.keyCode == 40 || e.keyCode == 38) { >+ var allOptions = multiSelectOptions.find('LABEL'); >+ var oldHoverIndex = allOptions.index(allOptions.filter('.hover')); >+ var newHoverIndex = -1; >+ >+ // if there is no current highlighted item then highlight the first item >+ if(oldHoverIndex < 0) { >+ // Default to first item >+ multiSelectOptions.find('LABEL:first').addClass('hover'); >+ } >+ // else if we are moving down and there is a next item then move >+ else if(e.keyCode == 40 && oldHoverIndex < allOptions.length - 1) >+ { >+ newHoverIndex = oldHoverIndex + 1; >+ } >+ // else if we are moving up and there is a prev item then move >+ else if(e.keyCode == 38 && oldHoverIndex > 0) >+ { >+ newHoverIndex = oldHoverIndex - 1; >+ } >+ >+ if(newHoverIndex >= 0) { >+ $(allOptions.get(oldHoverIndex)).removeClass('hover'); // remove the current highlight >+ $(allOptions.get(newHoverIndex)).addClass('hover'); // add the new highlight >+ >+ // Adjust the viewport if necessary >+ adjustViewPort(multiSelectOptions); >+ } >+ >+ return false; >+ } >+ >+ // Enter, Space >+ if( e.keyCode == 13 || e.keyCode == 32 ) { >+ var selectedCheckbox = multiSelectOptions.find('LABEL.hover INPUT:checkbox'); >+ >+ // Set the checkbox (and label class) >+ selectedCheckbox.attr('checked', !selectedCheckbox.attr('checked')).parent("LABEL").toggleClass('checked', selectedCheckbox.attr('checked')); >+ >+ // if the checkbox was the select all then set all the checkboxes >+ if(selectedCheckbox.hasClass("selectAll")) { >+ multiSelectOptions.find('INPUT:checkbox').attr('checked', selectedCheckbox.attr('checked')).parent("LABEL").addClass('checked').toggleClass('checked', selectedCheckbox.attr('checked')); >+ } >+ >+ updateSelected.call(multiSelect); >+ >+ if( callback ) callback($(this)); >+ return false; >+ } >+ >+ // Any other standard keyboard character (try and match the first character of an option) >+ if( e.keyCode >= 33 && e.keyCode <= 126 ) { >+ // find the next matching item after the current hovered item >+ var match = multiSelectOptions.find('LABEL:startsWith(' + String.fromCharCode(e.keyCode) + ')'); >+ >+ var currentHoverIndex = match.index(match.filter('LABEL.hover')); >+ >+ // filter the set to any items after the current hovered item >+ var afterHoverMatch = match.filter(function (index) { >+ return index > currentHoverIndex; >+ }); >+ >+ // if there were no item after the current hovered item then try using the full search results (filtered to the first one) >+ match = (afterHoverMatch.length >= 1 ? afterHoverMatch : match).filter("LABEL:first"); >+ >+ if(match.length == 1) { >+ // if we found a match then move the hover >+ multiSelectOptions.find('LABEL.hover').removeClass('hover'); >+ match.addClass('hover'); >+ >+ adjustViewPort(multiSelectOptions); >+ } >+ } >+ } else { >+ // Dropdown is not visible >+ if( e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13 || e.keyCode == 32 ) { //up, down, enter, space - show >+ // Show dropdown >+ $(this).removeClass('focus').trigger('click'); >+ multiSelectOptions.find('LABEL:first').addClass('hover'); >+ return false; >+ } >+ // Tab key >+ if( e.keyCode == 9 ) { >+ // Shift focus to next INPUT element on page >+ multiSelectOptions.next(':input').focus(); >+ return true; >+ } >+ } >+ // Prevent enter key from submitting form >+ if( e.keyCode == 13 ) return false; >+ }); >+ } >+ >+ // Adjust the viewport if necessary >+ function adjustViewPort(multiSelectOptions) >+ { >+ // check for and move down >+ var selectionBottom = multiSelectOptions.find('LABEL.hover').position().top + multiSelectOptions.find('LABEL.hover').outerHeight(); >+ >+ if(selectionBottom > multiSelectOptions.innerHeight()){ >+ multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + selectionBottom - multiSelectOptions.innerHeight()); >+ } >+ >+ // check for and move up >+ if(multiSelectOptions.find('LABEL.hover').position().top < 0){ >+ multiSelectOptions.scrollTop(multiSelectOptions.scrollTop() + multiSelectOptions.find('LABEL.hover').position().top); >+ } >+ } >+ >+ // Update the optgroup checked status >+ function updateOptGroup(optGroup) >+ { >+ var multiSelect = $(this); >+ var o = multiSelect.data("config"); >+ >+ // Determine if the optgroup should be checked >+ if(o.optGroupSelectable) { >+ var optGroupSelected = true; >+ $(optGroup).next().find('INPUT:checkbox').each( function() { >+ if( !$(this).attr('checked') ) { >+ optGroupSelected = false; >+ return false; >+ } >+ }); >+ >+ $(optGroup).find('INPUT.optGroup').attr('checked', optGroupSelected).parent("LABEL").toggleClass('checked', optGroupSelected); >+ } >+ } >+ >+ // Update the textbox with the total number of selected items, and determine select all >+ function updateSelected() { >+ var multiSelect = $(this); >+ var multiSelectOptions = multiSelect.next('.multiSelectOptions'); >+ var o = multiSelect.data("config"); >+ >+ var i = 0; >+ var selectAll = true; >+ var display = ''; >+ multiSelectOptions.find('INPUT:checkbox').not('.selectAll, .optGroup').each( function() { >+ if( $(this).attr('checked') ) { >+ i++; >+ display = display + $(this).parent().text() + ', '; >+ } >+ else selectAll = false; >+ }); >+ >+ // trim any end comma and surounding whitespace >+ display = display.replace(/\s*\,\s*$/,''); >+ >+ if( i == 0 ) { >+ multiSelect.find("span").html( o.noneSelected ); >+ } else { >+ if( o.TwoOrMoreSelected != undefined ) { >+ if( i == 1 ) { >+ multiSelect.find("span").html( display ); >+ multiSelect.attr( "title", display ); >+ } >+ else { >+ multiSelect.find("span").html( o.TwoOrMoreSelected.replace('%', i) ); >+ } >+ } >+ if( o.oneOrMoreSelected == '*' ) { >+ multiSelect.find("span").html( display ); >+ multiSelect.attr( "title", display ); >+ } else { >+ if ( o.oneOrMoreSelected != "^"){ >+ multiSelect.find("span").html( o.oneOrMoreSelected.replace('%', i) ); >+ } >+ } >+ } >+ >+ // Determine if Select All should be checked >+ if(o.selectAll) { >+ multiSelectOptions.find('INPUT.selectAll').attr('checked', selectAll).parent("LABEL").toggleClass('checked', selectAll); >+ } >+ } >+ >+ $.extend($.fn, { >+ multiSelect: function(o, callback) { >+ // Default options >+ if( !o ) o = {}; >+ if( o.selectAll == undefined ) o.selectAll = true; >+ if( o.selectAllText == undefined ) o.selectAllText = "Select All"; >+ if( o.noneSelected == undefined ) o.noneSelected = 'Select options'; >+ if( o.oneOrMoreSelected == undefined ) o.oneOrMoreSelected = '% selected'; >+ if( o.optGroupSelectable == undefined ) o.optGroupSelectable = false; >+ if( o.listHeight == undefined ) o.listHeight = 150; >+ >+ // Initialize each multiSelect >+ $(this).each( function() { >+ var select = $(this); >+ var html = '<a href="javascript:;" class="multiSelect"><span></span></a>'; >+ html += '<div class="multiSelectOptions" style="position: absolute; z-index: 99999; visibility: hidden;"></div>'; >+ $(select).after(html); >+ >+ var multiSelect = $(select).next('.multiSelect'); >+ var multiSelectOptions = multiSelect.next('.multiSelectOptions'); >+ >+ // if the select object had a width defined then match the new multilsect to it >+ multiSelect.find("span").css("width", $(select).width() + 'px'); >+ >+ // Attach the config options to the multiselect >+ multiSelect.data("config", o); >+ >+ // Attach the callback to the multiselect >+ multiSelect.data("callback", callback); >+ >+ // Serialize the select options into json options >+ var options = []; >+ $(select).children().each( function() { >+ if(this.tagName.toUpperCase() == 'OPTGROUP') >+ { >+ var suboptions = []; >+ options.push({ optgroup: $(this).attr('label'), options: suboptions }); >+ >+ $(this).children('OPTION').each( function() { >+ if( $(this).val() != '' ) { >+ suboptions.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); >+ } >+ }); >+ } >+ else if(this.tagName.toUpperCase() == 'OPTION') >+ { >+ if( $(this).val() != '' ) { >+ options.push({ text: $(this).html(), value: $(this).val(), selected: $(this).attr('selected') }); >+ } >+ } >+ }); >+ >+ // Eliminate the original form element >+ $(select).remove(); >+ >+ // Add the id that was on the original select element to the new input >+ multiSelect.attr("id", $(select).attr("id")); >+ >+ // Build the dropdown options >+ buildOptions.call(multiSelect, options); >+ >+ // Events >+ multiSelect.hover( function() { >+ $(this).addClass('hover'); >+ }, function() { >+ $(this).removeClass('hover'); >+ }).click( function() { >+ // Show/hide on click >+ if( $(this).hasClass('active') ) { >+ $(this).multiSelectOptionsHide(); >+ } else { >+ $(this).multiSelectOptionsShow(); >+ } >+ return false; >+ }).focus( function() { >+ // So it can be styled with CSS >+ $(this).addClass('focus'); >+ }).blur( function() { >+ // So it can be styled with CSS >+ $(this).removeClass('focus'); >+ }); >+ >+ // Add an event listener to the window to close the multiselect if the user clicks off >+ $(document).click( function(event) { >+ // If somewhere outside of the multiselect was clicked then hide the multiselect >+ if(!($(event.target).parents().andSelf().is('.multiSelectOptions'))){ >+ multiSelect.multiSelectOptionsHide(); >+ } >+ }); >+ }); >+ }, >+ >+ // Update the dropdown options >+ multiSelectOptionsUpdate: function(options) { >+ buildOptions.call($(this), options); >+ }, >+ >+ // Hide the dropdown >+ multiSelectOptionsHide: function() { >+ $(this).removeClass('active').removeClass('hover').next('.multiSelectOptions').css('visibility', 'hidden'); >+ }, >+ >+ // Show the dropdown >+ multiSelectOptionsShow: function() { >+ var multiSelect = $(this); >+ var multiSelectOptions = multiSelect.next('.multiSelectOptions'); >+ var o = multiSelect.data("config"); >+ >+ // Hide any open option boxes >+ $('.multiSelect').multiSelectOptionsHide(); >+ multiSelectOptions.find('LABEL').removeClass('hover'); >+ multiSelect.addClass('active').next('.multiSelectOptions').css('visibility', 'visible'); >+ multiSelect.focus(); >+ >+ // reset the scroll to the top >+ multiSelect.next('.multiSelectOptions').scrollTop(0); >+ >+ // Position it >+ var offset = multiSelect.position(); >+ multiSelect.next('.multiSelectOptions').css({ top: offset.top + $(this).outerHeight() + 'px' }); >+ multiSelect.next('.multiSelectOptions').css({ left: offset.left + 'px' }); >+ }, >+ >+ // get a coma-delimited list of selected values >+ selectedValuesString: function() { >+ var selectedValues = ""; >+ $(this).next('.multiSelectOptions').find('INPUT:checkbox:checked').not('.optGroup, .selectAll').each(function() { >+ selectedValues += $(this).attr('value') + ","; >+ }); >+ // trim any end comma and surounding whitespace >+ return selectedValues.replace(/\s*\,\s*$/,''); >+ } >+ }); >+ >+ // add a new ":startsWith" search filter >+ $.expr[":"].startsWith = function(el, i, m) { >+ var search = m[3]; >+ if (!search) return false; >+ return eval("/^[/s]*" + search + "/i").test($(el).text()); >+ }; >+ >+})(jQuery); >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt >index 4c1c552..8c7d0d0 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt >@@ -3,9 +3,17 @@ > [% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] > catalog › Advanced search > [% INCLUDE 'doc-head-close.inc' %] >+[% IF (MultiBranchSelect) %] >+<script type="text/javascript" language="javascript" src="/opac-tmpl/lib/jquery/plugins/jquery.bgiframe.min.js"></script> >+<script type="text/javascript" language="javascript" src="/opac-tmpl/lib/jquery/plugins/jquery.multiSelect.js"></script> >+<link href="/opac-tmpl/lib/jquery/plugins//css/jquery.multiSelect.css" rel="stylesheet" type="text/css" /> >+[% END %] > <script type="text/javascript" language="javascript">//<![CDATA[ > $(document).ready(function() { > $('#advsearches').tabs(); >+ [% IF (MultiBranchSelect) %] >+ $('#branchloop').multiSelect({ TwoOrMoreSelected: 'Multiple Libraries', oneOrMoreSelected: '^' }); >+ [% END %] > }); > //]]> > </script> >@@ -297,7 +305,11 @@ > <div id="location" class="container"><fieldset><legend>Location and availability: </legend> > > <label for="branchloop">Library:</label> >+ [% IF ( MultiBranchSelect ) %] >+ <select name="limit" id="branchloop" multiple="multiple"> >+ [% ELSE %] > <select name="limit" id="branchloop"> >+ [% END %] > <option value="">All libraries</option> > [% FOREACH BranchesLoo IN BranchesLoop %] > [% IF ( BranchesLoo.selected ) %] >diff --git a/opac/opac-search.pl b/opac/opac-search.pl >index 2854da6..e9a4a55 100755 >--- a/opac/opac-search.pl >+++ b/opac/opac-search.pl >@@ -51,6 +51,8 @@ use C4::Tags qw(get_tags); > use C4::Branch; # GetBranches > use C4::SocialData; > use C4::Ratings; >+use C4::Members; >+use C4::Members::Attributes; > use C4::External::OverDrive; > > use POSIX qw(ceil floor strftime); >@@ -123,7 +125,6 @@ else { > if ($template_name eq 'opac-results.tmpl') { > $template->param('COinSinOPACResults' => C4::Context->preference('COinSinOPACResults')); > } >- > # get biblionumbers stored in the cart > my @cart_list; > >@@ -309,6 +310,11 @@ if ( $template_type && $template_type eq 'advsearch' ) { > $template->param( expanded_options => $cgi->param('expanded_options')); > } > } >+ >+ # If Multiple Branch Select is enabled, tell the template. >+ if (C4::Context->preference("MultiBranchSelect")){ >+ $template->param( MultiBranchSelect => 1 ) >+ } > > if (C4::Context->preference('OPACNumbersPreferPhrase')) { > $template->param('numbersphr' => 1); >@@ -400,20 +406,67 @@ if ($operands[0] && !$operands[1]) { > > # limits are use to limit to results to a pre-defined category such as branch or language > my @limits = $cgi->param('limit'); >-@limits = map { uri_unescape($_) } @limits; >- >+my @branches; > if($params->{'multibranchlimit'}) { >- my $multibranch = '('.join( " or ", map { "branch: $_ " } @{ GetBranchesInCategory( $params->{'multibranchlimit'} ) } ).')'; >- push @limits, $multibranch if ($multibranch ne '()'); >+ @branches = @{GetBranchesInCategory($params->{'multibranchlimit'})}; >+@limits = map { uri_unescape($_) } @limits; > } > > my $available; >+my @newlimit; > foreach my $limit(@limits) { > if ($limit =~/available/) { > $available = 1; > } >+ if ($limit =~ m/^branch:(.*)/){ >+ push @branches, $1; >+ } else { >+ push @newlimit, $limit; >+ } >+} >+@limits = @newlimit; >+ >+my @branchloop = $params->{'branchloop[]'}; >+foreach my $line(@branchloop){ >+ if ($line =~ m/^branch:(.*)/){ >+ push @branches, $1; >+ } > } >+ > $template->param(available => $available); >+my @finalbranches; >+if(C4::Context->preference("SearchableBranches") ne 'all') { >+if(C4::Context->preference("SearchableBranches") eq 'securehome') { # Preference is set to search only the branches specified in patron record. >+ my %borrower_branches; >+ if(C4::Context->preference("multibranch")) { >+ my $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, "branchcode",1); #calling for an arrayref with all values. >+ foreach my $branchcode (@{$value}) { >+ $borrower_branches{$$branchcode[0]} = 1; >+ } >+ } >+ my $members = GetMember( 'borrowernumber' => $borrowernumber ); >+ my $homebranch = $members->{'branchcode'}; >+ $borrower_branches{$homebranch} = 1 if $homebranch; >+ if($ENV{'OPAC_SEARCH_LIMIT'} =~ m/^branch:(.*)/){ >+ $borrower_branches{$1} = 1; >+ } >+ >+ foreach my $branchcode (@branches) { >+ if ($borrower_branches{$branchcode}) {push @finalbranches, $branchcode}; >+ } >+ >+ if (!@finalbranches) { >+ foreach my $branchcode (keys %borrower_branches) { >+ push @finalbranches, $branchcode; >+ } >+ } >+} >+ else { >+ push (@finalbranches, @branches); >+ } >+} else {push (@finalbranches, @branches);} >+push @limits, "(". join(" or ", map { "branch: $_ "} @finalbranches) .")" if @finalbranches; >+ > > # append year limits if they exist > if ($params->{'limit-yr'}) { >-- >1.7.2.5 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 9055
:
13377
|
13474
|
13475
|
21991
|
21992
|
22742
|
23014
|
23015
|
23016
|
23038
|
23250
|
23251
|
23252