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 2431-2436 sub new_record_from_zebra { Link Here
2431
2432
2432
}
2433
}
2433
2434
2435
=head2 GetExternalSearchTargets
2436
2437
Returns the list of Z39.50 servers that are marked for search in the OPAC using
2438
Pazpar2.
2439
2440
=cut
2441
2442
sub GetExternalSearchTargets {
2443
    my ( $branchcode ) = @_;
2444
2445
    if ( $branchcode ) {
2446
        return C4::Context->dbh->selectall_arrayref( q{
2447
            SELECT * FROM external_targets et
2448
            LEFT JOIN external_target_restrictions etr
2449
                ON (etr.target_id = et.target_id and etr.branchcode = ?)
2450
            WHERE etr.target_id IS NULL
2451
            ORDER BY et.name
2452
        }, { Slice => {} }, $branchcode );
2453
    } else {
2454
        return C4::Context->dbh->selectall_arrayref( q{
2455
            SELECT * FROM external_targets et
2456
            LEFT JOIN external_target_restrictions etr USING (target_id)
2457
            GROUP by et.target_id
2458
            HAVING branchcode IS NULL
2459
            ORDER BY et.name
2460
        }, { Slice => {} } );
2461
    }
2462
}
2463
2434
END { }    # module clean-up code here (global destructor)
2464
END { }    # module clean-up code here (global destructor)
2435
2465
2436
1;
2466
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 258-263 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
258
('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'),
258
('OpacRenewalAllowed','0',NULL,'If ON, users can renew their issues directly from their OPAC account','YesNo'),
259
('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'),
259
('OpacRenewalBranch','checkoutbranch','itemhomebranch|patronhomebranch|checkoutbranch|null','Choose how the branch for an OPAC renewal is recorded in statistics','Choice'),
260
('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'),
260
('OPACResultsSidebar','','70|10','Define HTML to be included on the search results page, underneath the facets sidebar','Textarea'),
261
('OPACSearchExternalTargets','0',NULL,'Whether to search external targets in the OPAC','YesNo'),
261
('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'),
262
('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'),
262
('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'),
263
('OpacSeparateHoldings','0',NULL,'Separate current branch holdings from other holdings (OPAC)','YesNo'),
263
('OpacSeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings (OPAC)','Choice'),
264
('OpacSeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings (OPAC)','Choice'),
(-)a/installer/data/mysql/updatedatabase.pl (-1 / +33 lines)
Lines 7953-7959 if (CheckVersion($DBversion)) { Link Here
7953
    SetVersion($DBversion);
7953
    SetVersion($DBversion);
7954
}
7954
}
7955
7955
7956
$DBversion = "3.15.00.017";
7957
if(CheckVersion($DBversion)) {
7956
if(CheckVersion($DBversion)) {
7958
    $dbh->do(q{
7957
    $dbh->do(q{
7959
        UPDATE systempreferences
7958
        UPDATE systempreferences
Lines 8083-8088 if ( CheckVersion($DBversion) ) { Link Here
8083
    SetVersion($DBversion);
8082
    SetVersion($DBversion);
8084
}
8083
}
8085
8084
8085
$DBversion = "3.13.00.XXX";
8086
if(CheckVersion($DBversion)) {
8087
    $dbh->do(
8088
"INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES('OPACSearchExternalTargets','0','Whether to search external targets in the OPAC','','YesNo')"
8089
    );
8090
    $dbh->do( q{
8091
CREATE TABLE `external_targets` (
8092
  `target_id` int(11) NOT NULL AUTO_INCREMENT,
8093
  `host` varchar(128) NOT NULL,
8094
  `port` int(11) NOT NULL,
8095
  `db` varchar(64) NOT NULL,
8096
  `userid` varchar(64) DEFAULT '',
8097
  `password` varchar(64) DEFAULT '',
8098
  `name` varchar(64) NOT NULL,
8099
  `syntax` varchar(64) NOT NULL,
8100
  `encoding` varchar(16) DEFAULT 'MARC-8',
8101
  PRIMARY KEY (`target_id`)
8102
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
8103
    } );
8104
    $dbh->do( q{
8105
CREATE TABLE `external_target_restrictions` (
8106
  `branchcode` varchar(10) NOT NULL,
8107
  `target_id` int(11) NOT NULL,
8108
  KEY `branchcode` (`branchcode`),
8109
  KEY `target_id` (`target_id`),
8110
  CONSTRAINT `external_target_restrictions_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE,
8111
  CONSTRAINT `external_target_restrictions_ibfk_2` FOREIGN KEY (`target_id`) REFERENCES `external_targets` (`target_id`) ON DELETE CASCADE
8112
) ENGINE=InnoDB DEFAULT CHARSET=utf8
8113
    } );
8114
    print "Upgrade to $DBversion done (Bug 10486 - Allow external Z39.50 targets to be searched from the OPAC)\n";
8115
    SetVersion($DBversion);
8116
}
8117
8086
=head1 FUNCTIONS
8118
=head1 FUNCTIONS
8087
8119
8088
=head2 TableExists($table)
8120
=head2 TableExists($table)
(-)a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css (+14 lines)
Lines 270-275 tr.even td, tr.even.highlight td { Link Here
270
    border-right : 1px solid #BCBCBC;
270
    border-right : 1px solid #BCBCBC;
271
}
271
}
272
272
273
tr.highlight td {
274
	background-color : #F6F6F6;
275
	border-color : #BCBCBC;
276
}
277
278
tr.highlight th[scope=row] {
279
	background-color : #DDDDDD;
280
	border-color : #BCBCBC;
281
}
282
273
td.od {
283
td.od {
274
	color : #cc0000;
284
	color : #cc0000;
275
	font-weight : bold;
285
	font-weight : bold;
Lines 287-292 tr.odd.onissue td { Link Here
287
	background-color: #FFFFE1;
297
	background-color: #FFFFE1;
288
}
298
}
289
299
300
tr.updated td {
301
    background-color: #FFFFBB;
302
}
303
290
tfoot td {
304
tfoot td {
291
	background-color : #f3f3f3;
305
	background-color : #f3f3f3;
292
	font-weight : bold;
306
	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 436-441 OPAC: Link Here
436
                  yes: Allow
436
                  yes: Allow
437
                  no: Do not allow
437
                  no: Do not allow
438
            - users to add a note when placing a hold.
438
            - users to add a note when placing a hold.
439
        -
440
            - pref: OPACSearchExternalTargets
441
              default: 0
442
              choices:
443
                  yes: Search
444
                  no: "Don't search"
445
            - external targets from the OPAC. (Check with your system administrator first to ensure that Pazpar2 is enabled and running.)
439
446
440
    Policy:
447
    Policy:
441
        -
448
        -
(-)a/koha-tmpl/opac-tmpl/bootstrap/css/opac.css (-1 / +2684 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.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}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.action {
726
  clear: both;
727
  float: none;
728
  border: none;
729
  margin: 0;
730
  padding: 1em 0 .3em 0;
731
  width: auto;
732
}
733
fieldset.action p {
734
  margin-bottom: 1em;
735
}
736
fieldset table {
737
  font-size: 100%;
738
}
739
div.rows + div.rows {
740
  margin-top: .6em;
741
}
742
div.rows {
743
  float: left;
744
  clear: left;
745
  margin: 0 0 0 0;
746
  padding: 0;
747
  width: 100%;
748
}
749
div.rows span.label {
750
  float: left;
751
  font-weight: bold;
752
  width: 9em;
753
  margin-right: 1em;
754
  text-align: left;
755
}
756
div.rows ol {
757
  list-style-type: none;
758
  margin-left: 0;
759
  padding: .5em 1em 0 0;
760
}
761
div.rows li {
762
  border-bottom: 1px solid #EEE;
763
  float: left;
764
  clear: left;
765
  padding-bottom: .2em;
766
  padding-top: .1em;
767
  list-style-type: none;
768
  width: 100%;
769
}
770
div.rows ul li {
771
  margin-left: 7.3em;
772
}
773
div.rows ul li:first-child {
774
  float: none;
775
  clear: none;
776
  margin-left: 0;
777
}
778
div.rows ol li li {
779
  border-bottom: 0;
780
}
781
/* different sizes for different tags in opac-tags.tt */
782
.tagweight0 {
783
  font-size: 12px;
784
}
785
.tagweight1 {
786
  font-size: 14px;
787
}
788
.tagweight2 {
789
  font-size: 16px;
790
}
791
.tagweight3 {
792
  font-size: 18px;
793
}
794
.tagweight4 {
795
  font-size: 20px;
796
}
797
.tagweight5 {
798
  font-size: 22px;
799
}
800
.tagweight6 {
801
  font-size: 24px;
802
}
803
.tagweight7 {
804
  font-size: 26px;
805
}
806
.tagweight8 {
807
  font-size: 28px;
808
}
809
.tagweight9 {
810
  font-size: 30px;
811
}
812
.toolbar {
813
  background-color: #EEEEEE;
814
  border: 1px solid #E8E8E8;
815
  font-size: 85%;
816
  padding: 3px 3px 5px 5px;
817
  vertical-align: middle;
818
}
819
.toolbar a {
820
  white-space: nowrap;
821
}
822
.toolbar label {
823
  display: inline;
824
  font-size: 100%;
825
  font-weight: bold;
826
  margin-left: .5em;
827
}
828
.toolbar select {
829
  font-size: 97%;
830
  height: auto;
831
  line-height: inherit;
832
  padding: 0;
833
  margin: 0;
834
  width: auto;
835
  white-space: nowrap;
836
}
837
.toolbar .hold,
838
.toolbar #tagsel_tag {
839
  padding-left: 28px;
840
  font-size: 97%;
841
  font-weight: bold;
842
}
843
.toolbar #tagsel_form {
844
  margin-top: .5em;
845
}
846
.toolbar li {
847
  display: inline;
848
  list-style: none;
849
}
850
.toolbar li a {
851
  border-left: 1px solid #e8e8e8;
852
}
853
.toolbar li:first-child a {
854
  border-left: 0;
855
}
856
.toolbar ul {
857
  padding-left: 0;
858
}
859
#basket .toolbar {
860
  padding: 7px 5px 9px 9px;
861
}
862
#selections-toolbar {
863
  background: -moz-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
864
  /* FF3.6+ */
865
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #b2b2b2), color-stop(14%, #e0e0e0), color-stop(100%, #e8e8e8));
866
  /* Chrome,Safari4+ */
867
  background: -webkit-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
868
  /* Chrome10+,Safari5.1+ */
869
  background: -o-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
870
  /* Opera 11.10+ */
871
  background: -ms-linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
872
  /* IE10+ */
873
  background: linear-gradient(top, #b2b2b2 0%, #e0e0e0 14%, #e8e8e8 100%);
874
  /* W3C */
875
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e0e0e0', endColorstr='#e8e8e8', GradientType=0);
876
  /* IE6-9 */
877
  margin: 0 0 1em 0;
878
  padding-top: .5em;
879
  padding-left: 10px;
880
}
881
.list-actions {
882
  display: inline;
883
}
884
#tagsel_span input.submit,
885
#tagsel_tag {
886
  border: 0;
887
  background-color: transparent;
888
  font-size: 100%;
889
  color: #0076B2;
890
  cursor: pointer;
891
  background-image: url("../images/sprite.png");
892
  /* Tags */
893
  background-position: 1px -643px;
894
  background-repeat: no-repeat;
895
  padding-left: 25px;
896
  text-decoration: none;
897
}
898
#tagsel_tag.disabled {
899
  background-position: -1px -667px;
900
}
901
#tagsel_span input:hover,
902
#selections-toolbar input.hold:hover {
903
  color: #005580;
904
  text-decoration: underline;
905
}
906
#tagsel_span input.disabled,
907
#tagsel_span input.disabled:hover,
908
#tagsel_span input.hold.disabled,
909
#tagsel_span input.hold.disabled:hover,
910
#selections-toolbar input.hold.disabled,
911
#selections-toolbar input.hold.disabled:hover,
912
#selections-toolbar a.disabled,
913
#selections-toolbar a.disabled:hover {
914
  color: #888888;
915
  text-decoration: none;
916
  padding-left: 23px;
917
}
918
.results_summary {
919
  display: block;
920
  font-size: 85%;
921
  color: #707070;
922
  padding: 0 0 .5em 0;
923
}
924
.results_summary .results_summary {
925
  font-size: 100%;
926
}
927
.results_summary.actions {
928
  margin-top: .5em;
929
}
930
.results_summary.tagstatus {
931
  display: inline;
932
}
933
.results_summary .label {
934
  color: #202020;
935
}
936
.results_summary a {
937
  font-weight: normal;
938
}
939
#views {
940
  border-bottom: 1px solid #D6D6D6;
941
  margin-bottom: .5em;
942
  padding: 0 2em 0.2em 0.2em;
943
  white-space: nowrap;
944
}
945
.view {
946
  padding: 0.2em .2em 2px .2em;
947
}
948
#bibliodescriptions,
949
#isbdcontents {
950
  clear: left;
951
  margin-top: .5em;
952
}
953
.view a,
954
.view span {
955
  background-image: url("../images/sprite.png");
956
  background-repeat: no-repeat;
957
  font-size: 87%;
958
  font-weight: normal;
959
  padding: 0.4em 0.7em 5px 26px;
960
  text-decoration: none;
961
}
962
span#MARCview,
963
span#ISBDview,
964
span#Normalview,
965
span#Fullhistory,
966
span#Briefhistory {
967
  font-weight: bold;
968
}
969
a#MARCview,
970
span#MARCview {
971
  background-position: -3px -23px;
972
}
973
a#MARCviewPop,
974
span#MARCviewPop {
975
  background-position: -3px -23px;
976
}
977
a#ISBDview,
978
span#ISBDview {
979
  background-position: -3px -52px;
980
}
981
a#Normalview,
982
span#Normalview {
983
  background-position: -1px 6px;
984
}
985
.view a {
986
  background-color: #F3F3F3;
987
  border-left: 1px solid #C9C9C9;
988
}
989
#bookcover {
990
  float: left;
991
  margin: 0;
992
  padding: 0;
993
}
994
#bookcover .no-image {
995
  margin-right: 10px;
996
  margin-bottom: 10px;
997
}
998
#bookcover img {
999
  margin: 0 1em 1em 0;
1000
}
1001
/* pagination */
1002
.results-pagination {
1003
  position: absolute;
1004
  top: 32px;
1005
  left: -1px;
1006
  width: 100%;
1007
  height: auto;
1008
  border: 1px solid #D0D0D0;
1009
  display: none;
1010
  background-color: #F3F3F3;
1011
  padding-bottom: 10px;
1012
  z-index: 100;
1013
}
1014
.back {
1015
  float: right;
1016
}
1017
.back input {
1018
  background: none!important;
1019
  color: #999!important;
1020
}
1021
.pagination_list ul {
1022
  padding-top: 40px;
1023
  padding-left: 0px;
1024
}
1025
.pagination_list li {
1026
  list-style: none;
1027
  float: bottom;
1028
  padding: 4px;
1029
  color: #999;
1030
}
1031
.pagination_list li.highlight {
1032
  background-color: #F3F3F3;
1033
  border-top: 1px solid #DDDDDD;
1034
  border-bottom: 1px solid #DDDDDD;
1035
}
1036
.pagination_list li a {
1037
  padding-left: 0px;
1038
}
1039
.pagination_list .li_pag_index {
1040
  color: #999999;
1041
  float: left;
1042
  font-size: 15px;
1043
  font-weight: bold;
1044
  padding-right: 10px;
1045
  text-align: right;
1046
  width: 13px;
1047
}
1048
.nav_results {
1049
  background-color: #F3F3F3;
1050
  border: 1px solid #D0D0D0;
1051
  font-size: 95%;
1052
  font-weight: bold;
1053
  margin-top: 0.5em;
1054
  position: relative;
1055
}
1056
.nav_results .l_Results a {
1057
  background: #e1e1e1 url("../images/sprite.png") no-repeat 0px -504px;
1058
  /* Browse results menu */
1059
  color: #006699;
1060
  display: block;
1061
  padding: 8px 28px;
1062
  text-decoration: none;
1063
}
1064
.nav_results .l_Results:hover {
1065
  background-color: #D9D9D9;
1066
}
1067
.pg_menu {
1068
  margin: 0;
1069
  border-top: 1px solid #D0D0D0;
1070
  white-space: nowrap;
1071
}
1072
.pg_menu li {
1073
  color: #B2B2B2;
1074
  display: inline;
1075
  list-style: none;
1076
  margin: 0;
1077
}
1078
.pg_menu li.back_results a {
1079
  border-left: 1px solid #D0D0D0;
1080
  border-right: 1px solid #D0D0D0;
1081
}
1082
.pg_menu li a,
1083
.pg_menu li span {
1084
  background-color: #F3F3F3;
1085
  display: block;
1086
  float: left;
1087
  padding: .4em .5em;
1088
  text-decoration: none;
1089
  font-weight: normal;
1090
  text-align: center;
1091
}
1092
.pg_menu li span {
1093
  color: #B2B2B2;
1094
}
1095
#listResults li {
1096
  background-color: #999999;
1097
  color: #C5C5C5;
1098
  font-weight: normal;
1099
  display: block;
1100
  margin-right: 1px;
1101
  font-size: 80%;
1102
  padding: 0;
1103
  text-align: center;
1104
  min-width: 18px;
1105
}
1106
#listResults li:hover {
1107
  background-color: #006699;
1108
}
1109
#listResults li a {
1110
  color: #FFFFFF;
1111
  font-weight: normal;
1112
}
1113
/* nav */
1114
.nav_pages .close_pagination {
1115
  padding-right: 10px;
1116
  position: absolute;
1117
  right: 3px;
1118
  top: -25px;
1119
}
1120
.nav_pages .close_pagination a {
1121
  text-decoration: none!important;
1122
}
1123
.nav_pages ul {
1124
  padding-top: 10px;
1125
}
1126
.nav_pages li {
1127
  list-style: none;
1128
  float: left;
1129
  padding: 4px;
1130
  color: #999;
1131
}
1132
.nav_pages li a {
1133
  text-decoration: none!important;
1134
}
1135
.nav_pages li a:hover {
1136
  text-decoration: underline;
1137
}
1138
.nav_pages li ul {
1139
  float: left;
1140
}
1141
/* action buttons */
1142
#action {
1143
  margin: .5em 0 0 0;
1144
  background-color: #F3F3F3;
1145
  border: 1px solid #E8E8E8;
1146
  padding-bottom: 3px;
1147
}
1148
#action li {
1149
  list-style: none;
1150
  margin: .2em;
1151
  padding: .3em 0;
1152
}
1153
#action a {
1154
  font-weight: bold;
1155
  text-decoration: none;
1156
}
1157
#export li,
1158
#moresearches_menu li {
1159
  padding: 0;
1160
  margin: 0;
1161
}
1162
#export li a,
1163
#moresearches_menu li a {
1164
  font-weight: normal;
1165
}
1166
#export li a.menu-inactive,
1167
#moresearches_menu li a.menu-inactive {
1168
  font-weight: bold;
1169
}
1170
#format,
1171
#furthersearches {
1172
  padding-left: 35px;
1173
}
1174
.highlight_controls {
1175
  float: left;
1176
}
1177
a.addtocart,
1178
a.addtoshelf,
1179
a.brief,
1180
a.deleteshelf,
1181
a.deleteshelf.disabled,
1182
a.detail,
1183
a.download,
1184
a.editshelf,
1185
a.empty,
1186
a.hide,
1187
a.highlight_toggle,
1188
a.hold,
1189
a.hold.disabled,
1190
a.incart,
1191
a.new,
1192
a.print-small,
1193
a.print-large,
1194
a.removeitems,
1195
a.removeitems.disabled,
1196
a.reserve,
1197
a.send,
1198
a.tag_add,
1199
a.removefromlist,
1200
input.hold,
1201
input.hold.disabled,
1202
input.editshelf,
1203
.newshelf,
1204
.newshelf.disabled,
1205
.deleteshelf {
1206
  background-image: url("../images/sprite.png");
1207
  background-repeat: no-repeat;
1208
}
1209
a.addtocart {
1210
  background-position: -5px -265px;
1211
  /* Cart */
1212
  padding-left: 35px;
1213
}
1214
a.addtoshelf {
1215
  background-position: -5px -225px;
1216
  /* Virtual shelf */
1217
  padding-left: 35px;
1218
}
1219
a.brief {
1220
  background-position: -2px -868px;
1221
  /* Zoom out */
1222
  text-decoration: none;
1223
  padding-left: 27px;
1224
}
1225
a.cartRemove {
1226
  color: #cc3333;
1227
  font-size: 90%;
1228
  margin: 0;
1229
  padding: 0;
1230
}
1231
a.detail {
1232
  background-position: -2px -898px;
1233
  /* Zoom in */
1234
  text-decoration: none;
1235
  padding-left: 27px;
1236
}
1237
a.download {
1238
  background-position: -5px -348px;
1239
  /* Download */
1240
  padding-left: 20px;
1241
  text-decoration: none;
1242
}
1243
a.editshelf {
1244
  background-position: 2px -348px;
1245
  /* List edit */
1246
  padding-left: 26px;
1247
  text-decoration: none;
1248
}
1249
a.empty {
1250
  background-position: 2px -598px;
1251
  /* Trash */
1252
  text-decoration: none;
1253
  padding-left: 30px;
1254
}
1255
a.hide {
1256
  background-position: -3px -814px;
1257
  /* Close */
1258
  text-decoration: none;
1259
  padding-left: 26px;
1260
}
1261
a.highlight_toggle {
1262
  background-position: -5px -841px;
1263
  /* Highlight */
1264
  display: none;
1265
  padding-left: 35px;
1266
}
1267
a.hold,
1268
input.hold {
1269
  background-position: -2px -453px;
1270
  /* Toolbar place hold */
1271
  text-decoration: none;
1272
  padding-left: 23px;
1273
}
1274
a.hold.disabled,
1275
input.hold.disabled {
1276
  background-position: -5px -621px;
1277
  /* Place hold disabled */
1278
}
1279
a.incart {
1280
  background-position: -5px -265px;
1281
  /* Cart */
1282
  color: #666;
1283
  padding-left: 35px;
1284
}
1285
a.new {
1286
  background-image: url("../images/sprite.png");
1287
  /* New */
1288
  background-position: -4px -922px;
1289
  padding-left: 23px;
1290
  text-decoration: none;
1291
}
1292
a.print-small {
1293
  background-position: 0px -423px;
1294
  /* Toolbar print */
1295
  text-decoration: none;
1296
  padding-left: 30px;
1297
}
1298
a.print-large {
1299
  background-position: -5px -186px;
1300
  /* Toolbar print */
1301
  text-decoration: none;
1302
  padding-left: 35px;
1303
}
1304
a.removeitems,
1305
a.deleteshelf {
1306
  background-position: 2px -690px;
1307
  /* Delete */
1308
  text-decoration: none;
1309
  padding-left: 25px;
1310
}
1311
a.removeitems.disabled,
1312
a.deleteshelf.disabled {
1313
  background-position: 2px -712px;
1314
  /* Delete disabled */
1315
}
1316
a.reserve {
1317
  background-position: -6px -144px;
1318
  /* Place hold */
1319
  padding-left: 35px;
1320
}
1321
a.send {
1322
  background-position: 2px -386px;
1323
  /* Email */
1324
  text-decoration: none;
1325
  padding-left: 28px;
1326
}
1327
a.tag_add {
1328
  background-position: 3px -1111px;
1329
  /* Tag results */
1330
  padding-left: 27px;
1331
  text-decoration: none;
1332
}
1333
input.hold {
1334
  background-color: transparent;
1335
  border: 0;
1336
  color: #0076B2;
1337
  font-weight: bold;
1338
}
1339
input.editshelf {
1340
  background-color: transparent;
1341
  background-position: 2px -736px;
1342
  /* List edit */
1343
  border: 0;
1344
  color: #006699;
1345
  cursor: pointer;
1346
  filter: none;
1347
  font-size: 100%;
1348
  padding-left: 29px;
1349
  text-decoration: none;
1350
}
1351
.newshelf {
1352
  background-position: 2px -764px;
1353
  /* List new */
1354
  border: 0;
1355
  color: #006699;
1356
  cursor: pointer;
1357
  filter: none;
1358
  font-size: 100%;
1359
  padding-left: 28px;
1360
  text-decoration: none;
1361
}
1362
.newshelf.disabled {
1363
  background-position: -4px -791px;
1364
  /* List new disabled */
1365
}
1366
.deleteshelf {
1367
  background-color: transparent;
1368
  background-position: 2px -690px;
1369
  /* Delete */
1370
  border: 0;
1371
  color: #006699;
1372
  cursor: pointer;
1373
  filter: none;
1374
  font-size: 100%;
1375
  padding-left: 25px;
1376
  text-decoration: none;
1377
}
1378
.links a {
1379
  font-weight: bold;
1380
}
1381
.deleteshelf:hover {
1382
  color: #990033;
1383
}
1384
.editshelf:active,
1385
.deleteshelf:active {
1386
  border: 0;
1387
}
1388
#tagslist li {
1389
  display: inline;
1390
}
1391
#login4tags {
1392
  background-image: url("../images/sprite.png");
1393
  /* Tag results disabled */
1394
  background-position: -6px -1130px;
1395
  background-repeat: no-repeat;
1396
  padding-left: 20px;
1397
  text-decoration: none;
1398
}
1399
.tag_results_input {
1400
  margin-left: 1em;
1401
  padding: 0.3em;
1402
  font-size: 12px;
1403
}
1404
.tag_results_input input[type="text"] {
1405
  font-size: inherit;
1406
  margin: 0;
1407
  padding: 0;
1408
}
1409
.tag_results_input label {
1410
  display: inline;
1411
}
1412
.tagsinput input[type="text"] {
1413
  font-size: inherit;
1414
  margin: 0;
1415
  padding: 0;
1416
}
1417
.tagsinput label {
1418
  display: inline;
1419
}
1420
.branch-info-tooltip {
1421
  display: none;
1422
}
1423
#social_networks a {
1424
  background: transparent url("../images/social-sprite.png") no-repeat;
1425
  display: block;
1426
  height: 20px !important;
1427
  width: 20px;
1428
  text-indent: -999em;
1429
}
1430
#social_networks span {
1431
  color: #274D7F;
1432
  display: block;
1433
  float: left;
1434
  font-size: 85%;
1435
  font-weight: bold;
1436
  line-height: 2em;
1437
  margin: .5em 0 .5em .5em !important;
1438
}
1439
#social_networks div {
1440
  float: left !important;
1441
  margin: .5em 0 .5em .2em !important;
1442
}
1443
#social_networks #facebook {
1444
  background-position: -7px -35px;
1445
}
1446
#social_networks #twitter {
1447
  background-position: -7px -5px;
1448
}
1449
#social_networks #linkedin {
1450
  background-position: -7px -95px;
1451
}
1452
#social_networks #delicious {
1453
  background-position: -7px -66px;
1454
}
1455
#social_networks #email {
1456
  background-position: -7px -126px;
1457
}
1458
#marc td,
1459
#marc th {
1460
  background-color: transparent;
1461
  border: 0;
1462
  padding: 3px 5px;
1463
  text-align: left;
1464
}
1465
#marc td:first-child {
1466
  text-indent: 2em;
1467
}
1468
#marc p {
1469
  padding-bottom: .6em;
1470
}
1471
#marc p .label {
1472
  font-weight: bold;
1473
}
1474
#marc ul {
1475
  padding-bottom: .6em;
1476
}
1477
#marc .results_summary {
1478
  clear: left;
1479
}
1480
#marc .results_summary ul {
1481
  display: inline;
1482
  float: none;
1483
  clear: none;
1484
  margin: 0;
1485
  padding: 0;
1486
  list-style: none;
1487
}
1488
#marc .results_summary li {
1489
  display: inline;
1490
}
1491
#items,
1492
#items td #items th {
1493
  border: 1px solid #EEE;
1494
  font-size: 90%;
1495
}
1496
#plainmarc table {
1497
  border: 0;
1498
  margin: .7em 0 0 0;
1499
  font-family: monospace;
1500
  font-size: 95%;
1501
}
1502
#plainmarc th {
1503
  background-color: #FFF;
1504
  border: 0;
1505
  white-space: nowrap;
1506
  text-align: left;
1507
  vertical-align: top;
1508
  padding: 2px;
1509
}
1510
#plainmarc td {
1511
  border: 0;
1512
  padding: 2px;
1513
  vertical-align: top;
1514
}
1515
#renewcontrols {
1516
  float: right;
1517
  font-size: 66%;
1518
}
1519
#renewcontrols a {
1520
  background-repeat: no-repeat;
1521
  text-decoration: none;
1522
  padding: .1em .4em;
1523
  padding-left: 18px;
1524
}
1525
#renewselected_link {
1526
  background-image: url("../images/sprite.png");
1527
  background-position: -5px -986px;
1528
  background-repeat: no-repeat;
1529
}
1530
#renewall_link {
1531
  background-image: url("../images/sprite.png");
1532
  background-position: -8px -967px;
1533
  background-repeat: no-repeat;
1534
}
1535
.authref {
1536
  text-indent: 2em;
1537
}
1538
.authref .label {
1539
  font-style: italic;
1540
}
1541
.authstanza {
1542
  margin-top: 1em;
1543
}
1544
.authstanzaheading {
1545
  font-weight: bold;
1546
}
1547
.authorizedheading {
1548
  font-weight: bold;
1549
}
1550
.authstanza li {
1551
  margin-left: 0.5em;
1552
}
1553
.authres_notes,
1554
.authres_seealso,
1555
.authres_otherscript {
1556
  padding-top: .5em;
1557
}
1558
.authres_notes {
1559
  font-style: italic;
1560
}
1561
#didyoumean {
1562
  background-color: #EEE;
1563
  border: 1px solid #E8E8E8;
1564
  margin: 0 0 0.5em;
1565
  text-align: left;
1566
  padding: 0.5em;
1567
  -webkit-border-radius: 3px;
1568
  -moz-border-radius: 3px;
1569
  border-radius: 3px;
1570
}
1571
.suggestionlabel {
1572
  font-weight: bold;
1573
}
1574
.searchsuggestion {
1575
  padding: 0.2em 0.5em;
1576
  white-space: nowrap;
1577
  display: inline-block;
1578
}
1579
.authlink {
1580
  padding-left: 0.25em;
1581
}
1582
#hierarchies a {
1583
  font-weight: normal;
1584
  text-decoration: underline;
1585
  color: #069;
1586
}
1587
#hierarchies a:hover {
1588
  color: #990033;
1589
}
1590
#top-pages {
1591
  margin: 0 0 0.5em;
1592
}
1593
.dropdown-menu > li > a {
1594
  font-size: 90%;
1595
}
1596
a.listmenulink:link,
1597
a.listmenulink:visited {
1598
  color: #0076B2;
1599
  font-weight: bold;
1600
}
1601
a.listmenulink:hover,
1602
a.listmenulink:active {
1603
  color: #FFF;
1604
  font-weight: bold;
1605
}
1606
#cartDetails,
1607
#cartUpdate,
1608
#holdDetails,
1609
#listsDetails {
1610
  background-color: #FFF;
1611
  border: 1px solid rgba(0, 0, 0, 0.2);
1612
  border-radius: 6px 6px 6px 6px;
1613
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
1614
  color: black;
1615
  display: none;
1616
  font-size: 90%;
1617
  margin: 0;
1618
  padding: 8px 20px;
1619
  text-align: center;
1620
  width: 180px;
1621
  z-index: 2;
1622
}
1623
#cartmenulink {
1624
  white-space: nowrap;
1625
}
1626
#search-facets,
1627
#menu {
1628
  border: 1px solid #D2D2CF;
1629
  -webkit-border-radius: 7px;
1630
  -moz-border-radius: 7px;
1631
  border-radius: 7px;
1632
}
1633
#search-facets ul,
1634
#menu ul {
1635
  margin: 0;
1636
  padding: .3em;
1637
}
1638
#search-facets form,
1639
#menu form {
1640
  margin: 0;
1641
}
1642
#search-facets h4,
1643
#menu h4 {
1644
  font-size: 90%;
1645
  margin: 0 0 .6em 0;
1646
  text-align: center;
1647
}
1648
#search-facets h4 a,
1649
#menu h4 a {
1650
  background-color: #F2F2EF;
1651
  border-radius: 8px 8px 0 0;
1652
  border-bottom: 1px solid #D8D8D8;
1653
  display: block;
1654
  font-weight: bold;
1655
  padding: .7em .2em;
1656
  text-decoration: none;
1657
}
1658
#search-facets li,
1659
#menu li {
1660
  font-size: 90%;
1661
  font-weight: bold;
1662
  list-style-type: none;
1663
}
1664
#search-facets li li,
1665
#menu li li {
1666
  font-weight: normal;
1667
  font-size: 95%;
1668
  line-height: 125%;
1669
  margin-bottom: 2px;
1670
  padding: .1em .2em;
1671
}
1672
#search-facets li.showmore a,
1673
#menu li.showmore a {
1674
  font-weight: bold;
1675
  text-indent: 1em;
1676
}
1677
#search-facets a,
1678
#menu a {
1679
  font-weight: normal;
1680
  text-decoration: underline;
1681
}
1682
#menu {
1683
  font-size: 94%;
1684
}
1685
#menu li {
1686
  list-style-type: none;
1687
}
1688
#menu li a {
1689
  background: #eeeeee;
1690
  text-decoration: none;
1691
  display: block;
1692
  border: 1px solid #D8D8D8;
1693
  border-radius: 5px 0 0 5px;
1694
  border-bottom-color: #999;
1695
  font-size: 111%;
1696
  padding: .4em .6em;
1697
  margin: .4em 0;
1698
  margin-right: -1px;
1699
}
1700
#menu li a:hover {
1701
  background: #eaeef5;
1702
}
1703
#menu li.active a {
1704
  background-color: #FFF;
1705
  background-image: none;
1706
  border-right-width: 0;
1707
  font-weight: bold;
1708
}
1709
#menu li.active a:hover {
1710
  background-color: #fff;
1711
}
1712
#menu h4 {
1713
  display: none;
1714
}
1715
#addto {
1716
  max-width: 10em;
1717
}
1718
/* Search results add to cart (lists disabled) */
1719
.addto a.addtocart {
1720
  background-image: url("../images/sprite.png");
1721
  /* Cart */
1722
  background-position: -5px -266px;
1723
  background-repeat: no-repeat;
1724
  text-decoration: none;
1725
  padding-left: 33px;
1726
}
1727
.searchresults p {
1728
  margin: 0;
1729
  padding: 0 0 .6em 0;
1730
}
1731
.searchresults p.details {
1732
  color: #979797;
1733
}
1734
.searchresults a.highlight_toggle {
1735
  background-image: url("../images/sprite.png");
1736
  /* Highlight */
1737
  background-position: -11px -841px;
1738
  background-repeat: no-repeat;
1739
  display: none;
1740
  font-weight: normal;
1741
  padding: 0 10px 0 21px;
1742
}
1743
.searchresults .commentline {
1744
  background-color: #ffffcc;
1745
  background-color: rgba(255, 255, 204, 0.4);
1746
  border: 1px solid #CCC;
1747
  display: inline-block;
1748
  -webkit-border-radius: 3px;
1749
  -moz-border-radius: 3px;
1750
  border-radius: 3px;
1751
  -webkit-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1752
  -moz-box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1753
  box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.2);
1754
  margin: .3em;
1755
  padding: .4em;
1756
}
1757
.searchresults .commentline.yours {
1758
  background-color: #effed5;
1759
  background-color: rgba(239, 254, 213, 0.4);
1760
}
1761
.commentline .avatar {
1762
  float: right;
1763
  padding-left: .5em;
1764
}
1765
/* style for search terms in catalogsearch */
1766
.term {
1767
  /* color : blue; */
1768
  color: #990000;
1769
  background-color: #FFFFCC;
1770
}
1771
/* style for shelving location in catalogsearch */
1772
.shelvingloc {
1773
  display: block;
1774
  font-style: italic;
1775
}
1776
#CheckAll,
1777
#CheckNone {
1778
  font-weight: normal;
1779
  margin: 0 .5em;
1780
  text-decoration: underline;
1781
}
1782
span.sep {
1783
  color: #888;
1784
  padding: 0 .2em 0 .5em;
1785
  text-shadow: 1px 1px 0 #FFF;
1786
}
1787
/* style for PM-generated pagination bar */
1788
.pages span:first-child,
1789
.pages a:first-child {
1790
  border-width: 1px 1px 1px 1px;
1791
  border-bottom-left-radius: 3px;
1792
  border-top-left-radius: 3px;
1793
}
1794
.pages span:last-child,
1795
.pages a:last-child {
1796
  border-width: 1px 1px 1px 0;
1797
  border-bottom-right-radius: 3px;
1798
  border-top-right-radius: 3px;
1799
}
1800
.pages .inactive,
1801
.pages .currentPage,
1802
.pages a {
1803
  -moz-border-bottom-colors: none;
1804
  -moz-border-left-colors: none;
1805
  -moz-border-right-colors: none;
1806
  -moz-border-top-colors: none;
1807
  background-color: #FFFFFF;
1808
  border-color: #DDDDDD;
1809
  border-image: none;
1810
  border-style: solid;
1811
  border-width: 1px 1px 1px 0;
1812
  float: left;
1813
  font-size: 11.9px;
1814
  line-height: 20px;
1815
  padding: 4px 12px;
1816
  text-decoration: none;
1817
}
1818
.pages .inactive {
1819
  background-color: #F5F5F5;
1820
}
1821
.pages a[rel='last'] {
1822
  border-bottom-right-radius: 3px;
1823
  border-top-right-radius: 3px;
1824
}
1825
.hold-message {
1826
  background-color: #FFF0B1;
1827
  display: inline-block;
1828
  margin: 0.5em;
1829
  padding: 0.2em 0.5em;
1830
  -webkit-border-radius: 3px;
1831
  -moz-border-radius: 3px;
1832
  border-radius: 3px;
1833
}
1834
.reserve_date,
1835
.expiration_date {
1836
  white-space: nowrap;
1837
}
1838
.close {
1839
  color: #0088CC;
1840
  position: inherit;
1841
  top: auto;
1842
  right: auto;
1843
  filter: none;
1844
  float: none;
1845
  font-size: inherit;
1846
  font-weight: normal;
1847
  opacity: inherit;
1848
  text-shadow: none;
1849
}
1850
.close:hover {
1851
  color: #538200;
1852
  filter: inherit;
1853
  font-size: inherit;
1854
  opacity: inherit;
1855
}
1856
/* Redefine a new style for Bootstrap's class "close" since we use that already */
1857
/* Use <a class="closebtn" href="#">&times;</a> */
1858
.alert .closebtn {
1859
  position: relative;
1860
  top: -2px;
1861
  right: -21px;
1862
  line-height: 20px;
1863
}
1864
.modal-header .closebtn {
1865
  margin-top: 2px;
1866
}
1867
.closebtn {
1868
  float: right;
1869
  font-size: 20px;
1870
  font-weight: bold;
1871
  line-height: 20px;
1872
  color: #000000;
1873
  text-shadow: 0 1px 0 #ffffff;
1874
  opacity: 0.2;
1875
  filter: alpha(opacity=20);
1876
}
1877
.closebtn:hover {
1878
  color: #000000;
1879
  text-decoration: none;
1880
  cursor: pointer;
1881
  opacity: 0.4;
1882
  filter: alpha(opacity=40);
1883
}
1884
button.closebtn {
1885
  padding: 0;
1886
  cursor: pointer;
1887
  background: transparent;
1888
  border: 0;
1889
  -webkit-appearance: none;
1890
}
1891
.btn-group label,
1892
.btn-group select {
1893
  font-size: 13px;
1894
}
1895
.span2 select {
1896
  width: 100%;
1897
}
1898
.popup .main {
1899
  font-size: 90%;
1900
  padding: 0 1em;
1901
}
1902
.popup legend {
1903
  line-height: 1.5em;
1904
  margin-bottom: .5em;
1905
}
1906
.available {
1907
  color: #006600;
1908
}
1909
.waiting,
1910
.intransit,
1911
.notforloan,
1912
.checkedout,
1913
.lost,
1914
.notonhold {
1915
  display: block;
1916
}
1917
.notforloan {
1918
  color: #900;
1919
}
1920
.lost {
1921
  color: #666;
1922
}
1923
.suggestion {
1924
  background-color: #EEEEEB;
1925
  border: 1px solid #DDDED3;
1926
  margin: 1em auto;
1927
  padding: .5em;
1928
  width: 35%;
1929
  -webkit-border-radius: 3px;
1930
  -moz-border-radius: 3px;
1931
  border-radius: 3px;
1932
}
1933
.librarypulldown .transl1 {
1934
  width: auto;
1935
}
1936
.nolibrarypulldown {
1937
  width: 68%;
1938
}
1939
.nolibrarypulldown .transl1 {
1940
  width: 87%;
1941
}
1942
#opac-main-search select {
1943
  width: auto;
1944
  max-width: 12em;
1945
}
1946
#logo {
1947
  background: transparent url("../images/koha-logo-navbar.png") no-repeat scroll 0%;
1948
  border: 0;
1949
  float: left !important;
1950
  margin: 0;
1951
  padding: 0;
1952
  width: 100px;
1953
}
1954
#logo a {
1955
  border: 0;
1956
  cursor: pointer;
1957
  display: block;
1958
  height: 0px !important;
1959
  margin: 0;
1960
  overflow: hidden;
1961
  padding: 40px 0 0;
1962
  text-decoration: none;
1963
  width: 100px;
1964
}
1965
#user-menu-trigger {
1966
  display: none;
1967
}
1968
#user-menu-trigger .icon-user {
1969
  background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;
1970
  background-position: -168px 0;
1971
  background-repeat: no-repeat;
1972
  height: 14px;
1973
  line-height: 14px;
1974
  margin: 12px 0 0;
1975
  vertical-align: text-top;
1976
  width: 14px;
1977
}
1978
#user-menu-trigger .caret {
1979
  border-bottom-color: #999999;
1980
  border-top-color: #999999;
1981
  margin-top: 18px;
1982
}
1983
/* Class to be added to toolbar when it starts being fixed at the top of the screen*/
1984
.floating {
1985
  -webkit-box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4);
1986
  box-shadow: 0px 3px 2px 0px rgba(0, 0, 0, 0.4);
1987
  margin-top: 0;
1988
}
1989
.tdlabel {
1990
  font-weight: bold;
1991
  display: none;
1992
}
1993
td img {
1994
  max-width: none;
1995
}
1996
#ulactioncontainer {
1997
  min-width: 16em;
1998
}
1999
.notesrow label {
2000
  font-weight: bold;
2001
}
2002
.notesrow span {
2003
  display: block;
2004
}
2005
.thumbnail-shelfbrowser span {
2006
  margin: 0px auto;
2007
}
2008
.dropdown-menu > li > a.menu-inactive:hover {
2009
  background: #FFF none;
2010
  color: #000;
2011
}
2012
.table .sorting_asc {
2013
  padding-right: 19px;
2014
  background: url("../images/asc.gif") no-repeat scroll right center #ecede6;
2015
}
2016
.table .sorting_desc {
2017
  padding-right: 19px;
2018
  background: url("../images/desc.gif") no-repeat scroll right center #ecede6;
2019
}
2020
.table .sorting {
2021
  padding-right: 19px;
2022
  background: url("../images/ascdesc.gif") no-repeat scroll right center #ecede6;
2023
}
2024
.table .nosort,
2025
.table .nosort.sorting_asc,
2026
.table .nosort.sorting_desc,
2027
.table .nosort.sorting {
2028
  padding-right: 19px;
2029
  background: #ECEDE6 none;
2030
}
2031
.tags ul {
2032
  display: inline;
2033
  list-style: none;
2034
  margin-left: 0;
2035
}
2036
.tags ul li {
2037
  display: inline;
2038
}
2039
.coverimages {
2040
  float: right;
2041
}
2042
#i18nMenu {
2043
  margin-left: 1em;
2044
}
2045
#i18nMenu li {
2046
  font-size: 85%;
2047
}
2048
#i18nMenu li li {
2049
  font-size: 100%;
2050
}
2051
#i18nMenu li li > a {
2052
  font-size: 100%;
2053
}
2054
#i18nMenu li li > a:hover {
2055
  color: #FFF;
2056
}
2057
#i18nMenu li a {
2058
  color: #0076b2;
2059
}
2060
#i18nMenu .dropdown-menu li p {
2061
  clear: both;
2062
  display: block;
2063
  font-weight: normal;
2064
  line-height: 20px;
2065
  padding: 3px 20px;
2066
  white-space: nowrap;
2067
}
2068
#subjectsList label,
2069
#authorSearch label {
2070
  display: inline;
2071
  vertical-align: middle;
2072
}
2073
#subjectsList ul,
2074
#authorSearch ul {
2075
  border-bottom: 1px solid #EEE;
2076
  list-style-type: none;
2077
  margin: 0;
2078
  padding: .6em 0;
2079
}
2080
#subjectsList li,
2081
#authorSearch li {
2082
  list-style-type: none;
2083
  margin: 0;
2084
  padding: 0;
2085
}
2086
#overdrive-results,
2087
#pazpar2-results {
2088
  font-weight: bold;
2089
  padding-left: 1em;
2090
}
2091
.throbber {
2092
  vertical-align: middle;
2093
}
2094
#overdrive-results-list .star-rating-control {
2095
  display: block;
2096
  overflow: auto;
2097
}
2098
#shelfbrowser table {
2099
  margin: 0;
2100
}
2101
#shelfbrowser table,
2102
#shelfbrowser td,
2103
#shelfbrowser th {
2104
  border: 0;
2105
  font-size: 90%;
2106
  text-align: center;
2107
}
2108
#shelfbrowser td,
2109
#shelfbrowser th {
2110
  padding: 3px 5px;
2111
  width: 20%;
2112
}
2113
#shelfbrowser a {
2114
  display: block;
2115
  font-size: 110%;
2116
  font-weight: bold;
2117
  text-decoration: none;
2118
}
2119
#shelfbrowser #browser_next,
2120
#shelfbrowser #browser_previous {
2121
  background-image: url("../images/sprite.png");
2122
  background-repeat: no-repeat;
2123
  width: 16px;
2124
}
2125
#shelfbrowser #browser_next a,
2126
#shelfbrowser #browser_previous a {
2127
  cursor: pointer;
2128
  display: block;
2129
  height: 0 !important;
2130
  margin: 0;
2131
  overflow: hidden;
2132
  padding: 50px 0 0;
2133
  text-decoration: none;
2134
  width: 16px;
2135
}
2136
#shelfbrowser #browser_previous {
2137
  background-position: -9px -1007px;
2138
}
2139
#shelfbrowser #browser_next {
2140
  background-position: -9px -1057px;
2141
}
2142
#holds {
2143
  margin: 0 auto;
2144
  max-width: 800px;
2145
}
2146
.holdrow {
2147
  clear: both;
2148
  padding: 0 1em 1em 1em;
2149
  border-bottom: 1px solid #CCC;
2150
  margin-bottom: .5em;
2151
}
2152
.holdrow fieldset {
2153
  border: 0;
2154
  margin: 0;
2155
  float: none;
2156
}
2157
.holdrow fieldset .label {
2158
  font-size: 14px;
2159
}
2160
.holdrow label {
2161
  display: inline;
2162
}
2163
.hold-options {
2164
  clear: both;
2165
}
2166
.toggle-hold-options {
2167
  background-color: #eee;
2168
  clear: both;
2169
  display: block;
2170
  font-weight: bold;
2171
  margin: 1em 0;
2172
  padding: .5em;
2173
}
2174
.copiesrow {
2175
  clear: both;
2176
}
2177
#idreambooksreadometer {
2178
  float: right;
2179
}
2180
a.idreambooksrating {
2181
  font-size: 30px;
2182
  color: #29ADE4;
2183
  padding-left: 85px;
2184
  line-height: 30px;
2185
  text-decoration: none;
2186
}
2187
.idreambookslegend {
2188
  font-size: small;
2189
}
2190
a.reviewlink,
2191
a.reviewlink:visited {
2192
  text-decoration: none;
2193
  color: black;
2194
  font-weight: normal;
2195
}
2196
.idreambookssummary a {
2197
  color: #707070;
2198
  text-decoration: none;
2199
}
2200
.idreambookssummary img,
2201
.idbresult img {
2202
  vertical-align: middle;
2203
}
2204
.idbresult {
2205
  color: #29ADE4;
2206
  text-align: center;
2207
  margin: 0.5em;
2208
  padding: 0.5em;
2209
}
2210
.idbresult a,
2211
.idbresult a:visited {
2212
  text-decoration: none;
2213
  color: #29ADE4;
2214
}
2215
.idbresult img {
2216
  padding-right: 6px;
2217
}
2218
.js-show {
2219
  display: none;
2220
}
2221
.modal-nojs .modal-header,
2222
.modal-nojs .modal-footer {
2223
  display: none;
2224
}
2225
@media only screen and (min-width: 0px) and (max-width: 304px) {
2226
  /* Screens bewteen 0 and 304 pixels wide */
2227
  #oh:after {
2228
    content: "(min-width: 0px) and (max-width: 304px)";
2229
  }
2230
  input,
2231
  select,
2232
  textarea {
2233
    width: auto;
2234
    max-width: 11em;
2235
  }
2236
}
2237
@media only screen and (min-width: 0px) and (max-width: 390px) {
2238
  /* Screens bewteen 0 and 390 pixels wide */
2239
  #oh:after {
2240
    content: "(min-width: 0px) and (max-width: 390px)";
2241
  }
2242
  .ui-tabs .ui-tabs-nav li a,
2243
  .statictabs li a {
2244
    padding: .1em .5em;
2245
  }
2246
  #views {
2247
    border: 0;
2248
    padding: 0;
2249
    margin: 0;
2250
  }
2251
  .view {
2252
    padding: 0;
2253
  }
2254
  .view a,
2255
  .view span {
2256
    border: 1px solid #C9C9C9;
2257
    -webkit-border-radius: 4px;
2258
    -moz-border-radius: 4px;
2259
    border-radius: 4px;
2260
    font-size: 80%;
2261
    padding: 0.3em 0.4em 4px 26px;
2262
  }
2263
  .input-fluid {
2264
    width: 90%;
2265
  }
2266
}
2267
@media only screen and (min-width: 305px) and (max-width: 341px) {
2268
  /* Screens bewteen 305 and 341 pixels wide */
2269
  #oh:after {
2270
    content: "(min-width: 305px) and (max-width: 341px)";
2271
  }
2272
}
2273
@media only screen and (min-width: 342px) and (max-width: 479px) {
2274
  /* Screens bewteen 342 and 479 pixels wide */
2275
  #oh:after {
2276
    content: "(min-width: 342px) and (max-width: 479px)";
2277
  }
2278
  .input-fluid {
2279
    width: 75%;
2280
  }
2281
}
2282
/* Override Bootstrap Responsive CSS fixed navbar */
2283
@media (max-width: 979px) {
2284
  .navbar-fixed-top,
2285
  .navbar-fixed-bottom {
2286
    position: fixed;
2287
    margin-left: 0px;
2288
    margin-right: 0px;
2289
  }
2290
}
2291
@media only screen and (max-width: 608px) {
2292
  /* Screens below 608 pixels wide */
2293
  fieldset.rows label {
2294
    display: block;
2295
    float: none;
2296
    text-align: left;
2297
  }
2298
  fieldset.rows li {
2299
    padding-bottom: .5em;
2300
  }
2301
  fieldset.rows ol {
2302
    margin-left: 0;
2303
  }
2304
  body {
2305
    padding: 0;
2306
  }
2307
  .tdlabel {
2308
    display: inline;
2309
  }
2310
  .navbar-fixed-top,
2311
  .navbar-static-top {
2312
    margin: 0;
2313
  }
2314
  .navbar-inner {
2315
    padding: 0;
2316
  }
2317
  .checkall,
2318
  .clearall,
2319
  .highlight_controls,
2320
  #selections-toolbar,
2321
  .selectcol,
2322
  .list-actions,
2323
  #remove-selected {
2324
    display: none;
2325
  }
2326
  .table td.bibliocol {
2327
    padding-left: 1.3em;
2328
  }
2329
  .actions {
2330
    display: block;
2331
  }
2332
  .actions a,
2333
  .actions #login4tags {
2334
    background-color: #F2F2EF;
2335
    border: 1px solid #DDD;
2336
    -webkit-border-radius: 4px;
2337
    -moz-border-radius: 4px;
2338
    border-radius: 4px;
2339
    font-weight: bold;
2340
    display: block;
2341
    font-size: 120%;
2342
    margin: 2px 0;
2343
  }
2344
  .actions .label {
2345
    display: block;
2346
    font-weight: bold;
2347
  }
2348
  .actions #login4tags {
2349
    margin-right: 1em;
2350
  }
2351
  #opac-main-search button,
2352
  #opac-main-search input,
2353
  #opac-main-search select,
2354
  #opac-main-search .librarypulldown .transl1,
2355
  #opac-main-search .input-append {
2356
    display: block;
2357
    width: 97%;
2358
    max-width: 100%;
2359
    margin: .5em 0;
2360
    -webkit-border-radius: 5px;
2361
    -moz-border-radius: 5px;
2362
    border-radius: 5px;
2363
  }
2364
  #opac-main-search .input-append {
2365
    margin: 0;
2366
    width: 100%;
2367
  }
2368
  #opac-main-search .librarypulldown .transl1 {
2369
    width: 94.5%;
2370
  }
2371
  #toolbar .resort {
2372
    font-size: 14px;
2373
    max-width: 100%;
2374
    margin: .5em 0;
2375
    padding: 4px 6px;
2376
    -webkit-border-radius: 5px;
2377
    -moz-border-radius: 5px;
2378
    border-radius: 5px;
2379
  }
2380
  .mastheadsearch {
2381
    margin: 0;
2382
    -webkit-border-radius: 0px;
2383
    -moz-border-radius: 0px;
2384
    border-radius: 0px;
2385
  }
2386
  .main {
2387
    margin: .5em 0;
2388
    padding: 15px;
2389
    -webkit-border-radius: 0px;
2390
    -moz-border-radius: 0px;
2391
    border-radius: 0px;
2392
  }
2393
  .breadcrumb {
2394
    margin: 10px 0;
2395
  }
2396
  #moresearches {
2397
    text-align: center;
2398
  }
2399
  #searchsubmit {
2400
    font-weight: bold;
2401
  }
2402
  .ui-tabs-panel .item-thumbnail,
2403
  .tabs-container .item-thumbnail,
2404
  #topissues .item-thumbnail,
2405
  #usertags .item-thumbnail,
2406
  #usersuggestions .item-thumbnail {
2407
    margin: .5em 0 0 .5em;
2408
  }
2409
  .ui-tabs-panel .table-bordered,
2410
  .tabs-container .table-bordered,
2411
  #topissues .table-bordered,
2412
  #usertags .table-bordered,
2413
  #usersuggestions .table-bordered {
2414
    border: none;
2415
  }
2416
  .ui-tabs-panel .table th,
2417
  .tabs-container .table th,
2418
  #topissues .table th,
2419
  #usertags .table th,
2420
  #usersuggestions .table th,
2421
  .ui-tabs-panel .table thead,
2422
  .tabs-container .table thead,
2423
  #topissues .table thead,
2424
  #usertags .table thead,
2425
  #usersuggestions .table thead {
2426
    display: none;
2427
  }
2428
  .ui-tabs-panel .table td,
2429
  .tabs-container .table td,
2430
  #topissues .table td,
2431
  #usertags .table td,
2432
  #usersuggestions .table td {
2433
    border-right: 1px solid #dddddd;
2434
    border-left: 1px solid #dddddd;
2435
    border-top: 0;
2436
    display: block;
2437
    padding: .2em;
2438
  }
2439
  .ui-tabs-panel .table p,
2440
  .tabs-container .table p,
2441
  #topissues .table p,
2442
  #usertags .table p,
2443
  #usersuggestions .table p {
2444
    margin-bottom: 2px;
2445
  }
2446
  .ui-tabs-panel tr,
2447
  .tabs-container tr,
2448
  #topissues tr,
2449
  #usertags tr,
2450
  #usersuggestions tr {
2451
    display: block;
2452
    margin-bottom: .6em;
2453
  }
2454
  .ui-tabs-panel tr td:first-child,
2455
  .tabs-container tr td:first-child,
2456
  #topissues tr td:first-child,
2457
  #usertags tr td:first-child,
2458
  #usersuggestions tr td:first-child {
2459
    border-top: 1px solid #dddddd;
2460
    border-radius: 5px 5px 0 0;
2461
  }
2462
  .ui-tabs-panel tr td:last-child,
2463
  .tabs-container tr td:last-child,
2464
  #topissues tr td:last-child,
2465
  #usertags tr td:last-child,
2466
  #usersuggestions tr td:last-child {
2467
    border-radius: 0 0 5px 5px;
2468
    border-bottom: 2px solid #CACACA;
2469
  }
2470
  .no-image {
2471
    display: none;
2472
  }
2473
}
2474
@media only screen and (max-width: 700px) {
2475
  /* Screens below 700 pixels wide */
2476
  #opac-main-search label {
2477
    display: none;
2478
  }
2479
  #logo {
2480
    background: transparent url("../lib/bootstrap/img/glyphicons-halflings-white.png") no-repeat;
2481
    background-position: 0 -24px;
2482
    margin: 14px 14px 0 14px;
2483
    width: 14px;
2484
  }
2485
  #logo a {
2486
    padding: 14px 0 0;
2487
    width: 14px;
2488
  }
2489
  #user-menu-trigger {
2490
    display: inline;
2491
    margin-right: 12px;
2492
  }
2493
  #members {
2494
    display: none;
2495
    clear: both;
2496
  }
2497
  #members li {
2498
    padding-right: 20px;
2499
    text-align: right;
2500
    border-bottom: 1px solid #555;
2501
  }
2502
  #members li:first-child {
2503
    border-top: 1px solid #555;
2504
  }
2505
  #members li:last-child {
2506
    border-bottom: none;
2507
  }
2508
  #members .nav {
2509
    float: none;
2510
  }
2511
  #members .nav.pull-right {
2512
    float: none;
2513
  }
2514
  #members .nav > li {
2515
    float: none;
2516
  }
2517
  #members .divider-vertical {
2518
    border: 0;
2519
    height: 0;
2520
    margin: 0;
2521
  }
2522
}
2523
@media only screen and (min-width: 480px) and (max-width: 608px) {
2524
  /* Screens between 480 and 608 pixels wide */
2525
  #oh:after {
2526
    content: " Between 480 pixels and 608 pixels. ";
2527
  }
2528
  .input-fluid {
2529
    width: 75%;
2530
  }
2531
}
2532
@media only screen and (min-width: 608px) and (max-width: 767px) {
2533
  /* Screens between 608 and 767 pixels wide */
2534
  #oh:after {
2535
    content: " Between 608 pixels and 767 pixels. ";
2536
  }
2537
  .main {
2538
    padding: 0.8em 20px;
2539
  }
2540
  .breadcrumb {
2541
    margin: 10px 0;
2542
  }
2543
  .navbar-static-bottom {
2544
    margin-left: -20px;
2545
    margin-right: -20px;
2546
  }
2547
}
2548
@media only screen and (max-width: 767px) {
2549
  /* Screens below 767 pixels wide */
2550
  a.title {
2551
    font-size: 120%;
2552
  }
2553
  #userresults {
2554
    margin: 0 -20px;
2555
  }
2556
  .breadcrumb,
2557
  #top-pages,
2558
  .menu-collapse {
2559
    display: none;
2560
  }
2561
  #search-facets,
2562
  #menu {
2563
    margin-bottom: .5em;
2564
  }
2565
  #search-facets h4,
2566
  #menu h4 {
2567
    display: block;
2568
    margin: 0;
2569
    padding: 0;
2570
  }
2571
  #search-facets h4 a,
2572
  #menu h4 a {
2573
    -webkit-border-radius: 7px;
2574
    -moz-border-radius: 7px;
2575
    border-radius: 7px;
2576
    border-bottom: 0;
2577
    font-weight: normal;
2578
    padding: .7em .2em;
2579
  }
2580
  #search-facets ul,
2581
  #menu ul {
2582
    padding: 0;
2583
  }
2584
  #menu li a {
2585
    -webkit-border-radius: 0px;
2586
    -moz-border-radius: 0px;
2587
    border-radius: 0px;
2588
    border: 0;
2589
    display: block;
2590
    font-size: 120%;
2591
    text-decoration: none;
2592
    border-bottom: 1px solid #D8D8D8;
2593
    margin: 0;
2594
  }
2595
  #menu li.active a {
2596
    border-top: 1px solid #D8D8D8;
2597
    border-right-width: 1px;
2598
  }
2599
  #menu li:last-child a {
2600
    -webkit-border-radius: 0 0 7px 7px;
2601
    -moz-border-radius: 0 0 7px 7px;
2602
    border-radius: 0 0 7px 7px;
2603
  }
2604
  #search-facets li {
2605
    padding: .4em;
2606
  }
2607
  #search-facets h5 {
2608
    margin: .2em;
2609
  }
2610
  #menu h4 a.menu-open,
2611
  #search-facets h4 a.menu-open {
2612
    -webkit-border-radius: 7px 7px 0 0;
2613
    -moz-border-radius: 7px 7px 0 0;
2614
    border-radius: 7px 7px 0 0;
2615
    border-bottom: 1px solid #D8D8D8;
2616
  }
2617
}
2618
@media only screen and (max-width: 800px) {
2619
  /* Screens below 800 pixels wide */
2620
  .cartlabel,
2621
  .listslabel {
2622
    display: none;
2623
  }
2624
  .navbar .divider-vertical {
2625
    margin: 0 2px;
2626
  }
2627
  .navbar #members .divider-vertical {
2628
    margin: 0 9px;
2629
  }
2630
}
2631
@media only screen and (min-width: 768px) {
2632
  /* Screens above 768 pixels wide */
2633
  .main {
2634
    margin-left: 20px;
2635
    margin-right: 20px;
2636
  }
2637
  #menu {
2638
    border: 0;
2639
    -webkit-border-radius: 0px;
2640
    -moz-border-radius: 0px;
2641
    border-radius: 0px;
2642
    border-right: 1px solid #D8D8D8;
2643
  }
2644
  #menu h4 {
2645
    display: none;
2646
  }
2647
  #menu ul {
2648
    padding: 1em 0 1em 0;
2649
  }
2650
}
2651
@media only screen and (min-width: 768px) and (max-width: 984px) {
2652
  /* Screens between 768 and 984 pixels wide */
2653
  #oh:after {
2654
    content: " Between 768 and 984 pixels. ";
2655
  }
2656
  .librarypulldown .transl1 {
2657
    width: 38%;
2658
  }
2659
}
2660
@media only screen and (max-width: 984px) {
2661
  /* Screens up to 984 pixels wide */
2662
}
2663
@media only screen and (min-width: 984px) {
2664
  /* Screens above 969 pixels wide */
2665
  #oh:after {
2666
    content: " Above 984 pixels. ";
2667
  }
2668
  .librarypulldown .transl1 {
2669
    width: 53%;
2670
  }
2671
}
2672
@media only screen and (max-width: 1040px) {
2673
  .pg_menu li a {
2674
    float: none;
2675
    text-align: left;
2676
  }
2677
  .pg_menu li.back_results a {
2678
    border: 1px solid #D0D0D0;
2679
    border-width: 1px 0 1px 0;
2680
  }
2681
  #ulactioncontainer {
2682
    min-width: 0;
2683
  }
2684
}
(-)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 2194-2200 td img { Link Here
2194
}
2194
}
2195
2195
2196
2196
2197
#overdrive-results {
2197
#overdrive-results, #pazpar2-results {
2198
    font-weight: bold;
2198
    font-weight: bold;
2199
    padding-left: 1em;
2199
    padding-left: 1em;
2200
}
2200
}
(-)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 879-888 $template->{VARS}->{IDreamBooksReviews} = C4::Context->preference('IDreamBooksRe Link Here
879
$template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
882
$template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
880
$template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
883
$template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
881
884
882
if ($offset == 0 && IsOverDriveEnabled()) {
885
$template->{VARS}->{OPACSearchExternalTargets} = C4::Context->preference('OPACSearchExternalTargets');
883
    $template->param(OverDriveEnabled => 1);
886
$template->{VARS}->{external_search_targets} = GetExternalSearchTargets( C4::Context->userenv ? C4::Context->userenv->{branch} : '' );
884
    $template->param(OverDriveLibraryID => C4::Context->preference('OverDriveLibraryID'));
887
885
}
888
$template->{VARS}->{OverDriveLibraryID} = C4::Context->preference('OverDriveLibraryID');
889
$template->{VARS}->{OverDriveEnabled} = ($offset == 0 && IsOverDriveEnabled());
886
890
887
    $template->param( borrowernumber    => $borrowernumber);
891
    $template->param( borrowernumber    => $borrowernumber);
888
output_with_http_headers $cgi, $cookie, $template->output, $content_type;
892
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