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

(-)a/Koha/Signs.pm (+330 lines)
Line 0 Link Here
1
package Koha::Signs;
2
3
use C4::Context;
4
use C4::Biblio;
5
use C4::Koha;
6
use C4::Items;
7
use Modern::Perl;
8
9
use base qw( Exporter );
10
11
# set the version for version checking
12
our @EXPORT = qw(
13
14
    AddSignStream
15
    ModSignStream
16
    GetSignStream
17
    GetSignStreams
18
    DelSignStream
19
20
    GetSignStreamRecords
21
22
    AddSign
23
    ModSign
24
    GetSign
25
    GetSigns
26
    DelSign
27
28
    AttachSignStreamToSign
29
    DetachSignStreamFromSign
30
    GetSignStreamsAttachedToSign
31
    GetSignStreamsAttachedToSignWithRecords
32
33
    ModSignStreamParams
34
    GetSignStreamParams
35
);
36
37
my $dbh = C4::Context->dbh;
38
39
# Streams
40
41
# Returns id of new sign_stream
42
sub AddSignStream {
43
44
    my ( $name, $report ) = @_;
45
46
    my $sth=$dbh->prepare("INSERT INTO sign_streams SET name = ?, saved_sql_id = ?");
47
    $sth->execute( $name, $report );
48
    return $dbh->last_insert_id( undef, undef, 'sign_streams', 'sign_stream_id' );
49
50
}
51
52
sub ModSignStream {
53
54
    my ( $name, $report, $sign_stream_id ) = @_;
55
56
    my $sth = $dbh->prepare("UPDATE sign_streams SET name = ?, saved_sql_id = ? WHERE sign_stream_id = ?");
57
    return $sth->execute( $name, $report, $sign_stream_id );
58
59
}
60
61
sub GetSignStream {
62
63
    my ( $sign_id ) = @_;
64
65
    return unless $sign_id;
66
67
    my $query = "SELECT s.*, sq.report_name, sq.savedsql
68
                 FROM sign_streams AS s, saved_sql AS sq
69
                 WHERE s.saved_sql_id = sq.id
70
                   AND s.sign_stream_id = ?";
71
    my $sth = $dbh->prepare($query);
72
    $sth->execute($sign_id);
73
    return $sth->fetchrow_hashref();
74
75
}
76
77
sub GetSignStreams {
78
79
    my $query = "SELECT s.*, sq.report_name, sq.savedsql
80
                 FROM sign_streams AS s, saved_sql AS sq
81
                 WHERE s.saved_sql_id = sq.id
82
                 ORDER BY s.name";
83
    my $sth = $dbh->prepare($query);
84
    $sth->execute();
85
    return $sth->fetchall_arrayref({});
86
87
}
88
89
sub DelSignStream {
90
91
    my ( $sign_stream_id ) = @_;
92
93
    return unless $sign_stream_id;
94
95
    my $sth = $dbh->prepare('DELETE FROM sign_streams WHERE sign_stream_id = ?');
96
    return $sth->execute($sign_stream_id);
97
98
}
99
100
sub GetSignStreamRecords {
101
    my ( $stream, $sign_to_stream_id) = @_;
102
    my $sql = $stream->{'savedsql'};
103
104
    if ( defined $sign_to_stream_id ) {
105
        my $params = GetSignStreamParams( $sign_to_stream_id );
106
        $sql = ReplaceParamsInSQL( $sql, $params );
107
        return undef if ( $sql =~ m/<</ );
108
    }
109
110
    return {result => RunSQL( $sql ), sql => $sql };
111
}
112
113
# Signs
114
115
# Returns id of new sign
116
sub AddSign {
117
118
    my ( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter ) = @_;
119
120
    my $sth=$dbh->prepare("INSERT INTO signs SET name = ?, webapp = ?, swatch = ?, transition = ?, idleafter = ?, pagedelay = ?, reloadafter = ?");
121
    $sth->execute( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter );
122
    return $dbh->last_insert_id( undef, undef, 'signs', 'sign_id' );
123
124
}
125
126
sub ModSign {
127
128
    my ( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter, $sign_id ) = @_;
129
130
    my $sth = $dbh->prepare("UPDATE signs SET name = ?, webapp = ?, swatch = ?, transition = ?, idleafter = ?, pagedelay = ?, reloadafter = ? WHERE sign_id = ?");
131
    return $sth->execute( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter, $sign_id );
132
133
}
134
135
sub GetSign {
136
137
    my ( $sign_id ) = @_;
138
139
    return unless $sign_id;
140
141
    my $query = "SELECT *
142
                 FROM signs
143
                 WHERE sign_id = ?";
144
    my $sth = $dbh->prepare($query);
145
    $sth->execute($sign_id);
146
    return $sth->fetchrow_hashref();
147
148
}
149
150
sub GetSigns {
151
152
    my $query = "SELECT *
153
                 FROM signs
154
                 ORDER BY name";
155
    my $sth = $dbh->prepare($query);
156
    $sth->execute();
157
    return $sth->fetchall_arrayref({});
158
159
}
160
161
sub DelSign {
162
163
    my ( $sign_id ) = @_;
164
165
    return unless $sign_id;
166
167
    my $sth = $dbh->prepare('DELETE FROM signs WHERE sign_id = ?');
168
    return $sth->execute($sign_id);
169
170
}
171
172
# Streams attached to signs
173
174
# Returns the ID of the connection between sign and stream
175
sub AttachSignStreamToSign {
176
177
    my ( $sign_stream_id, $sign_id ) = @_;
178
179
    return unless $sign_stream_id || $sign_id;
180
181
    my $sth = $dbh->prepare( 'INSERT INTO signs_to_streams SET sign_stream_id = ?, sign_id = ?' );
182
    $sth->execute( $sign_stream_id, $sign_id );
183
    return $dbh->last_insert_id( undef, undef, 'signs_to_streams', 'sign_to_stream_id' );
184
185
}
186
187
sub ModSignStreamParams {
188
189
    my ( $sign_to_stream_id, $params ) = @_;
190
    return unless $sign_to_stream_id;
191
    my $sth = $dbh->prepare( 'UPDATE signs_to_streams SET params = ? WHERE sign_to_stream_id = ?' );
192
    return $sth->execute( $params, $sign_to_stream_id );
193
194
}
195
196
# Returns the string of params for a given stream-attached-to-sign
197
sub GetSignStreamParams {
198
199
    my ( $sign_to_stream_id ) = @_;
200
201
    return unless $sign_to_stream_id;
202
203
    my $query = 'SELECT params FROM signs_to_streams WHERE sign_to_stream_id = ?';
204
    my $sth = $dbh->prepare( $query );
205
    $sth->execute( $sign_to_stream_id );
206
    return $sth->fetchrow_array();
207
208
}
209
210
sub ReplaceParamsInSQL {
211
212
    my ( $sql, $params ) = @_;
213
214
    return unless $sql || $params;
215
    return $sql unless $sql =~ m/<</;
216
217
    foreach my $param ( split /&/, $params ) {
218
        my ( $key, $value ) = split /=/, $param;
219
        # FIXME Handle spaces
220
        $sql =~ s/<<$key>>/$value/g;
221
    }
222
    return $sql;
223
224
}
225
226
sub GetSignStreamsAttachedToSign {
227
228
    my ( $sign_id ) = @_;
229
230
    return unless $sign_id;
231
232
    my $query = 'SELECT s.*, sts.sign_to_stream_id, sts.params, sq.report_name, sq.savedsql
233
                 FROM sign_streams AS s, signs_to_streams AS sts, saved_sql AS sq
234
                 WHERE s.sign_stream_id = sts.sign_stream_id
235
                   AND s.saved_sql_id = sq.id
236
                   AND sts.sign_id = ?
237
                 ORDER BY s.name';
238
    my $sth = $dbh->prepare( $query );
239
    $sth->execute( $sign_id );
240
    return $sth->fetchall_arrayref({});
241
242
}
243
244
sub GetSignStreamsAttachedToSignWithRecords {
245
246
    my ( $sign_id, $include_marc ) = @_;
247
248
    return unless $sign_id;
249
250
    my $streams = GetSignStreamsAttachedToSign( $sign_id );
251
    my @changedstreams;
252
    my %record_cache = ();
253
254
    # Add records to the streams
255
    foreach my $stream ( @{$streams} ) {
256
257
        my $records = RunSQL( ReplaceParamsInSQL( $stream->{'savedsql'}, $stream->{'params'} ) );
258
259
        if ( $include_marc ) {
260
261
            my @processed_records;
262
            foreach my $rec ( @{$records} ) {
263
                unless(defined $record_cache{$rec->{'biblionumber'}}) {
264
                    my $marc = GetMarcBiblio( $rec->{'biblionumber'} );
265
                    if ( ! $marc ) {
266
                        next;
267
                    }
268
269
                    my $isbn = GetNormalizedISBN( undef, $marc, C4::Context->preference("marcflavor") ) || '';
270
                    $rec->{'isbn'} = $isbn;
271
272
                    my $dat = GetBiblioData($rec->{'biblionumber'});
273
                    my @items = GetItemsInfo($rec->{'biblionumber'});
274
                    foreach my $item ( @items ) {
275
                        my $shelflocations = GetKohaAuthorisedValues('items.location',$dat->{'frameworkcode'}, 'opac');
276
                        if ( defined $item->{'location'} ) {
277
                            $item->{'location_description'} = $shelflocations->{ $item->{'location'} };
278
                        }
279
                    }
280
                    $rec->{'items'} = \@items;
281
                    foreach ( keys %{$dat} ) {
282
                        $rec->{"$_"} = defined $dat->{$_} ? $dat->{$_} : '';
283
                    }
284
285
                    $rec->{'marc'} = $marc;
286
287
                    $record_cache{$rec->{'biblionumber'}} = $rec;
288
                }
289
                push @processed_records, $record_cache{$rec->{'biblionumber'}};
290
            }
291
            $stream->{'records'} = \@processed_records;
292
293
        } else {
294
295
          $stream->{'records'} = $records;
296
297
        }
298
299
        push @changedstreams, $stream;
300
301
    }
302
303
    return \@changedstreams;
304
305
}
306
307
sub DetachSignStreamFromSign {
308
309
    my ( $sign_to_stream_id ) = @_;
310
311
    return unless $sign_to_stream_id;
312
313
    my $sth = $dbh->prepare( 'DELETE FROM signs_to_streams WHERE sign_to_stream_id = ?' );
314
    return $sth->execute( $sign_to_stream_id );
315
316
}
317
318
sub RunSQL {
319
320
    my ( $query ) = @_;
321
322
    return unless $query;
323
324
    my $sth = $dbh->prepare($query);
325
    $sth->execute();
326
    return $sth->fetchall_arrayref({});
327
328
}
329
330
1;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref (-1 / +20 lines)
Lines 710-716 OPAC: Link Here
710
                  yes: Use
