From: Sven Schöling Date: Thu, 6 Oct 2016 09:42:10 +0000 (+0200) Subject: ActionBar: Funktionierender Prototyp mit submit und actionbutton X-Git-Tag: release-3.5.4~1418 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=e0a3b19e35aed6f3f8ba84e25381a5d0e6ca61f4;p=kivitendo-erp.git ActionBar: Funktionierender Prototyp mit submit und actionbutton --- diff --git a/SL/Layout/ActionBar.pm b/SL/Layout/ActionBar.pm index 3d9e4093a..edbd44e8d 100644 --- a/SL/Layout/ActionBar.pm +++ b/SL/Layout/ActionBar.pm @@ -3,6 +3,8 @@ package SL::Layout::ActionBar; use strict; use parent qw(SL::Layout::Base); +use SL::Layout::ActionBar::Action; + use constant HTML_CLASS => 'layout-actionbar'; use Rose::Object::MakeMethods::Generic ( @@ -13,22 +15,30 @@ use Rose::Object::MakeMethods::Generic ( ###### Layout overrides sub pre_content { - $::request->presenter->html_tag('div', '', class => HTML_CLASS); + my ($self) = @_; + + my $content = join '', map { $_->render } @{ $self->actions }; + $::request->presenter->html_tag('div', $content, class => HTML_CLASS); } -sub inline_javascript { - # data for bar +sub javascripts_inline { + join '', map { $_->script } @{ $_[0]->actions }; } sub javascripts { - + 'kivi.ActionBar.js' } ###### interface sub add_actions { my ($self, @actions) = @_; - push @{ $self->actions }, @actions; + push @{ $self->actions }, map { + !ref $_ ? SL::Layout::ActionBar::Action->from_descriptor($_) + : ref $_ && 'ARRAY' eq ref $_ ? SL::Layout::ActionBar::Action->simple($_) + : ref $_ && $_->isa('SL::Layout::Action') ? $_ + : do { die 'invalid action' }; + } @actions; } sub init_actions { @@ -93,7 +103,7 @@ Dispatches each each argument to C This is accessable through - $::request->layout->actionbar + $::request->layout->get('actionbar') =head1 DOM MODEL diff --git a/SL/Layout/ActionBar/Action.pm b/SL/Layout/ActionBar/Action.pm new file mode 100644 index 000000000..454255c8c --- /dev/null +++ b/SL/Layout/ActionBar/Action.pm @@ -0,0 +1,68 @@ +package SL::Layout::ActionBar::Action; + +use strict; +use parent qw(Rose::Object); + +use SL::Presenter; + +use Rose::Object::MakeMethods::Generic ( + 'scalar --get_set_init' => [ qw(id) ], +); + +# subclassing interface + +sub render { + die 'needs to be implemented'; +} + +sub script { + die 'needs to be implemented'; +} + + +# static constructors + +sub from_descriptor { + my ($class, $descriptor) = @_;a + + { + separator => SL::Layout::ActionBar::Separator->new, + } or die 'unknown descriptor'; +} + +# TODO: this necessary? +sub simple { + my ($class, $data) = @_; + + my ($text, %params) = @$data; + + if ($params{submit}) { + require SL::Layout::ActionBar::Submit; + return SL::Layout::ActionBar::Submit->new(text => $text, %params); + } + + if ($params{function}) { + require SL::Layout::ActionBar::ScriptButton; + return SL::Layout::ActionBar::ScriptButton->new(text => $text, %params); + } + + if ($params{combobox}) { + + } +} + +# shortcut for presenter + +sub p { + SL::Presenter->get +} + +# unique id to tie div and javascript together +sub init_id { + $_[0]->p->name_to_id('action[]') +} + + +1; + +__END__ diff --git a/SL/Layout/ActionBar/ScriptButton.pm b/SL/Layout/ActionBar/ScriptButton.pm new file mode 100644 index 000000000..47c1247af --- /dev/null +++ b/SL/Layout/ActionBar/ScriptButton.pm @@ -0,0 +1,26 @@ +package SL::Layout::ActionBar::ScriptButton; + +use strict; +use parent qw(SL::Layout::ActionBar::Action); + +use JSON; + +use Rose::Object::MakeMethods::Generic ( + 'scalar --get_set_init' => [ qw(text function) ], +); + +sub render { + $_[0]->p->html_tag('div', $_[0]->text, + id => $_[0]->id, + class => 'layout-actionbar-action layout-actionbar-scriptbutton', + ); +} + +sub script { + # store submit and form and stuff in data attribute + sprintf q|$('#%s').data('action', %s);|, $_[0]->id, JSON::to_json({ + function => $_[0]->function, + }); +} + +1; diff --git a/SL/Layout/ActionBar/Separator.pm b/SL/Layout/ActionBar/Separator.pm new file mode 100644 index 000000000..9fc172c17 --- /dev/null +++ b/SL/Layout/ActionBar/Separator.pm @@ -0,0 +1,10 @@ +package SL::Layout::ActionBar::Separator; + +use strict; +use parent qw(SL::Layout::ActionBar::Action); + +sub render { + $_[0]->p->html_tag('div', '', class => 'layout-actionbar-separator'); +} + +1; diff --git a/SL/Layout/ActionBar/Submit.pm b/SL/Layout/ActionBar/Submit.pm new file mode 100644 index 000000000..751a96915 --- /dev/null +++ b/SL/Layout/ActionBar/Submit.pm @@ -0,0 +1,26 @@ +package SL::Layout::ActionBar::Submit; + +use strict; +use parent qw(SL::Layout::ActionBar::Action); + +use JSON; + +use Rose::Object::MakeMethods::Generic ( + 'scalar --get_set_init' => [ qw(text submit) ], +); + +sub render { + $_[0]->p->html_tag('div', $_[0]->text, + id => $_[0]->id, + class => 'layout-actionbar-action layout-actionbar-submit', + ); +} + +sub script { + # store submit and form and stuff in data attribute + sprintf q|$('#%s').data('action', %s);|, $_[0]->id, JSON::to_json({ + submit => $_[0]->submit, + }); +} + +1; diff --git a/SL/Layout/Base.pm b/SL/Layout/Base.pm index e39502f1f..c2590449c 100644 --- a/SL/Layout/Base.pm +++ b/SL/Layout/Base.pm @@ -7,7 +7,7 @@ use List::MoreUtils qw(uniq); use Time::HiRes qw(); use Rose::Object::MakeMethods::Generic ( - 'scalar --get_set_init' => [ qw(menu auto_reload_resources_param) ], + 'scalar --get_set_init' => [ qw(menu auto_reload_resources_param sub_layouts_by_name) ], 'scalar' => qw(focus), 'array' => [ 'add_stylesheets_inline' => { interface => 'add', hash_key => 'stylesheets_inline' }, @@ -32,6 +32,15 @@ sub init_menu { SL::Menu->new('user'); } +sub init_sublayouts_by_name { + {} +} + +sub get { + $_[0]->sub_layouts; + $_[0]->sub_layouts_by_name->{$_[1]} +} + sub init_auto_reload_resources_param { return '' unless $::lx_office_conf{debug}->{auto_reload_resources}; return sprintf('?rand=%d-%d-%d', Time::HiRes::gettimeofday(), int(rand 1000000000000)); @@ -69,6 +78,8 @@ sub javascripts_inline { sub init_sub_layouts { [] } +sub init_sub_layouts_by_name { +{} } + ######################################### # Interface diff --git a/SL/Layout/Classic.pm b/SL/Layout/Classic.pm index 7575a1ac9..e8974c143 100644 --- a/SL/Layout/Classic.pm +++ b/SL/Layout/Classic.pm @@ -7,15 +7,18 @@ use SL::Layout::Top; use SL::Layout::MenuLeft; use SL::Layout::None; use SL::Layout::Split; +use SL::Layout::ActionBar; use SL::Layout::Content; sub init_sub_layouts { + $_[0]->sub_layouts_by_name->{actionbar} = SL::Layout::ActionBar->new; + [ SL::Layout::None->new, SL::Layout::Top->new, SL::Layout::Split->new( left => [ SL::Layout::MenuLeft->new ], - right => [ SL::Layout::Content->new ], + right => [ $_[0]->sub_layouts_by_name->{actionbar}, SL::Layout::Content->new ], ) ] } diff --git a/SL/Layout/Split.pm b/SL/Layout/Split.pm index e8e2a88f0..5b5484076 100644 --- a/SL/Layout/Split.pm +++ b/SL/Layout/Split.pm @@ -18,8 +18,8 @@ sub pre_content { my $left = join '', map { $_->pre_content } @{ $_[0]->left || [] }; my $right = join '', map { $_->pre_content } @{ $_[0]->right || [] }; - SL::Presenter->get->html_tag('div', $left, class => 't-layout-left') - .'
' . $right; + SL::Presenter->get->html_tag('div', $left, class => 'layout-split-left') + .'
' . $right; } sub post_content { diff --git a/css/lx-office-erp/main.css b/css/lx-office-erp/main.css index 13f9c6994..2b9042cbf 100644 --- a/css/lx-office-erp/main.css +++ b/css/lx-office-erp/main.css @@ -534,4 +534,44 @@ a.red { #bank_transactions_proposals span.invoice_number_highlight { background-color: #006400; color: #FFFFFF; + +} + +/* actionbar styling */ +div.layout-actionbar { + background-color: whitesmoke; +} + +div.layout-actionbar-action { + transition: background-color 0s; + -moz-transition: background-color 0s; + -webkit-transition: background-color 0s; +} + +div.layout-actionbar div.layout-actionbar-submit, +div.layout-actionbar div.layout-actionbar-scriptbutton, +div.layout-actionbar div.layout-actionbar-submit:focus, +div.layout-actionbar div.layout-actionbar-scriptbutton:focus { + display: inline-block; + box-sizing: border-box; + border: 1px; + border-color: darkgray; + border-style: solid; + padding: 4px 4px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; + background-color: whitesmoke; + cursor:default; +} + +div.layout-actionbar div.layout-actionbar-submit:hover, +div.layout-actionbar div.layout-actionbar-scriptbutton:hover { + border: 1px; + background-color: lightgray; + border-color: gray; + border-style: solid; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + border-radius: 2px; } diff --git a/js/kivi.ActionBar.js b/js/kivi.ActionBar.js new file mode 100644 index 000000000..aeba436d9 --- /dev/null +++ b/js/kivi.ActionBar.js @@ -0,0 +1,35 @@ +namespace('kivi', function(k){ + 'use strict'; + + k.ActionBarAction = function(e) { + var data = $(e).data('action'); + // dispatch as needed + if (data.submit) { + var form = data.submit[0]; + var params = data.submit[1]; + $(e).click(function(event) { + var $hidden, key; + for (key in params) { + $hidden = $('') + $hidden.attr('name', key) + $hidden.attr('value', params[key]) + $(form).append($hidden) + } + $(form).submit() + }) + } else if (data.function) { + // TODO: what to do with templated calls + console.log(data.function) + $(e).click(function(event) { + var func = kivi.get_function_by_name(data.function[0]); + func.apply(document, data.function.slice(1)) + }); + } + } +}); + +$(function(){ + $('div.layout-actionbar .layout-actionbar-action').each(function(_, e) { + kivi.ActionBarAction(e); + }); +});