Revision 4a663bf8
Von Tamino Steinert vor etwa 2 Monaten hinzugefügt
SL/ClientJS.pm | ||
---|---|---|
use Rose::Object::MakeMethods::Generic
|
||
(
|
||
scalar => [ qw() ],
|
||
'scalar --get_set_init' => [ qw(controller _actions _flash _flash_detail _no_flash_clear _error) ],
|
||
'scalar --get_set_init' => [ qw(controller _actions _error) ],
|
||
);
|
||
|
||
my %supported_methods = (
|
||
... | ... | |
redirect_to => 1, # window.location.href = <TARGET>
|
||
save_file => 4, # kivi.save_file(<TARGET>, <ARGS>)
|
||
|
||
flash => 2, # kivi.display_flash(<TARGET>, <ARGS>)
|
||
flash_detail => 2, # kivi.display_flash_detail(<TARGET>, <ARGS>)
|
||
clear_flash => 2, # kivi.clear_flash(<TARGET>, <ARGS>)
|
||
# flash
|
||
flash => -2, # kivi.Flash.display_flash.apply({}, action.slice(1, action.length))
|
||
clear_flash => 0, # kivi.Flash.clear_flash()
|
||
show_flash => 0, # kivi.Flash.show()
|
||
hide_flash => 0, # kivi.Flash.hide()
|
||
|
||
reinit_widgets => 0, # kivi.reinit_widgets()
|
||
run => -1, # kivi.run(<TARGET>, <ARGS>)
|
||
run_once_for => 3, # kivi.run_once_for(<TARGET>, <ARGS>)
|
||
... | ... | |
return [];
|
||
}
|
||
|
||
sub init__flash {
|
||
return {};
|
||
}
|
||
|
||
sub init__flash_detail {
|
||
return {};
|
||
}
|
||
|
||
sub init__error {
|
||
return '';
|
||
}
|
||
|
||
sub init__no_flash_clear {
|
||
return '';
|
||
}
|
||
|
||
sub to_json {
|
||
my ($self) = @_;
|
||
|
||
return SL::JSON::to_json({ error => $self->_error }) if $self->_error;
|
||
return SL::JSON::to_json({ no_flash_clear => $self->_no_flash_clear, eval_actions => $self->_actions });
|
||
return SL::JSON::to_json({ eval_actions => $self->_actions });
|
||
}
|
||
|
||
sub to_array {
|
||
... | ... | |
return $self;
|
||
}
|
||
|
||
sub flash {
|
||
my ($self, $type, @messages) = @_;
|
||
|
||
my $message = join ' ', grep { $_ } @messages;
|
||
|
||
if (!$self->_flash->{$type}) {
|
||
$self->_flash->{$type} = [ 'flash', $type, $message ];
|
||
push @{ $self->_actions }, $self->_flash->{$type};
|
||
} else {
|
||
$self->_flash->{$type}->[-1] .= ' ' . $message;
|
||
}
|
||
|
||
return $self;
|
||
}
|
||
|
||
sub flash_detail {
|
||
my ($self, $type, @messages) = @_;
|
||
|
||
my $message = join '<br>', grep { $_ } @messages;
|
||
|
||
if (!$self->_flash_detail->{$type}) {
|
||
$self->_flash_detail->{$type} = [ 'flash_detail', $type, $message ];
|
||
push @{ $self->_actions }, $self->_flash_detail->{$type};
|
||
} else {
|
||
$self->_flash_detail->{$type}->[-1] .= ' ' . $message;
|
||
}
|
||
|
||
return $self;
|
||
}
|
||
|
||
sub no_flash_clear{
|
||
my ($self) = @_;
|
||
$self->_no_flash_clear('1');
|
||
return $self;
|
||
$_[0]; # noop for compatibility
|
||
}
|
||
|
||
sub error {
|
||
... | ... | |
|
||
=over 4
|
||
|
||
=item C<flash $type, $message>
|
||
|
||
Display a C<$message> in the flash of type C<$type>. Multiple calls of
|
||
C<flash> on the same C<$self> will be merged by type.
|
||
|
||
On the client side the flashes of all types will be cleared after each
|
||
successful ClientJS call that did not end with C<$js-E<gt>error(...)>.
|
||
This clearing can be switched of by the function C<no_flash_clear>
|
||
|
||
=item C<flash_detail $type, $message>
|
||
|
||
Display a detailed message C<$message> in the flash of type C<$type>. Multiple calls of
|
||
C<flash_detail> on the same C<$self> will be merged by type.
|
||
So the flash message can be hold short and the visibility of details can toggled by the user.
|
||
|
||
=item C<no_flash_clear>
|
||
=item C<flash $type, $message [, $details [, timestamp ]]>
|
||
|
||
No automatic clearing of flash after successful ClientJS call
|
||
Display a C<$message> in the flash of type C<$type> with optional
|
||
C<$details>.
|
||
|
||
=item C<error $message>
|
||
|
SL/Controller/Flash.pm | ||
---|---|---|
package SL::Controller::Flash;
|
||
|
||
use strict;
|
||
use parent qw(SL::Controller::Base);
|
||
|
||
use SL::Helper::Flash;
|
||
|
||
sub action_reload {
|
||
my ($self) = @_;
|
||
|
||
$self->js->clear_flash;
|
||
$self->js->flash(@$_) for SL::Helper::Flash::flash_contents;
|
||
$self->js->show_flash;
|
||
$self->js->render;
|
||
}
|
||
|
||
1;
|
||
|
||
__END__
|
||
|
||
=encoding utf-8
|
||
|
||
=head1 NAME
|
||
|
||
SL::Controller::Flash - Flash actions
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
This controller contains actions that can be used to reload and control client
|
||
side flash messages
|
||
|
||
=head1 BUGS
|
||
|
||
None yet :)
|
||
|
||
=head1 AUTHOR
|
||
|
||
Sven Schöling E<lt>sven.schoeling@opendynamic.deE<gt>
|
||
|
||
=cut
|
SL/Helper/Flash.pm | ||
---|---|---|
require Exporter;
|
||
our @ISA = qw(Exporter);
|
||
our @EXPORT = qw(flash flash_later);
|
||
our @EXPORT_OK = qw(render_flash delay_flash);
|
||
our @EXPORT_OK = qw(delay_flash);
|
||
|
||
my %valid_categories = (
|
||
map({$_ => 'info'} qw(information message)),
|
||
... | ... | |
$::auth->set_session_value({ key => "FLASH", value => _store_flash($::auth->get_session_value('FLASH'), @_), auto_restore => 1 });
|
||
}
|
||
|
||
sub delay_flash {
|
||
my $store = $::form->{FLASH} || { };
|
||
flash_later($_ => @{ $store->{$_} || [] }) for keys %$store;
|
||
sub flash_contents {
|
||
return unless $::form;
|
||
return unless $::form->{FLASH};
|
||
return unless 'ARRAY' eq ref $::form->{FLASH};
|
||
|
||
@{ $::form->{FLASH} }
|
||
}
|
||
|
||
sub render_flash {
|
||
return $::form->parse_html_template('common/flash');
|
||
sub delay_flash {
|
||
my $store = $::form->{FLASH} || [];
|
||
flash_later(@{ $_ || [] }) for @$store;
|
||
}
|
||
|
||
#
|
||
... | ... | |
#
|
||
|
||
sub _store_flash {
|
||
my $store = shift || { };
|
||
my $category = _check_category(+shift);
|
||
my ($store, $type, $message, $details, $timestamp) = @_;
|
||
$store //= [ ];
|
||
$timestamp //= time();
|
||
my $category = _check_category($type);
|
||
|
||
$store->{ $category } ||= [ ];
|
||
push @{ $store->{ $category } }, @_;
|
||
push @{ $store }, [ $type, $message, $details, $timestamp ];
|
||
|
||
return $store;
|
||
}
|
||
... | ... | |
|
||
=head1 SYNOPSIS
|
||
|
||
use SL::Helper::Flash qw(flash flash_later delay_flash);
|
||
|
||
# display in this request
|
||
flash('info', 'Customer saved!');
|
||
flash('error', 'Something went wrong', "details about what went wrong");
|
||
flash('warning', 'this might not be a good idea');
|
||
|
||
# display after a redirect
|
||
flash_later('info', 'Customer saved!');
|
||
flash_later('error', 'Something went wrong', "details about what went wrong");
|
||
flash_later('warning', 'this might not be a good idea');
|
||
|
||
# delay flash() calls to next request:
|
||
delay_flash();
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
The flash is a store for messages that should be displayed to the
|
||
user. Each message has a category which is usually C<information>,
|
||
C<warning> or C<error>. The messages in each category are grouped and
|
||
displayed in colors appropriate for their severity (e.g. errors in
|
||
red).
|
||
|
||
Messages are rendered either by calling the function C<render_flash>
|
||
or by including the flash sub-template from a template with the
|
||
following code:
|
||
|
||
[%- INCLUDE 'common/flash.html' %]
|
||
Messages are rendered by including the L<SL::Layout::Flash> sub layout.
|
||
|
||
=head1 EXPORTS
|
||
|
||
The functions L</flash> and L</flash_later> are always exported.
|
||
|
||
The function L</render_flash> is only exported upon request.
|
||
|
||
=head1 FUNCTIONS
|
||
|
||
=over 4
|
||
|
||
=item C<flash $category, @messages>
|
||
=item C<flash $category, $message [, $details ]>
|
||
|
||
Stores messages for the given category. The category can be either
|
||
C<information>, C<warning> or C<error>. C<info> can also be used as an
|
||
alias for C<information>.
|
||
Store a message with optional details for the given category. The category can
|
||
be either C<information>, C<warning> or C<error>. C<info> can also be used as
|
||
an alias for C<information>.
|
||
|
||
=item C<flash_later $category, @messages>
|
||
=item C<flash_later $category, $message [, $details ]>
|
||
|
||
Stores messages for the given category for the next request. The
|
||
category can be either C<information>, C<warning> or C<error>. C<info>
|
||
can also be used as an alias for C<information>.
|
||
Store a message with optional details for the given category for the next
|
||
request. The category can be either C<information>, C<warning> or C<error>.
|
||
C<info> can also be used as an alias for C<information>.
|
||
|
||
The messages are stored in the user's session and restored upon the
|
||
The message is stored in the user's session and restored upon the
|
||
next request. Can be used for transmitting information over HTTP
|
||
redirects.
|
||
|
||
=item C<render_flash>
|
||
|
||
Outputs the flash message by parsing the C<common/flash.html> template
|
||
file.
|
||
|
||
This function is not exported by default.
|
||
|
||
=item C<delay_flash>
|
||
|
||
Delays flash, as if all flash messages in this request would have been
|
||
... | ... | |
|
||
Not exported by default.
|
||
|
||
=item C<flash_contents>
|
||
|
||
The contents of the current flash accumulator.
|
||
|
||
=back
|
||
|
||
=head1 AUTHOR
|
SL/Layout/Admin.pm | ||
---|---|---|
use SL::Layout::None;
|
||
use SL::Layout::Top;
|
||
use SL::Layout::CssMenu;
|
||
use SL::Layout::Flash;
|
||
|
||
sub init_sub_layouts {
|
||
$_[0]->sub_layouts_by_name->{flash} = SL::Layout::Flash->new;
|
||
|
||
[
|
||
SL::Layout::None->new,
|
||
SL::Layout::CssMenu->new(menu => SL::Menu->new('admin')),
|
||
$_[0]->sub_layouts_by_name->{flash},
|
||
]
|
||
}
|
||
|
SL/Layout/Classic.pm | ||
---|---|---|
use SL::Layout::None;
|
||
use SL::Layout::Split;
|
||
use SL::Layout::ActionBar;
|
||
use SL::Layout::Flash;
|
||
use SL::Layout::Content;
|
||
|
||
sub init_sub_layouts {
|
||
$_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
|
||
$_[0]->sub_layouts_by_name->{flash} = SL::Layout::Flash->new;
|
||
|
||
[
|
||
SL::Layout::None->new,
|
||
SL::Layout::Top->new,
|
||
SL::Layout::Split->new(
|
||
left => [ SL::Layout::MenuLeft->new ],
|
||
right => [ $_[0]->sub_layouts_by_name->{actionbar}, SL::Layout::Content->new ],
|
||
right => [
|
||
$_[0]->sub_layouts_by_name->{actionbar},
|
||
$_[0]->sub_layouts_by_name->{flash},
|
||
SL::Layout::Content->new,
|
||
],
|
||
)
|
||
]
|
||
}
|
SL/Layout/Flash.pm | ||
---|---|---|
package SL::Layout::Flash;
|
||
|
||
use strict;
|
||
use parent qw(SL::Layout::Base);
|
||
use SL::Presenter::EscapedText qw(escape_js);
|
||
use SL::Helper::Flash;
|
||
|
||
sub pre_content {
|
||
'<div style="position:relative"><div id="layout_flash_container"></div></div>'
|
||
}
|
||
|
||
sub javascripts_inline {
|
||
my ($self) = @_;
|
||
|
||
my $js = '';
|
||
|
||
for (SL::Helper::Flash::flash_contents()) {
|
||
next if $_->[3] + 60 < time(); # ignore entries from more than one minute ago
|
||
$js .= defined $_->[2]
|
||
? sprintf("kivi.Flash.display_flash('%s', '%s', '%s');", map { escape_js($_) } @$_[0,1,2] )
|
||
: sprintf("kivi.Flash.display_flash('%s', '%s');", map { escape_js($_) } @$_[0,1] );
|
||
}
|
||
|
||
$js;
|
||
}
|
||
|
||
sub static_javascripts {
|
||
'kivi.Flash.js'
|
||
}
|
||
|
||
|
||
1;
|
SL/Layout/Javascript.pm | ||
---|---|---|
use SL::Layout::DHTMLMenu;
|
||
use SL::Layout::Top;
|
||
use SL::Layout::ActionBar;
|
||
use SL::Layout::Flash;
|
||
use SL::Layout::Content;
|
||
|
||
use List::Util qw(max);
|
||
... | ... | |
|
||
sub init_sub_layouts {
|
||
$_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
|
||
$_[0]->sub_layouts_by_name->{flash} = SL::Layout::Flash->new;
|
||
[
|
||
SL::Layout::None->new,
|
||
SL::Layout::Top->new,
|
||
SL::Layout::DHTMLMenu->new,
|
||
$_[0]->sub_layouts_by_name->{actionbar},
|
||
$_[0]->sub_layouts_by_name->{flash},
|
||
SL::Layout::Content->new,
|
||
]
|
||
}
|
SL/Layout/Material.pm | ||
---|---|---|
use SL::Layout::None;
|
||
use SL::Layout::MaterialMenu;
|
||
use SL::Layout::MaterialStyle;
|
||
use SL::Layout::Flash;
|
||
use SL::Layout::Content;
|
||
|
||
sub get_stylesheet_for_user {
|
||
... | ... | |
SL::Layout::None->new,
|
||
SL::Layout::MaterialStyle->new,
|
||
SL::Layout::MaterialMenu->new,
|
||
SL::Layout::Flash->new,
|
||
SL::Layout::Content->new,
|
||
]
|
||
}
|
SL/Layout/V3.pm | ||
---|---|---|
use SL::Layout::Top;
|
||
use SL::Layout::CssMenu;
|
||
use SL::Layout::ActionBar;
|
||
use SL::Layout::Flash;
|
||
use SL::Layout::Content;
|
||
|
||
sub init_sub_layouts {
|
||
$_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
|
||
$_[0]->sub_layouts_by_name->{flash} = SL::Layout::Flash->new;
|
||
|
||
[
|
||
SL::Layout::None->new,
|
||
SL::Layout::Top->new,
|
||
SL::Layout::CssMenu->new,
|
||
$_[0]->sub_layouts_by_name->{actionbar},
|
||
$_[0]->sub_layouts_by_name->{flash},
|
||
SL::Layout::Content->new,
|
||
]
|
||
}
|
css/kivitendo/main.css | ||
---|---|---|
font-weight: bold;
|
||
}
|
||
|
||
/* Flash message */
|
||
#layout_flash_container {
|
||
position: absolute;
|
||
z-index: 200;
|
||
right: 20px;
|
||
min-width: 30%;
|
||
animation: fadein .5s;
|
||
}
|
||
@keyframes hop {
|
||
to { transform: scale(1.01); }
|
||
}
|
||
@keyframes flash {
|
||
from { background-color: black }
|
||
}
|
||
@keyframes fadein {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
.layout-flash-message {
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
padding: 5px;
|
||
border-width: 1px;
|
||
border-style: solid;
|
||
/* animation: .5s ease-out .2s 1 normal none running flash;*/
|
||
}
|
||
.layout-flash-body{
|
||
padding-top:5px;
|
||
margin-top:5px;
|
||
border-top: 1px dotted black;
|
||
}
|
||
.layout-flash-timestamp{
|
||
opacity: 0.75;
|
||
}
|
||
.layout-flash-details::before {
|
||
content: ': ';
|
||
}
|
||
.layout-flash-type {
|
||
font-weight: bold;
|
||
float: right;
|
||
}
|
||
.layout-flash-error {
|
||
background-color: #FFD6D6;
|
||
border-color: #AE0014;
|
||
}
|
||
.layout-flash-ok {
|
||
background-color: #ADFFB6;
|
||
border-color: #007F0F;
|
||
}
|
||
.layout-flash-warning {
|
||
background-color: #FFE8C7;
|
||
border-color: #FF6600;
|
||
}
|
||
.layout-flash-info {
|
||
background-color: #DCF2FF;
|
||
border-color: #4690FF;
|
||
}
|
||
.layout-flash-title {
|
||
font-weight: bold;
|
||
}
|
||
.layout-flash-remove {
|
||
padding-right: 4px;
|
||
}
|
||
|
||
|
||
/* Admin section: the menu itself doesn't occupy space. So make room
|
||
at the top of the div covering the whole admin area. */
|
||
body > div.admin {
|
js/client_js.js | ||
---|---|---|
// SL/ClientJS.pm for instructions.
|
||
|
||
namespace("kivi", function(ns) {
|
||
ns.display_flash = function(type, message, noscroll) {
|
||
$('#flash_' + type + '_content').text(message);
|
||
$('#flash_' + type).show();
|
||
if (!noscroll && $('#frame-header')[0]) {
|
||
$('#frame-header')[0].scrollIntoView();
|
||
}
|
||
};
|
||
|
||
ns.display_flash_detail = function(type, message) {
|
||
$('#flash_' + type + '_detail').html(message);
|
||
$('#flash_' + type + '_disp').show();
|
||
};
|
||
|
||
ns.clear_flash = function(category , timeout) {
|
||
window.setTimeout(function(){
|
||
$('#flash_' + category).hide();
|
||
$('#flash_detail_' + category).hide();
|
||
$('#flash_' + category + '_disp').hide();
|
||
$('#flash_' + category + '_content').empty();
|
||
$('#flash_' + category + '_detail').empty();
|
||
}, timeout);
|
||
};
|
||
|
||
ns.eval_json_result = function(data) {
|
||
if (!data)
|
||
return;
|
||
|
||
if (data.error)
|
||
return ns.display_flash('error', data.error);
|
||
if (data.error && ns.Flash)
|
||
return ns.Flash.display_flash('error', data.error);
|
||
|
||
if (!data.no_flash_clear) {
|
||
$(['info', 'warning', 'error']).each(function(idx, category) {
|
||
$('#flash_' + category).hide();
|
||
$('#flash_detail_' + category).hide();
|
||
$('#flash_' + category + '_disp').hide();
|
||
$('#flash_' + category + '_content').empty();
|
||
$('#flash_' + category + '_detail').empty();
|
||
});
|
||
}
|
||
if ((data.js || '') !== '')
|
||
// jshint -W061
|
||
eval(data.js);
|
||
... | ... | |
// ## other stuff ##
|
||
else if (action[0] == 'redirect_to') window.location.href = action[1];
|
||
else if (action[0] == 'save_file') kivi.save_file(action[1], action[2], action[3], action[4]);
|
||
else if (action[0] == 'flash') kivi.display_flash(action[1], action[2]);
|
||
else if (action[0] == 'flash_detail') kivi.display_flash_detail(action[1], action[2]);
|
||
else if (action[0] == 'clear_flash') kivi.clear_flash(action[1], action[2]);
|
||
|
||
// flash
|
||
else if (action[0] == 'flash') kivi.Flash.display_flash.apply({}, action.slice(1, action.length));
|
||
else if (action[0] == 'clear_flash') kivi.Flash.clear_flash();
|
||
else if (action[0] == 'show_flash') kivi.Flash.show();
|
||
else if (action[0] == 'hide_flash') kivi.Flash.hide();
|
||
else if (action[0] == 'reinit_widgets') kivi.reinit_widgets();
|
||
else if (action[0] == 'run') kivi.run(action[1], action.slice(2, action.length));
|
||
else if (action[0] == 'run_once_for') kivi.run_once_for(action[1], action[2], action[3]);
|
js/kivi.Flash.js | ||
---|---|---|
namespace("kivi.Flash", function(ns) {
|
||
"use strict";
|
||
|
||
ns.type_to_title = {
|
||
error: kivi.t8('Error'),
|
||
warning: kivi.t8('Warning'),
|
||
info: kivi.t8('Information'),
|
||
ok: kivi.t8('Ok')
|
||
};
|
||
|
||
ns.display_flash = function(type, message, details, timestamp) {
|
||
let $dom = $('<div>');
|
||
$dom.addClass('layout-flash-' + type);
|
||
$dom.addClass('layout-flash-message');
|
||
|
||
let $header = $('<div>');
|
||
$header.addClass('layout-flash-header');
|
||
|
||
let $remove = $('<span>✘</span>');
|
||
$remove.addClass('layout-flash-remove').addClass('cursor-pointer');
|
||
$remove.attr('alt', kivi.t8('Close Flash'));
|
||
$header.append($remove);
|
||
|
||
if (timestamp === undefined) {
|
||
timestamp = new Date();
|
||
} else if (timestamp > 0) {
|
||
timestamp = new Date(timestamp * 1000);
|
||
}
|
||
|
||
let $time = $('<span>');
|
||
$time.addClass('layout-flash-timestamp');
|
||
$time.text(kivi.format_time(timestamp));
|
||
$header.append($time);
|
||
|
||
let $type = $('<span>');
|
||
$type.addClass('layout-flash-type');
|
||
$type.text(ns.type_to_title[type]);
|
||
$header.append($type);
|
||
|
||
let $body = $('<div>');
|
||
$body.addClass('layout-flash-body');
|
||
|
||
if (message !== undefined && message !== null) {
|
||
let $message = $('<span>');
|
||
$message.addClass('layout-flash-content');
|
||
$message.html(message);
|
||
$body.append($message);
|
||
}
|
||
|
||
if (details !== undefined && details !== null) {
|
||
let $details = $('<span>');
|
||
$details.addClass('layout-flash-details');
|
||
$details.html(details);
|
||
$body.append($details);
|
||
}
|
||
|
||
$dom.append($header);
|
||
$dom.append($body);
|
||
|
||
$("#layout_flash_container").append($dom);
|
||
|
||
// fadeout after 1min
|
||
$dom.delay(60000).fadeOut('slow');
|
||
|
||
ns.show();
|
||
};
|
||
|
||
ns.display_flash_detail = function(type, message) {
|
||
$('#flash_' + type + '_disp').show();
|
||
};
|
||
|
||
ns.clear_flash = function(category, timeout) {
|
||
if (timeout === undefined) {
|
||
ns.clear_flash_now(category);
|
||
} else {
|
||
window.setTimeout(function(){
|
||
ns.clear_flash_now(category);
|
||
}, timeout);
|
||
}
|
||
};
|
||
|
||
ns.clear_flash_now = function(category) {
|
||
if (category) {
|
||
$('div.layout-flash-' + category).remove();
|
||
} else {
|
||
$('div.layout-flash-message').remove();
|
||
}
|
||
};
|
||
|
||
ns.remove_entry = function(e) {
|
||
$(e.target).closest('div.layout-flash-message').remove();
|
||
};
|
||
|
||
ns.toggle = function() {
|
||
$('#layout_flash_container').toggle();
|
||
};
|
||
ns.show = function() {
|
||
$('#layout_flash_container').show();
|
||
};
|
||
ns.hide = function() {
|
||
$('#layout_flash_container').hide();
|
||
};
|
||
ns.reload_flash = function() {
|
||
$.get("controller.pl", { action: "Flash/reload" }, kivi.eval_json_result);
|
||
};
|
||
|
||
ns.reinit_widgets = function() {
|
||
|
||
};
|
||
});
|
||
|
||
$(function() {
|
||
"use strict";
|
||
// dispatch to kivi.Flash for compatibility
|
||
kivi.display_flash = kivi.Flash.display_flash;
|
||
kivi.display_flash_detail = kivi.Flash.display_flash_detail;
|
||
kivi.empty_flash = kivi.Flash.empty_flash;
|
||
kivi.clear_flash = kivi.Flash.clear_flash;
|
||
|
||
$('.layout-flash-toggle').click(kivi.Flash.toggle);
|
||
$('#layout_flash_container').on('click', '.layout-flash-remove', kivi.Flash.remove_entry);
|
||
});
|
scripts/generate_client_js_actions.tpl | ||
---|---|---|
// SL/ClientJS.pm for instructions.
|
||
|
||
namespace("kivi", function(ns) {
|
||
ns.display_flash = function(type, message, noscroll) {
|
||
$('#flash_' + type + '_content').text(message);
|
||
$('#flash_' + type).show();
|
||
if (!noscroll) {
|
||
$('#frame-header')[0].scrollIntoView();
|
||
}
|
||
};
|
||
|
||
ns.display_flash_detail = function(type, message) {
|
||
$('#flash_' + type + '_detail').html(message);
|
||
$('#flash_' + type + '_disp').show();
|
||
};
|
||
|
||
ns.clear_flash = function(category , timeout) {
|
||
window.setTimeout(function(){
|
||
$('#flash_' + category).hide();
|
||
$('#flash_detail_' + category).hide();
|
||
$('#flash_' + category + '_disp').hide();
|
||
$('#flash_' + category + '_content').empty();
|
||
$('#flash_' + category + '_detail').empty();
|
||
}, timeout);
|
||
};
|
||
|
||
ns.eval_json_result = function(data) {
|
||
if (!data)
|
||
return;
|
||
|
||
if (data.error)
|
||
return ns.display_flash('error', data.error);
|
||
return ns.Flash.display_flash('error', data.error);
|
||
|
||
if (!data.no_flash_clear) {
|
||
$(['info', 'warning', 'error']).each(function(idx, category) {
|
||
$('#flash_' + category).hide();
|
||
$('#flash_detail_' + category).hide();
|
||
$('#flash_' + category + '_disp').hide();
|
||
$('#flash_' + category + '_content').empty();
|
||
$('#flash_' + category + '_detail').empty();
|
||
});
|
||
}
|
||
if ((data.js || '') !== '')
|
||
// jshint -W061
|
||
eval(data.js);
|
t/flash_migration/deprecated_calls.t | ||
---|---|---|
use strict;
|
||
|
||
use lib 't';
|
||
|
||
use Support::Files;
|
||
use Support::TestSetup;
|
||
|
||
use File::Spec;
|
||
use File::Slurp;
|
||
use Template;
|
||
use Template::Provider;
|
||
use Test::More;
|
||
|
||
my @deprecated_calls_perl = (
|
||
qr/render_flash/,
|
||
qr/flash_detail/,
|
||
qr{common/flash},
|
||
qr/flash (?:_later)? \( \s* ' (?: error | warning | information ) ' \s* , \s* \@ /x,
|
||
);
|
||
|
||
my @deprecated_calls_js = (
|
||
qr/kivi\.display_flash/,
|
||
qr/kivi\.clear_flash/,
|
||
);
|
||
|
||
for my $file (@Support::Files::files) {
|
||
open my $fh, '<', $file or die "can't open $file";
|
||
|
||
while (my $line = <$fh>) {
|
||
for my $re (@deprecated_calls_perl) {
|
||
if ($line =~ $re) {
|
||
ok 0, "$file contains '$&', most likely due to incomplete merge of the layout flash feature. Consult the documentation in this test script";
|
||
}
|
||
}
|
||
}
|
||
|
||
ok 1, $file;
|
||
}
|
||
|
||
for my $file (@Support::Files::javascript_files) {
|
||
next if $file eq 'js/kivi.Flash.js';
|
||
|
||
open my $fh, '<', $file or die "can't open $file";
|
||
|
||
while (my $line = <$fh>) {
|
||
for my $re (@deprecated_calls_js) {
|
||
if ($line =~ $re) {
|
||
TODO: { local $TODO = 'clean up compatibility kivi.display_flash and kivi.clear_flash';
|
||
ok 0, "$file contains '$&', most likely due to incomplete merge of the layout flash feature. Consult the documentation in this test script";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
ok 1, $file;
|
||
}
|
||
|
||
done_testing();
|
||
|
||
|
||
__END__
|
||
|
||
=encoding utf-8
|
||
|
||
=head1 NAME
|
||
|
||
t/flash_migration&deprecated_calls.t
|
||
|
||
=head1 DESCRIPTION
|
||
|
||
Okay, if this script triggers, this is what needs to be done:
|
||
|
||
In Javascript:
|
||
|
||
- all javascript calls to "kivi.display_flash" and "kivi.clear_flash" need to
|
||
be redirected to "kivi.Flash"
|
||
- kivi.display_flash_details doesn't exist any more, instead details can now be
|
||
passed as a third argument to kivi.Flash.display_flash
|
||
|
||
In html:
|
||
|
||
- There is no common/flash.html template any more, since the layout handles
|
||
that now. Any attempt to render it needs to be removed.
|
||
|
||
In Perl:
|
||
|
||
- flash_detail doesn't exist any more, instead flash() and flash_later() take a
|
||
third argument for details
|
||
- render_flash doesn't exist anymore and is now handled by the layout.
|
||
- flash('error', @errrs) and similar must be called in a loop: flash('error', $_) for @errors
|
||
|
||
=cut
|
templates/design40_webpages/common/flash.html | ||
---|---|---|
[% USE HTML %]
|
||
[% USE LxERP %]
|
||
[% USE T8 %]
|
||
|
||
[% BLOCK output %]
|
||
<div id="flash_[% type %]" class="flash_message flash_message_[% type %]" [% IF !messages || !messages.size %] style="display: none" [% END %]>
|
||
<div class="icon-container">
|
||
<a href="#" onclick='$("#flash_[% type %]_content").empty();$("#flash_[% type %]_detail").empty();$("#flash_[% type %]").hide()' class="icon-close"> ✕</a>
|
||
<span id="flash_[% type %]_disp" class="display" style="display: none">
|
||
<a href="#" onclick='$("#flash_detail_[% type %]").toggle();' class="button"> [% 'Details' | $T8 %] </a>
|
||
</span>
|
||
</div>
|
||
<div class="message-container">
|
||
<span class="flash_title">[% title %]:</span>
|
||
<div class="flash_notification">
|
||
<span id="flash_[% type %]_content" class="content">
|
||
[% FOREACH message = messages %] [% HTML.escape(message) %] [% UNLESS loop.last %]<br>[% END %] [% END %]
|
||
</span>
|
||
<div id="flash_detail_[% type %]" class="detail" style="display: none">
|
||
<span id="flash_[% type %]_detail"></span>
|
||
<a href="#" style="float:left" onclick='$("#flash_detail_[% type %]").hide()' class="icon-close">✕</a>
|
||
</div>
|
||
</div><!-- /.flash_notification -->
|
||
</div>
|
||
</div>
|
||
[% END #BLOCK output %]
|
||
|
||
[% PROCESS output title=LxERP.t8('Error') type='error' messages = FLASH.error %]
|
||
[% PROCESS output title=LxERP.t8('Warning') type='warning' messages = FLASH.warning %]
|
||
[% PROCESS output title=LxERP.t8('Information') type='info' messages = FLASH.info %]
|
||
[% PROCESS output title=LxERP.t8('Ok') type='ok' messages = FLASH.ok %]
|
templates/webpages/common/flash.html | ||
---|---|---|
[%- USE HTML -%][%- USE LxERP %][%- USE T8 %]
|
||
[%- BLOCK output %]
|
||
<div id="flash_[% type %]" class="flash_message_[% type %]"[% IF !messages || !messages.size %] style="display: none"[% END %]>
|
||
<a href='#' style='float:right'
|
||
onclick='$("#flash_[% type %]_content").empty();$("#flash_[% type %]_detail").empty();$("#flash_[% type %]").hide()'>
|
||
<img src='image/close.png' border='0' alt='[% 'Close Flash' | $T8 %]'></a>
|
||
<span class="flash_title">[%- title %]:</span>
|
||
<span id="flash_[% type %]_content">
|
||
[% FOREACH message = messages %]
|
||
[%- HTML.escape(message) %]
|
||
[%- UNLESS loop.last %]<br>[% END %]
|
||
[%- END %]
|
||
</span>
|
||
<span id="flash_[% type %]_disp" style="display: none">
|
||
<a href='#' style='float:left' onclick='$("#flash_detail_[% type %]").toggle();'>
|
||
[[% 'Details' | $T8 %]]</a> </span>
|
||
<div id="flash_detail_[% type %]" style="display: none">
|
||
<br>
|
||
<span id="flash_[% type %]_detail"></span><br>
|
||
<a href='#' style='float:left'
|
||
onclick='$("#flash_detail_[% type %]").hide()'>
|
||
<img src='image/close.png' border='0' alt='[% 'Close Details' | $T8 %]'></a><br>
|
||
</div>
|
||
</div>
|
||
[%- END %]
|
||
[%- PROCESS output title=LxERP.t8('Error') type='error' messages = FLASH.error %]
|
||
[%- PROCESS output title=LxERP.t8('Warning') type='warning' messages = FLASH.warning %]
|
||
[%- PROCESS output title=LxERP.t8('Information') type='info' messages = FLASH.info %]
|
||
[%- PROCESS output title=LxERP.t8('Ok') type='ok' messages = FLASH.ok %]
|
Auch abrufbar als: Unified diff
SL::Layout::Flash: fliegende Flash-Meldungen (portiert von Odyn)