710
                  yes: Use
711
                  no: "Don't use"
711
                  no: "Don't use"
712
            - "the item collection code when finding items for the shelf browser."      
712
            - "the item collection code when finding items for the shelf browser."      
713
714
    Self Registration:
713
    Self Registration:
715
        -
714
        -
716
            - pref: PatronSelfRegistration
715
            - pref: PatronSelfRegistration
Lines 772-777 OPAC: Link Here
772
                  no: "Do not display and prefill"
771
                  no: "Do not display and prefill"
773
            - "password and login form after a patron has self registered."
772
            - "password and login form after a patron has self registered."
774
773
774
    Digital Signs:
775
        -
776
            - pref: OPACDigitalSigns
777
              default: 0
778
              choices:
779
                  yes: Enable
780
                  no: Disable
781
            - "digital signs in the OPAC. Please note: Digital signs are not linked to from the OPAC by default, so you will have to load the relevant URL by hand on displays where you want to use them."
782
        -
783
            - "Include the following CSS in all digital signs:"
784
            - pref: OPACDigitalSignsCSS
785
              type: textarea
786
              class: code
787
            - (If you use this option to create custom swatches (e.g. with the <a href="http://jquerymobile.com/themeroller/">ThemeRoller for jQuery Mobile</a>) you might have to adjust the list of letters identifying available themes (swatches) in the OPACDigitalSignsSwatches preference.)
788
        -
789
            - Make it possible to choose one of the themes (swatches)
790
            - pref: OPACDigitalSignsSwatches
791
              class: long
792
            - when creating a new sign. By default the themes a-e are provided, but you can override these by creating your own themes and entering them into the OPACDigitalSignsCSS system preference. If you do add your own custom themes there you will want to adjust the letters in this system preference to match the themes you created.
793
775
    Advanced Search Options:
794
    Advanced Search Options:
776
        -
795
        -
777
            - Show search options
