From 62865dece92efd6222604f67b4d1ff4745faece5 Mon Sep 17 00:00:00 2001 From: Kyle M Hall <kyle@bywatersolutions.com> Date: Mon, 22 Dec 2014 05:32:05 -0500 Subject: [PATCH] Bug 11431 [8] - Add audio alerts editor --- Koha/AudioAlert.pm | 79 ++++++++++ Koha/AudioAlerts.pm | 157 ++++++++++++++++++++ Koha/Object.pm | 6 +- Koha/Objects.pm | 6 +- Koha/Template/Plugin/Koha.pm | 7 + admin/audio_alerts.pl | 60 ++++++++ .../intranet-tmpl/prog/en/includes/admin-menu.inc | 1 + .../prog/en/includes/doc-head-close.inc | 33 +---- koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js | 12 -- .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/audio_alerts.tt | 131 ++++++++++++++++ 11 files changed, 452 insertions(+), 42 deletions(-) create mode 100644 Koha/AudioAlert.pm create mode 100644 Koha/AudioAlerts.pm create mode 100755 admin/audio_alerts.pl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt diff --git a/Koha/AudioAlert.pm b/Koha/AudioAlert.pm new file mode 100644 index 0000000..4bedbb9 --- /dev/null +++ b/Koha/AudioAlert.pm @@ -0,0 +1,79 @@ +package Koha::AudioAlert; + +# Copyright ByWater Solutions 2014 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::AudioAlert - Koha Borrower Object class + +=head1 API + +=head2 Class Methods + +=head3 store + +Override base store to set default precedence +if there is not one set already. + +=cut + +sub store { + my ($self) = @_; + + $self->precedence( Koha::AudioAlerts->get_next_precedence() ) unless defined $self->precedence(); + + return $self->SUPER::store(); +} + +=head3 move + +$alert->move('up'); + +Changes the alert's precedence up, down, top, or bottom + +=cut + +sub move { + my ( $self, $where ) = @_; + + return Koha::AudioAlerts->move( { audio_alert => $self, where => $where } ); +} + +=head3 type + +=cut + +sub type { + return 'AudioAlert'; +} + +=head1 AUTHOR + +Kyle M Hall <kyle@bywatersolutions.com> + +=cut + +1; diff --git a/Koha/AudioAlerts.pm b/Koha/AudioAlerts.pm new file mode 100644 index 0000000..1127297 --- /dev/null +++ b/Koha/AudioAlerts.pm @@ -0,0 +1,157 @@ +package Koha::AudioAlerts; + +# Copyright ByWater Solutions 2014 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Carp; + +use Koha::Database; + +use Koha::AudioAlert; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::AudioAlert - Koha Borrower Object class + +=head1 API + +=head2 Class Methods + +=head3 search + +Overrides default search such that +the default ordering is by precedence + +=cut + +sub search { + my ( $self, $params, $attributes ) = @_; + + $attributes->{order_by} ||= 'precedence'; + + return $self->SUPER::search( $params, $attributes ); +} + +=head3 get_next_precedence + +Gets the next precedence value for audio alerts + +=cut + +sub get_next_precedence { + my ($self) = @_; + + return $self->get_last_precedence() + 1; +} + +=head3 get_last_precedence + +Gets the last precedence value for audio alerts + +=cut + +sub get_last_precedence { + my ($self) = @_; + + return $self->_resultset()->get_column('precedence')->max(); +} + +=head3 move + +Koha::AudioAlerts->move( { audio_alert => $audio_alert, where => $where } ); + +Moves the given alert precedence 'up', 'down', 'top' or 'bottom' + +=cut + +sub move { + my ( $self, $params ) = @_; + + my $alert = $params->{audio_alert}; + my $where = $params->{where}; + + return unless ( $alert && $where ); + + if ( $where eq 'up' ) { + unless ( $alert->precedence() == 1 ) { + my ($other) = $self->search( { precedence => $alert->precedence() - 1 } ); + $other->precedence( $alert->precedence() )->store(); + $alert->precedence( $alert->precedence() - 1 )->store(); + } + } + elsif ( $where eq 'down' ) { + unless ( $alert->precedence() == $self->get_last_precedence() ) { + my ($other) = $self->search( { precedence => $alert->precedence() + 1 } ); + $other->precedence( $alert->precedence() )->store(); + $alert->precedence( $alert->precedence() + 1 )->store(); + } + } + elsif ( $where eq 'top' ) { + $alert->precedence(0)->store(); + $self->fix_precedences(); + } + elsif ( $where eq 'bottom' ) { + $alert->precedence( $self->get_next_precedence() )->store(); + $self->fix_precedences(); + } +} + +=head3 fix_precedences + +Koha::AudioAlerts->fix_precedences(); + +Updates precedence numbers to start with 1 +and to have no gaps + +=cut + +sub fix_precedences { + my ($self) = @_; + + my @alerts = $self->search(); + + my $i = 1; + map { $_->precedence( $i++ )->store() } @alerts; +} + +=head3 type + +=cut + +sub type { + return 'AudioAlert'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::AudioAlert'; +} + +=head1 AUTHOR + +Kyle M Hall <kyle@bywatersolutions.com> + +=cut + +1; diff --git a/Koha/Object.pm b/Koha/Object.pm index bc2746f..1be2cf5 100644 --- a/Koha/Object.pm +++ b/Koha/Object.pm @@ -255,7 +255,11 @@ sub AUTOLOAD { # Using direct setter/getter like $item->barcode() or $item->barcode($barcode); if ( grep {/^$method$/} @columns ) { if ( @_ ) { - return $self->_result()->set_column( $method, @_ ); + warn "METHOD: $method"; + warn "VAL: " . $_[0]; + carp "TEST"; + $self->_result()->set_column( $method, @_ ); + return $self; } else { my $value = $self->_result()->get_column( $method ); return $value; diff --git a/Koha/Objects.pm b/Koha/Objects.pm index 5413fb6..6223d89 100644 --- a/Koha/Objects.pm +++ b/Koha/Objects.pm @@ -94,17 +94,17 @@ my @objects = Koha::Objects->search($params); =cut sub search { - my ( $self, $params ) = @_; + my ( $self, $params, $attributes ) = @_; if (wantarray) { - my @dbic_rows = $self->_resultset()->search($params); + my @dbic_rows = $self->_resultset()->search($params, $attributes); return $self->_wrap(@dbic_rows); } else { my $class = ref($self) ? ref($self) : $self; - my $rs = $self->_resultset()->search($params); + my $rs = $self->_resultset()->search($params, $attributes); return $class->_new_from_dbic($rs); } diff --git a/Koha/Template/Plugin/Koha.pm b/Koha/Template/Plugin/Koha.pm index 6b95e3b..3aebee3 100644 --- a/Koha/Template/Plugin/Koha.pm +++ b/Koha/Template/Plugin/Koha.pm @@ -19,6 +19,7 @@ package Koha::Template::Plugin::Koha; use Modern::Perl; use Encode qw( encode ); +use JSON; use base qw( Template::Plugin ); @@ -45,4 +46,10 @@ sub Preference { return encode('UTF-8', C4::Context->preference( $pref ) ); } +sub AudioAlerts { + my $dbh = C4::Context->dbh; + my $audio_alerts = $dbh->selectall_arrayref( 'SELECT * FROM audio_alerts ORDER BY precedence', { Slice => {} } ); + return encode_json($audio_alerts); +} + 1; diff --git a/admin/audio_alerts.pl b/admin/audio_alerts.pl new file mode 100755 index 0000000..f62bacd --- /dev/null +++ b/admin/audio_alerts.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +# Copyright 2014 ByWater Solutions +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; +use C4::Auth; +use C4::Output; +use Koha::AudioAlert; +use Koha::AudioAlerts; + +my $cgi = new CGI; + +my $selector = $cgi->param('selector'); +my $sound = $cgi->param('sound'); +my $id = $cgi->param('id'); +my $action = $cgi->param('action'); +my $where = $cgi->param('where'); +my @delete = $cgi->param('delete'); + +my ( $template, $loggedinuser, $cookie ) = get_template_and_user( + { + template_name => "admin/audio_alerts.tt", + query => $cgi, + type => "intranet", + authnotrequired => 0, + flagsrequired => { parameters => 'parameters_remaining_permissions' }, + debug => 1, + } +); + +if ( $selector && $sound ) { + Koha::AudioAlert->new( { selector => $selector, sound => $sound } )->store(); +} + +map { Koha::AudioAlerts->find($_)->delete() } @delete; + +if ( $id && $action && $where && $action eq 'move' ) { + Koha::AudioAlerts->find($id)->move($where); +} + +$template->param( audio_alerts => scalar Koha::AudioAlerts->search() ); + +output_html_with_http_headers $cgi, $cookie, $template->output; diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc index 281bb54..e38b0b4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/admin-menu.inc @@ -64,6 +64,7 @@ <li><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50/SRU servers</a></li> <li><a href="/cgi-bin/koha/admin/didyoumean.pl">Did you mean?</a></li> <li><a href="/cgi-bin/koha/admin/columns_settings.pl">Columns settings</a></li> + <li><a href="/cgi-bin/koha/admin/audio_alerts.pl">Audio alerts</a></li> </ul> </div> </div> diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc index 77b6381..cfa8254 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/doc-head-close.inc @@ -64,42 +64,23 @@ </script> [% END %] -[% IF AudioAlerts %] +[% IF Koha.Preference('AudioAlerts') %] <script type="text/javascript"> //<![CDATA[ var AUDIO_ALERT_PATH = '[% interface %]/[% theme %]/sound/'; - var AUDIO_ALERT_ACTION = '[% Koha.Preference("OverrideAudioAlertAction") || "opening.ogg" %]'; - var AUDIO_ALERT_WARNING = '[% Koha.Preference("OverrideAudioAlertWarning") || "critical.ogg" %]'; - var AUDIO_ALERT_SUCCESS = '[% Koha.Preference("OverrideAudioAlertSuccess") || "beep.ogg" %]'; - var AUDIO_ALERT_SELECTOR_ACTION = '[% Koha.Preference("AudioAlertSelectorAction") | replace( "'", "\\'" ) %]'; - var AUDIO_ALERT_SELECTOR_WARNING = '[% Koha.Preference("AudioAlertSelectorWarning") | replace( "'", "\\'" ) %]'; - var AUDIO_ALERT_SELECTOR_SUCCESS = '[% Koha.Preference("AudioAlertSelectorSuccess") | replace( "'", "\\'" ) %]'; - var AUDIO_ALERT_SELECTOR_CUSTOM = JSON.parse( '{ [% String.new( Koha.Preference("AudioAlertsCustom") ).collapse | replace( "'", "\\'" ) %] }' ); + var AUDIO_ALERTS = JSON.parse( '[% Koha.AudioAlerts | replace( "'", "\\'" ) %]' ); //]]> $( document ).ready(function() { - var no_sound_played = true; - if ( Object.keys(AUDIO_ALERT_SELECTOR_CUSTOM) ) { - for ( var k in AUDIO_ALERT_SELECTOR_CUSTOM ) { - if ( $(k).length ) { - playSound( AUDIO_ALERT_SELECTOR_CUSTOM[k] ); - no_sound_played = false; + if ( AUDIO_ALERTS ) { + for ( var k in AUDIO_ALERTS ) { + var alert = AUDIO_ALERTS[k]; + if ( $( alert.selector ).length ) { + playSound( alert.sound ); break; } } } - - if ( no_sound_played ) { - if ( $( AUDIO_ALERT_SELECTOR_ACTION ).length ) { - playSoundAction(); - } - else if ( $( AUDIO_ALERT_SELECTOR_WARNING ).length ) { - playSoundWarning(); - } - else if ( $( AUDIO_ALERT_SELECTOR_SUCCESS ).length ) { - playSoundSuccess(); - } - } }); </script> [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js b/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js index e6f03a2..fd0f33e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js @@ -128,15 +128,3 @@ function playSound( sound ) { } document.getElementById("audio-alert").innerHTML = '<audio src="' + sound + '" autoplay="autoplay" autobuffer="autobuffer"></audio>'; } - -function playSoundWarning() { - playSound( AUDIO_ALERT_WARNING ); -} - -function playSoundAction() { - playSound( AUDIO_ALERT_ACTION ); -} - -function playSoundSuccess() { - playSound( AUDIO_ALERT_SUCCESS ); -} diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt index 02bc60a..27068ae 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt @@ -104,6 +104,8 @@ <dd>Choose which plugins to use to suggest searches to patrons and staff.</dd> <dt><a href="/cgi-bin/koha/admin/columns_settings.pl">Configure columns</a></dt> <dd>Hide or show columns for tables.</dd> + <dt><a href="/cgi-bin/koha/admin/audio_alerts.pl">Audio alerts</a></dt> + <dd>Define which events trigger which sounds</dd> </dl> </div> diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt new file mode 100644 index 0000000..a64f9b6 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/audio_alerts.tt @@ -0,0 +1,131 @@ +[% INCLUDE 'doc-head-open.inc' %] +<title>Koha › Administration › Audio alerts</title> +[% INCLUDE 'doc-head-close.inc' %] + +<script type="text/javascript"> +$( document ).ready(function() { + $.ajax({ + //This will retrieve the contents of the folder if the folder is configured as 'browsable' + url: AUDIO_ALERT_PATH, + success: function (data) { + $("#fileNames").html('<ul>'); + //List all png or jpg or gif file names in the page + $(data).find('a:contains("ogg")').each(function () { + var filename = this.href.split('/').pop(); + $('#koha-sounds').append($('<option>', { value : filename }).text(filename)); + }); + } + }); + + $('#koha-sounds').on('change', function() { + $('#sound').val( this.value ); + }); + + $('#koha-sounds').on('change', function() { + $('#sound').val( this.value ); + }); + + $('#play-sound').on('click', function() { + playSound( $('#sound').val() ); + return false; + }); + + $('#new-alert-form').on('submit', function() { + if ( ! $('#selector').val() ) { + alert(_("You must enter a selector!")); + return false; + } else if ( ! $('#sound').val() ) { + alert(_("You must choose a sound!")); + return false; + } else { + return true; + } + }); + + $('#delete-alert-form').on('submit', function() { + return confirm(_("Are you sure you want to delete the selected audio alerts?")); + }); +}); +</script> + +</head> +<body> +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patrons-admin-search.inc' %] + +<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> › Audio alerts</div> + +<div id="doc3" class="yui-t2"> + <div id="bd"> + <div id="yui-main"> + <div class="yui-b"> + <form id="new-alert-form" action="audio_alerts.pl" method="post"> + <fieldset class="form-inline"> + <legend>Add new alert</legend> + + <input id="selector" name="selector" type="text" class="input-large" placeholder="selector" /> + <input id="sound" name="sound" type="text" class="input-large" placeholder="sound" /> + + <button id="play-sound" class="btn"><i class="icon-play"></i> Play sound</button> + + <br/> + + <select id="koha-sounds"> + <option value="">Select built-in sound</option> + </select> + + <button id="save-alert" type="submit" class="btn"><i class="icon-hdd"></i> Save alert</button> + </fieldset> + </form> + + <form id="delete-alert-form" action="audio_alerts.pl" method="post"> + <table> + <thead> + <tr> + <th> </th> + <th>Precedence</th> + <th> </th> + <th>Selector</th> + <th>Sound</th> + </tr> + </thead> + + <tbody> + [% FOREACH a IN audio_alerts %] + <tr> + <td><input type="checkbox" name="delete" value="[% a.id %]" /></td> + <td>[% a.precedence %]</td> + <td style="white-space:nowrap;"> + <a title="Move alert up" href="audio_alerts.pl?action=move&where=up&id=[% a.id %]"> + <img src="[% interface %]/[% theme %]/img/go-up.png" border="0" alt="Go up" /> + </a> + + <a title="Move alert to top" href="audio_alerts.pl?action=move&where=top&id=[% a.id %]"> + <img src="[% interface %]/[% theme %]/img/go-top.png" border="0" alt="Go top" /> + </a> + + <a title="Move alert to bottom" href="audio_alerts.pl?action=move&where=bottom&id=[% a.id %]"> + <img src="[% interface %]/[% theme %]/img/go-bottom.png" border="0" alt="Go bottom" /> + </a> + + <a title="Move alert down" href="audio_alerts.pl?action=move&where=down&id=[% a.id %]"> + <img src="[% interface %]/[% theme %]/img/go-down.png" border="0" alt="Go down" /> + </a> + </td> + <td>[% a.selector %]</td> + <td>[% a.sound %]</td> + </tr> + [% END %] + </tbody> + </table> + + <p/> + <button id="delete-alerts" type="submit" class="btn"><i class="icon-trash"></i> Delete selected alerts</button> + </form> + </div> + </div> + <div class="yui-b"> +[% INCLUDE 'admin-menu.inc' %] +</div> +</div> +[% INCLUDE 'intranet-bottom.inc' %] -- 1.7.2.5