Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision d1e36314

Von Sven Schöling vor mehr als 3 Jahren hinzugefügt

  • ID d1e363140d304907c9c175ad018c034c00343f4c
  • Vorgänger a534317b
  • Nachfolger aadd8f86

Layout: Javascript Menü refactoring

Das Javascript Menü war noch in einem Zustand aus der Anfangszeit von
SL::Layout. Diese Änderungen teilen das in ein Main Layout (Javascript)
und ein sub layout für das DHTMLMenu.

Das DHTMLMenu Layout ist außerdem ein wenig optimiert. Es benutzt jetzt
nicht mehr ein template sondern baut das DOM direkt zusammen (spart im
hot path einen template aufruf und ist um faktor 5 schneller), und
ausserdem werden die -f checks auf die icon Dateien jetzt mit
SL::System::ResourceCache gecacht, so dass nicht für jeden Request ein
paar Duzend stat() gemacht werden müssen.

Unterschiede anzeigen:

SL/Layout/DHTMLMenu.pm
1
package SL::Layout::DHTMLMenu;
2

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

  
6
use SL::Presenter::JavascriptMenu qw(render_menu);
7

  
8
sub static_javascripts {
9
  qw(dhtmlsuite/menu-for-applications.js),
10
}
11

  
12
sub javascripts_inline {
13
<<'EOJS',
14
  DHTMLSuite.createStandardObjects();
15
  DHTMLSuite.configObj.setImagePath('image/dhtmlsuite/');
16
  var menu_model = new DHTMLSuite.menuModel();
17
  menu_model.addItemsFromMarkup('main_menu_model');
18
  menu_model.init();
19
  var menu_bar = new DHTMLSuite.menuBar();
20
  menu_bar.addMenuItems(menu_model);
21
  menu_bar.setTarget('main_menu_div');
22
  menu_bar.init();
23
EOJS
24
}
25

  
26
sub pre_content {
27
  render_menu($_[0]->menu),
28
}
29

  
30
sub static_stylesheets {
31
  qw(
32
    dhtmlsuite/menu-item.css
33
    dhtmlsuite/menu-bar.css
34
    icons16.css
35
    menu.css
36
  );
37
}
38

  
39
1;
SL/Layout/Javascript.pm
4 4
use parent qw(SL::Layout::Base);
5 5

  
6 6
use SL::Layout::None;
7
use SL::Layout::DHTMLMenu;
7 8
use SL::Layout::Top;
8 9
use SL::Layout::ActionBar;
9 10
use SL::Layout::Content;
......
17 18
  [
18 19
    SL::Layout::None->new,
19 20
    SL::Layout::Top->new,
21
    SL::Layout::DHTMLMenu->new,
22
    $_[0]->sub_layouts_by_name->{actionbar},
20 23
    SL::Layout::Content->new,
21 24
  ]