796
            - Show search options
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/signs.tt (+479 lines)
Line 0 Link Here
1
[% USE Koha %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Koha &rsaquo; Tools &rsaquo; Digital signs</title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
6
[% INCLUDE 'datatables.inc' %]
7
<script type="text/javascript">
8
//<![CDATA[
9
10
	// prepare DOM for YUI Toolbar
11
	 $(document).ready(function() {
12
        $("#table_signs").dataTable($.extend(true, {}, dataTablesDefaults, {
13
            "aoColumns": [
14
                null,
15
                {"bSearchable": false},
16
                {"bSearchable": false},
17
                {"bSearchable": false},
18
                {"bSearchable": false},
19
                {"bSearchable": false},
20
                {"bSearchable": false},
21
                {"bSearchable": false, "bSortable": false},
22
                {"bSearchable": false, "bSortable": false},
23
                {"bSearchable": false, "bSortable": false},
24
                {"bSearchable": false, "bSortable": false}
25
            ],
26
            "sPaginationType": "four_button"
27
        } ));
28
        $("#table_streams").dataTable($.extend(true, {}, dataTablesDefaults, {
29
            "aoColumns": [
30
                null,
31
                {"bSearchable": false},
32
                {"bSearchable": false, "bSortable": false},
33
                {"bSearchable": false, "bSortable": false},
34
            ],
35
            "sPaginationType": "four_button"
36
        } ));
37
	 });
38
//]]>
39
</script>
40
</head>
41
<body id="tools_signs" class="tools">
42
[% INCLUDE 'header.inc' %]
43
[% INCLUDE 'cat-search.inc' %]
44
45
[% BLOCK dslink %]<a href="/cgi-bin/koha/tools/signs.pl">Digital signs</a> &rsaquo;[% END %]
46
<div id="breadcrumbs">
47
  <a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo;
48
  <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo;
49
  [% IF op == 'stream_form' %]
50
    [% IF ( stream.sign_stream_id ) %]
51
      [% INCLUDE dslink %] Edit "[% stream.name %]"
52
    [% ELSE %]
53
      [% INCLUDE dslink %] Add a new stream
54
    [% END %]
55
  [% ELSIF op == 'sign_form' %]
56
    [% IF ( sign.sign_id ) %]
57
      [% INCLUDE dslink %] Edit "[% sign.name %]"
58
    [% ELSE %]
59
      [% INCLUDE dslink %] Add a new sign
60
    [% END %]
61
  [% ELSIF op == 'edit_streams' %]
62
    [% INCLUDE dslink %] Edit streams attached to "[% sign.name %]"
63
  [% ELSIF op == 'get_params' %]
64
    [% INCLUDE dslink %] Get parameters
65
  [% ELSIF op == 'del_stream' %]
66
    [% INCLUDE dslink %] Delete stream "[% stream.name %]"
67
  [% ELSIF op == 'del_stream_ok' %]
68
    [% INCLUDE dslink %] Stream deleted
69
  [% ELSIF op == 'del_sign' %]
70
    [% INCLUDE dslink %] Delete sign "[% sign.name %]"
71
  [% ELSIF op == 'del_sign_ok' %]
72
    [% INCLUDE dslink %] Sign deleted
73
  [% ELSIF op == 'view_sign' %]
74
    [% INCLUDE dslink %] View sign
75
  [% ELSIF op == 'view_stream' %]
76
    [% INCLUDE dslink %] View stream
77
  [% ELSE %]
78
    Digital signs
79
  [% END %]
80
</div>
81
82
<div id="doc3" class="yui-t2">
83
84
   <div id="bd">
85
	<div id="yui-main">
86
	<div class="yui-b">
87
88
[% UNLESS Koha.Preference( 'OPACDigitalSigns' ) %]
89
<div class="dialog alert">
90
    <p>
91
    Digital signs are not enabled. Please enable
92
    <a href="/cgi-bin/koha/admin/preferences.pl?tab=&op=search&searchfield=OPACDigitalSigns">OPACDigitalSigns</a>
93
    for OPAC digital signs to work.
94
    </p>
95
</div>
96
[% END %]
97
98
[% IF ( else ) %]
99
  <div id="toolbar">
100
    <ul class="toolbar">
101
      <li><a id="newsign" href="?op=add_sign" class="btn btn-small"><i class="icon-plus"></i>New sign</a></li>
102
      <li><a id="newstream" href="?op=add_stream" class="btn btn-small"><i class="icon-plus"></i>New stream</a></li>
103
    </ul>
104
  </div>
105
[% END %]
106
107
[% IF op == 'stream_form' %]
108
  [% UNLESS ( reports ) %]
109
  <div class="dialog alert">
110
    <h3>No reports found</h3>
111
    <p>No reports with group code "SIG" were found. Please <a
112
    href="/cgi-bin/koha/reports/guided_reports.pl?phase=Create+report+from+SQL&submit=Create+report+from+SQL">create
113
    a new report</a> with group code "SIG" and try again.</p>
114
  </div>
115
  [% END %]
116
117
  [% IF ( stream.sign_stream_id ) %]
118
  <h1>Edit stream</h1>
119
  [% ELSE %]
120
  <h1>Add stream</h1>
121
  [% END %]
122
  <form action="[% script_name %]" name="streamform" id="streamform" method="post">
123
  <input type="hidden" name="op" value="save_stream" />
124
  [% IF ( stream.sign_stream_id ) %]
125
  <input type="hidden" name="sign_stream_id" value="[% stream.sign_stream_id %]" />
126
  [% END %]
127
  <fieldset class="rows">
128
    <ol>
129
    <li><label for="name">Name</label><input type="text" name="name" value="[% stream.name %]" /></li>
130
    <li><label for="report">Report</label>
131
      <select name="report" id="report">
132
        [% UNLESS ( stream.sign_stream_id ) %]
133
        <option value="">Choose report</option>
134
        [% END %]
135
        [% FOREACH report IN reports %]
136
          [% IF ( report.id == stream.saved_sql_id ) %]
137
            <option value="[% report.id %]" selected="selected">[% report.report_name %]</option>
138
          [% ELSE %]
139
            <option value="[% report.id %]">[% report.report_name %]</option>
140
          [% END %]
141
        [% END %]
142
      </select>
143
    </li>
144
    </ol>
145
  </fieldset>
146
  <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset>
147
  </form>
148
149
[% ELSIF op == 'sign_form' %]
150
151
  [% IF ( sign.sign_id ) %]
152
  <h1>Edit sign</h1>
153
  [% ELSE %]
154
  <h1>Add sign</h1>
155
  [% END %]
156
  <form action="[% script_name %]" name="signform" id="signform" method="post">
157
  <input type="hidden" name="op" value="save_sign" />
158
  [% IF ( sign.sign_id ) %]
159
  <input type="hidden" name="sign_id" value="[% sign.sign_id %]" />
160
  [% END %]
161
  <fieldset id="sign_general_info" class="rows">
162
    <legend id="general_info_lgd">General settings</legend>
163
    <ol>
164
    <li><label for="name">Name</label><input type="text" name="name" value="[% sign.name %]" /></li>
165
    </ol>
166
  </fieldset>
167
  <fieldset id="sign_appearance" class="rows">
168
    <legend id="appearance_lgd">Appearance</legend>
169
    <ol>
170
    <li><label for="webapp">Web-app</label>
171
      <select name="webapp" id="webapp">
172
        <option value="0">Display as a normal page</option>
173
        [% IF ( sign.webapp ) %]
174
        <option value="1" selected="selected">Display as a Web-app</option>
175
        [% ELSE %]
176
        <option value="1">Display as a Web-app</option>
177
        [% END %]
178
      </select>
179
    </li>
180
    <li><label for="swatch">Theme (swatch)</label>
181
      <select name="swatch" id="swatch">
182
        <option value="">Default</option>
183
        [% FOREACH swatch IN Koha.Preference('OPACDigitalSignsSwatches').split('') %]
184
          [% IF swatch == sign.swatch %]
185
            <option value="[% swatch %]" selected="selected">[% swatch %]</option>
186
          [% ELSE %]
187
            <option value="[% swatch %]">[% swatch %]</option>
188
          [% END %]
189
        [% END %]
190
      </select>
191
    </li>
192
    <li><label for="transition">Transition</label>
193
      <select name="transition" id="transition">
194
        [% FOREACH transition IN [ 'none' 'fade' 'pop' 'flip' 'turn' 'flow' 'slidefade' 'slide' 'slideup' 'slidedown' ] %]
195
          [% IF transition == sign.transition %]
196
            <option value="[% transition %]" selected="selected">[% transition %]</option>
197
          [% ELSE %]
198
            <option value="[% transition %]">[% transition %]</option>
199
          [% END %]
200
        [% END %]
201
      </select>
202
    </li>
203
    </ol>
204
  </fieldset>
205
  <fieldset id="sign_autopage" class="rows">
206
    <legend id="autopage_lgd">Automatic page turning</legend>
207
    <ol>
208
    <li><label for="idleafter">Idle after</label>
209
      <input type="text" name="idleafter" id="idleafter" value="[% sign.idleafter %]" size="4" /> seconds. (Set to 0 to disable automatic page turning.)
210
    </li>
211
    <li><label for="pagedelay">Page delay</label>
212
      <input type="text" name="pagedelay" id="pagedelay" value="[% sign.pagedelay %]" size="4" /> seconds.
213
    </li>
214
    <li><label for="reloadafter">Reload after</label>
215
      <input type="text" name="reloadafter" id="reloadafter" value="[% sign.reloadafter %]" size="4" /> seconds.
216
    </li>
217
    </ol>
218
  </fieldset>
219
  <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset>
220
  </form>
221
222
[% ELSIF op == 'edit_streams' %]
223
224
  <h1>Edit streams attached to [% sign.name %]</h1>
225
  <h2>Streams already attached to this sign</h2>
226
  [% IF ( attached.size ) %]
227
    <table>
228
    <thead>
229
    <tr><th>Name</th><th>Parameters</th><th>Edit parameters</th><th>Detach</th></tr>
230
    </thead>
231
    <tbody>
232
    [% FOREACH s IN attached %]
233
      <tr>
234
      <td>[% s.name %]</td>
235
      <td>[% s.params %]</td>
236
      <td>[% IF s.savedsql.match('<<') %]<a href="?op=get_params&sign_to_stream_id=[% s.sign_to_stream_id %]&sign_stream_id=[% s.sign_stream_id %]&sign_id=[% sign.sign_id %]">Edit parameters</a>[% ELSE %]No parameters[% END %]</td>
237
      <td><a href="?op=detach_stream_from_sign&sign_id=[% sign.sign_id %]&sign_to_stream_id=[% s.sign_to_stream_id %]">Detach</a></td>
238
      </tr>
239
    [% END %]
240
    </tbody>
241
    </table>
242
  [% ELSE %]
243
    <p>There are no streams attached to this sign, yet.</p>
244
  [% END %]
245
246
  <h2>Attach a new stream to this sign</h2>
247
  <form action="[% script_name %]" name="attach_stream_to_sign_form" id="attach_stream_to_sign_form" method="post">
248
  <input type="hidden" name="op" value="attach_stream_to_sign" />
249
  <input type="hidden" name="sign_id" value="[% sign_id %]" />
250
  <fieldset class="rows">
251
    <ol>
252
    <li><label for="stream">Choose a stream to attach</label>
253
      <select name="sign_stream_id" id="stream">
254
        [% FOREACH s IN streams %]
255
          <option value="[% s.sign_stream_id %]">[% s.name %]</option>
256
        [% END %]
257
      </select>
258
    </li>
259
    </ol>
260
  </fieldset>
261
  <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset>
262
  </form>
263
264
[% ELSIF op == 'get_params' %]
265
266
  <h1>Parameters for [% stream.name %]</h1>
267
  <p>Based on report: [% stream.report_name %] | <a href="/cgi-bin/koha/reports/guided_reports.pl?reports=[% stream.saved_sql_id %]&phase=Edit SQL">Edit this report</a></p>
268
269
  <form action="[% script_name %]" name="get_params_form" id="get_params_form" method="post">
270
  <input type="hidden" name="op" value="save_params" />
271
  <input type="hidden" name="sign_to_stream_id" value="[% sign_to_stream_id %]" />
272
  <input type="hidden" name="sign_stream_id" value="[% sign_stream_id %]" />
273
  <input type="hidden" name="sign_id" value="[% sign_id %]" />
274
  <fieldset class="rows">
275
    [% IF ( params ) %]
276
      <legend id="save_params_lgd">Edit parameters</legend>
277
    [% ELSE %]
278
      <legend id="save_params_lgd">Add parameters</legend>
279
    [% END %]
280
    <ol>
281
    <li><label for="stream">Parameters</label>
282
      <input type="text" size="60" name="parameters" id="parameters" value="[% params %]" />
283
    </li>
284
    </ol>
285
  </fieldset>
286
  <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset>
287
  </form>
288
289
  <h2>Raw SQL</h2>
290
  <pre id="sql_output">[% stream.savedsql | html %]</pre>
291
292
  <h2>SQL with current parameters replaced</h2>
293
  <pre id="sql_output">[% newsql | html %]</pre>
294
  [% IF ( has_params ) %]
295
    <p>Sorry, your SQL still contains placeholders. You need to add more parameters.</p>
296
  [% ELSE %]
297
    <h2>Records</h2>
298
    [% INCLUDE display_records %]
299
  [% END %]
300
301
[% ELSIF op == 'del_stream' %]
302
303
  <div class="dialog alert">
304
    <h3>Confirm deletion of stream <span class="ex">'[% stream.name %]'</span>?</h3>
305
    <form action="[% script_name %]" id ="confirm_stream_delete_form" method="post">
306
    <input type="hidden" name="op" value="del_stream_ok" />
307
    <input type="hidden" name="sign_stream_id" value="[% stream.sign_stream_id %]" />
308
    <input type="submit" class="approve" value="Yes, Delete this stream" /></form>
309
310
    <form action="[% script_name %]" id="cancel_stream_delete_form" method="get">
311
    <input type="submit" value="No, do not delete" class="deny" />
312
    </form>
313
    </div>
314
315
[% ELSIF op == 'del_stream_ok' %]
316
317
  <div class="dialog message">
318
    <h3>Stream deleted</h3>
319
    <form action="[% script_name %]" method="get">
320
    <input type="submit" value="OK" class="approve" />
321
    </form>
322
  </div>
323
324
[% ELSIF op == 'del_sign' %]
325
326
  <div class="dialog alert">
327
    <h3>Confirm deletion of sign <span class="ex">'[% sign.name %]'</span>?</h3>
328
    <form action="[% script_name %]" id ="confirm_sign_delete_form" method="post">
329
    <input type="hidden" name="op" value="del_sign_ok" />
330
    <input type="hidden" name="sign_id" value="[% sign.sign_id %]" />
331
    <input type="submit" class="approve" value="Yes, Delete this sign" /></form>
332
333
    <form action="[% script_name %]" id="cancel_sign_delete_form" method="get">
334
    <input type="submit" value="No, do not delete" class="deny" />
335
    </form>
336
    </div>
337
338
[% ELSIF op == 'del_sign_ok' %]
339
340
  <div class="dialog message">
341
    <h3>Sign deleted</h3>
342
    <form action="[% script_name %]" method="get">
343
    <input type="submit" value="OK" class="approve" />
344
    </form>
345
  </div>
346
347
[% ELSIF op == 'view_sign' %]
348
349
  <h1>[% sign.name %]</h1>
350
  <h2>Streams</h2>
351
352
  [% IF ( streams ) %]
353
    [% FOREACH stream IN streams %]
354
      <h3>[% stream.name %]</h3>
355
      <ul>
356
      [% FOREACH record IN stream.records %]
357
        <li><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% record.biblionumber %]">[% record.title %]</a></li>
