Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision de968328

Von Tamino Steinert vor 10 Monaten hinzugefügt

  • ID de968328fa32d13e9fa49ede581c6f2880228ad3
  • Vorgänger c1a83d34
  • Nachfolger 3d2dcee8

SL::Layout::Flash: fliegende Flash-Meldungen (portiert von Odyn)

TODOs:
- CSS für Design40 und Material anpassen
- Fehler von t/flash_migration/deprecated_calls beheben

Unterschiede anzeigen:

SL/ClientJS.pm
10 10
use Rose::Object::MakeMethods::Generic
11 11
(
12 12
  scalar                  => [ qw() ],
13
  'scalar --get_set_init' => [ qw(controller _actions _flash _flash_detail _no_flash_clear _error) ],
13
  'scalar --get_set_init' => [ qw(controller _actions _error) ],
14 14
);
15 15

  
16 16
my %supported_methods = (
......
115 115
  redirect_to            => 1,  # window.location.href = <TARGET>
116 116
  save_file              => 4,  # kivi.save_file(<TARGET>, <ARGS>)
117 117

  
118
  flash                  => 2,  # kivi.display_flash(<TARGET>, <ARGS>)
119
  flash_detail           => 2,  # kivi.display_flash_detail(<TARGET>, <ARGS>)
120
  clear_flash            => 2,  # kivi.clear_flash(<TARGET>, <ARGS>)
118
  # flash
119
  flash                  => -2, # kivi.Flash.display_flash.apply({}, action.slice(1, action.length))
120
  clear_flash            => 0,  # kivi.Flash.clear_flash()
121
  show_flash             => 0,  # kivi.Flash.show()
122
  hide_flash             => 0,  # kivi.Flash.hide()
123

  
121 124
  reinit_widgets         => 0,  # kivi.reinit_widgets()
122 125
  run                    => -1, # kivi.run(<TARGET>, <ARGS>)
123 126
  run_once_for           => 3,  # kivi.run_once_for(<TARGET>, <ARGS>)
......
181 184
  return [];
182 185
}
183 186

  
184
sub init__flash {
185
  return {};
186
}
187

  
188
sub init__flash_detail {
189
  return {};
190
}
191

  
192
sub init__error {
193
  return '';
194
}
195

  
196
sub init__no_flash_clear {
197
  return '';
198
}
199

  
200 187
sub to_json {
201 188
  my ($self) = @_;
202 189

  
203 190
  return SL::JSON::to_json({ error          => $self->_error   }) if $self->_error;
204
  return SL::JSON::to_json({ no_flash_clear => $self->_no_flash_clear, eval_actions => $self->_actions });
191
  return SL::JSON::to_json({ eval_actions => $self->_actions });
205 192
}
206 193

  
207 194
sub to_array {
......
234 221
  return $self;
235 222
}
236 223

  
237
sub flash {
238
  my ($self, $type, @messages) = @_;
239

  
240
  my $message = join ' ', grep { $_ } @messages;
241

  
242
  if (!$self->_flash->{$type}) {
243
    $self->_flash->{$type} = [ 'flash', $type, $message ];
244
    push @{ $self->_actions }, $self->_flash->{$type};
245
  } else {
246
    $self->_flash->{$type}->[-1] .= ' ' . $message;
247
  }
248

  
249
  return $self;
250
}
251

  
252
sub flash_detail {
253
  my ($self, $type, @messages) = @_;
254

  
255
  my $message = join '<br>', grep { $_ } @messages;
256

  
257
  if (!$self->_flash_detail->{$type}) {
258
    $self->_flash_detail->{$type} = [ 'flash_detail', $type, $message ];
259
    push @{ $self->_actions }, $self->_flash_detail->{$type};
260
  } else {
261
    $self->_flash_detail->{$type}->[-1] .= ' ' . $message;
262
  }
263

  
264
  return $self;
265
}
266

  
267 224
sub no_flash_clear{
268
  my ($self) = @_;
269
  $self->_no_flash_clear('1');
270
  return $self;
225
  $_[0]; # noop for compatibility
271 226
}
272 227

  
273 228
sub error {
......
485 440

  
486 441
=over 4
487 442

  
488
=item C<flash $type, $message>
489

  
490
Display a C<$message> in the flash of type C<$type>. Multiple calls of
491
C<flash> on the same C<$self> will be merged by type.
492

  
493
On the client side the flashes of all types will be cleared after each
494
successful ClientJS call that did not end with C<$js-E<gt>error(...)>.
495
This clearing can be switched of by the function C<no_flash_clear>
496

  
497
=item C<flash_detail $type, $message>
498

  
499
Display a detailed message C<$message> in the flash of type C<$type>. Multiple calls of
500
C<flash_detail> on the same C<$self> will be merged by type.
501
So the flash message can be hold short and the visibility of details can toggled by the user.
502

  
503
=item C<no_flash_clear>
443
=item C<flash $type, $message [, $details [, timestamp ]]>
504 444

  
505
No automatic clearing of flash after successful ClientJS call
445
Display a C<$message> in the flash of type C<$type> with optional
446
C<$details>.
506 447

  
507 448
=item C<error $message>
508 449

  
SL/Controller/Flash.pm
1
package SL::Controller::Flash;
2

  
3
use strict;
4
use parent qw(SL::Controller::Base);
5

  
6
use SL::Helper::Flash;
7

  
8
sub action_reload {
9
  my ($self) = @_;
10

  
11
  $self->js->clear_flash;
12
  $self->js->flash(@$_) for SL::Helper::Flash::flash_contents;
13
  $self->js->show_flash;
14
  $self->js->render;
15
}
16

  
17
1;
18

  
19
__END__
20

  
21
=encoding utf-8
22

  
23
=head1 NAME
24

  
25
SL::Controller::Flash - Flash actions
26

  
27
=head1 DESCRIPTION
28

  
29
This controller contains actions that can be used to reload and control client
30
side flash messages
31

  
32
=head1 BUGS
33

  
34
None yet :)
35

  
36
=head1 AUTHOR
37

  
38
Sven Schöling E<lt>sven.schoeling@opendynamic.deE<gt>
39

  
40
=cut
SL/Helper/Flash.pm
5 5
require Exporter;
6 6
our @ISA       = qw(Exporter);
7 7
our @EXPORT    = qw(flash flash_later);
8
our @EXPORT_OK = qw(render_flash delay_flash);
8
our @EXPORT_OK = qw(delay_flash);
9 9

  
10 10
my %valid_categories = (
11 11
  map({$_ => 'info'} qw(information message)),
......
24 24
  $::auth->set_session_value({ key => "FLASH", value => _store_flash($::auth->get_session_value('FLASH'), @_), auto_restore => 1 });
25 25
}
26 26

  
27
sub delay_flash {
28
  my $store = $::form->{FLASH} || { };
29
  flash_later($_ => @{ $store->{$_} || [] }) for keys %$store;
27
sub flash_contents {
28
  return unless $::form;
29
  return unless $::form->{FLASH};
30
  return unless 'ARRAY' eq ref $::form->{FLASH};
31

  
32
  @{ $::form->{FLASH} }
30 33
}
31 34

  
32
sub render_flash {
33
  return $::form->parse_html_template('common/flash');
35
sub delay_flash {
36
  my $store = $::form->{FLASH} || [];
37
  flash_later(@{ $_ || [] }) for @$store;
34 38
}
35 39

  
36 40
#
......
38 42
#
39 43

  
40 44
sub _store_flash {
41
  my $store    = shift || { };
42
  my $category = _check_category(+shift);
45
  my ($store, $type, $message, $details, $timestamp) = @_;
46
  $store     //= [ ];
47
  $timestamp //= time();
48
  my $category = _check_category($type);
43 49

  
44
  $store->{ $category } ||= [ ];
45
  push @{ $store->{ $category } }, @_;
50
  push @{ $store }, [ $type, $message, $details, $timestamp ];
46 51

  
47 52
  return $store;
48 53
}
......
68 73

  
69 74
=head1 SYNOPSIS
70 75

  
76
  use SL::Helper::Flash qw(flash flash_later delay_flash);
77

  
78
  # display in this request
79
  flash('info', 'Customer saved!');
80
  flash('error', 'Something went wrong', "details about what went wrong");
81
  flash('warning', 'this might not be a good idea');
82

  
83
  # display after a redirect
84
  flash_later('info', 'Customer saved!');
85
  flash_later('error', 'Something went wrong', "details about what went wrong");
86
  flash_later('warning', 'this might not be a good idea');
87

  
88
  # delay flash() calls to next request:
89
  delay_flash();
90

  
91
=head1 DESCRIPTION
92

  
71 93
The flash is a store for messages that should be displayed to the
72 94
user. Each message has a category which is usually C<information>,
73 95
C<warning> or C<error>. The messages in each category are grouped and
74 96
displayed in colors appropriate for their severity (e.g. errors in
75 97
red).
76 98

  
77
Messages are rendered either by calling the function C<render_flash>
78
or by including the flash sub-template from a template with the
79
following code:
80

  
81
  [%- INCLUDE 'common/flash.html' %]
99
Messages are rendered by including the L<SL::Layout::Flash> sub layout.
82 100

  
83 101
=head1 EXPORTS
84 102

  
85 103
The functions L</flash> and L</flash_later> are always exported.
86 104

  
87
The function L</render_flash> is only exported upon request.
88

  
89 105
=head1 FUNCTIONS
90 106

  
91 107
=over 4
92 108

  
93
=item C<flash $category, @messages>
109
=item C<flash $category, $message [, $details ]>
94 110

  
95
Stores messages for the given category. The category can be either
96
C<information>, C<warning> or C<error>. C<info> can also be used as an
97
alias for C<information>.
111
Store a message with optional details for the given category. The category can
112
be either C<information>, C<warning> or C<error>. C<info> can also be used as
113
an alias for C<information>.
98 114

  
99
=item C<flash_later $category, @messages>
115
=item C<flash_later $category, $message [, $details ]>
100 116

  
101
Stores messages for the given category for the next request. The
102
category can be either C<information>, C<warning> or C<error>. C<info>
103
can also be used as an alias for C<information>.
117
Store a message with optional details for the given category for the next
118
request. The category can be either C<information>, C<warning> or C<error>.
119
C<info> can also be used as an alias for C<information>.
104 120

  
105
The messages are stored in the user's session and restored upon the
121
The message is stored in the user's session and restored upon the
106 122
next request. Can be used for transmitting information over HTTP
107 123
redirects.
108 124

  
109
=item C<render_flash>
110

  
111
Outputs the flash message by parsing the C<common/flash.html> template
112
file.
113

  
114
This function is not exported by default.
115

  
116 125
=item C<delay_flash>
117 126

  
118 127
Delays flash, as if all flash messages in this request would have been
......
120 129

  
121 130
Not exported by default.
122 131

  
132
=item C<flash_contents>
133

  
134
The contents of the current flash accumulator.
135

  
123 136
=back
124 137

  
125 138
=head1 AUTHOR
SL/Layout/Admin.pm
7 7
use SL::Layout::None;
8 8
use SL::Layout::Top;
9 9
use SL::Layout::CssMenu;
10
use SL::Layout::Flash;
10 11

  
11 12
sub init_sub_layouts {
13
  $_[0]->sub_layouts_by_name->{flash}     = SL::Layout::Flash->new;
14

  
12 15
  [
13 16
    SL::Layout::None->new,
14 17
    SL::Layout::CssMenu->new(menu => SL::Menu->new('admin')),
18
    $_[0]->sub_layouts_by_name->{flash},
15 19
  ]
16 20
}
17 21

  
SL/Layout/Classic.pm
8 8
use SL::Layout::None;
9 9
use SL::Layout::Split;
10 10
use SL::Layout::ActionBar;
11
use SL::Layout::Flash;
11 12
use SL::Layout::Content;
12 13

  
13 14
sub init_sub_layouts {
14 15
  $_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
16
  $_[0]->sub_layouts_by_name->{flash}     = SL::Layout::Flash->new;
15 17

  
16 18
  [
17 19
    SL::Layout::None->new,
18 20
    SL::Layout::Top->new,
19 21
    SL::Layout::Split->new(
20 22
      left  => [ SL::Layout::MenuLeft->new ],
21
      right => [ $_[0]->sub_layouts_by_name->{actionbar}, SL::Layout::Content->new ],
23
      right => [
24
        $_[0]->sub_layouts_by_name->{actionbar},
25
        $_[0]->sub_layouts_by_name->{flash},
26
        SL::Layout::Content->new,
27
      ],
22 28
    )
23 29
  ]
24 30
}
SL/Layout/Flash.pm
1
package SL::Layout::Flash;
2

  
3
use strict;
4
use parent qw(SL::Layout::Base);
5
use SL::Presenter::EscapedText qw(escape_js);
6
use SL::Helper::Flash;
7

  
8
sub pre_content {
9
  '<div style="position:relative"><div id="layout_flash_container"></div></div>'
10
}
11

  
12
sub javascripts_inline {
13
  my ($self) = @_;
14

  
15
  my $js = '';
16

  
17
  for (SL::Helper::Flash::flash_contents()) {
18
    next if $_->[3] + 60 < time(); # ignore entries from more than one minute ago
19
    $js .= defined $_->[2]
20
      ? sprintf("kivi.Flash.display_flash('%s', '%s', '%s');", map { escape_js($_) } @$_[0,1,2] )
21
      : sprintf("kivi.Flash.display_flash('%s', '%s');", map { escape_js($_) } @$_[0,1] );
22
  }
23

  
24
  $js;
25
}
26

  
27
sub static_javascripts {
28
  'kivi.Flash.js'
29
}
30

  
31

  
32
1;
SL/Layout/Javascript.pm
7 7
use SL::Layout::DHTMLMenu;
8 8
use SL::Layout::Top;
9 9
use SL::Layout::ActionBar;
10
use SL::Layout::Flash;
10 11
use SL::Layout::Content;
11 12

  
12 13
use List::Util qw(max);
......
15 16

  
16 17
sub init_sub_layouts {
17 18
  $_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
19
  $_[0]->sub_layouts_by_name->{flash}     = SL::Layout::Flash->new;
18 20
  [
19 21
    SL::Layout::None->new,
20 22
    SL::Layout::Top->new,
21 23
    SL::Layout::DHTMLMenu->new,
22 24
    $_[0]->sub_layouts_by_name->{actionbar},
25
    $_[0]->sub_layouts_by_name->{flash},
23 26
    SL::Layout::Content->new,
24 27
  ]
25 28
}
SL/Layout/Material.pm
6 6
use SL::Layout::None;
7 7
use SL::Layout::MaterialMenu;
8 8
use SL::Layout::MaterialStyle;
9
use SL::Layout::Flash;
9 10
use SL::Layout::Content;
10 11

  
11 12
sub get_stylesheet_for_user {
......
22 23
    SL::Layout::None->new,
23 24
    SL::Layout::MaterialStyle->new,
24 25
    SL::Layout::MaterialMenu->new,
26
    SL::Layout::Flash->new,
25 27
    SL::Layout::Content->new,
26 28
  ]
27 29
}
SL/Layout/V3.pm
7 7
use SL::Layout::Top;
8 8
use SL::Layout::CssMenu;
9 9
use SL::Layout::ActionBar;
10
use SL::Layout::Flash;
10 11
use SL::Layout::Content;
11 12

  
12 13
sub init_sub_layouts {
13 14
  $_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new;
15
  $_[0]->sub_layouts_by_name->{flash}     = SL::Layout::Flash->new;
14 16

  
15 17
  [
16 18
    SL::Layout::None->new,
17 19
    SL::Layout::Top->new,
18 20
    SL::Layout::CssMenu->new,
19 21
    $_[0]->sub_layouts_by_name->{actionbar},
22
    $_[0]->sub_layouts_by_name->{flash},
20 23
    SL::Layout::Content->new,
21 24
  ]
22 25
}
css/kivitendo/main.css
607 607
  font-weight: bold;
608 608
}
609 609

  
610
/* Flash message */
611
#layout_flash_container {
612
  position: absolute;