22 25
}
23 26

  
24
sub javascripts {
25
  my ($self) = @_;
26

  
27
  return uniq grep { $_ } map { $self->_find_javascript($_)  }
28
    map({ $_->javascripts } $self->sub_layouts),
29
    qw(dhtmlsuite/menu-for-applications.js),
30
    $_[0]->sub_layouts_by_name->{actionbar}->javascripts,
31
    $self->use_javascript;
32
}
33

  
34
sub javascripts_inline {
35
  $_[0]->SUPER::javascripts_inline,
36
<<'EOJS',
37
  DHTMLSuite.createStandardObjects();
38
  DHTMLSuite.configObj.setImagePath('image/dhtmlsuite/');
39
  var menu_model = new DHTMLSuite.menuModel();
40
  menu_model.addItemsFromMarkup('main_menu_model');
41
  menu_model.init();
42
  var menu_bar = new DHTMLSuite.menuBar();
43
  menu_bar.addMenuItems(menu_model);
44
  menu_bar.setTarget('main_menu_div');
45
  menu_bar.init();
46
EOJS
47
  $_[0]->sub_layouts_by_name->{actionbar}->javascripts_inline,
48
}
49

  
50
sub pre_content {
51
  $_[0]->SUPER::pre_content .
52
  $_[0]->presenter->render("menu/menunew",
53
    force_ul_width  => 1,
54
    menu            => $_[0]->menu,
55
    icon_path       => sub { my $simg = "image/icons/svg/$_[0].svg";  my $pimg="image/icons/16x16/$_[0].png"; -f $simg ? $simg : ( -f $pimg ? $pimg : ()) },
56
    max_width       => sub { 10 * max map { length $::locale->text($_->{name}) } @{ $_[0]{children} || [] } },
57
  ) .
58
  ($_[0]->sub_layouts_by_name->{actionbar}->pre_content // '');
59
}
60

  
61
sub stylesheets {
62
  my ($self) = @_;
63
  my $css_path = $self->get_stylesheet_for_user;
64

  
65
  return
66
    uniq
67
    grep { $_ }
68
    map { $self->_find_stylesheet($_, $css_path)  }
69
    qw(
70
      dhtmlsuite/menu-item.css
71
      dhtmlsuite/menu-bar.css
72
      icons16.css
73
      menu.css
74
    ),
75
    ( map { $_->stylesheets } $_[0]->sub_layouts ),
76
    $_[0]->sub_layouts_by_name->{actionbar}->stylesheets,
77
    $_[0]->use_stylesheet;
78
}
79

  
80 27
1;
SL/Presenter/JavascriptMenu.pm
1
package SL::Presenter::JavascriptMenu;
2

  
3
use strict;
4
use SL::Presenter::EscapedText qw(escape is_escaped);
5
use SL::Presenter::Tag qw( html_tag link_tag);
6
use SL::Locale::String qw(t8);
7
use SL::System::ResourceCache;
8

  
9
use List::Util qw(max);
10

  
11
use Exporter qw(import);
12
our @EXPORT_OK = qw(render_menu);
13

  
14
sub render_menu {
15
  my ($menu) = @_;
16

  
17
  html_tag('div', '', id => 'main_menu_div') .
18
  html_tag('ul', render_children($menu, 100, $menu->{tree}),
19
    id    => "main_menu_model",
20
    style => 'display:none',
21
  );
22
}
23

  
24
sub render_node {
25
  my ($menu, $node, $id) = @_;
26
  return '' if !$node->{visible};
27

  
28
  my $icon = get_icon($node->{icon});
29
  my $link = $menu->href_for_node($node) || '#';
30
  my $name = $menu->name_for_node($node);
31

  
32
  html_tag('li',
33
      link_tag($link, $name, target => $node->{target})
34
    . html_tag('ul', render_children($menu, $id * 100, $node->{children} // []),
35
        width => max_width($node)
36
      ),
37
    id        => $id,
38
    (itemIcon => $icon)x!!$icon,
39
  )
40
}
41

  
42
sub render_children {
43
  my ($menu, $id, $children) = @_;
44
  my $sub_id = 1;
45

  
46
  join '', map {
47
    render_node($menu, $_, 100 * $id + $sub_id++)
48
  } @$children
49
}
50

  
51
sub max_width {
52
  11 * ( max( map { length $::locale->text($_->{name}) } @{ $_[0]{children} || [] } ) // 1 )
53
}
54

  
55
sub get_icon {
56
  my $name = $_[0];
57

  
58
  return undef if !defined $name;
59

  
60
  my $simg = "image/icons/svg/$name.svg";
61
  my $pimg = "image/icons/16x16/$name.png";
62

  
63
    SL::System::ResourceCache->get($simg) ? $simg
64
  : SL::System::ResourceCache->get($pimg) ? $pimg
65
  :                                         ();
66
}
67

  
68
1;
69

  
70

  
SL/System/ResourceCache.pm
1
package SL::System::ResourceCache;
2

  
3
use strict;
4
use File::stat;
5
use File::Find;
6

  
7
our @paths = qw(image css);
8
our $cache;
9

  
10
sub generate_data {
11
  return if $cache;
12

  
13
  $cache = {};
14

  
15
  File::Find::find(sub {
16
    $cache->{ $File::Find::name =~ s{^\./}{}r } = stat($_);
17
  }, @paths);
18
}
19

  
20
sub get {
21
  my ($class, $file) = @_;
22
  no warnings 'once';
23

  
24
  return stat($file) if ($::dispatcher // { interface => 'cgi' })->{interface} eq 'cgi';
25

  
26
  $class->generate_data;
27
  $cache->{$file};
28
}
29

  
30
1;
31

  
32

  
33
__END__
34

  
35
=encoding utf-8
36

  
37
=head1 NAME
38

  
39
SL::System::ResourceCache - provides access to resource files without having to access the filesystem all the time
40

  
41
=head1 SYNOPSIS
42

  
43
  use SL::System::ResourceCache;
44

  
45
  SL::System::ResourceCache->get($filename);
46

  
47
=head1 DESCRIPTION
48

  
49
This will stat() all files in the configured paths at startup once, so that
50
subsequent calls can use the cached values. Particularly useful for icons in
51
the menu, which would otherwise generate a few hundred file sytem accesses per
52
request.
53

  
54
The caching will not happen in CGI and script environments.
55

  
56
=head1 FUNCTIONS
57

  
58
=over 4
59

  
60
=item * C<get FILENAME>
61

  
62
If the file exists, returns a L<File::stat> object. If it doesn't exists, returns undef.
63

  
64
=back
65

  
66
=head1 BUGS
67

  
68
None yet :)
69

  
70
=head1 TODO
71

  
72
Make into instance cache and keep it as system wide object
73

  
74
=head1 AUTHOR
75

  
76
Sven Schöling E<lt>sven.schoeling@googlemail.comE<gt>
77

  
78
=cut
79

  
templates/webpages/menu/menunew.html
1
[%- USE T8 %]
2
[%- USE L %]
3
[%- USE HTML %]
4
[%- USE LxERP -%]
5
 <div id="main_menu_div"></div>
6
 [%- SET main_id = '100' %]
7
 <ul id="main_menu_model"  style='display:none'>
8
 [%- FOREACH node = menu.tree %]
9
  [%- NEXT UNLESS node.visible %]
10
  [%- SET main_id = main_id + 1 %]
11
  <li id="[% main_id %]"[% IF icon_path(node.icon) %] itemIcon="[% icon_path(node.icon) %]"[% END %]>
12
   [% L.link(menu.href_for_node(node) || '#', menu.name_for_node(node), target=node.target) %]
13
   [%- IF node.children %]
14
    <ul width="[% max_width(node) %]">
15
     [%- SET sub1_id = main_id * 100 %]
16
     [%- FOREACH sub1node = node.children %]
17
      [%- NEXT UNLESS sub1node.visible %]
18
      [%- SET sub1_id = sub1_id + 1 %]
19
      <li id="[% sub1_id %]"[% IF icon_path(sub1node.icon) %] itemIcon="[% icon_path(sub1node.icon) %]"[% END %]>
20
       [% L.link(menu.href_for_node(sub1node) || '#', menu.name_for_node(sub1node), target=sub1node.target) %]
21
       [%- IF sub1node.children %]
22
        <ul width="[% max_width(sub1node) %]">
23
         [%- SET sub2_id = sub1_id * 100 %]
24
         [%- FOREACH sub2node = sub1node.children %]
25
          [%- NEXT UNLESS sub2node.visible %]
26
          [%- SET sub2_id = sub2_id + 1 %]
27
          <li id="[% sub2_id %]"[% IF icon_path(sub2node.icon) %] itemIcon="[% icon_path(sub2node.icon) %]"[% END %]>
28
            [% L.link(menu.href_for_node(sub2node) || '#', menu.name_for_node(sub2node), target=sub2node.target) %]
29
          </li>
30
         [%- END %]
31
        </ul>
32
       [%- END %]
33
      </li>
34
     [%- END %]
35
    </ul>
36
   [%- END %]
37
  </li>
38
 [%- END %]
39
 </ul>

Auch abrufbar als: Unified diff