Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 9a2cf4dd

Von Sven Schöling vor fast 4 Jahren hinzugefügt

  • ID 9a2cf4ddab7b2094360c5f062ce884ef78787aed
  • Vorgänger 268ed982
  • Nachfolger 432be92f

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
package SL::Layout::DHTMLMenu;
use strict;
use parent qw(SL::Layout::Base);
use SL::Presenter::JavascriptMenu qw(render_menu);
sub static_javascripts {
qw(dhtmlsuite/menu-for-applications.js),
}
sub javascripts_inline {
<<'EOJS',
DHTMLSuite.createStandardObjects();
DHTMLSuite.configObj.setImagePath('image/dhtmlsuite/');
var menu_model = new DHTMLSuite.menuModel();
menu_model.addItemsFromMarkup('main_menu_model');
menu_model.init();
var menu_bar = new DHTMLSuite.menuBar();
menu_bar.addMenuItems(menu_model);
menu_bar.setTarget('main_menu_div');
menu_bar.init();
EOJS
}
sub pre_content {
render_menu($_[0]->menu),
}
sub static_stylesheets {
qw(
dhtmlsuite/menu-item.css
dhtmlsuite/menu-bar.css
icons16.css
menu.css
);
}
1;
SL/Layout/Javascript.pm
use parent qw(SL::Layout::Base);
use SL::Layout::None;
use SL::Layout::DHTMLMenu;
use SL::Layout::Top;
use SL::Layout::ActionBar;
use SL::Layout::Content;
......
[
SL::Layout::None->new,
SL::Layout::Top->new,
SL::Layout::DHTMLMenu->new,
$_[0]->sub_layouts_by_name->{actionbar},
SL::Layout::Content->new,
]
}
sub javascripts {
my ($self) = @_;
return uniq grep { $_ } map { $self->_find_javascript($_) }
map({ $_->javascripts } $self->sub_layouts),
qw(dhtmlsuite/menu-for-applications.js),
$_[0]->sub_layouts_by_name->{actionbar}->javascripts,
$self->use_javascript;
}
sub javascripts_inline {
$_[0]->SUPER::javascripts_inline,
<<'EOJS',
DHTMLSuite.createStandardObjects();
DHTMLSuite.configObj.setImagePath('image/dhtmlsuite/');
var menu_model = new DHTMLSuite.menuModel();
menu_model.addItemsFromMarkup('main_menu_model');
menu_model.init();
var menu_bar = new DHTMLSuite.menuBar();
menu_bar.addMenuItems(menu_model);
menu_bar.setTarget('main_menu_div');
menu_bar.init();
EOJS
$_[0]->sub_layouts_by_name->{actionbar}->javascripts_inline,
}
sub pre_content {
$_[0]->SUPER::pre_content .
$_[0]->presenter->render("menu/menunew",
force_ul_width => 1,
menu => $_[0]->menu,
icon_path => sub { my $simg = "image/icons/svg/$_[0].svg"; my $pimg="image/icons/16x16/$_[0].png"; -f $simg ? $simg : ( -f $pimg ? $pimg : ()) },
max_width => sub { 10 * max map { length $::locale->text($_->{name}) } @{ $_[0]{children} || [] } },
) .
($_[0]->sub_layouts_by_name->{actionbar}->pre_content // '');
}
sub stylesheets {
my ($self) = @_;
my $css_path = $self->get_stylesheet_for_user;
return
uniq
grep { $_ }
map { $self->_find_stylesheet($_, $css_path) }
qw(
dhtmlsuite/menu-item.css
dhtmlsuite/menu-bar.css
icons16.css
menu.css
),
( map { $_->stylesheets } $_[0]->sub_layouts ),
$_[0]->sub_layouts_by_name->{actionbar}->stylesheets,
$_[0]->use_stylesheet;
}
1;
SL/Presenter/JavascriptMenu.pm
package SL::Presenter::JavascriptMenu;
use strict;
use SL::Presenter::EscapedText qw(escape is_escaped);
use SL::Presenter::Tag qw( html_tag link_tag);
use SL::Locale::String qw(t8);
use SL::System::ResourceCache;
use List::Util qw(max);
use Exporter qw(import);
our @EXPORT_OK = qw(render_menu);
sub render_menu {
my ($menu) = @_;
html_tag('div', '', id => 'main_menu_div') .
html_tag('ul', render_children($menu, 100, $menu->{tree}),
id => "main_menu_model",
style => 'display:none',
);
}
sub render_node {
my ($menu, $node, $id) = @_;
return '' if !$node->{visible};
my $icon = get_icon($node->{icon});
my $link = $menu->href_for_node($node) || '#';
my $name = $menu->name_for_node($node);
html_tag('li',
link_tag($link, $name, target => $node->{target})
. html_tag('ul', render_children($menu, $id * 100, $node->{children} // []),
width => max_width($node)
),
id => $id,
(itemIcon => $icon)x!!$icon,
)
}
sub render_children {
my ($menu, $id, $children) = @_;
my $sub_id = 1;
join '', map {
render_node($menu, $_, 100 * $id + $sub_id++)
} @$children
}
sub max_width {
11 * ( max( map { length $::locale->text($_->{name}) } @{ $_[0]{children} || [] } ) // 1 )
}
sub get_icon {
my $name = $_[0];
return undef if !defined $name;
my $simg = "image/icons/svg/$name.svg";
my $pimg = "image/icons/16x16/$name.png";
SL::System::ResourceCache->get($simg) ? $simg
: SL::System::ResourceCache->get($pimg) ? $pimg
: ();
}
1;
SL/System/ResourceCache.pm
package SL::System::ResourceCache;
use strict;
use File::stat;
use File::Find;
our @paths = qw(image css);
our $cache;
sub generate_data {
return if $cache;
$cache = {};
File::Find::find(sub {
$cache->{ $File::Find::name =~ s{^\./}{}r } = stat($_);
}, @paths);
}
sub get {
my ($class, $file) = @_;
no warnings 'once';
return stat($file) if ($::dispatcher // { interface => 'cgi' })->{interface} eq 'cgi';
$class->generate_data;
$cache->{$file};
}
1;
__END__
=encoding utf-8
=head1 NAME
SL::System::ResourceCache - provides access to resource files without having to access the filesystem all the time
=head1 SYNOPSIS
use SL::System::ResourceCache;
SL::System::ResourceCache->get($filename);
=head1 DESCRIPTION
This will stat() all files in the configured paths at startup once, so that
subsequent calls can use the cached values. Particularly useful for icons in
the menu, which would otherwise generate a few hundred file sytem accesses per
request.
The caching will not happen in CGI and script environments.
=head1 FUNCTIONS
=over 4
=item * C<get FILENAME>
If the file exists, returns a L<File::stat> object. If it doesn't exists, returns undef.
=back
=head1 BUGS
None yet :)
=head1 TODO
Make into instance cache and keep it as system wide object
=head1 AUTHOR
Sven Schöling E<lt>sven.schoeling@googlemail.comE<gt>
=cut
templates/webpages/menu/menunew.html
[%- USE T8 %]
[%- USE L %]
[%- USE HTML %]
[%- USE LxERP -%]
<div id="main_menu_div"></div>
[%- SET main_id = '100' %]
<ul id="main_menu_model" style='display:none'>
[%- FOREACH node = menu.tree %]
[%- NEXT UNLESS node.visible %]
[%- SET main_id = main_id + 1 %]
<li id="[% main_id %]"[% IF icon_path(node.icon) %] itemIcon="[% icon_path(node.icon) %]"[% END %]>
[% L.link(menu.href_for_node(node) || '#', menu.name_for_node(node), target=node.target) %]
[%- IF node.children %]
<ul width="[% max_width(node) %]">
[%- SET sub1_id = main_id * 100 %]
[%- FOREACH sub1node = node.children %]
[%- NEXT UNLESS sub1node.visible %]
[%- SET sub1_id = sub1_id + 1 %]
<li id="[% sub1_id %]"[% IF icon_path(sub1node.icon) %] itemIcon="[% icon_path(sub1node.icon) %]"[% END %]>
[% L.link(menu.href_for_node(sub1node) || '#', menu.name_for_node(sub1node), target=sub1node.target) %]
[%- IF sub1node.children %]
<ul width="[% max_width(sub1node) %]">
[%- SET sub2_id = sub1_id * 100 %]
[%- FOREACH sub2node = sub1node.children %]
[%- NEXT UNLESS sub2node.visible %]
[%- SET sub2_id = sub2_id + 1 %]
<li id="[% sub2_id %]"[% IF icon_path(sub2node.icon) %] itemIcon="[% icon_path(sub2node.icon) %]"[% END %]>
[% L.link(menu.href_for_node(sub2node) || '#', menu.name_for_node(sub2node), target=sub2node.target) %]
</li>
[%- END %]
</ul>
[%- END %]
</li>
[%- END %]
</ul>
[%- END %]
</li>
[%- END %]
</ul>

Auch abrufbar als: Unified diff