From b2886b930529fa36cee80318294afa3165ba601e Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Mon, 22 Dec 2014 05:58:48 -0500 Subject: [PATCH] Bug 11431 - Add additional sound options This patch set replaces and extends Koha's current sound options. This is implemented be removing the existing sound system, and re-engineering using a table of selector/sound combinations such that the highest precedence selector that is found in the DOM will trigger and audio alert. The existing audio behaviors are implemented as a set of default audio alerts. Test Plan: 1) Apply this patch set 2) Run updatedatabase.pl 3) Enable the AudioAlerts system preference 4) Test existing sounds 5) Enter the new alerts editor in the admin section 6) Add a new audo alert with the following selector: "body:contains('Check in message')", choose any sound alert you wish, make sure it's not one of the 3 sounds already used! Make this selector precedence 1 4) Browse to the checkins page, you should hear the default sound 5) Attempt to return an invalid barcode, you should hear your custom sound! --- 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 ++++++++ circ/circulation.pl | 2 +- circ/returns.pl | 2 +- .../intranet-tmpl/prog/en/includes/admin-menu.inc | 1 + .../prog/en/includes/doc-head-close.inc | 54 +++++-- .../prog/en/includes/intranet-bottom.inc | 1 + koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js | 8 + .../prog/en/modules/admin/admin-home.tt | 2 + .../prog/en/modules/admin/audio_alerts.tt | 131 ++++++++++++++++ .../en/modules/admin/preferences/circulation.pref | 7 - .../en/modules/admin/preferences/staff_client.pref | 6 + .../prog/en/modules/circ/circulation.tt | 15 +-- .../intranet-tmpl/prog/en/modules/circ/returns.tt | 41 +---- .../prog/en/modules/help/admin/audio_alerts.tt | 29 ++++ 19 files changed, 544 insertions(+), 70 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 create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/help/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 + +=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 + +=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/circ/circulation.pl b/circ/circulation.pl index 6e9f449..219e917 100755 --- a/circ/circulation.pl +++ b/circ/circulation.pl @@ -597,7 +597,7 @@ $template->param( inprocess => $inprocess, is_child => ($borrowernumber && $borrower->{'category_type'} eq 'C'), circview => 1, - soundon => C4::Context->preference("SoundOn"), + AudioAlerts => C4::Context->preference("AudioAlerts"), fast_cataloging => $fast_cataloging, CircAutoPrintQuickSlip => C4::Context->preference("CircAutoPrintQuickSlip"), activeBorrowerRelationship => (C4::Context->preference('borrowerRelationship') ne ''), diff --git a/circ/returns.pl b/circ/returns.pl index adc2f1e..f3045a1 100755 --- a/circ/returns.pl +++ b/circ/returns.pl @@ -591,7 +591,7 @@ $template->param( dropboxmode => $dropboxmode, dropboxdate => output_pref($dropboxdate), overduecharges => $overduecharges, - soundon => C4::Context->preference("SoundOn"), + AudioAlerts => C4::Context->preference("AudioAlerts"), BlockReturnOfWithdrawnItems => C4::Context->preference("BlockReturnOfWithdrawnItems"), ); 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 @@
  • Z39.50/SRU servers
  • Did you mean?
  • Columns settings
  • +
  • Audio alerts
  • 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 f6269de..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 @@ -1,13 +1,15 @@ +[% USE Koha %] +[% USE String %] + [% INCLUDE intranetstylesheet.inc %] -[% IF ( bidi ) %] - -[% END %] +[% IF ( bidi ) %][% END %] [% IF ( IntranetUserCSS ) %][% END %] + @@ -22,14 +24,17 @@ + [% INCLUDE 'validator-strings.inc' %] + [% IF ( intranetuserjs ) %] [% END %] + [% IF ( virtualshelves || intranetbookbag ) %] - + + [% END %] + [% IF LocalCoverImages %] - - + + +[% END %] + +[% IF Koha.Preference('AudioAlerts') %] + [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc index d937656..f9103ce 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/intranet-bottom.inc @@ -65,5 +65,6 @@ [% END %] [% 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 5b086f1..fd0f33e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js +++ b/koha-tmpl/intranet-tmpl/prog/en/js/staff-global.js @@ -120,3 +120,11 @@ function toUC(f) { function confirmDelete(message) { return (confirm(message) ? true : false); } + +function playSound( sound ) { + // This is way faster than substring + if ( ! ( sound.charAt(4) == ':' && sound.charAt(5) == '/' && sound.charAt(6) == '/' ) ) { + sound = AUDIO_ALERT_PATH + sound; + } + document.getElementById("audio-alert").innerHTML = ''; +} 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 @@
    Choose which plugins to use to suggest searches to patrons and staff.
    Configure columns
    Hide or show columns for tables.
    +
    Audio alerts
    +
    Define which events trigger which sounds
    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' %] +Koha › Administration › Audio alerts +[% INCLUDE 'doc-head-close.inc' %] + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'patrons-admin-search.inc' %] + + + +
    +
    +
    +
    +
    +
    + Add new alert + + + + + + +
    + + + + +
    +
    + +
    + + + + + + + + + + + + + [% FOREACH a IN audio_alerts %] + + + + + + + + [% END %] + +
     Precedence SelectorSound
    [% a.precedence %] + + Go up + + + + Go top + + + + Go bottom + + + + Go down + + [% a.selector %][% a.sound %]
    + +

    + +

    +
    +
    +
    +[% INCLUDE 'admin-menu.inc' %] +
    +
    +[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index a296bf6..32300e3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -40,12 +40,6 @@ Circulation: desc: latest to earliest - due date. - - - pref: soundon - choices: - yes: "Enable" - no: "Don't enable" - - circulation sounds during checkin and checkout in the staff interface. Not supported by all web browsers yet. - - - pref: SpecifyDueDate choices: yes: Allow @@ -693,7 +687,6 @@ Circulation: yes: Show no: "Don't show" - "the print receipt popup dialog when self checkout is finished" - Course Reserves: - - pref: UseCourseReserves diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref index 0cbaee0..d14d207 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_client.pref @@ -128,3 +128,9 @@ Staff Client: yes: Enable no: Disable - item selection in record detail page. + - + - pref: AudioAlerts + choices: + yes: "Enable" + no: "Don't enable" + - audio alerts for events defined in the audio alerts section of administration. diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt index 6963c90..17f1faf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt @@ -172,7 +172,7 @@ $(document).ready(function() { [% IF ( NEEDSCONFIRMATION ) %]
    -
    +
    [% IF CAN_user_circulate_force_checkout %]

    Please confirm checkout

    [% ELSE %] @@ -345,12 +345,8 @@ $(document).ready(function() { [% IF ( IMPOSSIBLE ) %] -[% IF ( soundon ) %] - -[% END %] -
    -
    +
      [% IF ( STATS ) %] @@ -462,15 +458,12 @@ $(document).ready(function() {
    [% ELSE %] -[% IF ( soundon ) %] - -[% END %] - [% IF (forceallow) %]
    Restriction overridden temporarily
    [% END %] +[% END %] - [% END %] + [% IF ( issued ) %]

    Item checked out

    diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt index 3fe2e53..96389d0 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt @@ -89,6 +89,7 @@ $(document).ready(function () { + [% INCLUDE 'header.inc' %] [% INCLUDE 'checkin-search.inc' %] @@ -174,11 +175,7 @@ $(document).ready(function () { [% IF ( waiting ) %] -[% IF ( soundon ) %] - -[% END %] - -
    +

    Hold found (item is already waiting): [% title |html %]

    [% IF ( reservenotes ) %]

    Notes: [% reservenotes %]

    [% END %]

    Hold for:

    @@ -220,10 +217,7 @@ $(document).ready(function () { [% IF ( diffbranch ) %] - [% IF ( soundon ) %] - - [% END %] -
    +

    Hold needing transfer found: [% title |html %]

    Hold for:

      @@ -263,20 +257,14 @@ $(document).ready(function () { [% IF ( transfer ) %] -
      +

      Please return [% title or "item" |html %] to [% homebranchname %]
      ( Print slip )

      - [% IF ( soundon ) %] - - [% END %] [% END %] [% IF ( needstransfer ) %] - [% IF ( soundon ) %] - - [% END %] -

      This item needs to be transferred to [% homebranchname %]

      +

      This item needs to be transferred to [% homebranchname %]

      Transfer now?
      [% IF itemnumber %] @@ -301,10 +289,7 @@ $(document).ready(function () { [% IF ( diffbranch ) %] - [% IF ( soundon ) %] - - [% END %] -

      Item consigned:

      +

      Item consigned:

      @@ -333,11 +318,7 @@ $(document).ready(function () { [% IF ( reserved ) %] - [% IF ( soundon ) %] - - [% END %] - -
      +

      Hold found: [% title |html %]

      [% IF ( reservenotes ) %]

      Notes: [% reservenotes %]

      [% END %]
      Hold for:
      @@ -385,7 +366,7 @@ $(document).ready(function () { [% END %] [% IF ( errmsgloop ) %] -
      +

      Check in message

      [% FOREACH errmsgloo IN errmsgloop %] [% IF ( errmsgloo.NotForLoanStatusUpdated ) %] @@ -444,13 +425,7 @@ $(document).ready(function () { [% END %] [% END %] -[% IF ( soundon ) %] - -[% END %] [% ELSE %] -[% IF ( soundon ) %] - -[% END %] [% END %]
      diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt new file mode 100644 index 0000000..eccae8b --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/help/admin/audio_alerts.tt @@ -0,0 +1,29 @@ +[% INCLUDE 'help-top.inc' %] + +

      Audio alerts

      + +

      This section of Koha lets you specify a given sound to play when a given jQuery selector is matched.

      + +

      Adding a new alert

      + +

      To add a new alert:

      + +
        +
      • Locate the "Add new alert" form.
      • +
      • Enter a selector in the "selector" input, you can see documentation on jQuery selectors here. +
      • Enter a sound to be played, you can either select a built-in Koha sound using the pulldown selector, or you can enter a full URL to a sound file on another server
      • +
      • At this point, you can preview your sound by clicking the "Play sound" button
      • +
      • Click "Save alert" and your done!
      • +
      + +

      Sound precedence

      + +

      Sounds will be played in order from top to bottom. That is, the first select that finds a match will have its sound played.

      + +

      To change the precedence of a given alert, use the four arrows to move it up, down, or to the top or bottom of the list. + +

      Deleting alerts

      + +

      To delete one or more alerts, check the checkboxes for those alerts you wish to delete, then click the "Delete selected alerts" button and confirm you want to delete those alerts. + +[% INCLUDE 'help-bottom.inc' %] -- 1.7.2.5

      [% title |html %]