From 76cad4416d845e3fe0e8a07e6288c785e52f134d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sven=20Sch=C3=B6ling?= Date: Fri, 5 Mar 2021 18:52:30 +0100 Subject: [PATCH] MaterialComponents Presenter MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Erstmal für die wichtigsten Elemente: - buttons - submit - input felder - icons Zusammen mit einem Testcontroller zum rendern --- SL/Controller/MaterializeTest.pm | 10 + SL/Presenter/ALL.pm | 2 + SL/Presenter/MaterialComponents.pm | 183 ++++++++++++++++++ .../mobile_webpages/test/components.html | 29 +++ 4 files changed, 224 insertions(+) create mode 100644 SL/Controller/MaterializeTest.pm create mode 100644 SL/Presenter/MaterialComponents.pm create mode 100644 templates/mobile_webpages/test/components.html diff --git a/SL/Controller/MaterializeTest.pm b/SL/Controller/MaterializeTest.pm new file mode 100644 index 000000000..de7918202 --- /dev/null +++ b/SL/Controller/MaterializeTest.pm @@ -0,0 +1,10 @@ +package SL::Controller::MaterializeTest; + +use strict; +use parent qw(SL::Controller::Base); + +sub action_test { + $_[0]->render("test/components"); +} + +1; diff --git a/SL/Presenter/ALL.pm b/SL/Presenter/ALL.pm index a4bd72493..974b1a6e4 100644 --- a/SL/Presenter/ALL.pm +++ b/SL/Presenter/ALL.pm @@ -23,6 +23,7 @@ use SL::Presenter::ShopOrder; use SL::Presenter::Text; use SL::Presenter::Tag; use SL::Presenter::BankAccount; +use SL::Presenter::MaterialComponents; our %presenters = ( chart => 'SL::Presenter::Chart', @@ -46,6 +47,7 @@ our %presenters = ( text => 'SL::Presenter::Text', tag => 'SL::Presenter::Tag', bank_account => 'SL::Presenter::BankAccount', + M => 'SL::Presenter::MaterialComponents', ); sub wrap { diff --git a/SL/Presenter/MaterialComponents.pm b/SL/Presenter/MaterialComponents.pm new file mode 100644 index 000000000..e3f018110 --- /dev/null +++ b/SL/Presenter/MaterialComponents.pm @@ -0,0 +1,183 @@ +package SL::Presenter::MaterialComponents; + +use strict; + +use SL::HTML::Restrict; +use SL::Presenter::EscapedText qw(escape); +use SL::Presenter::Tag qw(html_tag); +use Scalar::Util qw(blessed); + +use Exporter qw(import); +our @EXPORT_OK = qw( + button_tag +); +our %EXPORT_TAGS = (ALL => \@EXPORT_OK); + +use constant BUTTON => 'btn'; +use constant BUTTON_FLAT => 'btn-flat'; +use constant BUTTON_FLOATING => 'btn-floating'; +use constant BUTTON_LARGE => 'btn-large'; +use constant BUTTON_SMALL => 'btn-small'; +use constant DISABLED => 'disabled'; +use constant LEFT => 'left'; +use constant MATERIAL_ICONS => 'material-icons'; +use constant RIGHT => 'right'; +use constant LARGE => 'large'; +use constant MEDIUM => 'medium'; +use constant SMALL => 'small'; +use constant TINY => 'tiny'; + +use constant WAVES_EFFECT => 'waves-effect'; +use constant WAVES_LIGHT => 'waves-light'; + + +my %optional_classes = ( + button => { + disabled => DISABLED, + flat => BUTTON_FLAT, + floating => BUTTON_FLOATING, + large => BUTTON_LARGE, + small => BUTTON_SMALL, + }, + icon => { + left => LEFT, + right => RIGHT, + large => LARGE, + medium => MEDIUM, + small => SMALL, + tiny => TINY, + }, +); + +use Carp; + +sub _confirm_js { + 'if (!confirm("'. _J($_[0]) .'")) return false;' +} + +sub _confirm_to_onclick { + my ($attributes, $onclick) = @_; + + if ($attributes->{confirm}) { + $$onclick //= ''; + $$onclick = _confirm_js(delete($attributes->{confirm})) . $attributes->{onlick}; + } +} + +# used to extract material properties that need to be translated to classes +# supports prefixing for delegation +# returns a list of classes, mutates the attributes +sub _extract_attribute_classes { + my ($attributes, $type, $prefix) = @_; + + my @classes; + my $attr; + for my $key (keys %$attributes) { + if ($prefix) { + next unless $key =~ /^${prefix}_(.*)/; + $attr = $1; + } else { + $attr = $key; + } + + if ($optional_classes{$type}{$attr}) { + $attributes->{$key} = undef; + push @classes, $optional_classes{$type}{$attr}; + } + } + + # delete all undefined values + my @delete_keys = grep { !defined $attributes->{$_} } keys %$attributes; + delete $attributes->{$_} for @delete_keys; + + @classes; +} + +sub button_tag { + my ($onclick, $value, %attributes) = @_; + + _set_id_attribute(\%attributes, $attributes{name}) if $attributes{name}; + _confirm_to_onclick(\%attributes, \$onclick); + + my @button_classes = _extract_attribute_classes(\%attributes, "button"); + my @icon_classes = _extract_attribute_classes(\%attributes, "icon", "icon"); + + $attributes{class} = [ + grep { $_ } $attributes{class}, WAVES_EFFECT, WAVES_LIGHT, BUTTON, @button_classes + ]; + + if ($attributes{icon}) { + $value = icon(delete $attributes{icon}, class => \@icon_classes) + . $value; + } + + html_tag('a', $value, %attributes, onclick => $onclick); +} + +sub submit_tag { + my ($name, $value, %attributes) = @_; + + _set_id_attribute(\%attributes, $attributes{name}) if $attributes{name}; + _confirm_to_onclick(\%attributes, \($attributes{onclick} //= '')); + + my @button_classes = _extract_attribute_classes(\%attributes, "button"); + my @icon_classes = _extract_attribute_classes(\%attributes, "icon", "icon"); + + $attributes{class} = [ + grep { $_ } $attributes{class}, WAVES_EFFECT, WAVES_LIGHT, BUTTON, @button_classes + ]; + + if ($attributes{icon}) { + $value = icon(delete $attributes{icon}, class => \@icon_classes) + . $value; + } + + html_tag('button', $value, type => 'submit', %attributes); +} + + +sub icon { + my ($name, %attributes) = @_; + + my @icon_classes = _extract_attribute_classes(\%attributes, "icon"); + + html_tag('i', $name, class => [ grep { $_ } MATERIAL_ICONS, @icon_classes, delete $attributes{class} ], %attributes); +} + + +sub input_tag { + my ($name, $value, %attributes) = @_; + + # todo icons + # todo label/active + # todo validate + + html_tag('input', $name, $value, %attributes) . html_tag('label', for => $attributes{id}, $name); +} + + +1; +__END__ + +=pod + +=encoding utf8 + +=head1 NAME + +SL::Presenter::MaterialComponents - MaterialCSS Component wrapper + +=head1 SYNOPSIS + + +=head1 DESCRIPTION + +=head1 BUGS + +Nothing here yet. + +=head1 AUTHOR + +Sven Schöling Es.schoeling@googlemail.comE + +=cut diff --git a/templates/mobile_webpages/test/components.html b/templates/mobile_webpages/test/components.html new file mode 100644 index 000000000..6af2d2c4b --- /dev/null +++ b/templates/mobile_webpages/test/components.html @@ -0,0 +1,29 @@ +[% USE P %] + +

Material Components Tests

+ + +

Buttons

+ +[% P.M.button_tag("", "button") %] +[% P.M.button_tag("", P.M.icon('add'), floating=1) %] +[% P.M.submit_tag("", "submit") %] +[% P.M.submit_tag("", "disabled submit", disabled=1) %] +[% P.M.button_tag("", "button with left icon", icon="cloud", icon_left=1) %] +[% P.M.button_tag("", "button with right icon", icon="save", icon_right=1) %] +[% P.M.button_tag("", "flat button", flat=1) %] +[% P.M.button_tag("", "large button", large=1) %] +[% P.M.button_tag("", "small button", small=1) %] +[% P.M.button_tag("", "disabled small button", disabled=1, small=1) %] + +

Icons

+ +[% P.M.icon("alarm") %] +[% P.M.icon("alarm", large=1) %] +[% P.M.icon("alarm", medium=1) %] +[% P.M.icon("alarm", small=1) %] +[% P.M.icon("alarm", tiny=1) %] + +

Inputs

+ +[% P.M.input_tag("", "test string") %] -- 2.20.1