358
      [% END %]
359
      </ul>
360
    [% END %]
361
  [% ELSE %]
362
    <p>No streams attached.</p>
363
  [% END%]
364
365
[% ELSIF op == 'view_stream' %]
366
367
  <h1>[% stream.name %]</h1>
368
  <p>Based on report: [% stream.report_name %] | <a href="/cgi-bin/koha/reports/guided_reports.pl?reports=[% stream.saved_sql_id %]&phase=Edit SQL">Edit this report</a></p>
369
  <h2>SQL</h2>
370
  <pre id="sql_output">[% stream.savedsql | html %]</pre>
371
  <h2>Records</h2>
372
  [% IF ( has_params ) %]
373
    <p>Sorry, the report this stream is based on has parameters and displaying it only makes sense after it has been attached to a sign and parameters have been added.</p>
374
  [% ELSE %]
375
    [% INCLUDE display_records %]
376
  [% END %]
377
378
[% ELSE %]
379
380
  <h1>Digital signs</h1>
381
382
  [% IF signs %]
383
    <h2>Signs</h2>
384
    <table id="table_signs">
385
        <thead>
386
            <tr>
387
                <th>Name</th>
388
                <th>Web-app</th>
389
                <th>Theme (swatch)</th>
390
                <th>Transition</th>
391
                <th>Idle after</th>
392
                <th>Page delay</th>
393
                <th>Reload after</th>
394
                <th>Edit</th>
395
                <th>Edit streams</th>
396
                <th>Delete</th>
397
                <th>View sign</th>
398
            </tr>
399
        </thead>
400
        <tbody>
401
        [% FOREACH s IN signs %]
402
            <tr>
403
                <td><a href="?op=view_sign&amp;sign_id=[% s.sign_id %]">[% s.name %]</a></td>
404
                <td>[% IF ( s.webapp ) %]Yes[% ELSE %]No[% END %]</td>
405
                <td>[% s.swatch %]</td>
406
                <td>[% s.transition %]</td>
407
                <td>[% s.idleafter %]</td>
408
                <td>[% s.pagedelay %]</td>
409
                <td>[% s.reloadafter %]</td>
410
                <td><a href="?op=edit_sign&amp;sign_id=[% s.sign_id %]">Edit</a></td>
411
                <td><a href="?op=edit_streams&amp;sign_id=[% s.sign_id %]">Edit streams</a></td>
412
                <td><a href="?op=del_sign&amp;sign_id=[% s.sign_id %]">Delete</a></td>
413
                <td>[% IF ( OPACBaseURL ) %]<a href="http://[% OPACBaseURL %]/cgi-bin/koha/opac-signs.pl?sign=[% s.sign_id %]" title="View this sign in the OPAC">View sign</a>[% END %]</td>
414
            </tr>
415
        [% END %]
416
        </tbody>
417
    </table>
418
    [% UNLESS ( OPACBaseURL ) %]<p>Please note: Links to view signs in the OPAC will only be displayed if you fill in the OPACBaseURL system preference.</p>[% END %]
419
  [% ELSE %]
420
    <p>No signs defined!</p>
421
  [% END %]
422
423
  [% IF streams %]
424
    <h2>Streams</h2>
425
    <table id="table_streams">
426
        <thead>
427
            <tr>
428
                <th>Name</th>
429
                <th>Report</th>
430
                <th>Edit</th>
431
                <th>Delete</th>
432
            </tr>
433
        </thead>
434
        <tbody>
435
        [% FOREACH s IN streams %]
436
            <tr>
437
                <td><a href="?op=view_stream&amp;sign_stream_id=[% s.sign_stream_id %]">[% s.name %]</a></td>
438
                <td title="ID: [% s.saved_sql_id %]">[% s.report_name %]</td>
439
                <td><a href="?op=edit_stream&amp;sign_stream_id=[% s.sign_stream_id %]">Edit</a></td>
440
                <td><a href="?op=del_stream&amp;sign_stream_id=[% s.sign_stream_id %]">Delete</a></td>
441
            </tr>
442
        [% END %]
443
        </tbody>
444
    </table>
445
  [% ELSE %]
446
    <p>No streams defined!</p>
447
  [% END %]
448
449
[% END %]
450
451
452
453
</div>
454
</div>
455
<div class="yui-b">
456
[% INCLUDE 'tools-menu.inc' %]
457
</div>
458
</div>
459
[% INCLUDE 'intranet-bottom.inc' %]
460
461
[% BLOCK display_records %]
462
  [% IF ( records.0 ) %]
463
    <table>
464
    <thead>
465
      <tr>
466
      <th>biblionumber</th>
467
      <th>title</th>
468
      </tr>
469
    </thead>
470
    <tbody>
471
    [% FOREACH r IN records %]
472
      <tr><td>[% r.biblionumber %]</td><td>[% r.title %]</td></tr>
473
    [% END %]
474
    </tbody>
475
    </table>
476
  [% ELSE %]
477
    <p>No records found.</p>
478
  [% END %]
