Bugzilla – Attachment 27785 Details for
Bug 10486
Allow external Z39.50 targets to be searched from the OPAC
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
[SIGNED OFF] Bug 10486 - Allow external Z39.50 targets to be searched from the OPAC
SIGNED-OFF-Bug-10486---Allow-external-Z3950-target.patch (text/plain), 249.78 KB, created by
Katrin Fischer
on 2014-04-29 21:07:02 UTC
(
hide
)
Description:
[SIGNED OFF] Bug 10486 - Allow external Z39.50 targets to be searched from the OPAC
Filename:
MIME Type:
Creator:
Katrin Fischer
Created:
2014-04-29 21:07:02 UTC
Size:
249.78 KB
patch
obsolete
>From db92b5e95c79999d349f0f7225d688381bd14102 Mon Sep 17 00:00:00 2001 >From: Jesse Weaver <pianohacker@gmail.com> >Date: Wed, 29 May 2013 14:59:57 -0600 >Subject: [PATCH] [SIGNED OFF] Bug 10486 - Allow external Z39.50 targets to be > searched from the OPAC > >This adds a new page to the OPAC that can search several Z39.50 targets >using Pazpar2. > >Test plan: >1) Apply patches. >2) Update database. >3) Add one or more Z39.50 targets, using the Administration -> External > targets screen. Note that not all targets support keyword search, but > here are some that do: > * Library of Congress: lx2.loc.gov, 210, LCDB, none, none, MARC21, UTF-8 > * BNF2: z3950.bnf.fr, 2211, TOUT, Z3950, Z3950_BNF, UNIMARC, UTF-8 >4) Perform a search on the OPAC, check to see if the "external targets" > notice pops up at the top. >5) Click on the results link near that message. >6) This should bring back results from all enabled targets, all of which > should be clickable to bring up a detailed view of the record. > >(This version incorporates previous QA followups and some fixes for >translation and per-branch-limiting.) > >Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de> >Passes tests, template problem showing up in the QA should be ok. >More verbose notes on the bug report. >--- > C4/Search.pm | 30 + > C4/XSLT.pm | 24 +- > Makefile.PL | 4 +- > admin/external_targets.pl | 129 + > etc/koha-conf.xml | 13 - > etc/koha-httpd.conf | 15 +- > etc/pazpar2/generic-settings.xml | 21 + > etc/pazpar2/pazpar2.xml | 19 +- > etc/pazpar2/unimarc-work-groups.xsl | 98 + > installer/data/mysql/sysprefs.sql | 1 + > installer/data/mysql/updatedatabase.pl | 36 +- > .../intranet-tmpl/prog/en/css/staff-global.css | 14 + > .../intranet-tmpl/prog/en/includes/admin-menu.inc | 1 + > .../prog/en/modules/admin/admin-home.tt | 2 + > .../prog/en/modules/admin/external-targets.tt | 178 ++ > .../prog/en/modules/admin/preferences/opac.pref | 7 + > koha-tmpl/opac-tmpl/bootstrap/css/opac.css | 2692 +++++++++++++++++++- > .../bootstrap/en/modules/opac-external-search.tt | 249 ++ > .../opac-tmpl/bootstrap/en/modules/opac-results.tt | 63 +- > .../bootstrap/en/xslt/MARC21slim2OPACResults.xsl | 7 +- > .../bootstrap/en/xslt/MARC21slimUtils.xsl | 2 +- > .../bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl | 4 + > koha-tmpl/opac-tmpl/bootstrap/less/opac.less | 2 +- > koha-tmpl/opac-tmpl/ccsr/en/css/opac.css | 16 + > .../en/lib/jquery/plugins/jquery.lightbox_me.js | 254 ++ > koha-tmpl/opac-tmpl/lib/koha/externalsearch.js | 104 + > koha-tmpl/opac-tmpl/lib/pz2.js | 1124 ++++++++ > koha-tmpl/opac-tmpl/prog/en/css/opac.css | 27 +- > .../en/lib/jquery/plugins/jquery.lightbox_me.js | 254 ++ > .../prog/en/modules/opac-external-search.tt | 240 ++ > .../opac-tmpl/prog/en/modules/opac-results.tt | 63 +- > .../prog/en/xslt/MARC21slim2OPACResults.xsl | 6 +- > .../opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl | 2 +- > .../prog/en/xslt/UNIMARCslim2OPACResults.xsl | 4 + > opac/opac-external-search.pl | 62 + > opac/opac-search.pl | 12 +- > opac/svc/pazpar2_init | 101 + > rewrite-config.PL | 8 +- > t/XSLT.t | 94 +- > 39 files changed, 5895 insertions(+), 87 deletions(-) > create mode 100755 admin/external_targets.pl > create mode 100644 etc/pazpar2/generic-settings.xml > create mode 100644 etc/pazpar2/unimarc-work-groups.xsl > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/external-targets.tt > create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-external-search.tt > create mode 100644 koha-tmpl/opac-tmpl/ccsr/en/lib/jquery/plugins/jquery.lightbox_me.js > create mode 100644 koha-tmpl/opac-tmpl/lib/koha/externalsearch.js > create mode 100644 koha-tmpl/opac-tmpl/lib/pz2.js > create mode 100644 koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.lightbox_me.js > create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-external-search.tt > create mode 100755 opac/opac-external-search.pl > create mode 100755 opac/svc/pazpar2_init > >diff --git a/C4/Search.pm b/C4/Search.pm >index 2c63f9c..9235845 100644 >--- a/C4/Search.pm >+++ b/C4/Search.pm >@@ -72,6 +72,7 @@ This module provides searching functions for Koha's bibliographic databases > &GetDistinctValues > &enabled_staff_search_views > &PurgeSearchHistory >+ &GetExternalSearchTargets > ); > > # make all your functions, whether exported or not; >@@ -2438,6 +2439,35 @@ sub new_record_from_zebra { > > } > >+=head2 GetExternalSearchTargets >+ >+Returns the list of Z39.50 servers that are marked for search in the OPAC using >+Pazpar2. >+ >+=cut >+ >+sub GetExternalSearchTargets { >+ my ( $branchcode ) = @_; >+ >+ if ( $branchcode ) { >+ return C4::Context->dbh->selectall_arrayref( q{ >+ SELECT * FROM external_targets et >+ LEFT JOIN external_target_restrictions etr >+ ON (etr.target_id = et.target_id and etr.branchcode = ?) >+ WHERE etr.target_id IS NULL >+ ORDER BY et.name >+ }, { Slice => {} }, $branchcode ); >+ } else { >+ return C4::Context->dbh->selectall_arrayref( q{ >+ SELECT * FROM external_targets et >+ LEFT JOIN external_target_restrictions etr USING (target_id) >+ GROUP by et.target_id >+ HAVING branchcode IS NULL >+ ORDER BY et.name >+ }, { Slice => {} } ); >+ } >+} >+ > END { } # module clean-up code here (global destructor) > > 1; >diff --git a/C4/XSLT.pm b/C4/XSLT.pm >index d85b048..7ebac8a 100644 >--- a/C4/XSLT.pm >+++ b/C4/XSLT.pm >@@ -42,6 +42,7 @@ BEGIN { > $VERSION = 3.07.00.049; > @ISA = qw(Exporter); > @EXPORT = qw( >+ &XSLTGetFilename > &XSLTParse4Display > &GetURI > ); >@@ -156,9 +157,10 @@ sub _get_best_default_xslt_filename { > return $xslfilename; > } > >-sub XSLTParse4Display { >- my ( $biblionumber, $orig_record, $xslsyspref, $fixamps, $hidden_items ) = @_; >- my $xslfilename = C4::Context->preference($xslsyspref); >+sub XSLTGetFilename { >+ my ( $marcflavour, $xslsyspref ) = @_; >+ >+ my $xslfilename = $marcflavour eq C4::Context->preference('marcflavour') ? C4::Context->preference($xslsyspref) : 'default'; > if ( $xslfilename =~ /^\s*"?default"?\s*$/i ) { > my $htdocs; > my $theme; >@@ -167,22 +169,22 @@ sub XSLTParse4Display { > if ($xslsyspref eq "XSLTDetailsDisplay") { > $htdocs = C4::Context->config('intrahtdocs'); > $theme = C4::Context->preference("template"); >- $xslfile = C4::Context->preference('marcflavour') . >+ $xslfile = $marcflavour . > "slim2intranetDetail.xsl"; > } elsif ($xslsyspref eq "XSLTResultsDisplay") { > $htdocs = C4::Context->config('intrahtdocs'); > $theme = C4::Context->preference("template"); >- $xslfile = C4::Context->preference('marcflavour') . >+ $xslfile = $marcflavour . > "slim2intranetResults.xsl"; > } elsif ($xslsyspref eq "OPACXSLTDetailsDisplay") { > $htdocs = C4::Context->config('opachtdocs'); > $theme = C4::Context->preference("opacthemes"); >- $xslfile = C4::Context->preference('marcflavour') . >+ $xslfile = $marcflavour . > "slim2OPACDetail.xsl"; > } elsif ($xslsyspref eq "OPACXSLTResultsDisplay") { > $htdocs = C4::Context->config('opachtdocs'); > $theme = C4::Context->preference("opacthemes"); >- $xslfile = C4::Context->preference('marcflavour') . >+ $xslfile = $marcflavour . > "slim2OPACResults.xsl"; > } > $xslfilename = _get_best_default_xslt_filename($htdocs, $theme, $lang, $xslfile); >@@ -193,6 +195,14 @@ sub XSLTParse4Display { > $xslfilename =~ s/\{langcode\}/$lang/; > } > >+ return $xslfilename; >+} >+ >+sub XSLTParse4Display { >+ my ( $biblionumber, $orig_record, $xslsyspref, $fixamps, $hidden_items ) = @_; >+ >+ my $xslfilename = XSLTGetFilename( C4::Context->preference( 'marcflavour' ), $xslsyspref ); >+ > # grab the XML, run it through our stylesheet, push it out to the browser > my $record = transformMARCXML4XSLT($biblionumber, $orig_record); > #return $record->as_formatted(); >diff --git a/Makefile.PL b/Makefile.PL >index 8b89633..8f01e49 100644 >--- a/Makefile.PL >+++ b/Makefile.PL >@@ -531,8 +531,8 @@ push @{ $pl_files->{'rewrite-config.PL'} }, ( > ); > if ($config{'INSTALL_PAZPAR2'} eq 'yes') { > push @{ $pl_files->{'rewrite-config.PL'} }, ( >- 'blib/PAZPAR2_CONF_DIR/koha-biblios.xml', >- 'blib/PAZPAR2_CONF_DIR/pazpar2.xml' >+ 'blib/PAZPAR2_CONF_DIR/generic-settings.xml', >+ 'blib/PAZPAR2_CONF_DIR/pazpar2.xml', > ); > } > $config{'ZEBRA_AUTH_CFG'} = $config{'AUTH_INDEX_MODE'} eq 'dom' >diff --git a/admin/external_targets.pl b/admin/external_targets.pl >new file mode 100755 >index 0000000..2525302 >--- /dev/null >+++ b/admin/external_targets.pl >@@ -0,0 +1,129 @@ >+#!/usr/bin/perl >+# >+# This file is part of Koha. >+# >+# Copyright 2013 Jesse Weaver >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+# >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth; >+use C4::Context; >+use C4::Branch; >+use C4::Output; >+use URI::Escape; >+ >+our $dbh = C4::Context->dbh; >+our $input = new CGI; >+ >+our ( $template, $loggedinuser, $cookie ) = get_template_and_user( { >+ template_name => "admin/external-targets.tt", >+ query => $input, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => {parameters => 'parameters_remaining_permissions'}, >+ debug => 1, >+} ); >+ >+our $op = $input->param( 'op' ) // 'show'; >+$template->{VARS}->{op} = $op; >+ >+if ( $op eq 'show' ) { >+ show_external_targets(); >+} elsif ( $op eq 'add' ) { >+ show_edit_form(); >+} elsif ( $op eq 'edit' ) { >+ show_edit_form(); >+} elsif ( $op eq 'save' ) { >+ save_target(); >+} elsif ( $op eq 'delete' ) { >+ delete_target(); >+} >+ >+output_html_with_http_headers $input, $cookie, $template->output; >+ >+sub show_external_targets { >+ $template->{VARS}->{saved_id} = $input->param( 'saved_id' ); >+ $template->{VARS}->{deleted_name} = $input->param( 'deleted_name' ); >+ $template->{VARS}->{targets} = $dbh->selectall_arrayref( q{ >+ SELECT * >+ FROM external_targets >+ }, { Slice => {} } ); >+} >+ >+sub show_edit_form { >+ $template->{VARS}->{branches} = GetBranchesLoop( undef, 0 ); >+ $template->{VARS}->{syntaxes} = [ 'MARC21', 'UNIMARC', 'NORMARC' ]; >+ $template->{VARS}->{encodings} = { 'utf8' => 'UTF-8', 'marc8' => 'MARC-8' }; >+ >+ my $target_id; >+ if ( $target_id = $input->param( 'target_id' ) ) { >+ $template->{VARS}->{target} = $dbh->selectrow_hashref( q{ SELECT * FROM external_targets WHERE target_id = ? }, {}, $target_id ); >+ >+ my $available_branches = $dbh->selectall_hashref( q{ SELECT * FROM external_target_restrictions WHERE target_id = ? }, 'branchcode', {}, $target_id ); >+ >+ foreach my $branch ( @{ $template->{VARS}->{branches} } ) { >+ $branch->{selected} = 1 if ( $available_branches->{$branch->{branchcode}} ); >+ } >+ } >+} >+ >+sub save_target { >+ my $target_id; >+ if ( $target_id = $input->param( 'target_id' ) ) { >+ $dbh->do( q{ >+ UPDATE external_targets >+ SET name = ?, host = ?, port = ?, db = ?, userid = ?, password = ?, syntax = ?, encoding = ? >+ WHERE target_id = ? >+ }, {}, map { $input->param( $_ ) // '' } qw( name host port db userid password syntax encoding target_id ) ); >+ } else { >+ $dbh->do( q{ >+ INSERT >+ INTO external_targets(name, host, port, db, userid, password, syntax, encoding) >+ VALUES(?, ?, ?, ?, ?, ?, ?, ?) >+ }, {}, map { $input->param( $_ ) // '' } qw( name host port db userid password syntax encoding ) ); >+ $target_id = $dbh->last_insert_id( undef, undef, undef, undef ); >+ } >+ >+ $dbh->do( q{ >+ DELETE >+ FROM external_target_restrictions >+ WHERE target_id = ? >+ }, {}, $target_id ); >+ >+ foreach my $branchcode ( $input->param( 'branch' ) ) { >+ $dbh->do( q{ >+ INSERT >+ INTO external_target_restrictions(branchcode, target_id) >+ VALUES(?, ?) >+ }, {}, $branchcode, $target_id ); >+ } >+ >+ print $input->redirect( '/cgi-bin/koha/admin/external_targets.pl?saved_id=' . $target_id ); >+ exit; >+} >+ >+sub delete_target { >+ my ($target_id, $target); >+ >+ return unless ( $target_id = $input->param( 'target_id' ) and $target = $dbh->selectrow_hashref( q{ SELECT * FROM external_targets WHERE target_id = ? }, {}, $target_id ) ); >+ >+ $dbh->do( q{ DELETE FROM external_targets WHERE target_id = ? }, {}, $target_id ); >+ >+ print $input->redirect( '/cgi-bin/koha/admin/external_targets.pl?deleted_name=' . uri_escape( $target->{'name'} ) ); >+} >diff --git a/etc/koha-conf.xml b/etc/koha-conf.xml >index 72da2de..78b55ac 100644 >--- a/etc/koha-conf.xml >+++ b/etc/koha-conf.xml >@@ -19,19 +19,6 @@ > <listen id="publicserver" >tcp:@:__ZEBRA_SRU_BIBLIOS_PORT__</listen> > --> > >-<!-- Settings for special biblio server instance for PazPar2. >- Because PazPar2 only connects to a Z39.50 server using TCP/IP, >- it cannot use the Unix-domain socket that biblioserver uses. >- Therefore, a custom server is defined. --> >-__PAZPAR2_TOGGLE_XML_PRE__ >-<listen id="mergeserver">tcp:@:__MERGE_SERVER_PORT__</listen> >-<server id="mergeserver" listenref="mergeserver"> >- <directory>__ZEBRA_DATA_DIR__/biblios</directory> >- <config>__ZEBRA_CONF_DIR__/__ZEBRA_BIB_CFG__</config> >- <cql2rpn>__ZEBRA_CONF_DIR__/pqf.properties</cql2rpn> >-</server> >-__PAZPAR2_TOGGLE_XML_POST__ >- > <!-- BIBLIOGRAPHIC RECORDS --> > <server id="biblioserver" listenref="biblioserver"> > <directory>__ZEBRA_DATA_DIR__/biblios</directory> >diff --git a/etc/koha-httpd.conf b/etc/koha-httpd.conf >index f9a1970..df3dae1 100644 >--- a/etc/koha-httpd.conf >+++ b/etc/koha-httpd.conf >@@ -32,7 +32,7 @@ > </Directory> > > # Secure internal stuff >- <DirectoryMatch "__OPAC_WWW_DIR__/.*/(modules|xslt|includes)"> >+ <DirectoryMatch "__OPAC_WWW_DIR__/.*/(modules|includes)"> > Order deny,allow > Deny from all > </DirectoryMatch> >@@ -113,6 +113,17 @@ > RewriteRule ^/isbn/([^\/]*)/?$ /search?q=isbn:$1 [PT] > RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT] > </IfModule> >+ >+ __PAZPAR2_TOGGLE_HTTPD_PRE__ >+ <Proxy *> >+ AddDefaultCharset off >+ Order deny,allow >+ Allow from all >+ </Proxy> >+ >+ ProxyRequests off >+ ProxyPass /pazpar2/search.pz2 http://__PAZPAR2_HOST__:__PAZPAR2_PORT__/search.pz2 >+ __PAZPAR2_TOGGLE_HTTPD_POST__ > </VirtualHost> > > ## Intranet >@@ -149,7 +160,7 @@ > </Directory> > > # Secure internal stuff >- <DirectoryMatch "__INTRANET_WWW_DIR__/.*/(modules|xslt|includes)"> >+ <DirectoryMatch "__INTRANET_WWW_DIR__/.*/(modules|includes)"> > Order deny,allow > Deny from all > </DirectoryMatch> >diff --git a/etc/pazpar2/generic-settings.xml b/etc/pazpar2/generic-settings.xml >new file mode 100644 >index 0000000..5d56b99 >--- /dev/null >+++ b/etc/pazpar2/generic-settings.xml >@@ -0,0 +1,21 @@ >+<settings target="*"> >+ <!-- This file introduces default settings for pazpar2 --> >+ <!-- $Id: loc.xml,v 1.2 2007-07-10 13:43:07 adam Exp $ --> >+ >+ <!-- mapping for unqualified search --> >+ <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/> >+ >+ <!-- field-specific mappings --> >+ >+ <set name="pz:cclmap:au" value="u=1004 s=al"/> >+ <set name="pz:cclmap:ti" value="u=4 s=al"/> >+ <set name="pz:cclmap:su" value="u=21 s=al"/> >+ <set name="pz:cclmap:isbn" value="u=7"/> >+ <set name="pz:cclmap:issn" value="u=8"/> >+ <set name="pz:cclmap:date" value="u=30 r=r"/> >+ >+ <!-- Retrieval settings --> >+ >+ <set name="pz:elements" value="F"/> >+ >+</settings> >diff --git a/etc/pazpar2/pazpar2.xml b/etc/pazpar2/pazpar2.xml >index 2269647..9969581 100644 >--- a/etc/pazpar2/pazpar2.xml >+++ b/etc/pazpar2/pazpar2.xml >@@ -4,32 +4,29 @@ > > <server> > <listen port="__PAZPAR2_PORT__"/> >- <settings src="__PAZPAR2_CONF_DIR__/koha-biblios.xml"/> >+ <settings src="__PAZPAR2_CONF_DIR__/generic-settings.xml"/> > > <relevance> >- <icu_chain id="relevance" locale="el"> >- <normalize rule="[:Control:] Any-Remove"/> >+ <icu_chain id="relevance" locale="en"> >+ <transform rule="[:Control:] Any-Remove"/> > <tokenize rule="l"/> >- <normalize rule="[[:WhiteSpace:][:Punctuation:]] Remove"/> >+ <transform rule="[[:WhiteSpace:][:Punctuation:]] Remove"/> > <casemap rule="l"/> >- <index/> > </icu_chain> > </relevance> > > <sort> >- <icu_chain id="sort" locale="el"> >- <normalize rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/> >+ <icu_chain id="sort" locale="en"> >+ <transform rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/> > <casemap rule="l"/> >- <sortkey/> > </icu_chain> > </sort> > > <mergekey> >- <icu_chain id="mergekey" locale="el"> >+ <icu_chain id="mergekey" locale="en"> > <tokenize rule="l"/> >- <normalize rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/> >+ <transform rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/> > <casemap rule="l"/> >- <index/> > </icu_chain> > </mergekey> > >diff --git a/etc/pazpar2/unimarc-work-groups.xsl b/etc/pazpar2/unimarc-work-groups.xsl >new file mode 100644 >index 0000000..50cbe3c >--- /dev/null >+++ b/etc/pazpar2/unimarc-work-groups.xsl >@@ -0,0 +1,98 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<xsl:stylesheet >+ version="1.0" >+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns:pz="http://www.indexdata.com/pazpar2/1.0" >+ xmlns:marc="http://www.loc.gov/MARC21/slim"> >+ >+ <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/> >+ >+ >+ <xsl:template match="/marc:record"> >+ <pz:record> >+ >+ <xsl:for-each select="marc:controlfield[@tag='001']"> >+ <pz:metadata type="id"> >+ <xsl:value-of select="."/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ <!-- --> >+ <xsl:for-each select="marc:datafield[@tag='020']"> >+ <xsl:if test="marc:subfield[@code='a'] = 'US'"> >+ <pz:metadata type="lccn"> >+ <xsl:value-of select="marc:subfield[@code='b']"/> >+ </pz:metadata> >+ </xsl:if> >+ </xsl:for-each> >+ >+ <xsl:for-each select="marc:datafield[@tag='010']"> >+ <pz:metadata type="isbn"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ <xsl:for-each select="marc:datafield[@tag='011']"> >+ <pz:metadata type="issn"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ >+ <xsl:for-each select="marc:datafield[@tag='200']"> >+ <pz:metadata type="work-title"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ >+ <!-- Date of Pulbication --> >+ <xsl:for-each select="marc:datafield[@tag='210']"> >+ <pz:metadata type="date"> >+ <xsl:value-of select="marc:subfield[@code='d']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ <!-- Usmarc 650 maps to unimarc 606 and marc21 653 maps to unimarc 610 --> >+ <xsl:for-each select="marc:datafield[@tag='606' or @tag='610']"> >+ <pz:metadata type="subject"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ <xsl:for-each select="marc:datafield[@tag >= 300 and @tag <= 345] >+ [@tag != '325']"> >+ <pz:metadata type="description"> >+ <xsl:value-of select="*/text()"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ >+ <!-- Author : primary, alternative and secondary responsibility (equivalent marc21 tags : 100, 700 --> >+ <xsl:for-each select="marc:datafield[@tag='700' or @tag='701' or @tag='702']"> >+ <pz:metadata type="work-author"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ <xsl:text>, </xsl:text> >+ <xsl:value-of select="marc:subfield[@code='b']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ <!-- Author : marc21 tag 720 maps to unimarc 730 >+ <xsl:for-each select="marc:datafield[@tag='730']"> >+ <pz:metadata type="author"> >+ <xsl:value-of select="marc:subfield[@code='a']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ --> >+ >+ <!-- --> >+ <xsl:for-each select="marc:datafield[@tag='856']"> >+ <pz:metadata type="url"> >+ <xsl:value-of select="marc:subfield[@code='u']"/> >+ </pz:metadata> >+ </xsl:for-each> >+ >+ </pz:record> >+ </xsl:template> >+ >+</xsl:stylesheet> >diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql >index 8dbf496..2db3d52 100644 >--- a/installer/data/mysql/sysprefs.sql >+++ b/installer/data/mysql/sysprefs.sql >@@ -263,6 +263,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'), > ('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'), > ('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'), >+('OPACSearchExternalTargets','0',NULL,'Whether to search external targets in the OPAC','YesNo'), > ('OPACSearchForTitleIn','<li><a href=\"http://worldcat.org/search?q={TITLE}\" target=\"_blank\">Other Libraries (WorldCat)</a></li>\n<li><a href=\"http://www.scholar.google.com/scholar?q={TITLE}\" target=\"_blank\">Other Databases (Google Scholar)</a></li>\n<li><a href=\"http://www.bookfinder.com/search/?author={AUTHOR}&title={TITLE}&st=xl&ac=qr\" target=\"_blank\">Online Stores (Bookfinder.com)</a></li>\n<li><a href=\"http://openlibrary.org/search/?author=({AUTHOR})&title=({TITLE})\" target=\"_blank\">Open Library (openlibrary.org)</a></li>','70|10','Enter the HTML that will appear in the \'Search for this title in\' box on the detail page in the OPAC. Enter {TITLE}, {AUTHOR}, or {ISBN} in place of their respective variables in the URL. Leave blank to disable \'More Searches\' menu.','Textarea'), > ('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'), > ('OpacSeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings (OPAC)','Choice'), >diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl >index 8aed2d6..7e3366d 100755 >--- a/installer/data/mysql/updatedatabase.pl >+++ b/installer/data/mysql/updatedatabase.pl >@@ -7957,7 +7957,6 @@ if (CheckVersion($DBversion)) { > SetVersion($DBversion); > } > >-$DBversion = "3.15.00.017"; > if(CheckVersion($DBversion)) { > $dbh->do(q{ > UPDATE systempreferences >@@ -8243,6 +8242,41 @@ if ( CheckVersion($DBversion) ) { > SetVersion ($DBversion); > } > >+ >+$DBversion = "3.15.00.XXX"; >+if(CheckVersion($DBversion)) { >+ $dbh->do( >+"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OPACSearchExternalTargets','0','Whether to search external targets in the OPAC','','YesNo')" >+ ); >+ $dbh->do( q{ >+CREATE TABLE `external_targets` ( >+ `target_id` int(11) NOT NULL AUTO_INCREMENT, >+ `host` varchar(128) NOT NULL, >+ `port` int(11) NOT NULL, >+ `db` varchar(64) NOT NULL, >+ `userid` varchar(64) DEFAULT '', >+ `password` varchar(64) DEFAULT '', >+ `name` varchar(64) NOT NULL, >+ `syntax` varchar(64) NOT NULL, >+ `encoding` varchar(16) DEFAULT 'MARC-8', >+ PRIMARY KEY (`target_id`) >+) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 >+ } ); >+ $dbh->do( q{ >+CREATE TABLE `external_target_restrictions` ( >+ `branchcode` varchar(10) NOT NULL, >+ `target_id` int(11) NOT NULL, >+ KEY `branchcode` (`branchcode`), >+ KEY `target_id` (`target_id`), >+ CONSTRAINT `external_target_restrictions_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE, >+ CONSTRAINT `external_target_restrictions_ibfk_2` FOREIGN KEY (`target_id`) REFERENCES `external_targets` (`target_id`) ON DELETE CASCADE >+) ENGINE=InnoDB DEFAULT CHARSET=utf8 >+ } ); >+ print "Upgrade to $DBversion done (Bug 10486 - Allow external Z39.50 targets to be searched from the OPAC)\n"; >+ SetVersion($DBversion); >+} >+ >+ > =head1 FUNCTIONS > > =head2 TableExists($table) >diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >index 1db0427..c5f9ac9 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >+++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css >@@ -274,6 +274,16 @@ tr.even td, tr.even.highlight td { > border-right : 1px solid #BCBCBC; > } > >+tr.highlight td { >+ background-color : #F6F6F6; >+ border-color : #BCBCBC; >+} >+ >+tr.highlight th[scope=row] { >+ background-color : #DDDDDD; >+ border-color : #BCBCBC; >+} >+ > td.od { > color : #cc0000; > font-weight : bold; >@@ -291,6 +301,10 @@ tr.odd.onissue td { > background-color: #FFFFE1; > } > >+tr.updated td { >+ background-color: #FFFFBB; >+} >+ > tfoot td { > background-color : #f3f3f3; > font-weight : bold; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc >index ebd345c..1731e39 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc >@@ -45,6 +45,7 @@ > <li><a href="/cgi-bin/koha/admin/classsources.pl">Classification sources</a></li> > <li><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></li> > <li><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI sets configuration</a></li> >+ <li><a href="/cgi-bin/koha/admin/external_targets.pl">External search targets</a></li> > </ul> > > <h5>Acquisition parameters</h5> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >index 217b069..435ac5a 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt >@@ -81,6 +81,8 @@ > <dt><a href="/cgi-bin/koha/admin/searchengine/solr/indexes.pl">Search engine configuration</a></dt> > <dd>Manage indexes, facets, and their mappings to MARC fields and subfields.</dd> > [% END %] >+ <dt><a href="/cgi-bin/koha/admin/external_targets.pl">External search targets</a></dt> >+ <dd>Define external search targets that can be searched from the OPAC.</dd> > </dl> > > <h3>Acquisition parameters</h3> >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/external-targets.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/external-targets.tt >new file mode 100644 >index 0000000..e6b8483 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/external-targets.tt >@@ -0,0 +1,178 @@ >+[% INCLUDE 'doc-head-open.inc' %] >+[% IF op == 'show' %] >+<title>Koha › Administration › External targets</title> >+[% ELSIF op == 'add' %] >+<title>Koha › Administration › External targets › Create an external target</title> >+[% ELSIF op == 'edit' %] >+<title>Koha › Administration › External targets › Editing '[% target.name %]'</title> >+[% END %] >+[% INCLUDE 'doc-head-close.inc' %] >+<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" /> >+[% INCLUDE 'datatables.inc' %] >+<script type="text/javascript"> >+//<![CDATA[ >+ $(document).ready(function() { >+ [% IF ( targets.size ) %] >+ var dTable = $("#targets").dataTable( $.extend( true, {}, dataTablesDefaults, { >+ aoColumnDefs: [ >+ { aTargets: [ 1,2,3,4,5 ], bSortable: false, bSearchable: false }, >+ ], >+ asStripeClasses: [ '', 'highlight' ], >+ bPaginate: false, >+ } ) ); >+ >+ [% IF saved_id %] >+ $( '#targets tr[data-targetid=[% saved_id %]]' ).addClass( 'updated' ); >+ [% END %] >+ >+ $( '#targets .delete' ).click( function() { >+ return confirm( _("Are you sure you wish to delete this target?") ); >+ } ); >+ [% END %] >+ }); >+//]]> >+</script> >+ >+</head> >+<body id="admin_z3950servers" class="admin"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+[% IF op == 'show' %] >+ >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> › External targets</div> >+ >+[% ELSIF op == 'add' %] >+ >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> › <a href="/cgi-bin/koha/admin/external_targets.pl">External targets</a> › Create an external target</div> >+ >+[% ELSIF op == 'edit' %] >+ >+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> › <a href="/cgi-bin/koha/admin/external_targets.pl">External targets</a> › Editing '[% target.name %]'</div> >+ >+[% END %] >+ >+<div id="doc3" class="yui-t2"> >+<div id="bd"> >+ >+<div id="yui-main"><div class="yui-b"> >+ >+[% IF op == 'show' %] >+ >+[% IF deleted_name %] >+<div class="alert"> >+ <p>Deleted target '[% deleted_name %]'</p> >+</div> >+[% END %] >+ >+<div id="toolbar" class="btn-toolbar"> >+ <a id="newtarget" class="btn btn-small" href="/cgi-bin/koha/admin/external_targets.pl?op=add"><i class="icon-plus"></i> New external target</a> >+</div> >+ >+<p>These Z39.50 targets are searched in the OPAC using the "external targets" feature. Note that Pazpar2 must be installed and configured for this to work.</p> >+ >+[% IF targets.size %] >+<table id="targets"> >+ <thead><tr><th>Name</th><th>Connection</th><th>Login</th><th>Syntax</th><th>Encoding</th><th> </th><th> </th></tr></thead> >+ <tbody> >+ [% FOREACH target = targets %] >+ <tr data-targetid="[% target.target_id %]"> >+ <td>[% target.name %]</td> >+ <td>[% target.host %]:[% target.port %]/[% target.db %]</td> >+ <td>[% IF target.userid %][% target.userid %] / [% IF target.password %]********[% ELSE %]<span class="hint">none</span>[% END %][% ELSE %]<span class="hint">none</span>[% END %]</td> >+ <td>[% target.syntax %]</td> >+ <td> >+ [% IF target.encoding == 'marc8' %] >+ MARC-8 >+ [% ELSIF target.encoding == 'utf8' %] >+ UTF-8 >+ [% END %] >+ </td> >+ <td><a href="/cgi-bin/koha/admin/external_targets.pl?op=edit&target_id=[% target.target_id %]">Edit</a></td> >+ <td><a class="delete" href="/cgi-bin/koha/admin/external_targets.pl?op=delete&target_id=[% target.target_id %]">Delete</a></td> >+ </tr> >+ [% END %] >+ </tbody> >+</table> >+[% ELSE %] >+<p>No external targets have been defined yet.</p> >+[% END %] >+ >+[% ELSIF op == 'add' || op == 'edit' %] >+ >+<form action="/cgi-bin/koha/admin/external_targets.pl" method="POST"> >+ [% IF op == 'add' %] >+ <h1>Create an external target</h1> >+ [% ELSIF op == 'edit' %] >+ <h1>Editing '[% target.name %]'</h1> >+ [% END %] >+ >+ <input type="hidden" name="op" value="save"> >+ <input type="hidden" name="target_id" value="[% target.target_id %]"> >+ >+ <fieldset class="rows"> >+ <ol> >+ <li><label for="name">Name:</label> <input type="text" id="name" name="name" value="[% target.name %]" required></li> >+ <li><label for="host">Host:</label> <input type="text" id="host" name="host" value="[% target.host %]" required></li> >+ <li><label for="port">Port:</label> <input type="num" id="port" name="port" value="[% target.port %]" required></li> >+ <li><label for="db">Database:</label> <input type="text" id="db" name="db" value="[% target.db %]" required></li> >+ <li><label for="userid">User:</label> <input type="text" id="userid" name="userid" value="[% target.userid %]"></li> >+ <li><label for="password">Password:</label> <input type="password" id="password" name="password" value="[% target.password %]" autocomplete="off"></li> >+ <li> >+ <label for="syntax">Syntax:</label> >+ <select id="syntax" name="syntax"> >+ [% FOREACH syntax = syntaxes %] >+ [% IF syntax == target.syntax %] >+ <option selected>[% syntax %] >+ [% ELSE %] >+ <option>[% syntax %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label for="encoding">Encoding:</label> >+ <select id="encoding" name="encoding"> >+ [% FOREACH encoding = encodings %] >+ [% IF encoding.key == target.encoding %] >+ <option value="[% encoding.key %]" selected>[% encoding.value %] >+ [% ELSE %] >+ <option value="[% encoding.key %]">[% encoding.value %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ <li> >+ <label>Restricted libraries:</label> >+ <fieldset> >+ <legend>Not available to patrons from:</legend> >+ <p>Only targets with no restrictions will be shown to anonymous (not logged in) users.</p> >+ <ol> >+ [% FOREACH branch = branches %] >+ <li> >+ <label for="branch-[% branch.branchcode %]">[% branch.branchname %]</label> >+ [% IF branch.selected %] >+ <input type="checkbox" id="branch-[% branch.branchcode %]" name="branch" value="[% branch.branchcode %]" checked /> >+ [% ELSE %] >+ <input type="checkbox" id="branch-[% branch.branchcode %]" name="branch" value="[% branch.branchcode %]" /> >+ [% END %] >+ </li> >+ [% END %] >+ </ol> >+ </fieldset> >+ </li> >+ </ol> >+ </fieldset> >+ >+ <fieldset class="action"><input type="submit" value="Save"></fieldset> >+</form> >+ >+[% END %] >+ >+</div></div> >+<div class="yui-b"> >+[% INCLUDE 'admin-menu.inc' %] >+</div> >+ >+</div> >+[% INCLUDE 'intranet-bottom.inc' %] >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 5483e0a..4e7b53c 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 >@@ -444,6 +444,13 @@ OPAC: > yes: Allow > no: Do not allow > - users to add a note when placing a hold. >+ - >+ - pref: OPACSearchExternalTargets >+ default: 0 >+ choices: >+ yes: Search >+ no: "Don't search" >+ - external targets from the OPAC. (Check with your system administrator first to ensure that Pazpar2 is enabled and running.) > > Policy: > - >diff --git a/koha-tmpl/opac-tmpl/bootstrap/css/opac.css b/koha-tmpl/opac-tmpl/bootstrap/css/opac.css >index 3231fd4..5a4a4be 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/css/opac.css >+++ b/koha-tmpl/opac-tmpl/bootstrap/css/opac.css >@@ -1 +1,2691 @@ >-.shadowed{-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2)}body{background-color:#eaeae6}html,body{height:100%}.no-js .dateformat{display:inline;white-space:nowrap}.no-js .modal-body{padding:0}.js .dateformat{display:none}#wrap{min-height:100%;height:auto!important;height:100%}.popup{padding-left:0;padding-right:0}a{color:#0076b2}a.cancel{padding-left:1em}a:visited{color:#0076b2}a.title{font-weight:bold;font-size:108%}a.btn-primary:visited{color:#FFF}.ui-widget-content a,.ui-widget-content a:visited{color:#0076b2}h1{font-size:140%;line-height:150%}h1#libraryname{background:transparent url(../images/logo-koha.png) no-repeat scroll 0;border:0;float:left!important;margin:0;padding:0;width:120px}h1#libraryname a{border:0;cursor:pointer;display:block;height:0!important;margin:0;overflow:hidden;padding:40px 0 0;text-decoration:none;width:120px}h2{font-size:130%;line-height:150%}h3{font-size:120%;line-height:150%}h4{font-size:110%}h5{font-size:100%}caption{font-size:120%;font-weight:bold;margin:0;text-align:left}input,textarea{width:auto}.input-fluid{width:50%}legend{font-size:110%;font-weight:bold}table,td{background-color:#FFF}td .btn{white-space:nowrap}td .btn-link{padding:0}#advsearches label,#booleansearch label{display:inline}#basketcount{display:inline;margin:0;padding:0}#basketcount span{background-color:#FFC;color:#000;display:inline;font-size:80%;font-weight:normal;margin:0 0 0 .9em;padding:0 .3em 0 .3em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}#members{display:block}#members p{color:#EEE}#members a{color:#a6d8ed;font-weight:bold}#members a.logout{color:#e8583c;padding:0 .3em 0 .3em}#koha_url p{color:#666;float:right;margin:0}#moresearches{margin:.5em 0;padding:0 .8em}#moresearches li{display:inline;white-space:nowrap}#moresearches li:after{content:" | "}#moresearches ul{margin:0}#moresearches li:last-child:after{content:""}#news{margin:.5em 0}#opacheader{background-color:#DDD}#selections{font-weight:bold}.actions a{white-space:nowrap}.actions a.hold{background-image:url("../images/sprite.png");background-position:-5px -542px;background-repeat:no-repeat;margin-right:1em;padding-left:21px;text-decoration:none}.actions a.addtocart{background-image:url("../images/sprite.png");background-position:-5px -572px;background-repeat:no-repeat;margin-right:1em;padding-left:20px;text-decoration:none}.actions a.addtoshelf{background-image:url("../images/sprite.png");background-position:-5px -27px;background-repeat:no-repeat;margin-right:1em;padding-left:20px;text-decoration:none}.actions a.addtolist{background-position:-5px -27px;margin-right:1em;padding-left:20px;text-decoration:none}.actions a.tag_add{background-position:-5px -1110px;margin-right:1em;padding-left:20px;text-decoration:none}.actions a.removefromlist{background-position:-8px -690px;margin-right:1em;text-decoration:none;padding-left:15px}.alert{background:#fffbe5;background:-moz-linear-gradient(top,#fffbe5 0,#fff0b2 9%,#fff1a8 89%,#f7e665 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fffbe5),color-stop(9%,#fff0b2),color-stop(89%,#fff1a8),color-stop(100%,#f7e665));background:-webkit-linear-gradient(top,#fffbe5 0,#fff0b2 9%,#fff1a8 89%,#f7e665 100%);background:-o-linear-gradient(top,#fffbe5 0,#fff0b2 9%,#fff1a8 89%,#f7e665 100%);background:-ms-linear-gradient(top,#fffbe5 0,#fff0b2 9%,#fff1a8 89%,#f7e665 100%);background:linear-gradient(to bottom,#fffbe5 0,#fff0b2 9%,#fff1a8 89%,#f7e665 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbe5',endColorstr='#f7e665',GradientType=0);border-color:#d6c43b;color:#333}.alert-info{background:#f4f6fa;background:-moz-linear-gradient(top,#f4f6fa 0,#eaeef5 4%,#e8edf6 96%,#cddbf2 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f4f6fa),color-stop(4%,#eaeef5),color-stop(96%,#e8edf6),color-stop(100%,#cddbf2));background:-webkit-linear-gradient(top,#f4f6fa 0,#eaeef5 4%,#e8edf6 96%,#cddbf2 100%);background:-o-linear-gradient(top,#f4f6fa 0,#eaeef5 4%,#e8edf6 96%,#cddbf2 100%);background:-ms-linear-gradient(top,#f4f6fa 0,#eaeef5 4%,#e8edf6 96%,#cddbf2 100%);background:linear-gradient(to bottom,#f4f6fa 0,#eaeef5 4%,#e8edf6 96%,#cddbf2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f6fa',endColorstr='#cddbf2',GradientType=0);border-color:#c5d1e5;color:#333}.alert-success{background:#f8ffe8;background:-moz-linear-gradient(top,#f8ffe8 0,#e3f5ab 4%,#dcf48d 98%,#9ebf28 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#f8ffe8),color-stop(4%,#e3f5ab),color-stop(98%,#dcf48d),color-stop(100%,#9ebf28));background:-webkit-linear-gradient(top,#f8ffe8 0,#e3f5ab 4%,#dcf48d 98%,#9ebf28 100%);background:-o-linear-gradient(top,#f8ffe8 0,#e3f5ab 4%,#dcf48d 98%,#9ebf28 100%);background:-ms-linear-gradient(top,#f8ffe8 0,#e3f5ab 4%,#dcf48d 98%,#9ebf28 100%);background:linear-gradient(to bottom,#f8ffe8 0,#e3f5ab 4%,#dcf48d 98%,#9ebf28 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8ffe8',endColorstr='#9ebf28',GradientType=0);border-color:#9fba35;color:#333}.breadcrumb{background-color:#f2f2ef;font-size:85%;list-style:none outside none;margin:10px 20px;padding:5px 10px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.form-inline{display:inline;padding:0;margin:0}.form-inline fieldset{margin:.3em 0;padding:.3em}.main{background-color:#FFF;border:1px solid #d2d2cf;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);margin-top:.5em;margin-bottom:.5em}.mastheadsearch{-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;padding:.8em;margin:.5em 0;background:#c7c7c1;background:-moz-linear-gradient(top,#c7c7c1 38%,#a7a7a2 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(38%,#c7c7c1),color-stop(100%,#a7a7a2));background:-webkit-linear-gradient(top,#c7c7c1 38%,#a7a7a2 100%);background:-o-linear-gradient(top,#c7c7c1 38%,#a7a7a2 100%);background:-ms-linear-gradient(top,#c7c7c1 38%,#a7a7a2 100%);background:linear-gradient(to bottom,#c7c7c1 38%,#a7a7a2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#c7c7c1',endColorstr='#a7a7a2',GradientType=0)}.mastheadsearch label{font-size:115%;font-weight:bold}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#9fe1ff;font-weight:bold}.navbar-fixed-bottom.navbar-static-bottom{margin-top:.5em;position:static}#changelanguage .nav>.active>p{padding:0 15px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f4f4f4}.ui-tabs-nav .ui-tabs-active a,.ui-tabs-nav a:hover,.ui-tabs-nav a:focus,.ui-tabs-nav a:active,.ui-tabs-nav span.a{background:none repeat scroll 0 0 transparent;outline:0 none}.ui-widget,.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:inherit;font-size:inherit}ul.ui-tabs-nav li{list-style:none}.ui-tabs.ui-widget-content{background:transparent none;border:0}.ui-tabs .ui-tabs-panel{border:1px solid #d8d8d8;margin-bottom:1em}.ui-tabs-nav.ui-widget-header{border:0;background:0}.ui-tabs .ui-tabs-nav li{background:#f3f3f3 none;border-color:#d8d8d8;margin-right:.4em}.ui-tabs .ui-tabs-nav li.ui-tabs-active{background-color:#FFF;border:1px solid #d8d8d8;border-bottom:0}.ui-tabs .ui-tabs-nav li.ui-tabs-active a{color:#000;font-weight:bold}.ui-tabs .ui-tabs-nav li.ui-state-default.ui-state-hover{background:#f3f3f3 none}.ui-tabs .ui-tabs-nav li.ui-tabs-active.ui-state-hover{background:#FFF none}.ui-tabs .ui-state-default a,.ui-tabs .ui-state-default a:link,.ui-tabs .ui-state-default a:visited{color:#069}.ui-tabs .ui-state-hover a,.ui-tabs .ui-state-hover a:link,.ui-tabs .ui-state-hover a:visited{color:#903}.statictabs ul{background:none repeat scroll 0 0 transparent;border:0 none;margin:0;padding:.2em .2em 0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-right-radius:4px;border-top-left-radius:4px;color:#222;font-weight:bold;font-size:100%;line-height:1.3;list-style:none outside none;outline:0 none;text-decoration:none}.statictabs ul:before{content:"";display:table}.statictabs ul:after{clear:both;content:"";display:table}.statictabs li{background:none repeat scroll 0 0 #e6f0f2;border:1px solid #b9d8d9;border-bottom:0 none!important;border-top-right-radius:4px;border-top-left-radius:4px;float:left;list-style:none outside none;margin-bottom:0;margin-right:.4em;padding:0;position:relative;white-space:nowrap;top:1px;color:#555;font-weight:normal}.statictabs li.active{background-color:#fff;color:#212121;font-weight:normal;padding-bottom:1px}.statictabs li a{color:#004d99;cursor:pointer;float:left;padding:.5em 1em;text-decoration:none}.statictabs li a:hover{background-color:#edf4f5;border-top-right-radius:4px;border-top-left-radius:4px;color:#538200}.statictabs li.active a{color:#000;font-weight:bold;cursor:text;background:none repeat scroll 0 0 transparent;outline:0 none}.statictabs .tabs-container{border:1px solid #b9d8d9;background:none repeat scroll 0 0 transparent;display:block;padding:1em 1.4em;border-bottom-right-radius:4px;border-bottom-left-radius:4px;color:#222}.ui-datepicker table{width:100%;font-size:.9em;border:0;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{background:transparent none;padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker-trigger{vertical-align:middle;margin:0 3px}.ui-datepicker{-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2)}.ui-widget-content{border:1px solid #AAA;background:#fff none;color:#222}.ui-widget-header{border:1px solid #AAA;background:#e6f0f2 none;color:#222;font-weight:bold}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #AAA;background:#f4f8f9 none;font-weight:normal;color:#555}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #AAA;background:#e6f0f2 none;font-weight:normal;color:#212121}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff none;font-weight:normal;color:#212121}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee;color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec;color:#cd0a0a}.ui-autocomplete{position:absolute;cursor:default;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2)}.ui-autocomplete.ui-widget-content .ui-state-hover{border:1px solid #AAA;background:#e6f0f2 none;font-weight:normal;color:#212121}.ui-autocomplete-loading{background:#fff url("../../img/loading-small.gif") right center no-repeat}.ui-menu li{list-style:none}th{background-color:#ecede6}.item-thumbnail{max-width:none}.no-image{background-color:#FFF;border:1px solid #AAA;color:#979797;display:block;font-size:86%;font-weight:bold;text-align:center;width:75px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}#bookcover .no-image{margin-right:10px;margin-bottom:10px}td.overdue{color:#c33}table{font-size:90%}th.sum{text-align:right}td.sum{background-color:#FFC;font-weight:bold}th[scope=row]{background-color:transparent;text-align:right}.required{color:#C00}.label{background-color:transparent;color:inherit;display:inline;font-weight:normal;padding:0;text-shadow:none}fieldset.rows{float:left;font-size:90%;clear:left;margin:.9em 0 0 0;padding:0;width:100%}fieldset.rows legend{font-weight:bold;font-size:130%}fieldset.rows label,fieldset.rows .label{float:left;font-weight:bold;width:9em;margin-right:1em;text-align:right}fieldset.rows label.lradio{float:none;margin:inherit;width:auto}fieldset.rows fieldset{margin:0;padding:.3em}fieldset.rows ol{padding:1em 1em 0 1em;list-style-type:none}fieldset.rows ol.lradio label{width:auto;float:none;margin-right:0}fieldset.rows ol.lradio label.lradio{float:left;width:12em;margin-right:1em}fieldset.rows li{float:left;clear:left;padding-bottom:1em;list-style-type:none;width:100%}fieldset.rows li.lradio{padding-left:8.5em;width:auto}fieldset.rows li.lradio label{float:none;width:auto;margin:0 0 0 1em}fieldset.rows .hint{display:block;margin-left:11em}fieldset.action{clear:both;float:none;border:0;margin:0;padding:1em 0 .3em 0;width:auto}fieldset.action p{margin-bottom:1em}fieldset table{font-size:100%}div.rows+div.rows{margin-top:.6em}div.rows{float:left;clear:left;margin:0;padding:0;width:100%}div.rows span.label{float:left;font-weight:bold;width:9em;margin-right:1em;text-align:left}div.rows ol{list-style-type:none;margin-left:0;padding:.5em 1em 0 0}div.rows li{border-bottom:1px solid #EEE;float:left;clear:left;padding-bottom:.2em;padding-top:.1em;list-style-type:none;width:100%}div.rows ul li{margin-left:7.3em}div.rows ul li:first-child{float:none;clear:none;margin-left:0}div.rows ol li li{border-bottom:0}.tagweight0{font-size:12px}.tagweight1{font-size:14px}.tagweight2{font-size:16px}.tagweight3{font-size:18px}.tagweight4{font-size:20px}.tagweight5{font-size:22px}.tagweight6{font-size:24px}.tagweight7{font-size:26px}.tagweight8{font-size:28px}.tagweight9{font-size:30px}.toolbar{background-color:#eee;border:1px solid #e8e8e8;font-size:85%;padding:3px 3px 5px 5px;vertical-align:middle}.toolbar a{white-space:nowrap}.toolbar label{display:inline;font-size:100%;font-weight:bold;margin-left:.5em}.toolbar select{font-size:97%;height:auto;line-height:inherit;padding:0;margin:0;width:auto;white-space:nowrap}.toolbar .hold,.toolbar #tagsel_tag{padding-left:28px;font-size:97%;font-weight:bold}.toolbar #tagsel_form{margin-top:.5em}.toolbar li{display:inline;list-style:none}.toolbar li a{border-left:1px solid #e8e8e8}.toolbar li:first-child a{border-left:0}.toolbar ul{padding-left:0}#basket .toolbar{padding:7px 5px 9px 9px}#selections-toolbar{background:-moz-linear-gradient(top,#b2b2b2 0,#e0e0e0 14%,#e8e8e8 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#b2b2b2),color-stop(14%,#e0e0e0),color-stop(100%,#e8e8e8));background:-webkit-linear-gradient(top,#b2b2b2 0,#e0e0e0 14%,#e8e8e8 100%);background:-o-linear-gradient(top,#b2b2b2 0,#e0e0e0 14%,#e8e8e8 100%);background:-ms-linear-gradient(top,#b2b2b2 0,#e0e0e0 14%,#e8e8e8 100%);background:linear-gradient(top,#b2b2b2 0,#e0e0e0 14%,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e0e0e0',endColorstr='#e8e8e8',GradientType=0);margin:0 0 1em 0;padding-top:.5em;padding-left:10px}.list-actions{display:inline}#tagsel_span input.submit,#tagsel_tag{border:0;background-color:transparent;font-size:100%;color:#0076b2;cursor:pointer;background-image:url("../images/sprite.png");background-position:1px -643px;background-repeat:no-repeat;padding-left:25px;text-decoration:none}#tagsel_tag.disabled{background-position:-1px -667px}#tagsel_span input:hover,#selections-toolbar input.hold:hover{color:#005580;text-decoration:underline}#tagsel_span input.disabled,#tagsel_span input.disabled:hover,#tagsel_span input.hold.disabled,#tagsel_span input.hold.disabled:hover,#selections-toolbar input.hold.disabled,#selections-toolbar input.hold.disabled:hover,#selections-toolbar a.disabled,#selections-toolbar a.disabled:hover{color:#888;text-decoration:none;padding-left:23px}.results_summary{display:block;font-size:85%;color:#707070;padding:0 0 .5em 0}.results_summary .results_summary{font-size:100%}.results_summary.actions{margin-top:.5em}.results_summary.tagstatus{display:inline}.results_summary .label{color:#202020}.results_summary a{font-weight:normal}#views{border-bottom:1px solid #d6d6d6;margin-bottom:.5em;padding:0 2em .2em .2em;white-space:nowrap}.view{padding:.2em .2em 2px .2em}#bibliodescriptions,#isbdcontents{clear:left;margin-top:.5em}.view a,.view span{background-image:url("../images/sprite.png");background-repeat:no-repeat;font-size:87%;font-weight:normal;padding:.4em .7em 5px 26px;text-decoration:none}span#MARCview,span#ISBDview,span#Normalview,span#Fullhistory,span#Briefhistory{font-weight:bold}a#MARCview,span#MARCview{background-position:-3px -23px}a#MARCviewPop,span#MARCviewPop{background-position:-3px -23px}a#ISBDview,span#ISBDview{background-position:-3px -52px}a#Normalview,span#Normalview{background-position:-1px 6px}.view a{background-color:#f3f3f3;border-left:1px solid #c9c9c9}#bookcover{float:left;margin:0;padding:0}#bookcover .no-image{margin-right:10px;margin-bottom:10px}#bookcover img{margin:0 1em 1em 0}.results-pagination{position:absolute;top:32px;left:-1px;width:100%;height:auto;border:1px solid #d0d0d0;display:none;background-color:#f3f3f3;padding-bottom:10px;z-index:100}.back{float:right}.back input{background:none!important;color:#999!important}.pagination_list ul{padding-top:40px;padding-left:0}.pagination_list li{list-style:none;float:bottom;padding:4px;color:#999}.pagination_list li.highlight{background-color:#f3f3f3;border-top:1px solid #ddd;border-bottom:1px solid #ddd}.pagination_list li a{padding-left:0}.pagination_list .li_pag_index{color:#999;float:left;font-size:15px;font-weight:bold;padding-right:10px;text-align:right;width:13px}.nav_results{background-color:#f3f3f3;border:1px solid #d0d0d0;font-size:95%;font-weight:bold;margin-top:.5em;position:relative}.nav_results .l_Results a{background:#e1e1e1 url("../images/sprite.png") no-repeat 0 -504px;color:#069;display:block;padding:8px 28px;text-decoration:none}.nav_results .l_Results:hover{background-color:#d9d9d9}.pg_menu{margin:0;border-top:1px solid #d0d0d0;white-space:nowrap}.pg_menu li{color:#b2b2b2;display:inline;list-style:none;margin:0}.pg_menu li.back_results a{border-left:1px solid #d0d0d0;border-right:1px solid #d0d0d0}.pg_menu li a,.pg_menu li span{background-color:#f3f3f3;display:block;float:left;padding:.4em .5em;text-decoration:none;font-weight:normal;text-align:center}.pg_menu li span{color:#b2b2b2}#listResults li{background-color:#999;color:#c5c5c5;font-weight:normal;display:block;margin-right:1px;font-size:80%;padding:0;text-align:center;min-width:18px}#listResults li:hover{background-color:#069}#listResults li a{color:#fff;font-weight:normal}.nav_pages .close_pagination{padding-right:10px;position:absolute;right:3px;top:-25px}.nav_pages .close_pagination a{text-decoration:none!important}.nav_pages ul{padding-top:10px}.nav_pages li{list-style:none;float:left;padding:4px;color:#999}.nav_pages li a{text-decoration:none!important}.nav_pages li a:hover{text-decoration:underline}.nav_pages li ul{float:left}#action{margin:.5em 0 0 0;background-color:#f3f3f3;border:1px solid #e8e8e8;padding-bottom:3px}#action li{list-style:none;margin:.2em;padding:.3em 0}#action a{font-weight:bold;text-decoration:none}#export li,#moresearches_menu li{padding:0;margin:0}#export li a,#moresearches_menu li a{font-weight:normal}#export li a.menu-inactive,#moresearches_menu li a.menu-inactive{font-weight:bold}#format,#furthersearches{padding-left:35px}.highlight_controls{float:left}a.addtocart,a.addtoshelf,a.brief,a.deleteshelf,a.deleteshelf.disabled,a.detail,a.download,a.editshelf,a.empty,a.hide,a.highlight_toggle,a.hold,a.hold.disabled,a.incart,a.new,a.print-small,a.print-large,a.removeitems,a.removeitems.disabled,a.reserve,a.send,a.tag_add,a.removefromlist,input.hold,input.hold.disabled,input.editshelf,.newshelf,.newshelf.disabled,.deleteshelf{background-image:url("../images/sprite.png");background-repeat:no-repeat}a.addtocart{background-position:-5px -265px;padding-left:35px}a.addtoshelf{background-position:-5px -225px;padding-left:35px}a.brief{background-position:-2px -868px;text-decoration:none;padding-left:27px}a.cartRemove{color:#c33;font-size:90%;margin:0;padding:0}a.detail{background-position:-2px -898px;text-decoration:none;padding-left:27px}a.download{background-position:-5px -348px;padding-left:20px;text-decoration:none}a.editshelf{background-position:2px -348px;padding-left:26px;text-decoration:none}a.empty{background-position:2px -598px;text-decoration:none;padding-left:30px}a.hide{background-position:-3px -814px;text-decoration:none;padding-left:26px}a.highlight_toggle{background-position:-5px -841px;display:none;padding-left:35px}a.hold,input.hold{background-position:-2px -453px;text-decoration:none;padding-left:23px}a.hold.disabled,input.hold.disabled{background-position:-5px -621px}a.incart{background-position:-5px -265px;color:#666;padding-left:35px}a.new{background-image:url("../images/sprite.png");background-position:-4px -922px;padding-left:23px;text-decoration:none}a.print-small{background-position:0 -423px;text-decoration:none;padding-left:30px}a.print-large{background-position:-5px -186px;text-decoration:none;padding-left:35px}a.removeitems,a.deleteshelf{background-position:2px -690px;text-decoration:none;padding-left:25px}a.removeitems.disabled,a.deleteshelf.disabled{background-position:2px -712px}a.reserve{background-position:-6px -144px;padding-left:35px}a.send{background-position:2px -386px;text-decoration:none;padding-left:28px}a.tag_add{background-position:3px -1111px;padding-left:27px;text-decoration:none}input.hold{background-color:transparent;border:0;color:#0076b2;font-weight:bold}input.editshelf{background-color:transparent;background-position:2px -736px;border:0;color:#069;cursor:pointer;filter:none;font-size:100%;padding-left:29px;text-decoration:none}.newshelf{background-position:2px -764px;border:0;color:#069;cursor:pointer;filter:none;font-size:100%;padding-left:28px;text-decoration:none}.newshelf.disabled{background-position:-4px -791px}.deleteshelf{background-color:transparent;background-position:2px -690px;border:0;color:#069;cursor:pointer;filter:none;font-size:100%;padding-left:25px;text-decoration:none}.links a{font-weight:bold}.deleteshelf:hover{color:#903}.editshelf:active,.deleteshelf:active{border:0}#tagslist li{display:inline}#login4tags{background-image:url("../images/sprite.png");background-position:-6px -1130px;background-repeat:no-repeat;padding-left:20px;text-decoration:none}.tag_results_input{margin-left:1em;padding:.3em;font-size:12px}.tag_results_input input[type="text"]{font-size:inherit;margin:0;padding:0}.tag_results_input label{display:inline}.tagsinput input[type="text"]{font-size:inherit;margin:0;padding:0}.tagsinput label{display:inline}.branch-info-tooltip{display:none}#social_networks a{background:transparent url("../images/social-sprite.png") no-repeat;display:block;height:20px!important;width:20px;text-indent:-999em}#social_networks span{color:#274d7f;display:block;float:left;font-size:85%;font-weight:bold;line-height:2em;margin:.5em 0 .5em .5em!important}#social_networks div{float:left!important;margin:.5em 0 .5em .2em!important}#social_networks #facebook{background-position:-7px -35px}#social_networks #twitter{background-position:-7px -5px}#social_networks #linkedin{background-position:-7px -95px}#social_networks #delicious{background-position:-7px -66px}#social_networks #email{background-position:-7px -126px}#marc td,#marc th{background-color:transparent;border:0;padding:3px 5px;text-align:left}#marc td:first-child{text-indent:2em}#marc p{padding-bottom:.6em}#marc p .label{font-weight:bold}#marc ul{padding-bottom:.6em}#marc .results_summary{clear:left}#marc .results_summary ul{display:inline;float:none;clear:none;margin:0;padding:0;list-style:none}#marc .results_summary li{display:inline}#items,#items td #items th{border:1px solid #EEE;font-size:90%}#plainmarc table{border:0;margin:.7em 0 0 0;font-family:monospace;font-size:95%}#plainmarc th{background-color:#FFF;border:0;white-space:nowrap;text-align:left;vertical-align:top;padding:2px}#plainmarc td{border:0;padding:2px;vertical-align:top}#renewcontrols{float:right;font-size:66%}#renewcontrols a{background-repeat:no-repeat;text-decoration:none;padding:.1em .4em;padding-left:18px}#renewselected_link{background-image:url("../images/sprite.png");background-position:-5px -986px;background-repeat:no-repeat}#renewall_link{background-image:url("../images/sprite.png");background-position:-8px -967px;background-repeat:no-repeat}.authref{text-indent:2em}.authref .label{font-style:italic}.authstanza{margin-top:1em}.authstanzaheading{font-weight:bold}.authorizedheading{font-weight:bold}.authstanza li{margin-left:.5em}.authres_notes,.authres_seealso,.authres_otherscript{padding-top:.5em}.authres_notes{font-style:italic}#didyoumean{background-color:#EEE;border:1px solid #e8e8e8;margin:0 0 .5em;text-align:left;padding:.5em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.suggestionlabel{font-weight:bold}.searchsuggestion{padding:.2em .5em;white-space:nowrap;display:inline-block}.authlink{padding-left:.25em}#hierarchies a{font-weight:normal;text-decoration:underline;color:#069}#hierarchies a:hover{color:#903}#top-pages{margin:0 0 .5em}.dropdown-menu>li>a{font-size:90%}a.listmenulink:link,a.listmenulink:visited{color:#0076b2;font-weight:bold}a.listmenulink:hover,a.listmenulink:active{color:#FFF;font-weight:bold}#cartDetails,#cartUpdate,#holdDetails,#listsDetails{background-color:#FFF;border:1px solid rgba(0,0,0,0.2);border-radius:6px 6px 6px 6px;box-shadow:0 5px 10px rgba(0,0,0,0.2);color:black;display:none;font-size:90%;margin:0;padding:8px 20px;text-align:center;width:180px;z-index:2}#cartmenulink{white-space:nowrap}#search-facets,#menu{border:1px solid #d2d2cf;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}#search-facets ul,#menu ul{margin:0;padding:.3em}#search-facets form,#menu form{margin:0}#search-facets h4,#menu h4{font-size:90%;margin:0 0 .6em 0;text-align:center}#search-facets h4 a,#menu h4 a{background-color:#f2f2ef;border-radius:8px 8px 0 0;border-bottom:1px solid #d8d8d8;display:block;font-weight:bold;padding:.7em .2em;text-decoration:none}#search-facets li,#menu li{font-size:90%;font-weight:bold;list-style-type:none}#search-facets li li,#menu li li{font-weight:normal;font-size:95%;line-height:125%;margin-bottom:2px;padding:.1em .2em}#search-facets li.showmore a,#menu li.showmore a{font-weight:bold;text-indent:1em}#search-facets a,#menu a{font-weight:normal;text-decoration:underline}#menu{font-size:94%}#menu li{list-style-type:none}#menu li a{background:#eee;text-decoration:none;display:block;border:1px solid #d8d8d8;border-radius:5px 0 0 5px;border-bottom-color:#999;font-size:111%;padding:.4em .6em;margin:.4em 0;margin-right:-1px}#menu li a:hover{background:#eaeef5}#menu li.active a{background-color:#FFF;background-image:none;border-right-width:0;font-weight:bold}#menu li.active a:hover{background-color:#fff}#menu h4{display:none}#addto{max-width:10em}.addto a.addtocart{background-image:url("../images/sprite.png");background-position:-5px -266px;background-repeat:no-repeat;text-decoration:none;padding-left:33px}.searchresults p{margin:0;padding:0 0 .6em 0}.searchresults p.details{color:#979797}.searchresults a.highlight_toggle{background-image:url("../images/sprite.png");background-position:-11px -841px;background-repeat:no-repeat;display:none;font-weight:normal;padding:0 10px 0 21px}.searchresults .commentline{background-color:#ffc;background-color:rgba(255,255,204,0.4);border:1px solid #CCC;display:inline-block;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);margin:.3em;padding:.4em}.searchresults .commentline.yours{background-color:#effed5;background-color:rgba(239,254,213,0.4)}.commentline .avatar{float:right;padding-left:.5em}.term{color:#900;background-color:#ffc}.shelvingloc{display:block;font-style:italic}#CheckAll,#CheckNone{font-weight:normal;margin:0 .5em;text-decoration:underline}span.sep{color:#888;padding:0 .2em 0 .5em;text-shadow:1px 1px 0 #FFF}.pages span:first-child,.pages a:first-child{border-width:1px 1px 1px 1px;border-bottom-left-radius:3px;border-top-left-radius:3px}.pages span:last-child,.pages a:last-child{border-width:1px 1px 1px 0;border-bottom-right-radius:3px;border-top-right-radius:3px}.pages .inactive,.pages .currentPage,.pages a{-moz-border-bottom-colors:none;-moz-border-left-colors:none;-moz-border-right-colors:none;-moz-border-top-colors:none;background-color:#fff;border-color:#ddd;border-image:none;border-style:solid;border-width:1px 1px 1px 0;float:left;font-size:11.9px;line-height:20px;padding:4px 12px;text-decoration:none}.pages .inactive{background-color:#f5f5f5}.pages a[rel='last']{border-bottom-right-radius:3px;border-top-right-radius:3px}.hold-message{background-color:#fff0b1;display:inline-block;margin:.5em;padding:.2em .5em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.reserve_date,.expiration_date{white-space:nowrap}.close{color:#08c;position:inherit;top:auto;right:auto;filter:none;float:none;font-size:inherit;font-weight:normal;opacity:inherit;text-shadow:none}.close:hover{color:#538200;filter:inherit;font-size:inherit;opacity:inherit}.alert .closebtn{position:relative;top:-2px;right:-21px;line-height:20px}.modal-header .closebtn{margin-top:2px}.closebtn{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.closebtn:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.closebtn{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn-group label,.btn-group select{font-size:13px}.span2 select{width:100%}.popup .main{font-size:90%;padding:0 1em}.popup legend{line-height:1.5em;margin-bottom:.5em}.available{color:#060}.waiting,.intransit,.notforloan,.checkedout,.lost,.notonhold{display:block}.notforloan{color:#900}.lost{color:#666}.suggestion{background-color:#eeeeeb;border:1px solid #ddded3;margin:1em auto;padding:.5em;width:35%;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.librarypulldown .transl1{width:auto}.nolibrarypulldown{width:68%}.nolibrarypulldown .transl1{width:87%}#opac-main-search select{width:auto;max-width:12em}#logo{background:transparent url("../images/koha-logo-navbar.png") no-repeat scroll 0;border:0;float:left!important;margin:0;padding:0;width:100px}#logo a{border:0;cursor:pointer;display:block;height:0!important;margin:0;overflow:hidden;padding:40px 0 0;text-decoration:none;width:100px}#user-menu-trigger{display:none}#user-menu-trigger .icon-user{background:transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;background-position:-168px 0;background-repeat:no-repeat;height:14px;line-height:14px;margin:12px 0 0;vertical-align:text-top;width:14px}#user-menu-trigger .caret{border-bottom-color:#999;border-top-color:#999;margin-top:18px}.floating{-webkit-box-shadow:0 3px 2px 0 rgba(0,0,0,0.4);box-shadow:0 3px 2px 0 rgba(0,0,0,0.4);margin-top:0}.tdlabel{font-weight:bold;display:none}td img{max-width:none}#ulactioncontainer{min-width:16em}.notesrow label{font-weight:bold}.notesrow span{display:block}.thumbnail-shelfbrowser span{margin:0 auto}.dropdown-menu>li>a.menu-inactive:hover{background:#FFF none;color:#000}.table .sorting_asc{padding-right:19px;background:url("../images/asc.gif") no-repeat scroll right center #ecede6}.table .sorting_desc{padding-right:19px;background:url("../images/desc.gif") no-repeat scroll right center #ecede6}.table .sorting{padding-right:19px;background:url("../images/ascdesc.gif") no-repeat scroll right center #ecede6}.table .nosort,.table .nosort.sorting_asc,.table .nosort.sorting_desc,.table .nosort.sorting{padding-right:19px;background:#ecede6 none}.tags ul{display:inline;list-style:none;margin-left:0}.tags ul li{display:inline}.coverimages{float:right}#i18nMenu{margin-left:1em}#i18nMenu li{font-size:85%}#i18nMenu li li{font-size:100%}#i18nMenu li li>a{font-size:100%}#i18nMenu li li>a:hover{color:#FFF}#i18nMenu li a{color:#0076b2}#i18nMenu .dropdown-menu li p{clear:both;display:block;font-weight:normal;line-height:20px;padding:3px 20px;white-space:nowrap}#subjectsList label,#authorSearch label{display:inline;vertical-align:middle}#subjectsList ul,#authorSearch ul{border-bottom:1px solid #EEE;list-style-type:none;margin:0;padding:.6em 0}#subjectsList li,#authorSearch li{list-style-type:none;margin:0;padding:0}#overdrive-results{font-weight:bold;padding-left:1em}.throbber{vertical-align:middle}#overdrive-results-list .star-rating-control{display:block;overflow:auto}#shelfbrowser table{margin:0}#shelfbrowser table,#shelfbrowser td,#shelfbrowser th{border:0;font-size:90%;text-align:center}#shelfbrowser td,#shelfbrowser th{padding:3px 5px;width:20%}#shelfbrowser a{display:block;font-size:110%;font-weight:bold;text-decoration:none}#shelfbrowser #browser_next,#shelfbrowser #browser_previous{background-image:url("../images/sprite.png");background-repeat:no-repeat;width:16px}#shelfbrowser #browser_next a,#shelfbrowser #browser_previous a{cursor:pointer;display:block;height:0!important;margin:0;overflow:hidden;padding:50px 0 0;text-decoration:none;width:16px}#shelfbrowser #browser_previous{background-position:-9px -1007px}#shelfbrowser #browser_next{background-position:-9px -1057px}#holds{margin:0 auto;max-width:800px}.holdrow{clear:both;padding:0 1em 1em 1em;border-bottom:1px solid #CCC;margin-bottom:.5em}.holdrow fieldset{border:0;margin:0;float:none}.holdrow fieldset .label{font-size:14px}.holdrow label{display:inline}.hold-options{clear:both}.toggle-hold-options{background-color:#eee;clear:both;display:block;font-weight:bold;margin:1em 0;padding:.5em}.copiesrow{clear:both}#idreambooksreadometer{float:right}a.idreambooksrating{font-size:30px;color:#29ade4;padding-left:85px;line-height:30px;text-decoration:none}.idreambookslegend{font-size:small}a.reviewlink,a.reviewlink:visited{text-decoration:none;color:black;font-weight:normal}.idreambookssummary a{color:#707070;text-decoration:none}.idreambookssummary img,.idbresult img{vertical-align:middle}.idbresult{color:#29ade4;text-align:center;margin:.5em;padding:.5em}.idbresult a,.idbresult a:visited{text-decoration:none;color:#29ade4}.idbresult img{padding-right:6px}.js-show{display:none}.modal-nojs .modal-header,.modal-nojs .modal-footer{display:none}.shadowed{-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);-moz-box-shadow:0 1px 1px 0 rgba(0,0,0,0.2);box-shadow:0 1px 1px 0 rgba(0,0,0,0.2)}@media only screen and (min-width:0) and (max-width:304px){#oh:after{content:"(min-width: 0px) and (max-width: 304px)"}input,select,textarea{width:auto;max-width:11em}}@media only screen and (min-width:0) and (max-width:390px){#oh:after{content:"(min-width: 0px) and (max-width: 390px)"}.ui-tabs .ui-tabs-nav li a,.statictabs li a{padding:.1em .5em}#views{border:0;padding:0;margin:0}.view{padding:0}.view a,.view span{border:1px solid #c9c9c9;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;font-size:80%;padding:.3em .4em 4px 26px}.input-fluid{width:90%}}@media only screen and (min-width:305px) and (max-width:341px){#oh:after{content:"(min-width: 305px) and (max-width: 341px)"}}@media only screen and (min-width:342px) and (max-width:479px){#oh:after{content:"(min-width: 342px) and (max-width: 479px)"}.input-fluid{width:75%}}@media(max-width:979px){.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;margin-left:0;margin-right:0}}@media only screen and (max-width:608px){fieldset.rows label{display:block;float:none;text-align:left}fieldset.rows li{padding-bottom:.5em}fieldset.rows ol{margin-left:0}fieldset.rows .hint{margin-left:0}body{padding:0}.tdlabel{display:inline}.navbar-fixed-top,.navbar-static-top{margin:0}.navbar-inner{padding:0}.checkall,.clearall,.highlight_controls,#selections-toolbar,.selectcol,.list-actions,#remove-selected{display:none}.table td.bibliocol{padding-left:1.3em}.actions{display:block}.actions a,.actions #login4tags{background-color:#f2f2ef;border:1px solid #DDD;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;font-weight:bold;display:block;font-size:120%;margin:2px 0}.actions .label{display:block;font-weight:bold}.actions #login4tags{margin-right:1em}#opac-main-search button,#opac-main-search input,#opac-main-search select,#opac-main-search .librarypulldown .transl1,#opac-main-search .input-append{display:block;width:97%;max-width:100%;margin:.5em 0;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}#opac-main-search .input-append{margin:0;width:100%}#opac-main-search .librarypulldown .transl1{width:94.5%}#toolbar .resort{font-size:14px;max-width:100%;margin:.5em 0;padding:4px 6px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mastheadsearch{margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.main{margin:.5em 0;padding:15px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.breadcrumb{margin:10px 0}#moresearches{text-align:center}#searchsubmit{font-weight:bold}.ui-tabs-panel .item-thumbnail,.tabs-container .item-thumbnail,#topissues .item-thumbnail,#usertags .item-thumbnail,#usersuggestions .item-thumbnail{margin:.5em 0 0 .5em}.ui-tabs-panel .table-bordered,.tabs-container .table-bordered,#topissues .table-bordered,#usertags .table-bordered,#usersuggestions .table-bordered{border:0}.ui-tabs-panel .table th,.tabs-container .table th,#topissues .table th,#usertags .table th,#usersuggestions .table th,.ui-tabs-panel .table thead,.tabs-container .table thead,#topissues .table thead,#usertags .table thead,#usersuggestions .table thead{display:none}.ui-tabs-panel .table td,.tabs-container .table td,#topissues .table td,#usertags .table td,#usersuggestions .table td{border-right:1px solid #ddd;border-left:1px solid #ddd;border-top:0;display:block;padding:.2em}.ui-tabs-panel .table p,.tabs-container .table p,#topissues .table p,#usertags .table p,#usersuggestions .table p{margin-bottom:2px}.ui-tabs-panel tr,.tabs-container tr,#topissues tr,#usertags tr,#usersuggestions tr{display:block;margin-bottom:.6em}.ui-tabs-panel tr td:first-child,.tabs-container tr td:first-child,#topissues tr td:first-child,#usertags tr td:first-child,#usersuggestions tr td:first-child{border-top:1px solid #ddd;border-radius:5px 5px 0 0}.ui-tabs-panel tr td:last-child,.tabs-container tr td:last-child,#topissues tr td:last-child,#usertags tr td:last-child,#usersuggestions tr td:last-child{border-radius:0 0 5px 5px;border-bottom:2px solid #cacaca}.no-image{display:none}}@media only screen and (max-width:700px){#opac-main-search label{display:none}#logo{background:transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;background-position:0 -24px;margin:14px 14px 0 14px;width:14px}#logo a{padding:14px 0 0;width:14px}#user-menu-trigger{display:inline;margin-right:12px}#members{display:none;clear:both}#members li{padding-right:20px;text-align:right;border-bottom:1px solid #555}#members li:first-child{border-top:1px solid #555}#members li:last-child{border-bottom:0}#members .nav{float:none}#members .nav.pull-right{float:none}#members .nav>li{float:none}#members .divider-vertical{border:0;height:0;margin:0}}@media only screen and (min-width:480px) and (max-width:608px){#oh:after{content:" Between 480 pixels and 608 pixels. "}.input-fluid{width:75%}}@media only screen and (min-width:608px) and (max-width:767px){#oh:after{content:" Between 608 pixels and 767 pixels. "}.main{padding:.8em 20px}.breadcrumb{margin:10px 0}.navbar-static-bottom{margin-left:-20px;margin-right:-20px}}@media only screen and (max-width:767px){a.title{font-size:120%}#userresults{margin:0 -20px}.breadcrumb,#top-pages,.menu-collapse{display:none}#search-facets,#menu{margin-bottom:.5em}#search-facets h4,#menu h4{display:block;margin:0;padding:0}#search-facets h4 a,#menu h4 a{-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;border-bottom:0;font-weight:normal;padding:.7em .2em}#search-facets ul,#menu ul{padding:0}#menu li a{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0;display:block;font-size:120%;text-decoration:none;border-bottom:1px solid #d8d8d8;margin:0}#menu li.active a{border-top:1px solid #d8d8d8;border-right-width:1px}#menu li:last-child a{-webkit-border-radius:0 0 7px 7px;-moz-border-radius:0 0 7px 7px;border-radius:0 0 7px 7px}#search-facets li{padding:.4em}#search-facets h5{margin:.2em}#menu h4 a.menu-open,#search-facets h4 a.menu-open{-webkit-border-radius:7px 7px 0 0;-moz-border-radius:7px 7px 0 0;border-radius:7px 7px 0 0;border-bottom:1px solid #d8d8d8}}@media only screen and (max-width:800px){.cartlabel,.listslabel{display:none}.navbar .divider-vertical{margin:0 2px}.navbar #members .divider-vertical{margin:0 9px}}@media only screen and (min-width:768px){.main{margin-left:20px;margin-right:20px}#menu{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-right:1px solid #d8d8d8}#menu h4{display:none}#menu ul{padding:1em 0 1em 0}}@media only screen and (min-width:768px) and (max-width:984px){#oh:after{content:" Between 768 and 984 pixels. "}.librarypulldown .transl1{width:38%}}@media only screen and (min-width:984px){#oh:after{content:" Above 984 pixels. "}.librarypulldown .transl1{width:53%}}@media only screen and (max-width:1040px){.pg_menu li a{float:none;text-align:left}.pg_menu li.back_results a{border:1px solid #d0d0d0;border-width:1px 0 1px 0}#ulactioncontainer{min-width:0}} >\ No newline at end of file >+.shadowed { >+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+} >+body { >+ background-color: #EAEAE6; >+} >+/* Sticky footer styles */ >+html, >+body { >+ height: 100%; >+ /* The html and body elements cannot have any padding or margin. */ >+} >+.no-js .dateformat { >+ display: inline; >+ white-space: nowrap; >+} >+.no-js .modal-body { >+ padding: 0; >+} >+.js .dateformat { >+ display: none; >+} >+/* Wrapper for page content to push down footer */ >+#wrap { >+ min-height: 100%; >+ height: auto !important; >+ height: 100%; >+ /* Negative indent footer by it's height */ >+} >+/* Set the fixed height of the footer here */ >+.popup { >+ padding-left: 0; >+ padding-right: 0; >+} >+a { >+ color: #0076b2; >+} >+a.cancel { >+ padding-left: 1em; >+} >+a:visited { >+ color: #0076b2; >+} >+a.title { >+ font-weight: bold; >+ font-size: 108%; >+} >+a.btn-primary:visited { >+ color: #FFF; >+} >+.ui-widget-content a, >+.ui-widget-content a:visited { >+ color: #0076b2; >+} >+h1 { >+ font-size: 140%; >+ line-height: 150%; >+} >+h1#libraryname { >+ background: transparent url(../images/logo-koha.png) no-repeat scroll 0%; >+ border: 0; >+ float: left !important; >+ margin: 0; >+ padding: 0; >+ width: 120px; >+} >+h1#libraryname a { >+ border: 0; >+ cursor: pointer; >+ display: block; >+ height: 0px !important; >+ margin: 0; >+ overflow: hidden; >+ padding: 40px 0 0; >+ text-decoration: none; >+ width: 120px; >+} >+h2 { >+ font-size: 130%; >+ line-height: 150%; >+} >+h3 { >+ font-size: 120%; >+ line-height: 150%; >+} >+h4 { >+ font-size: 110%; >+} >+h5 { >+ font-size: 100%; >+} >+caption { >+ font-size: 120%; >+ font-weight: bold; >+ margin: 0; >+ text-align: left; >+} >+input, >+textarea { >+ width: auto; >+} >+.input-fluid { >+ width: 50%; >+} >+legend { >+ font-size: 110%; >+ font-weight: bold; >+} >+table, >+td { >+ background-color: #FFF; >+} >+td .btn { >+ white-space: nowrap; >+} >+td .btn-link { >+ padding: 0; >+} >+#advsearches label, >+#booleansearch label { >+ display: inline; >+} >+#basketcount { >+ display: inline; >+ margin: 0; >+ padding: 0; >+} >+#basketcount span { >+ background-color: #FFC; >+ color: #000; >+ display: inline; >+ font-size: 80%; >+ font-weight: normal; >+ margin: 0 0 0 .9em; >+ padding: 0 .3em 0 .3em; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+} >+#members { >+ display: block; >+} >+#members p { >+ color: #EEE; >+} >+#members a { >+ color: #A6D8ED; >+ font-weight: bold; >+} >+#members a.logout { >+ color: #E8583C; >+ padding: 0 .3em 0 .3em; >+} >+#koha_url p { >+ color: #666666; >+ float: right; >+ margin: 0; >+} >+#moresearches { >+ margin: .5em 0; >+ padding: 0 .8em; >+} >+#moresearches li { >+ display: inline; >+ white-space: nowrap; >+} >+#moresearches li:after { >+ content: " | "; >+} >+#moresearches ul { >+ margin: 0; >+} >+#moresearches li:last-child:after { >+ content: ""; >+} >+#news { >+ margin: .5em 0; >+} >+#opacheader { >+ background-color: #DDD; >+} >+#selections { >+ font-weight: bold; >+} >+.actions a { >+ white-space: nowrap; >+ /* List contents remove from list link */ >+} >+.actions a.hold { >+ background-image: url("../images/sprite.png"); >+ /* Place hold small */ >+ background-position: -5px -542px; >+ background-repeat: no-repeat; >+ margin-right: 1em; >+ padding-left: 21px; >+ text-decoration: none; >+} >+.actions a.addtocart { >+ background-image: url("../images/sprite.png"); >+ /* Cart small */ >+ background-position: -5px -572px; >+ background-repeat: no-repeat; >+ margin-right: 1em; >+ padding-left: 20px; >+ text-decoration: none; >+} >+.actions a.addtoshelf { >+ background-image: url("../images/sprite.png"); >+ /* MARC view */ >+ background-position: -5px -27px; >+ background-repeat: no-repeat; >+ margin-right: 1em; >+ padding-left: 20px; >+ text-decoration: none; >+} >+.actions a.addtolist { >+ background-position: -5px -27px; >+ margin-right: 1em; >+ padding-left: 20px; >+ text-decoration: none; >+} >+.actions a.tag_add { >+ background-position: -5px -1110px; >+ margin-right: 1em; >+ padding-left: 20px; >+ text-decoration: none; >+} >+.actions a.removefromlist { >+ background-position: -8px -690px; >+ /* Delete */ >+ margin-right: 1em; >+ text-decoration: none; >+ padding-left: 15px; >+} >+/* Override Bootstrap alert */ >+.alert { >+ background: #fffbe5; >+ /* Old browsers */ >+ background: -moz-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%); >+ /* FF3.6+ */ >+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fffbe5), color-stop(9%, #fff0b2), color-stop(89%, #fff1a8), color-stop(100%, #f7e665)); >+ /* Chrome,Safari4+ */ >+ background: -webkit-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%); >+ /* Chrome10+,Safari5.1+ */ >+ background: -o-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%); >+ /* Opera 11.10+ */ >+ background: -ms-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%); >+ /* IE10+ */ >+ background: linear-gradient(to bottom, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%); >+ /* W3C */ >+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbe5', endColorstr='#f7e665', GradientType=0); >+ /* IE6-9 */ >+ border-color: #D6C43B; >+ color: #333; >+} >+/* Override Bootstrap alert.alert-info */ >+.alert-info { >+ background: #f4f6fa; >+ /* Old browsers */ >+ background: -moz-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%); >+ /* FF3.6+ */ >+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f6fa), color-stop(4%, #eaeef5), color-stop(96%, #e8edf6), color-stop(100%, #cddbf2)); >+ /* Chrome,Safari4+ */ >+ background: -webkit-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%); >+ /* Chrome10+,Safari5.1+ */ >+ background: -o-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%); >+ /* Opera 11.10+ */ >+ background: -ms-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%); >+ /* IE10+ */ >+ background: linear-gradient(to bottom, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%); >+ /* W3C */ >+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f6fa', endColorstr='#cddbf2', GradientType=0); >+ /* IE6-9 */ >+ border-color: #C5D1E5; >+ color: #333; >+} >+/* Override Bootstrap alert.alert-success */ >+.alert-success { >+ background: #f8ffe8; >+ /* Old browsers */ >+ background: -moz-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%); >+ /* FF3.6+ */ >+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8ffe8), color-stop(4%, #e3f5ab), color-stop(98%, #dcf48d), color-stop(100%, #9ebf28)); >+ /* Chrome,Safari4+ */ >+ background: -webkit-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%); >+ /* Chrome10+,Safari5.1+ */ >+ background: -o-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%); >+ /* Opera 11.10+ */ >+ background: -ms-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%); >+ /* IE10+ */ >+ background: linear-gradient(to bottom, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%); >+ /* W3C */ >+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8ffe8', endColorstr='#9ebf28', GradientType=0); >+ /* IE6-9 */ >+ border-color: #9FBA35; >+ color: #333; >+} >+.breadcrumb { >+ background-color: #F2F2EF; >+ font-size: 85%; >+ list-style: none outside none; >+ margin: 10px 20px; >+ padding: 5px 10px; >+ -webkit-border-radius: 7px; >+ -moz-border-radius: 7px; >+ border-radius: 7px; >+} >+.form-inline { >+ display: inline; >+ padding: 0; >+ margin: 0; >+} >+.form-inline fieldset { >+ margin: 0.3em 0; >+ padding: 0.3em; >+} >+.main { >+ background-color: #FFF; >+ border: 1px solid #D2D2CF; >+ -webkit-border-radius: 7px; >+ -moz-border-radius: 7px; >+ border-radius: 7px; >+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ margin-top: 0.5em; >+ margin-bottom: 0.5em; >+} >+.mastheadsearch { >+ -webkit-border-radius: 7px; >+ -moz-border-radius: 7px; >+ border-radius: 7px; >+ padding: .8em; >+ margin: .5em 0; >+ background: #c7c7c1; >+ /* Old browsers */ >+ background: -moz-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%); >+ /* FF3.6+ */ >+ background: -webkit-gradient(linear, left top, left bottom, color-stop(38%, #c7c7c1), color-stop(100%, #a7a7a2)); >+ /* Chrome,Safari4+ */ >+ background: -webkit-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%); >+ /* Chrome10+,Safari5.1+ */ >+ background: -o-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%); >+ /* Opera 11.10+ */ >+ background: -ms-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%); >+ /* IE10+ */ >+ background: linear-gradient(to bottom, #c7c7c1 38%, #a7a7a2 100%); >+ /* W3C */ >+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#c7c7c1', endColorstr='#a7a7a2', GradientType=0); >+ /* IE6-9 */ >+} >+.mastheadsearch label { >+ font-size: 115%; >+ font-weight: bold; >+} >+.navbar-inverse .brand, >+.navbar-inverse .nav > li > a { >+ color: #9FE1FF; >+ font-weight: bold; >+} >+.navbar-fixed-bottom.navbar-static-bottom { >+ margin-top: .5em; >+ position: static; >+} >+#changelanguage .nav > .active > p { >+ padding: 0 15px; >+} >+.table-striped tbody > tr:nth-child(odd) > td, >+.table-striped tbody > tr:nth-child(odd) > th { >+ background-color: #F4F4F4; >+} >+/* jQuery UI standard tabs */ >+.ui-tabs-nav .ui-tabs-active a, >+.ui-tabs-nav a:hover, >+.ui-tabs-nav a:focus, >+.ui-tabs-nav a:active, >+.ui-tabs-nav span.a { >+ background: none repeat scroll 0 0 transparent; >+ outline: 0 none; >+} >+.ui-widget, >+.ui-widget input, >+.ui-widget select, >+.ui-widget textarea, >+.ui-widget button { >+ font-family: inherit; >+ font-size: inherit; >+} >+ul.ui-tabs-nav li { >+ list-style: none; >+} >+.ui-tabs.ui-widget-content { >+ background: transparent none; >+ border: 0; >+} >+.ui-tabs .ui-tabs-panel { >+ border: 1px solid #D8D8D8; >+ margin-bottom: 1em; >+} >+.ui-tabs-nav.ui-widget-header { >+ border: 0; >+ background: none; >+} >+.ui-tabs .ui-tabs-nav li { >+ background: #F3F3F3 none; >+ border-color: #D8D8D8; >+ margin-right: .4em; >+} >+.ui-tabs .ui-tabs-nav li.ui-tabs-active { >+ background-color: #FFF; >+ border: 1px solid #D8D8D8; >+ border-bottom: 0; >+} >+.ui-tabs .ui-tabs-nav li.ui-tabs-active a { >+ color: #000; >+ font-weight: bold; >+} >+.ui-tabs .ui-tabs-nav li.ui-state-default.ui-state-hover { >+ background: #F3F3F3 none; >+} >+.ui-tabs .ui-tabs-nav li.ui-tabs-active.ui-state-hover { >+ background: #FFF none; >+} >+.ui-tabs .ui-state-default a, >+.ui-tabs .ui-state-default a:link, >+.ui-tabs .ui-state-default a:visited { >+ color: #006699; >+} >+.ui-tabs .ui-state-hover a, >+.ui-tabs .ui-state-hover a:link, >+.ui-tabs .ui-state-hover a:visited { >+ color: #990033; >+} >+.statictabs ul { >+ background: none repeat scroll 0 0 transparent; >+ border: 0 none; >+ margin: 0; >+ padding: 0.2em 0.2em 0; >+ border-bottom-right-radius: 4px; >+ border-bottom-left-radius: 4px; >+ border-top-right-radius: 4px; >+ border-top-left-radius: 4px; >+ color: #222222; >+ font-weight: bold; >+ font-size: 100%; >+ line-height: 1.3; >+ list-style: none outside none; >+ outline: 0 none; >+ text-decoration: none; >+} >+.statictabs ul:before { >+ content: ""; >+ display: table; >+} >+.statictabs ul:after { >+ clear: both; >+ content: ""; >+ display: table; >+} >+.statictabs li { >+ background: none repeat scroll 0 0 #E6F0F2; >+ border: 1px solid #B9D8D9; >+ border-bottom: 0 none !important; >+ border-top-right-radius: 4px; >+ border-top-left-radius: 4px; >+ float: left; >+ list-style: none outside none; >+ margin-bottom: 0; >+ margin-right: 0.4em; >+ padding: 0; >+ position: relative; >+ white-space: nowrap; >+ top: 1px; >+ color: #555555; >+ font-weight: normal; >+} >+.statictabs li.active { >+ background-color: #FFFFFF; >+ color: #212121; >+ font-weight: normal; >+ padding-bottom: 1px; >+} >+.statictabs li a { >+ color: #004D99; >+ cursor: pointer; >+ float: left; >+ padding: 0.5em 1em; >+ text-decoration: none; >+} >+.statictabs li a:hover { >+ background-color: #EDF4F5; >+ border-top-right-radius: 4px; >+ border-top-left-radius: 4px; >+ color: #538200; >+} >+.statictabs li.active a { >+ color: #000000; >+ font-weight: bold; >+ cursor: text; >+ background: none repeat scroll 0 0 transparent; >+ outline: 0 none; >+} >+.statictabs .tabs-container { >+ border: 1px solid #B9D8D9; >+ background: none repeat scroll 0 0 transparent; >+ display: block; >+ padding: 1em 1.4em; >+ border-bottom-right-radius: 4px; >+ border-bottom-left-radius: 4px; >+ color: #222222; >+} >+/* End jQueryUI tab styles */ >+/* jQuery UI Datepicker */ >+.ui-datepicker table { >+ width: 100%; >+ font-size: .9em; >+ border: 0; >+ border-collapse: collapse; >+ margin: 0 0 .4em; >+} >+.ui-datepicker th { >+ background: transparent none; >+ padding: .7em .3em; >+ text-align: center; >+ font-weight: bold; >+ border: 0; >+} >+.ui-datepicker-trigger { >+ vertical-align: middle; >+ margin: 0 3px; >+} >+.ui-datepicker { >+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+} >+/* End jQueryUI datepicker styles */ >+/* jQueryUI Core */ >+.ui-widget-content { >+ border: 1px solid #AAA; >+ background: #ffffff none; >+ color: #222222; >+} >+.ui-widget-header { >+ border: 1px solid #AAA; >+ background: #E6F0F2 none; >+ color: #222222; >+ font-weight: bold; >+} >+.ui-state-default, >+.ui-widget-content .ui-state-default, >+.ui-widget-header .ui-state-default { >+ border: 1px solid #AAA; >+ background: #F4F8F9 none; >+ font-weight: normal; >+ color: #555555; >+} >+.ui-state-hover, >+.ui-widget-content .ui-state-hover, >+.ui-widget-header .ui-state-hover, >+.ui-state-focus, >+.ui-widget-content .ui-state-focus, >+.ui-widget-header .ui-state-focus { >+ border: 1px solid #AAA; >+ background: #E6F0F2 none; >+ font-weight: normal; >+ color: #212121; >+} >+.ui-state-active, >+.ui-widget-content .ui-state-active, >+.ui-widget-header .ui-state-active { >+ border: 1px solid #aaaaaa; >+ background: #ffffff none; >+ font-weight: normal; >+ color: #212121; >+} >+.ui-state-highlight, >+.ui-widget-content .ui-state-highlight, >+.ui-widget-header .ui-state-highlight { >+ border: 1px solid #fcefa1; >+ background: #fbf9ee; >+ color: #363636; >+} >+.ui-state-error, >+.ui-widget-content .ui-state-error, >+.ui-widget-header .ui-state-error { >+ border: 1px solid #cd0a0a; >+ background: #fef1ec; >+ color: #cd0a0a; >+} >+/* end jQueryUI core */ >+/* jQueryUI autocomplete */ >+.ui-autocomplete { >+ position: absolute; >+ cursor: default; >+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+} >+.ui-autocomplete.ui-widget-content .ui-state-hover { >+ border: 1px solid #AAA; >+ background: #E6F0F2 none; >+ font-weight: normal; >+ color: #212121; >+} >+.ui-autocomplete-loading { >+ background: #ffffff url("../../img/loading-small.gif") right center no-repeat; >+} >+.ui-menu li { >+ list-style: none; >+} >+/* end jQueryUI autocomplete */ >+th { >+ background-color: #ECEDE6; >+} >+.item-thumbnail { >+ max-width: none; >+} >+.no-image { >+ background-color: #FFF; >+ border: 1px solid #AAA; >+ color: #979797; >+ display: block; >+ font-size: 86%; >+ font-weight: bold; >+ text-align: center; >+ width: 75px; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+} >+#bookcover .no-image { >+ margin-right: 10px; >+ margin-bottom: 10px; >+} >+td.overdue { >+ color: #cc3333; >+} >+table { >+ font-size: 90%; >+} >+th.sum { >+ text-align: right; >+} >+td.sum { >+ background-color: #FFC; >+ font-weight: bold; >+} >+th[scope=row] { >+ background-color: transparent; >+ text-align: right; >+} >+.required { >+ color: #C00; >+} >+.label { >+ background-color: transparent; >+ color: inherit; >+ display: inline; >+ font-weight: normal; >+ padding: 0; >+ text-shadow: none; >+} >+fieldset.rows { >+ float: left; >+ font-size: 90%; >+ clear: left; >+ margin: .9em 0 0 0; >+ padding: 0; >+ width: 100%; >+} >+fieldset.rows legend { >+ font-weight: bold; >+ font-size: 130%; >+} >+fieldset.rows label, >+fieldset.rows .label { >+ float: left; >+ font-weight: bold; >+ width: 9em; >+ margin-right: 1em; >+ text-align: right; >+} >+fieldset.rows label.lradio { >+ float: none; >+ margin: inherit; >+ width: auto; >+} >+fieldset.rows fieldset { >+ margin: 0; >+ padding: .3em; >+} >+fieldset.rows ol { >+ padding: 1em 1em 0 1em; >+ list-style-type: none; >+} >+fieldset.rows ol.lradio label { >+ width: auto; >+ float: none; >+ margin-right: 0; >+} >+fieldset.rows ol.lradio label.lradio { >+ float: left; >+ width: 12em; >+ margin-right: 1em; >+} >+fieldset.rows li { >+ float: left; >+ clear: left; >+ padding-bottom: 1em; >+ list-style-type: none; >+ width: 100%; >+} >+fieldset.rows li.lradio { >+ padding-left: 8.5em; >+ width: auto; >+} >+fieldset.rows li.lradio label { >+ float: none; >+ width: auto; >+ margin: 0 0 0 1em; >+} >+fieldset.rows .hint { >+ display: block; >+ margin-left: 11em; >+} >+fieldset.action { >+ clear: both; >+ float: none; >+ border: none; >+ margin: 0; >+ padding: 1em 0 .3em 0; >+ width: auto; >+} >+fieldset.action p { >+ margin-bottom: 1em; >+} >+fieldset table { >+ font-size: 100%; >+} >+div.rows + div.rows { >+ margin-top: .6em; >+} >+div.rows { >+ float: left; >+ clear: left; >+ margin: 0 0 0 0; >+ padding: 0; >+ width: 100%; >+} >+div.rows span.label { >+ float: left; >+ font-weight: bold; >+ width: 9em; >+ margin-right: 1em; >+ text-align: left; >+} >+div.rows ol { >+ list-style-type: none; >+ margin-left: 0; >+ padding: .5em 1em 0 0; >+} >+div.rows li { >+ border-bottom: 1px solid #EEE; >+ float: left; >+ clear: left; >+ padding-bottom: .2em; >+ padding-top: .1em; >+ list-style-type: none; >+ width: 100%; >+} >+div.rows ul li { >+ margin-left: 7.3em; >+} >+div.rows ul li:first-child { >+ float: none; >+ clear: none; >+ margin-left: 0; >+} >+div.rows ol li li { >+ border-bottom: 0; >+} >+/* different sizes for different tags in opac-tags.tt */ >+.tagweight0 { >+ font-size: 12px; >+} >+.tagweight1 { >+ font-size: 14px; >+} >+.tagweight2 { >+ font-size: 16px; >+} >+.tagweight3 { >+ font-size: 18px; >+} >+.tagweight4 { >+ font-size: 20px; >+} >+.tagweight5 { >+ font-size: 22px; >+} >+.tagweight6 { >+ font-size: 24px; >+} >+.tagweight7 { >+ font-size: 26px; >+} >+.tagweight8 { >+ font-size: 28px; >+} >+.tagweight9 { >+ font-size: 30px; >+} >+.toolbar { >+ background-color: #EEEEEE; >+ border: 1px solid #E8E8E8; >+ font-size: 85%; >+ padding: 3px 3px 5px 5px; >+ vertical-align: middle; >+} >+.toolbar a { >+ white-space: nowrap; >+} >+.toolbar label { >+ display: inline; >+ font-size: 100%; >+ font-weight: bold; >+ margin-left: .5em; >+} >+.toolbar select { >+ font-size: 97%; >+ height: auto; >+ line-height: inherit; >+ padding: 0; >+ margin: 0; >+ width: auto; >+ white-space: nowrap; >+} >+.toolbar .hold, >+.toolbar #tagsel_tag { >+ padding-left: 28px; >+ font-size: 97%; >+ font-weight: bold; >+} >+.toolbar #tagsel_form { >+ margin-top: .5em; >+} >+.toolbar li { >+ display: inline; >+ list-style: none; >+} >+.toolbar li a { >+ border-left: 1px solid #e8e8e8; >+} >+.toolbar li:first-child a { >+ border-left: 0; >+} >+.toolbar ul { >+ padding-left: 0; >+} >+#basket .toolbar { >+ padding: 7px 5px 9px 9px; >+} >+#selections-toolbar { >+ background: -moz-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%); >+ /* FF3.6+ */ >+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b2b2b2), color-stop(14%, #e0e0e0), color-stop(100%, #e8e8e8)); >+ /* Chrome,Safari4+ */ >+ background: -webkit-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%); >+ /* Chrome10+,Safari5.1+ */ >+ background: -o-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%); >+ /* Opera 11.10+ */ >+ background: -ms-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%); >+ /* IE10+ */ >+ background: linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%); >+ /* W3C */ >+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e0e0e0', endColorstr='#e8e8e8', GradientType=0); >+ /* IE6-9 */ >+ margin: 0 0 1em 0; >+ padding-top: .5em; >+ padding-left: 10px; >+} >+.list-actions { >+ display: inline; >+} >+#tagsel_span input.submit, >+#tagsel_tag { >+ border: 0; >+ background-color: transparent; >+ font-size: 100%; >+ color: #0076B2; >+ cursor: pointer; >+ background-image: url("../images/sprite.png"); >+ /* Tags */ >+ background-position: 1px -643px; >+ background-repeat: no-repeat; >+ padding-left: 25px; >+ text-decoration: none; >+} >+#tagsel_tag.disabled { >+ background-position: -1px -667px; >+} >+#tagsel_span input:hover, >+#selections-toolbar input.hold:hover { >+ color: #005580; >+ text-decoration: underline; >+} >+#tagsel_span input.disabled, >+#tagsel_span input.disabled:hover, >+#tagsel_span input.hold.disabled, >+#tagsel_span input.hold.disabled:hover, >+#selections-toolbar input.hold.disabled, >+#selections-toolbar input.hold.disabled:hover, >+#selections-toolbar a.disabled, >+#selections-toolbar a.disabled:hover { >+ color: #888888; >+ text-decoration: none; >+ padding-left: 23px; >+} >+.results_summary { >+ display: block; >+ font-size: 85%; >+ color: #707070; >+ padding: 0 0 .5em 0; >+} >+.results_summary .results_summary { >+ font-size: 100%; >+} >+.results_summary.actions { >+ margin-top: .5em; >+} >+.results_summary.tagstatus { >+ display: inline; >+} >+.results_summary .label { >+ color: #202020; >+} >+.results_summary a { >+ font-weight: normal; >+} >+#views { >+ border-bottom: 1px solid #D6D6D6; >+ margin-bottom: .5em; >+ padding: 0 2em 0.2em 0.2em; >+ white-space: nowrap; >+} >+.view { >+ padding: 0.2em .2em 2px .2em; >+} >+#bibliodescriptions, >+#isbdcontents { >+ clear: left; >+ margin-top: .5em; >+} >+.view a, >+.view span { >+ background-image: url("../images/sprite.png"); >+ background-repeat: no-repeat; >+ font-size: 87%; >+ font-weight: normal; >+ padding: 0.4em 0.7em 5px 26px; >+ text-decoration: none; >+} >+span#MARCview, >+span#ISBDview, >+span#Normalview, >+span#Fullhistory, >+span#Briefhistory { >+ font-weight: bold; >+} >+a#MARCview, >+span#MARCview { >+ background-position: -3px -23px; >+} >+a#MARCviewPop, >+span#MARCviewPop { >+ background-position: -3px -23px; >+} >+a#ISBDview, >+span#ISBDview { >+ background-position: -3px -52px; >+} >+a#Normalview, >+span#Normalview { >+ background-position: -1px 6px; >+} >+.view a { >+ background-color: #F3F3F3; >+ border-left: 1px solid #C9C9C9; >+} >+#bookcover { >+ float: left; >+ margin: 0; >+ padding: 0; >+} >+#bookcover .no-image { >+ margin-right: 10px; >+ margin-bottom: 10px; >+} >+#bookcover img { >+ margin: 0 1em 1em 0; >+} >+/* pagination */ >+.results-pagination { >+ position: absolute; >+ top: 32px; >+ left: -1px; >+ width: 100%; >+ height: auto; >+ border: 1px solid #D0D0D0; >+ display: none; >+ background-color: #F3F3F3; >+ padding-bottom: 10px; >+ z-index: 100; >+} >+.back { >+ float: right; >+} >+.back input { >+ background: none!important; >+ color: #999!important; >+} >+.pagination_list ul { >+ padding-top: 40px; >+ padding-left: 0px; >+} >+.pagination_list li { >+ list-style: none; >+ float: bottom; >+ padding: 4px; >+ color: #999; >+} >+.pagination_list li.highlight { >+ background-color: #F3F3F3; >+ border-top: 1px solid #DDDDDD; >+ border-bottom: 1px solid #DDDDDD; >+} >+.pagination_list li a { >+ padding-left: 0px; >+} >+.pagination_list .li_pag_index { >+ color: #999999; >+ float: left; >+ font-size: 15px; >+ font-weight: bold; >+ padding-right: 10px; >+ text-align: right; >+ width: 13px; >+} >+.nav_results { >+ background-color: #F3F3F3; >+ border: 1px solid #D0D0D0; >+ font-size: 95%; >+ font-weight: bold; >+ margin-top: 0.5em; >+ position: relative; >+} >+.nav_results .l_Results a { >+ background: #e1e1e1 url("../images/sprite.png") no-repeat 0px -504px; >+ /* Browse results menu */ >+ color: #006699; >+ display: block; >+ padding: 8px 28px; >+ text-decoration: none; >+} >+.nav_results .l_Results:hover { >+ background-color: #D9D9D9; >+} >+.pg_menu { >+ margin: 0; >+ border-top: 1px solid #D0D0D0; >+ white-space: nowrap; >+} >+.pg_menu li { >+ color: #B2B2B2; >+ display: inline; >+ list-style: none; >+ margin: 0; >+} >+.pg_menu li.back_results a { >+ border-left: 1px solid #D0D0D0; >+ border-right: 1px solid #D0D0D0; >+} >+.pg_menu li a, >+.pg_menu li span { >+ background-color: #F3F3F3; >+ display: block; >+ float: left; >+ padding: .4em .5em; >+ text-decoration: none; >+ font-weight: normal; >+ text-align: center; >+} >+.pg_menu li span { >+ color: #B2B2B2; >+} >+#listResults li { >+ background-color: #999999; >+ color: #C5C5C5; >+ font-weight: normal; >+ display: block; >+ margin-right: 1px; >+ font-size: 80%; >+ padding: 0; >+ text-align: center; >+ min-width: 18px; >+} >+#listResults li:hover { >+ background-color: #006699; >+} >+#listResults li a { >+ color: #FFFFFF; >+ font-weight: normal; >+} >+/* nav */ >+.nav_pages .close_pagination { >+ padding-right: 10px; >+ position: absolute; >+ right: 3px; >+ top: -25px; >+} >+.nav_pages .close_pagination a { >+ text-decoration: none!important; >+} >+.nav_pages ul { >+ padding-top: 10px; >+} >+.nav_pages li { >+ list-style: none; >+ float: left; >+ padding: 4px; >+ color: #999; >+} >+.nav_pages li a { >+ text-decoration: none!important; >+} >+.nav_pages li a:hover { >+ text-decoration: underline; >+} >+.nav_pages li ul { >+ float: left; >+} >+/* action buttons */ >+#action { >+ margin: .5em 0 0 0; >+ background-color: #F3F3F3; >+ border: 1px solid #E8E8E8; >+ padding-bottom: 3px; >+} >+#action li { >+ list-style: none; >+ margin: .2em; >+ padding: .3em 0; >+} >+#action a { >+ font-weight: bold; >+ text-decoration: none; >+} >+#export li, >+#moresearches_menu li { >+ padding: 0; >+ margin: 0; >+} >+#export li a, >+#moresearches_menu li a { >+ font-weight: normal; >+} >+#export li a.menu-inactive, >+#moresearches_menu li a.menu-inactive { >+ font-weight: bold; >+} >+#format, >+#furthersearches { >+ padding-left: 35px; >+} >+.highlight_controls { >+ float: left; >+} >+a.addtocart, >+a.addtoshelf, >+a.brief, >+a.deleteshelf, >+a.deleteshelf.disabled, >+a.detail, >+a.download, >+a.editshelf, >+a.empty, >+a.hide, >+a.highlight_toggle, >+a.hold, >+a.hold.disabled, >+a.incart, >+a.new, >+a.print-small, >+a.print-large, >+a.removeitems, >+a.removeitems.disabled, >+a.reserve, >+a.send, >+a.tag_add, >+a.removefromlist, >+input.hold, >+input.hold.disabled, >+input.editshelf, >+.newshelf, >+.newshelf.disabled, >+.deleteshelf { >+ background-image: url("../images/sprite.png"); >+ background-repeat: no-repeat; >+} >+a.addtocart { >+ background-position: -5px -265px; >+ /* Cart */ >+ padding-left: 35px; >+} >+a.addtoshelf { >+ background-position: -5px -225px; >+ /* Virtual shelf */ >+ padding-left: 35px; >+} >+a.brief { >+ background-position: -2px -868px; >+ /* Zoom out */ >+ text-decoration: none; >+ padding-left: 27px; >+} >+a.cartRemove { >+ color: #cc3333; >+ font-size: 90%; >+ margin: 0; >+ padding: 0; >+} >+a.detail { >+ background-position: -2px -898px; >+ /* Zoom in */ >+ text-decoration: none; >+ padding-left: 27px; >+} >+a.download { >+ background-position: -5px -348px; >+ /* Download */ >+ padding-left: 20px; >+ text-decoration: none; >+} >+a.editshelf { >+ background-position: 2px -348px; >+ /* List edit */ >+ padding-left: 26px; >+ text-decoration: none; >+} >+a.empty { >+ background-position: 2px -598px; >+ /* Trash */ >+ text-decoration: none; >+ padding-left: 30px; >+} >+a.hide { >+ background-position: -3px -814px; >+ /* Close */ >+ text-decoration: none; >+ padding-left: 26px; >+} >+a.highlight_toggle { >+ background-position: -5px -841px; >+ /* Highlight */ >+ display: none; >+ padding-left: 35px; >+} >+a.hold, >+input.hold { >+ background-position: -2px -453px; >+ /* Toolbar place hold */ >+ text-decoration: none; >+ padding-left: 23px; >+} >+a.hold.disabled, >+input.hold.disabled { >+ background-position: -5px -621px; >+ /* Place hold disabled */ >+} >+a.incart { >+ background-position: -5px -265px; >+ /* Cart */ >+ color: #666; >+ padding-left: 35px; >+} >+a.new { >+ background-image: url("../images/sprite.png"); >+ /* New */ >+ background-position: -4px -922px; >+ padding-left: 23px; >+ text-decoration: none; >+} >+a.print-small { >+ background-position: 0px -423px; >+ /* Toolbar print */ >+ text-decoration: none; >+ padding-left: 30px; >+} >+a.print-large { >+ background-position: -5px -186px; >+ /* Toolbar print */ >+ text-decoration: none; >+ padding-left: 35px; >+} >+a.removeitems, >+a.deleteshelf { >+ background-position: 2px -690px; >+ /* Delete */ >+ text-decoration: none; >+ padding-left: 25px; >+} >+a.removeitems.disabled, >+a.deleteshelf.disabled { >+ background-position: 2px -712px; >+ /* Delete disabled */ >+} >+a.reserve { >+ background-position: -6px -144px; >+ /* Place hold */ >+ padding-left: 35px; >+} >+a.send { >+ background-position: 2px -386px; >+ /* Email */ >+ text-decoration: none; >+ padding-left: 28px; >+} >+a.tag_add { >+ background-position: 3px -1111px; >+ /* Tag results */ >+ padding-left: 27px; >+ text-decoration: none; >+} >+input.hold { >+ background-color: transparent; >+ border: 0; >+ color: #0076B2; >+ font-weight: bold; >+} >+input.editshelf { >+ background-color: transparent; >+ background-position: 2px -736px; >+ /* List edit */ >+ border: 0; >+ color: #006699; >+ cursor: pointer; >+ filter: none; >+ font-size: 100%; >+ padding-left: 29px; >+ text-decoration: none; >+} >+.newshelf { >+ background-position: 2px -764px; >+ /* List new */ >+ border: 0; >+ color: #006699; >+ cursor: pointer; >+ filter: none; >+ font-size: 100%; >+ padding-left: 28px; >+ text-decoration: none; >+} >+.newshelf.disabled { >+ background-position: -4px -791px; >+ /* List new disabled */ >+} >+.deleteshelf { >+ background-color: transparent; >+ background-position: 2px -690px; >+ /* Delete */ >+ border: 0; >+ color: #006699; >+ cursor: pointer; >+ filter: none; >+ font-size: 100%; >+ padding-left: 25px; >+ text-decoration: none; >+} >+.links a { >+ font-weight: bold; >+} >+.deleteshelf:hover { >+ color: #990033; >+} >+.editshelf:active, >+.deleteshelf:active { >+ border: 0; >+} >+#tagslist li { >+ display: inline; >+} >+#login4tags { >+ background-image: url("../images/sprite.png"); >+ /* Tag results disabled */ >+ background-position: -6px -1130px; >+ background-repeat: no-repeat; >+ padding-left: 20px; >+ text-decoration: none; >+} >+.tag_results_input { >+ margin-left: 1em; >+ padding: 0.3em; >+ font-size: 12px; >+} >+.tag_results_input input[type="text"] { >+ font-size: inherit; >+ margin: 0; >+ padding: 0; >+} >+.tag_results_input label { >+ display: inline; >+} >+.tagsinput input[type="text"] { >+ font-size: inherit; >+ margin: 0; >+ padding: 0; >+} >+.tagsinput label { >+ display: inline; >+} >+.branch-info-tooltip { >+ display: none; >+} >+#social_networks a { >+ background: transparent url("../images/social-sprite.png") no-repeat; >+ display: block; >+ height: 20px !important; >+ width: 20px; >+ text-indent: -999em; >+} >+#social_networks span { >+ color: #274D7F; >+ display: block; >+ float: left; >+ font-size: 85%; >+ font-weight: bold; >+ line-height: 2em; >+ margin: .5em 0 .5em .5em !important; >+} >+#social_networks div { >+ float: left !important; >+ margin: .5em 0 .5em .2em !important; >+} >+#social_networks #facebook { >+ background-position: -7px -35px; >+} >+#social_networks #twitter { >+ background-position: -7px -5px; >+} >+#social_networks #linkedin { >+ background-position: -7px -95px; >+} >+#social_networks #delicious { >+ background-position: -7px -66px; >+} >+#social_networks #email { >+ background-position: -7px -126px; >+} >+#marc td, >+#marc th { >+ background-color: transparent; >+ border: 0; >+ padding: 3px 5px; >+ text-align: left; >+} >+#marc td:first-child { >+ text-indent: 2em; >+} >+#marc p { >+ padding-bottom: .6em; >+} >+#marc p .label { >+ font-weight: bold; >+} >+#marc ul { >+ padding-bottom: .6em; >+} >+#marc .results_summary { >+ clear: left; >+} >+#marc .results_summary ul { >+ display: inline; >+ float: none; >+ clear: none; >+ margin: 0; >+ padding: 0; >+ list-style: none; >+} >+#marc .results_summary li { >+ display: inline; >+} >+#items, >+#items td #items th { >+ border: 1px solid #EEE; >+ font-size: 90%; >+} >+#plainmarc table { >+ border: 0; >+ margin: .7em 0 0 0; >+ font-family: monospace; >+ font-size: 95%; >+} >+#plainmarc th { >+ background-color: #FFF; >+ border: 0; >+ white-space: nowrap; >+ text-align: left; >+ vertical-align: top; >+ padding: 2px; >+} >+#plainmarc td { >+ border: 0; >+ padding: 2px; >+ vertical-align: top; >+} >+#renewcontrols { >+ float: right; >+ font-size: 66%; >+} >+#renewcontrols a { >+ background-repeat: no-repeat; >+ text-decoration: none; >+ padding: .1em .4em; >+ padding-left: 18px; >+} >+#renewselected_link { >+ background-image: url("../images/sprite.png"); >+ background-position: -5px -986px; >+ background-repeat: no-repeat; >+} >+#renewall_link { >+ background-image: url("../images/sprite.png"); >+ background-position: -8px -967px; >+ background-repeat: no-repeat; >+} >+.authref { >+ text-indent: 2em; >+} >+.authref .label { >+ font-style: italic; >+} >+.authstanza { >+ margin-top: 1em; >+} >+.authstanzaheading { >+ font-weight: bold; >+} >+.authorizedheading { >+ font-weight: bold; >+} >+.authstanza li { >+ margin-left: 0.5em; >+} >+.authres_notes, >+.authres_seealso, >+.authres_otherscript { >+ padding-top: .5em; >+} >+.authres_notes { >+ font-style: italic; >+} >+#didyoumean { >+ background-color: #EEE; >+ border: 1px solid #E8E8E8; >+ margin: 0 0 0.5em; >+ text-align: left; >+ padding: 0.5em; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+} >+.suggestionlabel { >+ font-weight: bold; >+} >+.searchsuggestion { >+ padding: 0.2em 0.5em; >+ white-space: nowrap; >+ display: inline-block; >+} >+.authlink { >+ padding-left: 0.25em; >+} >+#hierarchies a { >+ font-weight: normal; >+ text-decoration: underline; >+ color: #069; >+} >+#hierarchies a:hover { >+ color: #990033; >+} >+#top-pages { >+ margin: 0 0 0.5em; >+} >+.dropdown-menu > li > a { >+ font-size: 90%; >+} >+a.listmenulink:link, >+a.listmenulink:visited { >+ color: #0076B2; >+ font-weight: bold; >+} >+a.listmenulink:hover, >+a.listmenulink:active { >+ color: #FFF; >+ font-weight: bold; >+} >+#cartDetails, >+#cartUpdate, >+#holdDetails, >+#listsDetails { >+ background-color: #FFF; >+ border: 1px solid rgba(0, 0, 0, 0.2); >+ border-radius: 6px 6px 6px 6px; >+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); >+ color: black; >+ display: none; >+ font-size: 90%; >+ margin: 0; >+ padding: 8px 20px; >+ text-align: center; >+ width: 180px; >+ z-index: 2; >+} >+#cartmenulink { >+ white-space: nowrap; >+} >+#search-facets, >+#menu { >+ border: 1px solid #D2D2CF; >+ -webkit-border-radius: 7px; >+ -moz-border-radius: 7px; >+ border-radius: 7px; >+} >+#search-facets ul, >+#menu ul { >+ margin: 0; >+ padding: .3em; >+} >+#search-facets form, >+#menu form { >+ margin: 0; >+} >+#search-facets h4, >+#menu h4 { >+ font-size: 90%; >+ margin: 0 0 .6em 0; >+ text-align: center; >+} >+#search-facets h4 a, >+#menu h4 a { >+ background-color: #F2F2EF; >+ border-radius: 8px 8px 0 0; >+ border-bottom: 1px solid #D8D8D8; >+ display: block; >+ font-weight: bold; >+ padding: .7em .2em; >+ text-decoration: none; >+} >+#search-facets li, >+#menu li { >+ font-size: 90%; >+ font-weight: bold; >+ list-style-type: none; >+} >+#search-facets li li, >+#menu li li { >+ font-weight: normal; >+ font-size: 95%; >+ line-height: 125%; >+ margin-bottom: 2px; >+ padding: .1em .2em; >+} >+#search-facets li.showmore a, >+#menu li.showmore a { >+ font-weight: bold; >+ text-indent: 1em; >+} >+#search-facets a, >+#menu a { >+ font-weight: normal; >+ text-decoration: underline; >+} >+#menu { >+ font-size: 94%; >+} >+#menu li { >+ list-style-type: none; >+} >+#menu li a { >+ background: #eeeeee; >+ text-decoration: none; >+ display: block; >+ border: 1px solid #D8D8D8; >+ border-radius: 5px 0 0 5px; >+ border-bottom-color: #999; >+ font-size: 111%; >+ padding: .4em .6em; >+ margin: .4em 0; >+ margin-right: -1px; >+} >+#menu li a:hover { >+ background: #eaeef5; >+} >+#menu li.active a { >+ background-color: #FFF; >+ background-image: none; >+ border-right-width: 0; >+ font-weight: bold; >+} >+#menu li.active a:hover { >+ background-color: #fff; >+} >+#menu h4 { >+ display: none; >+} >+#addto { >+ max-width: 10em; >+} >+/* Search results add to cart (lists disabled) */ >+.addto a.addtocart { >+ background-image: url("../images/sprite.png"); >+ /* Cart */ >+ background-position: -5px -266px; >+ background-repeat: no-repeat; >+ text-decoration: none; >+ padding-left: 33px; >+} >+.searchresults p { >+ margin: 0; >+ padding: 0 0 .6em 0; >+} >+.searchresults p.details { >+ color: #979797; >+} >+.searchresults a.highlight_toggle { >+ background-image: url("../images/sprite.png"); >+ /* Highlight */ >+ background-position: -11px -841px; >+ background-repeat: no-repeat; >+ display: none; >+ font-weight: normal; >+ padding: 0 10px 0 21px; >+} >+.searchresults .commentline { >+ background-color: #ffffcc; >+ background-color: rgba(255, 255, 204, 0.4); >+ border: 1px solid #CCC; >+ display: inline-block; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+ -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2); >+ margin: .3em; >+ padding: .4em; >+} >+.searchresults .commentline.yours { >+ background-color: #effed5; >+ background-color: rgba(239, 254, 213, 0.4); >+} >+.commentline .avatar { >+ float: right; >+ padding-left: .5em; >+} >+/* style for search terms in catalogsearch */ >+.term { >+ /* color : blue; */ >+ color: #990000; >+ background-color: #FFFFCC; >+} >+/* style for shelving location in catalogsearch */ >+.shelvingloc { >+ display: block; >+ font-style: italic; >+} >+#CheckAll, >+#CheckNone { >+ font-weight: normal; >+ margin: 0 .5em; >+ text-decoration: underline; >+} >+span.sep { >+ color: #888; >+ padding: 0 .2em 0 .5em; >+ text-shadow: 1px 1px 0 #FFF; >+} >+/* style for PM-generated pagination bar */ >+.pages span:first-child, >+.pages a:first-child { >+ border-width: 1px 1px 1px 1px; >+ border-bottom-left-radius: 3px; >+ border-top-left-radius: 3px; >+} >+.pages span:last-child, >+.pages a:last-child { >+ border-width: 1px 1px 1px 0; >+ border-bottom-right-radius: 3px; >+ border-top-right-radius: 3px; >+} >+.pages .inactive, >+.pages .currentPage, >+.pages a { >+ -moz-border-bottom-colors: none; >+ -moz-border-left-colors: none; >+ -moz-border-right-colors: none; >+ -moz-border-top-colors: none; >+ background-color: #FFFFFF; >+ border-color: #DDDDDD; >+ border-image: none; >+ border-style: solid; >+ border-width: 1px 1px 1px 0; >+ float: left; >+ font-size: 11.9px; >+ line-height: 20px; >+ padding: 4px 12px; >+ text-decoration: none; >+} >+.pages .inactive { >+ background-color: #F5F5F5; >+} >+.pages a[rel='last'] { >+ border-bottom-right-radius: 3px; >+ border-top-right-radius: 3px; >+} >+.hold-message { >+ background-color: #FFF0B1; >+ display: inline-block; >+ margin: 0.5em; >+ padding: 0.2em 0.5em; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+} >+.reserve_date, >+.expiration_date { >+ white-space: nowrap; >+} >+.close { >+ color: #0088CC; >+ position: inherit; >+ top: auto; >+ right: auto; >+ filter: none; >+ float: none; >+ font-size: inherit; >+ font-weight: normal; >+ opacity: inherit; >+ text-shadow: none; >+} >+.close:hover { >+ color: #538200; >+ filter: inherit; >+ font-size: inherit; >+ opacity: inherit; >+} >+/* Redefine a new style for Bootstrap's class "close" since we use that already */ >+/* Use <a class="closebtn" href="#">×</a> */ >+.alert .closebtn { >+ position: relative; >+ top: -2px; >+ right: -21px; >+ line-height: 20px; >+} >+.modal-header .closebtn { >+ margin-top: 2px; >+} >+.closebtn { >+ float: right; >+ font-size: 20px; >+ font-weight: bold; >+ line-height: 20px; >+ color: #000000; >+ text-shadow: 0 1px 0 #ffffff; >+ opacity: 0.2; >+ filter: alpha(opacity=20); >+} >+.closebtn:hover { >+ color: #000000; >+ text-decoration: none; >+ cursor: pointer; >+ opacity: 0.4; >+ filter: alpha(opacity=40); >+} >+button.closebtn { >+ padding: 0; >+ cursor: pointer; >+ background: transparent; >+ border: 0; >+ -webkit-appearance: none; >+} >+.btn-group label, >+.btn-group select { >+ font-size: 13px; >+} >+.span2 select { >+ width: 100%; >+} >+.popup .main { >+ font-size: 90%; >+ padding: 0 1em; >+} >+.popup legend { >+ line-height: 1.5em; >+ margin-bottom: .5em; >+} >+.available { >+ color: #006600; >+} >+.waiting, >+.intransit, >+.notforloan, >+.checkedout, >+.lost, >+.notonhold { >+ display: block; >+} >+.notforloan { >+ color: #900; >+} >+.lost { >+ color: #666; >+} >+.suggestion { >+ background-color: #EEEEEB; >+ border: 1px solid #DDDED3; >+ margin: 1em auto; >+ padding: .5em; >+ width: 35%; >+ -webkit-border-radius: 3px; >+ -moz-border-radius: 3px; >+ border-radius: 3px; >+} >+.librarypulldown .transl1 { >+ width: auto; >+} >+.nolibrarypulldown { >+ width: 68%; >+} >+.nolibrarypulldown .transl1 { >+ width: 87%; >+} >+#opac-main-search select { >+ width: auto; >+ max-width: 12em; >+} >+#logo { >+ background: transparent url("../images/koha-logo-navbar.png") no-repeat scroll 0%; >+ border: 0; >+ float: left !important; >+ margin: 0; >+ padding: 0; >+ width: 100px; >+} >+#logo a { >+ border: 0; >+ cursor: pointer; >+ display: block; >+ height: 0px !important; >+ margin: 0; >+ overflow: hidden; >+ padding: 40px 0 0; >+ text-decoration: none; >+ width: 100px; >+} >+#user-menu-trigger { >+ display: none; >+} >+#user-menu-trigger .icon-user { >+ background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat; >+ background-position: -168px 0; >+ background-repeat: no-repeat; >+ height: 14px; >+ line-height: 14px; >+ margin: 12px 0 0; >+ vertical-align: text-top; >+ width: 14px; >+} >+#user-menu-trigger .caret { >+ border-bottom-color: #999999; >+ border-top-color: #999999; >+ margin-top: 18px; >+} >+/* Class to be added to toolbar when it starts being fixed at the top of the screen*/ >+.floating { >+ -webkit-box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4); >+ box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4); >+ margin-top: 0; >+} >+.tdlabel { >+ font-weight: bold; >+ display: none; >+} >+td img { >+ max-width: none; >+} >+#ulactioncontainer { >+ min-width: 16em; >+} >+.notesrow label { >+ font-weight: bold; >+} >+.notesrow span { >+ display: block; >+} >+.thumbnail-shelfbrowser span { >+ margin: 0px auto; >+} >+.dropdown-menu > li > a.menu-inactive:hover { >+ background: #FFF none; >+ color: #000; >+} >+.table .sorting_asc { >+ padding-right: 19px; >+ background: url("../images/asc.gif") no-repeat scroll right center #ecede6; >+} >+.table .sorting_desc { >+ padding-right: 19px; >+ background: url("../images/desc.gif") no-repeat scroll right center #ecede6; >+} >+.table .sorting { >+ padding-right: 19px; >+ background: url("../images/ascdesc.gif") no-repeat scroll right center #ecede6; >+} >+.table .nosort, >+.table .nosort.sorting_asc, >+.table .nosort.sorting_desc, >+.table .nosort.sorting { >+ padding-right: 19px; >+ background: #ECEDE6 none; >+} >+.tags ul { >+ display: inline; >+ list-style: none; >+ margin-left: 0; >+} >+.tags ul li { >+ display: inline; >+} >+.coverimages { >+ float: right; >+} >+#i18nMenu { >+ margin-left: 1em; >+} >+#i18nMenu li { >+ font-size: 85%; >+} >+#i18nMenu li li { >+ font-size: 100%; >+} >+#i18nMenu li li > a { >+ font-size: 100%; >+} >+#i18nMenu li li > a:hover { >+ color: #FFF; >+} >+#i18nMenu li a { >+ color: #0076b2; >+} >+#i18nMenu .dropdown-menu li p { >+ clear: both; >+ display: block; >+ font-weight: normal; >+ line-height: 20px; >+ padding: 3px 20px; >+ white-space: nowrap; >+} >+#subjectsList label, >+#authorSearch label { >+ display: inline; >+ vertical-align: middle; >+} >+#subjectsList ul, >+#authorSearch ul { >+ border-bottom: 1px solid #EEE; >+ list-style-type: none; >+ margin: 0; >+ padding: .6em 0; >+} >+#subjectsList li, >+#authorSearch li { >+ list-style-type: none; >+ margin: 0; >+ padding: 0; >+} >+#overdrive-results, >+#pazpar2-results { >+ font-weight: bold; >+ padding-left: 1em; >+} >+.throbber { >+ vertical-align: middle; >+} >+#overdrive-results-list .star-rating-control { >+ display: block; >+ overflow: auto; >+} >+#shelfbrowser table { >+ margin: 0; >+} >+#shelfbrowser table, >+#shelfbrowser td, >+#shelfbrowser th { >+ border: 0; >+ font-size: 90%; >+ text-align: center; >+} >+#shelfbrowser td, >+#shelfbrowser th { >+ padding: 3px 5px; >+ width: 20%; >+} >+#shelfbrowser a { >+ display: block; >+ font-size: 110%; >+ font-weight: bold; >+ text-decoration: none; >+} >+#shelfbrowser #browser_next, >+#shelfbrowser #browser_previous { >+ background-image: url("../images/sprite.png"); >+ background-repeat: no-repeat; >+ width: 16px; >+} >+#shelfbrowser #browser_next a, >+#shelfbrowser #browser_previous a { >+ cursor: pointer; >+ display: block; >+ height: 0 !important; >+ margin: 0; >+ overflow: hidden; >+ padding: 50px 0 0; >+ text-decoration: none; >+ width: 16px; >+} >+#shelfbrowser #browser_previous { >+ background-position: -9px -1007px; >+} >+#shelfbrowser #browser_next { >+ background-position: -9px -1057px; >+} >+#holds { >+ margin: 0 auto; >+ max-width: 800px; >+} >+.holdrow { >+ clear: both; >+ padding: 0 1em 1em 1em; >+ border-bottom: 1px solid #CCC; >+ margin-bottom: .5em; >+} >+.holdrow fieldset { >+ border: 0; >+ margin: 0; >+ float: none; >+} >+.holdrow fieldset .label { >+ font-size: 14px; >+} >+.holdrow label { >+ display: inline; >+} >+.hold-options { >+ clear: both; >+} >+.toggle-hold-options { >+ background-color: #eee; >+ clear: both; >+ display: block; >+ font-weight: bold; >+ margin: 1em 0; >+ padding: .5em; >+} >+.copiesrow { >+ clear: both; >+} >+#idreambooksreadometer { >+ float: right; >+} >+a.idreambooksrating { >+ font-size: 30px; >+ color: #29ADE4; >+ padding-left: 85px; >+ line-height: 30px; >+ text-decoration: none; >+} >+.idreambookslegend { >+ font-size: small; >+} >+a.reviewlink, >+a.reviewlink:visited { >+ text-decoration: none; >+ color: black; >+ font-weight: normal; >+} >+.idreambookssummary a { >+ color: #707070; >+ text-decoration: none; >+} >+.idreambookssummary img, >+.idbresult img { >+ vertical-align: middle; >+} >+.idbresult { >+ color: #29ADE4; >+ text-align: center; >+ margin: 0.5em; >+ padding: 0.5em; >+} >+.idbresult a, >+.idbresult a:visited { >+ text-decoration: none; >+ color: #29ADE4; >+} >+.idbresult img { >+ padding-right: 6px; >+} >+.js-show { >+ display: none; >+} >+.modal-nojs .modal-header, >+.modal-nojs .modal-footer { >+ display: none; >+} >+@media only screen and (min-width: 0px) and (max-width: 304px) { >+ /* Screens bewteen 0 and 304 pixels wide */ >+ #oh:after { >+ content: "(min-width: 0px) and (max-width: 304px)"; >+ } >+ input, >+ select, >+ textarea { >+ width: auto; >+ max-width: 11em; >+ } >+} >+@media only screen and (min-width: 0px) and (max-width: 390px) { >+ /* Screens bewteen 0 and 390 pixels wide */ >+ #oh:after { >+ content: "(min-width: 0px) and (max-width: 390px)"; >+ } >+ .ui-tabs .ui-tabs-nav li a, >+ .statictabs li a { >+ padding: .1em .5em; >+ } >+ #views { >+ border: 0; >+ padding: 0; >+ margin: 0; >+ } >+ .view { >+ padding: 0; >+ } >+ .view a, >+ .view span { >+ border: 1px solid #C9C9C9; >+ -webkit-border-radius: 4px; >+ -moz-border-radius: 4px; >+ border-radius: 4px; >+ font-size: 80%; >+ padding: 0.3em 0.4em 4px 26px; >+ } >+ .input-fluid { >+ width: 90%; >+ } >+} >+@media only screen and (min-width: 305px) and (max-width: 341px) { >+ /* Screens bewteen 305 and 341 pixels wide */ >+ #oh:after { >+ content: "(min-width: 305px) and (max-width: 341px)"; >+ } >+} >+@media only screen and (min-width: 342px) and (max-width: 479px) { >+ /* Screens bewteen 342 and 479 pixels wide */ >+ #oh:after { >+ content: "(min-width: 342px) and (max-width: 479px)"; >+ } >+ .input-fluid { >+ width: 75%; >+ } >+} >+/* Override Bootstrap Responsive CSS fixed navbar */ >+@media (max-width: 979px) { >+ .navbar-fixed-top, >+ .navbar-fixed-bottom { >+ position: fixed; >+ margin-left: 0px; >+ margin-right: 0px; >+ } >+} >+@media only screen and (max-width: 608px) { >+ /* Screens below 608 pixels wide */ >+ fieldset.rows label { >+ display: block; >+ float: none; >+ text-align: left; >+ } >+ fieldset.rows li { >+ padding-bottom: .5em; >+ } >+ fieldset.rows ol { >+ margin-left: 0; >+ } >+ fieldset.rows .hint { >+ margin-left: 0; >+ } >+ body { >+ padding: 0; >+ } >+ .tdlabel { >+ display: inline; >+ } >+ .navbar-fixed-top, >+ .navbar-static-top { >+ margin: 0; >+ } >+ .navbar-inner { >+ padding: 0; >+ } >+ .checkall, >+ .clearall, >+ .highlight_controls, >+ #selections-toolbar, >+ .selectcol, >+ .list-actions, >+ #remove-selected { >+ display: none; >+ } >+ .table td.bibliocol { >+ padding-left: 1.3em; >+ } >+ .actions { >+ display: block; >+ } >+ .actions a, >+ .actions #login4tags { >+ background-color: #F2F2EF; >+ border: 1px solid #DDD; >+ -webkit-border-radius: 4px; >+ -moz-border-radius: 4px; >+ border-radius: 4px; >+ font-weight: bold; >+ display: block; >+ font-size: 120%; >+ margin: 2px 0; >+ } >+ .actions .label { >+ display: block; >+ font-weight: bold; >+ } >+ .actions #login4tags { >+ margin-right: 1em; >+ } >+ #opac-main-search button, >+ #opac-main-search input, >+ #opac-main-search select, >+ #opac-main-search .librarypulldown .transl1, >+ #opac-main-search .input-append { >+ display: block; >+ width: 97%; >+ max-width: 100%; >+ margin: .5em 0; >+ -webkit-border-radius: 5px; >+ -moz-border-radius: 5px; >+ border-radius: 5px; >+ } >+ #opac-main-search .input-append { >+ margin: 0; >+ width: 100%; >+ } >+ #opac-main-search .librarypulldown .transl1 { >+ width: 94.5%; >+ } >+ #toolbar .resort { >+ font-size: 14px; >+ max-width: 100%; >+ margin: .5em 0; >+ padding: 4px 6px; >+ -webkit-border-radius: 5px; >+ -moz-border-radius: 5px; >+ border-radius: 5px; >+ } >+ .mastheadsearch { >+ margin: 0; >+ -webkit-border-radius: 0px; >+ -moz-border-radius: 0px; >+ border-radius: 0px; >+ } >+ .main { >+ margin: .5em 0; >+ padding: 15px; >+ -webkit-border-radius: 0px; >+ -moz-border-radius: 0px; >+ border-radius: 0px; >+ } >+ .breadcrumb { >+ margin: 10px 0; >+ } >+ #moresearches { >+ text-align: center; >+ } >+ #searchsubmit { >+ font-weight: bold; >+ } >+ .ui-tabs-panel .item-thumbnail, >+ .tabs-container .item-thumbnail, >+ #topissues .item-thumbnail, >+ #usertags .item-thumbnail, >+ #usersuggestions .item-thumbnail { >+ margin: .5em 0 0 .5em; >+ } >+ .ui-tabs-panel .table-bordered, >+ .tabs-container .table-bordered, >+ #topissues .table-bordered, >+ #usertags .table-bordered, >+ #usersuggestions .table-bordered { >+ border: none; >+ } >+ .ui-tabs-panel .table th, >+ .tabs-container .table th, >+ #topissues .table th, >+ #usertags .table th, >+ #usersuggestions .table th, >+ .ui-tabs-panel .table thead, >+ .tabs-container .table thead, >+ #topissues .table thead, >+ #usertags .table thead, >+ #usersuggestions .table thead { >+ display: none; >+ } >+ .ui-tabs-panel .table td, >+ .tabs-container .table td, >+ #topissues .table td, >+ #usertags .table td, >+ #usersuggestions .table td { >+ border-right: 1px solid #dddddd; >+ border-left: 1px solid #dddddd; >+ border-top: 0; >+ display: block; >+ padding: .2em; >+ } >+ .ui-tabs-panel .table p, >+ .tabs-container .table p, >+ #topissues .table p, >+ #usertags .table p, >+ #usersuggestions .table p { >+ margin-bottom: 2px; >+ } >+ .ui-tabs-panel tr, >+ .tabs-container tr, >+ #topissues tr, >+ #usertags tr, >+ #usersuggestions tr { >+ display: block; >+ margin-bottom: .6em; >+ } >+ .ui-tabs-panel tr td:first-child, >+ .tabs-container tr td:first-child, >+ #topissues tr td:first-child, >+ #usertags tr td:first-child, >+ #usersuggestions tr td:first-child { >+ border-top: 1px solid #dddddd; >+ border-radius: 5px 5px 0 0; >+ } >+ .ui-tabs-panel tr td:last-child, >+ .tabs-container tr td:last-child, >+ #topissues tr td:last-child, >+ #usertags tr td:last-child, >+ #usersuggestions tr td:last-child { >+ border-radius: 0 0 5px 5px; >+ border-bottom: 2px solid #CACACA; >+ } >+ .no-image { >+ display: none; >+ } >+} >+@media only screen and (max-width: 700px) { >+ /* Screens below 700 pixels wide */ >+ #opac-main-search label { >+ display: none; >+ } >+ #logo { >+ background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat; >+ background-position: 0 -24px; >+ margin: 14px 14px 0 14px; >+ width: 14px; >+ } >+ #logo a { >+ padding: 14px 0 0; >+ width: 14px; >+ } >+ #user-menu-trigger { >+ display: inline; >+ margin-right: 12px; >+ } >+ #members { >+ display: none; >+ clear: both; >+ } >+ #members li { >+ padding-right: 20px; >+ text-align: right; >+ border-bottom: 1px solid #555; >+ } >+ #members li:first-child { >+ border-top: 1px solid #555; >+ } >+ #members li:last-child { >+ border-bottom: none; >+ } >+ #members .nav { >+ float: none; >+ } >+ #members .nav.pull-right { >+ float: none; >+ } >+ #members .nav > li { >+ float: none; >+ } >+ #members .divider-vertical { >+ border: 0; >+ height: 0; >+ margin: 0; >+ } >+} >+@media only screen and (min-width: 480px) and (max-width: 608px) { >+ /* Screens between 480 and 608 pixels wide */ >+ #oh:after { >+ content: " Between 480 pixels and 608 pixels. "; >+ } >+ .input-fluid { >+ width: 75%; >+ } >+} >+@media only screen and (min-width: 608px) and (max-width: 767px) { >+ /* Screens between 608 and 767 pixels wide */ >+ #oh:after { >+ content: " Between 608 pixels and 767 pixels. "; >+ } >+ .main { >+ padding: 0.8em 20px; >+ } >+ .breadcrumb { >+ margin: 10px 0; >+ } >+ .navbar-static-bottom { >+ margin-left: -20px; >+ margin-right: -20px; >+ } >+} >+@media only screen and (max-width: 767px) { >+ /* Screens below 767 pixels wide */ >+ a.title { >+ font-size: 120%; >+ } >+ #userresults { >+ margin: 0 -20px; >+ } >+ .breadcrumb, >+ #top-pages, >+ .menu-collapse { >+ display: none; >+ } >+ #search-facets, >+ #menu { >+ margin-bottom: .5em; >+ } >+ #search-facets h4, >+ #menu h4 { >+ display: block; >+ margin: 0; >+ padding: 0; >+ } >+ #search-facets h4 a, >+ #menu h4 a { >+ -webkit-border-radius: 7px; >+ -moz-border-radius: 7px; >+ border-radius: 7px; >+ border-bottom: 0; >+ font-weight: normal; >+ padding: .7em .2em; >+ } >+ #search-facets ul, >+ #menu ul { >+ padding: 0; >+ } >+ #menu li a { >+ -webkit-border-radius: 0px; >+ -moz-border-radius: 0px; >+ border-radius: 0px; >+ border: 0; >+ display: block; >+ font-size: 120%; >+ text-decoration: none; >+ border-bottom: 1px solid #D8D8D8; >+ margin: 0; >+ } >+ #menu li.active a { >+ border-top: 1px solid #D8D8D8; >+ border-right-width: 1px; >+ } >+ #menu li:last-child a { >+ -webkit-border-radius: 0 0 7px 7px; >+ -moz-border-radius: 0 0 7px 7px; >+ border-radius: 0 0 7px 7px; >+ } >+ #search-facets li { >+ padding: .4em; >+ } >+ #search-facets h5 { >+ margin: .2em; >+ } >+ #menu h4 a.menu-open, >+ #search-facets h4 a.menu-open { >+ -webkit-border-radius: 7px 7px 0 0; >+ -moz-border-radius: 7px 7px 0 0; >+ border-radius: 7px 7px 0 0; >+ border-bottom: 1px solid #D8D8D8; >+ } >+} >+@media only screen and (max-width: 800px) { >+ /* Screens below 800 pixels wide */ >+ .cartlabel, >+ .listslabel { >+ display: none; >+ } >+ .navbar .divider-vertical { >+ margin: 0 2px; >+ } >+ .navbar #members .divider-vertical { >+ margin: 0 9px; >+ } >+} >+@media only screen and (min-width: 768px) { >+ /* Screens above 768 pixels wide */ >+ .main { >+ margin-left: 20px; >+ margin-right: 20px; >+ } >+ #menu { >+ border: 0; >+ -webkit-border-radius: 0px; >+ -moz-border-radius: 0px; >+ border-radius: 0px; >+ border-right: 1px solid #D8D8D8; >+ } >+ #menu h4 { >+ display: none; >+ } >+ #menu ul { >+ padding: 1em 0 1em 0; >+ } >+} >+@media only screen and (min-width: 768px) and (max-width: 984px) { >+ /* Screens between 768 and 984 pixels wide */ >+ #oh:after { >+ content: " Between 768 and 984 pixels. "; >+ } >+ .librarypulldown .transl1 { >+ width: 38%; >+ } >+} >+@media only screen and (max-width: 984px) { >+ /* Screens up to 984 pixels wide */ >+} >+@media only screen and (min-width: 984px) { >+ /* Screens above 969 pixels wide */ >+ #oh:after { >+ content: " Above 984 pixels. "; >+ } >+ .librarypulldown .transl1 { >+ width: 53%; >+ } >+} >+@media only screen and (max-width: 1040px) { >+ .pg_menu li a { >+ float: none; >+ text-align: left; >+ } >+ .pg_menu li.back_results a { >+ border: 1px solid #D0D0D0; >+ border-width: 1px 0 1px 0; >+ } >+ #ulactioncontainer { >+ min-width: 0; >+ } >+} >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-external-search.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-external-search.tt >new file mode 100644 >index 0000000..9229423 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-external-search.tt >@@ -0,0 +1,249 @@ >+[% USE Koha %] >+[% INCLUDE 'doc-head-open.inc' %] >+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › External search for '[% q | html %]' >+[% INCLUDE 'doc-head-close.inc' %] >+[% BLOCK cssinclude %] >+<style> >+.actions a.addtocart { >+ display: inline; >+} >+#targets-facet label { >+ display: inline; >+ font-size: inherit; >+} >+</style> >+[% END %] >+</head> >+<body id="results" class="scrollto"> >+[% INCLUDE 'masthead.inc' %] >+ >+ <div class="main"> >+ <ul class="breadcrumb"> >+ <li><a href="/cgi-bin/koha/opac-main.pl">Home</a> <span class="divider">›</span></li> >+ <li> >+ <a href="#">External search for '[% q | html %]'</a> >+ </li> >+ </ul> >+ >+ <div id="maincontent" class="container-fluid"> >+ <div class="row-fluid"> >+ <div class="span3"> >+ <div id="facetcontainer"> >+ <div id="search-facets"> >+ <h4><a href="#" class="menu-collapse-toggle">Refine your search</a></h4> >+ <ul class="menu-collapse"> >+ <li id="targets-facet"> >+ Targets >+ <ul> >+ [% FOREACH target = external_search_targets %] >+ <li> >+ <input data-url="[% target.host %]:[% target.port %]/[% target.db %]" type="checkbox" id="target-[% loop.index %]" checked /> >+ <label for="target-[% loop.index %]">[% target.name %] >+ </li> >+ [% END %] >+ </ul> >+ </li> >+ </ul> >+ </div> >+ </div> >+ </div> >+ >+ <div class="span9 maincontent"> >+ <p id="numresults"></p> >+ <div id="top-pages"> >+ <div class="pagination pagination-small"><ul></ul></div> >+ </div> >+ <div id="searchresults"> >+ <table class="table table-striped" id="results"> >+ <tbody> >+ </tbody> >+ </table> >+ </div> >+ <div id="bottom-pages"> >+ <div class="pagination pagination-small"><ul></ul></div> >+ </div> >+ </div> >+ </div> >+ </div> >+ </div> >+</div> >+ >+</div> >+ >+<div id="modal-overlay" class="modal hide fade"></div> >+[% INCLUDE 'opac-bottom.inc' %] >+[% BLOCK jsinclude %] >+<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script> >+<script type="text/javascript"> >+var querystring = "[% q |replace( "'", "\'" ) |replace( '\n', '\\n' ) |replace( '\r', '\\r' ) |html %]"; >+var results_per_page = [% OPACnumSearchResults %]; >+KOHA.ExternalSearch.targets = { >+ [% FOREACH target IN external_search_targets %] >+ '[% target.host %]:[% target.port %]/[% target.db %]': { >+ name: '[% target.name %]', >+ syntax: '[% target.syntax %]', >+ }, >+ [% END %] >+}; >+ >+var xsltResultStylesheets = { >+ [% FOREACH stylesheet IN xslt_result_stylesheets %] >+ '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ), >+ [% END %] >+}; >+ >+var xsltDetailStylesheets = { >+ [% FOREACH stylesheet IN xslt_detail_stylesheets %] >+ '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ), >+ [% END %] >+}; >+ >+var recordCache = {}; >+var resultRenderCache = {}; >+ >+function showResult( syntax, recid ) { >+ if ( recordCache[ recid ] ) { >+ done( recordCache[ recid ] ); >+ } else { >+ KOHA.ExternalSearch.GetDetailedRecord( recid, function( record ) { >+ done( recordCache[ recid ] = record.xmlDoc ); >+ } ); >+ } >+ >+ function done( record ) { >+ xsltResultStylesheets[ syntax ].done( function( xslDoc ) { >+ var fragment = resultRenderCache[ recid ] = KOHA.TransformToFragment( record, xslDoc ); >+ var $tr = $( '#results tr' ).filter( function() { return $( this ).data( 'recid' ) == recid } ); >+ $tr.find( '.info' ).html( fragment ); >+ $tr.find( 'a' ).attr( 'href', '#' ).click( function() { >+ showDetail( syntax, recid ); >+ >+ return false; >+ } ); >+ } ); >+ } >+} >+ >+function showDetail( syntax, recid ) { >+ var record = recordCache[ recid ]; >+ >+ xsltDetailStylesheets[ syntax ].done( function( xslDoc ) { >+ var fragment = KOHA.TransformToFragment( record, xslDoc ); >+ >+ $( '#modal-overlay' ).html( fragment ).modal(); >+ } ); >+} >+ >+function search( offset, reset_search ) { >+ $( '#pazpar2-status' ).html( _("Searching external targets...") + '<img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" />' ); >+ >+ if ( reset_search ) { >+ KOHA.ExternalSearch.Search( querystring, results_per_page, callback ); >+ } else { >+ KOHA.ExternalSearch.Fetch( offset, callback ); >+ } >+ >+ function callback( data ) { >+ if ( data.error && data.error.code != 8 ) { // PAZPAR2_NO_TARGETS >+ $( '#pazpar2-status' ).html( '<strong class="unavailable">' + _("Error searching external targets.") + '</strong>' ); >+ return; >+ } >+ >+ if ( !data.total ) { >+ $( '#pazpar2-status' ).html( '<strong>' + _("No results found in the external targets.") + '</strong>' ); >+ return; >+ } >+ >+ $( '#results tbody' ).empty(); >+ >+ $( '#pazpar2-status' ).html( '<strong>' + _("Found __RESULTS__ results in __TARGETS__ external targets.").replace('__RESULTS__', data.total).replace('__TARGETS__', $( '#targets-facet input:checked' ).length ) ); >+ >+ for ( var i = 0; data.hits[i]; i++ ) { >+ var hit = data.hits[i]; >+ var results = []; >+ var recordSyntax = KOHA.ExternalSearch.targets[ hit.location[0]['@id'] ].syntax; >+ >+ results.push( '<tr>' ); >+ >+ results.push( '<td class="sourcecol">', hit.location[0]['@name'], '</td>' ); >+ >+ results.push( '<td class="info">' ); >+ >+ if ( resultRenderCache[ hit.recid[0] ] ) { >+ results.push( resultRenderCache[ hit.recid[0] ] ); >+ } else { >+ results.push( hit['md-work-title'] ? hit['md-work-title'][0] : _("Loading...") ); >+ showResult( recordSyntax, hit.recid[0] ); >+ } >+ >+ results.push( '</td>' ); >+ >+ results.push( '</tr>' ); >+ var $tr = $( results.join( '' ) ); >+ $tr.data( 'recid', hit.recid[0] ); >+ $( '#results tbody' ).append( $tr ); >+ >+ ( function( hit, recordSyntax ) { >+ $tr.find( 'a' ).attr( 'href', '#' ).click( function() { >+ showDetail( recordSyntax, hit.recid[0] ); >+ >+ return false; >+ } ); >+ } )( hit, recordSyntax ); >+ } >+ >+ var pages = []; >+ var cur_page = data.start / results_per_page; >+ var max_page = Math.floor( data.total / results_per_page ); >+ >+ if ( cur_page != 0 ) { >+ pages.push( '<li><a href="#" data-offset="' + (offset - results_per_page) + '"><< ' + _("Previous") + '</a></li>' ); >+ } >+ >+ for ( var page = Math.max( 0, cur_page - 9 ); page <= Math.min( max_page, cur_page + 9 ); page++ ) { >+ if ( page == cur_page ) { >+ pages.push( ' <li class="active"><a href="#">' + ( page + 1 ) + '</a></span>' ); >+ } else { >+ pages.push( ' <li><a href="#" data-offset="' + ( page * results_per_page ) + '">' + ( page + 1 ) + '</a></li>' ); >+ } >+ } >+ >+ if ( cur_page < max_page ) { >+ pages.push( ' <li><a href="#" data-offset="' + (offset + results_per_page) + '">' + _("Next") + ' >></a></li>' ); >+ } >+ >+ if ( pages.length > 1 ) $( '#top-pages, #bottom-pages' ).find( '.pagination ul' ).html( pages.join( '' ) ); >+ } >+} >+ >+$( document ).ready( function() { >+ $( '#numresults' ) >+ .append( ' ' ) >+ .append( '<span id="pazpar2-status"></span>' ); >+ >+ $( document ).on( 'click', 'a[data-offset]', function() { >+ search( $(this).data('offset') ); >+ return false; >+ }); >+ >+ var reSearchTimeout; >+ >+ $( '#targets-facet input' ).each( function() { >+ $( this ).click( function() { >+ KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked; >+ >+ if ( reSearchTimeout ) clearTimeout( reSearchTimeout ); >+ >+ reSearchTimeout = setTimeout( function() { >+ if ( $( '#targets-facet input:checked' ).length ) search( 0, true ); >+ }, 1000 ); >+ } ); >+ >+ KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked; >+ } ); >+ >+ search( 0, true ); >+} ); >+</script> >+[% END %] >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-results.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-results.tt >index 1328583..c4080d0 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-results.tt >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-results.tt >@@ -552,7 +552,12 @@ > [% IF ( OverDriveEnabled ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/js/overdrive.js"></script>[% END %] > <script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script> > [% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.highlight-3.js"></script> >-[% END %]<script type="text/javascript"> >+[% END %] >+[% IF ( Koha.Preference('OPACSearchExternalTargets') ) %] >+<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script> >+[% END %] >+<script type="text/javascript"> > //<![CDATA[ > [% IF ( Koha.Preference( 'opacuserlogin' ) == 1 ) && ( Koha.Preference( 'RequestOnOpac' ) == 1 ) %] > function holdMultiple() { >@@ -836,23 +841,61 @@ $(document).ready(function(){ > $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;}); > $("#highlight_toggle_off").show().click(function() {highlightOff();}); > [% END %] >+ >+ function StartExternalSearch(name, text) { >+ $( '#numresults' ) >+ .eq( 0 ) >+ .append( ' <span id="' + name + '-results">' + text + '... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' ); >+ } >+ function FailExternalSearch( name, text ) { >+ $( '#' + name + '-results' ).html( text ); >+ } >+ function FinishExternalSearch( name, text, numItems, url ) { >+ if ( numItems ) { >+ $( '#' + name + '-results' ).html( text.replace( '__LINK__', '<a href="' + url + '">' + _("__RESULTS__ results").replace( '__RESULTS__', numItems ) + '</a>' ) ); >+ } else { >+ $( '#' + name + '-results' ).remove(); >+ } >+ } >+ > [% IF ( OverDriveEnabled ) %] >- var $overdrive_results = $( '<span id="overdrive-results">' + _( 'Searching OverDrive...' ) + ' <img class="throbber" src="[% interface %]/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' ); >- $( '#numresults' ) .append( ' ' ) >- .append( $overdrive_results ); >+ StartExternalSearch( 'overdrive', _("Searching OverDrive") ); > KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) { > if ( data.error ) { >- $overdrive_results.html( _( 'Error searching OverDrive collection' ) ); >+ FailExternalSearch( 'overdrive', _("Error searching OverDrive collection") ); > return; > } > >- if ( data.totalItems ) { >- $overdrive_results.html( _( 'Found' ) + ' <a href="/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) + '">' + data.totalItems + ' ' + _( 'results' ) + '</a> ' + _( 'in OverDrive collection' ) ); >- } else { >- $overdrive_results.remove(); >- } >+ FinishExternalSearch( 'overdrive', _("Found __LINK__ in OverDrive collection"), data.totalItems, '/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) ); > } ); > [% END %] >+ >+ [% IF ( OPACSearchExternalTargets ) %] >+ KOHA.ExternalSearch.targets = { >+ [% FOREACH target IN external_search_targets %] >+ '[% target.host %]:[% target.port %]/[% target.db %]': { >+ id: '[% target.target_id %]', >+ name: '[% target.name %]', >+ syntax: '[% target.syntax %]', >+ }, >+ [% END %] >+ }; >+ var num_targets = 0; $.each( KOHA.ExternalSearch.targets, function() { num_targets++ } ); >+ var first_succeeded; >+ >+ if ( num_targets ) { >+ StartExternalSearch( 'pazpar2', _("Searching external targets") ); >+ KOHA.ExternalSearch.Search( querystring, 1, function( data ) { >+ if ( data.error ) { >+ if ( !first_succeeded ) FailExternalSearch( 'pazpar2', _("Error searching external targets") ); >+ return; >+ } >+ >+ first_succeeded = true; >+ FinishExternalSearch( 'pazpar2', _("Found __LINK__ in __TARGETS__ external targets").replace( '__TARGETS__', num_targets ), data.total, '/cgi-bin/koha/opac-external-search.pl?q=' + escape( querystring ) ); >+ } ); >+ } >+ [% END %] > [% END %] > > [% IF ( TagsInputEnabled && loggedinusername ) %] >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults.xsl b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults.xsl >index ea6af38..5b6734e 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults.xsl >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults.xsl >@@ -5,11 +5,13 @@ > xmlns:marc="http://www.loc.gov/MARC21/slim" > xmlns:items="http://www.koha-community.org/items" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns="http://www.w3.org/1999/xhtml" > exclude-result-prefixes="marc items"> > <xsl:import href="MARC21slimUtils.xsl"/> > <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/> > <xsl:key name="item-by-status" match="items:item" use="items:status"/> > <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/> >+ <xsl:param name="showAvailability" select="true()"/> > > <xsl:template match="/"> > <xsl:apply-templates/> >@@ -1027,6 +1029,7 @@ > </xsl:for-each> > </span> > </xsl:if> >+ <xsl:if test="$showAvailability"> > <span class="results_summary availability"> > <span class="label">Availability: </span> > <xsl:choose> >@@ -1035,7 +1038,8 @@ > <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]"> > <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/> > <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]"> >- <xsl:call-template select="marc:datafield[@tag=$AlternateHoldingsField]" name="subfieldSelect"> >+ <!-- Removed select="marc:datafield[@tag=$AlternateHoldingsField]" due to incompatibility with browser XSLT --> >+ <xsl:call-template name="subfieldSelect"> > <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param> > <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param> > </xsl:call-template> >@@ -1145,6 +1149,7 @@ > <xsl:text>). </xsl:text> </span> > </xsl:if> > </span> >+ </xsl:if> > <xsl:choose> > <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)"> > <span class="results_summary" id="location"> >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl >index 9599566..07fd266 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl >@@ -1,6 +1,6 @@ > <?xml version='1.0'?> > <!DOCTYPE stylesheet [<!ENTITY nbsp " " >]> >-<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> >+<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"> > <xsl:template name="datafield"> > <xsl:param name="tag"/> > <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param> >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl >index 5c9c88e..dd00614 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl >@@ -6,12 +6,14 @@ > xmlns:marc="http://www.loc.gov/MARC21/slim" > xmlns:items="http://www.koha-community.org/items" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns="http://www.w3.org/1999/xhtml" > exclude-result-prefixes="marc items"> > > <xsl:import href="UNIMARCslimUtils.xsl"/> > <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/> > <xsl:key name="item-by-status" match="items:item" use="items:status"/> > <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/> >+<xsl:param name="showAvailability" select="true()"/> > > <xsl:template match="/"> > <xsl:apply-templates/> >@@ -99,6 +101,7 @@ > > <xsl:call-template name="tag_215" /> > >+ <xsl:if test="$showAvailability"> > <span class="results_summary availability"> > <span class="label">Availability: </span> > <xsl:choose> >@@ -247,6 +250,7 @@ > </span> > </xsl:if> > </span> >+ </xsl:if> > > </xsl:template> > >diff --git a/koha-tmpl/opac-tmpl/bootstrap/less/opac.less b/koha-tmpl/opac-tmpl/bootstrap/less/opac.less >index 57bf132..b28199f 100644 >--- a/koha-tmpl/opac-tmpl/bootstrap/less/opac.less >+++ b/koha-tmpl/opac-tmpl/bootstrap/less/opac.less >@@ -2198,7 +2198,7 @@ td img { > } > > >-#overdrive-results { >+#overdrive-results, #pazpar2-results { > font-weight: bold; > padding-left: 1em; > } >diff --git a/koha-tmpl/opac-tmpl/ccsr/en/css/opac.css b/koha-tmpl/opac-tmpl/ccsr/en/css/opac.css >index 590cb19..7e59110 100644 >--- a/koha-tmpl/opac-tmpl/ccsr/en/css/opac.css >+++ b/koha-tmpl/opac-tmpl/ccsr/en/css/opac.css >@@ -1596,6 +1596,10 @@ strong em, em strong { > vertical-align: top; > width: 10px; > } >+.sourcecol { >+ vertical-align: top; >+ width: 100px; >+} > #container { > color : #000; > } >@@ -2865,3 +2869,15 @@ a.reviewlink,a.reviewlink:visited { > display: block; > overflow: auto; > } >+ >+#modal-overlay { >+ background-color: white; >+ border-radius: 5px; >+ max-width: 75%; >+ padding: 15px; >+} >+ >+#overdrive-results, #pazpar2-results { >+ font-weight: bold; >+ padding-left: 1em; >+} >diff --git a/koha-tmpl/opac-tmpl/ccsr/en/lib/jquery/plugins/jquery.lightbox_me.js b/koha-tmpl/opac-tmpl/ccsr/en/lib/jquery/plugins/jquery.lightbox_me.js >new file mode 100644 >index 0000000..effe8a6 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/ccsr/en/lib/jquery/plugins/jquery.lightbox_me.js >@@ -0,0 +1,254 @@ >+/* >+* $ lightbox_me >+* By: Buck Wilson >+* Version : 2.3 >+* >+* Licensed under the Apache License, Version 2.0 (the "License"); >+* you may not use this file except in compliance with the License. >+* You may obtain a copy of the License at >+* >+* http://www.apache.org/licenses/LICENSE-2.0 >+* >+* Unless required by applicable law or agreed to in writing, software >+* distributed under the License is distributed on an "AS IS" BASIS, >+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+* See the License for the specific language governing permissions and >+* limitations under the License. >+*/ >+ >+ >+(function($) { >+ >+ $.fn.lightbox_me = function(options) { >+ >+ return this.each(function() { >+ >+ var >+ opts = $.extend({}, $.fn.lightbox_me.defaults, options), >+ $overlay = $(), >+ $self = $(this), >+ $iframe = $('<iframe id="foo" style="z-index: ' + (opts.zIndex + 1) + ';border: none; margin: 0; padding: 0; position: absolute; width: 100%; height: 100%; top: 0; left: 0; filter: mask();"/>'), >+ ie6 = ($.browser.msie && $.browser.version < 7); >+ >+ if (opts.showOverlay) { >+ //check if there's an existing overlay, if so, make subequent ones clear >+ var $currentOverlays = $(".js_lb_overlay:visible"); >+ if ($currentOverlays.length > 0){ >+ $overlay = $('<div class="lb_overlay_clear js_lb_overlay"/>'); >+ } else { >+ $overlay = $('<div class="' + opts.classPrefix + '_overlay js_lb_overlay"/>'); >+ } >+ } >+ >+ /*---------------------------------------------------- >+ DOM Building >+ ---------------------------------------------------- */ >+ if (ie6) { >+ var src = /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'; >+ $iframe.attr('src', src); >+ $('body').append($iframe); >+ } // iframe shim for ie6, to hide select elements >+ $('body').append($self.hide()).append($overlay); >+ >+ >+ /*---------------------------------------------------- >+ Overlay CSS stuffs >+ ---------------------------------------------------- */ >+ >+ // set css of the overlay >+ if (opts.showOverlay) { >+ setOverlayHeight(); // pulled this into a function because it is called on window resize. >+ $overlay.css({ position: 'absolute', width: '100%', top: 0, left: 0, right: 0, bottom: 0, zIndex: (opts.zIndex + 2), display: 'none' }); >+ if (!$overlay.hasClass('lb_overlay_clear')){ >+ $overlay.css(opts.overlayCSS); >+ } >+ } >+ >+ /*---------------------------------------------------- >+ Animate it in. >+ ---------------------------------------------------- */ >+ // >+ if (opts.showOverlay) { >+ $overlay.fadeIn(opts.overlaySpeed, function() { >+ setSelfPosition(); >+ $self[opts.appearEffect](opts.lightboxSpeed, function() { setOverlayHeight(); setSelfPosition(); opts.onLoad()}); >+ }); >+ } else { >+ setSelfPosition(); >+ $self[opts.appearEffect](opts.lightboxSpeed, function() { opts.onLoad()}); >+ } >+ >+ /*---------------------------------------------------- >+ Hide parent if parent specified (parentLightbox should be jquery reference to any parent lightbox) >+ ---------------------------------------------------- */ >+ if (opts.parentLightbox) { >+ opts.parentLightbox.fadeOut(200); >+ } >+ >+ >+ /*---------------------------------------------------- >+ Bind Events >+ ---------------------------------------------------- */ >+ >+ $(window).resize(setOverlayHeight) >+ .resize(setSelfPosition) >+ .scroll(setSelfPosition); >+ >+ $(window).bind('keyup.lightbox_me', observeKeyPress); >+ >+ if (opts.closeClick) { >+ $overlay.click(function(e) { closeLightbox(); e.preventDefault; }); >+ } >+ $self.delegate(opts.closeSelector, "click", function(e) { >+ closeLightbox(); e.preventDefault(); >+ }); >+ $self.bind('close', closeLightbox); >+ $self.bind('reposition', setSelfPosition); >+ >+ >+ >+ /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- >+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ >+ >+ >+ /*---------------------------------------------------- >+ Private Functions >+ ---------------------------------------------------- */ >+ >+ /* Remove or hide all elements */ >+ function closeLightbox() { >+ var s = $self[0].style; >+ if (opts.destroyOnClose) { >+ $self.add($overlay).remove(); >+ } else { >+ $self.add($overlay).hide(); >+ } >+ >+ //show the hidden parent lightbox >+ if (opts.parentLightbox) { >+ opts.parentLightbox.fadeIn(200); >+ } >+ >+ $iframe.remove(); >+ >+ // clean up events. >+ $self.undelegate(opts.closeSelector, "click"); >+ >+ $(window).unbind('reposition', setOverlayHeight); >+ $(window).unbind('reposition', setSelfPosition); >+ $(window).unbind('scroll', setSelfPosition); >+ $(window).unbind('keyup.lightbox_me'); >+ if (ie6) >+ s.removeExpression('top'); >+ opts.onClose(); >+ } >+ >+ >+ /* Function to bind to the window to observe the escape/enter key press */ >+ function observeKeyPress(e) { >+ if((e.keyCode == 27 || (e.DOM_VK_ESCAPE == 27 && e.which==0)) && opts.closeEsc) closeLightbox(); >+ } >+ >+ >+ /* Set the height of the overlay >+ : if the document height is taller than the window, then set the overlay height to the document height. >+ : otherwise, just set overlay height: 100% >+ */ >+ function setOverlayHeight() { >+ if ($(window).height() < $(document).height()) { >+ $overlay.css({height: $(document).height() + 'px'}); >+ $iframe.css({height: $(document).height() + 'px'}); >+ } else { >+ $overlay.css({height: '100%'}); >+ if (ie6) { >+ $('html,body').css('height','100%'); >+ $iframe.css('height', '100%'); >+ } // ie6 hack for height: 100%; TODO: handle this in IE7 >+ } >+ } >+ >+ >+ /* Set the position of the modal'd window ($self) >+ : if $self is taller than the window, then make it absolutely positioned >+ : otherwise fixed >+ */ >+ function setSelfPosition() { >+ var s = $self[0].style; >+ >+ // reset CSS so width is re-calculated for margin-left CSS >+ $self.css({left: '50%', marginLeft: ($self.outerWidth() / 2) * -1, zIndex: (opts.zIndex + 3) }); >+ >+ >+ /* we have to get a little fancy when dealing with height, because lightbox_me >+ is just so fancy. >+ */ >+ >+ // if the height of $self is bigger than the window and self isn't already position absolute >+ if (($self.height() + 80 >= $(window).height()) && ($self.css('position') != 'absolute' || ie6)) { >+ >+ // we are going to make it positioned where the user can see it, but they can still scroll >+ // so the top offset is based on the user's scroll position. >+ var topOffset = $(document).scrollTop() + 40; >+ $self.css({position: 'absolute', top: topOffset + 'px', marginTop: 0}) >+ if (ie6) { >+ s.removeExpression('top'); >+ } >+ } else if ($self.height()+ 80 < $(window).height()) { >+ //if the height is less than the window height, then we're gonna make this thing position: fixed. >+ // in ie6 we're gonna fake it. >+ if (ie6) { >+ s.position = 'absolute'; >+ if (opts.centered) { >+ s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"') >+ s.marginTop = 0; >+ } else { >+ var top = (opts.modalCSS && opts.modalCSS.top) ? parseInt(opts.modalCSS.top) : 0; >+ s.setExpression('top', '((blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"') >+ } >+ } else { >+ if (opts.centered) { >+ $self.css({ position: 'fixed', top: '50%', marginTop: ($self.outerHeight() / 2) * -1}) >+ } else { >+ $self.css({ position: 'fixed'}).css(opts.modalCSS); >+ } >+ >+ } >+ } >+ } >+ >+ }); >+ >+ >+ >+ }; >+ >+ $.fn.lightbox_me.defaults = { >+ >+ // animation >+ appearEffect: "fadeIn", >+ appearEase: "", >+ overlaySpeed: 250, >+ lightboxSpeed: 300, >+ >+ // close >+ closeSelector: ".close", >+ closeClick: true, >+ closeEsc: true, >+ >+ // behavior >+ destroyOnClose: false, >+ showOverlay: true, >+ parentLightbox: false, >+ >+ // callbacks >+ onLoad: function() {}, >+ onClose: function() {}, >+ >+ // style >+ classPrefix: 'lb', >+ zIndex: 999, >+ centered: false, >+ modalCSS: {top: '40px'}, >+ overlayCSS: {background: 'black', opacity: .3} >+ } >+})(jQuery); >\ No newline at end of file >diff --git a/koha-tmpl/opac-tmpl/lib/koha/externalsearch.js b/koha-tmpl/opac-tmpl/lib/koha/externalsearch.js >new file mode 100644 >index 0000000..14a4d80 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/lib/koha/externalsearch.js >@@ -0,0 +1,104 @@ >+if ( typeof KOHA == "undefined" || !KOHA ) { >+ var KOHA = {}; >+} >+ >+KOHA.XSLTGet = ( function() { >+ // Horrible browser hack, but required due to the following hard-to-detect and long-unfixed bug: >+ // https://bugs.webkit.org/show_bug.cgi?id=60276 >+ var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); >+ var isSafari = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor); >+ >+ if ( !isChrome && !isSafari ) return $.get; >+ >+ return function( url ) { >+ var result = new jQuery.Deferred(); >+ var basepath = url.match( /(.*\/)*/ )[0]; >+ >+ $.get( url ).done( function( xslDoc ) { >+ var xslImports = xslDoc.getElementsByTagNameNS( 'http://www.w3.org/1999/XSL/Transform', 'import' ); >+ var importsRemaining = xslImports.length; >+ >+ if ( importsRemaining == 0 ) { >+ result.resolve( xslDoc ); >+ return; >+ } >+ >+ $.each( xslImports, function( i, importElem ) { >+ var path = $( importElem ).attr( 'href' ); >+ if ( !/^(\/|https?:)/.test( path ) ) path = basepath + path; >+ >+ KOHA.XSLTGet( path ).done( function( subDoc ) { >+ importsRemaining--; >+ $( importElem ).replaceWith( subDoc.documentElement.childNodes ); >+ >+ if ( importsRemaining == 0 ) result.resolve( xslDoc ); >+ } ).fail( function() { >+ importsRemaining = -1; >+ >+ result.reject(); >+ } ); >+ } ); >+ } ).fail( function() { >+ result.reject(); >+ } ); >+ >+ return result; >+ }; >+} )(); >+ >+KOHA.TransformToFragment = function( xmlDoc, xslDoc ) { >+ if ( window.XSLTProcessor ) { >+ var proc = new XSLTProcessor(); >+ proc.importStylesheet( xslDoc ); >+ proc.setParameter( null, 'showAvailability', false ); >+ return (new XMLSerializer).serializeToString( proc.transformToFragment( xmlDoc, document ) ); >+ } else if ( window.ActiveXObject ) { >+ var xslt = new ActiveXObject( "Msxml2.XSLTemplate" ); >+ xslt.stylesheet = xslDoc; >+ var xslProc = xslt.createProcessor(); >+ xslProc.input = xmlDoc; >+ xslProc.addParameter( 'showAvailability', false ); >+ xslProc.transform(); >+ return xslProc.output; >+ } >+}; >+ >+KOHA.ExternalSearch = ( function() { >+ return { >+ targets: {}, >+ Search: function( q, limit, callback ) { >+ var includedTargets = []; >+ >+ $.each( KOHA.ExternalSearch.targets, function ( url, info ) { >+ if ( !info.disabled ) { >+ includedTargets.push( url ); >+ } >+ } ); >+ >+ if ( KOHA.ExternalSearch._pz !== undefined ) { >+ afterinit( KOHA.ExternalSearch._pz ); >+ } else { >+ $.get( '/cgi-bin/koha/svc/pazpar2_init', {}, function( data ) { >+ KOHA.ExternalSearch._pz = new pz2({ >+ sessionId: data.sessionID, >+ onshow: callback, >+ errorhandler: function ( error ) { callback( { error: error } ) }, >+ } ); >+ afterinit( KOHA.ExternalSearch._pz ); >+ } ); >+ } >+ >+ function afterinit( pz ) { >+ pz.search( q, limit, 'relevance:0', 'pz:id=' + includedTargets.join( '|' ) ); >+ } >+ }, >+ Fetch: function( offset, callback ) { >+ var pz = KOHA.ExternalSearch._pz; >+ pz.showCallback = callback; >+ pz.show( offset ); >+ }, >+ GetDetailedRecord: function( recid, callback ) { >+ KOHA.ExternalSearch._pz.record( recid, 0, undefined, { callback: callback } ); >+ }, >+ }; >+} )(); >diff --git a/koha-tmpl/opac-tmpl/lib/pz2.js b/koha-tmpl/opac-tmpl/lib/pz2.js >new file mode 100644 >index 0000000..4234c07 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/lib/pz2.js >@@ -0,0 +1,1124 @@ >+/* >+ * pz2.js - pazpar2's javascript client library. >+ * Copyright (C) 2006-2013 Index Data. >+ * >+ * This program is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU General Public License >+ * as published by the Free Software Foundation; either version 2 >+ * of the License, or (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. >+*/ >+ >+//since explorer is flawed >+if (!window['Node']) { >+ window.Node = new Object(); >+ Node.ELEMENT_NODE = 1; >+ Node.ATTRIBUTE_NODE = 2; >+ Node.TEXT_NODE = 3; >+ Node.CDATA_SECTION_NODE = 4; >+ Node.ENTITY_REFERENCE_NODE = 5; >+ Node.ENTITY_NODE = 6; >+ Node.PROCESSING_INSTRUCTION_NODE = 7; >+ Node.COMMENT_NODE = 8; >+ Node.DOCUMENT_NODE = 9; >+ Node.DOCUMENT_TYPE_NODE = 10; >+ Node.DOCUMENT_FRAGMENT_NODE = 11; >+ Node.NOTATION_NODE = 12; >+} >+ >+// prevent execution of more than once >+if(typeof window.pz2 == "undefined") { >+window.undefined = window.undefined; >+ >+var pz2 = function ( paramArray ) >+{ >+ >+ // at least one callback required >+ if ( !paramArray ) >+ throw new Error("Pz2.js: Array with parameters has to be supplied."); >+ >+ //supported pazpar2's protocol version >+ this.suppProtoVer = '1'; >+ if (typeof paramArray.pazpar2path != "undefined") >+ this.pz2String = paramArray.pazpar2path; >+ else >+ this.pz2String = "/pazpar2/search.pz2"; >+ this.useSessions = true; >+ >+ this.stylesheet = paramArray.detailstylesheet || null; >+ //load stylesheet if required in async mode >+ if( this.stylesheet ) { >+ var context = this; >+ var request = new pzHttpRequest( this.stylesheet ); >+ request.get( {}, function ( doc ) { context.xslDoc = doc; } ); >+ } >+ >+ this.errorHandler = paramArray.errorhandler || null; >+ this.showResponseType = paramArray.showResponseType || "xml"; >+ >+ // function callbacks >+ this.initCallback = paramArray.oninit || null; >+ this.statCallback = paramArray.onstat || null; >+ this.showCallback = paramArray.onshow || null; >+ this.termlistCallback = paramArray.onterm || null; >+ this.recordCallback = paramArray.onrecord || null; >+ this.bytargetCallback = paramArray.onbytarget || null; >+ this.resetCallback = paramArray.onreset || null; >+ >+ // termlist keys >+ this.termKeys = paramArray.termlist || "subject"; >+ >+ // some configurational stuff >+ this.keepAlive = 50000; >+ >+ if ( paramArray.keepAlive < this.keepAlive ) >+ this.keepAlive = paramArray.keepAlive; >+ >+ this.sessionID = paramArray.sessionId || null; >+ this.serviceId = paramArray.serviceId || null; >+ this.initStatusOK = false; >+ this.pingStatusOK = false; >+ this.searchStatusOK = false; >+ >+ // for sorting >+ this.currentSort = "relevance"; >+ >+ // where are we? >+ this.currentStart = 0; >+ // currentNum can be overwritten in show >+ this.currentNum = 20; >+ >+ // last full record retrieved >+ this.currRecID = null; >+ >+ // current query >+ this.currQuery = null; >+ >+ //current raw record offset >+ this.currRecOffset = null; >+ >+ //timers >+ this.pingTimer = null; >+ this.statTime = paramArray.stattime || 1000; >+ this.statTimer = null; >+ this.termTime = paramArray.termtime || 1000; >+ this.termTimer = null; >+ this.showTime = paramArray.showtime || 1000; >+ this.showTimer = null; >+ this.showFastCount = 4; >+ this.bytargetTime = paramArray.bytargettime || 1000; >+ this.bytargetTimer = null; >+ this.recordTime = paramArray.recordtime || 500; >+ this.recordTimer = null; >+ >+ // counters for each command and applied delay >+ this.dumpFactor = 500; >+ this.showCounter = 0; >+ this.termCounter = 0; >+ this.statCounter = 0; >+ this.bytargetCounter = 0; >+ this.recordCounter = 0; >+ >+ // active clients, updated by stat and show >+ // might be an issue since bytarget will poll accordingly >+ this.activeClients = 1; >+ >+ // if in proxy mode no need to init >+ if (paramArray.usesessions != undefined) { >+ this.useSessions = paramArray.usesessions; >+ this.initStatusOK = true; >+ } >+ // else, auto init session or wait for a user init? >+ if (this.useSessions && paramArray.autoInit !== false) { >+ this.init(this.sessionID, this.serviceId); >+ } >+ // Version parameter >+ this.version = paramArray.version || null; >+}; >+ >+pz2.prototype = >+{ >+ //error handler for async error throws >+ throwError: function (errMsg, errCode) >+ { >+ var err = new Error(errMsg); >+ if (errCode) err.code = errCode; >+ >+ if (this.errorHandler) { >+ this.errorHandler(err); >+ } >+ else { >+ throw err; >+ } >+ }, >+ >+ // stop activity by clearing tiemouts >+ stop: function () >+ { >+ clearTimeout(this.statTimer); >+ clearTimeout(this.showTimer); >+ clearTimeout(this.termTimer); >+ clearTimeout(this.bytargetTimer); >+ }, >+ >+ // reset status variables >+ reset: function () >+ { >+ if ( this.useSessions ) { >+ this.sessionID = null; >+ this.initStatusOK = false; >+ this.pingStatusOK = false; >+ clearTimeout(this.pingTimer); >+ } >+ this.searchStatusOK = false; >+ this.stop(); >+ >+ if ( this.resetCallback ) >+ this.resetCallback(); >+ }, >+ >+ init: function (sessionId, serviceId) >+ { >+ this.reset(); >+ >+ // session id as a param >+ if (sessionId && this.useSessions ) { >+ this.initStatusOK = true; >+ this.sessionID = sessionId; >+ this.ping(); >+ // old school direct pazpar2 init >+ } else if (this.useSessions) { >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ var opts = {'command' : 'init'}; >+ if (serviceId) opts.service = serviceId; >+ request.safeGet( >+ opts, >+ function(data) { >+ if ( data.getElementsByTagName("status")[0] >+ .childNodes[0].nodeValue == "OK" ) { >+ if ( data.getElementsByTagName("protocol")[0] >+ .childNodes[0].nodeValue >+ != context.suppProtoVer ) >+ throw new Error( >+ "Server's protocol not supported by the client" >+ ); >+ context.initStatusOK = true; >+ context.sessionID = >+ data.getElementsByTagName("session")[0] >+ .childNodes[0].nodeValue; >+ if (data.getElementsByTagName("keepAlive").length > 0) { >+ context.keepAlive = data.getElementsByTagName("keepAlive")[0].childNodes[0].nodeValue; >+ } >+ context.pingTimer = >+ setTimeout( >+ function () { >+ context.ping(); >+ }, >+ context.keepAlive >+ ); >+ if ( context.initCallback ) >+ context.initCallback(); >+ } >+ else >+ context.throwError('Init failed. Malformed WS resonse.', >+ 110); >+ } >+ ); >+ // when through proxy no need to init >+ } else { >+ this.initStatusOK = true; >+ } >+ }, >+ // no need to ping explicitly >+ ping: function () >+ { >+ // pinging only makes sense when using pazpar2 directly >+ if( !this.initStatusOK || !this.useSessions ) >+ throw new Error( >+ 'Pz2.js: Ping not allowed (proxy mode) or session not initialized.' >+ ); >+ var context = this; >+ >+ clearTimeout(context.pingTimer); >+ >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ request.safeGet( >+ { "command": "ping", "session": this.sessionID, "windowid" : window.name }, >+ function(data) { >+ if ( data.getElementsByTagName("status")[0] >+ .childNodes[0].nodeValue == "OK" ) { >+ context.pingStatusOK = true; >+ context.pingTimer = >+ setTimeout( >+ function () { >+ context.ping(); >+ }, >+ context.keepAlive >+ ); >+ } >+ else >+ context.throwError('Ping failed. Malformed WS resonse.', >+ 111); >+ } >+ ); >+ }, >+ search: function (query, num, sort, filter, showfrom, addParamsArr) >+ { >+ clearTimeout(this.statTimer); >+ clearTimeout(this.showTimer); >+ clearTimeout(this.termTimer); >+ clearTimeout(this.bytargetTimer); >+ >+ this.showCounter = 0; >+ this.termCounter = 0; >+ this.bytargetCounter = 0; >+ this.statCounter = 0; >+ this.activeClients = 1; >+ >+ // no proxy mode >+ if( !this.initStatusOK ) >+ throw new Error('Pz2.js: session not initialized.'); >+ >+ if( query !== undefined ) >+ this.currQuery = query; >+ else >+ throw new Error("Pz2.js: no query supplied to the search command."); >+ >+ if ( showfrom !== undefined ) >+ var start = showfrom; >+ else >+ var start = 0; >+ >+ var searchParams = { >+ "command": "search", >+ "query": this.currQuery, >+ "session": this.sessionID, >+ "windowid" : window.name >+ }; >+ >+ if( sort !== undefined ) { >+ this.currentSort = sort; >+ searchParams["sort"] = sort; >+ } >+ if (filter !== undefined) >+ searchParams["filter"] = filter; >+ >+ // copy additional parmeters, do not overwrite >+ if (addParamsArr != undefined) { >+ for (var prop in addParamsArr) { >+ if (!searchParams.hasOwnProperty(prop)) >+ searchParams[prop] = addParamsArr[prop]; >+ } >+ } >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ request.safeGet( >+ searchParams, >+ function(data) { >+ if ( data.getElementsByTagName("status")[0] >+ .childNodes[0].nodeValue == "OK" ) { >+ context.searchStatusOK = true; >+ //piggyback search >+ context.show(start, num, sort); >+ if (context.statCallback) >+ context.stat(); >+ if (context.termlistCallback) >+ context.termlist(); >+ if (context.bytargetCallback) >+ context.bytarget(); >+ } >+ else >+ context.throwError('Search failed. Malformed WS resonse.', >+ 112); >+ } >+ ); >+ }, >+ stat: function() >+ { >+ if( !this.initStatusOK ) >+ throw new Error('Pz2.js: session not initialized.'); >+ >+ // if called explicitly takes precedence >+ clearTimeout(this.statTimer); >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ request.safeGet( >+ { "command": "stat", "session": this.sessionID, "windowid" : window.name }, >+ function(data) { >+ if ( data.getElementsByTagName("stat") ) { >+ var activeClients = >+ Number( data.getElementsByTagName("activeclients")[0] >+ .childNodes[0].nodeValue ); >+ context.activeClients = activeClients; >+ >+ var stat = Element_parseChildNodes(data.documentElement); >+ >+ context.statCounter++; >+ var delay = context.statTime >+ + context.statCounter * context.dumpFactor; >+ >+ if ( activeClients > 0 ) >+ context.statTimer = >+ setTimeout( >+ function () { >+ context.stat(); >+ }, >+ delay >+ ); >+ context.statCallback(stat); >+ } >+ else >+ context.throwError('Stat failed. Malformed WS resonse.', >+ 113); >+ } >+ ); >+ }, >+ show: function(start, num, sort, query_state) >+ { >+ if( !this.searchStatusOK && this.useSessions ) >+ throw new Error( >+ 'Pz2.js: show command has to be preceded with a search command.' >+ ); >+ >+ // if called explicitly takes precedence >+ clearTimeout(this.showTimer); >+ >+ if( sort !== undefined ) >+ this.currentSort = sort; >+ if( start !== undefined ) >+ this.currentStart = Number( start ); >+ if( num !== undefined ) >+ this.currentNum = Number( num ); >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ var requestParameters = >+ { >+ "command": "show", >+ "session": this.sessionID, >+ "start": this.currentStart, >+ "num": this.currentNum, >+ "sort": this.currentSort, >+ "block": 1, >+ "type": this.showResponseType, >+ "windowid" : window.name >+ }; >+ if (query_state) >+ requestParameters["query-state"] = query_state; >+ if (this.version && this.version > 0) >+ requestParameters["version"] = this.version; >+ request.safeGet( >+ requestParameters, >+ function(data, type) { >+ var show = null; >+ var activeClients = 0; >+ if (type === "json") { >+ show = {}; >+ activeClients = Number(data.activeclients[0]); >+ show.activeclients = activeClients; >+ show.merged = Number(data.merged[0]); >+ show.total = Number(data.total[0]); >+ show.start = Number(data.start[0]); >+ show.num = Number(data.num[0]); >+ show.hits = data.hit; >+ } else if (data.getElementsByTagName("status")[0] >+ .childNodes[0].nodeValue == "OK") { >+ // first parse the status data send along with records >+ // this is strictly bound to the format >+ activeClients = >+ Number(data.getElementsByTagName("activeclients")[0] >+ .childNodes[0].nodeValue); >+ show = { >+ "activeclients": activeClients, >+ "merged": >+ Number( data.getElementsByTagName("merged")[0] >+ .childNodes[0].nodeValue ), >+ "total": >+ Number( data.getElementsByTagName("total")[0] >+ .childNodes[0].nodeValue ), >+ "start": >+ Number( data.getElementsByTagName("start")[0] >+ .childNodes[0].nodeValue ), >+ "num": >+ Number( data.getElementsByTagName("num")[0] >+ .childNodes[0].nodeValue ), >+ "hits": [] >+ }; >+ // parse all the first-level nodes for all <hit> tags >+ var hits = data.getElementsByTagName("hit"); >+ for (i = 0; i < hits.length; i++) >+ show.hits[i] = Element_parseChildNodes(hits[i]); >+ } else { >+ context.throwError('Show failed. Malformed WS resonse.', >+ 114); >+ }; >+ >+ var approxNode = data.getElementsByTagName("approximation"); >+ if (approxNode && approxNode[0] && approxNode[0].childNodes[0] && approxNode[0].childNodes[0].nodeValue) >+ show['approximation'] = >+ Number( approxNode[0].childNodes[0].nodeValue); >+ >+ >+ data.getElementsByTagName("") >+ context.activeClients = activeClients; >+ context.showCounter++; >+ var delay = context.showTime; >+ if (context.showCounter > context.showFastCount) >+ delay += context.showCounter * context.dumpFactor; >+ if ( activeClients > 0 ) >+ context.showTimer = setTimeout( >+ function () { >+ context.show(); >+ }, >+ delay); >+ context.showCallback(show); >+ } >+ ); >+ }, >+ record: function(id, offset, syntax, handler) >+ { >+ // we may call record with no previous search if in proxy mode >+ if(!this.searchStatusOK && this.useSessions) >+ throw new Error( >+ 'Pz2.js: record command has to be preceded with a search command.' >+ ); >+ >+ if( id !== undefined ) >+ this.currRecID = id; >+ >+ var recordParams = { >+ "command": "record", >+ "session": this.sessionID, >+ "id": this.currRecID, >+ "windowid" : window.name >+ }; >+ >+ this.currRecOffset = null; >+ if (offset != undefined) { >+ recordParams["offset"] = offset; >+ this.currRecOffset = offset; >+ } >+ >+ if (syntax != undefined) >+ recordParams['syntax'] = syntax; >+ >+ //overwrite default callback id needed >+ var callback = this.recordCallback; >+ var args = undefined; >+ if (handler != undefined) { >+ callback = handler['callback']; >+ args = handler['args']; >+ } >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ >+ request.safeGet( >+ recordParams, >+ function(data) { >+ var recordNode; >+ var record; >+ //raw record >+ if (context.currRecOffset !== null) { >+ record = new Array(); >+ record['xmlDoc'] = data; >+ record['offset'] = context.currRecOffset; >+ callback(record, args); >+ //pz2 record >+ } else if ( recordNode = >+ data.getElementsByTagName("record")[0] ) { >+ // if stylesheet was fetched do not parse the response >+ if ( context.xslDoc ) { >+ record = new Array(); >+ record['xmlDoc'] = data; >+ record['xslDoc'] = context.xslDoc; >+ record['recid'] = >+ recordNode.getElementsByTagName("recid")[0] >+ .firstChild.nodeValue; >+ //parse record >+ } else { >+ record = Element_parseChildNodes(recordNode); >+ } >+ var activeClients = >+ Number( data.getElementsByTagName("activeclients")[0] >+ .childNodes[0].nodeValue ); >+ context.activeClients = activeClients; >+ context.recordCounter++; >+ var delay = context.recordTime + context.recordCounter * context.dumpFactor; >+ if ( activeClients > 0 ) >+ context.recordTimer = >+ setTimeout ( >+ function() { >+ context.record(id, offset, syntax, handler); >+ }, >+ delay >+ ); >+ callback(record, args); >+ } >+ else >+ context.throwError('Record failed. Malformed WS resonse.', >+ 115); >+ } >+ ); >+ }, >+ >+ termlist: function() >+ { >+ if( !this.searchStatusOK && this.useSessions ) >+ throw new Error( >+ 'Pz2.js: termlist command has to be preceded with a search command.' >+ ); >+ >+ // if called explicitly takes precedence >+ clearTimeout(this.termTimer); >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ request.safeGet( >+ { >+ "command": "termlist", >+ "session": this.sessionID, >+ "name": this.termKeys, >+ "windowid" : window.name, >+ "version" : this.version >+ >+ }, >+ function(data) { >+ if ( data.getElementsByTagName("termlist") ) { >+ var activeClients = >+ Number( data.getElementsByTagName("activeclients")[0] >+ .childNodes[0].nodeValue ); >+ context.activeClients = activeClients; >+ var termList = { "activeclients": activeClients }; >+ var termLists = data.getElementsByTagName("list"); >+ //for each termlist >+ for (i = 0; i < termLists.length; i++) { >+ var listName = termLists[i].getAttribute('name'); >+ termList[listName] = new Array(); >+ var terms = termLists[i].getElementsByTagName('term'); >+ //for each term in the list >+ for (j = 0; j < terms.length; j++) { >+ var term = { >+ "name": >+ (terms[j].getElementsByTagName("name")[0] >+ .childNodes.length >+ ? terms[j].getElementsByTagName("name")[0] >+ .childNodes[0].nodeValue >+ : 'ERROR'), >+ "freq": >+ terms[j] >+ .getElementsByTagName("frequency")[0] >+ .childNodes[0].nodeValue || 'ERROR' >+ }; >+ >+ // Only for xtargets: id, records, filtered >+ var termIdNode = >+ terms[j].getElementsByTagName("id"); >+ if(terms[j].getElementsByTagName("id").length) >+ term["id"] = >+ termIdNode[0].childNodes[0].nodeValue; >+ termList[listName][j] = term; >+ >+ var recordsNode = terms[j].getElementsByTagName("records"); >+ if (recordsNode && recordsNode.length) >+ term["records"] = recordsNode[0].childNodes[0].nodeValue; >+ >+ var filteredNode = terms[j].getElementsByTagName("filtered"); >+ if (filteredNode && filteredNode.length) >+ term["filtered"] = filteredNode[0].childNodes[0].nodeValue; >+ >+ } >+ } >+ >+ context.termCounter++; >+ var delay = context.termTime >+ + context.termCounter * context.dumpFactor; >+ if ( activeClients > 0 ) >+ context.termTimer = >+ setTimeout( >+ function () { >+ context.termlist(); >+ }, >+ delay >+ ); >+ >+ context.termlistCallback(termList); >+ } >+ else >+ context.throwError('Termlist failed. Malformed WS resonse.', >+ 116); >+ } >+ ); >+ >+ }, >+ bytarget: function() >+ { >+ if( !this.initStatusOK && this.useSessions ) >+ throw new Error( >+ 'Pz2.js: bytarget command has to be preceded with a search command.' >+ ); >+ >+ // no need to continue >+ if( !this.searchStatusOK ) >+ return; >+ >+ // if called explicitly takes precedence >+ clearTimeout(this.bytargetTimer); >+ >+ var context = this; >+ var request = new pzHttpRequest(this.pz2String, this.errorHandler); >+ request.safeGet( >+ { >+ "command": "bytarget", >+ "session": this.sessionID, >+ "block": 1, >+ "windowid" : window.name, >+ "version" : this.version >+ }, >+ function(data) { >+ if ( data.getElementsByTagName("status")[0] >+ .childNodes[0].nodeValue == "OK" ) { >+ var targetNodes = data.getElementsByTagName("target"); >+ var bytarget = new Array(); >+ for ( i = 0; i < targetNodes.length; i++) { >+ bytarget[i] = new Array(); >+ for( j = 0; j < targetNodes[i].childNodes.length; j++ ) { >+ if ( targetNodes[i].childNodes[j].nodeType >+ == Node.ELEMENT_NODE ) { >+ var nodeName = >+ targetNodes[i].childNodes[j].nodeName; >+ if (targetNodes[i].childNodes[j].firstChild != null) >+ { >+ var nodeText = targetNodes[i].childNodes[j] >+ .firstChild.nodeValue; >+ bytarget[i][nodeName] = nodeText; >+ } >+ else { >+ bytarget[i][nodeName] = ""; >+ } >+ >+ >+ } >+ } >+ if (bytarget[i]["state"]=="Client_Disconnected") { >+ bytarget[i]["hits"] = "Error"; >+ } else if (bytarget[i]["state"]=="Client_Error") { >+ bytarget[i]["hits"] = "Error"; >+ } else if (bytarget[i]["state"]=="Client_Working") { >+ bytarget[i]["hits"] = "..."; >+ } >+ if (bytarget[i].diagnostic == "1") { >+ bytarget[i].diagnostic = "Permanent system error"; >+ } else if (bytarget[i].diagnostic == "2") { >+ bytarget[i].diagnostic = "Temporary system error"; >+ } >+ var targetsSuggestions = targetNodes[i].getElementsByTagName("suggestions"); >+ if (targetsSuggestions != undefined && targetsSuggestions.length>0) { >+ var suggestions = targetsSuggestions[0]; >+ bytarget[i]["suggestions"] = Element_parseChildNodes(suggestions); >+ } >+ } >+ >+ context.bytargetCounter++; >+ var delay = context.bytargetTime >+ + context.bytargetCounter * context.dumpFactor; >+ if ( context.activeClients > 0 ) >+ context.bytargetTimer = >+ setTimeout( >+ function () { >+ context.bytarget(); >+ }, >+ delay >+ ); >+ >+ context.bytargetCallback(bytarget); >+ } >+ else >+ context.throwError('Bytarget failed. Malformed WS resonse.', >+ 117); >+ } >+ ); >+ }, >+ >+ // just for testing, probably shouldn't be here >+ showNext: function(page) >+ { >+ var step = page || 1; >+ this.show( ( step * this.currentNum ) + this.currentStart ); >+ }, >+ >+ showPrev: function(page) >+ { >+ if (this.currentStart == 0 ) >+ return false; >+ var step = page || 1; >+ var newStart = this.currentStart - (step * this.currentNum ); >+ this.show( newStart > 0 ? newStart : 0 ); >+ }, >+ >+ showPage: function(pageNum) >+ { >+ //var page = pageNum || 1; >+ this.show(pageNum * this.currentNum); >+ } >+}; >+ >+/* >+******************************************************************************** >+** AJAX HELPER CLASS *********************************************************** >+******************************************************************************** >+*/ >+var pzHttpRequest = function ( url, errorHandler ) { >+ this.maxUrlLength = 2048; >+ this.request = null; >+ this.url = url; >+ this.errorHandler = errorHandler || null; >+ this.async = true; >+ this.requestHeaders = {}; >+ >+ if ( window.XMLHttpRequest ) { >+ this.request = new XMLHttpRequest(); >+ } else if ( window.ActiveXObject ) { >+ try { >+ this.request = new ActiveXObject( 'Msxml2.XMLHTTP' ); >+ } catch (err) { >+ this.request = new ActiveXObject( 'Microsoft.XMLHTTP' ); >+ } >+ } >+}; >+ >+ >+pzHttpRequest.prototype = >+{ >+ safeGet: function ( params, callback ) >+ { >+ var encodedParams = this.encodeParams(params); >+ var url = this._urlAppendParams(encodedParams); >+ if (url.length >= this.maxUrlLength) { >+ this.requestHeaders["Content-Type"] >+ = "application/x-www-form-urlencoded"; >+ this._send( 'POST', this.url, encodedParams, callback ); >+ } else { >+ this._send( 'GET', url, '', callback ); >+ } >+ }, >+ >+ get: function ( params, callback ) >+ { >+ this._send( 'GET', this._urlAppendParams(this.encodeParams(params)), >+ '', callback ); >+ }, >+ >+ post: function ( params, data, callback ) >+ { >+ this._send( 'POST', this._urlAppendParams(this.encodeParams(params)), >+ data, callback ); >+ }, >+ >+ load: function () >+ { >+ this.async = false; >+ this.request.open( 'GET', this.url, this.async ); >+ this.request.send(''); >+ if ( this.request.status == 200 ) >+ return this.request.responseXML; >+ }, >+ >+ encodeParams: function (params) >+ { >+ var sep = ""; >+ var encoded = ""; >+ for (var key in params) { >+ if (params[key] != null) { >+ encoded += sep + key + '=' + encodeURIComponent(params[key]); >+ sep = '&'; >+ } >+ } >+ return encoded; >+ }, >+ >+ _send: function ( type, url, data, callback) >+ { >+ var context = this; >+ this.callback = callback; >+ this.async = true; >+ this.request.open( type, url, this.async ); >+ for (var key in this.requestHeaders) >+ this.request.setRequestHeader(key, this.requestHeaders[key]); >+ this.request.onreadystatechange = function () { >+ context._handleResponse(url); /// url used ONLY for error reporting >+ } >+ this.request.send(data); >+ }, >+ >+ _urlAppendParams: function (encodedParams) >+ { >+ if (encodedParams) >+ return this.url + "?" + encodedParams; >+ else >+ return this.url; >+ }, >+ >+ _handleResponse: function (savedUrlForErrorReporting) >+ { >+ if ( this.request.readyState == 4 ) { >+ // pick up appplication errors first >+ var errNode = null; >+ if (this.request.responseXML && >+ (errNode = this.request.responseXML.documentElement) >+ && errNode.nodeName == 'error') { >+ var errMsg = errNode.getAttribute("msg"); >+ var errCode = errNode.getAttribute("code"); >+ var errAddInfo = ''; >+ if (errNode.childNodes.length) >+ errAddInfo = ': ' + errNode.childNodes[0].nodeValue; >+ >+ var err = new Error(errMsg + errAddInfo); >+ err.code = errCode; >+ >+ if (this.errorHandler) { >+ this.errorHandler(err); >+ } >+ else { >+ throw err; >+ } >+ } else if (this.request.status == 200 && >+ this.request.responseXML == null) { >+ if (this.request.responseText != null) { >+ //assume JSON >+ >+ var json = null; >+ var text = this.request.responseText; >+ if (typeof window.JSON == "undefined") >+ json = eval("(" + text + ")"); >+ else { >+ try { >+ json = JSON.parse(text); >+ } >+ catch (e) { >+ // Safari: eval will fail as well. Considering trying JSON2 (non-native implementation) instead >+ /* DEBUG only works in mk2-mobile >+ if (document.getElementById("log")) >+ document.getElementById("log").innerHTML = "" + e + " " + length + ": " + text; >+ */ >+ try { >+ json = eval("(" + text + ")"); >+ } >+ catch (e) { >+ /* DEBUG only works in mk2-mobile >+ if (document.getElementById("log")) >+ document.getElementById("log").innerHTML = "" + e + " " + length + ": " + text; >+ */ >+ } >+ } >+ } >+ this.callback(json, "json"); >+ } else { >+ var err = new Error("XML response is empty but no error " + >+ "for " + savedUrlForErrorReporting); >+ err.code = -1; >+ if (this.errorHandler) { >+ this.errorHandler(err); >+ } else { >+ throw err; >+ } >+ } >+ } else if (this.request.status == 200) { >+ this.callback(this.request.responseXML); >+ } else { >+ var err = new Error("HTTP response not OK: " >+ + this.request.status + " - " >+ + this.request.statusText ); >+ err.code = '00' + this.request.status; >+ if (this.errorHandler) { >+ this.errorHandler(err); >+ } >+ else { >+ throw err; >+ } >+ } >+ } >+ } >+}; >+ >+/* >+******************************************************************************** >+** XML HELPER FUNCTIONS ******************************************************** >+******************************************************************************** >+*/ >+ >+// DOMDocument >+ >+if ( window.ActiveXObject) { >+ var DOMDoc = document; >+} else { >+ var DOMDoc = Document.prototype; >+} >+ >+DOMDoc.newXmlDoc = function ( root ) >+{ >+ var doc; >+ >+ if (document.implementation && document.implementation.createDocument) { >+ doc = document.implementation.createDocument('', root, null); >+ } else if ( window.ActiveXObject ) { >+ doc = new ActiveXObject("MSXML2.DOMDocument"); >+ doc.loadXML('<' + root + '/>'); >+ } else { >+ throw new Error ('No XML support in this browser'); >+ } >+ >+ return doc; >+} >+ >+ >+DOMDoc.parseXmlFromString = function ( xmlString ) >+{ >+ var doc; >+ >+ if ( window.DOMParser ) { >+ var parser = new DOMParser(); >+ doc = parser.parseFromString( xmlString, "text/xml"); >+ } else if ( window.ActiveXObject ) { >+ doc = new ActiveXObject("MSXML2.DOMDocument"); >+ doc.loadXML( xmlString ); >+ } else { >+ throw new Error ("No XML parsing support in this browser."); >+ } >+ >+ return doc; >+} >+ >+DOMDoc.transformToDoc = function (xmlDoc, xslDoc) >+{ >+ if ( window.XSLTProcessor ) { >+ var proc = new XSLTProcessor(); >+ proc.importStylesheet( xslDoc ); >+ return proc.transformToDocument(xmlDoc); >+ } else if ( window.ActiveXObject ) { >+ return document.parseXmlFromString(xmlDoc.transformNode(xslDoc)); >+ } else { >+ alert( 'Unable to perform XSLT transformation in this browser' ); >+ } >+} >+ >+// DOMElement >+ >+Element_removeFromDoc = function (DOM_Element) >+{ >+ DOM_Element.parentNode.removeChild(DOM_Element); >+} >+ >+Element_emptyChildren = function (DOM_Element) >+{ >+ while( DOM_Element.firstChild ) { >+ DOM_Element.removeChild( DOM_Element.firstChild ) >+ } >+} >+ >+Element_appendTransformResult = function ( DOM_Element, xmlDoc, xslDoc ) >+{ >+ if ( window.XSLTProcessor ) { >+ var proc = new XSLTProcessor(); >+ proc.importStylesheet( xslDoc ); >+ var docFrag = false; >+ docFrag = proc.transformToFragment( xmlDoc, DOM_Element.ownerDocument ); >+ DOM_Element.appendChild(docFrag); >+ } else if ( window.ActiveXObject ) { >+ DOM_Element.innerHTML = xmlDoc.transformNode( xslDoc ); >+ } else { >+ alert( 'Unable to perform XSLT transformation in this browser' ); >+ } >+} >+ >+Element_appendTextNode = function (DOM_Element, tagName, textContent ) >+{ >+ var node = DOM_Element.ownerDocument.createElement(tagName); >+ var text = DOM_Element.ownerDocument.createTextNode(textContent); >+ >+ DOM_Element.appendChild(node); >+ node.appendChild(text); >+ >+ return node; >+} >+ >+Element_setTextContent = function ( DOM_Element, textContent ) >+{ >+ if (typeof DOM_Element.textContent !== "undefined") { >+ DOM_Element.textContent = textContent; >+ } else if (typeof DOM_Element.innerText !== "undefined" ) { >+ DOM_Element.innerText = textContent; >+ } else { >+ throw new Error("Cannot set text content of the node, no such method."); >+ } >+} >+ >+Element_getTextContent = function (DOM_Element) >+{ >+ if ( typeof DOM_Element.textContent != 'undefined' ) { >+ return DOM_Element.textContent; >+ } else if (typeof DOM_Element.text != 'undefined') { >+ return DOM_Element.text; >+ } else { >+ throw new Error("Cannot get text content of the node, no such method."); >+ } >+} >+ >+Element_parseChildNodes = function (node) >+{ >+ var parsed = {}; >+ var hasChildElems = false; >+ var textContent = ''; >+ >+ if (node.hasChildNodes()) { >+ var children = node.childNodes; >+ for (var i = 0; i < children.length; i++) { >+ var child = children[i]; >+ switch (child.nodeType) { >+ case Node.ELEMENT_NODE: >+ hasChildElems = true; >+ var nodeName = child.nodeName; >+ if (!(nodeName in parsed)) >+ parsed[nodeName] = []; >+ parsed[nodeName].push(Element_parseChildNodes(child)); >+ break; >+ case Node.TEXT_NODE: >+ textContent += child.nodeValue; >+ break; >+ case Node.CDATA_SECTION_NODE: >+ textContent += child.nodeValue; >+ break; >+ } >+ } >+ } >+ >+ var attrs = node.attributes; >+ for (var i = 0; i < attrs.length; i++) { >+ hasChildElems = true; >+ var attrName = '@' + attrs[i].nodeName; >+ var attrValue = attrs[i].nodeValue; >+ parsed[attrName] = attrValue; >+ } >+ >+ // if no nested elements/attrs set value to text >+ if (hasChildElems) >+ parsed['#text'] = textContent; >+ else >+ parsed = textContent; >+ >+ return parsed; >+} >+ >+/* do not remove trailing bracket */ >+} >diff --git a/koha-tmpl/opac-tmpl/prog/en/css/opac.css b/koha-tmpl/opac-tmpl/prog/en/css/opac.css >index 9e15cee..4aa962a 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/css/opac.css >+++ b/koha-tmpl/opac-tmpl/prog/en/css/opac.css >@@ -1677,6 +1677,10 @@ strong em, em strong { > vertical-align: top; > width: 10px; > } >+.sourcecol { >+ vertical-align: top; >+ width: 100px; >+} > #container { > color : #000; > } >@@ -3006,6 +3010,16 @@ float:left; > padding: 0.1em 0; > } > >+.notesrow label { >+ font-weight: bold; >+} >+.notesrow span { >+ display: block; >+} >+.notesrow textarea { >+ width: 100%; >+} >+ > .thumbnail-shelfbrowser span { > margin: 0px auto; > } >@@ -3030,7 +3044,7 @@ padding: 0.1em 0; > background: #EEEEEE none; > } > >-#overdrive-results { >+#overdrive-results, #pazpar2-results { > font-weight: bold; > padding-left: 1em; > } >@@ -3074,3 +3088,14 @@ padding: 0.1em 0; > width: 35%; > font-size: 111%; > } >+ >+.thumbnail-shelfbrowser span { >+ margin: 0px auto; >+} >+ >+#modal-overlay { >+ background-color: white; >+ border-radius: 5px; >+ max-width: 75%; >+ padding: 15px; >+} >diff --git a/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.lightbox_me.js b/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.lightbox_me.js >new file mode 100644 >index 0000000..effe8a6 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.lightbox_me.js >@@ -0,0 +1,254 @@ >+/* >+* $ lightbox_me >+* By: Buck Wilson >+* Version : 2.3 >+* >+* Licensed under the Apache License, Version 2.0 (the "License"); >+* you may not use this file except in compliance with the License. >+* You may obtain a copy of the License at >+* >+* http://www.apache.org/licenses/LICENSE-2.0 >+* >+* Unless required by applicable law or agreed to in writing, software >+* distributed under the License is distributed on an "AS IS" BASIS, >+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+* See the License for the specific language governing permissions and >+* limitations under the License. >+*/ >+ >+ >+(function($) { >+ >+ $.fn.lightbox_me = function(options) { >+ >+ return this.each(function() { >+ >+ var >+ opts = $.extend({}, $.fn.lightbox_me.defaults, options), >+ $overlay = $(), >+ $self = $(this), >+ $iframe = $('<iframe id="foo" style="z-index: ' + (opts.zIndex + 1) + ';border: none; margin: 0; padding: 0; position: absolute; width: 100%; height: 100%; top: 0; left: 0; filter: mask();"/>'), >+ ie6 = ($.browser.msie && $.browser.version < 7); >+ >+ if (opts.showOverlay) { >+ //check if there's an existing overlay, if so, make subequent ones clear >+ var $currentOverlays = $(".js_lb_overlay:visible"); >+ if ($currentOverlays.length > 0){ >+ $overlay = $('<div class="lb_overlay_clear js_lb_overlay"/>'); >+ } else { >+ $overlay = $('<div class="' + opts.classPrefix + '_overlay js_lb_overlay"/>'); >+ } >+ } >+ >+ /*---------------------------------------------------- >+ DOM Building >+ ---------------------------------------------------- */ >+ if (ie6) { >+ var src = /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'; >+ $iframe.attr('src', src); >+ $('body').append($iframe); >+ } // iframe shim for ie6, to hide select elements >+ $('body').append($self.hide()).append($overlay); >+ >+ >+ /*---------------------------------------------------- >+ Overlay CSS stuffs >+ ---------------------------------------------------- */ >+ >+ // set css of the overlay >+ if (opts.showOverlay) { >+ setOverlayHeight(); // pulled this into a function because it is called on window resize. >+ $overlay.css({ position: 'absolute', width: '100%', top: 0, left: 0, right: 0, bottom: 0, zIndex: (opts.zIndex + 2), display: 'none' }); >+ if (!$overlay.hasClass('lb_overlay_clear')){ >+ $overlay.css(opts.overlayCSS); >+ } >+ } >+ >+ /*---------------------------------------------------- >+ Animate it in. >+ ---------------------------------------------------- */ >+ // >+ if (opts.showOverlay) { >+ $overlay.fadeIn(opts.overlaySpeed, function() { >+ setSelfPosition(); >+ $self[opts.appearEffect](opts.lightboxSpeed, function() { setOverlayHeight(); setSelfPosition(); opts.onLoad()}); >+ }); >+ } else { >+ setSelfPosition(); >+ $self[opts.appearEffect](opts.lightboxSpeed, function() { opts.onLoad()}); >+ } >+ >+ /*---------------------------------------------------- >+ Hide parent if parent specified (parentLightbox should be jquery reference to any parent lightbox) >+ ---------------------------------------------------- */ >+ if (opts.parentLightbox) { >+ opts.parentLightbox.fadeOut(200); >+ } >+ >+ >+ /*---------------------------------------------------- >+ Bind Events >+ ---------------------------------------------------- */ >+ >+ $(window).resize(setOverlayHeight) >+ .resize(setSelfPosition) >+ .scroll(setSelfPosition); >+ >+ $(window).bind('keyup.lightbox_me', observeKeyPress); >+ >+ if (opts.closeClick) { >+ $overlay.click(function(e) { closeLightbox(); e.preventDefault; }); >+ } >+ $self.delegate(opts.closeSelector, "click", function(e) { >+ closeLightbox(); e.preventDefault(); >+ }); >+ $self.bind('close', closeLightbox); >+ $self.bind('reposition', setSelfPosition); >+ >+ >+ >+ /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- >+ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ >+ >+ >+ /*---------------------------------------------------- >+ Private Functions >+ ---------------------------------------------------- */ >+ >+ /* Remove or hide all elements */ >+ function closeLightbox() { >+ var s = $self[0].style; >+ if (opts.destroyOnClose) { >+ $self.add($overlay).remove(); >+ } else { >+ $self.add($overlay).hide(); >+ } >+ >+ //show the hidden parent lightbox >+ if (opts.parentLightbox) { >+ opts.parentLightbox.fadeIn(200); >+ } >+ >+ $iframe.remove(); >+ >+ // clean up events. >+ $self.undelegate(opts.closeSelector, "click"); >+ >+ $(window).unbind('reposition', setOverlayHeight); >+ $(window).unbind('reposition', setSelfPosition); >+ $(window).unbind('scroll', setSelfPosition); >+ $(window).unbind('keyup.lightbox_me'); >+ if (ie6) >+ s.removeExpression('top'); >+ opts.onClose(); >+ } >+ >+ >+ /* Function to bind to the window to observe the escape/enter key press */ >+ function observeKeyPress(e) { >+ if((e.keyCode == 27 || (e.DOM_VK_ESCAPE == 27 && e.which==0)) && opts.closeEsc) closeLightbox(); >+ } >+ >+ >+ /* Set the height of the overlay >+ : if the document height is taller than the window, then set the overlay height to the document height. >+ : otherwise, just set overlay height: 100% >+ */ >+ function setOverlayHeight() { >+ if ($(window).height() < $(document).height()) { >+ $overlay.css({height: $(document).height() + 'px'}); >+ $iframe.css({height: $(document).height() + 'px'}); >+ } else { >+ $overlay.css({height: '100%'}); >+ if (ie6) { >+ $('html,body').css('height','100%'); >+ $iframe.css('height', '100%'); >+ } // ie6 hack for height: 100%; TODO: handle this in IE7 >+ } >+ } >+ >+ >+ /* Set the position of the modal'd window ($self) >+ : if $self is taller than the window, then make it absolutely positioned >+ : otherwise fixed >+ */ >+ function setSelfPosition() { >+ var s = $self[0].style; >+ >+ // reset CSS so width is re-calculated for margin-left CSS >+ $self.css({left: '50%', marginLeft: ($self.outerWidth() / 2) * -1, zIndex: (opts.zIndex + 3) }); >+ >+ >+ /* we have to get a little fancy when dealing with height, because lightbox_me >+ is just so fancy. >+ */ >+ >+ // if the height of $self is bigger than the window and self isn't already position absolute >+ if (($self.height() + 80 >= $(window).height()) && ($self.css('position') != 'absolute' || ie6)) { >+ >+ // we are going to make it positioned where the user can see it, but they can still scroll >+ // so the top offset is based on the user's scroll position. >+ var topOffset = $(document).scrollTop() + 40; >+ $self.css({position: 'absolute', top: topOffset + 'px', marginTop: 0}) >+ if (ie6) { >+ s.removeExpression('top'); >+ } >+ } else if ($self.height()+ 80 < $(window).height()) { >+ //if the height is less than the window height, then we're gonna make this thing position: fixed. >+ // in ie6 we're gonna fake it. >+ if (ie6) { >+ s.position = 'absolute'; >+ if (opts.centered) { >+ s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"') >+ s.marginTop = 0; >+ } else { >+ var top = (opts.modalCSS && opts.modalCSS.top) ? parseInt(opts.modalCSS.top) : 0; >+ s.setExpression('top', '((blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"') >+ } >+ } else { >+ if (opts.centered) { >+ $self.css({ position: 'fixed', top: '50%', marginTop: ($self.outerHeight() / 2) * -1}) >+ } else { >+ $self.css({ position: 'fixed'}).css(opts.modalCSS); >+ } >+ >+ } >+ } >+ } >+ >+ }); >+ >+ >+ >+ }; >+ >+ $.fn.lightbox_me.defaults = { >+ >+ // animation >+ appearEffect: "fadeIn", >+ appearEase: "", >+ overlaySpeed: 250, >+ lightboxSpeed: 300, >+ >+ // close >+ closeSelector: ".close", >+ closeClick: true, >+ closeEsc: true, >+ >+ // behavior >+ destroyOnClose: false, >+ showOverlay: true, >+ parentLightbox: false, >+ >+ // callbacks >+ onLoad: function() {}, >+ onClose: function() {}, >+ >+ // style >+ classPrefix: 'lb', >+ zIndex: 999, >+ centered: false, >+ modalCSS: {top: '40px'}, >+ overlayCSS: {background: 'black', opacity: .3} >+ } >+})(jQuery); >\ No newline at end of file >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-external-search.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-external-search.tt >new file mode 100644 >index 0000000..0be0056 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-external-search.tt >@@ -0,0 +1,240 @@ >+[% INCLUDE 'doc-head-open.inc' %] >+[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › External search for '[% q | html %]' >+[% INCLUDE 'doc-head-close.inc' %] >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.lightbox_me.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script> >+<script type="text/javascript"> >+var querystring = "[% q |replace( "'", "\'" ) |replace( '\n', '\\n' ) |replace( '\r', '\\r' ) |html %]"; >+var results_per_page = [% OPACnumSearchResults %]; >+KOHA.ExternalSearch.targets = { >+ [% FOREACH target IN external_search_targets %] >+ '[% target.host %]:[% target.port %]/[% target.db %]': { >+ name: '[% target.name %]', >+ syntax: '[% target.syntax %]', >+ }, >+ [% END %] >+}; >+ >+var xsltResultStylesheets = { >+ [% FOREACH stylesheet IN xslt_result_stylesheets %] >+ '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ), >+ [% END %] >+}; >+ >+var xsltDetailStylesheets = { >+ [% FOREACH stylesheet IN xslt_detail_stylesheets %] >+ '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ), >+ [% END %] >+}; >+ >+var recordCache = {}; >+var resultRenderCache = {}; >+ >+function showResult( syntax, recid ) { >+ if ( recordCache[ recid ] ) { >+ done( recordCache[ recid ] ); >+ } else { >+ KOHA.ExternalSearch.GetDetailedRecord( recid, function( record ) { >+ done( recordCache[ recid ] = record.xmlDoc ); >+ } ); >+ } >+ >+ function done( record ) { >+ xsltResultStylesheets[ syntax ].done( function( xslDoc ) { >+ var fragment = resultRenderCache[ recid ] = KOHA.TransformToFragment( record, xslDoc ); >+ var $tr = $( '#results tr' ).filter( function() { return $( this ).data( 'recid' ) == recid } ); >+ $tr.find( '.info' ).html( fragment ); >+ $tr.find( 'a' ).attr( 'href', '#' ).click( function() { >+ showDetail( syntax, recid ); >+ >+ return false; >+ } ); >+ } ); >+ } >+} >+ >+function showDetail( syntax, recid ) { >+ var record = recordCache[ recid ]; >+ console.info((new XMLSerializer).serializeToString( record )); >+ >+ xsltDetailStylesheets[ syntax ].done( function( xslDoc ) { >+ var fragment = KOHA.TransformToFragment( record, xslDoc ); >+ >+ $( '#modal-overlay' ).html( fragment ).lightbox_me( { >+ centered: true, >+ } ); >+ } ); >+} >+ >+function search( offset, reset_search ) { >+ $( '#pazpar2-status' ).html( _("Searching external targets...") + '<img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" />' ); >+ >+ if ( reset_search ) { >+ KOHA.ExternalSearch.Search( querystring, results_per_page, callback ); >+ } else { >+ KOHA.ExternalSearch.Fetch( offset, callback ); >+ } >+ >+ function callback( data ) { >+ if ( data.error && data.error.code != 8 ) { // PAZPAR2_NO_TARGETS >+ $( '#pazpar2-status' ).html( '<strong class="unavailable">' + _("Error searching external targets.") + '</strong>' ); >+ return; >+ } >+ >+ if ( !data.total ) { >+ $( '#pazpar2-status' ).html( '<strong>' + _("No results found in the external targets.") + '</strong>' ); >+ return; >+ } >+ >+ $( '#results tbody' ).empty(); >+ >+ $( '#pazpar2-status' ).html( '<strong>' + _("Found __RESULTS__ results in __TARGETS__ external targets.").replace('__RESULTS__', data.total).replace('__TARGETS__', $( '#targets-facet input:checked' ).length ) ); >+ >+ for ( var i = 0; data.hits[i]; i++ ) { >+ var hit = data.hits[i]; >+ var results = []; >+ var recordSyntax = KOHA.ExternalSearch.targets[ hit.location[0]['@id'] ].syntax; >+ >+ results.push( '<tr>' ); >+ >+ results.push( '<td class="sourcecol">', hit.location[0]['@name'], '</td>' ); >+ >+ results.push( '<td class="info">' ); >+ >+ if ( resultRenderCache[ hit.recid[0] ] ) { >+ results.push( resultRenderCache[ hit.recid[0] ] ); >+ } else { >+ results.push( hit['md-work-title'] ? hit['md-work-title'][0] : _("Loading...") ); >+ showResult( recordSyntax, hit.recid[0] ); >+ } >+ >+ results.push( '</td>' ); >+ >+ results.push( '</tr>' ); >+ var $tr = $( results.join( '' ) ); >+ $tr.data( 'recid', hit.recid[0] ); >+ $( '#results tbody' ).append( $tr ); >+ >+ ( function( hit, recordSyntax ) { >+ $tr.find( 'a' ).attr( 'href', '#' ).click( function() { >+ showDetail( recordSyntax, hit.recid[0] ); >+ >+ return false; >+ } ); >+ } )( hit, recordSyntax ); >+ } >+ >+ $( '#results tr:odd' ).addClass( 'highlight' ); >+ >+ var pages = []; >+ var cur_page = data.start / results_per_page; >+ var max_page = Math.floor( data.total / results_per_page ); >+ >+ if ( cur_page != 0 ) { >+ pages.push( '<a class="nav" href="#" data-offset="' + (offset - results_per_page) + '"><< ' + _("Previous") + '</a>' ); >+ } >+ >+ for ( var page = Math.max( 0, cur_page - 9 ); page <= Math.min( max_page, cur_page + 9 ); page++ ) { >+ if ( page == cur_page ) { >+ pages.push( ' <span class="current">' + ( page + 1 ) + '</span>' ); >+ } else { >+ pages.push( ' <a class="nav" href="#" data-offset="' + ( page * results_per_page ) + '">' + ( page + 1 ) + '</a>' ); >+ } >+ } >+ >+ if ( cur_page < max_page ) { >+ pages.push( ' <a class="nav" href="#" data-offset="' + (offset + results_per_page) + '">' + _("Next") + ' >></a>' ); >+ } >+ >+ if ( pages.length > 1 ) $( '#top-pages, #bottom-pages' ).find( '.pages' ).html( pages.join( '' ) ); >+ } >+} >+ >+$( document ).ready( function() { >+ $( '#breadcrumbs p' ) >+ .append( ' ' ) >+ .append( '<span id="pazpar2-status"></span>' ); >+ >+ $( document ).on( 'click', 'a.nav', function() { >+ search( $( this ).data( 'offset' ) ); >+ return false; >+ }); >+ >+ var reSearchTimeout; >+ >+ $( '#targets-facet input' ).each( function() { >+ $( this ).click( function() { >+ KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked; >+ >+ if ( reSearchTimeout ) clearTimeout( reSearchTimeout ); >+ >+ reSearchTimeout = setTimeout( function() { >+ if ( $( '#targets-facet input:checked' ).length ) search( 0, true ); >+ }, 1000 ); >+ } ); >+ >+ KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked; >+ } ); >+ >+ search( 0, true ); >+} ); >+</script> >+<style> >+.actions a.addtocart { >+ display: inline; >+} >+</style> >+</head> >+<body> >+<div id="doc3" class="yui-t1"> >+ >+<div id="bd"> >+ [% INCLUDE 'masthead.inc' %] >+ >+ <h1>External search for '[% q | html %]'</h1> >+ <div id="breadcrumbs"> >+ <p></p> >+ </div> >+ >+ <div id="yui-main"><div class="yui-b searchresults"> >+ <div id="top-pages"> >+ <div class="pages"> >+ </div> >+ </div> >+ <table id="results"> >+ <tbody> >+ </tbody> >+ </table> >+ <div id="bottom-pages"> >+ <div class="pages"> >+ </div> >+ </div> >+ </div></div> >+ >+ <div class="yui-b"><div id="facetcontainer" class="container"> >+ <div id="search-facets"> >+ >+ <h4>Refine your search</h4> >+ >+ <ul> >+ <li id="targets-facet"> >+ Targets >+ <ul> >+ [% FOREACH target = external_search_targets %] >+ <li> >+ <input data-url="[% target.host %]:[% target.port %]/[% target.db %]" type="checkbox" id="target-[% loop.index %]" checked /> >+ <label for="target-[% loop.index %]">[% target.name %] >+ </li> >+ [% END %] >+ </ul> >+ </li> >+ </ul> >+ </div> >+ </div></div> >+</div> >+ >+</div> >+ >+<div id="modal-overlay" style="display: none"></div> >+[% INCLUDE 'opac-bottom.inc' %] >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt >index 4e264d4..dac7211 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt >@@ -16,7 +16,11 @@ > <link rel="stylesheet" type="text/css" href="[% themelang %]/css/jquery.rating.css" /> > [% END %] > >-<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script> >+[% IF ( OverDriveEnabled ) %]<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script>[% END %] >+[% IF ( Koha.Preference('OPACSearchExternalTargets') ) %] >+<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script> >+<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script> >+[% END %] > <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script> > [% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.highlight-3.js"></script> > [% END %]<script type="text/javascript"> >@@ -266,24 +270,61 @@ $(document).ready(function(){ > $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;}); > $("#highlight_toggle_off").show().click(function() {highlightOff();}); > [% END %] >+ function StartExternalSearch(name, text) { >+ $( '#breadcrumbs p' ) >+ .eq( 0 ) >+ .append( ' <span id="' + name + '-results">' + text + '... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' ); >+ } >+ function FailExternalSearch( name, text ) { >+ $( '#' + name + '-results' ).html( text ); >+ } >+ function FinishExternalSearch( name, text, numItems, url ) { >+ if ( numItems ) { >+ $( '#' + name + '-results' ).html( text.replace( '__LINK__', '<a href="' + url + '">' + numItems + _(" results") + '</a>' ) ); >+ } else { >+ $( '#' + name + '-results' ).remove(); >+ } >+ } >+ > [% IF ( OverDriveEnabled ) %] >- var $overdrive_results = $( '<span id="overdrive-results">' + _( 'Searching OverDrive...' ) + ' <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' ); >- $( '#breadcrumbs p' ).eq(0) >- .append( ' ' ) >- .append( $overdrive_results ); >+ StartExternalSearch( 'overdrive', _("Searching OverDrive") ); > KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) { > if ( data.error ) { >- $overdrive_results.html( _( 'Error searching OverDrive collection' ) ); >+ FailExternalSearch( 'overdrive', _("Error searching OverDrive collection") ); > return; > } > >- if ( data.totalItems ) { >- $overdrive_results.html( _( 'Found' ) + ' <a href="/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) + '">' + data.totalItems + ' ' + _( 'results' ) + '</a> ' + _( 'in OverDrive collection' ) ); >- } else { >- $overdrive_results.remove(); >- } >+ FinishExternalSearch( 'overdrive', _("Found __LINK__ in OverDrive collection"), data.totalItems, '/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) ); > } ); > [% END %] >+ >+ [% IF ( OPACSearchExternalTargets ) %] >+ KOHA.ExternalSearch.targets = { >+ [% FOREACH target IN external_search_targets %] >+ '[% target.host %]:[% target.port %]/[% target.db %]': { >+ id: '[% target.target_id %]', >+ name: '[% target.name %]', >+ syntax: '[% target.syntax %]', >+ }, >+ [% END %] >+ }; >+ var num_targets = 0; $.each( KOHA.ExternalSearch.targets, function() { num_targets++ } ); >+ var first_succeeded; >+ >+ if ( num_targets ) { >+ StartExternalSearch( 'pazpar2', _("Searching external targets") ); >+ KOHA.ExternalSearch.Search( querystring, 1, function( data ) { >+ if ( data.error ) { >+ if ( !first_succeeded ) FailExternalSearch( 'pazpar2', _("Error searching external targets") ); >+ return; >+ } >+ >+ first_succeeded = true; >+ FinishExternalSearch( 'pazpar2', _("Found __LINK__ in __TARGETS__ external targets").replace( '__TARGETS__', num_targets ), data.total, '/cgi-bin/koha/opac-external-search.pl?q=' + escape( querystring ) ); >+ } ); >+ } >+ [% END %] >+ > [% END %] > > [% IF ( TagsInputEnabled && loggedinusername ) %] >diff --git a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl >index 6b314d1..bac472d 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl >+++ b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl >@@ -5,11 +5,13 @@ > xmlns:marc="http://www.loc.gov/MARC21/slim" > xmlns:items="http://www.koha-community.org/items" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns="http://www.w3.org/1999/xhtml" > exclude-result-prefixes="marc items"> > <xsl:import href="MARC21slimUtils.xsl"/> > <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/> > <xsl:key name="item-by-status" match="items:item" use="items:status"/> > <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/> >+ <xsl:param name="showAvailability" select="true()"/> > > <xsl:template match="/"> > <xsl:apply-templates/> >@@ -1027,6 +1029,7 @@ > </xsl:for-each> > </span> > </xsl:if> >+ <xsl:if test="$showAvailability"> > <span class="results_summary availability"> > <span class="label">Availability: </span> > <xsl:choose> >@@ -1035,7 +1038,7 @@ > <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]"> > <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/> > <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]"> >- <xsl:call-template select="marc:datafield[@tag=$AlternateHoldingsField]" name="subfieldSelect"> >+ <xsl:call-template name="subfieldSelect"> > <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param> > <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param> > </xsl:call-template> >@@ -1145,6 +1148,7 @@ > <xsl:text>). </xsl:text> </span> > </xsl:if> > </span> >+ </xsl:if> > <xsl:choose> > <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)"> > <span class="results_summary" id="location"> >diff --git a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl >index df7c450..1f18054 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl >+++ b/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl >@@ -1,6 +1,6 @@ > <?xml version='1.0'?> > <!DOCTYPE stylesheet [<!ENTITY nbsp " " >]> >-<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> >+<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"> > <xsl:template name="datafield"> > <xsl:param name="tag"/> > <xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param> >diff --git a/koha-tmpl/opac-tmpl/prog/en/xslt/UNIMARCslim2OPACResults.xsl b/koha-tmpl/opac-tmpl/prog/en/xslt/UNIMARCslim2OPACResults.xsl >index 0becec1..c224cec 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/xslt/UNIMARCslim2OPACResults.xsl >+++ b/koha-tmpl/opac-tmpl/prog/en/xslt/UNIMARCslim2OPACResults.xsl >@@ -6,12 +6,14 @@ > xmlns:marc="http://www.loc.gov/MARC21/slim" > xmlns:items="http://www.koha-community.org/items" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns="http://www.w3.org/1999/xhtml" > exclude-result-prefixes="marc items"> > > <xsl:import href="UNIMARCslimUtils.xsl"/> > <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/> > <xsl:key name="item-by-status" match="items:item" use="items:status"/> > <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/> >+<xsl:param name="showAvailability" select="true()"/> > > <xsl:template match="/"> > <xsl:apply-templates/> >@@ -99,6 +101,7 @@ > > <xsl:call-template name="tag_215" /> > >+ <xsl:if test="$showAvailability"> > <span class="results_summary availability"> > <span class="label">Availability: </span> > <xsl:choose> >@@ -247,6 +250,7 @@ > </span> > </xsl:if> > </span> >+ </xsl:if> > > </xsl:template> > >diff --git a/opac/opac-external-search.pl b/opac/opac-external-search.pl >new file mode 100755 >index 0000000..423dc0d >--- /dev/null >+++ b/opac/opac-external-search.pl >@@ -0,0 +1,62 @@ >+#!/usr/bin/perl >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+use Modern::Perl; >+ >+use CGI; >+ >+use C4::Auth qw(:DEFAULT get_session); >+use C4::Output; >+use C4::Search qw( GetExternalSearchTargets ); >+use C4::XSLT qw( XSLTGetFilename ); >+ >+my $cgi = new CGI; >+ >+# Getting the template and auth >+my ($template, $loggedinuser, $cookie) >+= get_template_and_user({template_name => "opac-external-search.tmpl", >+ query => $cgi, >+ type => "opac", >+ authnotrequired => 1, >+ flagsrequired => {borrowers => 1}, >+ debug => 1, >+ }); >+ >+$template->{VARS}->{q} = $cgi->param('q'); >+$template->{VARS}->{limit} = C4::Context->preference('OPACnumSearchResults') || 20; >+$template->{VARS}->{OPACnumSearchResults} = C4::Context->preference('OPACnumSearchResults') || 20; >+$template->{VARS}->{external_search_targets} = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' ); >+ >+my @xsltResultStylesheets; >+my @xsltDetailStylesheets; >+ >+foreach my $syntax ( qw( MARC21 UNIMARC NORMARC ) ) { >+ if ( XSLTGetFilename( $syntax, 'OPACXSLTResultsDisplay' ) =~ m,/opac-tmpl/.*|^https:?.*, ) { >+ push @xsltResultStylesheets, { syntax => $syntax, url => $& }; >+ } >+ >+ if ( XSLTGetFilename( $syntax, 'OPACXSLTDetailsDisplay' ) =~ m,/opac-tmpl/.*|^https:?.*, ) { >+ push @xsltDetailStylesheets, { syntax => $syntax, url => $& }; >+ } >+} >+ >+$template->{VARS}->{xslt_result_stylesheets} = \@xsltResultStylesheets; >+$template->{VARS}->{xslt_detail_stylesheets} = \@xsltDetailStylesheets; >+ >+output_html_with_http_headers $cgi, $cookie, $template->output; >diff --git a/opac/opac-search.pl b/opac/opac-search.pl >index e2236c2..e2a2f44 100755 >--- a/opac/opac-search.pl >+++ b/opac/opac-search.pl >@@ -74,6 +74,9 @@ if ( $branch_group_limit ) { > -name => 'multibranchlimit', > -values => substr($branch_group_limit, 17) > ); >+ } elsif ( $branch_group_limit eq '@overdrive' ) { >+ print $cgi->redirect( '/cgi-bin/koha/opac-overdrive-search.pl?q=' . join( '+', $cgi->param( 'q' ) ) ); >+ exit; > } else { > $cgi->append( > -name => 'limit', >@@ -880,10 +883,11 @@ $template->{VARS}->{IDreamBooksReviews} = C4::Context->preference('IDreamBooksRe > $template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer'); > $template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults'); > >-if ($offset == 0 && IsOverDriveEnabled()) { >- $template->param(OverDriveEnabled => 1); >- $template->param(OverDriveLibraryID => C4::Context->preference('OverDriveLibraryID')); >-} >+$template->{VARS}->{OPACSearchExternalTargets} = C4::Context->preference('OPACSearchExternalTargets'); >+$template->{VARS}->{external_search_targets} = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' ); >+ >+$template->{VARS}->{OverDriveLibraryID} = C4::Context->preference('OverDriveLibraryID'); >+$template->{VARS}->{OverDriveEnabled} = ($offset == 0 && IsOverDriveEnabled()); > > $template->param( borrowernumber => $borrowernumber); > output_with_http_headers $cgi, $cookie, $template->output, $content_type; >diff --git a/opac/svc/pazpar2_init b/opac/svc/pazpar2_init >new file mode 100755 >index 0000000..039995c >--- /dev/null >+++ b/opac/svc/pazpar2_init >@@ -0,0 +1,101 @@ >+#!/usr/bin/perl >+ >+# Copyright 2013 ByWater Solutions >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it >+# under the terms of the GNU General Public License as published by >+# the Free Software Foundation; either version 3 of the License, or >+# (at your option) any later version. >+# >+# Koha is distributed in the hope that it will be useful, but >+# WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+=head1 NAME >+ >+svc/pazpar2_init: Initialize a Pazpar2 session >+ >+=head1 SYNOPSIS >+ >+svc/pazpar2_init -> ../pazpar2/search.pz2?command=init&... >+ >+=head1 DESCRIPTION >+ >+This services connects to pazpar2 and authenticates connections on behalf of >+client-side search code. The proxy is necessary to prevent exposing >+authentication information. >+ >+=cut >+ >+use strict; >+use warnings; >+ >+use CGI qw(-oldstyle_urls); >+use HTTP::Request::Common; >+use JSON; >+use URI; >+use XML::Simple; >+ >+use C4::Context; >+use C4::Search; >+use C4::Service; >+use C4::Output; >+ >+my $dbh = C4::Context->dbh; >+my ( $query, $response ) = C4::Service->init; >+ >+my %init_opts; >+ >+my $targets = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' ); >+ >+foreach my $target ( @$targets ) { >+ my $target_url = $target->{'host'} . ':' . $target->{'port'} . '/' . $target->{'db'}; >+ $init_opts{ 'pz:name[' . $target_url . ']' } = $target->{'name'}; >+ $init_opts{ 'pz:queryencoding[' . $target_url . ']' } = $target->{'encoding'}; >+ $init_opts{ 'pz:xslt[' . $target_url . ']' } = lc( $target->{'syntax'} ) . '-work-groups.xsl'; >+ $init_opts{ 'pz:requestsyntax[' . $target_url . ']' } = $target->{'syntax'}; >+ $init_opts{ 'pz:nativesyntax[' . $target_url . ']' } = 'iso2709'; >+ >+ if ( $target->{'userid'} ) { >+ if ( $target->{'password'} ) { >+ $init_opts{ 'pz:authentication[' . $target_url . ']' } = $target->{'userid'} . '/' . $target->{'password'}; >+ } else { >+ $init_opts{ 'pz:authentication[' . $target_url . ']' } = $target->{'userid'}; >+ } >+ } >+} >+ >+my $uri = 'http://' . C4::Context->preference( 'OPACBaseURL' ) . "/pazpar2/search.pz2"; >+ >+my $request = HTTP::Request::Common::POST( $uri, [ command => 'init', %init_opts ] ); >+ >+my $ua = LWP::UserAgent->new( "Koha " . C4::Context->KOHAVERSION ); >+ >+my $response = $ua->request( $request ) ; >+if ( !$response->is_success ) { >+ print $query->header( >+ -status => '500 Internal Server Error' >+ ); >+ >+ warn "Pazpar2 init failed: " . $response->message; >+ my $content = to_json({ >+ error => 'Could not connect to Pazpar2', >+ }); >+ output_with_http_headers $query, undef, $content, 'json', '500 Internal Server Error'; >+ >+ exit; >+} else { >+ my $xs = XML::Simple->new; >+ my $data = $xs->XMLin( $response->content ); >+ >+ my $content = to_json({ >+ sessionID => $data->{'session'} >+ }); >+ output_with_http_headers $query, undef, $content, 'json', '200 OK'; >+} >diff --git a/rewrite-config.PL b/rewrite-config.PL >index ea69c94..5467bf5 100644 >--- a/rewrite-config.PL >+++ b/rewrite-config.PL >@@ -136,8 +136,8 @@ $prefix = $ENV{'INSTALL_BASE'} || "/usr"; > "__INSTALL_BASE__" => '/usr/share/koha', > "__INSTALL_SRU__" => 'yes', > "__INSTALL_PAZPAR2__" => 'no', >- "__PAZPAR2_TOGGLE_XML_PRE__" => '<!--', >- "__PAZPAR2_TOGGLE_XML_POST__" => '-->', >+ "__PAZPAR2_TOGGLE_HTTPD_PRE__" => '<IfDefine PAZPAR2_IS_DISABLED>', >+ "__PAZPAR2_TOGGLE_HTTPD_POST__" => '</IfDefine>', > "__AUTH_INDEX_MODE__" => 'grs1', > "__BIB_INDEX_MODE__" => 'grs1', > "__RUN_DATABASE_TESTS__" => 'no', >@@ -157,8 +157,8 @@ foreach $key (keys %configuration) { > # munge commenting out the PazPar2 mergeserver > # entry in koha-conf.xml if necessary > if ($configuration{'__INSTALL_PAZPAR2__'} eq 'yes') { >- $configuration{'__PAZPAR2_TOGGLE_XML_PRE__'} = ''; >- $configuration{'__PAZPAR2_TOGGLE_XML_POST__'} = ''; >+ $configuration{'__PAZPAR2_TOGGLE_HTTPD_PRE__'} = ''; >+ $configuration{'__PAZPAR2_TOGGLE_HTTPD_POST__'} = ''; > } > > $fname = $ARGV[0]; >diff --git a/t/XSLT.t b/t/XSLT.t >index 64cd597..d9aaf24 100755 >--- a/t/XSLT.t >+++ b/t/XSLT.t >@@ -6,7 +6,11 @@ > use strict; > use warnings; > >-use Test::More tests => 8; >+use C4::Context; >+use C4::Templates; >+use Test::More tests => 13; >+use Test::MockModule; >+use File::Basename qw/dirname/; > use File::Temp; > use File::Path qw/make_path/; > >@@ -14,36 +18,96 @@ BEGIN { > use_ok('C4::XSLT'); > } > >-my $dir = File::Temp->newdir(); >+my $opacdir = File::Temp->newdir(); >+my $staffdir = File::Temp->newdir(); > my @themes = ('prog', 'test'); > my @langs = ('en', 'es-ES'); > >+sub make_test_file { >+ my ( $filename, $contents ) = @_; >+ >+ make_path(dirname($filename)); >+ open my $fh, '>', $filename or die "Could not create test file: $filename"; >+ print $fh $contents; >+ close $fh; >+} >+ > # create temporary files to be tested later > foreach my $theme (@themes) { > foreach my $lang (@langs) { >- make_path("$dir/$theme/$lang/xslt"); >- open my $fh, '>', "$dir/$theme/$lang/xslt/my_file.xslt"; >- print $fh "Theme $theme, language $lang"; >- close $fh; >+ foreach my $dir ($opacdir, $staffdir) { >+ make_test_file( "$dir/$theme/$lang/xslt/my_file.xslt", "Theme $theme, language $lang" ); >+ make_test_file( "$dir/$theme/$lang/xslt/MARC21slim2intranetDetail.xsl", "Theme $theme, language $lang, MARC21slim2intranetDetail" ); >+ make_test_file( "$dir/$theme/$lang/xslt/test_en.xsl", "Theme $theme, language $lang, test_en" ); >+ make_test_file( "$dir/$theme/$lang/xslt/UNIMARCslim2OPACDetail.xsl", "Theme $theme, language $lang, UNIMARCslim2OPACDetail" ); >+ make_test_file( "$dir/$theme/$lang/xslt/nondefault_test.xsl", "Theme $theme, language $lang, nondefault_test" ); >+ make_test_file( "$dir/$theme/$lang/xslt/MARC21slim2OPACResults.xsl", "Theme $theme, language $lang, MARC21slim2OPACResults" ); >+ } > } > } > >-sub find_and_slurp { >+sub find_and_slurp_default { > my ($dir, $theme, $lang) = @_; > > my $filename = C4::XSLT::_get_best_default_xslt_filename($dir, $theme, $lang, 'my_file.xslt'); >- open my $fh, '<', $filename; >+ open my $fh, '<', $filename or return "Could not open: $filename"; > my $str = <$fh>; > close $fh; > return $str; > } > >+sub find_and_slurp { >+ my ($marcflavour, $xslsyspref) = @_; >+ >+ my $filename = C4::XSLT::XSLTGetFilename( $marcflavour, $xslsyspref ); >+ open my $fh, '<', $filename or return "Could not open: $filename"; >+ my $str = <$fh>; >+ close $fh; >+ return $str; >+} >+ >+my $module_context = new Test::MockModule('C4::Context'); >+$module_context->mock( >+ 'config', >+ sub { >+ my ( $self, $var ) = @_; >+ my %predefs = ( >+ opachtdocs => $opacdir, >+ intrahtdocs => $staffdir, >+ ); >+ >+ return $predefs{$var} || $module_context->original('config')->(@_); >+ } >+); >+$module_context->mock( >+ 'preference', >+ sub { >+ my ( $self, $var ) = @_; >+ my %predefs = ( >+ template => 'prog', >+ marcflavour => 'MARC21', >+ opacthemes => 'test', >+ XSLTDetailsDisplay => 'default', >+ XSLTResultsDisplay => "$staffdir/prog/en/xslt/test_en.xsl", >+ OPACXSLTDetailsDisplay => "$opacdir/test/en/xslt/nondefault_test.xsl", >+ OPACXSLTResultsDisplay => '"default"', >+ ); >+ >+ return $predefs{$var} || $module_context->original('preference')->(@_); >+ } >+); >+ > # These tests verify that we're finding the right XSLT file when present, > # and falling back to the right XSLT file when an exact match is not present. >-is(find_and_slurp($dir, 'test', 'en' ), 'Theme test, language en', 'Found test/en'); >-is(find_and_slurp($dir, 'test', 'es-ES'), 'Theme test, language es-ES', 'Found test/es-ES'); >-is(find_and_slurp($dir, 'prog', 'en', ), 'Theme prog, language en', 'Found test/en'); >-is(find_and_slurp($dir, 'prog', 'es-ES'), 'Theme prog, language es-ES', 'Found test/es-ES'); >-is(find_and_slurp($dir, 'test', 'fr-FR'), 'Theme test, language en', 'Fell back to test/en for test/fr-FR'); >-is(find_and_slurp($dir, 'nope', 'es-ES'), 'Theme prog, language es-ES', 'Fell back to prog/es-ES for nope/es-ES'); >-is(find_and_slurp($dir, 'nope', 'fr-FR'), 'Theme prog, language en', 'Fell back to prog/en for nope/fr-FR'); >+is(find_and_slurp_default($opacdir, 'test', 'en' ), 'Theme test, language en', 'Found test/en'); >+is(find_and_slurp_default($opacdir, 'test', 'es-ES'), 'Theme test, language es-ES', 'Found test/es-ES'); >+is(find_and_slurp_default($opacdir, 'prog', 'en', ), 'Theme prog, language en', 'Found test/en'); >+is(find_and_slurp_default($opacdir, 'prog', 'es-ES'), 'Theme prog, language es-ES', 'Found test/es-ES'); >+is(find_and_slurp_default($opacdir, 'test', 'fr-FR'), 'Theme test, language en', 'Fell back to test/en for test/fr-FR'); >+is(find_and_slurp_default($opacdir, 'nope', 'es-ES'), 'Theme prog, language es-ES', 'Fell back to prog/es-ES for nope/es-ES'); >+is(find_and_slurp_default($opacdir, 'nope', 'fr-FR'), 'Theme prog, language en', 'Fell back to prog/en for nope/fr-FR'); >+is(find_and_slurp('MARC21', 'XSLTDetailsDisplay'), 'Theme prog, language en, MARC21slim2intranetDetail', 'Used default for staff/details'); >+is(find_and_slurp('MARC21', 'XSLTResultsDisplay'), 'Theme prog, language en, test_en', 'Used non-default with langcode for staff/results'); >+is(find_and_slurp('MARC21', 'OPACXSLTDetailsDisplay'), 'Theme test, language en, nondefault_test', 'not-prog: Used non-default for local marcflavour and opac/details'); >+is(find_and_slurp('UNIMARC', 'OPACXSLTDetailsDisplay'), 'Theme test, language en, UNIMARCslim2OPACDetail', 'not-prog: Used default for non-local marcflavour and opac/details'); >+is(find_and_slurp('MARC21', 'OPACXSLTResultsDisplay'), 'Theme test, language en, MARC21slim2OPACResults', 'not-prog: Used "default" for opac/results'); >-- >1.8.3.2
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 10486
:
19142
|
19143
|
19226
|
19227
|
19680
|
21687
|
21734
|
22084
|
22540
|
23109
|
23112
|
23113
|
24036
|
24206
|
24207
|
24208
|
25235
|
25236
|
25979
|
26002
|
26017
|
26129
|
26804
|
26988
|
27275
|
27276
|
27438
|
27439
|
27440
|
27559
|
27756
|
27781
|
27783
| 27785 |
27786
|
27787
|
27788
|
27789
|
27790