613
  z-index: 200;
614
  right: 20px;
615
  min-width: 30%;
616
  animation: fadein .5s;
617
}
618
@keyframes hop {
619
  to  { transform: scale(1.01); }
620
}
621
@keyframes flash {
622
  from  { background-color: black }
623
}
624
@keyframes fadein {
625
  from  { opacity: 0; }
626
  to  { opacity: 1; }
627
}
628
.layout-flash-message {
629
  margin-top: 5px;
630
  margin-bottom: 5px;
631
  padding: 5px;
632
  border-width: 1px;
633
  border-style: solid;
634
 /* animation: .5s ease-out .2s 1 normal none running flash;*/
635
}
636
.layout-flash-body{
637
  padding-top:5px;
638
  margin-top:5px;
639
  border-top: 1px dotted black;
640
}
641
.layout-flash-timestamp{
642
  opacity: 0.75;
643
}
644
.layout-flash-details::before {
645
  content: ': ';
646
}
647
.layout-flash-type {
648
  font-weight: bold;
649
  float: right;
650
}
651
.layout-flash-error {
652
  background-color: #FFD6D6;
653
  border-color: #AE0014;
654
}
655
.layout-flash-ok {
656
  background-color: #ADFFB6;
657
  border-color: #007F0F;
658
}
659
.layout-flash-warning {
660
  background-color: #FFE8C7;
661
  border-color: #FF6600;
662
}
663
.layout-flash-info {
664
  background-color: #DCF2FF;
665
  border-color: #4690FF;
666
}
667
.layout-flash-title {
668
  font-weight: bold;
669
}
670
.layout-flash-remove {
671
  padding-right: 4px;
672
}
673

  
674

  
610 675
/* Admin section: the menu itself doesn't occupy space. So make room
611 676
   at the top of the div covering the whole admin area. */
