Bugzilla – Attachment 13377 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 and security
0001-Multibranch-search-patrons-and-security-mod.patch (text/plain), 43.55 KB, created by
Waylon Robertson
on 2012-11-11 04:29:54 UTC
(
hide
)
Description:
Multibranch search and security
Filename:
MIME Type:
Creator:
Waylon Robertson
Created:
2012-11-11 04:29:54 UTC
Size:
43.55 KB
patch
obsolete
>From 4d6678d0b37e2c6540906ce4860987d888a4852a Mon Sep 17 00:00:00 2001 >From: Waylon Robertson <wrobertson1981@yahoo.co.nz> >Date: Sat, 10 Nov 2012 06:52:11 -0600 >Subject: [PATCH] Multibranch search, patrons and security mod > >--- > C4/Auth.pm | 4 +- > C4/Branch.pm | 24 +- > C4/Koha.pm | 4 +- > C4/Members/Attributes.pm | 14 +- > .../prog/en/modules/admin/preferences/opac.pref | 12 +- > .../prog/en/modules/admin/preferences/patrons.pref | 6 + > .../en/modules/admin/preferences/searching.pref | 7 + > .../opac-tmpl/prog/en/css/jquery.multiSelect.css | 85 +++ > .../opac-tmpl/prog/en/js/jquery.bgiframe.min.js | 7 + > .../opac-tmpl/prog/en/js/jquery.multiSelect.js | 554 ++++++++++++++++++++ > .../opac-tmpl/prog/en/modules/opac-advsearch.tt | 12 + > .../opac-tmpl/prog/images/dropdown.blue.active.png | Bin 0 -> 390 bytes > .../opac-tmpl/prog/images/dropdown.blue.hover.png | Bin 0 -> 389 bytes > koha-tmpl/opac-tmpl/prog/images/dropdown.blue.png | Bin 0 -> 298 bytes > koha-tmpl/opac-tmpl/prog/images/dropdown.gif | Bin 0 -> 61 bytes > .../opac-tmpl/prog/images/dropdown_active.gif | Bin 0 -> 61 bytes > koha-tmpl/opac-tmpl/prog/images/dropdown_hover.gif | Bin 0 -> 61 bytes > opac/opac-search.pl | 60 ++- > 18 files changed, 771 insertions(+), 18 deletions(-) > create mode 100644 koha-tmpl/opac-tmpl/prog/en/css/jquery.multiSelect.css > create mode 100644 koha-tmpl/opac-tmpl/prog/en/js/jquery.bgiframe.min.js > create mode 100644 koha-tmpl/opac-tmpl/prog/en/js/jquery.multiSelect.js > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown.blue.active.png > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown.blue.hover.png > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown.blue.png > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown.gif > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown_active.gif > create mode 100644 koha-tmpl/opac-tmpl/prog/images/dropdown_hover.gif > >diff --git a/C4/Auth.pm b/C4/Auth.pm >index 705eda0..e03b261 100644 >--- a/C4/Auth.pm >+++ b/C4/Auth.pm >@@ -383,7 +383,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 (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( >@@ -429,7 +429,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 d765c99..f42c6ce 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); > >@@ -109,11 +111,31 @@ 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 $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, "branchcode",1); #calling for an arrayref with all values. >+ my %borrower_branches; >+ 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 d38729a..bc32399 100644 >--- a/C4/Koha.pm >+++ b/C4/Koha.pm >@@ -717,7 +717,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', >@@ -779,7 +779,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 e175915..c431893 100644 >--- a/C4/Members/Attributes.pm >+++ b/C4/Members/Attributes.pm >@@ -118,24 +118,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/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref >index 1a9fa09..a4df4af 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 >@@ -389,11 +389,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..efdfdcd 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: Enable >+ no: Disable >+ - assigning multiple branches to a patron. >+ - > - 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 0b9e3cb..087b54a 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 >@@ -78,6 +78,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/prog/en/css/jquery.multiSelect.css b/koha-tmpl/opac-tmpl/prog/en/css/jquery.multiSelect.css >new file mode 100644 >index 0000000..5aafec9 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/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/prog/en/js/jquery.bgiframe.min.js b/koha-tmpl/opac-tmpl/prog/en/js/jquery.bgiframe.min.js >new file mode 100644 >index 0000000..36be59d >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/js/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/prog/en/js/jquery.multiSelect.js b/koha-tmpl/opac-tmpl/prog/en/js/jquery.multiSelect.js >new file mode 100644 >index 0000000..0de0a44 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/js/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 55eea18..b06d16c 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-advsearch.tt >@@ -2,9 +2,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="[% themelang %]/js/jquery.bgiframe.min.js"></script> >+<script type="text/javascript" language="javascript" src="[% themelang %]/js/jquery.multiSelect.js"></script> >+<link href="[% themelang %]/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> >@@ -268,7 +276,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/koha-tmpl/opac-tmpl/prog/images/dropdown.blue.active.png b/koha-tmpl/opac-tmpl/prog/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/prog/images/dropdown.blue.hover.png b/koha-tmpl/opac-tmpl/prog/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/prog/images/dropdown.blue.png b/koha-tmpl/opac-tmpl/prog/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/prog/images/dropdown.gif b/koha-tmpl/opac-tmpl/prog/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/prog/images/dropdown_active.gif b/koha-tmpl/opac-tmpl/prog/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/prog/images/dropdown_hover.gif b/koha-tmpl/opac-tmpl/prog/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/opac/opac-search.pl b/opac/opac-search.pl >index 7677d86..ce499b1 100755 >--- a/opac/opac-search.pl >+++ b/opac/opac-search.pl >@@ -51,7 +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 POSIX qw(ceil floor strftime); > use URI::Escape; > use Storable qw(thaw freeze); >@@ -293,6 +294,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 ) >+ } > output_html_with_http_headers $cgi, $cookie, $template->output; > exit; > } >@@ -374,18 +380,66 @@ 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'); >- >+my @finalbranches; >+my @branches; > if($params->{'multibranchlimit'}) { >- push @limits, '('.join( " or ", map { "branch: $_ " } @{ GetBranchesInCategory( $params->{'multibranchlimit'} ) } ).')'; >+ @branches = @{GetBranchesInCategory($params->{'multibranchlimit'})}; > } > > 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 $value = C4::Members::Attributes::GetBorrowerAttributeValue($borrowernumber, "branchcode",1); #calling for an arrayref with all values. >+ my %borrower_branches; >+ 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) { >+ warn $branchcode; >+ 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