View | Details | Raw Unified | Return to bug 10486
Collapse All | Expand All

(-)a/C4/Search.pm (+30 lines)
Lines 72-77 This module provides searching functions for Koha's bibliographic databases Link Here
72
  &GetDistinctValues
72
  &GetDistinctValues
73
  &enabled_staff_search_views
73
  &enabled_staff_search_views
74
  &PurgeSearchHistory
74
  &PurgeSearchHistory
75
  &GetExternalSearchTargets
75
);
76
);
76
77
77
# make all your functions, whether exported or not;
78
# make all your functions, whether exported or not;
Lines 2438-2443 sub new_record_from_zebra { Link Here
2438
2439
2439
}
2440
}
2440
2441
2442
=head2 GetExternalSearchTargets
2443
2444
Returns the list of Z39.50 servers that are marked for search in the OPAC using
2445
Pazpar2.
2446
2447
=cut
2448
2449
sub GetExternalSearchTargets {
2450
    my ( $branchcode ) = @_;
2451
2452
    if ( $branchcode ) {
2453
        return C4::Context->dbh->selectall_arrayref( q{
2454
            SELECT * FROM external_targets et
2455
            LEFT JOIN external_target_restrictions etr
2456
                ON (etr.target_id = et.target_id and etr.branchcode = ?)
2457
            WHERE etr.target_id IS NULL
2458
            ORDER BY et.name
2459
        }, { Slice => {} }, $branchcode );
2460
    } else {
2461
        return C4::Context->dbh->selectall_arrayref( q{
2462
            SELECT * FROM external_targets et
2463
            LEFT JOIN external_target_restrictions etr USING (target_id)
2464
            GROUP by et.target_id
2465
            HAVING branchcode IS NULL
2466
            ORDER BY et.name
2467
        }, { Slice => {} } );
2468
    }
2469
}
2470
2441
END { }    # module clean-up code here (global destructor)
2471
END { }    # module clean-up code here (global destructor)
2442
2472
2443
1;
2473
1;
(-)a/C4/XSLT.pm (-7 / +17 lines)
Lines 42-47 BEGIN { Link Here
42
    $VERSION = 3.07.00.049;
42
    $VERSION = 3.07.00.049;
43
    @ISA = qw(Exporter);
43
    @ISA = qw(Exporter);
44
    @EXPORT = qw(
44
    @EXPORT = qw(
45
        &XSLTGetFilename
45
        &XSLTParse4Display
46
        &XSLTParse4Display
46
        &GetURI
47
        &GetURI
47
    );
48
    );
Lines 156-164 sub _get_best_default_xslt_filename { Link Here
156
    return $xslfilename;
157
    return $xslfilename;
157
}
158
}
158
159
159
sub XSLTParse4Display {
160
sub XSLTGetFilename {
160
    my ( $biblionumber, $orig_record, $xslsyspref, $fixamps, $hidden_items ) = @_;
161
    my ( $marcflavour, $xslsyspref ) = @_;
161
    my $xslfilename = C4::Context->preference($xslsyspref);
162
163
    my $xslfilename = $marcflavour eq C4::Context->preference('marcflavour') ? C4::Context->preference($xslsyspref) : 'default';
162
    if ( $xslfilename =~ /^\s*"?default"?\s*$/i ) {
164
    if ( $xslfilename =~ /^\s*"?default"?\s*$/i ) {
163
        my $htdocs;
165
        my $htdocs;
164
        my $theme;
166
        my $theme;
Lines 167-188 sub XSLTParse4Display { Link Here
167
        if ($xslsyspref eq "XSLTDetailsDisplay") {
169
        if ($xslsyspref eq "XSLTDetailsDisplay") {
168
            $htdocs  = C4::Context->config('intrahtdocs');
170
            $htdocs  = C4::Context->config('intrahtdocs');
169
            $theme   = C4::Context->preference("template");
171
            $theme   = C4::Context->preference("template");
170
            $xslfile = C4::Context->preference('marcflavour') .
172
            $xslfile = $marcflavour .
171
                       "slim2intranetDetail.xsl";
173
                       "slim2intranetDetail.xsl";
172
        } elsif ($xslsyspref eq "XSLTResultsDisplay") {
174
        } elsif ($xslsyspref eq "XSLTResultsDisplay") {
173
            $htdocs  = C4::Context->config('intrahtdocs');
175
            $htdocs  = C4::Context->config('intrahtdocs');
174
            $theme   = C4::Context->preference("template");
176
            $theme   = C4::Context->preference("template");
175
            $xslfile = C4::Context->preference('marcflavour') .
177
            $xslfile = $marcflavour .
176
                        "slim2intranetResults.xsl";
178
                        "slim2intranetResults.xsl";
177
        } elsif ($xslsyspref eq "OPACXSLTDetailsDisplay") {
179
        } elsif ($xslsyspref eq "OPACXSLTDetailsDisplay") {
178
            $htdocs  = C4::Context->config('opachtdocs');
180
            $htdocs  = C4::Context->config('opachtdocs');
179
            $theme   = C4::Context->preference("opacthemes");
181
            $theme   = C4::Context->preference("opacthemes");
180
            $xslfile = C4::Context->preference('marcflavour') .
182
            $xslfile = $marcflavour .
181
                       "slim2OPACDetail.xsl";
183
                       "slim2OPACDetail.xsl";
182
        } elsif ($xslsyspref eq "OPACXSLTResultsDisplay") {
184
        } elsif ($xslsyspref eq "OPACXSLTResultsDisplay") {
183
            $htdocs  = C4::Context->config('opachtdocs');
185
            $htdocs  = C4::Context->config('opachtdocs');
184
            $theme   = C4::Context->preference("opacthemes");
186
            $theme   = C4::Context->preference("opacthemes");
185
            $xslfile = C4::Context->preference('marcflavour') .
187
            $xslfile = $marcflavour .
186
                       "slim2OPACResults.xsl";
188
                       "slim2OPACResults.xsl";
187
        }
189
        }
188
        $xslfilename = _get_best_default_xslt_filename($htdocs, $theme, $lang, $xslfile);
190
        $xslfilename = _get_best_default_xslt_filename($htdocs, $theme, $lang, $xslfile);
Lines 193-198 sub XSLTParse4Display { Link Here
193
        $xslfilename =~ s/\{langcode\}/$lang/;
195
        $xslfilename =~ s/\{langcode\}/$lang/;
194
    }
196
    }
195
197
198
    return $xslfilename;
199
}
200
201
sub XSLTParse4Display {
202
    my ( $biblionumber, $orig_record, $xslsyspref, $fixamps, $hidden_items ) = @_;
203
204
    my $xslfilename = XSLTGetFilename( C4::Context->preference( 'marcflavour' ), $xslsyspref );
205
196
    # grab the XML, run it through our stylesheet, push it out to the browser
206
    # grab the XML, run it through our stylesheet, push it out to the browser
197
    my $record = transformMARCXML4XSLT($biblionumber, $orig_record);
207
    my $record = transformMARCXML4XSLT($biblionumber, $orig_record);
198
    #return $record->as_formatted();
208
    #return $record->as_formatted();
(-)a/Makefile.PL (-2 / +2 lines)
Lines 531-538 push @{ $pl_files->{'rewrite-config.PL'} }, ( Link Here
531
);
531
);
532
if ($config{'INSTALL_PAZPAR2'} eq 'yes') {
532
if ($config{'INSTALL_PAZPAR2'} eq 'yes') {
533
    push @{ $pl_files->{'rewrite-config.PL'} }, (
533
    push @{ $pl_files->{'rewrite-config.PL'} }, (
534
        'blib/PAZPAR2_CONF_DIR/koha-biblios.xml',
534
        'blib/PAZPAR2_CONF_DIR/generic-settings.xml',
535
        'blib/PAZPAR2_CONF_DIR/pazpar2.xml'
535
        'blib/PAZPAR2_CONF_DIR/pazpar2.xml',
536
    );
536
    );
537
}
537
}
538
$config{'ZEBRA_AUTH_CFG'} = $config{'AUTH_INDEX_MODE'} eq 'dom'
538
$config{'ZEBRA_AUTH_CFG'} = $config{'AUTH_INDEX_MODE'} eq 'dom'
(-)a/admin/external_targets.pl (+129 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
#
3
# This file is part of Koha.
4
#
5
# Copyright 2013 Jesse Weaver
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
#
20
21
use Modern::Perl;
22
23
use CGI;
24
25
use C4::Auth;
26
use C4::Context;
27
use C4::Branch;
28
use C4::Output;
29
use URI::Escape;
30
31
our $dbh = C4::Context->dbh;
32
our $input = new CGI;
33
34
our ( $template, $loggedinuser, $cookie ) = get_template_and_user( {
35
    template_name => "admin/external-targets.tt",
36
    query => $input,
37
    type => "intranet",
38
    authnotrequired => 0,
39
    flagsrequired => {parameters => 'parameters_remaining_permissions'},
40
    debug => 1,
41
} );
42
43
our $op = $input->param( 'op' ) // 'show';
44
$template->{VARS}->{op} = $op;
45
46
if ( $op eq 'show' ) {
47
    show_external_targets();
48
} elsif ( $op eq 'add' ) {
49
    show_edit_form();
50
} elsif ( $op eq 'edit' ) {
51
    show_edit_form();
52
} elsif ( $op eq 'save' ) {
53
    save_target();
54
} elsif ( $op eq 'delete' ) {
55
    delete_target();
56
}
57
58
output_html_with_http_headers $input, $cookie, $template->output;
59
60
sub show_external_targets {
61
    $template->{VARS}->{saved_id} = $input->param( 'saved_id' );
62
    $template->{VARS}->{deleted_name} = $input->param( 'deleted_name' );
63
    $template->{VARS}->{targets} = $dbh->selectall_arrayref( q{
64
        SELECT *
65
        FROM external_targets
66
    }, { Slice => {} } );
67
}
68
69
sub show_edit_form {
70
    $template->{VARS}->{branches} = GetBranchesLoop( undef, 0 );
71
    $template->{VARS}->{syntaxes} = [ 'MARC21', 'UNIMARC', 'NORMARC' ];
72
    $template->{VARS}->{encodings} = { 'utf8' => 'UTF-8', 'marc8' => 'MARC-8' };
73
74
    my $target_id;
75
    if ( $target_id = $input->param( 'target_id' ) ) {
76
        $template->{VARS}->{target} = $dbh->selectrow_hashref( q{ SELECT * FROM external_targets WHERE target_id = ? }, {}, $target_id );
77
78
        my $available_branches = $dbh->selectall_hashref( q{ SELECT * FROM external_target_restrictions WHERE target_id = ? }, 'branchcode', {}, $target_id );
79
80
        foreach my $branch ( @{ $template->{VARS}->{branches} } ) {
81
            $branch->{selected} = 1 if ( $available_branches->{$branch->{branchcode}} );
82
        }
83
    }
84
}
85
86
sub save_target {
87
    my $target_id;
88
    if ( $target_id = $input->param( 'target_id' ) ) {
89
        $dbh->do( q{
90
            UPDATE external_targets
91
            SET name = ?, host = ?, port = ?, db = ?, userid = ?, password = ?, syntax = ?, encoding = ?
92
            WHERE target_id = ?
93
        }, {}, map { $input->param( $_ ) // '' } qw( name host port db userid password syntax encoding target_id ) );
94
    } else {
95
        $dbh->do( q{
96
            INSERT
97
            INTO external_targets(name, host, port, db, userid, password, syntax, encoding)
98
            VALUES(?, ?, ?, ?, ?, ?, ?, ?)
99
        }, {}, map { $input->param( $_ ) // '' } qw( name host port db userid password syntax encoding ) );
100
        $target_id = $dbh->last_insert_id( undef, undef, undef, undef );
101
    }
102
103
    $dbh->do( q{
104
        DELETE
105
        FROM external_target_restrictions
106
        WHERE target_id = ?
107
    }, {}, $target_id );
108
109
    foreach my $branchcode ( $input->param( 'branch' ) ) {
110
        $dbh->do( q{
111
            INSERT
112
            INTO external_target_restrictions(branchcode, target_id)
113
            VALUES(?, ?)
114
        }, {}, $branchcode, $target_id );
115
    }
116
117
    print $input->redirect( '/cgi-bin/koha/admin/external_targets.pl?saved_id=' . $target_id );
118
    exit;
119
}
120
121
sub delete_target {
122
    my ($target_id, $target);
123
124
    return unless ( $target_id = $input->param( 'target_id' ) and $target = $dbh->selectrow_hashref( q{ SELECT * FROM external_targets WHERE target_id = ? }, {}, $target_id ) );
125
126
    $dbh->do( q{ DELETE FROM external_targets WHERE target_id = ? }, {}, $target_id );
127
128
    print $input->redirect( '/cgi-bin/koha/admin/external_targets.pl?deleted_name=' . uri_escape( $target->{'name'} ) );
129
}
(-)a/etc/koha-conf.xml (-13 lines)
Lines 19-37 Link Here
19
<listen id="publicserver" >tcp:@:__ZEBRA_SRU_BIBLIOS_PORT__</listen>
19
<listen id="publicserver" >tcp:@:__ZEBRA_SRU_BIBLIOS_PORT__</listen>
20
-->
20
-->
21
21
22
<!-- Settings for special biblio server instance for PazPar2.
23
     Because PazPar2 only connects to a Z39.50 server using TCP/IP,
24
     it cannot use the Unix-domain socket that biblioserver uses.
25
     Therefore, a custom server is defined. -->
26
__PAZPAR2_TOGGLE_XML_PRE__
27
<listen id="mergeserver">tcp:@:__MERGE_SERVER_PORT__</listen>
28
<server id="mergeserver"  listenref="mergeserver"> 
29
    <directory>__ZEBRA_DATA_DIR__/biblios</directory>
30
    <config>__ZEBRA_CONF_DIR__/__ZEBRA_BIB_CFG__</config>
31
    <cql2rpn>__ZEBRA_CONF_DIR__/pqf.properties</cql2rpn>
32
</server>
33
__PAZPAR2_TOGGLE_XML_POST__
34
35
<!-- BIBLIOGRAPHIC RECORDS -->
22
<!-- BIBLIOGRAPHIC RECORDS -->
36
<server id="biblioserver"  listenref="biblioserver"> 
23
<server id="biblioserver"  listenref="biblioserver"> 
37
    <directory>__ZEBRA_DATA_DIR__/biblios</directory>
24
    <directory>__ZEBRA_DATA_DIR__/biblios</directory>
(-)a/etc/koha-httpd.conf (-2 / +13 lines)
Lines 32-38 Link Here
32
   </Directory>
32
   </Directory>
33
33
34
   # Secure internal stuff
34
   # Secure internal stuff
35
   <DirectoryMatch "__OPAC_WWW_DIR__/.*/(modules|xslt|includes)">
35
   <DirectoryMatch "__OPAC_WWW_DIR__/.*/(modules|includes)">
36
      Order deny,allow
36
      Order deny,allow
37
      Deny from all
37
      Deny from all
38
   </DirectoryMatch>
38
   </DirectoryMatch>
Lines 113-118 Link Here
113
     RewriteRule ^/isbn/([^\/]*)/?$ /search?q=isbn:$1 [PT]
113
     RewriteRule ^/isbn/([^\/]*)/?$ /search?q=isbn:$1 [PT]
114
     RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT]
114
     RewriteRule ^/issn/([^\/]*)/?$ /search?q=issn:$1 [PT]
115
   </IfModule>
115
   </IfModule>
116
117
   __PAZPAR2_TOGGLE_HTTPD_PRE__
118
     <Proxy *>
119
         AddDefaultCharset off
120
         Order deny,allow
121
         Allow from all
122
     </Proxy>
123
124
     ProxyRequests off
125
     ProxyPass /pazpar2/search.pz2 http://__PAZPAR2_HOST__:__PAZPAR2_PORT__/search.pz2
126
   __PAZPAR2_TOGGLE_HTTPD_POST__
116
</VirtualHost>
127
</VirtualHost>
117
128
118
## Intranet
129
## Intranet
Lines 149-155 Link Here
149
   </Directory>
160
   </Directory>
150
161
151
   # Secure internal stuff
162
   # Secure internal stuff
152
   <DirectoryMatch "__INTRANET_WWW_DIR__/.*/(modules|xslt|includes)">
163
   <DirectoryMatch "__INTRANET_WWW_DIR__/.*/(modules|includes)">
153
      Order deny,allow
164
      Order deny,allow
154
      Deny from all
165
      Deny from all
155
   </DirectoryMatch>
166
   </DirectoryMatch>
(-)a/etc/pazpar2/generic-settings.xml (+21 lines)
Line 0 Link Here
1
<settings target="*">
2
  <!-- This file introduces default settings for pazpar2 -->
3
  <!-- $Id: loc.xml,v 1.2 2007-07-10 13:43:07 adam Exp $ -->
4
5
  <!-- mapping for unqualified search -->
6
  <set name="pz:cclmap:term" value="u=1016 t=l,r s=al"/>
7
8
  <!-- field-specific mappings -->
9
10
  <set name="pz:cclmap:au" value="u=1004 s=al"/>
11
  <set name="pz:cclmap:ti" value="u=4 s=al"/>
12
  <set name="pz:cclmap:su" value="u=21 s=al"/>
13
  <set name="pz:cclmap:isbn" value="u=7"/>
14
  <set name="pz:cclmap:issn" value="u=8"/>
15
  <set name="pz:cclmap:date" value="u=30 r=r"/>
16
17
  <!-- Retrieval settings -->
18
19
  <set name="pz:elements" value="F"/>
20
21
</settings>
(-)a/etc/pazpar2/pazpar2.xml (-11 / +8 lines)
Lines 4-35 Link Here
4
  
4
  
5
  <server>
5
  <server>
6
    <listen port="__PAZPAR2_PORT__"/>
6
    <listen port="__PAZPAR2_PORT__"/>
7
    <settings src="__PAZPAR2_CONF_DIR__/koha-biblios.xml"/>
7
    <settings src="__PAZPAR2_CONF_DIR__/generic-settings.xml"/>
8
8
9
    <relevance>
9
    <relevance>
10
      <icu_chain id="relevance" locale="el">
10
      <icu_chain id="relevance" locale="en">
11
	<normalize rule="[:Control:] Any-Remove"/>
11
	<transform rule="[:Control:] Any-Remove"/>
12
	<tokenize rule="l"/>
12
	<tokenize rule="l"/>
13
	<normalize rule="[[:WhiteSpace:][:Punctuation:]] Remove"/>
13
	<transform rule="[[:WhiteSpace:][:Punctuation:]] Remove"/>
14
	<casemap rule="l"/>
14
	<casemap rule="l"/>
15
	<index/>
16
      </icu_chain>
15
      </icu_chain>
17
    </relevance>
16
    </relevance>
18
17
19
    <sort>
18
    <sort>
20
      <icu_chain id="sort" locale="el">
19
      <icu_chain id="sort" locale="en">
21
	<normalize rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/>
20
	<transform rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/>
22
	<casemap rule="l"/>
21
	<casemap rule="l"/>
23
	<sortkey/>
24
      </icu_chain>
22
      </icu_chain>
25
    </sort>
23
    </sort>
26
    
24
    
27
    <mergekey>
25
    <mergekey>
28
      <icu_chain id="mergekey" locale="el">
26
      <icu_chain id="mergekey" locale="en">
29
	<tokenize rule="l"/>
27
	<tokenize rule="l"/>
30
	<normalize rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/>
28
	<transform rule="[[:Control:][:WhiteSpace:][:Punctuation:]] Remove"/>
31
	<casemap rule="l"/>
29
	<casemap rule="l"/>
32
	<index/>
33
      </icu_chain>
30
      </icu_chain>
34
    </mergekey>
31
    </mergekey>
35
    
32
    
(-)a/etc/pazpar2/unimarc-work-groups.xsl (+98 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<xsl:stylesheet
3
    version="1.0"
4
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5
    xmlns:pz="http://www.indexdata.com/pazpar2/1.0"
6
    xmlns:marc="http://www.loc.gov/MARC21/slim">
7
8
 <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/>
9
10
11
  <xsl:template match="/marc:record">
12
    <pz:record>
13
14
      <xsl:for-each select="marc:controlfield[@tag='001']">
15
        <pz:metadata type="id">
16
          <xsl:value-of select="."/>
17
        </pz:metadata>
18
      </xsl:for-each>
19
20
      <!-- -->
21
      <xsl:for-each select="marc:datafield[@tag='020']">
22
	<xsl:if test="marc:subfield[@code='a'] = 'US'">
23
          <pz:metadata type="lccn">
24
	    <xsl:value-of select="marc:subfield[@code='b']"/>
25
	  </pz:metadata>
26
	</xsl:if>
27
      </xsl:for-each>
28
29
      <xsl:for-each select="marc:datafield[@tag='010']">
30
        <pz:metadata type="isbn">
31
	  <xsl:value-of select="marc:subfield[@code='a']"/>
32
	</pz:metadata>
33
      </xsl:for-each>
34
35
      <xsl:for-each select="marc:datafield[@tag='011']">
36
        <pz:metadata type="issn">
37
	  <xsl:value-of select="marc:subfield[@code='a']"/>
38
	</pz:metadata>
39
      </xsl:for-each>
40
41
42
      <xsl:for-each select="marc:datafield[@tag='200']">
43
        <pz:metadata type="work-title">
44
          <xsl:value-of select="marc:subfield[@code='a']"/>
45
        </pz:metadata>
46
      </xsl:for-each>
47
48
49
      <!-- Date of Pulbication -->
50
      <xsl:for-each select="marc:datafield[@tag='210']">
51
        <pz:metadata type="date">
52
	  <xsl:value-of select="marc:subfield[@code='d']"/>
53
	</pz:metadata>
54
      </xsl:for-each>
55
56
      <!--  Usmarc 650 maps to unimarc 606 and marc21 653 maps to unimarc 610 -->
57
      <xsl:for-each select="marc:datafield[@tag='606' or @tag='610']">
58
	<pz:metadata type="subject">
59
	  <xsl:value-of select="marc:subfield[@code='a']"/>
60
	</pz:metadata>
61
      </xsl:for-each>
62
63
      <xsl:for-each select="marc:datafield[@tag &gt;= 300 and @tag &lt;= 345]
64
                            [@tag != '325']">
65
        <pz:metadata type="description">
66
            <xsl:value-of select="*/text()"/>
67
        </pz:metadata>
68
      </xsl:for-each>
69
70
71
      <!-- Author : primary, alternative and secondary responsibility (equivalent marc21 tags : 100, 700 -->
72
      <xsl:for-each select="marc:datafield[@tag='700' or @tag='701' or @tag='702']">
73
	<pz:metadata type="work-author">
74
	  <xsl:value-of select="marc:subfield[@code='a']"/>
75
          <xsl:text>, </xsl:text>
76
	  <xsl:value-of select="marc:subfield[@code='b']"/>
77
	</pz:metadata>
78
      </xsl:for-each>
79
80
      <!-- Author : marc21 tag 720 maps to unimarc 730
81
      <xsl:for-each select="marc:datafield[@tag='730']">
82
	<pz:metadata type="author">
83
	  <xsl:value-of select="marc:subfield[@code='a']"/>
84
	</pz:metadata>
85
      </xsl:for-each>
86
      -->
87
88
      <!-- -->
89
      <xsl:for-each select="marc:datafield[@tag='856']">
90
	<pz:metadata type="url">
91
	  <xsl:value-of select="marc:subfield[@code='u']"/>
92
	</pz:metadata>
93
      </xsl:for-each>
94
95
    </pz:record>
96
  </xsl:template>
97
98
</xsl:stylesheet>
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 263-268 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
263
('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'),
263
('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'),
264
('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'),
264
('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'),
265
('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'),
265
('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'),
266
('OPACSearchExternalTargets','0',NULL,'Whether to search external targets in the OPAC','YesNo'),
266
('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}&amp;title={TITLE}&amp;st=xl&amp;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'),
267
('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}&amp;title={TITLE}&amp;st=xl&amp;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'),
267
('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'),
268
('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'),
268
('OpacSeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings (OPAC)','Choice'),
269
('OpacSeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings (OPAC)','Choice'),
(-)a/installer/data/mysql/updatedatabase.pl (-1 / +35 lines)
Lines 7957-7963 if (CheckVersion($DBversion)) { Link Here
7957
    SetVersion($DBversion);
7957
    SetVersion($DBversion);
7958
}
7958
}
7959
7959
7960
$DBversion = "3.15.00.017";
7961
if(CheckVersion($DBversion)) {
7960
if(CheckVersion($DBversion)) {
7962
    $dbh->do(q{
7961
    $dbh->do(q{
7963
        UPDATE systempreferences
7962
        UPDATE systempreferences
Lines 8243-8248 if ( CheckVersion($DBversion) ) { Link Here
8243
    SetVersion ($DBversion);
8242
    SetVersion ($DBversion);
8244
}
8243
}
8245
8244
8245
8246
$DBversion = "3.15.00.XXX";
8247
if(CheckVersion($DBversion)) {
8248
    $dbh->do(
8249
"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OPACSearchExternalTargets','0','Whether to search external targets in the OPAC','','YesNo')"
8250
    );
8251
    $dbh->do( q{
8252
CREATE TABLE `external_targets` (
8253
  `target_id` int(11) NOT NULL AUTO_INCREMENT,
8254
  `host` varchar(128) NOT NULL,
8255
  `port` int(11) NOT NULL,
8256
  `db` varchar(64) NOT NULL,
8257
  `userid` varchar(64) DEFAULT '',
8258
  `password` varchar(64) DEFAULT '',
8259
  `name` varchar(64) NOT NULL,
8260
  `syntax` varchar(64) NOT NULL,
8261
  `encoding` varchar(16) DEFAULT 'MARC-8',
8262
  PRIMARY KEY (`target_id`)
8263
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
8264
    } );
8265
    $dbh->do( q{
8266
CREATE TABLE `external_target_restrictions` (
8267
  `branchcode` varchar(10) NOT NULL,
8268
  `target_id` int(11) NOT NULL,
8269
  KEY `branchcode` (`branchcode`),
8270
  KEY `target_id` (`target_id`),
8271
  CONSTRAINT `external_target_restrictions_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
8272
  CONSTRAINT `external_target_restrictions_ibfk_2` FOREIGN KEY (`target_id`) REFERENCES `external_targets` (`target_id`) ON DELETE CASCADE
8273
) ENGINE=InnoDB DEFAULT CHARSET=utf8
8274
    } );
8275
    print "Upgrade to $DBversion done (Bug 10486 - Allow external Z39.50 targets to be searched from the OPAC)\n";
8276
    SetVersion($DBversion);
8277
}
8278
8279
8246
=head1 FUNCTIONS
8280
=head1 FUNCTIONS
8247
8281
8248
=head2 TableExists($table)
8282
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css (+14 lines)
Lines 274-279 tr.even td, tr.even.highlight td { Link Here
274
    border-right : 1px solid #BCBCBC;
274
    border-right : 1px solid #BCBCBC;
275
}
275
}
276
276
277
tr.highlight td {
278
	background-color : #F6F6F6;
279
	border-color : #BCBCBC;
280
}
281
282
tr.highlight th[scope=row] {
283
	background-color : #DDDDDD;
284
	border-color : #BCBCBC;
285
}
286
277
td.od {
287
td.od {
278
	color : #cc0000;
288
	color : #cc0000;
279
	font-weight : bold;
289
	font-weight : bold;
Lines 291-296 tr.odd.onissue td { Link Here
291
	background-color: #FFFFE1;
301
	background-color: #FFFFE1;
292
}
302
}
293
303
304
tr.updated td {
305
    background-color: #FFFFBB;
306
}
307
294
tfoot td {
308
tfoot td {
295
	background-color : #f3f3f3;
309
	background-color : #f3f3f3;
296
	font-weight : bold;
310
	font-weight : bold;
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc (+1 lines)
Lines 45-50 Link Here
45
    <li><a href="/cgi-bin/koha/admin/classsources.pl">Classification sources</a></li>
45
    <li><a href="/cgi-bin/koha/admin/classsources.pl">Classification sources</a></li>
46
    <li><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></li>
46
    <li><a href="/cgi-bin/koha/admin/matching-rules.pl">Record matching rules</a></li>
47
    <li><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI sets configuration</a></li>
47
    <li><a href="/cgi-bin/koha/admin/oai_sets.pl">OAI sets configuration</a></li>
48
    <li><a href="/cgi-bin/koha/admin/external_targets.pl">External search targets</a></li>
48
</ul>
49
</ul>
49
50
50
<h5>Acquisition parameters</h5>
51
<h5>Acquisition parameters</h5>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (+2 lines)
Lines 81-86 Link Here
81
      <dt><a href="/cgi-bin/koha/admin/searchengine/solr/indexes.pl">Search engine configuration</a></dt>
81
      <dt><a href="/cgi-bin/koha/admin/searchengine/solr/indexes.pl">Search engine configuration</a></dt>
82
      <dd>Manage indexes, facets, and their mappings to MARC fields and subfields.</dd>
82
      <dd>Manage indexes, facets, and their mappings to MARC fields and subfields.</dd>
83
    [% END %]
83
    [% END %]
84
    <dt><a href="/cgi-bin/koha/admin/external_targets.pl">External search targets</a></dt>
85
    <dd>Define external search targets that can be searched from the OPAC.</dd>
84
</dl>
86
</dl>
85
87
86
<h3>Acquisition parameters</h3>
88
<h3>Acquisition parameters</h3>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/external-targets.tt (+178 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% IF op == 'show' %]
3
<title>Koha &rsaquo; Administration &rsaquo; External targets</title>
4
[% ELSIF op == 'add' %]
5
<title>Koha &rsaquo; Administration &rsaquo; External targets &rsaquo; Create an external target</title>
6
[% ELSIF op == 'edit' %]
7
<title>Koha &rsaquo; Administration &rsaquo; External targets &rsaquo; Editing '[% target.name %]'</title>
8
[% END %]
9
[% INCLUDE 'doc-head-close.inc' %]
10
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
11
[% INCLUDE 'datatables.inc' %]
12
<script type="text/javascript">
13
//<![CDATA[
14
 $(document).ready(function() {
15
    [% IF ( targets.size ) %]
16
    var dTable = $("#targets").dataTable( $.extend( true, {}, dataTablesDefaults, {
17
        aoColumnDefs: [
18
            { aTargets: [ 1,2,3,4,5 ], bSortable: false, bSearchable: false },
19
        ],
20
        asStripeClasses: [ '', 'highlight' ],
21
        bPaginate: false,
22
    } ) );
23
24
    [% IF saved_id %]
25
    $( '#targets tr[data-targetid=[% saved_id %]]' ).addClass( 'updated' );
26
    [% END %]
27
28
    $( '#targets .delete' ).click( function() {
29
        return confirm( _("Are you sure you wish to delete this target?") );
30
    } );
31
    [% END %]
32
 });
33
//]]>
34
</script>
35
36
</head>
37
<body id="admin_z3950servers" class="admin">
38
[% INCLUDE 'header.inc' %]
39
[% INCLUDE 'cat-search.inc' %]
40
41
[% IF op == 'show' %]
42
43
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; External targets</div>
44
45
[% ELSIF op == 'add' %]
46
47
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; <a href="/cgi-bin/koha/admin/external_targets.pl">External targets</a> &rsaquo; Create an external target</div>
48
49
[% ELSIF op == 'edit' %]
50
51
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; <a href="/cgi-bin/koha/admin/external_targets.pl">External targets</a> &rsaquo; Editing '[% target.name %]'</div>
52
53
[% END %]
54
55
<div id="doc3" class="yui-t2">
56
<div id="bd">
57
58
<div id="yui-main"><div class="yui-b">
59
60
[% IF op == 'show' %]
61
62
[% IF deleted_name %]
63
<div class="alert">
64
    <p>Deleted target '[% deleted_name %]'</p>
65
</div>
66
[% END %]
67
68
<div id="toolbar" class="btn-toolbar">
69
    <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>
70
</div>
71
72
<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>
73
74
[% IF targets.size %]
75
<table id="targets">
76
    <thead><tr><th>Name</th><th>Connection</th><th>Login</th><th>Syntax</th><th>Encoding</th><th>&nbsp;</th><th>&nbsp;</th></tr></thead>
77
    <tbody>
78
        [% FOREACH target = targets %]
79
        <tr data-targetid="[% target.target_id %]">
80
            <td>[% target.name %]</td>
81
            <td>[% target.host %]:[% target.port %]/[% target.db %]</td>
82
            <td>[% IF target.userid %][% target.userid %] / [% IF target.password %]********[% ELSE %]<span class="hint">none</span>[% END %][% ELSE %]<span class="hint">none</span>[% END %]</td>
83
            <td>[% target.syntax %]</td>
84
            <td>
85
                [% IF target.encoding == 'marc8' %]
86
                MARC-8
87
                [% ELSIF target.encoding == 'utf8' %]
88
                UTF-8
89
                [% END %]
90
            </td>
91
            <td><a href="/cgi-bin/koha/admin/external_targets.pl?op=edit&amp;target_id=[% target.target_id %]">Edit</a></td>
92
            <td><a class="delete" href="/cgi-bin/koha/admin/external_targets.pl?op=delete&amp;target_id=[% target.target_id %]">Delete</a></td>
93
        </tr>
94
        [% END %]
95
    </tbody>
96
</table>
97
[% ELSE %]
98
<p>No external targets have been defined yet.</p>
99
[% END %]
100
101
[% ELSIF op == 'add' || op == 'edit' %]
102
103
<form action="/cgi-bin/koha/admin/external_targets.pl" method="POST">
104
    [% IF op == 'add' %]
105
    <h1>Create an external target</h1>
106
    [% ELSIF op == 'edit' %]
107
    <h1>Editing '[% target.name %]'</h1>
108
    [% END %]
109
110
    <input type="hidden" name="op" value="save">
111
    <input type="hidden" name="target_id" value="[% target.target_id %]">
112
113
    <fieldset class="rows">
114
        <ol>
115
            <li><label for="name">Name:</label> <input type="text" id="name" name="name" value="[% target.name %]" required></li>
116
            <li><label for="host">Host:</label> <input type="text" id="host" name="host" value="[% target.host %]" required></li>
117
            <li><label for="port">Port:</label> <input type="num" id="port" name="port" value="[% target.port %]" required></li>
118
            <li><label for="db">Database:</label> <input type="text" id="db" name="db" value="[% target.db %]" required></li>
119
            <li><label for="userid">User:</label> <input type="text" id="userid" name="userid" value="[% target.userid %]"></li>
120
            <li><label for="password">Password:</label> <input type="password" id="password" name="password" value="[% target.password %]" autocomplete="off"></li>
121
            <li>
122
                <label for="syntax">Syntax:</label>
123
                <select id="syntax" name="syntax">
124
                    [% FOREACH syntax = syntaxes %]
125
                    [% IF syntax == target.syntax %]
126
                    <option selected>[% syntax %]
127
                    [% ELSE %]
128
                    <option>[% syntax %]</option>
129
                    [% END %]
130
                    [% END %]
131
                </select>
132
            </li>
133
            <li>
134
                <label for="encoding">Encoding:</label>
135
                <select id="encoding" name="encoding">
136
                    [% FOREACH encoding = encodings %]
137
                    [% IF encoding.key == target.encoding %]
138
                    <option value="[% encoding.key %]" selected>[% encoding.value %]
139
                    [% ELSE %]
140
                    <option value="[% encoding.key %]">[% encoding.value %]</option>
141
                    [% END %]
142
                    [% END %]
143
                </select>
144
            </li>
145
            <li>
146
                <label>Restricted libraries:</label>
147
                <fieldset>
148
                    <legend>Not available to patrons from:</legend>
149
                    <p>Only targets with no restrictions will be shown to anonymous (not logged in) users.</p>
150
                    <ol>
151
                        [% FOREACH branch = branches %]
152
                        <li>
153
                            <label for="branch-[% branch.branchcode %]">[% branch.branchname %]</label>
154
                            [% IF branch.selected %]
155
                            <input type="checkbox" id="branch-[% branch.branchcode %]" name="branch" value="[% branch.branchcode %]" checked />
156
                            [% ELSE %]
157
                            <input type="checkbox" id="branch-[% branch.branchcode %]" name="branch" value="[% branch.branchcode %]" />
158
                            [% END %]
159
                        </li>
160
                        [% END %]
161
                    </ol>
162
                </fieldset>
163
            </li>
164
        </ol>
165
    </fieldset>
166
167
    <fieldset class="action"><input type="submit" value="Save"></fieldset>
168
</form>
169
170
[% END %]
171
172
</div></div>
173
<div class="yui-b">
174
[% INCLUDE 'admin-menu.inc' %]
175
</div>
176
177
</div>
178
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref (+7 lines)
Lines 444-449 OPAC: Link Here
444
                  yes: Allow
444
                  yes: Allow
445
                  no: Do not allow
445
                  no: Do not allow
446
            - users to add a note when placing a hold.
446
            - users to add a note when placing a hold.
447
        -
448
            - pref: OPACSearchExternalTargets
449
              default: 0
450
              choices:
451
                  yes: Search
452
                  no: "Don't search"
453
            - external targets from the OPAC. (Check with your system administrator first to ensure that Pazpar2 is enabled and running.)
447
454
448
    Policy:
455
    Policy:
449
        -
456
        -
(-)a/koha-tmpl/opac-tmpl/bootstrap/css/opac.css (-1 / +2691 lines)
Line 1 Link Here
1
.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}}
1
.shadowed {
2
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
3
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
4
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
5
}
6
body {
7
  background-color: #EAEAE6;
8
}
9
/* Sticky footer styles */
10
html,
11
body {
12
  height: 100%;
13
  /* The html and body elements cannot have any padding or margin. */
14
}
15
.no-js .dateformat {
16
  display: inline;
17
  white-space: nowrap;
18
}
19
.no-js .modal-body {
20
  padding: 0;
21
}
22
.js .dateformat {
23
  display: none;
24
}
25
/* Wrapper for page content to push down footer */
26
#wrap {
27
  min-height: 100%;
28
  height: auto !important;
29
  height: 100%;
30
  /* Negative indent footer by it's height */
31
}
32
/* Set the fixed height of the footer here */
33
.popup {
34
  padding-left: 0;
35
  padding-right: 0;
36
}
37
a {
38
  color: #0076b2;
39
}
40
a.cancel {
41
  padding-left: 1em;
42
}
43
a:visited {
44
  color: #0076b2;
45
}
46
a.title {
47
  font-weight: bold;
48
  font-size: 108%;
49
}
50
a.btn-primary:visited {
51
  color: #FFF;
52
}
53
.ui-widget-content a,
54
.ui-widget-content a:visited {
55
  color: #0076b2;
56
}
57
h1 {
58
  font-size: 140%;
59
  line-height: 150%;
60
}
61
h1#libraryname {
62
  background: transparent url(../images/logo-koha.png) no-repeat scroll 0%;
63
  border: 0;
64
  float: left !important;
65
  margin: 0;
66
  padding: 0;
67
  width: 120px;
68
}
69
h1#libraryname a {
70
  border: 0;
71
  cursor: pointer;
72
  display: block;
73
  height: 0px !important;
74
  margin: 0;
75
  overflow: hidden;
76
  padding: 40px 0 0;
77
  text-decoration: none;
78
  width: 120px;
79
}
80
h2 {
81
  font-size: 130%;
82
  line-height: 150%;
83
}
84
h3 {
85
  font-size: 120%;
86
  line-height: 150%;
87
}
88
h4 {
89
  font-size: 110%;
90
}
91
h5 {
92
  font-size: 100%;
93
}
94
caption {
95
  font-size: 120%;
96
  font-weight: bold;
97
  margin: 0;
98
  text-align: left;
99
}
100
input,
101
textarea {
102
  width: auto;
103
}
104
.input-fluid {
105
  width: 50%;
106
}
107
legend {
108
  font-size: 110%;
109
  font-weight: bold;
110
}
111
table,
112
td {
113
  background-color: #FFF;
114
}
115
td .btn {
116
  white-space: nowrap;
117
}
118
td .btn-link {
119
  padding: 0;
120
}
121
#advsearches label,
122
#booleansearch label {
123
  display: inline;
124
}
125
#basketcount {
126
  display: inline;
127
  margin: 0;
128
  padding: 0;
129
}
130
#basketcount span {
131
  background-color: #FFC;
132
  color: #000;
133
  display: inline;
134
  font-size: 80%;
135
  font-weight: normal;
136
  margin: 0 0 0 .9em;
137
  padding: 0 .3em 0 .3em;
138
  -webkit-border-radius: 3px;
139
  -moz-border-radius: 3px;
140
  border-radius: 3px;
141
}
142
#members {
143
  display: block;
144
}
145
#members p {
146
  color: #EEE;
147
}
148
#members a {
149
  color: #A6D8ED;
150
  font-weight: bold;
151
}
152
#members a.logout {
153
  color: #E8583C;
154
  padding: 0 .3em 0 .3em;
155
}
156
#koha_url p {
157
  color: #666666;
158
  float: right;
159
  margin: 0;
160
}
161
#moresearches {
162
  margin: .5em 0;
163
  padding: 0 .8em;
164
}
165
#moresearches li {
166
  display: inline;
167
  white-space: nowrap;
168
}
169
#moresearches li:after {
170
  content: " | ";
171
}
172
#moresearches ul {
173
  margin: 0;
174
}
175
#moresearches li:last-child:after {
176
  content: "";
177
}
178
#news {
179
  margin: .5em 0;
180
}
181
#opacheader {
182
  background-color: #DDD;
183
}
184
#selections {
185
  font-weight: bold;
186
}
187
.actions a {
188
  white-space: nowrap;
189
  /* List contents remove from list link */
190
}
191
.actions a.hold {
192
  background-image: url("../images/sprite.png");
193
  /* Place hold small */
194
  background-position: -5px -542px;
195
  background-repeat: no-repeat;
196
  margin-right: 1em;
197
  padding-left: 21px;
198
  text-decoration: none;
199
}
200
.actions a.addtocart {
201
  background-image: url("../images/sprite.png");
202
  /* Cart small */
203
  background-position: -5px -572px;
204
  background-repeat: no-repeat;
205
  margin-right: 1em;
206
  padding-left: 20px;
207
  text-decoration: none;
208
}
209
.actions a.addtoshelf {
210
  background-image: url("../images/sprite.png");
211
  /* MARC view */
212
  background-position: -5px -27px;
213
  background-repeat: no-repeat;
214
  margin-right: 1em;
215
  padding-left: 20px;
216
  text-decoration: none;
217
}
218
.actions a.addtolist {
219
  background-position: -5px -27px;
220
  margin-right: 1em;
221
  padding-left: 20px;
222
  text-decoration: none;
223
}
224
.actions a.tag_add {
225
  background-position: -5px -1110px;
226
  margin-right: 1em;
227
  padding-left: 20px;
228
  text-decoration: none;
229
}
230
.actions a.removefromlist {
231
  background-position: -8px -690px;
232
  /* Delete */
233
  margin-right: 1em;
234
  text-decoration: none;
235
  padding-left: 15px;
236
}
237
/* Override Bootstrap alert */
238
.alert {
239
  background: #fffbe5;
240
  /* Old browsers */
241
  background: -moz-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%);
242
  /* FF3.6+ */
243
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fffbe5), color-stop(9%, #fff0b2), color-stop(89%, #fff1a8), color-stop(100%, #f7e665));
244
  /* Chrome,Safari4+ */
245
  background: -webkit-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%);
246
  /* Chrome10+,Safari5.1+ */
247
  background: -o-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%);
248
  /* Opera 11.10+ */
249
  background: -ms-linear-gradient(top, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%);
250
  /* IE10+ */
251
  background: linear-gradient(to bottom, #fffbe5 0%, #fff0b2 9%, #fff1a8 89%, #f7e665 100%);
252
  /* W3C */
253
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbe5', endColorstr='#f7e665', GradientType=0);
254
  /* IE6-9 */
255
  border-color: #D6C43B;
256
  color: #333;
257
}
258
/* Override Bootstrap alert.alert-info */
259
.alert-info {
260
  background: #f4f6fa;
261
  /* Old browsers */
262
  background: -moz-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%);
263
  /* FF3.6+ */
264
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f6fa), color-stop(4%, #eaeef5), color-stop(96%, #e8edf6), color-stop(100%, #cddbf2));
265
  /* Chrome,Safari4+ */
266
  background: -webkit-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%);
267
  /* Chrome10+,Safari5.1+ */
268
  background: -o-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%);
269
  /* Opera 11.10+ */
270
  background: -ms-linear-gradient(top, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%);
271
  /* IE10+ */
272
  background: linear-gradient(to bottom, #f4f6fa 0%, #eaeef5 4%, #e8edf6 96%, #cddbf2 100%);
273
  /* W3C */
274
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f6fa', endColorstr='#cddbf2', GradientType=0);
275
  /* IE6-9 */
276
  border-color: #C5D1E5;
277
  color: #333;
278
}
279
/* Override Bootstrap alert.alert-success */
280
.alert-success {
281
  background: #f8ffe8;
282
  /* Old browsers */
283
  background: -moz-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%);
284
  /* FF3.6+ */
285
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8ffe8), color-stop(4%, #e3f5ab), color-stop(98%, #dcf48d), color-stop(100%, #9ebf28));
286
  /* Chrome,Safari4+ */
287
  background: -webkit-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%);
288
  /* Chrome10+,Safari5.1+ */
289
  background: -o-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%);
290
  /* Opera 11.10+ */
291
  background: -ms-linear-gradient(top, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%);
292
  /* IE10+ */
293
  background: linear-gradient(to bottom, #f8ffe8 0%, #e3f5ab 4%, #dcf48d 98%, #9ebf28 100%);
294
  /* W3C */
295
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8ffe8', endColorstr='#9ebf28', GradientType=0);
296
  /* IE6-9 */
297
  border-color: #9FBA35;
298
  color: #333;
299
}
300
.breadcrumb {
301
  background-color: #F2F2EF;
302
  font-size: 85%;
303
  list-style: none outside none;
304
  margin: 10px 20px;
305
  padding: 5px 10px;
306
  -webkit-border-radius: 7px;
307
  -moz-border-radius: 7px;
308
  border-radius: 7px;
309
}
310
.form-inline {
311
  display: inline;
312
  padding: 0;
313
  margin: 0;
314
}
315
.form-inline fieldset {
316
  margin: 0.3em 0;
317
  padding: 0.3em;
318
}
319
.main {
320
  background-color: #FFF;
321
  border: 1px solid #D2D2CF;
322
  -webkit-border-radius: 7px;
323
  -moz-border-radius: 7px;
324
  border-radius: 7px;
325
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
326
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
327
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
328
  margin-top: 0.5em;
329
  margin-bottom: 0.5em;
330
}
331
.mastheadsearch {
332
  -webkit-border-radius: 7px;
333
  -moz-border-radius: 7px;
334
  border-radius: 7px;
335
  padding: .8em;
336
  margin: .5em 0;
337
  background: #c7c7c1;
338
  /* Old browsers */
339
  background: -moz-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%);
340
  /* FF3.6+ */
341
  background: -webkit-gradient(linear, left top, left bottom, color-stop(38%, #c7c7c1), color-stop(100%, #a7a7a2));
342
  /* Chrome,Safari4+ */
343
  background: -webkit-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%);
344
  /* Chrome10+,Safari5.1+ */
345
  background: -o-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%);
346
  /* Opera 11.10+ */
347
  background: -ms-linear-gradient(top, #c7c7c1 38%, #a7a7a2 100%);
348
  /* IE10+ */
349
  background: linear-gradient(to bottom, #c7c7c1 38%, #a7a7a2 100%);
350
  /* W3C */
351
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#c7c7c1', endColorstr='#a7a7a2', GradientType=0);
352
  /* IE6-9 */
353
}
354
.mastheadsearch label {
355
  font-size: 115%;
356
  font-weight: bold;
357
}
358
.navbar-inverse .brand,
359
.navbar-inverse .nav > li > a {
360
  color: #9FE1FF;
361
  font-weight: bold;
362
}
363
.navbar-fixed-bottom.navbar-static-bottom {
364
  margin-top: .5em;
365
  position: static;
366
}
367
#changelanguage .nav > .active > p {
368
  padding: 0 15px;
369
}
370
.table-striped tbody > tr:nth-child(odd) > td,
371
.table-striped tbody > tr:nth-child(odd) > th {
372
  background-color: #F4F4F4;
373
}
374
/* jQuery UI standard tabs */
375
.ui-tabs-nav .ui-tabs-active a,
376
.ui-tabs-nav a:hover,
377
.ui-tabs-nav a:focus,
378
.ui-tabs-nav a:active,
379
.ui-tabs-nav span.a {
380
  background: none repeat scroll 0 0 transparent;
381
  outline: 0 none;
382
}
383
.ui-widget,
384
.ui-widget input,
385
.ui-widget select,
386
.ui-widget textarea,
387
.ui-widget button {
388
  font-family: inherit;
389
  font-size: inherit;
390
}
391
ul.ui-tabs-nav li {
392
  list-style: none;
393
}
394
.ui-tabs.ui-widget-content {
395
  background: transparent none;
396
  border: 0;
397
}
398
.ui-tabs .ui-tabs-panel {
399
  border: 1px solid #D8D8D8;
400
  margin-bottom: 1em;
401
}
402
.ui-tabs-nav.ui-widget-header {
403
  border: 0;
404
  background: none;
405
}
406
.ui-tabs .ui-tabs-nav li {
407
  background: #F3F3F3 none;
408
  border-color: #D8D8D8;
409
  margin-right: .4em;
410
}
411
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
412
  background-color: #FFF;
413
  border: 1px solid #D8D8D8;
414
  border-bottom: 0;
415
}
416
.ui-tabs .ui-tabs-nav li.ui-tabs-active a {
417
  color: #000;
418
  font-weight: bold;
419
}
420
.ui-tabs .ui-tabs-nav li.ui-state-default.ui-state-hover {
421
  background: #F3F3F3 none;
422
}
423
.ui-tabs .ui-tabs-nav li.ui-tabs-active.ui-state-hover {
424
  background: #FFF none;
425
}
426
.ui-tabs .ui-state-default a,
427
.ui-tabs .ui-state-default a:link,
428
.ui-tabs .ui-state-default a:visited {
429
  color: #006699;
430
}
431
.ui-tabs .ui-state-hover a,
432
.ui-tabs .ui-state-hover a:link,
433
.ui-tabs .ui-state-hover a:visited {
434
  color: #990033;
435
}
436
.statictabs ul {
437
  background: none repeat scroll 0 0 transparent;
438
  border: 0 none;
439
  margin: 0;
440
  padding: 0.2em 0.2em 0;
441
  border-bottom-right-radius: 4px;
442
  border-bottom-left-radius: 4px;
443
  border-top-right-radius: 4px;
444
  border-top-left-radius: 4px;
445
  color: #222222;
446
  font-weight: bold;
447
  font-size: 100%;
448
  line-height: 1.3;
449
  list-style: none outside none;
450
  outline: 0 none;
451
  text-decoration: none;
452
}
453
.statictabs ul:before {
454
  content: "";
455
  display: table;
456
}
457
.statictabs ul:after {
458
  clear: both;
459
  content: "";
460
  display: table;
461
}
462
.statictabs li {
463
  background: none repeat scroll 0 0 #E6F0F2;
464
  border: 1px solid #B9D8D9;
465
  border-bottom: 0 none !important;
466
  border-top-right-radius: 4px;
467
  border-top-left-radius: 4px;
468
  float: left;
469
  list-style: none outside none;
470
  margin-bottom: 0;
471
  margin-right: 0.4em;
472
  padding: 0;
473
  position: relative;
474
  white-space: nowrap;
475
  top: 1px;
476
  color: #555555;
477
  font-weight: normal;
478
}
479
.statictabs li.active {
480
  background-color: #FFFFFF;
481
  color: #212121;
482
  font-weight: normal;
483
  padding-bottom: 1px;
484
}
485
.statictabs li a {
486
  color: #004D99;
487
  cursor: pointer;
488
  float: left;
489
  padding: 0.5em 1em;
490
  text-decoration: none;
491
}
492
.statictabs li a:hover {
493
  background-color: #EDF4F5;
494
  border-top-right-radius: 4px;
495
  border-top-left-radius: 4px;
496
  color: #538200;
497
}
498
.statictabs li.active a {
499
  color: #000000;
500
  font-weight: bold;
501
  cursor: text;
502
  background: none repeat scroll 0 0 transparent;
503
  outline: 0 none;
504
}
505
.statictabs .tabs-container {
506
  border: 1px solid #B9D8D9;
507
  background: none repeat scroll 0 0 transparent;
508
  display: block;
509
  padding: 1em 1.4em;
510
  border-bottom-right-radius: 4px;
511
  border-bottom-left-radius: 4px;
512
  color: #222222;
513
}
514
/* End jQueryUI tab styles */
515
/* jQuery UI Datepicker */
516
.ui-datepicker table {
517
  width: 100%;
518
  font-size: .9em;
519
  border: 0;
520
  border-collapse: collapse;
521
  margin: 0 0 .4em;
522
}
523
.ui-datepicker th {
524
  background: transparent none;
525
  padding: .7em .3em;
526
  text-align: center;
527
  font-weight: bold;
528
  border: 0;
529
}
530
.ui-datepicker-trigger {
531
  vertical-align: middle;
532
  margin: 0 3px;
533
}
534
.ui-datepicker {
535
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
536
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
537
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
538
}
539
/* End jQueryUI datepicker styles */
540
/* jQueryUI Core */
541
.ui-widget-content {
542
  border: 1px solid #AAA;
543
  background: #ffffff none;
544
  color: #222222;
545
}
546
.ui-widget-header {
547
  border: 1px solid #AAA;
548
  background: #E6F0F2 none;
549
  color: #222222;
550
  font-weight: bold;
551
}
552
.ui-state-default,
553
.ui-widget-content .ui-state-default,
554
.ui-widget-header .ui-state-default {
555
  border: 1px solid #AAA;
556
  background: #F4F8F9 none;
557
  font-weight: normal;
558
  color: #555555;
559
}
560
.ui-state-hover,
561
.ui-widget-content .ui-state-hover,
562
.ui-widget-header .ui-state-hover,
563
.ui-state-focus,
564
.ui-widget-content .ui-state-focus,
565
.ui-widget-header .ui-state-focus {
566
  border: 1px solid #AAA;
567
  background: #E6F0F2 none;
568
  font-weight: normal;
569
  color: #212121;
570
}
571
.ui-state-active,
572
.ui-widget-content .ui-state-active,
573
.ui-widget-header .ui-state-active {
574
  border: 1px solid #aaaaaa;
575
  background: #ffffff none;
576
  font-weight: normal;
577
  color: #212121;
578
}
579
.ui-state-highlight,
580
.ui-widget-content .ui-state-highlight,
581
.ui-widget-header .ui-state-highlight {
582
  border: 1px solid #fcefa1;
583
  background: #fbf9ee;
584
  color: #363636;
585
}
586
.ui-state-error,
587
.ui-widget-content .ui-state-error,
588
.ui-widget-header .ui-state-error {
589
  border: 1px solid #cd0a0a;
590
  background: #fef1ec;
591
  color: #cd0a0a;
592
}
593
/* end jQueryUI core */
594
/* jQueryUI autocomplete */
595
.ui-autocomplete {
596
  position: absolute;
597
  cursor: default;
598
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
599
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
600
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
601
}
602
.ui-autocomplete.ui-widget-content .ui-state-hover {
603
  border: 1px solid #AAA;
604
  background: #E6F0F2 none;
605
  font-weight: normal;
606
  color: #212121;
607
}
608
.ui-autocomplete-loading {
609
  background: #ffffff url("../../img/loading-small.gif") right center no-repeat;
610
}
611
.ui-menu li {
612
  list-style: none;
613
}
614
/* end jQueryUI autocomplete */
615
th {
616
  background-color: #ECEDE6;
617
}
618
.item-thumbnail {
619
  max-width: none;
620
}
621
.no-image {
622
  background-color: #FFF;
623
  border: 1px solid #AAA;
624
  color: #979797;
625
  display: block;
626
  font-size: 86%;
627
  font-weight: bold;
628
  text-align: center;
629
  width: 75px;
630
  -webkit-border-radius: 3px;
631
  -moz-border-radius: 3px;
632
  border-radius: 3px;
633
}
634
#bookcover .no-image {
635
  margin-right: 10px;
636
  margin-bottom: 10px;
637
}
638
td.overdue {
639
  color: #cc3333;
640
}
641
table {
642
  font-size: 90%;
643
}
644
th.sum {
645
  text-align: right;
646
}
647
td.sum {
648
  background-color: #FFC;
649
  font-weight: bold;
650
}
651
th[scope=row] {
652
  background-color: transparent;
653
  text-align: right;
654
}
655
.required {
656
  color: #C00;
657
}
658
.label {
659
  background-color: transparent;
660
  color: inherit;
661
  display: inline;
662
  font-weight: normal;
663
  padding: 0;
664
  text-shadow: none;
665
}
666
fieldset.rows {
667
  float: left;
668
  font-size: 90%;
669
  clear: left;
670
  margin: .9em 0 0 0;
671
  padding: 0;
672
  width: 100%;
673
}
674
fieldset.rows legend {
675
  font-weight: bold;
676
  font-size: 130%;
677
}
678
fieldset.rows label,
679
fieldset.rows .label {
680
  float: left;
681
  font-weight: bold;
682
  width: 9em;
683
  margin-right: 1em;
684
  text-align: right;
685
}
686
fieldset.rows label.lradio {
687
  float: none;
688
  margin: inherit;
689
  width: auto;
690
}
691
fieldset.rows fieldset {
692
  margin: 0;
693
  padding: .3em;
694
}
695
fieldset.rows ol {
696
  padding: 1em 1em 0 1em;
697
  list-style-type: none;
698
}
699
fieldset.rows ol.lradio label {
700
  width: auto;
701
  float: none;
702
  margin-right: 0;
703
}
704
fieldset.rows ol.lradio label.lradio {
705
  float: left;
706
  width: 12em;
707
  margin-right: 1em;
708
}
709
fieldset.rows li {
710
  float: left;
711
  clear: left;
712
  padding-bottom: 1em;
713
  list-style-type: none;
714
  width: 100%;
715
}
716
fieldset.rows li.lradio {
717
  padding-left: 8.5em;
718
  width: auto;
719
}
720
fieldset.rows li.lradio label {
721
  float: none;
722
  width: auto;
723
  margin: 0 0 0 1em;
724
}
725
fieldset.rows .hint {
726
  display: block;
727
  margin-left: 11em;
728
}
729
fieldset.action {
730
  clear: both;
731
  float: none;
732
  border: none;
733
  margin: 0;
734
  padding: 1em 0 .3em 0;
735
  width: auto;
736
}
737
fieldset.action p {
738
  margin-bottom: 1em;
739
}
740
fieldset table {
741
  font-size: 100%;
742
}
743
div.rows + div.rows {
744
  margin-top: .6em;
745
}
746
div.rows {
747
  float: left;
748
  clear: left;
749
  margin: 0 0 0 0;
750
  padding: 0;
751
  width: 100%;
752
}
753
div.rows span.label {
754
  float: left;
755
  font-weight: bold;
756
  width: 9em;
757
  margin-right: 1em;
758
  text-align: left;
759
}
760
div.rows ol {
761
  list-style-type: none;
762
  margin-left: 0;
763
  padding: .5em 1em 0 0;
764
}
765
div.rows li {
766
  border-bottom: 1px solid #EEE;
767
  float: left;
768
  clear: left;
769
  padding-bottom: .2em;
770
  padding-top: .1em;
771
  list-style-type: none;
772
  width: 100%;
773
}
774
div.rows ul li {
775
  margin-left: 7.3em;
776
}
777
div.rows ul li:first-child {
778
  float: none;
779
  clear: none;
780
  margin-left: 0;
781
}
782
div.rows ol li li {
783
  border-bottom: 0;
784
}
785
/* different sizes for different tags in opac-tags.tt */
786
.tagweight0 {
787
  font-size: 12px;
788
}
789
.tagweight1 {
790
  font-size: 14px;
791
}
792
.tagweight2 {
793
  font-size: 16px;
794
}
795
.tagweight3 {
796
  font-size: 18px;
797
}
798
.tagweight4 {
799
  font-size: 20px;
800
}
801
.tagweight5 {
802
  font-size: 22px;
803
}
804
.tagweight6 {
805
  font-size: 24px;
806
}
807
.tagweight7 {
808
  font-size: 26px;
809
}
810
.tagweight8 {
811
  font-size: 28px;
812
}
813
.tagweight9 {
814
  font-size: 30px;
815
}
816
.toolbar {
817
  background-color: #EEEEEE;
818
  border: 1px solid #E8E8E8;
819
  font-size: 85%;
820
  padding: 3px 3px 5px 5px;
821
  vertical-align: middle;
822
}
823
.toolbar a {
824
  white-space: nowrap;
825
}
826
.toolbar label {
827
  display: inline;
828
  font-size: 100%;
829
  font-weight: bold;
830
  margin-left: .5em;
831
}
832
.toolbar select {
833
  font-size: 97%;
834
  height: auto;
835
  line-height: inherit;
836
  padding: 0;
837
  margin: 0;
838
  width: auto;
839
  white-space: nowrap;
840
}
841
.toolbar .hold,
842
.toolbar #tagsel_tag {
843
  padding-left: 28px;
844
  font-size: 97%;
845
  font-weight: bold;
846
}
847
.toolbar #tagsel_form {
848
  margin-top: .5em;
849
}
850
.toolbar li {
851
  display: inline;
852
  list-style: none;
853
}
854
.toolbar li a {
855
  border-left: 1px solid #e8e8e8;
856
}
857
.toolbar li:first-child a {
858
  border-left: 0;
859
}
860
.toolbar ul {
861
  padding-left: 0;
862
}
863
#basket .toolbar {
864
  padding: 7px 5px 9px 9px;
865
}
866
#selections-toolbar {
867
  background: -moz-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
868
  /* FF3.6+ */
869
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b2b2b2), color-stop(14%, #e0e0e0), color-stop(100%, #e8e8e8));
870
  /* Chrome,Safari4+ */
871
  background: -webkit-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
872
  /* Chrome10+,Safari5.1+ */
873
  background: -o-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
874
  /* Opera 11.10+ */
875
  background: -ms-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
876
  /* IE10+ */
877
  background: linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
878
  /* W3C */
879
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e0e0e0', endColorstr='#e8e8e8', GradientType=0);
880
  /* IE6-9 */
881
  margin: 0 0 1em 0;
882
  padding-top: .5em;
883
  padding-left: 10px;
884
}
885
.list-actions {
886
  display: inline;
887
}
888
#tagsel_span input.submit,
889
#tagsel_tag {
890
  border: 0;
891
  background-color: transparent;
892
  font-size: 100%;
893
  color: #0076B2;
894
  cursor: pointer;
895
  background-image: url("../images/sprite.png");
896
  /* Tags */
897
  background-position: 1px -643px;
898
  background-repeat: no-repeat;
899
  padding-left: 25px;
900
  text-decoration: none;
901
}
902
#tagsel_tag.disabled {
903
  background-position: -1px -667px;
904
}
905
#tagsel_span input:hover,
906
#selections-toolbar input.hold:hover {
907
  color: #005580;
908
  text-decoration: underline;
909
}
910
#tagsel_span input.disabled,
911
#tagsel_span input.disabled:hover,
912
#tagsel_span input.hold.disabled,
913
#tagsel_span input.hold.disabled:hover,
914
#selections-toolbar input.hold.disabled,
915
#selections-toolbar input.hold.disabled:hover,
916
#selections-toolbar a.disabled,
917
#selections-toolbar a.disabled:hover {
918
  color: #888888;
919
  text-decoration: none;
920
  padding-left: 23px;
921
}
922
.results_summary {
923
  display: block;
924
  font-size: 85%;
925
  color: #707070;
926
  padding: 0 0 .5em 0;
927
}
928
.results_summary .results_summary {
929
  font-size: 100%;
930
}
931
.results_summary.actions {
932
  margin-top: .5em;
933
}
934
.results_summary.tagstatus {
935
  display: inline;
936
}
937
.results_summary .label {
938
  color: #202020;
939
}
940
.results_summary a {
941
  font-weight: normal;
942
}
943
#views {
944
  border-bottom: 1px solid #D6D6D6;
945
  margin-bottom: .5em;
946
  padding: 0 2em 0.2em 0.2em;
947
  white-space: nowrap;
948
}
949
.view {
950
  padding: 0.2em .2em 2px .2em;
951
}
952
#bibliodescriptions,
953
#isbdcontents {
954
  clear: left;
955
  margin-top: .5em;
956
}
957
.view a,
958
.view span {
959
  background-image: url("../images/sprite.png");
960
  background-repeat: no-repeat;
961
  font-size: 87%;
962
  font-weight: normal;
963
  padding: 0.4em 0.7em 5px 26px;
964
  text-decoration: none;
965
}
966
span#MARCview,
967
span#ISBDview,
968
span#Normalview,
969
span#Fullhistory,
970
span#Briefhistory {
971
  font-weight: bold;
972
}
973
a#MARCview,
974
span#MARCview {
975
  background-position: -3px -23px;
976
}
977
a#MARCviewPop,
978
span#MARCviewPop {
979
  background-position: -3px -23px;
980
}
981
a#ISBDview,
982
span#ISBDview {
983
  background-position: -3px -52px;
984
}
985
a#Normalview,
986
span#Normalview {
987
  background-position: -1px 6px;
988
}
989
.view a {
990
  background-color: #F3F3F3;
991
  border-left: 1px solid #C9C9C9;
992
}
993
#bookcover {
994
  float: left;
995
  margin: 0;
996
  padding: 0;
997
}
998
#bookcover .no-image {
999
  margin-right: 10px;
1000
  margin-bottom: 10px;
1001
}
1002
#bookcover img {
1003
  margin: 0 1em 1em 0;
1004
}
1005
/* pagination */
1006
.results-pagination {
1007
  position: absolute;
1008
  top: 32px;
1009
  left: -1px;
1010
  width: 100%;
1011
  height: auto;
1012
  border: 1px solid #D0D0D0;
1013
  display: none;
1014
  background-color: #F3F3F3;
1015
  padding-bottom: 10px;
1016
  z-index: 100;
1017
}
1018
.back {
1019
  float: right;
1020
}
1021
.back input {
1022
  background: none!important;
1023
  color: #999!important;
1024
}
1025
.pagination_list ul {
1026
  padding-top: 40px;
1027
  padding-left: 0px;
1028
}
1029
.pagination_list li {
1030
  list-style: none;
1031
  float: bottom;
1032
  padding: 4px;
1033
  color: #999;
1034
}
1035
.pagination_list li.highlight {
1036
  background-color: #F3F3F3;
1037
  border-top: 1px solid #DDDDDD;
1038
  border-bottom: 1px solid #DDDDDD;
1039
}
1040
.pagination_list li a {
1041
  padding-left: 0px;
1042
}
1043
.pagination_list .li_pag_index {
1044
  color: #999999;
1045
  float: left;
1046
  font-size: 15px;
1047
  font-weight: bold;
1048
  padding-right: 10px;
1049
  text-align: right;
1050
  width: 13px;
1051
}
1052
.nav_results {
1053
  background-color: #F3F3F3;
1054
  border: 1px solid #D0D0D0;
1055
  font-size: 95%;
1056
  font-weight: bold;
1057
  margin-top: 0.5em;
1058
  position: relative;
1059
}
1060
.nav_results .l_Results a {
1061
  background: #e1e1e1 url("../images/sprite.png") no-repeat 0px -504px;
1062
  /* Browse results menu */
1063
  color: #006699;
1064
  display: block;
1065
  padding: 8px 28px;
1066
  text-decoration: none;
1067
}
1068
.nav_results .l_Results:hover {
1069
  background-color: #D9D9D9;
1070
}
1071
.pg_menu {
1072
  margin: 0;
1073
  border-top: 1px solid #D0D0D0;
1074
  white-space: nowrap;
1075
}
1076
.pg_menu li {
1077
  color: #B2B2B2;
1078
  display: inline;
1079
  list-style: none;
1080
  margin: 0;
1081
}
1082
.pg_menu li.back_results a {
1083
  border-left: 1px solid #D0D0D0;
1084
  border-right: 1px solid #D0D0D0;
1085
}
1086
.pg_menu li a,
1087
.pg_menu li span {
1088
  background-color: #F3F3F3;
1089
  display: block;
1090
  float: left;
1091
  padding: .4em .5em;
1092
  text-decoration: none;
1093
  font-weight: normal;
1094
  text-align: center;
1095
}
1096
.pg_menu li span {
1097
  color: #B2B2B2;
1098
}
1099
#listResults li {
1100
  background-color: #999999;
1101
  color: #C5C5C5;
1102
  font-weight: normal;
1103
  display: block;
1104
  margin-right: 1px;
1105
  font-size: 80%;
1106
  padding: 0;
1107
  text-align: center;
1108
  min-width: 18px;
1109
}
1110
#listResults li:hover {
1111
  background-color: #006699;
1112
}
1113
#listResults li a {
1114
  color: #FFFFFF;
1115
  font-weight: normal;
1116
}
1117
/* nav */
1118
.nav_pages .close_pagination {
1119
  padding-right: 10px;
1120
  position: absolute;
1121
  right: 3px;
1122
  top: -25px;
1123
}
1124
.nav_pages .close_pagination a {
1125
  text-decoration: none!important;
1126
}
1127
.nav_pages ul {
1128
  padding-top: 10px;
1129
}
1130
.nav_pages li {
1131
  list-style: none;
1132
  float: left;
1133
  padding: 4px;
1134
  color: #999;
1135
}
1136
.nav_pages li a {
1137
  text-decoration: none!important;
1138
}
1139
.nav_pages li a:hover {
1140
  text-decoration: underline;
1141
}
1142
.nav_pages li ul {
1143
  float: left;
1144
}
1145
/* action buttons */
1146
#action {
1147
  margin: .5em 0 0 0;
1148
  background-color: #F3F3F3;
1149
  border: 1px solid #E8E8E8;
1150
  padding-bottom: 3px;
1151
}
1152
#action li {
1153
  list-style: none;
1154
  margin: .2em;
1155
  padding: .3em 0;
1156
}
1157
#action a {
1158
  font-weight: bold;
1159
  text-decoration: none;
1160
}
1161
#export li,
1162
#moresearches_menu li {
1163
  padding: 0;
1164
  margin: 0;
1165
}
1166
#export li a,
1167
#moresearches_menu li a {
1168
  font-weight: normal;
1169
}
1170
#export li a.menu-inactive,
1171
#moresearches_menu li a.menu-inactive {
1172
  font-weight: bold;
1173
}
1174
#format,
1175
#furthersearches {
1176
  padding-left: 35px;
1177
}
1178
.highlight_controls {
1179
  float: left;
1180
}
1181
a.addtocart,
1182
a.addtoshelf,
1183
a.brief,
1184
a.deleteshelf,
1185
a.deleteshelf.disabled,
1186
a.detail,
1187
a.download,
1188
a.editshelf,
1189
a.empty,
1190
a.hide,
1191
a.highlight_toggle,
1192
a.hold,
1193
a.hold.disabled,
1194
a.incart,
1195
a.new,
1196
a.print-small,
1197
a.print-large,
1198
a.removeitems,
1199
a.removeitems.disabled,
1200
a.reserve,
1201
a.send,
1202
a.tag_add,
1203
a.removefromlist,
1204
input.hold,
1205
input.hold.disabled,
1206
input.editshelf,
1207
.newshelf,
1208
.newshelf.disabled,
1209
.deleteshelf {
1210
  background-image: url("../images/sprite.png");
1211
  background-repeat: no-repeat;
1212
}
1213
a.addtocart {
1214
  background-position: -5px -265px;
1215
  /* Cart */
1216
  padding-left: 35px;
1217
}
1218
a.addtoshelf {
1219
  background-position: -5px -225px;
1220
  /* Virtual shelf */
1221
  padding-left: 35px;
1222
}
1223
a.brief {
1224
  background-position: -2px -868px;
1225
  /* Zoom out */
1226
  text-decoration: none;
1227
  padding-left: 27px;
1228
}
1229
a.cartRemove {
1230
  color: #cc3333;
1231
  font-size: 90%;
1232
  margin: 0;
1233
  padding: 0;
1234
}
1235
a.detail {
1236
  background-position: -2px -898px;
1237
  /* Zoom in */
1238
  text-decoration: none;
1239
  padding-left: 27px;
1240
}
1241
a.download {
1242
  background-position: -5px -348px;
1243
  /* Download */
1244
  padding-left: 20px;
1245
  text-decoration: none;
1246
}
1247
a.editshelf {
1248
  background-position: 2px -348px;
1249
  /* List edit */
1250
  padding-left: 26px;
1251
  text-decoration: none;
1252
}
1253
a.empty {
1254
  background-position: 2px -598px;
1255
  /* Trash */
1256
  text-decoration: none;
1257
  padding-left: 30px;
1258
}
1259
a.hide {
1260
  background-position: -3px -814px;
1261
  /* Close */
1262
  text-decoration: none;
1263
  padding-left: 26px;
1264
}
1265
a.highlight_toggle {
1266
  background-position: -5px -841px;
1267
  /* Highlight */
1268
  display: none;
1269
  padding-left: 35px;
1270
}
1271
a.hold,
1272
input.hold {
1273
  background-position: -2px -453px;
1274
  /* Toolbar place hold */
1275
  text-decoration: none;
1276
  padding-left: 23px;
1277
}
1278
a.hold.disabled,
1279
input.hold.disabled {
1280
  background-position: -5px -621px;
1281
  /* Place hold disabled */
1282
}
1283
a.incart {
1284
  background-position: -5px -265px;
1285
  /* Cart */
1286
  color: #666;
1287
  padding-left: 35px;
1288
}
1289
a.new {
1290
  background-image: url("../images/sprite.png");
1291
  /* New */
1292
  background-position: -4px -922px;
1293
  padding-left: 23px;
1294
  text-decoration: none;
1295
}
1296
a.print-small {
1297
  background-position: 0px -423px;
1298
  /* Toolbar print */
1299
  text-decoration: none;
1300
  padding-left: 30px;
1301
}
1302
a.print-large {
1303
  background-position: -5px -186px;
1304
  /* Toolbar print */
1305
  text-decoration: none;
1306
  padding-left: 35px;
1307
}
1308
a.removeitems,
1309
a.deleteshelf {
1310
  background-position: 2px -690px;
1311
  /* Delete */
1312
  text-decoration: none;
1313
  padding-left: 25px;
1314
}
1315
a.removeitems.disabled,
1316
a.deleteshelf.disabled {
1317
  background-position: 2px -712px;
1318
  /* Delete disabled */
1319
}
1320
a.reserve {
1321
  background-position: -6px -144px;
1322
  /* Place hold */
1323
  padding-left: 35px;
1324
}
1325
a.send {
1326
  background-position: 2px -386px;
1327
  /* Email */
1328
  text-decoration: none;
1329
  padding-left: 28px;
1330
}
1331
a.tag_add {
1332
  background-position: 3px -1111px;
1333
  /* Tag results */
1334
  padding-left: 27px;
1335
  text-decoration: none;
1336
}
1337
input.hold {
1338
  background-color: transparent;
1339
  border: 0;
1340
  color: #0076B2;
1341
  font-weight: bold;
1342
}
1343
input.editshelf {
1344
  background-color: transparent;
1345
  background-position: 2px -736px;
1346
  /* List edit */
1347
  border: 0;
1348
  color: #006699;
1349
  cursor: pointer;
1350
  filter: none;
1351
  font-size: 100%;
1352
  padding-left: 29px;
1353
  text-decoration: none;
1354
}
1355
.newshelf {
1356
  background-position: 2px -764px;
1357
  /* List new */
1358
  border: 0;
1359
  color: #006699;
1360
  cursor: pointer;
1361
  filter: none;
1362
  font-size: 100%;
1363
  padding-left: 28px;
1364
  text-decoration: none;
1365
}
1366
.newshelf.disabled {
1367
  background-position: -4px -791px;
1368
  /* List new disabled */
1369
}
1370
.deleteshelf {
1371
  background-color: transparent;
1372
  background-position: 2px -690px;
1373
  /* Delete */
1374
  border: 0;
1375
  color: #006699;
1376
  cursor: pointer;
1377
  filter: none;
1378
  font-size: 100%;
1379
  padding-left: 25px;
1380
  text-decoration: none;
1381
}
1382
.links a {
1383
  font-weight: bold;
1384
}
1385
.deleteshelf:hover {
1386
  color: #990033;
1387
}
1388
.editshelf:active,
1389
.deleteshelf:active {
1390
  border: 0;
1391
}
1392
#tagslist li {
1393
  display: inline;
1394
}
1395
#login4tags {
1396
  background-image: url("../images/sprite.png");
1397
  /* Tag results disabled */
1398
  background-position: -6px -1130px;
1399
  background-repeat: no-repeat;
1400
  padding-left: 20px;
1401
  text-decoration: none;
1402
}
1403
.tag_results_input {
1404
  margin-left: 1em;
1405
  padding: 0.3em;
1406
  font-size: 12px;
1407
}
1408
.tag_results_input input[type="text"] {
1409
  font-size: inherit;
1410
  margin: 0;
1411
  padding: 0;
1412
}
1413
.tag_results_input label {
1414
  display: inline;
1415
}
1416
.tagsinput input[type="text"] {
1417
  font-size: inherit;
1418
  margin: 0;
1419
  padding: 0;
1420
}
1421
.tagsinput label {
1422
  display: inline;
1423
}
1424
.branch-info-tooltip {
1425
  display: none;
1426
}
1427
#social_networks a {
1428
  background: transparent url("../images/social-sprite.png") no-repeat;
1429
  display: block;
1430
  height: 20px !important;
1431
  width: 20px;
1432
  text-indent: -999em;
1433
}
1434
#social_networks span {
1435
  color: #274D7F;
1436
  display: block;
1437
  float: left;
1438
  font-size: 85%;
1439
  font-weight: bold;
1440
  line-height: 2em;
1441
  margin: .5em 0 .5em .5em !important;
1442
}
1443
#social_networks div {
1444
  float: left !important;
1445
  margin: .5em 0 .5em .2em !important;
1446
}
1447
#social_networks #facebook {
1448
  background-position: -7px -35px;
1449
}
1450
#social_networks #twitter {
1451
  background-position: -7px -5px;
1452
}
1453
#social_networks #linkedin {
1454
  background-position: -7px -95px;
1455
}
1456
#social_networks #delicious {
1457
  background-position: -7px -66px;
1458
}
1459
#social_networks #email {
1460
  background-position: -7px -126px;
1461
}
1462
#marc td,
1463
#marc th {
1464
  background-color: transparent;
1465
  border: 0;
1466
  padding: 3px 5px;
1467
  text-align: left;
1468
}
1469
#marc td:first-child {
1470
  text-indent: 2em;
1471
}
1472
#marc p {
1473
  padding-bottom: .6em;
1474
}
1475
#marc p .label {
1476
  font-weight: bold;
1477
}
1478
#marc ul {
1479
  padding-bottom: .6em;
1480
}
1481
#marc .results_summary {
1482
  clear: left;
1483
}
1484
#marc .results_summary ul {
1485
  display: inline;
1486
  float: none;
1487
  clear: none;
1488
  margin: 0;
1489
  padding: 0;
1490
  list-style: none;
1491
}
1492
#marc .results_summary li {
1493
  display: inline;
1494
}
1495
#items,
1496
#items td #items th {
1497
  border: 1px solid #EEE;
1498
  font-size: 90%;
1499
}
1500
#plainmarc table {
1501
  border: 0;
1502
  margin: .7em 0 0 0;
1503
  font-family: monospace;
1504
  font-size: 95%;
1505
}
1506
#plainmarc th {
1507
  background-color: #FFF;
1508
  border: 0;
1509
  white-space: nowrap;
1510
  text-align: left;
1511
  vertical-align: top;
1512
  padding: 2px;
1513
}
1514
#plainmarc td {
1515
  border: 0;
1516
  padding: 2px;
1517
  vertical-align: top;
1518
}
1519
#renewcontrols {
1520
  float: right;
1521
  font-size: 66%;
1522
}
1523
#renewcontrols a {
1524
  background-repeat: no-repeat;
1525
  text-decoration: none;
1526
  padding: .1em .4em;
1527
  padding-left: 18px;
1528
}
1529
#renewselected_link {
1530
  background-image: url("../images/sprite.png");
1531
  background-position: -5px -986px;
1532
  background-repeat: no-repeat;
1533
}
1534
#renewall_link {
1535
  background-image: url("../images/sprite.png");
1536
  background-position: -8px -967px;
1537
  background-repeat: no-repeat;
1538
}
1539
.authref {
1540
  text-indent: 2em;
1541
}
1542
.authref .label {
1543
  font-style: italic;
1544
}
1545
.authstanza {
1546
  margin-top: 1em;
1547
}
1548
.authstanzaheading {
1549
  font-weight: bold;
1550
}
1551
.authorizedheading {
1552
  font-weight: bold;
1553
}
1554
.authstanza li {
1555
  margin-left: 0.5em;
1556
}
1557
.authres_notes,
1558
.authres_seealso,
1559
.authres_otherscript {
1560
  padding-top: .5em;
1561
}
1562
.authres_notes {
1563
  font-style: italic;
1564
}
1565
#didyoumean {
1566
  background-color: #EEE;
1567
  border: 1px solid #E8E8E8;
1568
  margin: 0 0 0.5em;
1569
  text-align: left;
1570
  padding: 0.5em;
1571
  -webkit-border-radius: 3px;
1572
  -moz-border-radius: 3px;
1573
  border-radius: 3px;
1574
}
1575
.suggestionlabel {
1576
  font-weight: bold;
1577
}
1578
.searchsuggestion {
1579
  padding: 0.2em 0.5em;
1580
  white-space: nowrap;
1581
  display: inline-block;
1582
}
1583
.authlink {
1584
  padding-left: 0.25em;
1585
}
1586
#hierarchies a {
1587
  font-weight: normal;
1588
  text-decoration: underline;
1589
  color: #069;
1590
}
1591
#hierarchies a:hover {
1592
  color: #990033;
1593
}
1594
#top-pages {
1595
  margin: 0 0 0.5em;
1596
}
1597
.dropdown-menu > li > a {
1598
  font-size: 90%;
1599
}
1600
a.listmenulink:link,
1601
a.listmenulink:visited {
1602
  color: #0076B2;
1603
  font-weight: bold;
1604
}
1605
a.listmenulink:hover,
1606
a.listmenulink:active {
1607
  color: #FFF;
1608
  font-weight: bold;
1609
}
1610
#cartDetails,
1611
#cartUpdate,
1612
#holdDetails,
1613
#listsDetails {
1614
  background-color: #FFF;
1615
  border: 1px solid rgba(0, 0, 0, 0.2);
1616
  border-radius: 6px 6px 6px 6px;
1617
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
1618
  color: black;
1619
  display: none;
1620
  font-size: 90%;
1621
  margin: 0;
1622
  padding: 8px 20px;
1623
  text-align: center;
1624
  width: 180px;
1625
  z-index: 2;
1626
}
1627
#cartmenulink {
1628
  white-space: nowrap;
1629
}
1630
#search-facets,
1631
#menu {
1632
  border: 1px solid #D2D2CF;
1633
  -webkit-border-radius: 7px;
1634
  -moz-border-radius: 7px;
1635
  border-radius: 7px;
1636
}
1637
#search-facets ul,
1638
#menu ul {
1639
  margin: 0;
1640
  padding: .3em;
1641
}
1642
#search-facets form,
1643
#menu form {
1644
  margin: 0;
1645
}
1646
#search-facets h4,
1647
#menu h4 {
1648
  font-size: 90%;
1649
  margin: 0 0 .6em 0;
1650
  text-align: center;
1651
}
1652
#search-facets h4 a,
1653
#menu h4 a {
1654
  background-color: #F2F2EF;
1655
  border-radius: 8px 8px 0 0;
1656
  border-bottom: 1px solid #D8D8D8;
1657
  display: block;
1658
  font-weight: bold;
1659
  padding: .7em .2em;
1660
  text-decoration: none;
1661
}
1662
#search-facets li,
1663
#menu li {
1664
  font-size: 90%;
1665
  font-weight: bold;
1666
  list-style-type: none;
1667
}
1668
#search-facets li li,
1669
#menu li li {
1670
  font-weight: normal;
1671
  font-size: 95%;
1672
  line-height: 125%;
1673
  margin-bottom: 2px;
1674
  padding: .1em .2em;
1675
}
1676
#search-facets li.showmore a,
1677
#menu li.showmore a {
1678
  font-weight: bold;
1679
  text-indent: 1em;
1680
}
1681
#search-facets a,
1682
#menu a {
1683
  font-weight: normal;
1684
  text-decoration: underline;
1685
}
1686
#menu {
1687
  font-size: 94%;
1688
}
1689
#menu li {
1690
  list-style-type: none;
1691
}
1692
#menu li a {
1693
  background: #eeeeee;
1694
  text-decoration: none;
1695
  display: block;
1696
  border: 1px solid #D8D8D8;
1697
  border-radius: 5px 0 0 5px;
1698
  border-bottom-color: #999;
1699
  font-size: 111%;
1700
  padding: .4em .6em;
1701
  margin: .4em 0;
1702
  margin-right: -1px;
1703
}
1704
#menu li a:hover {
1705
  background: #eaeef5;
1706
}
1707
#menu li.active a {
1708
  background-color: #FFF;
1709
  background-image: none;
1710
  border-right-width: 0;
1711
  font-weight: bold;
1712
}
1713
#menu li.active a:hover {
1714
  background-color: #fff;
1715
}
1716
#menu h4 {
1717
  display: none;
1718
}
1719
#addto {
1720
  max-width: 10em;
1721
}
1722
/* Search results add to cart (lists disabled) */
1723
.addto a.addtocart {
1724
  background-image: url("../images/sprite.png");
1725
  /* Cart */
1726
  background-position: -5px -266px;
1727
  background-repeat: no-repeat;
1728
  text-decoration: none;
1729
  padding-left: 33px;
1730
}
1731
.searchresults p {
1732
  margin: 0;
1733
  padding: 0 0 .6em 0;
1734
}
1735
.searchresults p.details {
1736
  color: #979797;
1737
}
1738
.searchresults a.highlight_toggle {
1739
  background-image: url("../images/sprite.png");
1740
  /* Highlight */
1741
  background-position: -11px -841px;
1742
  background-repeat: no-repeat;
1743
  display: none;
1744
  font-weight: normal;
1745
  padding: 0 10px 0 21px;
1746
}
1747
.searchresults .commentline {
1748
  background-color: #ffffcc;
1749
  background-color: rgba(255, 255, 204, 0.4);
1750
  border: 1px solid #CCC;
1751
  display: inline-block;
1752
  -webkit-border-radius: 3px;
1753
  -moz-border-radius: 3px;
1754
  border-radius: 3px;
1755
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1756
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1757
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1758
  margin: .3em;
1759
  padding: .4em;
1760
}
1761
.searchresults .commentline.yours {
1762
  background-color: #effed5;
1763
  background-color: rgba(239, 254, 213, 0.4);
1764
}
1765
.commentline .avatar {
1766
  float: right;
1767
  padding-left: .5em;
1768
}
1769
/* style for search terms in catalogsearch */
1770
.term {
1771
  /* color : blue; */
1772
  color: #990000;
1773
  background-color: #FFFFCC;
1774
}
1775
/* style for shelving location in catalogsearch */
1776
.shelvingloc {
1777
  display: block;
1778
  font-style: italic;
1779
}
1780
#CheckAll,
1781
#CheckNone {
1782
  font-weight: normal;
1783
  margin: 0 .5em;
1784
  text-decoration: underline;
1785
}
1786
span.sep {
1787
  color: #888;
1788
  padding: 0 .2em 0 .5em;
1789
  text-shadow: 1px 1px 0 #FFF;
1790
}
1791
/* style for PM-generated pagination bar */
1792
.pages span:first-child,
1793
.pages a:first-child {
1794
  border-width: 1px 1px 1px 1px;
1795
  border-bottom-left-radius: 3px;
1796
  border-top-left-radius: 3px;
1797
}
1798
.pages span:last-child,
1799
.pages a:last-child {
1800
  border-width: 1px 1px 1px 0;
1801
  border-bottom-right-radius: 3px;
1802
  border-top-right-radius: 3px;
1803
}
1804
.pages .inactive,
1805
.pages .currentPage,
1806
.pages a {
1807
  -moz-border-bottom-colors: none;
1808
  -moz-border-left-colors: none;
1809
  -moz-border-right-colors: none;
1810
  -moz-border-top-colors: none;
1811
  background-color: #FFFFFF;
1812
  border-color: #DDDDDD;
1813
  border-image: none;
1814
  border-style: solid;
1815
  border-width: 1px 1px 1px 0;
1816
  float: left;
1817
  font-size: 11.9px;
1818
  line-height: 20px;
1819
  padding: 4px 12px;
1820
  text-decoration: none;
1821
}
1822
.pages .inactive {
1823
  background-color: #F5F5F5;
1824
}
1825
.pages a[rel='last'] {
1826
  border-bottom-right-radius: 3px;
1827
  border-top-right-radius: 3px;
1828
}
1829
.hold-message {
1830
  background-color: #FFF0B1;
1831
  display: inline-block;
1832
  margin: 0.5em;
1833
  padding: 0.2em 0.5em;
1834
  -webkit-border-radius: 3px;
1835
  -moz-border-radius: 3px;
1836
  border-radius: 3px;
1837
}
1838
.reserve_date,
1839
.expiration_date {
1840
  white-space: nowrap;
1841
}
1842
.close {
1843
  color: #0088CC;
1844
  position: inherit;
1845
  top: auto;
1846
  right: auto;
1847
  filter: none;
1848
  float: none;
1849
  font-size: inherit;
1850
  font-weight: normal;
1851
  opacity: inherit;
1852
  text-shadow: none;
1853
}
1854
.close:hover {
1855
  color: #538200;
1856
  filter: inherit;
1857
  font-size: inherit;
1858
  opacity: inherit;
1859
}
1860
/* Redefine a new style for Bootstrap's class "close" since we use that already */
1861
/* Use <a class="closebtn" href="#">&times;</a> */
1862
.alert .closebtn {
1863
  position: relative;
1864
  top: -2px;
1865
  right: -21px;
1866
  line-height: 20px;
1867
}
1868
.modal-header .closebtn {
1869
  margin-top: 2px;
1870
}
1871
.closebtn {
1872
  float: right;
1873
  font-size: 20px;
1874
  font-weight: bold;
1875
  line-height: 20px;
1876
  color: #000000;
1877
  text-shadow: 0 1px 0 #ffffff;
1878
  opacity: 0.2;
1879
  filter: alpha(opacity=20);
1880
}
1881
.closebtn:hover {
1882
  color: #000000;
1883
  text-decoration: none;
1884
  cursor: pointer;
1885
  opacity: 0.4;
1886
  filter: alpha(opacity=40);
1887
}
1888
button.closebtn {
1889
  padding: 0;
1890
  cursor: pointer;
1891
  background: transparent;
1892
  border: 0;
1893
  -webkit-appearance: none;
1894
}
1895
.btn-group label,
1896
.btn-group select {
1897
  font-size: 13px;
1898
}
1899
.span2 select {
1900
  width: 100%;
1901
}
1902
.popup .main {
1903
  font-size: 90%;
1904
  padding: 0 1em;
1905
}
1906
.popup legend {
1907
  line-height: 1.5em;
1908
  margin-bottom: .5em;
1909
}
1910
.available {
1911
  color: #006600;
1912
}
1913
.waiting,
1914
.intransit,
1915
.notforloan,
1916
.checkedout,
1917
.lost,
1918
.notonhold {
1919
  display: block;
1920
}
1921
.notforloan {
1922
  color: #900;
1923
}
1924
.lost {
1925
  color: #666;
1926
}
1927
.suggestion {
1928
  background-color: #EEEEEB;
1929
  border: 1px solid #DDDED3;
1930
  margin: 1em auto;
1931
  padding: .5em;
1932
  width: 35%;
1933
  -webkit-border-radius: 3px;
1934
  -moz-border-radius: 3px;
1935
  border-radius: 3px;
1936
}
1937
.librarypulldown .transl1 {
1938
  width: auto;
1939
}
1940
.nolibrarypulldown {
1941
  width: 68%;
1942
}
1943
.nolibrarypulldown .transl1 {
1944
  width: 87%;
1945
}
1946
#opac-main-search select {
1947
  width: auto;
1948
  max-width: 12em;
1949
}
1950
#logo {
1951
  background: transparent url("../images/koha-logo-navbar.png") no-repeat scroll 0%;
1952
  border: 0;
1953
  float: left !important;
1954
  margin: 0;
1955
  padding: 0;
1956
  width: 100px;
1957
}
1958
#logo a {
1959
  border: 0;
1960
  cursor: pointer;
1961
  display: block;
1962
  height: 0px !important;
1963
  margin: 0;
1964
  overflow: hidden;
1965
  padding: 40px 0 0;
1966
  text-decoration: none;
1967
  width: 100px;
1968
}
1969
#user-menu-trigger {
1970
  display: none;
1971
}
1972
#user-menu-trigger .icon-user {
1973
  background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;
1974
  background-position: -168px 0;
1975
  background-repeat: no-repeat;
1976
  height: 14px;
1977
  line-height: 14px;
1978
  margin: 12px 0 0;
1979
  vertical-align: text-top;
1980
  width: 14px;
1981
}
1982
#user-menu-trigger .caret {
1983
  border-bottom-color: #999999;
1984
  border-top-color: #999999;
1985
  margin-top: 18px;
1986
}
1987
/* Class to be added to toolbar when it starts being fixed at the top of the screen*/
1988
.floating {
1989
  -webkit-box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4);
1990
  box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4);
1991
  margin-top: 0;
1992
}
1993
.tdlabel {
1994
  font-weight: bold;
1995
  display: none;
1996
}
1997
td img {
1998
  max-width: none;
1999
}
2000
#ulactioncontainer {
2001
  min-width: 16em;
2002
}
2003
.notesrow label {
2004
  font-weight: bold;
2005
}
2006
.notesrow span {
2007
  display: block;
2008
}
2009
.thumbnail-shelfbrowser span {
2010
  margin: 0px auto;
2011
}
2012
.dropdown-menu > li > a.menu-inactive:hover {
2013
  background: #FFF none;
2014
  color: #000;
2015
}
2016
.table .sorting_asc {
2017
  padding-right: 19px;
2018
  background: url("../images/asc.gif") no-repeat scroll right center #ecede6;
2019
}
2020
.table .sorting_desc {
2021
  padding-right: 19px;
2022
  background: url("../images/desc.gif") no-repeat scroll right center #ecede6;
2023
}
2024
.table .sorting {
2025
  padding-right: 19px;
2026
  background: url("../images/ascdesc.gif") no-repeat scroll right center #ecede6;
2027
}
2028
.table .nosort,
2029
.table .nosort.sorting_asc,
2030
.table .nosort.sorting_desc,
2031
.table .nosort.sorting {
2032
  padding-right: 19px;
2033
  background: #ECEDE6 none;
2034
}
2035
.tags ul {
2036
  display: inline;
2037
  list-style: none;
2038
  margin-left: 0;
2039
}
2040
.tags ul li {
2041
  display: inline;
2042
}
2043
.coverimages {
2044
  float: right;
2045
}
2046
#i18nMenu {
2047
  margin-left: 1em;
2048
}
2049
#i18nMenu li {
2050
  font-size: 85%;
2051
}
2052
#i18nMenu li li {
2053
  font-size: 100%;
2054
}
2055
#i18nMenu li li > a {
2056
  font-size: 100%;
2057
}
2058
#i18nMenu li li > a:hover {
2059
  color: #FFF;
2060
}
2061
#i18nMenu li a {
2062
  color: #0076b2;
2063
}
2064
#i18nMenu .dropdown-menu li p {
2065
  clear: both;
2066
  display: block;
2067
  font-weight: normal;
2068
  line-height: 20px;
2069
  padding: 3px 20px;
2070
  white-space: nowrap;
2071
}
2072
#subjectsList label,
2073
#authorSearch label {
2074
  display: inline;
2075
  vertical-align: middle;
2076
}
2077
#subjectsList ul,
2078
#authorSearch ul {
2079
  border-bottom: 1px solid #EEE;
2080
  list-style-type: none;
2081
  margin: 0;
2082
  padding: .6em 0;
2083
}
2084
#subjectsList li,
2085
#authorSearch li {
2086
  list-style-type: none;
2087
  margin: 0;
2088
  padding: 0;
2089
}
2090
#overdrive-results,
2091
#pazpar2-results {
2092
  font-weight: bold;
2093
  padding-left: 1em;
2094
}
2095
.throbber {
2096
  vertical-align: middle;
2097
}
2098
#overdrive-results-list .star-rating-control {
2099
  display: block;
2100
  overflow: auto;
2101
}
2102
#shelfbrowser table {
2103
  margin: 0;
2104
}
2105
#shelfbrowser table,
2106
#shelfbrowser td,
2107
#shelfbrowser th {
2108
  border: 0;
2109
  font-size: 90%;
2110
  text-align: center;
2111
}
2112
#shelfbrowser td,
2113
#shelfbrowser th {
2114
  padding: 3px 5px;
2115
  width: 20%;
2116
}
2117
#shelfbrowser a {
2118
  display: block;
2119
  font-size: 110%;
2120
  font-weight: bold;
2121
  text-decoration: none;
2122
}
2123
#shelfbrowser #browser_next,
2124
#shelfbrowser #browser_previous {
2125
  background-image: url("../images/sprite.png");
2126
  background-repeat: no-repeat;
2127
  width: 16px;
2128
}
2129
#shelfbrowser #browser_next a,
2130
#shelfbrowser #browser_previous a {
2131
  cursor: pointer;
2132
  display: block;
2133
  height: 0 !important;
2134
  margin: 0;
2135
  overflow: hidden;
2136
  padding: 50px 0 0;
2137
  text-decoration: none;
2138
  width: 16px;
2139
}
2140
#shelfbrowser #browser_previous {
2141
  background-position: -9px -1007px;
2142
}
2143
#shelfbrowser #browser_next {
2144
  background-position: -9px -1057px;
2145
}
2146
#holds {
2147
  margin: 0 auto;
2148
  max-width: 800px;
2149
}
2150
.holdrow {
2151
  clear: both;
2152
  padding: 0 1em 1em 1em;
2153
  border-bottom: 1px solid #CCC;
2154
  margin-bottom: .5em;
2155
}
2156
.holdrow fieldset {
2157
  border: 0;
2158
  margin: 0;
2159
  float: none;
2160
}
2161
.holdrow fieldset .label {
2162
  font-size: 14px;
2163
}
2164
.holdrow label {
2165
  display: inline;
2166
}
2167
.hold-options {
2168
  clear: both;
2169
}
2170
.toggle-hold-options {
2171
  background-color: #eee;
2172
  clear: both;
2173
  display: block;
2174
  font-weight: bold;
2175
  margin: 1em 0;
2176
  padding: .5em;
2177
}
2178
.copiesrow {
2179
  clear: both;
2180
}
2181
#idreambooksreadometer {
2182
  float: right;
2183
}
2184
a.idreambooksrating {
2185
  font-size: 30px;
2186
  color: #29ADE4;
2187
  padding-left: 85px;
2188
  line-height: 30px;
2189
  text-decoration: none;
2190
}
2191
.idreambookslegend {
2192
  font-size: small;
2193
}
2194
a.reviewlink,
2195
a.reviewlink:visited {
2196
  text-decoration: none;
2197
  color: black;
2198
  font-weight: normal;
2199
}
2200
.idreambookssummary a {
2201
  color: #707070;
2202
  text-decoration: none;
2203
}
2204
.idreambookssummary img,
2205
.idbresult img {
2206
  vertical-align: middle;
2207
}
2208
.idbresult {
2209
  color: #29ADE4;
2210
  text-align: center;
2211
  margin: 0.5em;
2212
  padding: 0.5em;
2213
}
2214
.idbresult a,
2215
.idbresult a:visited {
2216
  text-decoration: none;
2217
  color: #29ADE4;
2218
}
2219
.idbresult img {
2220
  padding-right: 6px;
2221
}
2222
.js-show {
2223
  display: none;
2224
}
2225
.modal-nojs .modal-header,
2226
.modal-nojs .modal-footer {
2227
  display: none;
2228
}
2229
@media only screen and (min-width: 0px) and (max-width: 304px) {
2230
  /* Screens bewteen 0 and 304 pixels wide */
2231
  #oh:after {
2232
    content: "(min-width: 0px) and (max-width: 304px)";
2233
  }
2234
  input,
2235
  select,
2236
  textarea {
2237
    width: auto;
2238
    max-width: 11em;
2239
  }
2240
}
2241
@media only screen and (min-width: 0px) and (max-width: 390px) {
2242
  /* Screens bewteen 0 and 390 pixels wide */
2243
  #oh:after {
2244
    content: "(min-width: 0px) and (max-width: 390px)";
2245
  }
2246
  .ui-tabs .ui-tabs-nav li a,
2247
  .statictabs li a {
2248
    padding: .1em .5em;
2249
  }
2250
  #views {
2251
    border: 0;
2252
    padding: 0;
2253
    margin: 0;
2254
  }
2255
  .view {
2256
    padding: 0;
2257
  }
2258
  .view a,
2259
  .view span {
2260
    border: 1px solid #C9C9C9;
2261
    -webkit-border-radius: 4px;
2262
    -moz-border-radius: 4px;
2263
    border-radius: 4px;
2264
    font-size: 80%;
2265
    padding: 0.3em 0.4em 4px 26px;
2266
  }
2267
  .input-fluid {
2268
    width: 90%;
2269
  }
2270
}
2271
@media only screen and (min-width: 305px) and (max-width: 341px) {
2272
  /* Screens bewteen 305 and 341 pixels wide */
2273
  #oh:after {
2274
    content: "(min-width: 305px) and (max-width: 341px)";
2275
  }
2276
}
2277
@media only screen and (min-width: 342px) and (max-width: 479px) {
2278
  /* Screens bewteen 342 and 479 pixels wide */
2279
  #oh:after {
2280
    content: "(min-width: 342px) and (max-width: 479px)";
2281
  }
2282
  .input-fluid {
2283
    width: 75%;
2284
  }
2285
}
2286
/* Override Bootstrap Responsive CSS fixed navbar */
2287
@media (max-width: 979px) {
2288
  .navbar-fixed-top,
2289
  .navbar-fixed-bottom {
2290
    position: fixed;
2291
    margin-left: 0px;
2292
    margin-right: 0px;
2293
  }
2294
}
2295
@media only screen and (max-width: 608px) {
2296
  /* Screens below 608 pixels wide */
2297
  fieldset.rows label {
2298
    display: block;
2299
    float: none;
2300
    text-align: left;
2301
  }
2302
  fieldset.rows li {
2303
    padding-bottom: .5em;
2304
  }
2305
  fieldset.rows ol {
2306
    margin-left: 0;
2307
  }
2308
  fieldset.rows .hint {
2309
    margin-left: 0;
2310
  }
2311
  body {
2312
    padding: 0;
2313
  }
2314
  .tdlabel {
2315
    display: inline;
2316
  }
2317
  .navbar-fixed-top,
2318
  .navbar-static-top {
2319
    margin: 0;
2320
  }
2321
  .navbar-inner {
2322
    padding: 0;
2323
  }
2324
  .checkall,
2325
  .clearall,
2326
  .highlight_controls,
2327
  #selections-toolbar,
2328
  .selectcol,
2329
  .list-actions,
2330
  #remove-selected {
2331
    display: none;
2332
  }
2333
  .table td.bibliocol {
2334
    padding-left: 1.3em;
2335
  }
2336
  .actions {
2337
    display: block;
2338
  }
2339
  .actions a,
2340
  .actions #login4tags {
2341
    background-color: #F2F2EF;
2342
    border: 1px solid #DDD;
2343
    -webkit-border-radius: 4px;
2344
    -moz-border-radius: 4px;
2345
    border-radius: 4px;
2346
    font-weight: bold;
2347
    display: block;
2348
    font-size: 120%;
2349
    margin: 2px 0;
2350
  }
2351
  .actions .label {
2352
    display: block;
2353
    font-weight: bold;
2354
  }
2355
  .actions #login4tags {
2356
    margin-right: 1em;
2357
  }
2358
  #opac-main-search button,
2359
  #opac-main-search input,
2360
  #opac-main-search select,
2361
  #opac-main-search .librarypulldown .transl1,
2362
  #opac-main-search .input-append {
2363
    display: block;
2364
    width: 97%;
2365
    max-width: 100%;
2366
    margin: .5em 0;
2367
    -webkit-border-radius: 5px;
2368
    -moz-border-radius: 5px;
2369
    border-radius: 5px;
2370
  }
2371
  #opac-main-search .input-append {
2372
    margin: 0;
2373
    width: 100%;
2374
  }
2375
  #opac-main-search .librarypulldown .transl1 {
2376
    width: 94.5%;
2377
  }
2378
  #toolbar .resort {
2379
    font-size: 14px;
2380
    max-width: 100%;
2381
    margin: .5em 0;
2382
    padding: 4px 6px;
2383
    -webkit-border-radius: 5px;
2384
    -moz-border-radius: 5px;
2385
    border-radius: 5px;
2386
  }
2387
  .mastheadsearch {
2388
    margin: 0;
2389
    -webkit-border-radius: 0px;
2390
    -moz-border-radius: 0px;
2391
    border-radius: 0px;
2392
  }
2393
  .main {
2394
    margin: .5em 0;
2395
    padding: 15px;
2396
    -webkit-border-radius: 0px;
2397
    -moz-border-radius: 0px;
2398
    border-radius: 0px;
2399
  }
2400
  .breadcrumb {
2401
    margin: 10px 0;
2402
  }
2403
  #moresearches {
2404
    text-align: center;
2405
  }
2406
  #searchsubmit {
2407
    font-weight: bold;
2408
  }
2409
  .ui-tabs-panel .item-thumbnail,
2410
  .tabs-container .item-thumbnail,
2411
  #topissues .item-thumbnail,
2412
  #usertags .item-thumbnail,
2413
  #usersuggestions .item-thumbnail {
2414
    margin: .5em 0 0 .5em;
2415
  }
2416
  .ui-tabs-panel .table-bordered,
2417
  .tabs-container .table-bordered,
2418
  #topissues .table-bordered,
2419
  #usertags .table-bordered,
2420
  #usersuggestions .table-bordered {
2421
    border: none;
2422
  }
2423
  .ui-tabs-panel .table th,
2424
  .tabs-container .table th,
2425
  #topissues .table th,
2426
  #usertags .table th,
2427
  #usersuggestions .table th,
2428
  .ui-tabs-panel .table thead,
2429
  .tabs-container .table thead,
2430
  #topissues .table thead,
2431
  #usertags .table thead,
2432
  #usersuggestions .table thead {
2433
    display: none;
2434
  }
2435
  .ui-tabs-panel .table td,
2436
  .tabs-container .table td,
2437
  #topissues .table td,
2438
  #usertags .table td,
2439
  #usersuggestions .table td {
2440
    border-right: 1px solid #dddddd;
2441
    border-left: 1px solid #dddddd;
2442
    border-top: 0;
2443
    display: block;
2444
    padding: .2em;
2445
  }
2446
  .ui-tabs-panel .table p,
2447
  .tabs-container .table p,
2448
  #topissues .table p,
2449
  #usertags .table p,
2450
  #usersuggestions .table p {
2451
    margin-bottom: 2px;
2452
  }
2453
  .ui-tabs-panel tr,
2454
  .tabs-container tr,
2455
  #topissues tr,
2456
  #usertags tr,
2457
  #usersuggestions tr {
2458
    display: block;
2459
    margin-bottom: .6em;
2460
  }
2461
  .ui-tabs-panel tr td:first-child,
2462
  .tabs-container tr td:first-child,
2463
  #topissues tr td:first-child,
2464
  #usertags tr td:first-child,
2465
  #usersuggestions tr td:first-child {
2466
    border-top: 1px solid #dddddd;
2467
    border-radius: 5px 5px 0 0;
2468
  }
2469
  .ui-tabs-panel tr td:last-child,
2470
  .tabs-container tr td:last-child,
2471
  #topissues tr td:last-child,
2472
  #usertags tr td:last-child,
2473
  #usersuggestions tr td:last-child {
2474
    border-radius: 0 0 5px 5px;
2475
    border-bottom: 2px solid #CACACA;
2476
  }
2477
  .no-image {
2478
    display: none;
2479
  }
2480
}
2481
@media only screen and (max-width: 700px) {
2482
  /* Screens below 700 pixels wide */
2483
  #opac-main-search label {
2484
    display: none;
2485
  }
2486
  #logo {
2487
    background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;
2488
    background-position: 0 -24px;
2489
    margin: 14px 14px 0 14px;
2490
    width: 14px;
2491
  }
2492
  #logo a {
2493
    padding: 14px 0 0;
2494
    width: 14px;
2495
  }
2496
  #user-menu-trigger {
2497
    display: inline;
2498
    margin-right: 12px;
2499
  }
2500
  #members {
2501
    display: none;
2502
    clear: both;
2503
  }
2504
  #members li {
2505
    padding-right: 20px;
2506
    text-align: right;
2507
    border-bottom: 1px solid #555;
2508
  }
2509
  #members li:first-child {
2510
    border-top: 1px solid #555;
2511
  }
2512
  #members li:last-child {
2513
    border-bottom: none;
2514
  }
2515
  #members .nav {
2516
    float: none;
2517
  }
2518
  #members .nav.pull-right {
2519
    float: none;
2520
  }
2521
  #members .nav > li {
2522
    float: none;
2523
  }
2524
  #members .divider-vertical {
2525
    border: 0;
2526
    height: 0;
2527
    margin: 0;
2528
  }
2529
}
2530
@media only screen and (min-width: 480px) and (max-width: 608px) {
2531
  /* Screens between 480 and 608 pixels wide */
2532
  #oh:after {
2533
    content: " Between 480 pixels and 608 pixels. ";
2534
  }
2535
  .input-fluid {
2536
    width: 75%;
2537
  }
2538
}
2539
@media only screen and (min-width: 608px) and (max-width: 767px) {
2540
  /* Screens between 608 and 767 pixels wide */
2541
  #oh:after {
2542
    content: " Between 608 pixels and 767 pixels. ";
2543
  }
2544
  .main {
2545
    padding: 0.8em 20px;
2546
  }
2547
  .breadcrumb {
2548
    margin: 10px 0;
2549
  }
2550
  .navbar-static-bottom {
2551
    margin-left: -20px;
2552
    margin-right: -20px;
2553
  }
2554
}
2555
@media only screen and (max-width: 767px) {
2556
  /* Screens below 767 pixels wide */
2557
  a.title {
2558
    font-size: 120%;
2559
  }
2560
  #userresults {
2561
    margin: 0 -20px;
2562
  }
2563
  .breadcrumb,
2564
  #top-pages,
2565
  .menu-collapse {
2566
    display: none;
2567
  }
2568
  #search-facets,
2569
  #menu {
2570
    margin-bottom: .5em;
2571
  }
2572
  #search-facets h4,
2573
  #menu h4 {
2574
    display: block;
2575
    margin: 0;
2576
    padding: 0;
2577
  }
2578
  #search-facets h4 a,
2579
  #menu h4 a {
2580
    -webkit-border-radius: 7px;
2581
    -moz-border-radius: 7px;
2582
    border-radius: 7px;
2583
    border-bottom: 0;
2584
    font-weight: normal;
2585
    padding: .7em .2em;
2586
  }
2587
  #search-facets ul,
2588
  #menu ul {
2589
    padding: 0;
2590
  }
2591
  #menu li a {
2592
    -webkit-border-radius: 0px;
2593
    -moz-border-radius: 0px;
2594
    border-radius: 0px;
2595
    border: 0;
2596
    display: block;
2597
    font-size: 120%;
2598
    text-decoration: none;
2599
    border-bottom: 1px solid #D8D8D8;
2600
    margin: 0;
2601
  }
2602
  #menu li.active a {
2603
    border-top: 1px solid #D8D8D8;
2604
    border-right-width: 1px;
2605
  }
2606
  #menu li:last-child a {
2607
    -webkit-border-radius: 0 0 7px 7px;
2608
    -moz-border-radius: 0 0 7px 7px;
2609
    border-radius: 0 0 7px 7px;
2610
  }
2611
  #search-facets li {
2612
    padding: .4em;
2613
  }
2614
  #search-facets h5 {
2615
    margin: .2em;
2616
  }
2617
  #menu h4 a.menu-open,
2618
  #search-facets h4 a.menu-open {
2619
    -webkit-border-radius: 7px 7px 0 0;
2620
    -moz-border-radius: 7px 7px 0 0;
2621
    border-radius: 7px 7px 0 0;
2622
    border-bottom: 1px solid #D8D8D8;
2623
  }
2624
}
2625
@media only screen and (max-width: 800px) {
2626
  /* Screens below 800 pixels wide */
2627
  .cartlabel,
2628
  .listslabel {
2629
    display: none;
2630
  }
2631
  .navbar .divider-vertical {
2632
    margin: 0 2px;
2633
  }
2634
  .navbar #members .divider-vertical {
2635
    margin: 0 9px;
2636
  }
2637
}
2638
@media only screen and (min-width: 768px) {
2639
  /* Screens above 768 pixels wide */
2640
  .main {
2641
    margin-left: 20px;
2642
    margin-right: 20px;
2643
  }
2644
  #menu {
2645
    border: 0;
2646
    -webkit-border-radius: 0px;
2647
    -moz-border-radius: 0px;
2648
    border-radius: 0px;
2649
    border-right: 1px solid #D8D8D8;
2650
  }
2651
  #menu h4 {
2652
    display: none;
2653
  }
2654
  #menu ul {
2655
    padding: 1em 0 1em 0;
2656
  }
2657
}
2658
@media only screen and (min-width: 768px) and (max-width: 984px) {
2659
  /* Screens between 768 and 984 pixels wide */
2660
  #oh:after {
2661
    content: " Between 768 and 984 pixels. ";
2662
  }
2663
  .librarypulldown .transl1 {
2664
    width: 38%;
2665
  }
2666
}
2667
@media only screen and (max-width: 984px) {
2668
  /* Screens up to 984 pixels wide */
2669
}
2670
@media only screen and (min-width: 984px) {
2671
  /* Screens above 969 pixels wide */
2672
  #oh:after {
2673
    content: " Above 984 pixels. ";
2674
  }
2675
  .librarypulldown .transl1 {
2676
    width: 53%;
2677
  }
2678
}
2679
@media only screen and (max-width: 1040px) {
2680
  .pg_menu li a {
2681
    float: none;
2682
    text-align: left;
2683
  }
2684
  .pg_menu li.back_results a {
2685
    border: 1px solid #D0D0D0;
2686
    border-width: 1px 0 1px 0;
2687
  }
2688
  #ulactioncontainer {
2689
    min-width: 0;
2690
  }
2691
}
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-external-search.tt (+249 lines)
Line 0 Link Here
1
[% USE Koha %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog &rsaquo; External search for '[% q | html %]'
4
[% INCLUDE 'doc-head-close.inc' %]
5
[% BLOCK cssinclude %]
6
<style>
7
.actions a.addtocart {
8
    display: inline;
9
}
10
#targets-facet label {
11
    display: inline;
12
    font-size: inherit;
13
}
14
</style>
15
[% END %]
16
</head>
17
<body id="results" class="scrollto">
18
[% INCLUDE 'masthead.inc' %]
19
20
    <div class="main">
21
        <ul class="breadcrumb">
22
            <li><a href="/cgi-bin/koha/opac-main.pl">Home</a> <span class="divider">&rsaquo;</span></li>
23
            <li>
24
                <a href="#">External search for '[% q | html %]'</a>
25
            </li>
26
        </ul>
27
28
        <div id="maincontent" class="container-fluid">
29
            <div class="row-fluid">
30
                <div class="span3">
31
                    <div id="facetcontainer">
32
                        <div id="search-facets">
33
                            <h4><a href="#" class="menu-collapse-toggle">Refine your search</a></h4>
34
                            <ul class="menu-collapse">
35
                                <li id="targets-facet">
36
                                    Targets
37
                                    <ul>
38
                                        [% FOREACH target = external_search_targets %]
39
                                        <li>
40
                                            <input data-url="[% target.host %]:[% target.port %]/[% target.db %]" type="checkbox" id="target-[% loop.index %]" checked />
41
                                            <label for="target-[% loop.index %]">[% target.name %]
42
                                        </li>
43
                                        [% END %]
44
                                    </ul>
45
                                </li>
46
                            </ul>
47
                        </div>
48
                    </div>
49
                </div>
50
51
                <div class="span9 maincontent">
52
                    <p id="numresults"></p>
53
                    <div id="top-pages">
54
                        <div class="pagination pagination-small"><ul></ul></div>
55
                    </div>
56
                    <div id="searchresults">
57
                        <table class="table table-striped" id="results">
58
                            <tbody>
59
                            </tbody>
60
                        </table>
61
                    </div>
62
                    <div id="bottom-pages">
63
                        <div class="pagination pagination-small"><ul></ul></div>
64
                    </div>
65
                </div>
66
            </div>
67
        </div>
68
    </div>
69
</div>
70
71
</div>
72
73
<div id="modal-overlay" class="modal hide fade"></div>
74
[% INCLUDE 'opac-bottom.inc' %]
75
[% BLOCK jsinclude %]
76
<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script>
77
<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script>
78
<script type="text/javascript">
79
var querystring = "[% q |replace( "'", "\'" ) |replace( '\n', '\\n' ) |replace( '\r', '\\r' ) |html %]";
80
var results_per_page = [% OPACnumSearchResults %];
81
KOHA.ExternalSearch.targets = {
82
    [% FOREACH target IN external_search_targets %]
83
        '[% target.host %]:[% target.port %]/[% target.db %]': {
84
            name: '[% target.name %]',
85
            syntax: '[% target.syntax %]',
86
        },
87
    [% END %]
88
};
89
90
var xsltResultStylesheets = {
91
    [% FOREACH stylesheet IN xslt_result_stylesheets %]
92
    '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ),
93
    [% END %]
94
};
95
96
var xsltDetailStylesheets = {
97
    [% FOREACH stylesheet IN xslt_detail_stylesheets %]
98
    '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ),
99
    [% END %]
100
};
101
102
var recordCache = {};
103
var resultRenderCache = {};
104
105
function showResult( syntax, recid ) {
106
    if ( recordCache[ recid ] ) {
107
        done( recordCache[ recid ] );
108
    } else {
109
        KOHA.ExternalSearch.GetDetailedRecord( recid, function( record ) {
110
            done( recordCache[ recid ] = record.xmlDoc );
111
        } );
112
    }
113
114
    function done( record ) {
115
        xsltResultStylesheets[ syntax ].done( function( xslDoc ) {
116
            var fragment = resultRenderCache[ recid ] = KOHA.TransformToFragment( record, xslDoc );
117
            var $tr = $( '#results tr' ).filter( function() { return $( this ).data( 'recid' ) == recid } );
118
            $tr.find( '.info' ).html( fragment );
119
            $tr.find( 'a' ).attr( 'href', '#' ).click( function() {
120
                showDetail( syntax, recid );
121
122
                return false;
123
            } );
124
        } );
125
    }
126
}
127
128
function showDetail( syntax, recid ) {
129
    var record = recordCache[ recid ];
130
131
    xsltDetailStylesheets[ syntax ].done( function( xslDoc ) {
132
        var fragment = KOHA.TransformToFragment( record, xslDoc );
133
134
        $( '#modal-overlay' ).html( fragment ).modal();
135
    } );
136
}
137
138
function search( offset, reset_search ) {
139
    $( '#pazpar2-status' ).html( _("Searching external targets...") + '<img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" />' );
140
141
    if ( reset_search ) {
142
        KOHA.ExternalSearch.Search( querystring, results_per_page, callback );
143
    } else {
144
        KOHA.ExternalSearch.Fetch( offset, callback );
145
    }
146
147
    function callback( data ) {
148
        if ( data.error && data.error.code != 8 ) { // PAZPAR2_NO_TARGETS
149
            $( '#pazpar2-status' ).html( '<strong class="unavailable">' + _("Error searching external targets.") + '</strong>' );
150
            return;
151
        }
152
153
        if ( !data.total ) {
154
            $( '#pazpar2-status' ).html( '<strong>' + _("No results found in the external targets.") + '</strong>' );
155
            return;
156
        }
157
158
        $( '#results tbody' ).empty();
159
160
        $( '#pazpar2-status' ).html( '<strong>' + _("Found __RESULTS__ results in __TARGETS__ external targets.").replace('__RESULTS__', data.total).replace('__TARGETS__', $( '#targets-facet input:checked' ).length ) );
161
162
        for ( var i = 0; data.hits[i]; i++ ) {
163
            var hit = data.hits[i];
164
            var results = [];
165
            var recordSyntax = KOHA.ExternalSearch.targets[ hit.location[0]['@id'] ].syntax;
166
167
            results.push( '<tr>' );
168
169
            results.push( '<td class="sourcecol">', hit.location[0]['@name'], '</td>' );
170
171
            results.push( '<td class="info">' );
172
173
            if ( resultRenderCache[ hit.recid[0] ] ) {
174
                results.push( resultRenderCache[ hit.recid[0] ] );
175
            } else {
176
                results.push( hit['md-work-title'] ? hit['md-work-title'][0] : _("Loading...") );
177
                showResult( recordSyntax, hit.recid[0] );
178
            }
179
180
            results.push( '</td>' );
181
182
            results.push( '</tr>' );
183
            var $tr = $( results.join( '' ) );
184
            $tr.data( 'recid', hit.recid[0] );
185
            $( '#results tbody' ).append( $tr );
186
187
            ( function( hit, recordSyntax ) {
188
                $tr.find( 'a' ).attr( 'href', '#' ).click( function() {
189
                    showDetail( recordSyntax, hit.recid[0] );
190
191
                    return false;
192
                } );
193
            } )( hit, recordSyntax );
194
        }
195
196
        var pages = [];
197
        var cur_page = data.start / results_per_page;
198
        var max_page = Math.floor( data.total / results_per_page );
199
200
        if ( cur_page != 0 ) {
201
            pages.push( '<li><a href="#" data-offset="' + (offset - results_per_page) + '">&lt;&lt; ' + _("Previous") + '</a></li>' );
202
        }
203
204
        for ( var page = Math.max( 0, cur_page - 9 ); page <= Math.min( max_page, cur_page + 9 ); page++ ) {
205
            if ( page == cur_page ) {
206
                pages.push( ' <li class="active"><a href="#">' + ( page + 1 ) + '</a></span>' );
207
            } else {
208
                pages.push( ' <li><a href="#" data-offset="' + ( page * results_per_page ) + '">' + ( page + 1 ) + '</a></li>' );
209
            }
210
        }
211
212
        if ( cur_page < max_page ) {
213
            pages.push( ' <li><a href="#" data-offset="' + (offset + results_per_page) + '">' + _("Next") + ' >></a></li>' );
214
        }
215
216
        if ( pages.length > 1 ) $( '#top-pages, #bottom-pages' ).find( '.pagination ul' ).html( pages.join( '' ) );
217
    }
218
}
219
220
$( document ).ready( function() {
221
    $( '#numresults' )
222
        .append( ' ' )
223
        .append( '<span id="pazpar2-status"></span>' );
224
225
    $( document ).on( 'click', 'a[data-offset]', function() {
226
        search( $(this).data('offset') );
227
        return false;
228
    });
229
230
    var reSearchTimeout;
231
232
    $( '#targets-facet input' ).each( function() {
233
        $( this ).click( function() {
234
            KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked;
235
236
            if ( reSearchTimeout ) clearTimeout( reSearchTimeout );
237
238
            reSearchTimeout = setTimeout( function() {
239
                if ( $( '#targets-facet input:checked' ).length ) search( 0, true );
240
            }, 1000 );
241
        } );
242
243
        KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked;
244
    } );
245
246
    search( 0, true );
247
} );
248
</script>
249
[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-results.tt (-10 / +53 lines)
Lines 552-558 Link Here
552
[% IF ( OverDriveEnabled ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/js/overdrive.js"></script>[% END %]
552
[% IF ( OverDriveEnabled ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/js/overdrive.js"></script>[% END %]
553
<script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
553
<script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
554
[% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.highlight-3.js"></script>
554
[% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% interface %]/[% theme %]/lib/jquery/plugins/jquery.highlight-3.js"></script>
555
[% END %]<script type="text/javascript">
555
[% END %]
556
[% IF ( Koha.Preference('OPACSearchExternalTargets') ) %]
557
<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script>
558
<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script>
559
[% END %]
560
<script type="text/javascript">
556
//<![CDATA[
561
//<![CDATA[
557
[% IF ( Koha.Preference( 'opacuserlogin' ) == 1 ) && ( Koha.Preference( 'RequestOnOpac' ) == 1 ) %]
562
[% IF ( Koha.Preference( 'opacuserlogin' ) == 1 ) && ( Koha.Preference( 'RequestOnOpac' ) == 1 ) %]
558
function holdMultiple() {
563
function holdMultiple() {
Lines 836-858 $(document).ready(function(){ Link Here
836
        $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;});
841
        $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;});
837
        $("#highlight_toggle_off").show().click(function() {highlightOff();});
842
        $("#highlight_toggle_off").show().click(function() {highlightOff();});
838
    [% END %]
843
    [% END %]
844
845
    function StartExternalSearch(name, text) {
846
        $( '#numresults' )
847
            .eq( 0 )
848
            .append( ' <span id="' + name + '-results">' + text + '... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
849
    }
850
    function FailExternalSearch( name, text ) {
851
        $( '#' + name + '-results' ).html( text );
852
    }
853
    function FinishExternalSearch( name, text, numItems, url ) {
854
        if ( numItems ) {
855
            $( '#' + name + '-results' ).html( text.replace( '__LINK__', '<a href="' + url + '">' + _("__RESULTS__ results").replace( '__RESULTS__', numItems ) + '</a>' ) );
856
        } else {
857
            $( '#' + name + '-results' ).remove();
858
        }
859
    }
860
839
    [% IF ( OverDriveEnabled ) %]
861
    [% IF ( OverDriveEnabled ) %]
840
        var $overdrive_results = $( '<span id="overdrive-results">' + _( 'Searching OverDrive...' ) + ' <img class="throbber" src="[% interface %]/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
862
        StartExternalSearch( 'overdrive', _("Searching OverDrive") );
841
        $( '#numresults' ) .append( ' ' )
842
            .append( $overdrive_results );
843
        KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) {
863
        KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) {
844
            if ( data.error ) {
864
            if ( data.error ) {
845
                $overdrive_results.html( _( 'Error searching OverDrive collection' ) );
865
                FailExternalSearch( 'overdrive', _("Error searching OverDrive collection") );
846
                return;
866
                return;
847
            }
867
            }
848
868
849
            if ( data.totalItems ) {
869
            FinishExternalSearch( 'overdrive', _("Found __LINK__ in OverDrive collection"), data.totalItems, '/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) );
850
                $overdrive_results.html( _( 'Found' ) + ' <a href="/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) + '">' + data.totalItems + ' ' + _( 'results' ) + '</a> ' + _( 'in OverDrive collection' ) );
851
            } else {
852
                $overdrive_results.remove();
853
            }
854
        } );
870
        } );
855
    [% END %]
871
    [% END %]
872
873
    [% IF ( OPACSearchExternalTargets ) %]
874
        KOHA.ExternalSearch.targets = {
875
            [% FOREACH target IN external_search_targets %]
876
                '[% target.host %]:[% target.port %]/[% target.db %]': {
877
                    id: '[% target.target_id %]',
878
                    name: '[% target.name %]',
879
                    syntax: '[% target.syntax %]',
880
                },
881
            [% END %]
882
        };
883
        var num_targets = 0; $.each( KOHA.ExternalSearch.targets, function() { num_targets++ } );
884
        var first_succeeded;
885
886
        if ( num_targets ) {
887
            StartExternalSearch( 'pazpar2', _("Searching external targets") );
888
            KOHA.ExternalSearch.Search( querystring, 1, function( data ) {
889
                if ( data.error ) {
890
                    if ( !first_succeeded ) FailExternalSearch( 'pazpar2', _("Error searching external targets") );
891
                    return;
892
                }
893
894
                first_succeeded = true;
895
                FinishExternalSearch( 'pazpar2', _("Found __LINK__ in __TARGETS__ external targets").replace( '__TARGETS__', num_targets ), data.total, '/cgi-bin/koha/opac-external-search.pl?q=' + escape( querystring ) );
896
            } );
897
        }
898
    [% END %]
856
[% END %]
899
[% END %]
857
900
858
[% IF ( TagsInputEnabled && loggedinusername ) %]
901
[% IF ( TagsInputEnabled && loggedinusername ) %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slim2OPACResults.xsl (-1 / +6 lines)
Lines 5-15 Link Here
5
  xmlns:marc="http://www.loc.gov/MARC21/slim"
5
  xmlns:marc="http://www.loc.gov/MARC21/slim"
6
  xmlns:items="http://www.koha-community.org/items"
6
  xmlns:items="http://www.koha-community.org/items"
7
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
7
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
8
  xmlns="http://www.w3.org/1999/xhtml"
8
  exclude-result-prefixes="marc items">
9
  exclude-result-prefixes="marc items">
9
    <xsl:import href="MARC21slimUtils.xsl"/>
10
    <xsl:import href="MARC21slimUtils.xsl"/>
10
    <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
11
    <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
11
    <xsl:key name="item-by-status" match="items:item" use="items:status"/>
12
    <xsl:key name="item-by-status" match="items:item" use="items:status"/>
12
    <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
13
    <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
14
    <xsl:param name="showAvailability" select="true()"/>
13
15
14
    <xsl:template match="/">
16
    <xsl:template match="/">
15
            <xsl:apply-templates/>
17
            <xsl:apply-templates/>
Lines 1027-1032 Link Here
1027
                            </xsl:for-each>
1029
                            </xsl:for-each>
1028
                            </span>
1030
                            </span>
1029
                        </xsl:if>
1031
                        </xsl:if>
1032
                        <xsl:if test="$showAvailability">
1030
                        <span class="results_summary availability">
1033
                        <span class="results_summary availability">
1031
                        <span class="label">Availability: </span>
1034
                        <span class="label">Availability: </span>
1032
                        <xsl:choose>
1035
                        <xsl:choose>
Lines 1035-1041 Link Here
1035
                            <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]">
1038
                            <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]">
1036
                            <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/>
1039
                            <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/>
1037
                            <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]">
1040
                            <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]">
1038
                                <xsl:call-template select="marc:datafield[@tag=$AlternateHoldingsField]" name="subfieldSelect">
1041
                                <!-- Removed select="marc:datafield[@tag=$AlternateHoldingsField]" due to incompatibility with browser XSLT -->
1042
                                <xsl:call-template name="subfieldSelect">
1039
                                    <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param>
1043
                                    <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param>
1040
                                    <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param>
1044
                                    <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param>
1041
                                </xsl:call-template>
1045
                                </xsl:call-template>
Lines 1145-1150 Link Here
1145
                       <xsl:text>). </xsl:text>                   </span>
1149
                       <xsl:text>). </xsl:text>                   </span>
1146
                   </xsl:if>
1150
                   </xsl:if>
1147
               </span>
1151
               </span>
1152
               </xsl:if>
1148
    <xsl:choose>
1153
    <xsl:choose>
1149
        <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)">
1154
        <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)">
1150
            <span class="results_summary" id="location">
1155
            <span class="results_summary" id="location">
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/MARC21slimUtils.xsl (-1 / +1 lines)
Lines 1-6 Link Here
1
<?xml version='1.0'?>
1
<?xml version='1.0'?>
2
<!DOCTYPE stylesheet [<!ENTITY nbsp "&#160;" >]>
2
<!DOCTYPE stylesheet [<!ENTITY nbsp "&#160;" >]>
3
<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3
<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">
4
	<xsl:template name="datafield">
4
	<xsl:template name="datafield">
5
		<xsl:param name="tag"/>
5
		<xsl:param name="tag"/>
6
		<xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
6
		<xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACResults.xsl (+4 lines)
Lines 6-17 Link Here
6
  xmlns:marc="http://www.loc.gov/MARC21/slim"
6
  xmlns:marc="http://www.loc.gov/MARC21/slim"
7
  xmlns:items="http://www.koha-community.org/items"
7
  xmlns:items="http://www.koha-community.org/items"
8
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
8
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
9
  xmlns="http://www.w3.org/1999/xhtml"
9
  exclude-result-prefixes="marc items">
10
  exclude-result-prefixes="marc items">
10
11
11
<xsl:import href="UNIMARCslimUtils.xsl"/>
12
<xsl:import href="UNIMARCslimUtils.xsl"/>
12
<xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
13
<xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
13
<xsl:key name="item-by-status" match="items:item" use="items:status"/>
14
<xsl:key name="item-by-status" match="items:item" use="items:status"/>
14
<xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
15
<xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
16
<xsl:param name="showAvailability" select="true()"/>
15
17
16
<xsl:template match="/">
18
<xsl:template match="/">
17
  <xsl:apply-templates/>
19
  <xsl:apply-templates/>
Lines 99-104 Link Here
99
101
100
  <xsl:call-template name="tag_215" />
102
  <xsl:call-template name="tag_215" />
101
103
104
  <xsl:if test="$showAvailability">
102
  <span class="results_summary availability">
105
  <span class="results_summary availability">
103
    <span class="label">Availability: </span>
106
    <span class="label">Availability: </span>
104
    <xsl:choose>
107
    <xsl:choose>
Lines 247-252 Link Here
247
      </span>
250
      </span>
248
    </xsl:if>
251
    </xsl:if>
249
  </span>
252
  </span>
253
  </xsl:if>
250
254
251
</xsl:template>
255
</xsl:template>
252
256
(-)a/koha-tmpl/opac-tmpl/bootstrap/less/opac.less (-1 / +1 lines)
Lines 2198-2204 td img { Link Here
2198
}
2198
}
2199
2199
2200
2200
2201
#overdrive-results {
2201
#overdrive-results, #pazpar2-results {
2202
    font-weight: bold;
2202
    font-weight: bold;
2203
    padding-left: 1em;
2203
    padding-left: 1em;
2204
}
2204
}
(-)a/koha-tmpl/opac-tmpl/ccsr/en/css/opac.css (+16 lines)
Lines 1596-1601 strong em, em strong { Link Here
1596
     vertical-align: top;
1596
     vertical-align: top;
1597
   width: 10px;
1597
   width: 10px;
1598
}
1598
}
1599
.sourcecol {
1600
	vertical-align: top;
1601
	width: 100px;
1602
}
1599
#container {
1603
#container {
1600
    color : #000;
1604
    color : #000;
1601
}
1605
}
Lines 2865-2867 a.reviewlink,a.reviewlink:visited { Link Here
2865
    display: block;
2869
    display: block;
2866
    overflow: auto;
2870
    overflow: auto;
2867
}
2871
}
2872
2873
#modal-overlay {
2874
    background-color: white;
2875
    border-radius: 5px;
2876
    max-width: 75%;
2877
    padding: 15px;
2878
}
2879
2880
#overdrive-results, #pazpar2-results {
2881
    font-weight: bold;
2882
    padding-left: 1em;
2883
}
(-)a/koha-tmpl/opac-tmpl/ccsr/en/lib/jquery/plugins/jquery.lightbox_me.js (+254 lines)
Line 0 Link Here
1
/*
2
* $ lightbox_me
3
* By: Buck Wilson
4
* Version : 2.3
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
10
*     http://www.apache.org/licenses/LICENSE-2.0
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*/
18
19
20
(function($) {
21
22
    $.fn.lightbox_me = function(options) {
23
24
        return this.each(function() {
25
26
            var
27
                opts = $.extend({}, $.fn.lightbox_me.defaults, options),
28
                $overlay = $(),
29
                $self = $(this),
30
                $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();"/>'),
31
                ie6 = ($.browser.msie && $.browser.version < 7);
32
33
            if (opts.showOverlay) {
34
                //check if there's an existing overlay, if so, make subequent ones clear
35
               var $currentOverlays = $(".js_lb_overlay:visible");
36
                if ($currentOverlays.length > 0){
37
                    $overlay = $('<div class="lb_overlay_clear js_lb_overlay"/>');
38
                } else {
39
                    $overlay = $('<div class="' + opts.classPrefix + '_overlay js_lb_overlay"/>');
40
                }
41
            }
42
43
            /*----------------------------------------------------
44
               DOM Building
45
            ---------------------------------------------------- */
46
            if (ie6) {
47
                var src = /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank';
48
                $iframe.attr('src', src);
49
                $('body').append($iframe);
50
            } // iframe shim for ie6, to hide select elements
51
            $('body').append($self.hide()).append($overlay);
52
53
54
            /*----------------------------------------------------
55
               Overlay CSS stuffs
56
            ---------------------------------------------------- */
57
58
            // set css of the overlay
59
            if (opts.showOverlay) {
60
                setOverlayHeight(); // pulled this into a function because it is called on window resize.
61
                $overlay.css({ position: 'absolute', width: '100%', top: 0, left: 0, right: 0, bottom: 0, zIndex: (opts.zIndex + 2), display: 'none' });
62
				if (!$overlay.hasClass('lb_overlay_clear')){
63
			$overlay.css(opts.overlayCSS);
64
                }
65
            }
66
67
            /*----------------------------------------------------
68
               Animate it in.
69
            ---------------------------------------------------- */
70
               //
71
            if (opts.showOverlay) {
72
                $overlay.fadeIn(opts.overlaySpeed, function() {
73
                    setSelfPosition();
74
                    $self[opts.appearEffect](opts.lightboxSpeed, function() { setOverlayHeight(); setSelfPosition(); opts.onLoad()});
75
                });
76
            } else {
77
                setSelfPosition();
78
                $self[opts.appearEffect](opts.lightboxSpeed, function() { opts.onLoad()});
79
            }
80
81
            /*----------------------------------------------------
82
               Hide parent if parent specified (parentLightbox should be jquery reference to any parent lightbox)
83
            ---------------------------------------------------- */
84
            if (opts.parentLightbox) {
85
                opts.parentLightbox.fadeOut(200);
86
            }
87
88
89
            /*----------------------------------------------------
90
               Bind Events
91
            ---------------------------------------------------- */
92
93
            $(window).resize(setOverlayHeight)
94
                     .resize(setSelfPosition)
95
                     .scroll(setSelfPosition);
96
97
            $(window).bind('keyup.lightbox_me', observeKeyPress);
98
99
            if (opts.closeClick) {
100
                $overlay.click(function(e) { closeLightbox(); e.preventDefault; });
101
            }
102
            $self.delegate(opts.closeSelector, "click", function(e) {
103
                closeLightbox(); e.preventDefault();
104
            });
105
            $self.bind('close', closeLightbox);
106
            $self.bind('reposition', setSelfPosition);
107
108
109
110
            /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
111
              -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
112
113
114
            /*----------------------------------------------------
115
               Private Functions
116
            ---------------------------------------------------- */
117
118
            /* Remove or hide all elements */
119
            function closeLightbox() {
120
                var s = $self[0].style;
121
                if (opts.destroyOnClose) {
122
                    $self.add($overlay).remove();
123
                } else {
124
                    $self.add($overlay).hide();
125
                }
126
127
                //show the hidden parent lightbox
128
                if (opts.parentLightbox) {
129
                    opts.parentLightbox.fadeIn(200);
130
                }
131
132
                $iframe.remove();
133
134
				// clean up events.
135
                $self.undelegate(opts.closeSelector, "click");
136
137
                $(window).unbind('reposition', setOverlayHeight);
138
                $(window).unbind('reposition', setSelfPosition);
139
                $(window).unbind('scroll', setSelfPosition);
140
                $(window).unbind('keyup.lightbox_me');
141
                if (ie6)
142
                    s.removeExpression('top');
143
                opts.onClose();
144
            }
145
146
147
            /* Function to bind to the window to observe the escape/enter key press */
148
            function observeKeyPress(e) {
149
                if((e.keyCode == 27 || (e.DOM_VK_ESCAPE == 27 && e.which==0)) && opts.closeEsc) closeLightbox();
150
            }
151
152
153
            /* Set the height of the overlay
154
                    : if the document height is taller than the window, then set the overlay height to the document height.
155
                    : otherwise, just set overlay height: 100%
156
            */
157
            function setOverlayHeight() {
158
                if ($(window).height() < $(document).height()) {
159
                    $overlay.css({height: $(document).height() + 'px'});
160
                     $iframe.css({height: $(document).height() + 'px'});
161
                } else {
162
                    $overlay.css({height: '100%'});
163
                    if (ie6) {
164
                        $('html,body').css('height','100%');
165
                        $iframe.css('height', '100%');
166
                    } // ie6 hack for height: 100%; TODO: handle this in IE7
167
                }
168
            }
169
170
171
            /* Set the position of the modal'd window ($self)
172
                    : if $self is taller than the window, then make it absolutely positioned
173
                    : otherwise fixed
174
            */
175
            function setSelfPosition() {
176
                var s = $self[0].style;
177
178
                // reset CSS so width is re-calculated for margin-left CSS
179
                $self.css({left: '50%', marginLeft: ($self.outerWidth() / 2) * -1,  zIndex: (opts.zIndex + 3) });
180
181
182
                /* we have to get a little fancy when dealing with height, because lightbox_me
183
                    is just so fancy.
184
                 */
185
186
                // if the height of $self is bigger than the window and self isn't already position absolute
187
                if (($self.height() + 80  >= $(window).height()) && ($self.css('position') != 'absolute' || ie6)) {
188
189
                    // we are going to make it positioned where the user can see it, but they can still scroll
190
                    // so the top offset is based on the user's scroll position.
191
                    var topOffset = $(document).scrollTop() + 40;
192
                    $self.css({position: 'absolute', top: topOffset + 'px', marginTop: 0})
193
                    if (ie6) {
194
                        s.removeExpression('top');
195
                    }
196
                } else if ($self.height()+ 80  < $(window).height()) {
197
                    //if the height is less than the window height, then we're gonna make this thing position: fixed.
198
                    // in ie6 we're gonna fake it.
199
                    if (ie6) {
200
                        s.position = 'absolute';
201
                        if (opts.centered) {
202
                            s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"')
203
                            s.marginTop = 0;
204
                        } else {
205
                            var top = (opts.modalCSS && opts.modalCSS.top) ? parseInt(opts.modalCSS.top) : 0;
206
                            s.setExpression('top', '((blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"')
207
                        }
208
                    } else {
209
                        if (opts.centered) {
210
                            $self.css({ position: 'fixed', top: '50%', marginTop: ($self.outerHeight() / 2) * -1})
211
                        } else {
212
                            $self.css({ position: 'fixed'}).css(opts.modalCSS);
213
                        }
214
215
                    }
216
                }
217
            }
218
219
        });
220
221
222
223
    };
224
225
    $.fn.lightbox_me.defaults = {
226
227
        // animation
228
        appearEffect: "fadeIn",
229
        appearEase: "",
230
        overlaySpeed: 250,
231
        lightboxSpeed: 300,
232
233
        // close
234
        closeSelector: ".close",
235
        closeClick: true,
236
        closeEsc: true,
237
238
        // behavior
239
        destroyOnClose: false,
240
        showOverlay: true,
241
        parentLightbox: false,
242
243
        // callbacks
244
        onLoad: function() {},
245
        onClose: function() {},
246
247
        // style
248
        classPrefix: 'lb',
249
        zIndex: 999,
250
        centered: false,
251
        modalCSS: {top: '40px'},
252
        overlayCSS: {background: 'black', opacity: .3}
253
    }
254
})(jQuery);
(-)a/koha-tmpl/opac-tmpl/lib/koha/externalsearch.js (+104 lines)
Line 0 Link Here
1
if ( typeof KOHA == "undefined" || !KOHA ) {
2
    var KOHA = {};
3
}
4
5
KOHA.XSLTGet = ( function() {
6
    // Horrible browser hack, but required due to the following hard-to-detect and long-unfixed bug:
7
    // https://bugs.webkit.org/show_bug.cgi?id=60276
8
    var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
9
    var isSafari = /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor);
10
11
    if ( !isChrome && !isSafari ) return $.get;
12
13
    return function( url ) {
14
        var result = new jQuery.Deferred();
15
        var basepath = url.match( /(.*\/)*/ )[0];
16
17
        $.get( url ).done( function( xslDoc ) {
18
            var xslImports = xslDoc.getElementsByTagNameNS( 'http://www.w3.org/1999/XSL/Transform', 'import' );
19
            var importsRemaining = xslImports.length;
20
21
            if ( importsRemaining == 0 ) {
22
                result.resolve( xslDoc );
23
                return;
24
            }
25
26
            $.each( xslImports, function( i, importElem ) {
27
                var path = $( importElem ).attr( 'href' );
28
                if ( !/^(\/|https?:)/.test( path ) ) path = basepath + path;
29
30
                KOHA.XSLTGet( path ).done( function( subDoc ) {
31
                    importsRemaining--;
32
                    $( importElem ).replaceWith( subDoc.documentElement.childNodes );
33
34
                    if ( importsRemaining == 0 ) result.resolve( xslDoc );
35
                } ).fail( function() {
36
                    importsRemaining = -1;
37
38
                    result.reject();
39
                } );
40
            } );
41
        } ).fail( function() {
42
            result.reject();
43
        } );
44
45
        return result;
46
    };
47
} )();
48
49
KOHA.TransformToFragment = function( xmlDoc, xslDoc ) {
50
    if ( window.XSLTProcessor ) {
51
        var proc = new XSLTProcessor();
52
        proc.importStylesheet( xslDoc );
53
        proc.setParameter( null, 'showAvailability', false );
54
        return (new XMLSerializer).serializeToString( proc.transformToFragment( xmlDoc, document ) );
55
    } else if ( window.ActiveXObject ) {
56
        var xslt = new ActiveXObject( "Msxml2.XSLTemplate" );
57
        xslt.stylesheet = xslDoc;
58
        var xslProc = xslt.createProcessor();
59
        xslProc.input = xmlDoc;
60
        xslProc.addParameter( 'showAvailability', false );
61
        xslProc.transform();
62
        return xslProc.output;
63
    }
64
};
65
66
KOHA.ExternalSearch = ( function() {
67
    return {
68
        targets: {},
69
        Search: function( q, limit, callback ) {
70
            var includedTargets = [];
71
72
            $.each( KOHA.ExternalSearch.targets, function ( url, info ) {
73
                if ( !info.disabled ) {
74
                    includedTargets.push( url );
75
                }
76
            } );
77
78
            if ( KOHA.ExternalSearch._pz !== undefined ) {
79
                afterinit( KOHA.ExternalSearch._pz );
80
            } else {
81
                $.get( '/cgi-bin/koha/svc/pazpar2_init', {}, function( data ) {
82
                    KOHA.ExternalSearch._pz = new pz2({
83
                        sessionId: data.sessionID,
84
                        onshow: callback,
85
                        errorhandler: function ( error ) { callback( { error: error } ) },
86
                    } );
87
                    afterinit( KOHA.ExternalSearch._pz );
88
                } );
89
            }
90
91
            function afterinit( pz ) {
92
                pz.search( q, limit, 'relevance:0', 'pz:id=' + includedTargets.join( '|' ) );
93
            }
94
        },
95
        Fetch: function( offset, callback ) {
96
            var pz = KOHA.ExternalSearch._pz;
97
            pz.showCallback = callback;
98
            pz.show( offset );
99
        },
100
        GetDetailedRecord: function( recid, callback ) {
101
            KOHA.ExternalSearch._pz.record( recid, 0, undefined, { callback: callback } );
102
        },
103
    };
104
} )();
(-)a/koha-tmpl/opac-tmpl/lib/pz2.js (+1124 lines)
Line 0 Link Here
1
/*
2
 * pz2.js - pazpar2's javascript client library.
3
 * Copyright (C) 2006-2013 Index Data.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
*/
19
20
//since explorer is flawed
21
if (!window['Node']) {
22
    window.Node = new Object();
23
    Node.ELEMENT_NODE = 1;
24
    Node.ATTRIBUTE_NODE = 2;
25
    Node.TEXT_NODE = 3;
26
    Node.CDATA_SECTION_NODE = 4;
27
    Node.ENTITY_REFERENCE_NODE = 5;
28
    Node.ENTITY_NODE = 6;
29
    Node.PROCESSING_INSTRUCTION_NODE = 7;
30
    Node.COMMENT_NODE = 8;
31
    Node.DOCUMENT_NODE = 9;
32
    Node.DOCUMENT_TYPE_NODE = 10;
33
    Node.DOCUMENT_FRAGMENT_NODE = 11;
34
    Node.NOTATION_NODE = 12;
35
}
36
37
// prevent execution of more than once
38
if(typeof window.pz2 == "undefined") {
39
window.undefined = window.undefined;
40
41
var pz2 = function ( paramArray )
42
{
43
44
    // at least one callback required
45
    if ( !paramArray )
46
        throw new Error("Pz2.js: Array with parameters has to be supplied.");
47
48
    //supported pazpar2's protocol version
49
    this.suppProtoVer = '1';
50
    if (typeof paramArray.pazpar2path != "undefined")
51
        this.pz2String = paramArray.pazpar2path;
52
    else
53
        this.pz2String = "/pazpar2/search.pz2";
54
    this.useSessions = true;
55
56
    this.stylesheet = paramArray.detailstylesheet || null;
57
    //load stylesheet if required in async mode
58
    if( this.stylesheet ) {
59
        var context = this;
60
        var request = new pzHttpRequest( this.stylesheet );
61
        request.get( {}, function ( doc ) { context.xslDoc = doc; } );
62
    }
63
64
    this.errorHandler = paramArray.errorhandler || null;
65
    this.showResponseType = paramArray.showResponseType || "xml";
66
67
    // function callbacks
68
    this.initCallback = paramArray.oninit || null;
69
    this.statCallback = paramArray.onstat || null;
70
    this.showCallback = paramArray.onshow || null;
71
    this.termlistCallback = paramArray.onterm || null;
72
    this.recordCallback = paramArray.onrecord || null;
73
    this.bytargetCallback = paramArray.onbytarget || null;
74
    this.resetCallback = paramArray.onreset || null;
75
76
    // termlist keys
77
    this.termKeys = paramArray.termlist || "subject";
78
79
    // some configurational stuff
80
    this.keepAlive = 50000;
81
82
    if ( paramArray.keepAlive < this.keepAlive )
83
        this.keepAlive = paramArray.keepAlive;
84
85
    this.sessionID = paramArray.sessionId || null;
86
    this.serviceId = paramArray.serviceId || null;
87
    this.initStatusOK = false;
88
    this.pingStatusOK = false;
89
    this.searchStatusOK = false;
90
91
    // for sorting
92
    this.currentSort = "relevance";
93
94
    // where are we?
95
    this.currentStart = 0;
96
    // currentNum can be overwritten in show
97
    this.currentNum = 20;
98
99
    // last full record retrieved
100
    this.currRecID = null;
101
102
    // current query
103
    this.currQuery = null;
104
105
    //current raw record offset
106
    this.currRecOffset = null;
107
108
    //timers
109
    this.pingTimer = null;
110
    this.statTime = paramArray.stattime || 1000;
111
    this.statTimer = null;
112
    this.termTime = paramArray.termtime || 1000;
113
    this.termTimer = null;
114
    this.showTime = paramArray.showtime || 1000;
115
    this.showTimer = null;
116
    this.showFastCount = 4;
117
    this.bytargetTime = paramArray.bytargettime || 1000;
118
    this.bytargetTimer = null;
119
    this.recordTime = paramArray.recordtime || 500;
120
    this.recordTimer = null;
121
122
    // counters for each command and applied delay
123
    this.dumpFactor = 500;
124
    this.showCounter = 0;
125
    this.termCounter = 0;
126
    this.statCounter = 0;
127
    this.bytargetCounter = 0;
128
    this.recordCounter = 0;
129
130
    // active clients, updated by stat and show
131
    // might be an issue since bytarget will poll accordingly
132
    this.activeClients = 1;
133
134
    // if in proxy mode no need to init
135
    if (paramArray.usesessions != undefined) {
136
         this.useSessions = paramArray.usesessions;
137
        this.initStatusOK = true;
138
    }
139
    // else, auto init session or wait for a user init?
140
    if (this.useSessions && paramArray.autoInit !== false) {
141
        this.init(this.sessionID, this.serviceId);
142
    }
143
    // Version parameter
144
    this.version = paramArray.version || null;
145
};
146
147
pz2.prototype =
148
{
149
    //error handler for async error throws
150
   throwError: function (errMsg, errCode)
151
   {
152
        var err = new Error(errMsg);
153
        if (errCode) err.code = errCode;
154
155
        if (this.errorHandler) {
156
            this.errorHandler(err);
157
        }
158
        else {
159
            throw err;
160
        }
161
   },
162
163
    // stop activity by clearing tiemouts
164
   stop: function ()
165
   {
166
       clearTimeout(this.statTimer);
167
       clearTimeout(this.showTimer);
168
       clearTimeout(this.termTimer);
169
       clearTimeout(this.bytargetTimer);
170
    },
171
172
    // reset status variables
173
    reset: function ()
174
    {
175
        if ( this.useSessions ) {
176
            this.sessionID = null;
177
            this.initStatusOK = false;
178
            this.pingStatusOK = false;
179
            clearTimeout(this.pingTimer);
180
        }
181
        this.searchStatusOK = false;
182
        this.stop();
183
184
        if ( this.resetCallback )
185
                this.resetCallback();
186
    },
187
188
    init: function (sessionId, serviceId)
189
    {
190
        this.reset();
191
192
        // session id as a param
193
        if (sessionId && this.useSessions ) {
194
            this.initStatusOK = true;
195
            this.sessionID = sessionId;
196
            this.ping();
197
        // old school direct pazpar2 init
198
        } else if (this.useSessions) {
199
            var context = this;
200
            var request = new pzHttpRequest(this.pz2String, this.errorHandler);
201
            var opts = {'command' : 'init'};
202
            if (serviceId) opts.service = serviceId;
203
            request.safeGet(
204
                opts,
205
                function(data) {
206
                    if ( data.getElementsByTagName("status")[0]
207
                            .childNodes[0].nodeValue == "OK" ) {
208
                        if ( data.getElementsByTagName("protocol")[0]
209
                                .childNodes[0].nodeValue
210
                            != context.suppProtoVer )
211
                            throw new Error(
212
                                "Server's protocol not supported by the client"
213
                            );
214
                        context.initStatusOK = true;
215
                        context.sessionID =
216
                            data.getElementsByTagName("session")[0]
217
                                .childNodes[0].nodeValue;
218
                        if (data.getElementsByTagName("keepAlive").length > 0) {
219
                            context.keepAlive = data.getElementsByTagName("keepAlive")[0].childNodes[0].nodeValue;
220
                        }
221
                        context.pingTimer =
222
                            setTimeout(
223
                                function () {
224
                                    context.ping();
225
                                },
226
                                context.keepAlive
227
                            );
228
                        if ( context.initCallback )
229
                            context.initCallback();
230
                    }
231
                    else
232
                        context.throwError('Init failed. Malformed WS resonse.',
233
                                            110);
234
                }
235
            );
236
        // when through proxy no need to init
237
        } else {
238
            this.initStatusOK = true;
239
	}
240
    },
241
    // no need to ping explicitly
242
    ping: function ()
243
    {
244
        // pinging only makes sense when using pazpar2 directly
245
        if( !this.initStatusOK || !this.useSessions )
246
            throw new Error(
247
            'Pz2.js: Ping not allowed (proxy mode) or session not initialized.'
248
            );
249
        var context = this;
250
251
        clearTimeout(context.pingTimer);
252
253
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
254
        request.safeGet(
255
            { "command": "ping", "session": this.sessionID, "windowid" : window.name },
256
            function(data) {
257
                if ( data.getElementsByTagName("status")[0]
258
                        .childNodes[0].nodeValue == "OK" ) {
259
                    context.pingStatusOK = true;
260
                    context.pingTimer =
261
                        setTimeout(
262
                            function () {
263
                                context.ping();
264
                            },
265
                            context.keepAlive
266
                        );
267
                }
268
                else
269
                    context.throwError('Ping failed. Malformed WS resonse.',
270
                                        111);
271
            }
272
        );
273
    },
274
    search: function (query, num, sort, filter, showfrom, addParamsArr)
275
    {
276
        clearTimeout(this.statTimer);
277
        clearTimeout(this.showTimer);
278
        clearTimeout(this.termTimer);
279
        clearTimeout(this.bytargetTimer);
280
281
        this.showCounter = 0;
282
        this.termCounter = 0;
283
        this.bytargetCounter = 0;
284
        this.statCounter = 0;
285
        this.activeClients = 1;
286
287
        // no proxy mode
288
        if( !this.initStatusOK )
289
            throw new Error('Pz2.js: session not initialized.');
290
291
        if( query !== undefined )
292
            this.currQuery = query;
293
        else
294
            throw new Error("Pz2.js: no query supplied to the search command.");
295
296
        if ( showfrom !== undefined )
297
            var start = showfrom;
298
        else
299
            var start = 0;
300
301
	var searchParams = {
302
          "command": "search",
303
          "query": this.currQuery,
304
          "session": this.sessionID,
305
          "windowid" : window.name
306
        };
307
308
        if( sort !== undefined ) {
309
            this.currentSort = sort;
310
	    searchParams["sort"] = sort;
311
	}
312
        if (filter !== undefined)
313
	        searchParams["filter"] = filter;
314
315
        // copy additional parmeters, do not overwrite
316
        if (addParamsArr != undefined) {
317
            for (var prop in addParamsArr) {
318
                if (!searchParams.hasOwnProperty(prop))
319
                    searchParams[prop] = addParamsArr[prop];
320
            }
321
        }
322
323
        var context = this;
324
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
325
        request.safeGet(
326
            searchParams,
327
            function(data) {
328
                if ( data.getElementsByTagName("status")[0]
329
                        .childNodes[0].nodeValue == "OK" ) {
330
                    context.searchStatusOK = true;
331
                    //piggyback search
332
                    context.show(start, num, sort);
333
                    if (context.statCallback)
334
                        context.stat();
335
                    if (context.termlistCallback)
336
                        context.termlist();
337
                    if (context.bytargetCallback)
338
                        context.bytarget();
339
                }
340
                else
341
                    context.throwError('Search failed. Malformed WS resonse.',
342
                                        112);
343
            }
344
        );
345
    },
346
    stat: function()
347
    {
348
        if( !this.initStatusOK )
349
            throw new Error('Pz2.js: session not initialized.');
350
351
        // if called explicitly takes precedence
352
        clearTimeout(this.statTimer);
353
354
        var context = this;
355
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
356
        request.safeGet(
357
            { "command": "stat", "session": this.sessionID, "windowid" : window.name },
358
            function(data) {
359
                if ( data.getElementsByTagName("stat") ) {
360
                    var activeClients =
361
                        Number( data.getElementsByTagName("activeclients")[0]
362
                                    .childNodes[0].nodeValue );
363
                    context.activeClients = activeClients;
364
365
		    var stat = Element_parseChildNodes(data.documentElement);
366
367
                    context.statCounter++;
368
		    var delay = context.statTime
369
                        + context.statCounter * context.dumpFactor;
370
371
                    if ( activeClients > 0 )
372
                        context.statTimer =
373
                            setTimeout(
374
                                function () {
375
                                    context.stat();
376
                                },
377
                                delay
378
                            );
379
                    context.statCallback(stat);
380
                }
381
                else
382
                    context.throwError('Stat failed. Malformed WS resonse.',
383
                                        113);
384
            }
385
        );
386
    },
387
    show: function(start, num, sort, query_state)
388
    {
389
        if( !this.searchStatusOK && this.useSessions )
390
            throw new Error(
391
                'Pz2.js: show command has to be preceded with a search command.'
392
            );
393
394
        // if called explicitly takes precedence
395
        clearTimeout(this.showTimer);
396
397
        if( sort !== undefined )
398
            this.currentSort = sort;
399
        if( start !== undefined )
400
            this.currentStart = Number( start );
401
        if( num !== undefined )
402
            this.currentNum = Number( num );
403
404
        var context = this;
405
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
406
	var requestParameters =
407
          {
408
              "command": "show",
409
              "session": this.sessionID,
410
              "start": this.currentStart,
411
              "num": this.currentNum,
412
              "sort": this.currentSort,
413
              "block": 1,
414
              "type": this.showResponseType,
415
              "windowid" : window.name
416
          };
417
        if (query_state)
418
          requestParameters["query-state"] = query_state;
419
	if (this.version && this.version > 0)
420
	    requestParameters["version"] = this.version;
421
        request.safeGet(
422
	  requestParameters,
423
          function(data, type) {
424
            var show = null;
425
            var activeClients = 0;
426
            if (type === "json") {
427
              show = {};
428
              activeClients = Number(data.activeclients[0]);
429
              show.activeclients = activeClients;
430
              show.merged = Number(data.merged[0]);
431
              show.total = Number(data.total[0]);
432
              show.start = Number(data.start[0]);
433
              show.num = Number(data.num[0]);
434
              show.hits = data.hit;
435
            } else if (data.getElementsByTagName("status")[0]
436
                  .childNodes[0].nodeValue == "OK") {
437
                // first parse the status data send along with records
438
                // this is strictly bound to the format
439
                activeClients =
440
                  Number(data.getElementsByTagName("activeclients")[0]
441
                      .childNodes[0].nodeValue);
442
                show = {
443
                  "activeclients": activeClients,
444
                  "merged":
445
                    Number( data.getElementsByTagName("merged")[0]
446
                        .childNodes[0].nodeValue ),
447
                  "total":
448
                    Number( data.getElementsByTagName("total")[0]
449
                        .childNodes[0].nodeValue ),
450
                  "start":
451
                    Number( data.getElementsByTagName("start")[0]
452
                        .childNodes[0].nodeValue ),
453
                  "num":
454
                    Number( data.getElementsByTagName("num")[0]
455
                        .childNodes[0].nodeValue ),
456
                  "hits": []
457
                };
458
                // parse all the first-level nodes for all <hit> tags
459
                var hits = data.getElementsByTagName("hit");
460
                for (i = 0; i < hits.length; i++)
461
                  show.hits[i] = Element_parseChildNodes(hits[i]);
462
            } else {
463
              context.throwError('Show failed. Malformed WS resonse.',
464
                  114);
465
            };
466
467
	    var approxNode = data.getElementsByTagName("approximation");
468
	    if (approxNode && approxNode[0] && approxNode[0].childNodes[0] && approxNode[0].childNodes[0].nodeValue)
469
		show['approximation'] =
470
		  Number( approxNode[0].childNodes[0].nodeValue);
471
472
473
	      data.getElementsByTagName("")
474
            context.activeClients = activeClients;
475
            context.showCounter++;
476
            var delay = context.showTime;
477
            if (context.showCounter > context.showFastCount)
478
              delay += context.showCounter * context.dumpFactor;
479
            if ( activeClients > 0 )
480
              context.showTimer = setTimeout(
481
                function () {
482
                  context.show();
483
                },
484
                delay);
485
            context.showCallback(show);
486
          }
487
        );
488
    },
489
    record: function(id, offset, syntax, handler)
490
    {
491
        // we may call record with no previous search if in proxy mode
492
        if(!this.searchStatusOK && this.useSessions)
493
           throw new Error(
494
            'Pz2.js: record command has to be preceded with a search command.'
495
            );
496
497
        if( id !== undefined )
498
            this.currRecID = id;
499
500
	var recordParams = {
501
            "command": "record",
502
            "session": this.sessionID,
503
            "id": this.currRecID,
504
            "windowid" : window.name
505
        };
506
507
	this.currRecOffset = null;
508
        if (offset != undefined) {
509
	    recordParams["offset"] = offset;
510
            this.currRecOffset = offset;
511
        }
512
513
        if (syntax != undefined)
514
            recordParams['syntax'] = syntax;
515
516
        //overwrite default callback id needed
517
        var callback = this.recordCallback;
518
        var args = undefined;
519
        if (handler != undefined) {
520
            callback = handler['callback'];
521
            args = handler['args'];
522
        }
523
524
        var context = this;
525
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
526
527
        request.safeGet(
528
	    recordParams,
529
            function(data) {
530
                var recordNode;
531
                var record;
532
                //raw record
533
                if (context.currRecOffset !== null) {
534
                    record = new Array();
535
                    record['xmlDoc'] = data;
536
                    record['offset'] = context.currRecOffset;
537
                    callback(record, args);
538
                //pz2 record
539
                } else if ( recordNode =
540
                    data.getElementsByTagName("record")[0] ) {
541
                    // if stylesheet was fetched do not parse the response
542
                    if ( context.xslDoc ) {
543
                        record = new Array();
544
                        record['xmlDoc'] = data;
545
                        record['xslDoc'] = context.xslDoc;
546
                        record['recid'] =
547
                            recordNode.getElementsByTagName("recid")[0]
548
                                .firstChild.nodeValue;
549
                    //parse record
550
                    } else {
551
                        record = Element_parseChildNodes(recordNode);
552
                    }
553
		    var activeClients =
554
		       Number( data.getElementsByTagName("activeclients")[0]
555
				.childNodes[0].nodeValue );
556
		    context.activeClients = activeClients;
557
                    context.recordCounter++;
558
                    var delay = context.recordTime + context.recordCounter * context.dumpFactor;
559
                    if ( activeClients > 0 )
560
                        context.recordTimer =
561
                           setTimeout (
562
                               function() {
563
                                  context.record(id, offset, syntax, handler);
564
                                  },
565
                                  delay
566
                               );
567
                    callback(record, args);
568
                }
569
                else
570
                    context.throwError('Record failed. Malformed WS resonse.',
571
                                        115);
572
            }
573
        );
574
    },
575
576
    termlist: function()
577
    {
578
        if( !this.searchStatusOK && this.useSessions )
579
            throw new Error(
580
            'Pz2.js: termlist command has to be preceded with a search command.'
581
            );
582
583
        // if called explicitly takes precedence
584
        clearTimeout(this.termTimer);
585
586
        var context = this;
587
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
588
        request.safeGet(
589
            {
590
                "command": "termlist",
591
                "session": this.sessionID,
592
                "name": this.termKeys,
593
                "windowid" : window.name,
594
		"version" : this.version
595
596
            },
597
            function(data) {
598
                if ( data.getElementsByTagName("termlist") ) {
599
                    var activeClients =
600
                        Number( data.getElementsByTagName("activeclients")[0]
601
                                    .childNodes[0].nodeValue );
602
                    context.activeClients = activeClients;
603
                    var termList = { "activeclients":  activeClients };
604
                    var termLists = data.getElementsByTagName("list");
605
                    //for each termlist
606
                    for (i = 0; i < termLists.length; i++) {
607
			var listName = termLists[i].getAttribute('name');
608
                        termList[listName] = new Array();
609
                        var terms = termLists[i].getElementsByTagName('term');
610
                        //for each term in the list
611
                        for (j = 0; j < terms.length; j++) {
612
                            var term = {
613
                                "name":
614
                                    (terms[j].getElementsByTagName("name")[0]
615
                                        .childNodes.length
616
                                    ? terms[j].getElementsByTagName("name")[0]
617
                                        .childNodes[0].nodeValue
618
                                    : 'ERROR'),
619
                                "freq":
620
                                    terms[j]
621
                                    .getElementsByTagName("frequency")[0]
622
                                    .childNodes[0].nodeValue || 'ERROR'
623
                            };
624
625
			    // Only for xtargets: id, records, filtered
626
                            var termIdNode =
627
                                terms[j].getElementsByTagName("id");
628
                            if(terms[j].getElementsByTagName("id").length)
629
                                term["id"] =
630
                                    termIdNode[0].childNodes[0].nodeValue;
631
                            termList[listName][j] = term;
632
633
			    var recordsNode  = terms[j].getElementsByTagName("records");
634
			    if (recordsNode && recordsNode.length)
635
				term["records"] = recordsNode[0].childNodes[0].nodeValue;
636
637
			    var filteredNode  = terms[j].getElementsByTagName("filtered");
638
			    if (filteredNode && filteredNode.length)
639
				term["filtered"] = filteredNode[0].childNodes[0].nodeValue;
640
641
                        }
642
                    }
643
644
                    context.termCounter++;
645
                    var delay = context.termTime
646
                        + context.termCounter * context.dumpFactor;
647
                    if ( activeClients > 0 )
648
                        context.termTimer =
649
                            setTimeout(
650
                                function () {
651
                                    context.termlist();
652
                                },
653
                                delay
654
                            );
655
656
                   context.termlistCallback(termList);
657
                }
658
                else
659
                    context.throwError('Termlist failed. Malformed WS resonse.',
660
                                        116);
661
            }
662
        );
663
664
    },
665
    bytarget: function()
666
    {
667
        if( !this.initStatusOK && this.useSessions )
668
            throw new Error(
669
            'Pz2.js: bytarget command has to be preceded with a search command.'
670
            );
671
672
        // no need to continue
673
        if( !this.searchStatusOK )
674
            return;
675
676
        // if called explicitly takes precedence
677
        clearTimeout(this.bytargetTimer);
678
679
        var context = this;
680
        var request = new pzHttpRequest(this.pz2String, this.errorHandler);
681
        request.safeGet(
682
            {
683
		"command": "bytarget",
684
		"session": this.sessionID,
685
		"block": 1,
686
		"windowid" : window.name,
687
		"version" : this.version
688
	    },
689
            function(data) {
690
                if ( data.getElementsByTagName("status")[0]
691
                        .childNodes[0].nodeValue == "OK" ) {
692
                    var targetNodes = data.getElementsByTagName("target");
693
                    var bytarget = new Array();
694
                    for ( i = 0; i < targetNodes.length; i++) {
695
                        bytarget[i] = new Array();
696
                        for( j = 0; j < targetNodes[i].childNodes.length; j++ ) {
697
                            if ( targetNodes[i].childNodes[j].nodeType
698
                                == Node.ELEMENT_NODE ) {
699
                                var nodeName =
700
                                    targetNodes[i].childNodes[j].nodeName;
701
				if (targetNodes[i].childNodes[j].firstChild != null)
702
				{
703
                                    var nodeText = targetNodes[i].childNodes[j]
704
					.firstChild.nodeValue;
705
                                    bytarget[i][nodeName] = nodeText;
706
				}
707
				else {
708
				    bytarget[i][nodeName] = "";
709
				}
710
711
712
                            }
713
                        }
714
                        if (bytarget[i]["state"]=="Client_Disconnected") {
715
                          bytarget[i]["hits"] = "Error";
716
                        } else if (bytarget[i]["state"]=="Client_Error") {
717
                          bytarget[i]["hits"] = "Error";
718
                        } else if (bytarget[i]["state"]=="Client_Working") {
719
                          bytarget[i]["hits"] = "...";
720
                        }
721
                        if (bytarget[i].diagnostic == "1") {
722
                          bytarget[i].diagnostic = "Permanent system error";
723
                        } else if (bytarget[i].diagnostic == "2") {
724
                          bytarget[i].diagnostic = "Temporary system error";
725
                        }
726
                        var targetsSuggestions = targetNodes[i].getElementsByTagName("suggestions");
727
                        if (targetsSuggestions != undefined && targetsSuggestions.length>0) {
728
                          var suggestions = targetsSuggestions[0];
729
                          bytarget[i]["suggestions"] = Element_parseChildNodes(suggestions);
730
                        }
731
                    }
732
733
                    context.bytargetCounter++;
734
                    var delay = context.bytargetTime
735
                        + context.bytargetCounter * context.dumpFactor;
736
                    if ( context.activeClients > 0 )
737
                        context.bytargetTimer =
738
                            setTimeout(
739
                                function () {
740
                                    context.bytarget();
741
                                },
742
                                delay
743
                            );
744
745
                    context.bytargetCallback(bytarget);
746
                }
747
                else
748
                    context.throwError('Bytarget failed. Malformed WS resonse.',
749
                                        117);
750
            }
751
        );
752
    },
753
754
    // just for testing, probably shouldn't be here
755
    showNext: function(page)
756
    {
757
        var step = page || 1;
758
        this.show( ( step * this.currentNum ) + this.currentStart );
759
    },
760
761
    showPrev: function(page)
762
    {
763
        if (this.currentStart == 0 )
764
            return false;
765
        var step = page || 1;
766
        var newStart = this.currentStart - (step * this.currentNum );
767
        this.show( newStart > 0 ? newStart : 0 );
768
    },
769
770
    showPage: function(pageNum)
771
    {
772
        //var page = pageNum || 1;
773
        this.show(pageNum * this.currentNum);
774
    }
775
};
776
777
/*
778
********************************************************************************
779
** AJAX HELPER CLASS ***********************************************************
780
********************************************************************************
781
*/
782
var pzHttpRequest = function ( url, errorHandler ) {
783
        this.maxUrlLength = 2048;
784
        this.request = null;
785
        this.url = url;
786
        this.errorHandler = errorHandler || null;
787
        this.async = true;
788
        this.requestHeaders = {};
789
790
        if ( window.XMLHttpRequest ) {
791
            this.request = new XMLHttpRequest();
792
        } else if ( window.ActiveXObject ) {
793
            try {
794
                this.request = new ActiveXObject( 'Msxml2.XMLHTTP' );
795
            } catch (err) {
796
                this.request = new ActiveXObject( 'Microsoft.XMLHTTP' );
797
            }
798
        }
799
};
800
801
802
pzHttpRequest.prototype =
803
{
804
    safeGet: function ( params, callback )
805
    {
806
        var encodedParams =  this.encodeParams(params);
807
        var url = this._urlAppendParams(encodedParams);
808
        if (url.length >= this.maxUrlLength) {
809
            this.requestHeaders["Content-Type"]
810
                = "application/x-www-form-urlencoded";
811
            this._send( 'POST', this.url, encodedParams, callback );
812
        } else {
813
            this._send( 'GET', url, '', callback );
814
        }
815
    },
816
817
    get: function ( params, callback )
818
    {
819
        this._send( 'GET', this._urlAppendParams(this.encodeParams(params)),
820
            '', callback );
821
    },
822
823
    post: function ( params, data, callback )
824
    {
825
        this._send( 'POST', this._urlAppendParams(this.encodeParams(params)),
826
            data, callback );
827
    },
828
829
    load: function ()
830
    {
831
        this.async = false;
832
        this.request.open( 'GET', this.url, this.async );
833
        this.request.send('');
834
        if ( this.request.status == 200 )
835
            return this.request.responseXML;
836
    },
837
838
    encodeParams: function (params)
839
    {
840
        var sep = "";
841
        var encoded = "";
842
        for (var key in params) {
843
            if (params[key] != null) {
844
                encoded += sep + key + '=' + encodeURIComponent(params[key]);
845
                sep = '&';
846
            }
847
        }
848
        return encoded;
849
    },
850
851
    _send: function ( type, url, data, callback)
852
    {
853
        var context = this;
854
        this.callback = callback;
855
        this.async = true;
856
        this.request.open( type, url, this.async );
857
        for (var key in this.requestHeaders)
858
            this.request.setRequestHeader(key, this.requestHeaders[key]);
859
        this.request.onreadystatechange = function () {
860
            context._handleResponse(url); /// url used ONLY for error reporting
861
        }
862
        this.request.send(data);
863
    },
864
865
    _urlAppendParams: function (encodedParams)
866
    {
867
        if (encodedParams)
868
            return this.url + "?" + encodedParams;
869
        else
870
            return this.url;
871
    },
872
873
    _handleResponse: function (savedUrlForErrorReporting)
874
    {
875
        if ( this.request.readyState == 4 ) {
876
            // pick up appplication errors first
877
            var errNode = null;
878
            if (this.request.responseXML &&
879
                (errNode = this.request.responseXML.documentElement)
880
                && errNode.nodeName == 'error') {
881
                var errMsg = errNode.getAttribute("msg");
882
                var errCode = errNode.getAttribute("code");
883
                var errAddInfo = '';
884
                if (errNode.childNodes.length)
885
                    errAddInfo = ': ' + errNode.childNodes[0].nodeValue;
886
887
                var err = new Error(errMsg + errAddInfo);
888
                err.code = errCode;
889
890
                if (this.errorHandler) {
891
                    this.errorHandler(err);
892
                }
893
                else {
894
                    throw err;
895
                }
896
            } else if (this.request.status == 200 &&
897
                       this.request.responseXML == null) {
898
              if (this.request.responseText != null) {
899
                //assume JSON
900
901
		var json = null;
902
		var text = this.request.responseText;
903
		if (typeof window.JSON == "undefined")
904
		    json = eval("(" + text + ")");
905
		else {
906
		    try	{
907
			json = JSON.parse(text);
908
		    }
909
		    catch (e) {
910
			// Safari: eval will fail as well. Considering trying JSON2 (non-native implementation) instead
911
			/* DEBUG only works in mk2-mobile
912
			if (document.getElementById("log"))
913
			    document.getElementById("log").innerHTML = "" + e + " " + length + ": " + text;
914
			*/
915
			try {
916
			    json = eval("(" + text + ")");
917
			}
918
			catch (e) {
919
			    /* DEBUG only works in mk2-mobile
920
			    if (document.getElementById("log"))
921
				document.getElementById("log").innerHTML = "" + e + " " + length + ": " + text;
922
			    */
923
			}
924
		    }
925
		}
926
		this.callback(json, "json");
927
              } else {
928
                var err = new Error("XML response is empty but no error " +
929
                                    "for " + savedUrlForErrorReporting);
930
                err.code = -1;
931
                if (this.errorHandler) {
932
                    this.errorHandler(err);
933
                } else {
934
                    throw err;
935
                }
936
              }
937
            } else if (this.request.status == 200) {
938
                this.callback(this.request.responseXML);
939
            } else {
940
                var err = new Error("HTTP response not OK: "
941
                            + this.request.status + " - "
942
                            + this.request.statusText );
943
                err.code = '00' + this.request.status;
944
                if (this.errorHandler) {
945
                    this.errorHandler(err);
946
                }
947
                else {
948
                    throw err;
949
                }
950
            }
951
        }
952
    }
953
};
954
955
/*
956
********************************************************************************
957
** XML HELPER FUNCTIONS ********************************************************
958
********************************************************************************
959
*/
960
961
// DOMDocument
962
963
if ( window.ActiveXObject) {
964
    var DOMDoc = document;
965
} else {
966
    var DOMDoc = Document.prototype;
967
}
968
969
DOMDoc.newXmlDoc = function ( root )
970
{
971
    var doc;
972
973
    if (document.implementation && document.implementation.createDocument) {
974
        doc = document.implementation.createDocument('', root, null);
975
    } else if ( window.ActiveXObject ) {
976
        doc = new ActiveXObject("MSXML2.DOMDocument");
977
        doc.loadXML('<' + root + '/>');
978
    } else {
979
        throw new Error ('No XML support in this browser');
980
    }
981
982
    return doc;
983
}
984
985
986
DOMDoc.parseXmlFromString = function ( xmlString )
987
{
988
    var doc;
989
990
    if ( window.DOMParser ) {
991
        var parser = new DOMParser();
992
        doc = parser.parseFromString( xmlString, "text/xml");
993
    } else if ( window.ActiveXObject ) {
994
        doc = new ActiveXObject("MSXML2.DOMDocument");
995
        doc.loadXML( xmlString );
996
    } else {
997
        throw new Error ("No XML parsing support in this browser.");
998
    }
999
1000
    return doc;
1001
}
1002
1003
DOMDoc.transformToDoc = function (xmlDoc, xslDoc)
1004
{
1005
    if ( window.XSLTProcessor ) {
1006
        var proc = new XSLTProcessor();
1007
        proc.importStylesheet( xslDoc );
1008
        return proc.transformToDocument(xmlDoc);
1009
    } else if ( window.ActiveXObject ) {
1010
        return document.parseXmlFromString(xmlDoc.transformNode(xslDoc));
1011
    } else {
1012
        alert( 'Unable to perform XSLT transformation in this browser' );
1013
    }
1014
}
1015
1016
// DOMElement
1017
1018
Element_removeFromDoc = function (DOM_Element)
1019
{
1020
    DOM_Element.parentNode.removeChild(DOM_Element);
1021
}
1022
1023
Element_emptyChildren = function (DOM_Element)
1024
{
1025
    while( DOM_Element.firstChild ) {
1026
        DOM_Element.removeChild( DOM_Element.firstChild )
1027
    }
1028
}
1029
1030
Element_appendTransformResult = function ( DOM_Element, xmlDoc, xslDoc )
1031
{
1032
    if ( window.XSLTProcessor ) {
1033
        var proc = new XSLTProcessor();
1034
        proc.importStylesheet( xslDoc );
1035
        var docFrag = false;
1036
        docFrag = proc.transformToFragment( xmlDoc, DOM_Element.ownerDocument );
1037
        DOM_Element.appendChild(docFrag);
1038
    } else if ( window.ActiveXObject ) {
1039
        DOM_Element.innerHTML = xmlDoc.transformNode( xslDoc );
1040
    } else {
1041
        alert( 'Unable to perform XSLT transformation in this browser' );
1042
    }
1043
}
1044
1045
Element_appendTextNode = function (DOM_Element, tagName, textContent )
1046
{
1047
    var node = DOM_Element.ownerDocument.createElement(tagName);
1048
    var text = DOM_Element.ownerDocument.createTextNode(textContent);
1049
1050
    DOM_Element.appendChild(node);
1051
    node.appendChild(text);
1052
1053
    return node;
1054
}
1055
1056
Element_setTextContent = function ( DOM_Element, textContent )
1057
{
1058
    if (typeof DOM_Element.textContent !== "undefined") {
1059
        DOM_Element.textContent = textContent;
1060
    } else if (typeof DOM_Element.innerText !== "undefined" ) {
1061
        DOM_Element.innerText = textContent;
1062
    } else {
1063
        throw new Error("Cannot set text content of the node, no such method.");
1064
    }
1065
}
1066
1067
Element_getTextContent = function (DOM_Element)
1068
{
1069
    if ( typeof DOM_Element.textContent != 'undefined' ) {
1070
        return DOM_Element.textContent;
1071
    } else if (typeof DOM_Element.text != 'undefined') {
1072
        return DOM_Element.text;
1073
    } else {
1074
        throw new Error("Cannot get text content of the node, no such method.");
1075
    }
1076
}
1077
1078
Element_parseChildNodes = function (node)
1079
{
1080
    var parsed = {};
1081
    var hasChildElems = false;
1082
    var textContent = '';
1083
1084
    if (node.hasChildNodes()) {
1085
        var children = node.childNodes;
1086
        for (var i = 0; i < children.length; i++) {
1087
            var child = children[i];
1088
            switch (child.nodeType) {
1089
              case Node.ELEMENT_NODE:
1090
                hasChildElems = true;
1091
                var nodeName = child.nodeName;
1092
                if (!(nodeName in parsed))
1093
                    parsed[nodeName] = [];
1094
                parsed[nodeName].push(Element_parseChildNodes(child));
1095
                break;
1096
              case Node.TEXT_NODE:
1097
                textContent += child.nodeValue;
1098
                break;
1099
              case Node.CDATA_SECTION_NODE:
1100
                textContent += child.nodeValue;
1101
                break;
1102
            }
1103
        }
1104
    }
1105
1106
    var attrs = node.attributes;
1107
    for (var i = 0; i < attrs.length; i++) {
1108
        hasChildElems = true;
1109
        var attrName = '@' + attrs[i].nodeName;
1110
        var attrValue = attrs[i].nodeValue;
1111
        parsed[attrName] = attrValue;
1112
    }
1113
1114
    // if no nested elements/attrs set value to text
1115
    if (hasChildElems)
1116
      parsed['#text'] = textContent;
1117
    else
1118
      parsed = textContent;
1119
1120
    return parsed;
1121
}
1122
1123
/* do not remove trailing bracket */
1124
}
(-)a/koha-tmpl/opac-tmpl/prog/en/css/opac.css (-1 / +26 lines)
Lines 1677-1682 strong em, em strong { Link Here
1677
	vertical-align: top;
1677
	vertical-align: top;
1678
	width: 10px;
1678
	width: 10px;
1679
}
1679
}
1680
.sourcecol {
1681
	vertical-align: top;
1682
	width: 100px;
1683
}
1680
#container {
1684
#container {
1681
	color : #000;
1685
	color : #000;
1682
}
1686
}
Lines 3006-3011 float:left; Link Here
3006
padding: 0.1em 0;
3010
padding: 0.1em 0;
3007
}
3011
}
3008
3012
3013
.notesrow label {
3014
    font-weight: bold;
3015
}
3016
.notesrow span {
3017
    display: block;
3018
}
3019
.notesrow textarea {
3020
    width: 100%;
3021
}
3022
3009
.thumbnail-shelfbrowser span {
3023
.thumbnail-shelfbrowser span {
3010
    margin: 0px auto;
3024
    margin: 0px auto;
3011
}
3025
}
Lines 3030-3036 padding: 0.1em 0; Link Here
3030
    background: #EEEEEE none;
3044
    background: #EEEEEE none;
3031
}
3045
}
3032
3046
3033
#overdrive-results {
3047
#overdrive-results, #pazpar2-results {
3034
    font-weight: bold;
3048
    font-weight: bold;
3035
    padding-left: 1em;
3049
    padding-left: 1em;
3036
}
3050
}
Lines 3074-3076 padding: 0.1em 0; Link Here
3074
    width: 35%;
3088
    width: 35%;
3075
    font-size: 111%;
3089
    font-size: 111%;
3076
}
3090
}
3091
3092
.thumbnail-shelfbrowser span {
3093
    margin: 0px auto;
3094
}
3095
3096
#modal-overlay {
3097
    background-color: white;
3098
    border-radius: 5px;
3099
    max-width: 75%;
3100
    padding: 15px;
3101
}
(-)a/koha-tmpl/opac-tmpl/prog/en/lib/jquery/plugins/jquery.lightbox_me.js (+254 lines)
Line 0 Link Here
1
/*
2
* $ lightbox_me
3
* By: Buck Wilson
4
* Version : 2.3
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
10
*     http://www.apache.org/licenses/LICENSE-2.0
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*/
18
19
20
(function($) {
21
22
    $.fn.lightbox_me = function(options) {
23
24
        return this.each(function() {
25
26
            var
27
                opts = $.extend({}, $.fn.lightbox_me.defaults, options),
28
                $overlay = $(),
29
                $self = $(this),
30
                $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();"/>'),
31
                ie6 = ($.browser.msie && $.browser.version < 7);
32
33
            if (opts.showOverlay) {
34
                //check if there's an existing overlay, if so, make subequent ones clear
35
               var $currentOverlays = $(".js_lb_overlay:visible");
36
                if ($currentOverlays.length > 0){
37
                    $overlay = $('<div class="lb_overlay_clear js_lb_overlay"/>');
38
                } else {
39
                    $overlay = $('<div class="' + opts.classPrefix + '_overlay js_lb_overlay"/>');
40
                }
41
            }
42
43
            /*----------------------------------------------------
44
               DOM Building
45
            ---------------------------------------------------- */
46
            if (ie6) {
47
                var src = /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank';
48
                $iframe.attr('src', src);
49
                $('body').append($iframe);
50
            } // iframe shim for ie6, to hide select elements
51
            $('body').append($self.hide()).append($overlay);
52
53
54
            /*----------------------------------------------------
55
               Overlay CSS stuffs
56
            ---------------------------------------------------- */
57
58
            // set css of the overlay
59
            if (opts.showOverlay) {
60
                setOverlayHeight(); // pulled this into a function because it is called on window resize.
61
                $overlay.css({ position: 'absolute', width: '100%', top: 0, left: 0, right: 0, bottom: 0, zIndex: (opts.zIndex + 2), display: 'none' });
62
				if (!$overlay.hasClass('lb_overlay_clear')){
63
			$overlay.css(opts.overlayCSS);
64
                }
65
            }
66
67
            /*----------------------------------------------------
68
               Animate it in.
69
            ---------------------------------------------------- */
70
               //
71
            if (opts.showOverlay) {
72
                $overlay.fadeIn(opts.overlaySpeed, function() {
73
                    setSelfPosition();
74
                    $self[opts.appearEffect](opts.lightboxSpeed, function() { setOverlayHeight(); setSelfPosition(); opts.onLoad()});
75
                });
76
            } else {
77
                setSelfPosition();
78
                $self[opts.appearEffect](opts.lightboxSpeed, function() { opts.onLoad()});
79
            }
80
81
            /*----------------------------------------------------
82
               Hide parent if parent specified (parentLightbox should be jquery reference to any parent lightbox)
83
            ---------------------------------------------------- */
84
            if (opts.parentLightbox) {
85
                opts.parentLightbox.fadeOut(200);
86
            }
87
88
89
            /*----------------------------------------------------
90
               Bind Events
91
            ---------------------------------------------------- */
92
93
            $(window).resize(setOverlayHeight)
94
                     .resize(setSelfPosition)
95
                     .scroll(setSelfPosition);
96
97
            $(window).bind('keyup.lightbox_me', observeKeyPress);
98
99
            if (opts.closeClick) {
100
                $overlay.click(function(e) { closeLightbox(); e.preventDefault; });
101
            }
102
            $self.delegate(opts.closeSelector, "click", function(e) {
103
                closeLightbox(); e.preventDefault();
104
            });
105
            $self.bind('close', closeLightbox);
106
            $self.bind('reposition', setSelfPosition);
107
108
109
110
            /*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
111
              -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
112
113
114
            /*----------------------------------------------------
115
               Private Functions
116
            ---------------------------------------------------- */
117
118
            /* Remove or hide all elements */
119
            function closeLightbox() {
120
                var s = $self[0].style;
121
                if (opts.destroyOnClose) {
122
                    $self.add($overlay).remove();
123
                } else {
124
                    $self.add($overlay).hide();
125
                }
126
127
                //show the hidden parent lightbox
128
                if (opts.parentLightbox) {
129
                    opts.parentLightbox.fadeIn(200);
130
                }
131
132
                $iframe.remove();
133
134
				// clean up events.
135
                $self.undelegate(opts.closeSelector, "click");
136
137
                $(window).unbind('reposition', setOverlayHeight);
138
                $(window).unbind('reposition', setSelfPosition);
139
                $(window).unbind('scroll', setSelfPosition);
140
                $(window).unbind('keyup.lightbox_me');
141
                if (ie6)
142
                    s.removeExpression('top');
143
                opts.onClose();
144
            }
145
146
147
            /* Function to bind to the window to observe the escape/enter key press */
148
            function observeKeyPress(e) {
149
                if((e.keyCode == 27 || (e.DOM_VK_ESCAPE == 27 && e.which==0)) && opts.closeEsc) closeLightbox();
150
            }
151
152
153
            /* Set the height of the overlay
154
                    : if the document height is taller than the window, then set the overlay height to the document height.
155
                    : otherwise, just set overlay height: 100%
156
            */
157
            function setOverlayHeight() {
158
                if ($(window).height() < $(document).height()) {
159
                    $overlay.css({height: $(document).height() + 'px'});
160
                     $iframe.css({height: $(document).height() + 'px'});
161
                } else {
162
                    $overlay.css({height: '100%'});
163
                    if (ie6) {
164
                        $('html,body').css('height','100%');
165
                        $iframe.css('height', '100%');
166
                    } // ie6 hack for height: 100%; TODO: handle this in IE7
167
                }
168
            }
169
170
171
            /* Set the position of the modal'd window ($self)
172
                    : if $self is taller than the window, then make it absolutely positioned
173
                    : otherwise fixed
174
            */
175
            function setSelfPosition() {
176
                var s = $self[0].style;
177
178
                // reset CSS so width is re-calculated for margin-left CSS
179
                $self.css({left: '50%', marginLeft: ($self.outerWidth() / 2) * -1,  zIndex: (opts.zIndex + 3) });
180
181
182
                /* we have to get a little fancy when dealing with height, because lightbox_me
183
                    is just so fancy.
184
                 */
185
186
                // if the height of $self is bigger than the window and self isn't already position absolute
187
                if (($self.height() + 80  >= $(window).height()) && ($self.css('position') != 'absolute' || ie6)) {
188
189
                    // we are going to make it positioned where the user can see it, but they can still scroll
190
                    // so the top offset is based on the user's scroll position.
191
                    var topOffset = $(document).scrollTop() + 40;
192
                    $self.css({position: 'absolute', top: topOffset + 'px', marginTop: 0})
193
                    if (ie6) {
194
                        s.removeExpression('top');
195
                    }
196
                } else if ($self.height()+ 80  < $(window).height()) {
197
                    //if the height is less than the window height, then we're gonna make this thing position: fixed.
198
                    // in ie6 we're gonna fake it.
199
                    if (ie6) {
200
                        s.position = 'absolute';
201
                        if (opts.centered) {
202
                            s.setExpression('top', '(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"')
203
                            s.marginTop = 0;
204
                        } else {
205
                            var top = (opts.modalCSS && opts.modalCSS.top) ? parseInt(opts.modalCSS.top) : 0;
206
                            s.setExpression('top', '((blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"')
207
                        }
208
                    } else {
209
                        if (opts.centered) {
210
                            $self.css({ position: 'fixed', top: '50%', marginTop: ($self.outerHeight() / 2) * -1})
211
                        } else {
212
                            $self.css({ position: 'fixed'}).css(opts.modalCSS);
213
                        }
214
215
                    }
216
                }
217
            }
218
219
        });
220
221
222
223
    };
224
225
    $.fn.lightbox_me.defaults = {
226
227
        // animation
228
        appearEffect: "fadeIn",
229
        appearEase: "",
230
        overlaySpeed: 250,
231
        lightboxSpeed: 300,
232
233
        // close
234
        closeSelector: ".close",
235
        closeClick: true,
236
        closeEsc: true,
237
238
        // behavior
239
        destroyOnClose: false,
240
        showOverlay: true,
241
        parentLightbox: false,
242
243
        // callbacks
244
        onLoad: function() {},
245
        onClose: function() {},
246
247
        // style
248
        classPrefix: 'lb',
249
        zIndex: 999,
250
        centered: false,
251
        modalCSS: {top: '40px'},
252
        overlayCSS: {background: 'black', opacity: .3}
253
    }
254
})(jQuery);
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-external-search.tt (+240 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog &rsaquo; External search for '[% q | html %]'
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.lightbox_me.js"></script>
5
<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script>
6
<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script>
7
<script type="text/javascript">
8
var querystring = "[% q |replace( "'", "\'" ) |replace( '\n', '\\n' ) |replace( '\r', '\\r' ) |html %]";
9
var results_per_page = [% OPACnumSearchResults %];
10
KOHA.ExternalSearch.targets = {
11
    [% FOREACH target IN external_search_targets %]
12
        '[% target.host %]:[% target.port %]/[% target.db %]': {
13
            name: '[% target.name %]',
14
            syntax: '[% target.syntax %]',
15
        },
16
    [% END %]
17
};
18
19
var xsltResultStylesheets = {
20
    [% FOREACH stylesheet IN xslt_result_stylesheets %]
21
    '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ),
22
    [% END %]
23
};
24
25
var xsltDetailStylesheets = {
26
    [% FOREACH stylesheet IN xslt_detail_stylesheets %]
27
    '[% stylesheet.syntax %]': KOHA.XSLTGet( '[% stylesheet.url %]' ),
28
    [% END %]
29
};
30
31
var recordCache = {};
32
var resultRenderCache = {};
33
34
function showResult( syntax, recid ) {
35
    if ( recordCache[ recid ] ) {
36
        done( recordCache[ recid ] );
37
    } else {
38
        KOHA.ExternalSearch.GetDetailedRecord( recid, function( record ) {
39
            done( recordCache[ recid ] = record.xmlDoc );
40
        } );
41
    }
42
43
    function done( record ) {
44
        xsltResultStylesheets[ syntax ].done( function( xslDoc ) {
45
            var fragment = resultRenderCache[ recid ] = KOHA.TransformToFragment( record, xslDoc );
46
            var $tr = $( '#results tr' ).filter( function() { return $( this ).data( 'recid' ) == recid } );
47
            $tr.find( '.info' ).html( fragment );
48
            $tr.find( 'a' ).attr( 'href', '#' ).click( function() {
49
                showDetail( syntax, recid );
50
51
                return false;
52
            } );
53
        } );
54
    }
55
}
56
57
function showDetail( syntax, recid ) {
58
    var record = recordCache[ recid ];
59
    console.info((new XMLSerializer).serializeToString( record ));
60
61
    xsltDetailStylesheets[ syntax ].done( function( xslDoc ) {
62
        var fragment = KOHA.TransformToFragment( record, xslDoc );
63
64
        $( '#modal-overlay' ).html( fragment ).lightbox_me( {
65
            centered: true,
66
        } );
67
    } );
68
}
69
70
function search( offset, reset_search ) {
71
    $( '#pazpar2-status' ).html( _("Searching external targets...") + '<img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" />' );
72
73
    if ( reset_search ) {
74
        KOHA.ExternalSearch.Search( querystring, results_per_page, callback );
75
    } else {
76
        KOHA.ExternalSearch.Fetch( offset, callback );
77
    }
78
79
    function callback( data ) {
80
        if ( data.error && data.error.code != 8 ) { // PAZPAR2_NO_TARGETS
81
            $( '#pazpar2-status' ).html( '<strong class="unavailable">' + _("Error searching external targets.") + '</strong>' );
82
            return;
83
        }
84
85
        if ( !data.total ) {
86
            $( '#pazpar2-status' ).html( '<strong>' + _("No results found in the external targets.") + '</strong>' );
87
            return;
88
        }
89
90
        $( '#results tbody' ).empty();
91
92
        $( '#pazpar2-status' ).html( '<strong>' + _("Found __RESULTS__ results in __TARGETS__ external targets.").replace('__RESULTS__', data.total).replace('__TARGETS__', $( '#targets-facet input:checked' ).length ) );
93
94
        for ( var i = 0; data.hits[i]; i++ ) {
95
            var hit = data.hits[i];
96
            var results = [];
97
            var recordSyntax = KOHA.ExternalSearch.targets[ hit.location[0]['@id'] ].syntax;
98
99
            results.push( '<tr>' );
100
101
            results.push( '<td class="sourcecol">', hit.location[0]['@name'], '</td>' );
102
103
            results.push( '<td class="info">' );
104
105
            if ( resultRenderCache[ hit.recid[0] ] ) {
106
                results.push( resultRenderCache[ hit.recid[0] ] );
107
            } else {
108
                results.push( hit['md-work-title'] ? hit['md-work-title'][0] : _("Loading...") );
109
                showResult( recordSyntax, hit.recid[0] );
110
            }
111
112
            results.push( '</td>' );
113
114
            results.push( '</tr>' );
115
            var $tr = $( results.join( '' ) );
116
            $tr.data( 'recid', hit.recid[0] );
117
            $( '#results tbody' ).append( $tr );
118
119
            ( function( hit, recordSyntax ) {
120
                $tr.find( 'a' ).attr( 'href', '#' ).click( function() {
121
                    showDetail( recordSyntax, hit.recid[0] );
122
123
                    return false;
124
                } );
125
            } )( hit, recordSyntax );
126
        }
127
128
        $( '#results tr:odd' ).addClass( 'highlight' );
129
130
        var pages = [];
131
        var cur_page = data.start / results_per_page;
132
        var max_page = Math.floor( data.total / results_per_page );
133
134
        if ( cur_page != 0 ) {
135
            pages.push( '<a class="nav" href="#" data-offset="' + (offset - results_per_page) + '">&lt;&lt; ' + _("Previous") + '</a>' );
136
        }
137
138
        for ( var page = Math.max( 0, cur_page - 9 ); page <= Math.min( max_page, cur_page + 9 ); page++ ) {
139
            if ( page == cur_page ) {
140
                pages.push( ' <span class="current">' + ( page + 1 ) + '</span>' );
141
            } else {
142
                pages.push( ' <a class="nav" href="#" data-offset="' + ( page * results_per_page ) + '">' + ( page + 1 ) + '</a>' );
143
            }
144
        }
145
146
        if ( cur_page < max_page ) {
147
            pages.push( ' <a class="nav" href="#" data-offset="' + (offset + results_per_page) + '">' + _("Next") + ' >></a>' );
148
        }
149
150
        if ( pages.length > 1 ) $( '#top-pages, #bottom-pages' ).find( '.pages' ).html( pages.join( '' ) );
151
    }
152
}
153
154
$( document ).ready( function() {
155
    $( '#breadcrumbs p' )
156
        .append( ' ' )
157
        .append( '<span id="pazpar2-status"></span>' );
158
159
    $( document ).on( 'click', 'a.nav', function() {
160
        search( $( this ).data( 'offset' ) );
161
        return false;
162
    });
163
164
    var reSearchTimeout;
165
166
    $( '#targets-facet input' ).each( function() {
167
        $( this ).click( function() {
168
            KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked;
169
170
            if ( reSearchTimeout ) clearTimeout( reSearchTimeout );
171
172
            reSearchTimeout = setTimeout( function() {
173
                if ( $( '#targets-facet input:checked' ).length ) search( 0, true );
174
            }, 1000 );
175
        } );
176
177
        KOHA.ExternalSearch.targets[ $( this ).data( 'url' ) ].disabled = !this.checked;
178
    } );
179
180
    search( 0, true );
181
} );
182
</script>
183
<style>
184
.actions a.addtocart {
185
    display: inline;
186
}
187
</style>
188
</head>
189
<body>
190
<div id="doc3" class="yui-t1">
191
192
<div id="bd">
193
    [% INCLUDE 'masthead.inc' %]
194
195
    <h1>External search for '[% q | html %]'</h1>
196
    <div id="breadcrumbs">
197
        <p></p>
198
    </div>
199
200
    <div id="yui-main"><div class="yui-b searchresults">
201
        <div id="top-pages">
202
            <div class="pages">
203
            </div>
204
        </div>
205
        <table id="results">
206
            <tbody>
207
            </tbody>
208
        </table>
209
        <div id="bottom-pages">
210
            <div class="pages">
211
            </div>
212
        </div>
213
    </div></div>
214
215
    <div class="yui-b"><div id="facetcontainer" class="container">
216
    <div id="search-facets">
217
218
        <h4>Refine your search</h4>
219
220
        <ul>
221
            <li id="targets-facet">
222
                Targets
223
                <ul>
224
                    [% FOREACH target = external_search_targets %]
225
                    <li>
226
                        <input data-url="[% target.host %]:[% target.port %]/[% target.db %]" type="checkbox" id="target-[% loop.index %]" checked />
227
                        <label for="target-[% loop.index %]">[% target.name %]
228
                    </li>
229
                    [% END %]
230
                </ul>
231
            </li>
232
        </ul>
233
    </div>
234
    </div></div>
235
</div>
236
237
</div>
238
239
<div id="modal-overlay" style="display: none"></div>
240
[% INCLUDE 'opac-bottom.inc' %]
(-)a/koha-tmpl/opac-tmpl/prog/en/modules/opac-results.tt (-11 / +52 lines)
Lines 16-22 Link Here
16
  <link rel="stylesheet" type="text/css" href="[% themelang %]/css/jquery.rating.css" />
16
  <link rel="stylesheet" type="text/css" href="[% themelang %]/css/jquery.rating.css" />
17
[% END %]
17
[% END %]
18
18
19
<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script>
19
[% IF ( OverDriveEnabled ) %]<script type="text/javascript" src="[% themelang %]/js/overdrive.js"></script>[% END %]
20
[% IF ( Koha.Preference('OPACSearchExternalTargets') ) %]
21
<script type="text/javascript" src="[% interface %]/lib/pz2.js"></script>
22
<script type="text/javascript" src="[% interface %]/lib/koha/externalsearch.js"></script>
23
[% END %]
20
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
24
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
21
[% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.highlight-3.js"></script>
25
[% IF ( OpacHighlightedWords ) %]<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.highlight-3.js"></script>
22
[% END %]<script type="text/javascript">
26
[% END %]<script type="text/javascript">
Lines 266-289 $(document).ready(function(){ Link Here
266
        $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;});
270
        $("#highlight_toggle_on" ).hide().click(function() {highlightOn() ;});
267
        $("#highlight_toggle_off").show().click(function() {highlightOff();});
271
        $("#highlight_toggle_off").show().click(function() {highlightOff();});
268
    [% END %]
272
    [% END %]
273
    function StartExternalSearch(name, text) {
274
        $( '#breadcrumbs p' )
275
            .eq( 0 )
276
            .append( ' <span id="' + name + '-results">' + text + '... <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
277
    }
278
    function FailExternalSearch( name, text ) {
279
        $( '#' + name + '-results' ).html( text );
280
    }
281
    function FinishExternalSearch( name, text, numItems, url ) {
282
        if ( numItems ) {
283
            $( '#' + name + '-results' ).html( text.replace( '__LINK__', '<a href="' + url + '">'  + numItems + _(" results") + '</a>' ) );
284
        } else {
285
            $( '#' + name + '-results' ).remove();
286
        }
287
    }
288
269
    [% IF ( OverDriveEnabled ) %]
289
    [% IF ( OverDriveEnabled ) %]
270
        var $overdrive_results = $( '<span id="overdrive-results">' + _( 'Searching OverDrive...' ) + ' <img class="throbber" src="/opac-tmpl/lib/jquery/plugins/themes/classic/throbber.gif" /></span>' );
290
        StartExternalSearch( 'overdrive', _("Searching OverDrive") );
271
        $( '#breadcrumbs p' ).eq(0)
272
            .append( ' ' )
273
            .append( $overdrive_results );
274
        KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) {
291
        KOHA.OverDrive.Search( "[% OverDriveLibraryID %]", querystring, 1, 0, function( data ) {
275
            if ( data.error ) {
292
            if ( data.error ) {
276
                $overdrive_results.html( _( 'Error searching OverDrive collection' ) );
293
                FailExternalSearch( 'overdrive', _("Error searching OverDrive collection") );
277
                return;
294
                return;
278
            }
295
            }
279
296
280
            if ( data.totalItems ) {
297
            FinishExternalSearch( 'overdrive', _("Found __LINK__ in OverDrive collection"), data.totalItems, '/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) );
281
                $overdrive_results.html( _( 'Found' ) + ' <a href="/cgi-bin/koha/opac-overdrive-search.pl?q=' + escape( querystring ) + '">' + data.totalItems + ' ' + _( 'results' ) + '</a> ' + _( 'in OverDrive collection' ) );
282
            } else {
283
                $overdrive_results.remove();
284
            }
285
        } );
298
        } );
286
    [% END %]
299
    [% END %]
300
301
    [% IF ( OPACSearchExternalTargets ) %]
302
        KOHA.ExternalSearch.targets = {
303
            [% FOREACH target IN external_search_targets %]
304
                '[% target.host %]:[% target.port %]/[% target.db %]': {
305
                    id: '[% target.target_id %]',
306
                    name: '[% target.name %]',
307
                    syntax: '[% target.syntax %]',
308
                },
309
            [% END %]
310
        };
311
        var num_targets = 0; $.each( KOHA.ExternalSearch.targets, function() { num_targets++ } );
312
        var first_succeeded;
313
314
        if ( num_targets ) {
315
            StartExternalSearch( 'pazpar2', _("Searching external targets") );
316
            KOHA.ExternalSearch.Search( querystring, 1, function( data ) {
317
                if ( data.error ) {
318
                    if ( !first_succeeded ) FailExternalSearch( 'pazpar2', _("Error searching external targets") );
319
                    return;
320
                }
321
322
                first_succeeded = true;
323
                FinishExternalSearch( 'pazpar2', _("Found __LINK__ in __TARGETS__ external targets").replace( '__TARGETS__', num_targets ), data.total, '/cgi-bin/koha/opac-external-search.pl?q=' + escape( querystring ) );
324
            } );
325
        }
326
    [% END %]
327
287
[% END %]
328
[% END %]
288
329
289
[% IF ( TagsInputEnabled && loggedinusername ) %]
330
[% IF ( TagsInputEnabled && loggedinusername ) %]
(-)a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slim2OPACResults.xsl (-1 / +5 lines)
Lines 5-15 Link Here
5
  xmlns:marc="http://www.loc.gov/MARC21/slim"
5
  xmlns:marc="http://www.loc.gov/MARC21/slim"
6
  xmlns:items="http://www.koha-community.org/items"
6
  xmlns:items="http://www.koha-community.org/items"
7
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
7
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
8
  xmlns="http://www.w3.org/1999/xhtml"
8
  exclude-result-prefixes="marc items">
9
  exclude-result-prefixes="marc items">
9
    <xsl:import href="MARC21slimUtils.xsl"/>
10
    <xsl:import href="MARC21slimUtils.xsl"/>
10
    <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
11
    <xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
11
    <xsl:key name="item-by-status" match="items:item" use="items:status"/>
12
    <xsl:key name="item-by-status" match="items:item" use="items:status"/>
12
    <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
13
    <xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
14
    <xsl:param name="showAvailability" select="true()"/>
13
15
14
    <xsl:template match="/">
16
    <xsl:template match="/">
15
            <xsl:apply-templates/>
17
            <xsl:apply-templates/>
Lines 1027-1032 Link Here
1027
                            </xsl:for-each>
1029
                            </xsl:for-each>
1028
                            </span>
1030
                            </span>
1029
                        </xsl:if>
1031
                        </xsl:if>
1032
                        <xsl:if test="$showAvailability">
1030
                        <span class="results_summary availability">
1033
                        <span class="results_summary availability">
1031
                        <span class="label">Availability: </span>
1034
                        <span class="label">Availability: </span>
1032
                        <xsl:choose>
1035
                        <xsl:choose>
Lines 1035-1041 Link Here
1035
                            <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]">
1038
                            <xsl:when test="string-length($AlternateHoldingsField)=3 and marc:datafield[@tag=$AlternateHoldingsField]">
1036
                            <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/>
1039
                            <xsl:variable name="AlternateHoldingsCount" select="count(marc:datafield[@tag=$AlternateHoldingsField])"/>
1037
                            <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]">
1040
                            <xsl:for-each select="marc:datafield[@tag=$AlternateHoldingsField][1]">
1038
                                <xsl:call-template select="marc:datafield[@tag=$AlternateHoldingsField]" name="subfieldSelect">
1041
                                <xsl:call-template name="subfieldSelect">
1039
                                    <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param>
1042
                                    <xsl:with-param name="codes"><xsl:value-of select="$AlternateHoldingsSubfields"/></xsl:with-param>
1040
                                    <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param>
1043
                                    <xsl:with-param name="delimeter"><xsl:value-of select="$AlternateHoldingsSeparator"/></xsl:with-param>
1041
                                </xsl:call-template>
1044
                                </xsl:call-template>
Lines 1145-1150 Link Here
1145
                       <xsl:text>). </xsl:text>                   </span>
1148
                       <xsl:text>). </xsl:text>                   </span>
1146
                   </xsl:if>
1149
                   </xsl:if>
1147
               </span>
1150
               </span>
1151
               </xsl:if>
1148
    <xsl:choose>
1152
    <xsl:choose>
1149
        <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)">
1153
        <xsl:when test="($OPACItemLocation='location' or $OPACItemLocation='ccode') and (count(key('item-by-status', 'available'))!=0 or count(key('item-by-status', 'reference'))!=0)">
1150
            <span class="results_summary" id="location">
1154
            <span class="results_summary" id="location">
(-)a/koha-tmpl/opac-tmpl/prog/en/xslt/MARC21slimUtils.xsl (-1 / +1 lines)
Lines 1-6 Link Here
1
<?xml version='1.0'?>
1
<?xml version='1.0'?>
2
<!DOCTYPE stylesheet [<!ENTITY nbsp "&#160;" >]>
2
<!DOCTYPE stylesheet [<!ENTITY nbsp "&#160;" >]>
3
<xsl:stylesheet version="1.0" xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3
<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">
4
	<xsl:template name="datafield">
4
	<xsl:template name="datafield">
5
		<xsl:param name="tag"/>
5
		<xsl:param name="tag"/>
6
		<xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
6
		<xsl:param name="ind1"><xsl:text> </xsl:text></xsl:param>
(-)a/koha-tmpl/opac-tmpl/prog/en/xslt/UNIMARCslim2OPACResults.xsl (+4 lines)
Lines 6-17 Link Here
6
  xmlns:marc="http://www.loc.gov/MARC21/slim"
6
  xmlns:marc="http://www.loc.gov/MARC21/slim"
7
  xmlns:items="http://www.koha-community.org/items"
7
  xmlns:items="http://www.koha-community.org/items"
8
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
8
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
9
  xmlns="http://www.w3.org/1999/xhtml"
9
  exclude-result-prefixes="marc items">
10
  exclude-result-prefixes="marc items">
10
11
11
<xsl:import href="UNIMARCslimUtils.xsl"/>
12
<xsl:import href="UNIMARCslimUtils.xsl"/>
12
<xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
13
<xsl:output method = "html" indent="yes" omit-xml-declaration = "yes" encoding="UTF-8"/>
13
<xsl:key name="item-by-status" match="items:item" use="items:status"/>
14
<xsl:key name="item-by-status" match="items:item" use="items:status"/>
14
<xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
15
<xsl:key name="item-by-status-and-branch" match="items:item" use="concat(items:status, ' ', items:homebranch)"/>
16
<xsl:param name="showAvailability" select="true()"/>
15
17
16
<xsl:template match="/">
18
<xsl:template match="/">
17
  <xsl:apply-templates/>
19
  <xsl:apply-templates/>
Lines 99-104 Link Here
99
101
100
  <xsl:call-template name="tag_215" />
102
  <xsl:call-template name="tag_215" />
101
103
104
  <xsl:if test="$showAvailability">
102
  <span class="results_summary availability">
105
  <span class="results_summary availability">
103
    <span class="label">Availability: </span>
106
    <span class="label">Availability: </span>
104
    <xsl:choose>
107
    <xsl:choose>
Lines 247-252 Link Here
247
      </span>
250
      </span>
248
    </xsl:if>
251
    </xsl:if>
249
  </span>
252
  </span>
253
  </xsl:if>
250
254
251
</xsl:template>
255
</xsl:template>
252
256
(-)a/opac/opac-external-search.pl (+62 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2013 ByWater Solutions
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use CGI;
23
24
use C4::Auth qw(:DEFAULT get_session);
25
use C4::Output;
26
use C4::Search qw( GetExternalSearchTargets );
27
use C4::XSLT qw( XSLTGetFilename );
28
29
my $cgi = new CGI;
30
31
# Getting the template and auth
32
my ($template, $loggedinuser, $cookie)
33
= get_template_and_user({template_name => "opac-external-search.tmpl",
34
                                query => $cgi,
35
                                type => "opac",
36
                                authnotrequired => 1,
37
                                flagsrequired => {borrowers => 1},
38
                                debug => 1,
39
                                });
40
41
$template->{VARS}->{q} = $cgi->param('q');
42
$template->{VARS}->{limit} = C4::Context->preference('OPACnumSearchResults') || 20;
43
$template->{VARS}->{OPACnumSearchResults} = C4::Context->preference('OPACnumSearchResults') || 20;
44
$template->{VARS}->{external_search_targets} = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' );
45
46
my @xsltResultStylesheets;
47
my @xsltDetailStylesheets;
48
49
foreach my $syntax ( qw( MARC21 UNIMARC NORMARC ) ) {
50
    if ( XSLTGetFilename( $syntax, 'OPACXSLTResultsDisplay' ) =~ m,/opac-tmpl/.*|^https:?.*, ) {
51
        push @xsltResultStylesheets, { syntax => $syntax, url => $& };
52
    }
53
54
    if ( XSLTGetFilename( $syntax, 'OPACXSLTDetailsDisplay' ) =~ m,/opac-tmpl/.*|^https:?.*, ) {
55
        push @xsltDetailStylesheets, { syntax => $syntax, url => $& };
56
    }
57
}
58
59
$template->{VARS}->{xslt_result_stylesheets} = \@xsltResultStylesheets;
60
$template->{VARS}->{xslt_detail_stylesheets} = \@xsltDetailStylesheets;
61
62
output_html_with_http_headers $cgi, $cookie, $template->output;
(-)a/opac/opac-search.pl (-4 / +8 lines)
Lines 74-79 if ( $branch_group_limit ) { Link Here
74
            -name => 'multibranchlimit',
74
            -name => 'multibranchlimit',
75
            -values => substr($branch_group_limit, 17)
75
            -values => substr($branch_group_limit, 17)
76
        );
76
        );
77
    } elsif ( $branch_group_limit eq '@overdrive' ) {
78
        print $cgi->redirect( '/cgi-bin/koha/opac-overdrive-search.pl?q=' . join( '+', $cgi->param( 'q' ) ) );
79
        exit;
77
    } else {
80
    } else {
78
        $cgi->append(
81
        $cgi->append(
79
            -name => 'limit',
82
            -name => 'limit',
Lines 880-889 $template->{VARS}->{IDreamBooksReviews} = C4::Context->preference('IDreamBooksRe Link Here
880
$template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
883
$template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
881
$template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
884
$template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
882
885
883
if ($offset == 0 && IsOverDriveEnabled()) {
886
$template->{VARS}->{OPACSearchExternalTargets} = C4::Context->preference('OPACSearchExternalTargets');
884
    $template->param(OverDriveEnabled => 1);
887
$template->{VARS}->{external_search_targets} = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' );
885
    $template->param(OverDriveLibraryID => C4::Context->preference('OverDriveLibraryID'));
888
886
}
889
$template->{VARS}->{OverDriveLibraryID} = C4::Context->preference('OverDriveLibraryID');
890
$template->{VARS}->{OverDriveEnabled} = ($offset == 0 && IsOverDriveEnabled());
887
891
888
    $template->param( borrowernumber    => $borrowernumber);
892
    $template->param( borrowernumber    => $borrowernumber);
889
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
893
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
(-)a/opac/svc/pazpar2_init (+101 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2013 ByWater Solutions
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
=head1 NAME
21
22
svc/pazpar2_init: Initialize a Pazpar2 session
23
24
=head1 SYNOPSIS
25
26
svc/pazpar2_init -> ../pazpar2/search.pz2?command=init&...
27
28
=head1 DESCRIPTION
29
30
This services connects to pazpar2 and authenticates connections on behalf of
31
client-side search code. The proxy is necessary to prevent exposing
32
authentication information.
33
34
=cut
35
36
use strict;
37
use warnings;
38
39
use CGI qw(-oldstyle_urls);
40
use HTTP::Request::Common;
41
use JSON;
42
use URI;
43
use XML::Simple;
44
45
use C4::Context;
46
use C4::Search;
47
use C4::Service;
48
use C4::Output;
49
50
my $dbh = C4::Context->dbh;
51
my ( $query, $response ) = C4::Service->init;
52
53
my %init_opts;
54
55
my $targets = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' );
56
57
foreach my $target ( @$targets ) {
58
    my $target_url = $target->{'host'} . ':' . $target->{'port'} . '/' . $target->{'db'};
59
    $init_opts{ 'pz:name[' . $target_url . ']' } = $target->{'name'};
60
    $init_opts{ 'pz:queryencoding[' . $target_url . ']' } = $target->{'encoding'};
61
    $init_opts{ 'pz:xslt[' . $target_url . ']' } = lc( $target->{'syntax'} ) . '-work-groups.xsl';
62
    $init_opts{ 'pz:requestsyntax[' . $target_url . ']' } = $target->{'syntax'};
63
    $init_opts{ 'pz:nativesyntax[' . $target_url . ']' } = 'iso2709';
64
65
    if ( $target->{'userid'} ) {
66
        if ( $target->{'password'} ) {
67
            $init_opts{ 'pz:authentication[' . $target_url . ']' } = $target->{'userid'} . '/' . $target->{'password'};
68
        } else {
69
            $init_opts{ 'pz:authentication[' . $target_url . ']' } = $target->{'userid'};
70
        }
71
    }
72
}
73
74
my $uri = 'http://' . C4::Context->preference( 'OPACBaseURL' ) . "/pazpar2/search.pz2";
75
76
my $request = HTTP::Request::Common::POST( $uri, [ command => 'init', %init_opts ] );
77
78
my $ua = LWP::UserAgent->new( "Koha " . C4::Context->KOHAVERSION );
79
80
my $response = $ua->request( $request ) ;
81
if ( !$response->is_success ) {
82
    print $query->header(
83
        -status => '500 Internal Server Error'
84
    );
85
86
    warn "Pazpar2 init failed: " . $response->message;
87
    my $content = to_json({
88
        error => 'Could not connect to Pazpar2',
89
    });
90
    output_with_http_headers $query, undef, $content, 'json', '500 Internal Server Error';
91
92
    exit;
93
} else {
94
    my $xs = XML::Simple->new;
95
    my $data = $xs->XMLin( $response->content );
96
97
    my $content = to_json({
98
        sessionID => $data->{'session'}
99
    });
100
    output_with_http_headers $query, undef, $content, 'json', '200 OK';
101
}
(-)a/rewrite-config.PL (-4 / +4 lines)
Lines 136-143 $prefix = $ENV{'INSTALL_BASE'} || "/usr"; Link Here
136
  "__INSTALL_BASE__" => '/usr/share/koha',
136
  "__INSTALL_BASE__" => '/usr/share/koha',
137
  "__INSTALL_SRU__" => 'yes',
137
  "__INSTALL_SRU__" => 'yes',
138
  "__INSTALL_PAZPAR2__" => 'no',
138
  "__INSTALL_PAZPAR2__" => 'no',
139
  "__PAZPAR2_TOGGLE_XML_PRE__" => '<!--',
139
  "__PAZPAR2_TOGGLE_HTTPD_PRE__" => '<IfDefine PAZPAR2_IS_DISABLED>',
140
  "__PAZPAR2_TOGGLE_XML_POST__" => '-->',
140
  "__PAZPAR2_TOGGLE_HTTPD_POST__" => '</IfDefine>',
141
  "__AUTH_INDEX_MODE__" => 'grs1',
141
  "__AUTH_INDEX_MODE__" => 'grs1',
142
  "__BIB_INDEX_MODE__" => 'grs1',
142
  "__BIB_INDEX_MODE__" => 'grs1',
143
  "__RUN_DATABASE_TESTS__" => 'no',
143
  "__RUN_DATABASE_TESTS__" => 'no',
Lines 157-164 foreach $key (keys %configuration) { Link Here
157
# munge commenting out the PazPar2 mergeserver
157
# munge commenting out the PazPar2 mergeserver
158
# entry in koha-conf.xml if necessary
158
# entry in koha-conf.xml if necessary
159
if ($configuration{'__INSTALL_PAZPAR2__'} eq 'yes') {
159
if ($configuration{'__INSTALL_PAZPAR2__'} eq 'yes') {
160
    $configuration{'__PAZPAR2_TOGGLE_XML_PRE__'} = '';
160
    $configuration{'__PAZPAR2_TOGGLE_HTTPD_PRE__'} = '';
161
    $configuration{'__PAZPAR2_TOGGLE_XML_POST__'} = '';
161
    $configuration{'__PAZPAR2_TOGGLE_HTTPD_POST__'} = '';
162
}
162
}
163
163
164
$fname = $ARGV[0];
164
$fname = $ARGV[0];
(-)a/t/XSLT.t (-16 / +79 lines)
Lines 6-12 Link Here
6
use strict;
6
use strict;
7
use warnings;
7
use warnings;
8
8
9
use Test::More tests => 8;
9
use C4::Context;
10
use C4::Templates;
11
use Test::More tests => 13;
12
use Test::MockModule;
13
use File::Basename qw/dirname/;
10
use File::Temp;
14
use File::Temp;
11
use File::Path qw/make_path/;
15
use File::Path qw/make_path/;
12
16
Lines 14-49 BEGIN { Link Here
14
        use_ok('C4::XSLT');
18
        use_ok('C4::XSLT');
15
}
19
}
16
20
17
my $dir = File::Temp->newdir();
21
my $opacdir = File::Temp->newdir();
22
my $staffdir = File::Temp->newdir();
18
my @themes = ('prog', 'test');
23
my @themes = ('prog', 'test');
19
my @langs = ('en', 'es-ES');
24
my @langs = ('en', 'es-ES');
20
25
26
sub make_test_file {
27
    my ( $filename, $contents ) = @_;
28
29
    make_path(dirname($filename));
30
    open my $fh, '>', $filename or die "Could not create test file: $filename";
31
    print $fh $contents;
32
    close $fh;
33
}
34
21
# create temporary files to be tested later
35
# create temporary files to be tested later
22
foreach my $theme (@themes) {
36
foreach my $theme (@themes) {
23
    foreach my $lang (@langs) {
37
    foreach my $lang (@langs) {
24
        make_path("$dir/$theme/$lang/xslt");
38
        foreach my $dir ($opacdir, $staffdir) {
25
        open my $fh, '>', "$dir/$theme/$lang/xslt/my_file.xslt";
39
            make_test_file( "$dir/$theme/$lang/xslt/my_file.xslt", "Theme $theme, language $lang" );
26
        print $fh "Theme $theme, language $lang";
40
            make_test_file( "$dir/$theme/$lang/xslt/MARC21slim2intranetDetail.xsl", "Theme $theme, language $lang, MARC21slim2intranetDetail" );
27
        close $fh;
41
            make_test_file( "$dir/$theme/$lang/xslt/test_en.xsl", "Theme $theme, language $lang, test_en" );
42
            make_test_file( "$dir/$theme/$lang/xslt/UNIMARCslim2OPACDetail.xsl", "Theme $theme, language $lang, UNIMARCslim2OPACDetail" );
43
            make_test_file( "$dir/$theme/$lang/xslt/nondefault_test.xsl", "Theme $theme, language $lang, nondefault_test" );
44
            make_test_file( "$dir/$theme/$lang/xslt/MARC21slim2OPACResults.xsl", "Theme $theme, language $lang, MARC21slim2OPACResults" );
45
        }
28
    }
46
    }
29
}
47
}
30
48
31
sub find_and_slurp {
49
sub find_and_slurp_default {
32
    my ($dir, $theme, $lang) = @_;
50
    my ($dir, $theme, $lang) = @_;
33
51
34
    my $filename = C4::XSLT::_get_best_default_xslt_filename($dir, $theme, $lang, 'my_file.xslt');
52
    my $filename = C4::XSLT::_get_best_default_xslt_filename($dir, $theme, $lang, 'my_file.xslt');
35
    open my $fh, '<', $filename;
53
    open my $fh, '<', $filename or return "Could not open: $filename";
36
    my $str = <$fh>;
54
    my $str = <$fh>;
37
    close $fh;
55
    close $fh;
38
    return $str;
56
    return $str;
39
}
57
}
40
58
59
sub find_and_slurp {
60
    my ($marcflavour, $xslsyspref) = @_;
61
62
    my $filename = C4::XSLT::XSLTGetFilename( $marcflavour, $xslsyspref );
63
    open my $fh, '<', $filename or return "Could not open: $filename";
64
    my $str = <$fh>;
65
    close $fh;
66
    return $str;
67
}
68
69
my $module_context = new Test::MockModule('C4::Context');
70
$module_context->mock(
71
    'config',
72
    sub {
73
        my ( $self, $var ) = @_;
74
        my %predefs = (
75
            opachtdocs => $opacdir,
76
            intrahtdocs => $staffdir,
77
        );
78
79
        return $predefs{$var} || $module_context->original('config')->(@_);
80
    }
81
);
82
$module_context->mock(
83
    'preference',
84
    sub {
85
        my ( $self, $var ) = @_;
86
        my %predefs = (
87
            template => 'prog',
88
            marcflavour => 'MARC21',
89
            opacthemes => 'test',
90
            XSLTDetailsDisplay => 'default',
91
            XSLTResultsDisplay => "$staffdir/prog/en/xslt/test_en.xsl",
92
            OPACXSLTDetailsDisplay => "$opacdir/test/en/xslt/nondefault_test.xsl",
93
            OPACXSLTResultsDisplay => '"default"',
94
        );
95
96
        return $predefs{$var} || $module_context->original('preference')->(@_);
97
    }
98
);
99
41
# These tests verify that we're finding the right XSLT file when present,
100
# These tests verify that we're finding the right XSLT file when present,
42
# and falling back to the right XSLT file when an exact match is not present.
101
# and falling back to the right XSLT file when an exact match is not present.
43
is(find_and_slurp($dir, 'test', 'en'   ), 'Theme test, language en',    'Found test/en');
102
is(find_and_slurp_default($opacdir, 'test', 'en'   ), 'Theme test, language en',    'Found test/en');
44
is(find_and_slurp($dir, 'test', 'es-ES'), 'Theme test, language es-ES', 'Found test/es-ES');
103
is(find_and_slurp_default($opacdir, 'test', 'es-ES'), 'Theme test, language es-ES', 'Found test/es-ES');
45
is(find_and_slurp($dir, 'prog', 'en',  ), 'Theme prog, language en',    'Found test/en');
104
is(find_and_slurp_default($opacdir, 'prog', 'en',  ), 'Theme prog, language en',    'Found test/en');
46
is(find_and_slurp($dir, 'prog', 'es-ES'), 'Theme prog, language es-ES', 'Found test/es-ES');
105
is(find_and_slurp_default($opacdir, 'prog', 'es-ES'), 'Theme prog, language es-ES', 'Found test/es-ES');
47
is(find_and_slurp($dir, 'test', 'fr-FR'), 'Theme test, language en',    'Fell back to test/en for test/fr-FR');
106
is(find_and_slurp_default($opacdir, 'test', 'fr-FR'), 'Theme test, language en',    'Fell back to test/en for test/fr-FR');
48
is(find_and_slurp($dir, 'nope', 'es-ES'), 'Theme prog, language es-ES', 'Fell back to prog/es-ES for nope/es-ES');
107
is(find_and_slurp_default($opacdir, 'nope', 'es-ES'), 'Theme prog, language es-ES', 'Fell back to prog/es-ES for nope/es-ES');
49
is(find_and_slurp($dir, 'nope', 'fr-FR'), 'Theme prog, language en',    'Fell back to prog/en for nope/fr-FR');
108
is(find_and_slurp_default($opacdir, 'nope', 'fr-FR'), 'Theme prog, language en',    'Fell back to prog/en for nope/fr-FR');
109
is(find_and_slurp('MARC21', 'XSLTDetailsDisplay'), 'Theme prog, language en, MARC21slim2intranetDetail', 'Used default for staff/details');
110
is(find_and_slurp('MARC21', 'XSLTResultsDisplay'), 'Theme prog, language en, test_en', 'Used non-default with langcode for staff/results');
111
is(find_and_slurp('MARC21', 'OPACXSLTDetailsDisplay'), 'Theme test, language en, nondefault_test', 'not-prog: Used non-default for local marcflavour and opac/details');
112
is(find_and_slurp('UNIMARC', 'OPACXSLTDetailsDisplay'), 'Theme test, language en, UNIMARCslim2OPACDetail', 'not-prog: Used default for non-local marcflavour and opac/details');
113
is(find_and_slurp('MARC21', 'OPACXSLTResultsDisplay'), 'Theme test, language en, MARC21slim2OPACResults', 'not-prog: Used "default" for opac/results');
50
- 

Return to bug 10486