612 677
body > div.admin {
js/client_js.js
5 5
// SL/ClientJS.pm for instructions.
6 6

  
7 7
namespace("kivi", function(ns) {
8
ns.display_flash = function(type, message, noscroll) {
9
  $('#flash_' + type + '_content').text(message);
10
  $('#flash_' + type).show();
11
  if (!noscroll && $('#frame-header')[0]) {
12
    $('#frame-header')[0].scrollIntoView();
13
  }
14
};
15

  
16
ns.display_flash_detail = function(type, message) {
17
  $('#flash_' + type + '_detail').html(message);
18
  $('#flash_' + type + '_disp').show();
19
};
20

  
21
ns.clear_flash = function(category , timeout) {
22
  window.setTimeout(function(){
23
    $('#flash_' + category).hide();
24
    $('#flash_detail_' + category).hide();
25
    $('#flash_' + category + '_disp').hide();
26
    $('#flash_' + category + '_content').empty();
27
    $('#flash_' + category + '_detail').empty();
28
  }, timeout);
29
};
30 8

  
31 9
ns.eval_json_result = function(data) {
32 10
  if (!data)
33 11
    return;
34 12

  
35
  if (data.error)
36
    return ns.display_flash('error', data.error);
13
  if (data.error && ns.Flash)
14
    return ns.Flash.display_flash('error', data.error);
37 15

  
38
  if (!data.no_flash_clear) {
39
    $(['info', 'warning', 'error']).each(function(idx, category) {
40
      $('#flash_' + category).hide();
41
      $('#flash_detail_' + category).hide();
42
      $('#flash_' + category + '_disp').hide();
43
      $('#flash_' + category + '_content').empty();
44
      $('#flash_' + category + '_detail').empty();
45
    });
46
  }
47 16
  if ((data.js || '') !== '')
48 17
    // jshint -W061
49 18
    eval(data.js);
......
152 121
      // ## other stuff ##
153 122
      else if (action[0] == 'redirect_to')          window.location.href = action[1];
154 123
      else if (action[0] == 'save_file')            kivi.save_file(action[1], action[2], action[3], action[4]);
155
      else if (action[0] == 'flash')                kivi.display_flash(action[1], action[2]);
156
      else if (action[0] == 'flash_detail')         kivi.display_flash_detail(action[1], action[2]);
157
      else if (action[0] == 'clear_flash')          kivi.clear_flash(action[1], action[2]);
124

  
125
      // flash
126
      else if (action[0] == 'flash')                kivi.Flash.display_flash.apply({}, action.slice(1, action.length));
127
      else if (action[0] == 'clear_flash')          kivi.Flash.clear_flash();
128
      else if (action[0] == 'show_flash')           kivi.Flash.show();
129
      else if (action[0] == 'hide_flash')           kivi.Flash.hide();
158 130
      else if (action[0] == 'reinit_widgets')       kivi.reinit_widgets();
159 131
      else if (action[0] == 'run')                  kivi.run(action[1], action.slice(2, action.length));
160 132
      else if (action[0] == 'run_once_for')         kivi.run_once_for(action[1], action[2], action[3]);
js/kivi.Flash.js
1
namespace("kivi.Flash", function(ns) {
2
  "use strict";
3

  
4
  ns.type_to_title = {
5
    error:   kivi.t8('Error'),
6
    warning: kivi.t8('Warning'),
7
    info:    kivi.t8('Information'),
8
    ok:      kivi.t8('Ok')
9
  };
10

  
11
  ns.display_flash = function(type, message, details, timestamp) {
12
    let $dom = $('<div>');
13
    $dom.addClass('layout-flash-' + type);
14
    $dom.addClass('layout-flash-message');
15

  
16
    let $header = $('<div>');
17
    $header.addClass('layout-flash-header');
18

  
19
    let $remove = $('<span>✘</span>');
20
    $remove.addClass('layout-flash-remove').addClass('cursor-pointer');
21
    $remove.attr('alt', kivi.t8('Close Flash'));
22
    $header.append($remove);
23

  
24
    if (timestamp === undefined) {
25
      timestamp = new Date();
26
    } else if (timestamp > 0) {
27
      timestamp = new Date(timestamp * 1000);
28
    }
29

  
30
    let $time = $('<span>');
31
    $time.addClass('layout-flash-timestamp');
32
    $time.text(kivi.format_time(timestamp));
33
    $header.append($time);
34

  
35
    let $type = $('<span>');
36
    $type.addClass('layout-flash-type');
37
    $type.text(ns.type_to_title[type]);
38
    $header.append($type);
39

  
40
    let $body = $('<div>');
41
    $body.addClass('layout-flash-body');
42

  
43
    if (message !== undefined && message !== null) {
44
      let $message =  $('<span>');
45
      $message.addClass('layout-flash-content');
46
      $message.html(message);
47
      $body.append($message);
48
    }
49

  
50
    if (details !== undefined && details !== null) {
51
      let $details =  $('<span>');
52
      $details.addClass('layout-flash-details');
53
      $details.html(details);
54
      $body.append($details);
55
    }
56

  
57
    $dom.append($header);
58
    $dom.append($body);
59

  
60
    $("#layout_flash_container").append($dom);
61

  
62
    // fadeout after 1min
63
    $dom.delay(60000).fadeOut('slow');
64

  
65
    ns.show();
66
  };
67

  
68
  ns.display_flash_detail = function(type, message) {
69
    $('#flash_' + type + '_disp').show();
70
  };
71

  
72
  ns.clear_flash = function(category, timeout) {
73
    if (timeout === undefined) {
74
      ns.clear_flash_now(category);
75
    } else {
76
      window.setTimeout(function(){
77
        ns.clear_flash_now(category);
78
      }, timeout);
79
    }
80
  };
81

  
82
  ns.clear_flash_now = function(category) {
83
    if (category) {
84
      $('div.layout-flash-' + category).remove();
85
    } else {
86
      $('div.layout-flash-message').remove();
87
    }
88
  };
89

  
90
  ns.remove_entry = function(e) {
91
    $(e.target).closest('div.layout-flash-message').remove();
92
  };
93

  
94
  ns.toggle = function() {
95
    $('#layout_flash_container').toggle();
96
  };
97
  ns.show = function() {
98
    $('#layout_flash_container').show();
99
  };
100
  ns.hide = function() {
101
    $('#layout_flash_container').hide();
102
  };
103
  ns.reload_flash = function() {
104
    $.get("controller.pl", { action: "Flash/reload" }, kivi.eval_json_result);
105
  };
106

  
107
  ns.reinit_widgets = function() {
108

  
109
  };
110
});
111

  
112
$(function() {
113
  "use strict";
114
  // dispatch to kivi.Flash for compatibility
115
  kivi.display_flash        = kivi.Flash.display_flash;
116
  kivi.display_flash_detail = kivi.Flash.display_flash_detail;
117
  kivi.empty_flash          = kivi.Flash.empty_flash;
118
  kivi.clear_flash          = kivi.Flash.clear_flash;
119

  
120
  $('.layout-flash-toggle').click(kivi.Flash.toggle);
121
  $('#layout_flash_container').on('click', '.layout-flash-remove', kivi.Flash.remove_entry);
122
});
scripts/generate_client_js_actions.tpl
5 5
// SL/ClientJS.pm for instructions.
6 6

  
7 7
namespace("kivi", function(ns) {
8
ns.display_flash = function(type, message, noscroll) {
9
  $('#flash_' + type + '_content').text(message);
10
  $('#flash_' + type).show();
11
  if (!noscroll) {
12
    $('#frame-header')[0].scrollIntoView();
13
  }
14
};
15

  
16
ns.display_flash_detail = function(type, message) {
17
  $('#flash_' + type + '_detail').html(message);
18
  $('#flash_' + type + '_disp').show();
19
};
20

  
21
ns.clear_flash = function(category , timeout) {
22
  window.setTimeout(function(){
23
    $('#flash_' + category).hide();
24
    $('#flash_detail_' + category).hide();
25
    $('#flash_' + category + '_disp').hide();
26
    $('#flash_' + category + '_content').empty();
27
    $('#flash_' + category + '_detail').empty();
28
  }, timeout);
29
};
30 8

  
31 9
ns.eval_json_result = function(data) {
32 10
  if (!data)
33 11
    return;
34 12

  
35 13
  if (data.error)
36
    return ns.display_flash('error', data.error);
14
    return ns.Flash.display_flash('error', data.error);
37 15

  
38
  if (!data.no_flash_clear) {
39
    $(['info', 'warning', 'error']).each(function(idx, category) {
40
      $('#flash_' + category).hide();
41
      $('#flash_detail_' + category).hide();
42
      $('#flash_' + category + '_disp').hide();
43
      $('#flash_' + category + '_content').empty();
44
      $('#flash_' + category + '_detail').empty();
45
    });
46
  }
47 16
  if ((data.js || '') !== '')
48 17
    // jshint -W061
49 18
    eval(data.js);
t/flash_migration/deprecated_calls.t
1
use strict;
2

  
3
use lib 't';
4

  
5
use Support::Files;
6
use Support::TestSetup;
7

  
8
use File::Spec;
9
use File::Slurp;
10
use Template;
11
use Template::Provider;
12
use Test::More;
13

  
14
my @deprecated_calls_perl = (
15
  qr/render_flash/,
16
  qr/flash_detail/,
17
  qr{common/flash},
18
  qr/flash (?:_later)? \( \s* ' (?: error | warning | information ) ' \s* , \s* \@ /x,
19
);
20

  
21
my @deprecated_calls_js = (
22
  qr/kivi\.display_flash/,
23
  qr/kivi\.clear_flash/,
24
);
25

  
26
for my $file (@Support::Files::files) {
27
  open my $fh, '<', $file or die "can't open $file";
28

  
29
  while (my $line = <$fh>) {
30
    for my $re (@deprecated_calls_perl) {
31
      if ($line =~ $re) {
32
        ok 0, "$file contains '$&', most likely due to incomplete merge of the layout flash feature. Consult the documentation in this test script";
33
      }
34
    }
35
  }
36

  
37
  ok 1, $file;
38
}
39

  
40
for my $file (@Support::Files::javascript_files) {
41
  next if $file eq 'js/kivi.Flash.js';
42

  
43
  open my $fh, '<', $file or die "can't open $file";
44

  
45
  while (my $line = <$fh>) {
46
    for my $re (@deprecated_calls_js) {
47
      if ($line =~ $re) {
48
        TODO: { local $TODO = 'clean up compatibility kivi.display_flash and kivi.clear_flash';
49
          ok 0, "$file contains '$&', most likely due to incomplete merge of the layout flash feature. Consult the documentation in this test script";
50
        }
51
      }
52
    }
53
  }
54

  
55
  ok 1, $file;
56
}
57

  
58
done_testing();
59

  
60

  
61
__END__
62

  
63
=encoding utf-8
64

  
65
=head1 NAME
66

  
67
t/flash_migration&deprecated_calls.t
68

  
69
=head1 DESCRIPTION
70

  
71
Okay, if this script triggers, this is what needs to be done:
72

  
73
In Javascript:
74

  
75
- all javascript calls to "kivi.display_flash" and "kivi.clear_flash" need to
76
  be redirected to "kivi.Flash"
77
- kivi.display_flash_details doesn't exist any more, instead details can now be
78
  passed as a third argument to kivi.Flash.display_flash
79

  
80
In html:
81

  
82
- There is no common/flash.html template any more, since the layout handles
83
  that now. Any attempt to render it needs to be removed.
84

  
85
In Perl:
86

  
87
- flash_detail doesn't exist any more, instead flash() and flash_later() take a
88
  third argument for details
89
- render_flash doesn't exist anymore and is now handled by the layout.
90
- flash('error', @errrs) and similar must be called in a loop: flash('error', $_) for @errors
91

  
92
=cut
templates/design40_webpages/common/flash.html
1
[% USE HTML %]
2
[% USE LxERP %]
3
[% USE T8 %]
4

  
5
[% BLOCK output %]
6
<div id="flash_[% type %]" class="flash_message flash_message_[% type %]" [% IF !messages || !messages.size %] style="display: none" [% END %]>
7
<div class="icon-container">
8
  <a href="#" onclick='$("#flash_[% type %]_content").empty();$("#flash_[% type %]_detail").empty();$("#flash_[% type %]").hide()' class="icon-close"> &#10005;</a>
9
  <span id="flash_[% type %]_disp" class="display" style="display: none">
10
    <a href="#" onclick='$("#flash_detail_[% type %]").toggle();' class="button"> [% 'Details' | $T8 %] </a>
11
  </span>
12
</div>
13
<div class="message-container">
14
  <span class="flash_title">[% title %]:</span>
15
  <div class="flash_notification">
16
    <span id="flash_[% type %]_content" class="content">
17
      [% FOREACH message = messages %] [% HTML.escape(message) %] [% UNLESS loop.last %]<br>[% END %] [% END %]
18
    </span>
19
    <div id="flash_detail_[% type %]" class="detail" style="display: none">
20
      <span id="flash_[% type %]_detail"></span>
21
      <a href="#" style="float:left" onclick='$("#flash_detail_[% type %]").hide()' class="icon-close">&#10005;</a>
22
    </div>
23
  </div><!-- /.flash_notification -->
24
</div>
25
</div>
26
[% END #BLOCK output %]
27

  
28
[% PROCESS output title=LxERP.t8('Error') type='error' messages = FLASH.error %]
29
[% PROCESS output title=LxERP.t8('Warning') type='warning' messages = FLASH.warning %]
30
[% PROCESS output title=LxERP.t8('Information') type='info' messages = FLASH.info %]
31
[% PROCESS output title=LxERP.t8('Ok') type='ok' messages = FLASH.ok %]
templates/webpages/common/flash.html
1
[%- USE HTML -%][%- USE LxERP %][%- USE T8 %]
2
[%- BLOCK output %]
3
 <div id="flash_[% type %]" class="flash_message_[% type %]"[% IF !messages || !messages.size %] style="display: none"[% END %]>
4
  <a href='#' style='float:right'
5
     onclick='$("#flash_[% type %]_content").empty();$("#flash_[% type %]_detail").empty();$("#flash_[% type %]").hide()'>
6
     <img src='image/close.png' border='0' alt='[% 'Close Flash' | $T8 %]'></a>
7
  <span class="flash_title">[%- title %]:</span>
8
  <span id="flash_[% type %]_content">
9
   [% FOREACH message = messages %]
10
    [%- HTML.escape(message) %]
11
    [%- UNLESS loop.last %]<br>[% END %]
12
   [%- END %]
13
  </span>
14
  <span id="flash_[% type %]_disp" style="display: none">
15
  <a href='#' style='float:left' onclick='$("#flash_detail_[% type %]").toggle();'>
16
     [[% 'Details' | $T8 %]]</a>&nbsp;&nbsp;</span>
17
  <div id="flash_detail_[% type %]" style="display: none">
18
    <br>
19
    <span id="flash_[% type %]_detail"></span><br>
20
    <a href='#' style='float:left'
21
      onclick='$("#flash_detail_[% type %]").hide()'>
22
      <img src='image/close.png' border='0' alt='[% 'Close Details' | $T8 %]'></a><br>
23
  </div>
24
 </div>
25
[%- END %]
26
[%- PROCESS output title=LxERP.t8('Error')       type='error'   messages = FLASH.error %]
27
[%- PROCESS output title=LxERP.t8('Warning')     type='warning' messages = FLASH.warning %]
28
[%- PROCESS output title=LxERP.t8('Information') type='info'    messages = FLASH.info %]
29
[%- PROCESS output title=LxERP.t8('Ok')          type='ok'      messages = FLASH.ok %]

Auch abrufbar als: Unified diff