Bugzilla – Attachment 42704 Details for
Bug 8628
Add digital signs to the OPAC
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 8628: Add digital signs to the OPAC
Bug-8628-Add-digital-signs-to-the-OPAC.patch (text/plain), 70.43 KB, created by
Martin Stenberg
on 2015-09-18 12:51:10 UTC
(
hide
)
Description:
Bug 8628: Add digital signs to the OPAC
Filename:
MIME Type:
Creator:
Martin Stenberg
Created:
2015-09-18 12:51:10 UTC
Size:
70.43 KB
patch
obsolete
>From b23ec541b3b9372c19bdf41e85069a6e5f1da110 Mon Sep 17 00:00:00 2001 >From: Martin Stenberg <martin@xinxidi.net> >Date: Fri, 18 Sep 2015 14:29:50 +0200 >Subject: [PATCH] Bug 8628: Add digital signs to the OPAC > >See http://wiki.koha-community.org/wiki/Digital_signs_RFC for details. > >To test: >1. Apply this patch and the database updates patch >2. Run updatedatabase.pl >3. In staff client, go to Tools/Additional Tools/Digital signs >4. You should be warned about OPACDigitalSigns not being enabled, you can ignore > this for now. >5. Add a new sign by clicking the "+ New sign" button >6. Enter a name and optionally numbers for automatic page turing >7. Your new sign should appear in the Signs list >8. Add a new stream by clicking the "+ New stream" button >9. Unless you already have reports in the report group with code SIG, you should > be warned that there are no reports in the group with code SIG and given a > link for creating a new report. Follow the link and create a new report with > report group code SIG. En example SQL command for the report could be: > > SELECT * FROM biblio WHERE timestamp > DATE_SUB(NOW(), INTERVAL 7 DAY) >10. Go back to the "new stream" page, and reload. You should no longer see a > warning message, and your newly created report should appear in the list of > reports. >11. Select the report and click Submit. Your newly created stream should now > appear in the list of streams. >12. In the list of signs, press "edit streams" for the sign you previously > created. >13. Choose a stream to attach and click Submit. Your sign is now ready for OPAC. >14. In OPAC, visit /cgi-bin/koha/opac-signs.pl >15. You should be told that Digital signs are not enabled. Enable with new > system preference OPACDigitalSigns and reload the page. >15. You should see a list of available signs, click on a sign that you wish to > display. >16. You should now see a list of all books matching the SQL query in the report > that you attached to your stream. >17. If you have OPACLocalCoverImages enabled, all books with local covers > attached should be presented using this cover. > If no local cover is available and the book has a ISBN with a cover in > openlibrary.org, the cover image from openlibrary.org should be shown. > If all of the above fails, a cover matching the theme of the page should be > seen, showing the book title and author. >18. Clicking a book should bring you to a detailed view of the book where you > can see the books availability. You should also see the two next books and > the two previous books in the stream (unless you're at the beginning or end > of the stream) >19. Swiping (if no touch screen, click and hold left mouse button and drag) > left/right should bring you to next/previous book. Clicking on the > next/previous books (right/left of the active one) should bring you to the > detailed view of the clicked book. >20. Leaving the page idle (i.e no user interaction) for the amount of time > specified in step 6. should result in the page automatically switching to > the next book in the stream. > >Sponsored-by: Regionbibliotek Halland / County library of Halland >--- > Koha/Signs.pm | 330 ++++++++++++ > .../prog/en/modules/admin/preferences/opac.pref | 20 +- > .../intranet-tmpl/prog/en/modules/tools/signs.tt | 479 +++++++++++++++++ > .../prog/en/modules/tools/tools-home.tt | 5 + > koha-tmpl/opac-tmpl/bootstrap/css/signs.css | 102 ++++ > .../opac-tmpl/bootstrap/en/modules/opac-signs.tt | 565 +++++++++++++++++++++ > opac/opac-signs.pl | 49 ++ > tools/signs.pl | 258 ++++++++++ > 8 files changed, 1807 insertions(+), 1 deletion(-) > create mode 100644 Koha/Signs.pm > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/signs.tt > create mode 100644 koha-tmpl/opac-tmpl/bootstrap/css/signs.css > create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-signs.tt > create mode 100755 opac/opac-signs.pl > create mode 100755 tools/signs.pl > >diff --git a/Koha/Signs.pm b/Koha/Signs.pm >new file mode 100644 >index 0000000..35df437 >--- /dev/null >+++ b/Koha/Signs.pm >@@ -0,0 +1,330 @@ >+package Koha::Signs; >+ >+use C4::Context; >+use C4::Biblio; >+use C4::Koha; >+use C4::Items; >+use Modern::Perl; >+ >+use base qw( Exporter ); >+ >+# set the version for version checking >+our @EXPORT = qw( >+ >+ AddSignStream >+ ModSignStream >+ GetSignStream >+ GetSignStreams >+ DelSignStream >+ >+ GetSignStreamRecords >+ >+ AddSign >+ ModSign >+ GetSign >+ GetSigns >+ DelSign >+ >+ AttachSignStreamToSign >+ DetachSignStreamFromSign >+ GetSignStreamsAttachedToSign >+ GetSignStreamsAttachedToSignWithRecords >+ >+ ModSignStreamParams >+ GetSignStreamParams >+); >+ >+my $dbh = C4::Context->dbh; >+ >+# Streams >+ >+# Returns id of new sign_stream >+sub AddSignStream { >+ >+ my ( $name, $report ) = @_; >+ >+ my $sth=$dbh->prepare("INSERT INTO sign_streams SET name = ?, saved_sql_id = ?"); >+ $sth->execute( $name, $report ); >+ return $dbh->last_insert_id( undef, undef, 'sign_streams', 'sign_stream_id' ); >+ >+} >+ >+sub ModSignStream { >+ >+ my ( $name, $report, $sign_stream_id ) = @_; >+ >+ my $sth = $dbh->prepare("UPDATE sign_streams SET name = ?, saved_sql_id = ? WHERE sign_stream_id = ?"); >+ return $sth->execute( $name, $report, $sign_stream_id ); >+ >+} >+ >+sub GetSignStream { >+ >+ my ( $sign_id ) = @_; >+ >+ return unless $sign_id; >+ >+ my $query = "SELECT s.*, sq.report_name, sq.savedsql >+ FROM sign_streams AS s, saved_sql AS sq >+ WHERE s.saved_sql_id = sq.id >+ AND s.sign_stream_id = ?"; >+ my $sth = $dbh->prepare($query); >+ $sth->execute($sign_id); >+ return $sth->fetchrow_hashref(); >+ >+} >+ >+sub GetSignStreams { >+ >+ my $query = "SELECT s.*, sq.report_name, sq.savedsql >+ FROM sign_streams AS s, saved_sql AS sq >+ WHERE s.saved_sql_id = sq.id >+ ORDER BY s.name"; >+ my $sth = $dbh->prepare($query); >+ $sth->execute(); >+ return $sth->fetchall_arrayref({}); >+ >+} >+ >+sub DelSignStream { >+ >+ my ( $sign_stream_id ) = @_; >+ >+ return unless $sign_stream_id; >+ >+ my $sth = $dbh->prepare('DELETE FROM sign_streams WHERE sign_stream_id = ?'); >+ return $sth->execute($sign_stream_id); >+ >+} >+ >+sub GetSignStreamRecords { >+ my ( $stream, $sign_to_stream_id) = @_; >+ my $sql = $stream->{'savedsql'}; >+ >+ if ( defined $sign_to_stream_id ) { >+ my $params = GetSignStreamParams( $sign_to_stream_id ); >+ $sql = ReplaceParamsInSQL( $sql, $params ); >+ return undef if ( $sql =~ m/<</ ); >+ } >+ >+ return {result => RunSQL( $sql ), sql => $sql }; >+} >+ >+# Signs >+ >+# Returns id of new sign >+sub AddSign { >+ >+ my ( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter ) = @_; >+ >+ my $sth=$dbh->prepare("INSERT INTO signs SET name = ?, webapp = ?, swatch = ?, transition = ?, idleafter = ?, pagedelay = ?, reloadafter = ?"); >+ $sth->execute( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter ); >+ return $dbh->last_insert_id( undef, undef, 'signs', 'sign_id' ); >+ >+} >+ >+sub ModSign { >+ >+ my ( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter, $sign_id ) = @_; >+ >+ my $sth = $dbh->prepare("UPDATE signs SET name = ?, webapp = ?, swatch = ?, transition = ?, idleafter = ?, pagedelay = ?, reloadafter = ? WHERE sign_id = ?"); >+ return $sth->execute( $name, $webapp, $swatch, $transition, $idleafter, $pagedelay, $reloadafter, $sign_id ); >+ >+} >+ >+sub GetSign { >+ >+ my ( $sign_id ) = @_; >+ >+ return unless $sign_id; >+ >+ my $query = "SELECT * >+ FROM signs >+ WHERE sign_id = ?"; >+ my $sth = $dbh->prepare($query); >+ $sth->execute($sign_id); >+ return $sth->fetchrow_hashref(); >+ >+} >+ >+sub GetSigns { >+ >+ my $query = "SELECT * >+ FROM signs >+ ORDER BY name"; >+ my $sth = $dbh->prepare($query); >+ $sth->execute(); >+ return $sth->fetchall_arrayref({}); >+ >+} >+ >+sub DelSign { >+ >+ my ( $sign_id ) = @_; >+ >+ return unless $sign_id; >+ >+ my $sth = $dbh->prepare('DELETE FROM signs WHERE sign_id = ?'); >+ return $sth->execute($sign_id); >+ >+} >+ >+# Streams attached to signs >+ >+# Returns the ID of the connection between sign and stream >+sub AttachSignStreamToSign { >+ >+ my ( $sign_stream_id, $sign_id ) = @_; >+ >+ return unless $sign_stream_id || $sign_id; >+ >+ my $sth = $dbh->prepare( 'INSERT INTO signs_to_streams SET sign_stream_id = ?, sign_id = ?' ); >+ $sth->execute( $sign_stream_id, $sign_id ); >+ return $dbh->last_insert_id( undef, undef, 'signs_to_streams', 'sign_to_stream_id' ); >+ >+} >+ >+sub ModSignStreamParams { >+ >+ my ( $sign_to_stream_id, $params ) = @_; >+ return unless $sign_to_stream_id; >+ my $sth = $dbh->prepare( 'UPDATE signs_to_streams SET params = ? WHERE sign_to_stream_id = ?' ); >+ return $sth->execute( $params, $sign_to_stream_id ); >+ >+} >+ >+# Returns the string of params for a given stream-attached-to-sign >+sub GetSignStreamParams { >+ >+ my ( $sign_to_stream_id ) = @_; >+ >+ return unless $sign_to_stream_id; >+ >+ my $query = 'SELECT params FROM signs_to_streams WHERE sign_to_stream_id = ?'; >+ my $sth = $dbh->prepare( $query ); >+ $sth->execute( $sign_to_stream_id ); >+ return $sth->fetchrow_array(); >+ >+} >+ >+sub ReplaceParamsInSQL { >+ >+ my ( $sql, $params ) = @_; >+ >+ return unless $sql || $params; >+ return $sql unless $sql =~ m/<</; >+ >+ foreach my $param ( split /&/, $params ) { >+ my ( $key, $value ) = split /=/, $param; >+ # FIXME Handle spaces >+ $sql =~ s/<<$key>>/$value/g; >+ } >+ return $sql; >+ >+} >+ >+sub GetSignStreamsAttachedToSign { >+ >+ my ( $sign_id ) = @_; >+ >+ return unless $sign_id; >+ >+ my $query = 'SELECT s.*, sts.sign_to_stream_id, sts.params, sq.report_name, sq.savedsql >+ FROM sign_streams AS s, signs_to_streams AS sts, saved_sql AS sq >+ WHERE s.sign_stream_id = sts.sign_stream_id >+ AND s.saved_sql_id = sq.id >+ AND sts.sign_id = ? >+ ORDER BY s.name'; >+ my $sth = $dbh->prepare( $query ); >+ $sth->execute( $sign_id ); >+ return $sth->fetchall_arrayref({}); >+ >+} >+ >+sub GetSignStreamsAttachedToSignWithRecords { >+ >+ my ( $sign_id, $include_marc ) = @_; >+ >+ return unless $sign_id; >+ >+ my $streams = GetSignStreamsAttachedToSign( $sign_id ); >+ my @changedstreams; >+ my %record_cache = (); >+ >+ # Add records to the streams >+ foreach my $stream ( @{$streams} ) { >+ >+ my $records = RunSQL( ReplaceParamsInSQL( $stream->{'savedsql'}, $stream->{'params'} ) ); >+ >+ if ( $include_marc ) { >+ >+ my @processed_records; >+ foreach my $rec ( @{$records} ) { >+ unless(defined $record_cache{$rec->{'biblionumber'}}) { >+ my $marc = GetMarcBiblio( $rec->{'biblionumber'} ); >+ if ( ! $marc ) { >+ next; >+ } >+ >+ my $isbn = GetNormalizedISBN( undef, $marc, C4::Context->preference("marcflavor") ) || ''; >+ $rec->{'isbn'} = $isbn; >+ >+ my $dat = GetBiblioData($rec->{'biblionumber'}); >+ my @items = GetItemsInfo($rec->{'biblionumber'}); >+ foreach my $item ( @items ) { >+ my $shelflocations = GetKohaAuthorisedValues('items.location',$dat->{'frameworkcode'}, 'opac'); >+ if ( defined $item->{'location'} ) { >+ $item->{'location_description'} = $shelflocations->{ $item->{'location'} }; >+ } >+ } >+ $rec->{'items'} = \@items; >+ foreach ( keys %{$dat} ) { >+ $rec->{"$_"} = defined $dat->{$_} ? $dat->{$_} : ''; >+ } >+ >+ $rec->{'marc'} = $marc; >+ >+ $record_cache{$rec->{'biblionumber'}} = $rec; >+ } >+ push @processed_records, $record_cache{$rec->{'biblionumber'}}; >+ } >+ $stream->{'records'} = \@processed_records; >+ >+ } else { >+ >+ $stream->{'records'} = $records; >+ >+ } >+ >+ push @changedstreams, $stream; >+ >+ } >+ >+ return \@changedstreams; >+ >+} >+ >+sub DetachSignStreamFromSign { >+ >+ my ( $sign_to_stream_id ) = @_; >+ >+ return unless $sign_to_stream_id; >+ >+ my $sth = $dbh->prepare( 'DELETE FROM signs_to_streams WHERE sign_to_stream_id = ?' ); >+ return $sth->execute( $sign_to_stream_id ); >+ >+} >+ >+sub RunSQL { >+ >+ my ( $query ) = @_; >+ >+ return unless $query; >+ >+ my $sth = $dbh->prepare($query); >+ $sth->execute(); >+ return $sth->fetchall_arrayref({}); >+ >+} >+ >+1; >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref >index 17d0b1a..82b015e 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref >@@ -645,7 +645,6 @@ OPAC: > yes: Use > no: "Don't use" > - "the item collection code when finding items for the shelf browser." >- > Self Registration: > - > - pref: PatronSelfRegistration >@@ -684,6 +683,25 @@ OPAC: > - pref: PatronSelfRegistrationAdditionalInstructions > type: htmlarea > class: html >+ Digital Signs: >+ - >+ - pref: OPACDigitalSigns >+ default: 0 >+ choices: >+ yes: Enable >+ no: Disable >+ - "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." >+ - >+ - "Include the following CSS in all digital signs:" >+ - pref: OPACDigitalSignsCSS >+ type: textarea >+ class: code >+ - (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.) >+ - >+ - Make it possible to choose one of the themes (swatches) >+ - pref: OPACDigitalSignsSwatches >+ class: long >+ - 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. > Advanced Search Options: > - > - Show search options >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/signs.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/signs.tt >new file mode 100644 >index 0000000..100c814 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/signs.tt >@@ -0,0 +1,479 @@ >+[% USE Koha %] >+[% INCLUDE 'doc-head-open.inc' %] >+<title>Koha › Tools › Digital signs</title> >+[% INCLUDE 'doc-head-close.inc' %] >+<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" /> >+[% INCLUDE 'datatables.inc' %] >+<script type="text/javascript"> >+//<![CDATA[ >+ >+ // prepare DOM for YUI Toolbar >+ $(document).ready(function() { >+ $("#table_signs").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumns": [ >+ null, >+ {"bSearchable": false}, >+ {"bSearchable": false}, >+ {"bSearchable": false}, >+ {"bSearchable": false}, >+ {"bSearchable": false}, >+ {"bSearchable": false}, >+ {"bSearchable": false, "bSortable": false}, >+ {"bSearchable": false, "bSortable": false}, >+ {"bSearchable": false, "bSortable": false}, >+ {"bSearchable": false, "bSortable": false} >+ ], >+ "sPaginationType": "four_button" >+ } )); >+ $("#table_streams").dataTable($.extend(true, {}, dataTablesDefaults, { >+ "aoColumns": [ >+ null, >+ {"bSearchable": false}, >+ {"bSearchable": false, "bSortable": false}, >+ {"bSearchable": false, "bSortable": false}, >+ ], >+ "sPaginationType": "four_button" >+ } )); >+ }); >+//]]> >+</script> >+</head> >+<body id="tools_signs" class="tools"> >+[% INCLUDE 'header.inc' %] >+[% INCLUDE 'cat-search.inc' %] >+ >+[% BLOCK dslink %]<a href="/cgi-bin/koha/tools/signs.pl">Digital signs</a> ›[% END %] >+<div id="breadcrumbs"> >+ <a href="/cgi-bin/koha/mainpage.pl">Home</a> › >+ <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> › >+ [% IF op == 'stream_form' %] >+ [% IF ( stream.sign_stream_id ) %] >+ [% INCLUDE dslink %] Edit "[% stream.name %]" >+ [% ELSE %] >+ [% INCLUDE dslink %] Add a new stream >+ [% END %] >+ [% ELSIF op == 'sign_form' %] >+ [% IF ( sign.sign_id ) %] >+ [% INCLUDE dslink %] Edit "[% sign.name %]" >+ [% ELSE %] >+ [% INCLUDE dslink %] Add a new sign >+ [% END %] >+ [% ELSIF op == 'edit_streams' %] >+ [% INCLUDE dslink %] Edit streams attached to "[% sign.name %]" >+ [% ELSIF op == 'get_params' %] >+ [% INCLUDE dslink %] Get parameters >+ [% ELSIF op == 'del_stream' %] >+ [% INCLUDE dslink %] Delete stream "[% stream.name %]" >+ [% ELSIF op == 'del_stream_ok' %] >+ [% INCLUDE dslink %] Stream deleted >+ [% ELSIF op == 'del_sign' %] >+ [% INCLUDE dslink %] Delete sign "[% sign.name %]" >+ [% ELSIF op == 'del_sign_ok' %] >+ [% INCLUDE dslink %] Sign deleted >+ [% ELSIF op == 'view_sign' %] >+ [% INCLUDE dslink %] View sign >+ [% ELSIF op == 'view_stream' %] >+ [% INCLUDE dslink %] View stream >+ [% ELSE %] >+ Digital signs >+ [% END %] >+</div> >+ >+<div id="doc3" class="yui-t2"> >+ >+ <div id="bd"> >+ <div id="yui-main"> >+ <div class="yui-b"> >+ >+[% UNLESS Koha.Preference( 'OPACDigitalSigns' ) %] >+<div class="dialog alert"> >+ <p> >+ Digital signs are not enabled. Please enable >+ <a href="/cgi-bin/koha/admin/preferences.pl?tab=&op=search&searchfield=OPACDigitalSigns">OPACDigitalSigns</a> >+ for OPAC digital signs to work. >+ </p> >+</div> >+[% END %] >+ >+[% IF ( else ) %] >+ <div id="toolbar"> >+ <ul class="toolbar"> >+ <li><a id="newsign" href="?op=add_sign" class="btn btn-small"><i class="icon-plus"></i>New sign</a></li> >+ <li><a id="newstream" href="?op=add_stream" class="btn btn-small"><i class="icon-plus"></i>New stream</a></li> >+ </ul> >+ </div> >+[% END %] >+ >+[% IF op == 'stream_form' %] >+ [% UNLESS ( reports ) %] >+ <div class="dialog alert"> >+ <h3>No reports found</h3> >+ <p>No reports with group code "SIG" were found. Please <a >+ href="/cgi-bin/koha/reports/guided_reports.pl?phase=Create+report+from+SQL&submit=Create+report+from+SQL">create >+ a new report</a> with group code "SIG" and try again.</p> >+ </div> >+ [% END %] >+ >+ [% IF ( stream.sign_stream_id ) %] >+ <h1>Edit stream</h1> >+ [% ELSE %] >+ <h1>Add stream</h1> >+ [% END %] >+ <form action="[% script_name %]" name="streamform" id="streamform" method="post"> >+ <input type="hidden" name="op" value="save_stream" /> >+ [% IF ( stream.sign_stream_id ) %] >+ <input type="hidden" name="sign_stream_id" value="[% stream.sign_stream_id %]" /> >+ [% END %] >+ <fieldset class="rows"> >+ <ol> >+ <li><label for="name">Name</label><input type="text" name="name" value="[% stream.name %]" /></li> >+ <li><label for="report">Report</label> >+ <select name="report" id="report"> >+ [% UNLESS ( stream.sign_stream_id ) %] >+ <option value="">Choose report</option> >+ [% END %] >+ [% FOREACH report IN reports %] >+ [% IF ( report.id == stream.saved_sql_id ) %] >+ <option value="[% report.id %]" selected="selected">[% report.report_name %]</option> >+ [% ELSE %] >+ <option value="[% report.id %]">[% report.report_name %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset> >+ </form> >+ >+[% ELSIF op == 'sign_form' %] >+ >+ [% IF ( sign.sign_id ) %] >+ <h1>Edit sign</h1> >+ [% ELSE %] >+ <h1>Add sign</h1> >+ [% END %] >+ <form action="[% script_name %]" name="signform" id="signform" method="post"> >+ <input type="hidden" name="op" value="save_sign" /> >+ [% IF ( sign.sign_id ) %] >+ <input type="hidden" name="sign_id" value="[% sign.sign_id %]" /> >+ [% END %] >+ <fieldset id="sign_general_info" class="rows"> >+ <legend id="general_info_lgd">General settings</legend> >+ <ol> >+ <li><label for="name">Name</label><input type="text" name="name" value="[% sign.name %]" /></li> >+ </ol> >+ </fieldset> >+ <fieldset id="sign_appearance" class="rows"> >+ <legend id="appearance_lgd">Appearance</legend> >+ <ol> >+ <li><label for="webapp">Web-app</label> >+ <select name="webapp" id="webapp"> >+ <option value="0">Display as a normal page</option> >+ [% IF ( sign.webapp ) %] >+ <option value="1" selected="selected">Display as a Web-app</option> >+ [% ELSE %] >+ <option value="1">Display as a Web-app</option> >+ [% END %] >+ </select> >+ </li> >+ <li><label for="swatch">Theme (swatch)</label> >+ <select name="swatch" id="swatch"> >+ <option value="">Default</option> >+ [% FOREACH swatch IN Koha.Preference('OPACDigitalSignsSwatches').split('') %] >+ [% IF swatch == sign.swatch %] >+ <option value="[% swatch %]" selected="selected">[% swatch %]</option> >+ [% ELSE %] >+ <option value="[% swatch %]">[% swatch %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ <li><label for="transition">Transition</label> >+ <select name="transition" id="transition"> >+ [% FOREACH transition IN [ 'none' 'fade' 'pop' 'flip' 'turn' 'flow' 'slidefade' 'slide' 'slideup' 'slidedown' ] %] >+ [% IF transition == sign.transition %] >+ <option value="[% transition %]" selected="selected">[% transition %]</option> >+ [% ELSE %] >+ <option value="[% transition %]">[% transition %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset id="sign_autopage" class="rows"> >+ <legend id="autopage_lgd">Automatic page turning</legend> >+ <ol> >+ <li><label for="idleafter">Idle after</label> >+ <input type="text" name="idleafter" id="idleafter" value="[% sign.idleafter %]" size="4" /> seconds. (Set to 0 to disable automatic page turning.) >+ </li> >+ <li><label for="pagedelay">Page delay</label> >+ <input type="text" name="pagedelay" id="pagedelay" value="[% sign.pagedelay %]" size="4" /> seconds. >+ </li> >+ <li><label for="reloadafter">Reload after</label> >+ <input type="text" name="reloadafter" id="reloadafter" value="[% sign.reloadafter %]" size="4" /> seconds. >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset> >+ </form> >+ >+[% ELSIF op == 'edit_streams' %] >+ >+ <h1>Edit streams attached to [% sign.name %]</h1> >+ <h2>Streams already attached to this sign</h2> >+ [% IF ( attached.size ) %] >+ <table> >+ <thead> >+ <tr><th>Name</th><th>Parameters</th><th>Edit parameters</th><th>Detach</th></tr> >+ </thead> >+ <tbody> >+ [% FOREACH s IN attached %] >+ <tr> >+ <td>[% s.name %]</td> >+ <td>[% s.params %]</td> >+ <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> >+ <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> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <p>There are no streams attached to this sign, yet.</p> >+ [% END %] >+ >+ <h2>Attach a new stream to this sign</h2> >+ <form action="[% script_name %]" name="attach_stream_to_sign_form" id="attach_stream_to_sign_form" method="post"> >+ <input type="hidden" name="op" value="attach_stream_to_sign" /> >+ <input type="hidden" name="sign_id" value="[% sign_id %]" /> >+ <fieldset class="rows"> >+ <ol> >+ <li><label for="stream">Choose a stream to attach</label> >+ <select name="sign_stream_id" id="stream"> >+ [% FOREACH s IN streams %] >+ <option value="[% s.sign_stream_id %]">[% s.name %]</option> >+ [% END %] >+ </select> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset> >+ </form> >+ >+[% ELSIF op == 'get_params' %] >+ >+ <h1>Parameters for [% stream.name %]</h1> >+ <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> >+ >+ <form action="[% script_name %]" name="get_params_form" id="get_params_form" method="post"> >+ <input type="hidden" name="op" value="save_params" /> >+ <input type="hidden" name="sign_to_stream_id" value="[% sign_to_stream_id %]" /> >+ <input type="hidden" name="sign_stream_id" value="[% sign_stream_id %]" /> >+ <input type="hidden" name="sign_id" value="[% sign_id %]" /> >+ <fieldset class="rows"> >+ [% IF ( params ) %] >+ <legend id="save_params_lgd">Edit parameters</legend> >+ [% ELSE %] >+ <legend id="save_params_lgd">Add parameters</legend> >+ [% END %] >+ <ol> >+ <li><label for="stream">Parameters</label> >+ <input type="text" size="60" name="parameters" id="parameters" value="[% params %]" /> >+ </li> >+ </ol> >+ </fieldset> >+ <fieldset class="action"> <input type="submit" value="Submit" class="submit" /></fieldset> >+ </form> >+ >+ <h2>Raw SQL</h2> >+ <pre id="sql_output">[% stream.savedsql | html %]</pre> >+ >+ <h2>SQL with current parameters replaced</h2> >+ <pre id="sql_output">[% newsql | html %]</pre> >+ [% IF ( has_params ) %] >+ <p>Sorry, your SQL still contains placeholders. You need to add more parameters.</p> >+ [% ELSE %] >+ <h2>Records</h2> >+ [% INCLUDE display_records %] >+ [% END %] >+ >+[% ELSIF op == 'del_stream' %] >+ >+ <div class="dialog alert"> >+ <h3>Confirm deletion of stream <span class="ex">'[% stream.name %]'</span>?</h3> >+ <form action="[% script_name %]" id ="confirm_stream_delete_form" method="post"> >+ <input type="hidden" name="op" value="del_stream_ok" /> >+ <input type="hidden" name="sign_stream_id" value="[% stream.sign_stream_id %]" /> >+ <input type="submit" class="approve" value="Yes, Delete this stream" /></form> >+ >+ <form action="[% script_name %]" id="cancel_stream_delete_form" method="get"> >+ <input type="submit" value="No, do not delete" class="deny" /> >+ </form> >+ </div> >+ >+[% ELSIF op == 'del_stream_ok' %] >+ >+ <div class="dialog message"> >+ <h3>Stream deleted</h3> >+ <form action="[% script_name %]" method="get"> >+ <input type="submit" value="OK" class="approve" /> >+ </form> >+ </div> >+ >+[% ELSIF op == 'del_sign' %] >+ >+ <div class="dialog alert"> >+ <h3>Confirm deletion of sign <span class="ex">'[% sign.name %]'</span>?</h3> >+ <form action="[% script_name %]" id ="confirm_sign_delete_form" method="post"> >+ <input type="hidden" name="op" value="del_sign_ok" /> >+ <input type="hidden" name="sign_id" value="[% sign.sign_id %]" /> >+ <input type="submit" class="approve" value="Yes, Delete this sign" /></form> >+ >+ <form action="[% script_name %]" id="cancel_sign_delete_form" method="get"> >+ <input type="submit" value="No, do not delete" class="deny" /> >+ </form> >+ </div> >+ >+[% ELSIF op == 'del_sign_ok' %] >+ >+ <div class="dialog message"> >+ <h3>Sign deleted</h3> >+ <form action="[% script_name %]" method="get"> >+ <input type="submit" value="OK" class="approve" /> >+ </form> >+ </div> >+ >+[% ELSIF op == 'view_sign' %] >+ >+ <h1>[% sign.name %]</h1> >+ <h2>Streams</h2> >+ >+ [% IF ( streams ) %] >+ [% FOREACH stream IN streams %] >+ <h3>[% stream.name %]</h3> >+ <ul> >+ [% FOREACH record IN stream.records %] >+ <li><a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% record.biblionumber %]">[% record.title %]</a></li> >+ [% END %] >+ </ul> >+ [% END %] >+ [% ELSE %] >+ <p>No streams attached.</p> >+ [% END%] >+ >+[% ELSIF op == 'view_stream' %] >+ >+ <h1>[% stream.name %]</h1> >+ <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> >+ <h2>SQL</h2> >+ <pre id="sql_output">[% stream.savedsql | html %]</pre> >+ <h2>Records</h2> >+ [% IF ( has_params ) %] >+ <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> >+ [% ELSE %] >+ [% INCLUDE display_records %] >+ [% END %] >+ >+[% ELSE %] >+ >+ <h1>Digital signs</h1> >+ >+ [% IF signs %] >+ <h2>Signs</h2> >+ <table id="table_signs"> >+ <thead> >+ <tr> >+ <th>Name</th> >+ <th>Web-app</th> >+ <th>Theme (swatch)</th> >+ <th>Transition</th> >+ <th>Idle after</th> >+ <th>Page delay</th> >+ <th>Reload after</th> >+ <th>Edit</th> >+ <th>Edit streams</th> >+ <th>Delete</th> >+ <th>View sign</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH s IN signs %] >+ <tr> >+ <td><a href="?op=view_sign&sign_id=[% s.sign_id %]">[% s.name %]</a></td> >+ <td>[% IF ( s.webapp ) %]Yes[% ELSE %]No[% END %]</td> >+ <td>[% s.swatch %]</td> >+ <td>[% s.transition %]</td> >+ <td>[% s.idleafter %]</td> >+ <td>[% s.pagedelay %]</td> >+ <td>[% s.reloadafter %]</td> >+ <td><a href="?op=edit_sign&sign_id=[% s.sign_id %]">Edit</a></td> >+ <td><a href="?op=edit_streams&sign_id=[% s.sign_id %]">Edit streams</a></td> >+ <td><a href="?op=del_sign&sign_id=[% s.sign_id %]">Delete</a></td> >+ <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> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% 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 %] >+ [% ELSE %] >+ <p>No signs defined!</p> >+ [% END %] >+ >+ [% IF streams %] >+ <h2>Streams</h2> >+ <table id="table_streams"> >+ <thead> >+ <tr> >+ <th>Name</th> >+ <th>Report</th> >+ <th>Edit</th> >+ <th>Delete</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH s IN streams %] >+ <tr> >+ <td><a href="?op=view_stream&sign_stream_id=[% s.sign_stream_id %]">[% s.name %]</a></td> >+ <td title="ID: [% s.saved_sql_id %]">[% s.report_name %]</td> >+ <td><a href="?op=edit_stream&sign_stream_id=[% s.sign_stream_id %]">Edit</a></td> >+ <td><a href="?op=del_stream&sign_stream_id=[% s.sign_stream_id %]">Delete</a></td> >+ </tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <p>No streams defined!</p> >+ [% END %] >+ >+[% END %] >+ >+ >+ >+</div> >+</div> >+<div class="yui-b"> >+[% INCLUDE 'tools-menu.inc' %] >+</div> >+</div> >+[% INCLUDE 'intranet-bottom.inc' %] >+ >+[% BLOCK display_records %] >+ [% IF ( records.0 ) %] >+ <table> >+ <thead> >+ <tr> >+ <th>biblionumber</th> >+ <th>title</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH r IN records %] >+ <tr><td>[% r.biblionumber %]</td><td>[% r.title %]</td></tr> >+ [% END %] >+ </tbody> >+ </table> >+ [% ELSE %] >+ <p>No records found.</p> >+ [% END %] >+[% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt >index 7b2e14e..9d8309b 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt >@@ -106,6 +106,11 @@ > <dd>Quote editor for Quote-of-the-day feature in OPAC</dd> > [% END %] > >+ [% IF ( CAN_user_tools_edit_digital_signs ) %] >+ <dt><a href="/cgi-bin/koha/tools/signs.pl">Digital signs</a></dt> >+ <dd>Create and edit digital signs for the OPAC</dd> >+ [% END %] >+ > [% IF ( UseKohaPlugins && CAN_user_plugins_tool ) %] > <dt><a href="/cgi-bin/koha/plugins/plugins-home.pl?method=tool">Tool Plugins</a></dt> > <dd>Use tool plugins</dd> >diff --git a/koha-tmpl/opac-tmpl/bootstrap/css/signs.css b/koha-tmpl/opac-tmpl/bootstrap/css/signs.css >new file mode 100644 >index 0000000..e1bf843 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/bootstrap/css/signs.css >@@ -0,0 +1,102 @@ >+.carousel-container { >+ width: 225px; >+ height: 225px; >+ position: relative; >+ margin: 0 auto 40px; >+ -webkit-perspective: 1100px; >+ -moz-perspective: 1100px; >+ -o-perspective: 1100px; >+ -ms-perspective: 1100px; >+ perspective: 1100px; >+} >+ >+.carousel { >+ width: 100%; >+ height: 100%; >+ position: absolute; >+ -webkit-transform-style: preserve-3d; >+ -moz-transform-style: preserve-3d; >+ -o-transform-style: preserve-3d; >+ -ms-transform-style: preserve-3d; >+ transform-style: preserve-3d; >+} >+ >+.unicorn { >+ display: block; >+ position: absolute; >+ width: 150px; >+ height: 225px; >+ left: 10px; >+ top: 10px; >+ -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)); >+} >+ >+.ui-li { >+ padding-top: 0px !important; >+ padding-bottom: 0px !important; >+ margin-bottom: -7px !important; >+} >+ >+.ui-li h4 { >+ margin-top: 2px !important; >+ margin-bottom: 2px !important; >+} >+ >+.ui-li-icon { >+ top: 15% !important; >+} >+ >+.vspace { >+ margin-top: 2em; >+} >+ >+.content { >+ text-align: center; >+} >+ >+.btn-record { >+ margin: 10px; >+} >+ >+.cover { >+ border: none; >+ display: inline-block; >+ height: 225px; >+ width: 150px; >+ background-size: 100%; >+ background-repeat: round; >+} >+ >+.cover.cover-blank { >+} >+ >+.cover.placeholder { >+} >+ >+.cover .cover-inner { >+ display: table-cell; >+ vertical-align: middle; >+ padding: 25px; >+ border: 2px solid #fff; >+ height: 171px; >+ max-height: 171px; >+ width: inherit; >+} >+ >+.cover-text { >+ text-align: center; >+ position: relative; >+ font-family: Georgia, "Palatino Linotype", "Book Antiqua", Palatino, "Times New Roman", serif; >+ font-size: 1em; >+ max-height: inherit; >+ overflow: hidden; >+} >+ >+.cover-text .title { >+ font-weight: bold; >+} >+ >+.cover-text .author { >+ font-style: italic; >+ margin-top: 1em; >+} >diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-signs.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-signs.tt >new file mode 100644 >index 0000000..812e8f1 >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-signs.tt >@@ -0,0 +1,565 @@ >+[% USE Koha %] >+[% USE KohaDates %] >+[% USE Branches %] >+[% USE JSON.Escape %] >+ >+[%- BLOCK item_status -%] >+ [%- SET itemavailable = 1 -%] >+ [%- IF ( item.itemlost ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]Item lost >+ [%- END -%] >+ [%- IF ( item.datedue || issue.date_due ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%- IF item.onsite_checkout -%] >+ [%-%]Currently in local use >+ [%- ELSE -%] >+ [%-%]Checked out >+ [%- END -%] >+ [%- END -%] >+ [%- IF ( item.transfertwhen ) %] >+ [%- SET itemavailable = 0 -%] >+ [%-%]In transit from [%- item.transfertfrom %] to [%- item.transfertto %] since [%- item.transfertwhen | $KohaDates %] >+ [%- END %] >+ [%- IF ( item.waiting ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]On hold >+ [%- END -%] >+ [%- IF ( item.withdrawn ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]Item withdrawn >+ [%- END -%] >+ [%- IF ( item.itemnotforloan ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%- IF ( item.notforloanvalueopac ) -%] >+ [%- item.notforloanvalueopac -%] [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%] >+ [%- ELSE -%] >+ [%-%]Not for loan [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%] >+ [%- END -%] >+ [%- ELSIF ( item.notforloan_per_itemtype ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]Not for loan [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%] >+ [%- END -%] >+ [%- IF ( item.damaged ) -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]Item damaged >+ [%- END -%] >+ [%- IF item.on_order -%] >+ [%- SET itemavailable = 0 -%] >+ [%-%]On order >+ [%- END -%] >+ [%- IF ( itemavailable ) -%] >+ [%-%]Available [%- IF ( item.restrictedopac ) -%] ([%- item.restrictedopac -%])[%- END -%] >+ [%- END -%] >+[%- END -%] >+ >+[% INCLUDE 'doc-head-open.inc' %] >+<title>[% IF ( sign ) %][% sign.name %] - Koha[% ELSE %]Koha digital signs[% END %]</title> >+[%- IF ( sign.webapp ) %] >+ <meta name="apple-mobile-web-app-capable" content="yes" /> >+ <meta name="viewport" content="width=device-width, initial-scale=1"> >+[% END -%] >+[% BLOCK cssinclude %] >+ [%- IF Koha.Preference( 'OPACDigitalSignsCSS' ) != '' -%] >+ <style type="text/css"> >+ [% Koha.Preference( 'OPACDigitalSignsCSS' ) %] >+ </style> >+ <link rel="stylesheet" href="/opac-tmpl/lib/jquery/mobile/jquery.mobile.structure.min.css" /> >+ [%- ELSE -%] >+ <link rel="stylesheet" href="/opac-tmpl/bootstrap/css/signs.css" /> >+ <link rel="stylesheet" href="/opac-tmpl/lib/jquery/mobile/jquery.mobile.min.css" /> >+ [%- END -%] >+[% END # BLOCK cssinclude %] >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+[% INCLUDE 'bodytag.inc' bodyid='opac-signs' %] >+ >+[%- UNLESS Koha.Preference( 'OPACDigitalSigns' ) -%] >+ <p>Digital signs are not enabled!</p> >+[%- ELSE -%] >+ [%# Display a sign, all its streams and all records %] >+ [%- IF ( sign ) -%] >+ [%- IF ( streams.0 ) -%] >+ [%# Iterate through the streams, creating one front page for each %] >+ [%- FOREACH s IN streams -%] >+ <div data-role="page" class="page-stream" data-stream-id="[% s.sign_stream_id %]" data-theme="[% sign.swatch %]" id="stream_[% s.sign_stream_id %]"> >+ <div data-role="header" data-theme="[% sign.swatch %]" data-position="fixed"> >+ <div style="text-align: center;"> >+ [%# The header has a list of buttons for all the streams %] >+ [%- SET localstreams = streams -%] >+ [%- FOREACH stream IN localstreams -%] >+ [% IF s.sign_stream_id == stream.sign_stream_id %] >+ <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> >+ [% ELSE %] >+ <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> >+ [% END %] >+ [% END -%] >+ </div> >+ </div> <!-- /header --> >+ <div data-role="content" class="content"> >+ <h1>[% s.name %]</h1> >+ </div> <!-- /content --> >+ </div> <!-- /page --> >+ >+ [% END # FOREACH s IN streams %] >+ [% ELSE %] >+ <p>No streams attached to this sign.</p> >+ [% END # IF ( streams.0 ) %] >+ [% END # IF ( sign ) %] >+ >+ [%# 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. %] >+ [%# This page is not meant to be viewed by non-librarians, so it can not be themed. %] >+ [% IF ( signs ) %] >+ <div data-role="page" id="allsigns"> >+ <div data-role="header" data-position="fixed"> >+ <h1>All signs</h1> >+ </div> >+ <div data-role="content"> >+ <ul data-role="listview"> >+ [% FOREACH SIGN IN signs %] >+ <li><a href="?sign=[% SIGN.sign_id %]" data-ajax="false">[% SIGN.name %]</a></li> >+ [% END %] >+ </ul> >+ </div> >+ </div> >+ [% END # IF ( signs ) %] >+[% END # UNLESS Koha.Preference( 'OPACDigitalSigns' ) %] >+ >+[% INCLUDE 'opac-bottom.inc' is_popup=1 %] >+[% BLOCK jsinclude %] >+ [% IF sign && Koha.Preference( 'OPACDigitalSigns') %] >+ <script type="text/javascript"> >+ //<![CDATA[ >+ $(function (){ >+ var active_stream = '#' + $('.page-stream').first().attr('id'); >+ var active_record; >+ >+ /***************************************************************** >+ * Page idle handling >+ */ >+ var doIdle = false; >+ var idleTimePage = 0; >+ var idleTime = 0; >+ var idleInterval = setInterval(idleIncrementer, 1000); >+ >+ function resetIdle() { >+ idleTimePage = 0; >+ idleTime = 0; >+ doIdle = false; >+ } >+ >+ function idleIncrementer() { >+ idleTimePage++; >+ idleTime++; >+ >+ [% IF ( sign.idleafter ) -%] >+ if (idleTime >= [% sign.idleafter %]) { >+ doIdle = true; >+ } >+ [%- END -%] >+ >+ [%- IF ( sign.pagedelay ) -%] >+ if (doIdle && idleTimePage >= [% sign.pagedelay %]) { >+ idleTimePage = 0; >+ swipe('next', true, true); >+ } >+ [%- END -%] >+ >+ [%- IF ( sign.reloadafter ) -%] >+ if (doIdle && idleTime >= [% sign.reloadafter %]) { >+ resetIdle(); >+ window.location.reload(true); >+ } >+ [%- END -%] >+ } >+ >+ /***************************************************************** >+ * User interaction methods >+ */ >+ $('.btn-stream').click(function(){ >+ active_stream = $(this).attr('href'); >+ active_record = $(active_stream).find('.content a').first().attr('href'); >+ }); >+ >+ /* swipe to next/previous record/stream */ >+ function swipe(direction, forceRecordView, warp) { >+ var delta = direction == 'prev' ? -1 : 1; >+ var isInRecordView = forceRecordView || window.location.hash.indexOf('#record') >= 0; >+ >+ if(isInRecordView) { >+ active_record = do_swipe( >+ $(active_stream).find('.content a'), >+ function($elm){ >+ return $elm.attr('href'); >+ }, >+ active_record >+ ); >+ } >+ else { // in stream view >+ active_stream = do_swipe( >+ $('.page-stream'), >+ function($elm) { >+ return '#'+$elm.attr('id'); >+ }, >+ active_stream >+ ); >+ } >+ >+ /* jump to next/prev page in pages returned from <selector> >+ * filtered through <filter> in references to <active>. >+ * >+ * Return new active page. >+ */ >+ function do_swipe(selector, filter, active) { >+ var list = []; >+ selector.each(function(){ >+ list.push(filter($(this))); >+ }); >+ >+ var i = list.indexOf(active); >+ i = i == -1 ? 0 : i; // default to first if no active found >+ >+ if(i >= 0) { >+ if(i >= list.length-1 && delta > 0) { >+ if(warp) >+ i = 0; // warp to start >+ else >+ return list[i]; >+ } else if(i == 0 && delta < 0) { >+ if(warp) >+ i = list.length-1; // warp to end >+ else >+ return list[i]; >+ } else { >+ i += delta; >+ } >+ >+ $.mobile.changePage(list[i]); >+ return list[i]; >+ } >+ >+ return active; >+ } >+ } >+ >+ /***************************************************************** >+ * Global events >+ */ >+ $(window).on( 'swiperight', function() { resetIdle(); swipe('prev'); }); >+ $(window).on( 'swipeleft', function() { resetIdle(); swipe('next'); }); >+ $(window).on( 'mousemove', function() { resetIdle(); }); >+ $(window).on( 'keypress', function() { resetIdle(); }); >+ $(window).on( 'tap', function() { resetIdle(); }); >+ >+ /***************************************************************** >+ * Carousel >+ */ >+ var Carousel = function ($elm) { >+ var self = this; >+ this.$elm = $elm; >+ this.unicornCount = $elm.children().length; >+ this.rotateFn = 'rotateY'; >+ this.$unicorns = this.$elm.children(); >+ this.i_active = this.$unicorns.index(this.$elm.children('.active')); >+ this.unicornSize = this.$unicorns.first().outerWidth(); >+ >+ this.modify = function() { >+ var offsetScale = $(window).width() / (this.unicornSize*this.unicornCount); >+ offsetScale = offsetScale > 1 ? 1 : offsetScale; >+ >+ for ( i = 0; i < this.unicornCount ; i++ ) { >+ var $unicorn = this.$unicorns.eq(i); >+ var angle = 50*(i < this.i_active ? 1 : -1); >+ var scale = 0.75/Math.abs(i-this.i_active); >+ if(i == this.i_active) { >+ scale=1; >+ angle=0; >+ } >+ >+ var transform = this.rotateFn + '(' + angle + 'deg) scale('+scale+')'; >+ $unicorn.css({ >+ '-webkit-transform': transform, >+ '-moz-transform': transform, >+ '-o-transform': transform, >+ '-ms-transform': transform, >+ 'transform': transform >+ }); >+ $unicorn.css('left', offsetScale*this.unicornSize*(i-this.i_active)+'px'); >+ $unicorn.css('z-index', -1*Math.abs(i-this.i_active)); >+ } >+ }; >+ }; >+ >+ >+ /***************************************************************** >+ * ImageCache >+ */ >+ var ImageCache = function() { >+ var self = this; >+ self.cached = {}; >+ self.nocover = {}; >+ >+ /* get cover image from local cover or fallbacks */ >+ self.get = function(record, finished_cb) { >+ if( record.biblionumber in self.cached ) { >+ finished_cb(self.cached[record.biblionumber]); >+ } else { >+ // first try local cover >+ var $img = $('<img/>') >+ .attr('src','opac-image.pl?biblionumber='+record.biblionumber) >+ .css('display','none') >+ .appendTo('body'); >+ >+ $img.on('load', function() { >+ self.cached[record.biblionumber] = $(this); >+ // have a 1x1 pixel image, fallback to openlibrary ... >+ if($(this).height() <= 1) { >+ // ... if we can >+ if(record.isbn) { >+ var ol_url = 'http://covers.openlibrary.org/b/isbn/'; >+ ol_url += record.isbn + '-M.jpg?default=false'; >+ >+ var $ol_img = $('<img/>') >+ .attr('src',ol_url) >+ .css('display','none') >+ .appendTo('body') >+ .on('load', function() { >+ $img.remove(); // remove old 1x1 pixel image >+ self.cached[record.biblionumber] = $ol_img; >+ finished_cb($(this)); >+ }) >+ .on('error', function() { >+ // fallback to no cover image >+ self.nocover[record.biblionumber] = true; >+ finished_cb($(this)); >+ }); >+ } else { >+ // fallback to no cover image >+ self.nocover[record.biblionumber] = true; >+ finished_cb($(this)); >+ } >+ } else { >+ finished_cb($(this)); >+ } >+ }); >+ } >+ } >+ >+ self.have_cover = function(record) { return !(record.biblionumber in self.nocover) } >+ }; >+ var img_cache = new ImageCache(); >+ >+ /***************************************************************** >+ * Cover >+ */ >+ var coverCounter = 0; >+ var Cover = function(record) { >+ var self = this; >+ self.record = record; >+ self.id = coverCounter++; >+ >+ /* generate cover div */ >+ self.render = function(finished_cb) { >+ img_cache.get(record, function($img) { >+ self.$cover = $('<div class="cover cover_'+self.id+'" data-id="'+self.id+'"/>'); >+ self.$cover.css('background-image', 'url("'+$img.attr('src')+'")'); >+ self.$cover.css('background-size', '100%'); >+ self.$cover.css('background-position', 'center center'); >+ self.$cover.css('background-repeat', 'no-repeat'); >+ self.$cover.addClass('ui-bar-[% sign.swatch %]'); >+ >+ if( !img_cache.have_cover(record) ) { >+ self.$vcontainer = $('<div class="cover-inner"/>'); >+ self.$vcontainer.addClass('ui-bar-[% sign.swatch %]'); >+ self.$cover.append(self.$vcontainer); >+ >+ self.$cover.addClass('cover-blank'); >+ self.$cover.css('border-color', $('.ui-bar-[% sign.swatch %]').first().css('background-color')); >+ >+ var $covertext = $('<div class="cover-text"></div>'); >+ $covertext.append($('<div class="title">'+record.title+'</div>')); >+ $covertext.append($('<div class="author">'+record.author+'</div>')); >+ >+ self.$vcontainer.append($covertext); >+ } >+ >+ finished_cb(self); >+ }); >+ } >+ }; >+ >+ /* create page for a cover */ >+ function create_CoverPage(cover, sid) { >+ var $cover = cover.$cover.clone(); >+ var $stream = $('#stream_'+sid); >+ >+ var $page = $('<div data-role="page" data-close-btn="none" data-theme="[% sign.swatch %]" id="record_'+sid+'_'+cover.record.biblionumber+'"/>'); >+ var $head = $('<div data-role="header" data-theme="[% sign.swatch %]"/>'); >+ var $content = $('<div data-role="content" class="content"/>') >+ var $foot = $('<div data-role="foot" data-position="fixed" class="foot"/>') >+ >+ /*************** >+ * header >+ *******/ >+ $head.append($('<h1 aria-level="1" role="heading" class="ui-title">'+cover.record.title+'</h1>')); >+ >+ /*************** >+ * content >+ ********/ >+ /* carousel */ >+ var $carousel_container = $('<div class="carousel-container"/>'); >+ $content.append($carousel_container); >+ >+ var $carousel = $('<ul class="carousel"/>'); >+ var neighbours= 2; // on each side >+ var unicorns = []; >+ >+ /* grab <neighbours> covers around the active */ >+ $stream.find('.cover').each(function() { >+ unicorns.push($(this).data('id')); >+ }); >+ var this_unicorn = unicorns.indexOf(cover.id); >+ unicorns = unicorns.slice( >+ Math.max(this_unicorn-neighbours, 0), >+ 1+Math.min(this_unicorn+neighbours, unicorns.length-1) >+ ); >+ >+ /* create unicorns and add to carousel */ >+ for(var i=0; i < unicorns.length; i++) { >+ var $unicorn_cover = $('#stream_'+sid).find('.cover_'+unicorns[i]); >+ $unicorn_cover = $unicorn_cover.parent('a').clone(); >+ var $unicorn = $('<li class="unicorn"/>').append($unicorn_cover); >+ if(unicorns[i] == cover.id) { >+ $unicorn.addClass('active'); >+ } >+ $carousel.append($unicorn); >+ } >+ $carousel_container.append($carousel); >+ >+ /* initilize carousel on pagecreate */ >+ $page.on("pagecreate", function(){ >+ var carousel = new Carousel($carousel); >+ $page.data('carousel', carousel); >+ carousel.modify(); >+ }); >+ >+ /* item info */ >+ var $info = $('<div/>') >+ $info.append($('<span><strong>'+_('Author')+':</strong> ' + cover.record.author+'</span>')); >+ if(cover.record.publisher) { >+ $info.append($('<br/><span><strong>'+_('Publisher')+':</strong> ' + cover.record.publisher + '</span>')); >+ } >+ >+ if(cover.record.items.length > 0) { >+ $info.append('<div class="vspace"/>'); >+ } >+ var $items = $('<ul data-role="listview"/>'); >+ for(var i=0; i < cover.record.items.length; i++) { >+ var $li = $('<li/>'); >+ var item = cover.record.items[i]; >+ >+ if(item.type) { >+ $li.append($('<img src="/opac-tmpl/lib/famfamfam/'+item.type+'.png" class="ui-li-icon"/>')); >+ } >+ var location = item.location_description ? item.location_description + _(' in ') + item.home_branch: item.home_branch; >+ var item_info = item.status + _(' at ') + location; >+ $li.append($('<h4>'+item_info+'</h4>')); >+ if(item.datedue) { >+ $li.append('<p>'+_('Date due') + ': ' + item.datedue+'</p>'); >+ } >+ $items.append($li); >+ } >+ $info.append($items); >+ $content.append($info); >+ >+ /*************** >+ * footer >+ *******/ >+ $foot.append($('<a href="#stream_'+sid+'" data-role="button" data-theme="[% sign.swatch %]" data-transition="[% sign.transition %]">'+_('Back')+'</a>')); >+ >+ >+ /*************** >+ * page >+ *****/ >+ $page.append($head); >+ $page.append($content); >+ $page.append($foot); >+ $page.appendTo('body'); >+ >+ return $page; >+ }; >+ >+ /***************************************************************** >+ * Page generation >+ */ >+ var streams = { >+ [%- FOREACH stream IN streams %] >+ '[% stream.sign_stream_id %]': { >+ 'name': [% stream.name.json || '""' %], >+ 'records': [ >+ [%- FOREACH record IN stream.records %] >+ {'author': [% record.author.json || '""' %], >+ 'title': [% record.title.json || '""' %], >+ 'publisher': [% record.publishercode.json || '""' %], >+ 'biblionumber': [% record.biblionumber.json || '""' %], >+ 'isbn': [% record.isbn.json || '""' %], >+ 'items': [ >+ [%- FOREACH item IN record.items %] >+ { >+ 'type': [% item.itemtype.json || '""' %], >+ 'datedue': "[% item.datedue | $KohaDates as_due_date => 1 %]", >+ 'location': [% item.location.json || '""' %], >+ 'location_description': [% item.location_description.json || '""' %], >+ 'home_branch': "[% Branches.GetName(item.homebranch) | json %]", >+ 'status': "[% INCLUDE item_status item = item %]" >+ >+ } >+ [%- UNLESS loop.last -%],[%- END -%] >+ [%- END %] >+ ] >+ } >+ [%- UNLESS loop.last -%],[%- END -%] >+ [%- END %] >+ ] >+ } >+ [%- UNLESS loop.last -%],[%- END -%] >+ [%- END %] >+ }; >+ >+ /* fill up streams with records */ >+ var firstLoadedRecord = true; >+ $('.page-stream').each(function() { >+ var sid = $(this).data('stream-id'); >+ var $content = $(this).children('.content').first(); >+ >+ for(var i in streams[sid].records) { >+ var cover = new Cover(streams[sid].records[i]); >+ var $link = $('<a href="#record_'+sid+'_'+cover.record.biblionumber+'" class="btn-record" data-transition="[% sign.transition %]"/>') >+ $link.click(function(){ active_record = $(this).attr('href'); }); >+ $content.append($link.append($('<div class="cover placeholder ui-bar-[% sign.swatch %] cover_'+cover.id+'" data-id="'+cover.id+'"/>'))); >+ >+ cover.render(function(cover_rendered) { >+ var $coverPage = create_CoverPage(cover_rendered, sid); >+ /* initilize active_record with first loaded record from active stream */ >+ if(firstLoadedRecord && sid == $(active_stream).data('stream-id') ){ >+ active_record = cover_rendered.$cover.attr('href'); >+ firstLoadedRecord = false; >+ } >+ >+ /* replace all placeholders for this cover with rendered version*/ >+ $('.placeholder.cover_'+cover_rendered.id).each(function() { >+ $(this).replaceWith(cover_rendered.$cover.clone()); >+ }); >+ }); >+ } >+ >+ }); >+ }); >+ //]]> >+ </script> >+ [% END # IF ( sign ) %] >+ <script src="/opac-tmpl/lib/jquery/mobile/jquery.mobile.min.js"></script> >+[% END # BLOCK jsinclude %] >+ >+</body> >+</html> >diff --git a/opac/opac-signs.pl b/opac/opac-signs.pl >new file mode 100755 >index 0000000..66057df >--- /dev/null >+++ b/opac/opac-signs.pl >@@ -0,0 +1,49 @@ >+#!/usr/bin/perl >+ >+# Copyright 2012 Magnus Enger Libriotech >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use CGI; >+use C4::Auth; >+use C4::Output; >+use Koha::Signs; >+use Modern::Perl; >+ >+binmode STDOUT, ':encoding(UTF-8)'; # FIXME Non-ASCII is broken without this >+ >+my $query = CGI->new; >+my $sign_id = $query->param('sign') || ''; >+ >+my ( $template, $borrowernumber, $cookie ) = get_template_and_user({ >+ 'template_name' => 'opac-signs.tt', >+ 'query' => $query, >+ 'type' => 'opac', >+ 'authnotrequired' => ( C4::Context->preference('OpacPublic') ? 1 : 0 ), >+ 'flagsrequired' => { borrow => 1 }, >+}); >+ >+if ( C4::Context->preference('OPACDigitalSigns') ) { >+ if ( $sign_id ne '' ) { # Display a sign with streams >+ $template->{VARS}->{'sign'} = GetSign( $sign_id ); >+ $template->{VARS}->{'streams'} = GetSignStreamsAttachedToSignWithRecords( $sign_id, 1 ); >+ } >+ else { # Display a list of all available signs >+ $template->{VARS}->{'signs'} = GetSigns(); >+ } >+} >+ >+output_html_with_http_headers $query, $cookie, $template->output; >diff --git a/tools/signs.pl b/tools/signs.pl >new file mode 100755 >index 0000000..702829d >--- /dev/null >+++ b/tools/signs.pl >@@ -0,0 +1,258 @@ >+#!/usr/bin/perl >+# >+# Copyright 2012 Magnus Enger Libriotech >+# >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 2 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+# >+# >+# >+ >+=head1 NAME >+ >+signs.pl - Script for managing digital signs for the OPAC. >+ >+=head1 SYNOPSIS >+ >+signs.pl >+ >+=head1 DESCRIPTION >+ >+Allows authorized users to create and manage digital signs for the OPAC. >+ >+=cut >+ >+use Koha::Signs; >+use CGI; >+use C4::Auth; >+use C4::Context; >+use C4::Log; >+use C4::Output; >+use C4::Reports::Guided; >+use Modern::Perl; >+ >+my $cgi = new CGI; >+my $dbh = C4::Context->dbh; >+my $script_name = 'signs.pl'; >+ >+my ( $template, $loggedinuser, $cookie ) = get_template_and_user({ >+ template_name => "tools/signs.tt", >+ query => $cgi, >+ type => "intranet", >+ authnotrequired => 0, >+ flagsrequired => { tools => 'edit_digital_signs' }, >+ debug => 0, >+}); >+ >+my $op = $cgi->param('op') || ''; >+my $sign_id = $cgi->param('sign_id') || ''; >+my $sign_stream_id = $cgi->param('sign_stream_id') || ''; >+my $sign_to_stream_id = $cgi->param('sign_to_stream_id') || ''; >+my $parameters = $cgi->param('parameters') || ''; >+ >+# Streams >+ >+if ( $op eq 'add_stream' ) { >+ >+ $template->param( >+ 'op' => 'stream_form', >+ 'reports' => get_saved_reports( { group => 'SIG' } ), >+ ); >+ >+} elsif ( $op eq 'edit_stream' && $sign_stream_id ne '') { >+ >+ my $stream = GetSignStream( $sign_stream_id ); >+ >+ $template->param( >+ 'op' => 'stream_form', >+ 'stream' => $stream, >+ 'reports' => get_saved_reports( { group => 'SIG' } ), >+ 'script_name' => $script_name >+ ); >+ >+} elsif ( $op eq 'save_stream' ) { >+ >+ if ( $sign_stream_id ne '' ) { >+ ModSignStream( $cgi->param('name'), $cgi->param('report'), $cgi->param('sign_stream_id') ); >+ } else { >+ AddSignStream( $cgi->param('name'), $cgi->param('report'), ); >+ } >+ print $cgi->redirect($script_name); >+ >+} elsif ( $op eq 'view_stream' && $sign_stream_id ne '' ) { >+ >+ my $stream = GetSignStream( $sign_stream_id ); >+ >+ if ( $stream->{'savedsql'} =~ m/<</ ) { >+ $template->param( 'has_params' => 1 ); >+ } else { >+ my $records = GetSignStreamRecords( $stream ); >+ $template->param( 'records' => $records->{result} ); >+ } >+ >+ $template->param( >+ 'op' => 'view_stream', >+ 'stream' => $stream, >+ 'script_name' => $script_name >+ ); >+ >+} elsif ( $op eq 'del_stream' ) { >+ >+ my $stream = GetSignStream( $sign_stream_id ); >+ >+ $template->param( >+ 'op' => 'del_stream', >+ 'stream' => $stream, >+ 'script_name' => $script_name, >+ ); >+ >+} elsif ( $op eq 'del_stream_ok' ) { >+ >+ DelSignStream( $sign_stream_id ); >+ >+ $template->param( >+ 'op' => 'del_stream_ok', >+ 'script_name' => $script_name, >+ ); >+ >+# Signs >+ >+} elsif ( $op eq 'add_sign' ) { >+ >+ $template->param( >+ 'op' => 'sign_form', >+ ); >+ >+} elsif ( $op eq 'edit_sign' && $sign_id ne '' ) { >+ >+ $template->param( >+ 'op' => 'sign_form', >+ 'sign' => GetSign( $sign_id ), >+ 'script_name' => $script_name, >+ ); >+ >+} elsif ( $op eq 'save_sign' ) { >+ >+ if ($cgi->param('sign_id')) { >+ 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') ); >+ } else { >+ AddSign( $cgi->param('name'), $cgi->param('webapp'), $cgi->param('swatch'), $cgi->param('transition'), $cgi->param('idleafter'), $cgi->param('pagedelay'), $cgi->param('reloadafter') ); >+ } >+ print $cgi->redirect($script_name); >+ >+} elsif ( $op eq 'view_sign' && $sign_id ne '' ) { >+ >+ $template->param( >+ 'op' => 'view_sign', >+ 'sign' => GetSign( $sign_id ), >+ 'streams' => GetSignStreamsAttachedToSignWithRecords( $sign_id, 0 ), >+ 'script_name' => $script_name, >+ ); >+ >+} elsif ( $op eq 'del_sign' && $sign_id ne '' ) { >+ >+ $template->param( >+ 'op' => 'del_sign', >+ 'sign' => GetSign( $sign_id ), >+ 'script_name' => $script_name, >+ ); >+ >+} elsif ( $op eq 'del_sign_ok' ) { >+ >+ DelSign( $sign_id ); >+ >+ $template->param( >+ 'op' => 'del_sign_ok', >+ 'script_name' => $script_name, >+ ); >+ >+# Signs and streams >+ >+} elsif ( $op eq 'edit_streams' && $sign_id ne '') { >+ >+ $template->param( >+ 'op' => 'edit_streams', >+ 'sign' => GetSign( $sign_id ), >+ 'sign_id' => $sign_id, >+ 'streams' => GetSignStreams(), >+ 'attached' => GetSignStreamsAttachedToSign( $sign_id ), >+ 'script_name' => $script_name >+ ); >+ >+} elsif ( $op eq 'attach_stream_to_sign' && $sign_stream_id ne '' && $sign_id ne '' ) { >+ >+ my $sign_to_stream_id = AttachSignStreamToSign( $sign_stream_id, $sign_id ); >+ >+ # Check if the SQL associated with the stream needs parameters >+ my $stream = GetSignStream( $sign_stream_id ); >+ if ( $stream->{'savedsql'} =~ m/<</ ) { >+ 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 ); >+ } else { >+ print $cgi->redirect( $script_name . '?op=edit_streams&sign_id=' . $sign_id ); >+ } >+ >+} elsif ( $op eq 'get_params' && $sign_to_stream_id ne '' && $sign_stream_id ne '' && $sign_id ne '' ) { >+ >+ my $stream = GetSignStream( $sign_stream_id ); >+ my $records = GetSignStreamRecords($stream, $sign_to_stream_id); >+ if ( $records ) { >+ $template->param( 'records' => $records->{result} ); >+ } else { >+ $template->param( 'has_params' => 1 ); >+ } >+ >+ $template->param( >+ 'op' => 'get_params', >+ 'stream' => $stream, >+ 'sign_id' => $sign_id, >+ 'sign_stream_id' => $sign_stream_id, >+ 'sign_to_stream_id' => $sign_to_stream_id, >+ 'params' => GetSignStreamParams( $sign_to_stream_id ), >+ 'newsql' => $records->{sql}, >+ 'script_name' => $script_name, >+ ); >+ >+} elsif ( $op eq 'save_params' && $sign_to_stream_id ne '' && $sign_id ne '' ) { >+ >+ ModSignStreamParams( $sign_to_stream_id, $parameters ); >+ 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 ); >+ >+} elsif ( $op eq 'detach_stream_from_sign' && $sign_to_stream_id ne '' ) { >+ >+ DetachSignStreamFromSign( $sign_to_stream_id ); >+ print $cgi->redirect($script_name . '?op=edit_streams&sign_id=' . $sign_id); >+ >+} else { >+ >+ # TODO Check the setting of OPACDigitalSigns, give a warning if it is off >+ >+ $template->param( >+ 'streams' => GetSignStreams(), >+ 'signs' => GetSigns(), >+ 'OPACBaseURL' => C4::Context->preference( 'OPACBaseURL' ) || '', >+ 'else' => 1 >+ ); >+ >+} >+ >+output_html_with_http_headers $cgi, $cookie, $template->output; >+ >+exit 0; >+ >+=head1 AUTHORS >+ >+Written by Magnus Enger of Libriotech. >+ >+=cut >-- >2.5.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 8628
:
42703
|
42704
|
45968
|
45969
|
58602
|
58603
|
58604
|
58605
|
62338
|
64249
|
66246
|
66247
|
66248
|
66249
|
66250
|
77025
|
77026
|
77027
|
77028
|
77141
|
77142
|
77143
|
77144
|
77145
|
78709
|
80248
|
80249
|
80250
|
80252
|
82896
|
82897
|
82898
|
82899
|
82900
|
82901
|
83312
|
88821
|
88822
|
88823
|
88824
|
88825
|
88826
|
93054
|
93055
|
93056
|
93057
|
93058
|
93059
|
93066
|
93067
|
93068
|
93069
|
93070
|
93071
|
99608
|
99609
|
99610
|
99611
|
99612
|
99613
|
99614
|
99615
|
99616
|
99617
|
99618
|
99619
|
99620
|
99621
|
99622
|
99623
|
99624
|
99717
|
99718
|
99801
|
118472
|
118473
|
118474
|
118475
|
118476
|
118477
|
118478
|
118479
|
118480
|
119455
|
131223
|
131224
|
145645
|
145646
|
145647
|
145648
|
145649
|
145650
|
145651
|
145652
|
145653
|
145654
|
147000
|
147001
|
147002
|
147003
|
147004
|
147005
|
147006
|
147007
|
147008
|
147009
|
147010