ActionBar: Funktionierender Prototyp mit submit und actionbutton
authorSven Schöling <s.schoeling@linet-services.de>
Thu, 6 Oct 2016 09:42:10 +0000 (11:42 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Tue, 28 Feb 2017 09:04:33 +0000 (10:04 +0100)
SL/Layout/ActionBar.pm
SL/Layout/ActionBar/Action.pm [new file with mode: 0644]
SL/Layout/ActionBar/ScriptButton.pm [new file with mode: 0644]
SL/Layout/ActionBar/Separator.pm [new file with mode: 0644]
SL/Layout/ActionBar/Submit.pm [new file with mode: 0644]
SL/Layout/Base.pm
SL/Layout/Classic.pm
SL/Layout/Split.pm
css/lx-office-erp/main.css
js/kivi.ActionBar.js [new file with mode: 0644]

index 3d9e409..edbd44e 100644 (file)
@@ -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<add_action>
 
 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 (file)
index 0000000..454255c
--- /dev/null
@@ -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 (file)
index 0000000..47c1247
--- /dev/null
@@ -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 (file)
index 0000000..9fc172c
--- /dev/null
@@ -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 (file)
index 0000000..751a969
--- /dev/null
@@ -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;
index e39502f..c259044 100644 (file)
@@ -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
index 7575a1a..e8974c1 100644 (file)
@@ -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 ],
     )
   ]
 }
index e8e2a88..5b54840 100644 (file)
@@ -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')
-  .'<div class="t-layout-right html-menu">' . $right;
+  SL::Presenter->get->html_tag('div', $left, class => 'layout-split-left')
+  .'<div class="layout-split-right">' . $right;
 }
 
 sub post_content {
index 13f9c69..2b9042c 100644 (file)
@@ -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 (file)
index 0000000..aeba436
--- /dev/null
@@ -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 = $('<input type=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);
+  });
+});