use strict;
use parent qw(SL::Layout::Base);
+use SL::Layout::ActionBar::Action;
+
use constant HTML_CLASS => 'layout-actionbar';
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 {
This is accessable through
- $::request->layout->actionbar
+ $::request->layout->get('actionbar')
=head1 DOM MODEL
--- /dev/null
+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__
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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;
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' },
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));
sub init_sub_layouts { [] }
+sub init_sub_layouts_by_name { +{} }
+
#########################################
# Interface
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 ],
)
]
}
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 {
#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;
}
--- /dev/null
+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);
+ });
+});