479
[% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (+5 lines)
Lines 104-109 Link Here
104
    <dd>Quote editor for Quote-of-the-day feature in OPAC</dd>
104
    <dd>Quote editor for Quote-of-the-day feature in OPAC</dd>
105
    [% END %]
105
    [% END %]
106
106
107
    [% IF ( CAN_user_tools_edit_digital_signs ) %]
108
    <dt><a href="/cgi-bin/koha/tools/signs.pl">Digital signs</a></dt>
109
    <dd>Create and edit digital signs for the OPAC</dd>
110
    [% END %]
111
107
    [% IF ( UseKohaPlugins && CAN_user_plugins_tool ) %]
112
    [% IF ( UseKohaPlugins && CAN_user_plugins_tool ) %]
108
    <dt><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=tool">Tool plugins</a></dt>
113
    <dt><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=tool">Tool plugins</a></dt>
109
    <dd>Use tool plugins</dd>
114
    <dd>Use tool plugins</dd>
(-)a/koha-tmpl/opac-tmpl/bootstrap/css/signs.css (+102 lines)
Line 0 Link Here
1
.carousel-container {
2
    width: 225px;
3
    height: 225px;
4
    position: relative;
5
    margin: 0 auto 40px;
6
    -webkit-perspective: 1100px;
7
    -moz-perspective: 1100px;
8
    -o-perspective: 1100px;
9
    -ms-perspective: 1100px;
10
    perspective: 1100px;
11
}
12
13
.carousel {
14
    width: 100%;
15
    height: 100%;
16
    position: absolute;
17
    -webkit-transform-style: preserve-3d;
18
    -moz-transform-style: preserve-3d;
19
    -o-transform-style: preserve-3d;
20
    -ms-transform-style: preserve-3d;
21
    transform-style: preserve-3d;
22
}
23
24
.unicorn {
25
    display: block;
26
    position: absolute;
27
    width: 150px;
28
    height: 225px;
29
    left: 10px;
30
    top: 10px;
31
    -webkit-box-reflect: below 0 -webkit-gradient(linear, left bottom, left top, color-stop(0.05, rgba(255, 255, 255, 0.12)), color-stop(0.2, transparent));
32
}
33
34
.ui-li {
35
    padding-top: 0px !important;
36
    padding-bottom: 0px !important;
37
    margin-bottom: -7px !important;
38
}
39
40
.ui-li h4 {
41
    margin-top: 2px !important;
42
    margin-bottom: 2px !important;
43
}
44
45
.ui-li-icon {
46
    top: 15% !important;
47
}
48
49
.vspace {
50
    margin-top: 2em;
51
}
52
53
.content {
54
    text-align: center;
55
}
56
57
.btn-record {
58
    margin: 10px;
59
}
60
61
.cover {
62
    border: none;
63
    display: inline-block;
64
    height: 225px;
65
    width: 150px;
66
    background-size: 100%;
67
    background-repeat: round;
68
}
69
70
.cover.cover-blank {
71
}
72
73
.cover.placeholder {
74
}
75
76
.cover .cover-inner {
77
    display: table-cell;
78
    vertical-align: middle;
79
    padding: 25px;
80
    border: 2px solid #fff;
81
    height: 171px;
82
    max-height: 171px;
83
    width: inherit;
84
}
85
86
.cover-text {
87
    text-align: center;
88
    position: relative;
89
    font-family: Georgia, "Palatino Linotype", "Book Antiqua", Palatino, "Times New Roman", serif;
90
    font-size: 1em;
91
    max-height: inherit;
92
    overflow: hidden;
93
}
94
95
.cover-text .title {
96
    font-weight: bold;
97
}
98
99
.cover-text .author {
100
    font-style: italic;
101
    margin-top: 1em;
102
}
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-signs.tt (+565 lines)
Line 0 Link Here
1
[% USE Koha %]
2
[% USE KohaDates %]
3
[% USE Branches %]
4
[% USE JSON.Escape %]
5
6
[%- BLOCK item_status -%]
7
    [%- SET itemavailable = 1 -%]
8
    [%- IF ( item.itemlost ) -%]
9
        [%- SET itemavailable = 0 -%]
10
        [%-%]Item lost
11
    [%- END -%]
12
    [%- IF ( item.datedue || issue.date_due ) -%]
13
        [%- SET itemavailable = 0 -%]
14
        [%- IF item.onsite_checkout -%]
15
            [%-%]Currently in local use
16
        [%- ELSE -%]
17
            [%-%]Checked out
18
        [%- END -%]
19
    [%- END -%]
20
    [%- IF ( item.transfertwhen ) %]
21
        [%- SET itemavailable = 0 -%]
22
        [%-%]In transit from [%- item.transfertfrom %] to [%- item.transfertto %] since [%- item.transfertwhen | $KohaDates %]
23
    [%- END %]
24
    [%- IF ( item.waiting ) -%]
25
        [%- SET itemavailable = 0 -%]
26
        [%-%]On hold
27
    [%- END -%]
28
    [%- IF ( item.withdrawn ) -%]
29
        [%- SET itemavailable = 0 -%]
30
        [%-%]Item withdrawn
31
    [%- END -%]
32
    [%- IF ( item.itemnotforloan ) -%]
33
        [%- SET itemavailable = 0 -%]
34
        [%- IF ( item.notforloanvalueopac ) -%]
35
            [%- item.notforloanvalueopac -%] [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%]
36
        [%- ELSE -%]
37
            [%-%]Not for loan [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%]
38
        [%- END -%]
39
    [%- ELSIF ( item.notforloan_per_itemtype ) -%]
40
        [%- SET itemavailable = 0 -%]
41
        [%-%]Not for loan [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%]
42
    [%- END -%]
43
    [%- IF ( item.damaged ) -%]
44
        [%- SET itemavailable = 0 -%]
45
        [%-%]Item damaged
46
    [%- END -%]
47
    [%- IF item.on_order -%]
48
        [%- SET itemavailable = 0 -%]
49
        [%-%]On order
50
    [%- END -%]
51
    [%- IF ( itemavailable ) -%]
52
        [%-%]Available [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%]
53
    [%- END -%]
54
[%- END -%]
55
56
[% INCLUDE 'doc-head-open.inc' %]
57
<title>[% IF ( sign )  %][% sign.name %] - Koha[% ELSE %]Koha digital signs[% END %]</title>
58
[%- IF ( sign.webapp ) %]
59
    <meta name="apple-mobile-web-app-capable" content="yes" />
60
    <meta name="viewport" content="width=device-width, initial-scale=1">
61
[% END -%]
62
[% BLOCK cssinclude %]
63
    [%- IF Koha.Preference( 'OPACDigitalSignsCSS' ) != '' -%]
64
      <style type="text/css">
65
        [% Koha.Preference( 'OPACDigitalSignsCSS' ) %]
66
      </style>
67
      <link rel="stylesheet" href="/opac-tmpl/lib/jquery/mobile/jquery.mobile.structure.min.css" />
68
    [%- ELSE -%]
69
      <link rel="stylesheet" href="/opac-tmpl/bootstrap/css/signs.css" />
70
      <link rel="stylesheet" href="/opac-tmpl/lib/jquery/mobile/jquery.mobile.min.css" />
71
    [%- END -%]
72
[% END # BLOCK cssinclude %]
73
[% INCLUDE 'doc-head-close.inc' %]
74
</head>
75
[% INCLUDE 'bodytag.inc' bodyid='opac-signs' %]
76
77
[%- UNLESS Koha.Preference( 'OPACDigitalSigns' ) -%]
78
  <p>Digital signs are not enabled!</p>
79
[%- ELSE -%]
80
  [%# Display a sign, all its streams and all records  %]
81
  [%- IF ( sign )  -%]
82
    [%- IF ( streams.0 )  -%]
83
      [%# Iterate through the streams, creating one front page for each %]
84
      [%- FOREACH s IN streams -%]
85
          <div data-role="page" class="page-stream" data-stream-id="[% s.sign_stream_id %]" data-theme="[% sign.swatch %]" id="stream_[% s.sign_stream_id %]">
86
              <div data-role="header" data-theme="[% sign.swatch %]" data-position="fixed">
87
                  <div style="text-align: center;">
88
                      [%# The header has a list of buttons for all the streams %]
89
                      [%- SET localstreams = streams -%]
90
                      [%- FOREACH stream IN localstreams -%]
91
                          [% IF s.sign_stream_id == stream.sign_stream_id %]
92
                              <a href="#stream_[% stream.sign_stream_id %]" data-stream-id="[% stream.sign_stream_id %]" class="btn-stream stream-active" data-inline="true" data-icon="star" data-role="button">[% stream.name %]</a>
93
                          [% ELSE %]
94
                              <a href="#stream_[% stream.sign_stream_id %]" data-stream-id="[% stream.sign_stream_id %]" class="btn-stream" data-inline="true" data-role="button">[% stream.name %]</a>
95
                          [% END %]
96
                      [% END -%]
97
                  </div>
98
              </div> <!-- /header -->
99
              <div data-role="content" class="content">
100
                  <h1>[% s.name %]</h1>
101
              </div> <!-- /content -->
102
          </div> <!-- /page -->
103
104
      [% END # FOREACH s IN streams %]
105
    [% ELSE %]
106
      <p>No streams attached to this sign.</p>
107
    [% END # IF ( streams.0 ) %]
108
  [% END # IF ( sign ) %]
109
110
  [%# Display a list of all signs, as a default. Links use data-ajax="false" so signs will replace the first page, not be AJAXed in. %]
111
  [%# This page is not meant to be viewed by non-librarians, so it can not be themed. %]
112
  [% IF ( signs )  %]
113
    <div data-role="page" id="allsigns">
114
      <div data-role="header" data-position="fixed">
115
        <h1>All signs</h1>
116
      </div>
117
      <div data-role="content">
118
        <ul data-role="listview">
119
        [% FOREACH SIGN IN signs %]
120
          <li><a href="?sign=[% SIGN.sign_id %]" data-ajax="false">[% SIGN.name %]</a></li>
121
        [% END %]
122
        </ul>
123
      </div>
124
    </div>
125
  [% END # IF ( signs ) %]
126
[% END # UNLESS Koha.Preference( 'OPACDigitalSigns' ) %]
127
128
[% INCLUDE 'opac-bottom.inc' is_popup=1 %]
129
[% BLOCK jsinclude %]
130
    [% IF sign && Koha.Preference( 'OPACDigitalSigns') %]
131
    <script type="text/javascript">
132
    //<![CDATA[
133
        $(function (){
134
            var active_stream = '#' + $('.page-stream').first().attr('id');
135
            var active_record;
136
137
            /*****************************************************************
138
            * Page idle handling
139
            */
140
            var doIdle = false;
141
            var idleTimePage = 0;
142
            var idleTime = 0;
143
            var idleInterval = setInterval(idleIncrementer, 1000);
144
145
            function resetIdle() {
146
                idleTimePage = 0;
147
                idleTime = 0;
148
                doIdle = false;
149
            }
150
151
            function idleIncrementer() {
152
                idleTimePage++;
153
                idleTime++;
154
155
                [% IF ( sign.idleafter ) -%]
156
                if (idleTime >= [% sign.idleafter %]) {
157
                    doIdle = true;
158
                }
159
                [%- END -%]
160
161
                [%- IF ( sign.pagedelay ) -%]
162
                if (doIdle && idleTimePage >= [% sign.pagedelay %]) {
163
                    idleTimePage = 0;
164
                    swipe('next', true, true);
165
                }
166
                [%- END -%]
167
168
                [%- IF ( sign.reloadafter ) -%]
169
                if (doIdle && idleTime >= [% sign.reloadafter %]) {
170
                    resetIdle();
171
                    window.location.reload(true);
172
                }
173
                [%- END -%]
174
            }
175
176
            /*****************************************************************
177
            * User interaction methods
178
            */
179
            $('.btn-stream').click(function(){
180
                active_stream = $(this).attr('href');
181
                active_record = $(active_stream).find('.content a').first().attr('href');
182
            });
183
184
            /* swipe to next/previous record/stream */
185
            function swipe(direction, forceRecordView, warp) {
186
                var delta = direction == 'prev' ? -1 : 1;
187
                var isInRecordView = forceRecordView || window.location.hash.indexOf('#record') >= 0;
188
189
                if(isInRecordView) {
190
                    active_record = do_swipe(
191
                                        $(active_stream).find('.content a'),
192
                                        function($elm){
193
                                            return $elm.attr('href');
194
                                        },
195
                                        active_record
196
                                    );
197
                }
198
                else { // in stream view
199
                    active_stream = do_swipe(
200
                                        $('.page-stream'),
201
                                        function($elm) {
202
                                            return '#'+$elm.attr('id');
203
                                        },
204
                                        active_stream
205
                                    );
206
                }
207
208
                /* jump to next/prev page in pages returned from <selector>
209
                *  filtered through <filter> in references to <active>.
210
                *
211
                *  Return new active page.
212
                */
213
                function do_swipe(selector, filter, active) {
214
                    var list = [];
215
                    selector.each(function(){
216
                        list.push(filter($(this)));
217
                    });
218
219
                    var i = list.indexOf(active);
220
                    i = i == -1 ? 0 : i; // default to first if no active found
221
222
                    if(i >= 0) {
223
                        if(i >= list.length-1 && delta > 0) {
224
                            if(warp)
225
                                i = 0; // warp to start
226
                            else
227
                                return list[i];
228
                        } else if(i == 0 && delta < 0) {
229
                            if(warp)
230
                                i = list.length-1; // warp to end
231
                            else
232
                                return list[i];
233
                        } else {
234
                            i += delta;
235
                        }
236
237
                        $.mobile.changePage(list[i]);
238
                        return list[i];
239
                    }
240
241
                    return active;
242
                }
243
            }
244
245
            /*****************************************************************
246
            * Global events
247
            */
248
            $(window).on( 'swiperight', function() { resetIdle(); swipe('prev'); });
249
            $(window).on( 'swipeleft',  function() { resetIdle(); swipe('next'); });
250
            $(window).on( 'mousemove',  function() { resetIdle(); });
251
            $(window).on( 'keypress',   function() { resetIdle(); });
252
            $(window).on( 'tap',        function() { resetIdle(); });
253
254
            /*****************************************************************
255
            * Carousel
256
            */
257
            var Carousel = function ($elm) {
258
                var self = this;
259
                this.$elm = $elm;
260
                this.unicornCount = $elm.children().length;
261
                this.rotateFn = 'rotateY';
262
                this.$unicorns = this.$elm.children();
263
                this.i_active = this.$unicorns.index(this.$elm.children('.active'));
264
                this.unicornSize = this.$unicorns.first().outerWidth();
265
266
                this.modify = function() {
267
                    var offsetScale = $(window).width() / (this.unicornSize*this.unicornCount);
268
                    offsetScale = offsetScale > 1 ? 1 : offsetScale;
269
270
                    for ( i = 0; i < this.unicornCount ; i++ ) {
271
                        var $unicorn = this.$unicorns.eq(i);
272
                        var angle = 50*(i < this.i_active ? 1 : -1);
273
                        var scale = 0.75/Math.abs(i-this.i_active);
274
                        if(i == this.i_active) {
275
                            scale=1;
276
                            angle=0;
277
                        }
278
279
                        var transform = this.rotateFn + '(' + angle + 'deg) scale('+scale+')';
280
                        $unicorn.css({
281
                                        '-webkit-transform': transform,
282
                                        '-moz-transform': transform,
283
                                        '-o-transform': transform,
284
                                        '-ms-transform': transform,
285
                                        'transform': transform
286
                                    });
287
                        $unicorn.css('left', offsetScale*this.unicornSize*(i-this.i_active)+'px');
288
                        $unicorn.css('z-index', -1*Math.abs(i-this.i_active));
289
                    }
290
                };
291
            };
292
293
294
            /*****************************************************************
295
            * ImageCache
296
            */
297
            var ImageCache = function() {
298
                var self = this;
299
                self.cached = {};
300
                self.nocover = {};
301
302
                /* get cover image from local cover or fallbacks */
303
                self.get = function(record, finished_cb) {
304
                    if( record.biblionumber in self.cached ) {
305
                        finished_cb(self.cached[record.biblionumber]);
306
                    } else {
307
                        // first try local cover
308
                        var $img = $('<img/>')
309
                                    .attr('src','opac-image.pl?biblionumber='+record.biblionumber)
310
                                    .css('display','none')
311
                                    .appendTo('body');
312
313
                        $img.on('load', function() {
314
                            self.cached[record.biblionumber] = $(this);
315
                            // have a 1x1 pixel image, fallback to openlibrary ...
316
                            if($(this).height() <= 1) {
317
                                // ... if we can
318
                                if(record.isbn) {
319
                                    var ol_url = 'http://covers.openlibrary.org/b/isbn/';
320
                                    ol_url += record.isbn + '-M.jpg?default=false';
321
322
                                    var $ol_img = $('<img/>')
323
                                        .attr('src',ol_url)
324
                                        .css('display','none')
325
                                        .appendTo('body')
326
                                        .on('load', function() {
327
                                            $img.remove(); // remove old 1x1 pixel image
328
                                            self.cached[record.biblionumber] = $ol_img;
329
                                            finished_cb($(this));
330
                                        })
331
                                        .on('error', function() {
332
                                            // fallback to no cover image
333
                                            self.nocover[record.biblionumber] = true;
334
                                            finished_cb($(this));
335
                                        });
336
                                } else {
337
                                    // fallback to no cover image
338
                                    self.nocover[record.biblionumber] = true;
339
                                    finished_cb($(this));
340
                                }
341
                            } else {
342
                                finished_cb($(this));
343
                            }
344
                        });
345
                    }
346
                }
347
348
                self.have_cover = function(record) { return !(record.biblionumber in self.nocover) }
349
            };
350
            var img_cache = new ImageCache();
351
352
            /*****************************************************************
353
            * Cover
354
            */
355
            var coverCounter = 0;
356
            var Cover = function(record) {
357
                var self = this;
358
                self.record = record;
359
                self.id = coverCounter++;
360
361
                /* generate cover div */
362
                self.render = function(finished_cb) {
363
                    img_cache.get(record, function($img) {
364
                        self.$cover = $('<div class="cover cover_'+self.id+'" data-id="'+self.id+'"/>');
365
                        self.$cover.css('background-image', 'url("'+$img.attr('src')+'")');
366
                        self.$cover.css('background-size', '100%');
367
                        self.$cover.css('background-position', 'center center');
368
                        self.$cover.css('background-repeat', 'no-repeat');
369
                        self.$cover.addClass('ui-bar-[% sign.swatch %]');
370
371
                        if( !img_cache.have_cover(record) ) {
372
                            self.$vcontainer = $('<div class="cover-inner"/>');
373
                            self.$vcontainer.addClass('ui-bar-[% sign.swatch %]');
374
                            self.$cover.append(self.$vcontainer);
375
376
                            self.$cover.addClass('cover-blank');
377
                            self.$cover.css('border-color', $('.ui-bar-[% sign.swatch %]').first().css('background-color'));
378
379
                            var $covertext = $('<div class="cover-text"></div>');
380
                            $covertext.append($('<div class="title">'+record.title+'</div>'));
381
                            $covertext.append($('<div class="author">'+record.author+'</div>'));
382
383
                            self.$vcontainer.append($covertext);
384
                        }
385
386
                        finished_cb(self);
387
                    });
388
                }
389
            };
390
391
            /* create page for a cover */
392
            function create_CoverPage(cover, sid) {
393
                var $cover = cover.$cover.clone();
394
                var $stream = $('#stream_'+sid);
395
396
                var $page = $('<div data-role="page" data-close-btn="none" data-theme="[% sign.swatch %]" id="record_'+sid+'_'+cover.record.biblionumber+'"/>');
397
                var $head = $('<div data-role="header" data-theme="[% sign.swatch %]"/>');
398
                var $content = $('<div data-role="content" class="content"/>')
399
                var $foot = $('<div data-role="foot" data-position="fixed" class="foot"/>')
400
401
                /***************
402
                * header
403
                *******/
404
                $head.append($('<h1 aria-level="1" role="heading" class="ui-title">'+cover.record.title+'</h1>'));
405
406
                /***************
407
                * content
408
                ********/
409
                /* carousel */
410
                var $carousel_container = $('<div class="carousel-container"/>');
411
                $content.append($carousel_container);
412
413
                var $carousel = $('<ul class="carousel"/>');
414
                var neighbours= 2; // on each side
415
                var unicorns = [];
416
417
                /* grab <neighbours> covers around the active */
418
                $stream.find('.cover').each(function() {
419
                    unicorns.push($(this).data('id'));
420
                });
421
                var this_unicorn = unicorns.indexOf(cover.id);
422
                unicorns = unicorns.slice(
423
                        Math.max(this_unicorn-neighbours, 0),
424
                        1+Math.min(this_unicorn+neighbours, unicorns.length-1)
425
                        );
426
427
                /* create unicorns and add to carousel */
428
                for(var i=0; i < unicorns.length; i++) {
429
                    var $unicorn_cover = $('#stream_'+sid).find('.cover_'+unicorns[i]);
430
                    $unicorn_cover = $unicorn_cover.parent('a').clone();
431
                    var $unicorn = $('<li class="unicorn"/>').append($unicorn_cover);
432
                    if(unicorns[i] == cover.id) {
433
                        $unicorn.addClass('active');
434
                    }
435
                    $carousel.append($unicorn);
436
                }
437
                $carousel_container.append($carousel);
438
439
                /* initilize carousel on pagecreate */
440
                $page.on("pagecreate", function(){
441
                        var carousel = new Carousel($carousel);
442
                        $page.data('carousel', carousel);
443
                        carousel.modify();
444
                });
445
446
                /* item info */
447
                var $info = $('<div/>')
448
                $info.append($('<span><strong>'+_('Author')+':</strong> ' + cover.record.author+'</span>'));
449
                if(cover.record.publisher) {
450
                    $info.append($('<br/><span><strong>'+_('Publisher')+':</strong> ' + cover.record.publisher + '</span>'));
451
                }
452
453
                if(cover.record.items.length > 0) {
454
                    $info.append('<div class="vspace"/>');
455
                }
456
                var $items = $('<ul data-role="listview"/>');
457
                for(var i=0; i < cover.record.items.length; i++) {
458
                    var $li = $('<li/>');
459
                    var item = cover.record.items[i];
460
461
                    if(item.type) {
462
                        $li.append($('<img src="/opac-tmpl/lib/famfamfam/'+item.type+'.png" class="ui-li-icon"/>'));
463
                    }
464
                    var location = item.location_description ?  item.location_description + _(' in ') + item.home_branch: item.home_branch;
465
                    var item_info = item.status + _(' at ') + location;
466
                    $li.append($('<h4>'+item_info+'</h4>'));
467
                    if(item.datedue) {
468
                        $li.append('<p>'+_('Date due') + ': ' + item.datedue+'</p>');
469
                    }
470
                    $items.append($li);
471
                }
472
                $info.append($items);
473
                $content.append($info);
474
475
                /***************
476
                * footer
477
                *******/
478
                $foot.append($('<a href="#stream_'+sid+'" data-role="button" data-theme="[% sign.swatch %]" data-transition="[% sign.transition %]">'+_('Back')+'</a>'));
479
480
481
                /***************
482
                * page
483
                *****/
484
                $page.append($head);
485
                $page.append($content);
486
                $page.append($foot);
487
                $page.appendTo('body');
488
489
                return $page;
490
            };
491
492
            /*****************************************************************
493
            * Page generation
494
            */
495
            var streams = {
496
                [%- FOREACH stream IN streams %]
497
                    '[% stream.sign_stream_id %]': {
498
                        'name': [% stream.name.json || '""' %],
499
                        'records': [
500
                        [%- FOREACH record IN stream.records %]
501
                            {'author': [% record.author.json || '""' %],
502
                            'title': [% record.title.json || '""' %],
503
                            'publisher': [% record.publishercode.json || '""' %],
504
                            'biblionumber': [% record.biblionumber.json || '""' %],
505
                            'isbn': [% record.isbn.json || '""' %],
506
                            'items': [
507
                                [%- FOREACH item IN record.items %]
508
                                    {
509
                                        'type': [% item.itemtype.json || '""' %],
510
                                        'datedue': "[% item.datedue | $KohaDates as_due_date => 1 %]",
511
                                        'location': [% item.location.json || '""' %],
512
                                        'location_description': [% item.location_description.json || '""' %],
513
                                        'home_branch': "[% Branches.GetName(item.homebranch) | json %]",
514
                                        'status': "[% INCLUDE item_status item = item %]"
515
516
                                    }
517
                                    [%- UNLESS loop.last -%],[%- END -%]
518
                                [%- END %]
519
                            ]
520
                            }
521
                            [%- UNLESS loop.last -%],[%- END -%]
522
                        [%- END %]
523
                        ]
524
                }
525
                [%- UNLESS loop.last -%],[%- END -%]
526
                [%- END %]
527
            };
528
529
            /* fill up streams with records */
530
            var firstLoadedRecord = true;
531
            $('.page-stream').each(function() {
532
                var sid = $(this).data('stream-id');
533
                var $content = $(this).children('.content').first();
534
535
                for(var i in streams[sid].records) {
536
                    var cover = new Cover(streams[sid].records[i]);
537
                    var $link = $('<a href="#record_'+sid+'_'+cover.record.biblionumber+'" class="btn-record" data-transition="[% sign.transition %]"/>')
538
                    $link.click(function(){ active_record = $(this).attr('href'); });
539
                    $content.append($link.append($('<div class="cover placeholder ui-bar-[% sign.swatch %] cover_'+cover.id+'" data-id="'+cover.id+'"/>')));
540
541
                    cover.render(function(cover_rendered) {
542
                        var $coverPage = create_CoverPage(cover_rendered, sid);
543
                        /* initilize active_record with first loaded record from active stream */
544
                        if(firstLoadedRecord && sid == $(active_stream).data('stream-id') ){
545
                            active_record = cover_rendered.$cover.attr('href');
546
                            firstLoadedRecord = false;
547
                        }
548
549
                        /* replace all placeholders for this cover with rendered version*/
550
                        $('.placeholder.cover_'+cover_rendered.id).each(function() {
551
                            $(this).replaceWith(cover_rendered.$cover.clone());
552
                        });
553
                    });
554
                }
555
556
            });
557
        });
558
    //]]>
559
    </script>
560
    [% END # IF ( sign ) %]
561
    <script src="/opac-tmpl/lib/jquery/mobile/jquery.mobile.min.js"></script>
562
[% END # BLOCK jsinclude %]
563
564
</body>
565
</html>
(-)a/opac/opac-signs.pl (+49 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 Magnus Enger Libriotech
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use CGI;
21
use C4::Auth;
22
use C4::Output;
23
use Koha::Signs;
24
use Modern::Perl;
25
26
binmode STDOUT, ':encoding(UTF-8)'; # FIXME Non-ASCII is broken without this
27
28
my $query   = CGI->new;
29
my $sign_id = $query->param('sign')         || '';
30
31
my ( $template, $borrowernumber, $cookie ) = get_template_and_user({
32
    'template_name'   => 'opac-signs.tt',
33
    'query'           => $query,
34
    'type'            => 'opac',
35
    'authnotrequired' => ( C4::Context->preference('OpacPublic') ? 1 : 0 ),
36
    'flagsrequired'   => { borrow => 1 },
37
});
38
39
if ( C4::Context->preference('OPACDigitalSigns') ) {
40
    if ( $sign_id ne '' ) { # Display a sign with streams
41
        $template->{VARS}->{'sign'}    = GetSign( $sign_id );
42
        $template->{VARS}->{'streams'} = GetSignStreamsAttachedToSignWithRecords( $sign_id, 1 );
43
    }
44
    else { # Display a list of all available signs
45
       $template->{VARS}->{'signs'}  = GetSigns();
46
    }
47
}
48
49
output_html_with_http_headers $query, $cookie, $template->output;
(-)a/tools/signs.pl (-1 / +258 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
#
3
# Copyright 2012 Magnus Enger Libriotech
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
#
20
#
21
#
22
23
=head1 NAME
24
25
signs.pl - Script for managing digital signs for the OPAC.
26
27
=head1 SYNOPSIS
28
29
signs.pl
30
31
=head1 DESCRIPTION
32
33
Allows authorized users to create and manage digital signs for the OPAC.
34
35
=cut
36
37
use Koha::Signs;
38
use CGI;
39
use C4::Auth;
40
use C4::Context;
41
use C4::Log;
42
use C4::Output;
43
use C4::Reports::Guided;
44
use Modern::Perl;
45
46
my $cgi = new CGI;
47
my $dbh = C4::Context->dbh;
48
my $script_name = 'signs.pl';
49
50
my ( $template, $loggedinuser, $cookie ) = get_template_and_user({
51
    template_name   => "tools/signs.tt",
52
    query           => $cgi,
53
    type            => "intranet",
54
    authnotrequired => 0,
55
    flagsrequired   => { tools => 'edit_digital_signs' },
56
    debug           => 0,
57
});
58
59
my $op                = $cgi->param('op') || '';
60
my $sign_id           = $cgi->param('sign_id') || '';
61
my $sign_stream_id    = $cgi->param('sign_stream_id') || '';
62
my $sign_to_stream_id = $cgi->param('sign_to_stream_id') || '';
63
my $parameters        = $cgi->param('parameters') || '';
64
65
# Streams
66
67
if ( $op eq 'add_stream' ) {
68
69
    $template->param(
70
        'op'      => 'stream_form',
71
        'reports' => get_saved_reports( { group => 'SIG' } ),
72
    );
73
74
} elsif ( $op eq 'edit_stream' && $sign_stream_id ne '') {
75
76
    my $stream = GetSignStream( $sign_stream_id );
77
78
    $template->param(
79
      'op'          => 'stream_form',
80
      'stream'      => $stream,
81
      'reports'     => get_saved_reports( { group => 'SIG' } ),
82
      'script_name' => $script_name
83
    );
84
85
} elsif ( $op eq 'save_stream' ) {
86
87
    if ( $sign_stream_id ne '' ) {
88
        ModSignStream( $cgi->param('name'), $cgi->param('report'), $cgi->param('sign_stream_id') );
89
    } else {
90
        AddSignStream( $cgi->param('name'), $cgi->param('report'),  );
91
    }
92
    print $cgi->redirect($script_name);
93
94
} elsif ( $op eq 'view_stream' && $sign_stream_id ne '' ) {
95
96
    my $stream = GetSignStream( $sign_stream_id );
97
98
    if ( $stream->{'savedsql'} =~ m/<</ ) {
99
        $template->param( 'has_params' => 1 );
100
    } else {
101
        my $records = GetSignStreamRecords( $stream );
102
        $template->param( 'records' => $records->{result} );
103
    }
104
105
    $template->param(
106
        'op'          => 'view_stream',
107
        'stream'      => $stream,
108
        'script_name' => $script_name
109
    );
110
111
} elsif ( $op eq 'del_stream' ) {
112
113
    my $stream = GetSignStream( $sign_stream_id );
114
115
    $template->param(
116
        'op'          => 'del_stream',
117
        'stream'      => $stream,
118
        'script_name' => $script_name,
119
    );
120
121
} elsif ( $op eq 'del_stream_ok' ) {
122
123
    DelSignStream( $sign_stream_id );
124
125
    $template->param(
126
        'op'          => 'del_stream_ok',
127
        'script_name' => $script_name,
128
    );
129
130
# Signs
131
132
} elsif ( $op eq 'add_sign' ) {
133
134
    $template->param(
135
        'op'       => 'sign_form',
136
    );
137
138
} elsif ( $op eq 'edit_sign' && $sign_id ne '' ) {
139
140
    $template->param(
141
        'op'          => 'sign_form',
142
        'sign'        => GetSign( $sign_id ),
143
        'script_name' => $script_name,
144
    );
145
146
} elsif ( $op eq 'save_sign' ) {
147
148
    if ($cgi->param('sign_id')) {
149
        ModSign( $cgi->param('name'), $cgi->param('webapp'), $cgi->param('swatch'), $cgi->param('transition'), $cgi->param('idleafter'), $cgi->param('pagedelay'), $cgi->param('reloadafter'), $cgi->param('sign_id') );
150
    } else {
151
        AddSign(  $cgi->param('name'), $cgi->param('webapp'), $cgi->param('swatch'), $cgi->param('transition'), $cgi->param('idleafter'), $cgi->param('pagedelay'), $cgi->param('reloadafter') );
152
    }
153
    print $cgi->redirect($script_name);
154
155
} elsif ( $op eq 'view_sign' && $sign_id ne '' ) {
156
157
    $template->param(
158
        'op'          => 'view_sign',
159
        'sign'        => GetSign( $sign_id ),
160
        'streams'     => GetSignStreamsAttachedToSignWithRecords( $sign_id, 0 ),
161
        'script_name' => $script_name,
162
    );
163
164
} elsif ( $op eq 'del_sign' && $sign_id ne '' ) {
165
166
    $template->param(
167
        'op'          => 'del_sign',
168
        'sign'        => GetSign( $sign_id ),
169
        'script_name' => $script_name,
170
    );
171
172
} elsif ( $op eq 'del_sign_ok' ) {
173
174
    DelSign( $sign_id );
175
176
    $template->param(
177
        'op'          => 'del_sign_ok',
178
        'script_name' => $script_name,
179
    );
180
181
# Signs and streams
182
183
} elsif ( $op eq 'edit_streams' && $sign_id ne '') {
184
185
    $template->param(
186
        'op'          => 'edit_streams',
187
        'sign'        => GetSign( $sign_id ),
188
        'sign_id'     => $sign_id,
189
        'streams'     => GetSignStreams(),
190
        'attached'    => GetSignStreamsAttachedToSign( $sign_id ),
191
        'script_name' => $script_name
192
    );
193
194
} elsif ( $op eq 'attach_stream_to_sign' && $sign_stream_id ne '' && $sign_id ne '' ) {
195
196
    my $sign_to_stream_id = AttachSignStreamToSign( $sign_stream_id, $sign_id );
197
198
    # Check if the SQL associated with the stream needs parameters
199
    my $stream = GetSignStream( $sign_stream_id );
200
    if ( $stream->{'savedsql'} =~ m/<</ ) {
201
        print $cgi->redirect( $script_name . '?op=get_params&sign_to_stream_id=' . $sign_to_stream_id . '&sign_stream_id=' . $sign_stream_id . '&sign_id=' . $sign_id );
202
    } else {
203
        print $cgi->redirect( $script_name . '?op=edit_streams&sign_id=' . $sign_id );
204
    }
205
206
} elsif ( $op eq 'get_params' && $sign_to_stream_id ne '' && $sign_stream_id ne '' && $sign_id ne '' ) {
207
208
    my $stream = GetSignStream( $sign_stream_id );
209
    my $records = GetSignStreamRecords($stream, $sign_to_stream_id);
210
    if ( $records ) {
211
        $template->param( 'records' => $records->{result} );
212
    } else {
213
        $template->param( 'has_params' => 1 );
214
    }
215
216
    $template->param(
217
        'op'                => 'get_params',
218
        'stream'            => $stream,
219
        'sign_id'           => $sign_id,
220
        'sign_stream_id'    => $sign_stream_id,
221
        'sign_to_stream_id' => $sign_to_stream_id,
222
        'params'            => GetSignStreamParams( $sign_to_stream_id ),
223
        'newsql'            => $records->{sql},
224
        'script_name'       => $script_name,
225
    );
226
227
} elsif ( $op eq 'save_params' && $sign_to_stream_id ne '' && $sign_id ne '' ) {
228
229
    ModSignStreamParams( $sign_to_stream_id, $parameters );
230
    print $cgi->redirect( $script_name . '?op=get_params&sign_to_stream_id=' . $sign_to_stream_id . '&sign_stream_id=' . $sign_stream_id . '&sign_id=' . $sign_id );
231
232
} elsif ( $op eq 'detach_stream_from_sign' && $sign_to_stream_id ne '' ) {
233
234
    DetachSignStreamFromSign( $sign_to_stream_id );
235
    print $cgi->redirect($script_name . '?op=edit_streams&sign_id=' . $sign_id);
236
237
} else {
238
239
    # TODO Check the setting of OPACDigitalSigns, give a warning if it is off
240
241
    $template->param(
242
        'streams'     => GetSignStreams(),
243
        'signs'       => GetSigns(),
244
        'OPACBaseURL' => C4::Context->preference( 'OPACBaseURL' ) || '',
245
        'else'        => 1
246
    );
247
248
}
249
250
output_html_with_http_headers $cgi, $cookie, $template->output;
251
252
exit 0;
253
254
=head1 AUTHORS
255
256
Written by Magnus Enger of Libriotech.
257
258
=cut

Return to bug 8628