From 54daa586799871ce5ede8f628a03ea55a9660cf5 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Fri, 8 Mar 2013 15:31:36 +0100 Subject: [PATCH] =?utf8?q?Pflichtenhefte:=20Erste=20Version=20Baumansicht?= =?utf8?q?=20Textbl=C3=B6cke/Abschnitte/Funktionsbl=C3=B6cke?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- SL/Controller/RequirementSpec.pm | 58 ++++---- SL/Controller/RequirementSpecItem.pm | 93 +++++++++++++ SL/Controller/RequirementSpecTextBlock.pm | 62 +++++++++ SL/Presenter.pm | 1 + SL/Presenter/RequirementSpec.pm | 39 ++++++ css/kivitendo/jquery-ui.custom.css | 5 + css/requirement_spec.css | 4 + js/requirement_spec.js | 105 ++++++++++++++ js/themes/requirement-spec/d.gif | Bin 0 -> 2944 bytes js/themes/requirement-spec/d.png | Bin 0 -> 7635 bytes js/themes/requirement-spec/style.css | 74 ++++++++++ js/themes/requirement-spec/throbber.gif | Bin 0 -> 1849 bytes locale/de/all | 3 + templates/webpages/requirement_spec/tree.html | 131 ++++++++++++++++++ .../requirement_spec_item/_section_form.html | 24 ++++ 15 files changed, 573 insertions(+), 26 deletions(-) create mode 100644 SL/Controller/RequirementSpecItem.pm create mode 100644 SL/Controller/RequirementSpecTextBlock.pm create mode 100644 SL/Presenter/RequirementSpec.pm create mode 100644 js/requirement_spec.js create mode 100644 js/themes/requirement-spec/d.gif create mode 100644 js/themes/requirement-spec/d.png create mode 100644 js/themes/requirement-spec/style.css create mode 100644 js/themes/requirement-spec/throbber.gif create mode 100644 templates/webpages/requirement_spec/tree.html create mode 100644 templates/webpages/requirement_spec_item/_section_form.html diff --git a/SL/Controller/RequirementSpec.pm b/SL/Controller/RequirementSpec.pm index b865d2924..d7d897867 100644 --- a/SL/Controller/RequirementSpec.pm +++ b/SL/Controller/RequirementSpec.pm @@ -23,7 +23,7 @@ use Rose::Object::MakeMethods::Generic ); __PACKAGE__->run_before('setup'); -__PACKAGE__->run_before('load_requirement_spec', only => [ qw( edit update destroy) ]); +__PACKAGE__->run_before('load_requirement_spec', only => [ qw( edit update destroy tree) ]); __PACKAGE__->run_before('load_select_options', only => [ qw(new edit create update list) ]); __PACKAGE__->run_before('load_search_select_options', only => [ qw( list) ]); @@ -109,6 +109,11 @@ sub action_reorder { $self->render('1;', { type => 'js', inline => 1 }); } +sub action_tree { + my ($self) = @_; + my $r = $self->render('requirement_spec/tree', now => DateTime->now); +} + # # filters # @@ -117,12 +122,37 @@ sub setup { my ($self) = @_; $::auth->assert('config'); - $::request->{layout}->use_stylesheet("requirement_spec.css"); + $::request->{layout}->use_stylesheet("${_}.css") for qw(requirement_spec yaml/core/base.min); + $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree requirement_spec); $self->is_template($::form->{is_template} ? 1 : 0); return 1; } +sub load_requirement_spec { + my ($self) = @_; + $self->{requirement_spec} = SL::DB::RequirementSpec->new(id => $::form->{id})->load || die "No such requirement spec"; +} + +sub load_select_options { + my ($self) = @_; + + my @filter = ('!obsolete' => 1); + if ($self->requirement_spec && $self->requirement_spec->customer_id) { + @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] ); + } + + $self->customers(SL::DB::Manager::Customer->get_all_sorted(where => \@filter)); + $self->statuses( SL::DB::Manager::RequirementSpecStatus->get_all_sorted); + $self->types( SL::DB::Manager::RequirementSpecType->get_all_sorted); +} + +sub load_search_select_options { + my ($self) = @_; + + $self->projects(SL::DB::Manager::Project->get_all_sorted); +} + # # helpers # @@ -149,30 +179,6 @@ sub create_or_update { $self->redirect_to(action => 'list'); } -sub load_requirement_spec { - my ($self) = @_; - $self->{requirement_spec} = SL::DB::RequirementSpec->new(id => $::form->{id})->load; -} - -sub load_select_options { - my ($self) = @_; - - my @filter = ('!obsolete' => 1); - if ($self->requirement_spec && $self->requirement_spec->customer_id) { - @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] ); - } - - $self->customers(SL::DB::Manager::Customer->get_all_sorted(where => \@filter)); - $self->statuses( SL::DB::Manager::RequirementSpecStatus->get_all_sorted); - $self->types( SL::DB::Manager::RequirementSpecType->get_all_sorted); -} - -sub load_search_select_options { - my ($self) = @_; - - $self->projects(SL::DB::Manager::Project->get_all_sorted); -} - sub setup_db_args_from_filter { my ($self) = @_; diff --git a/SL/Controller/RequirementSpecItem.pm b/SL/Controller/RequirementSpecItem.pm new file mode 100644 index 000000000..6ddf3a63a --- /dev/null +++ b/SL/Controller/RequirementSpecItem.pm @@ -0,0 +1,93 @@ +package SL::Controller::RequirementSpecItem; + +use strict; + +use parent qw(SL::Controller::Base); + +use Time::HiRes (); + +use SL::DB::RequirementSpec; +use SL::DB::RequirementSpecItem; +use SL::Helper::Flash; +use SL::JSON; +use SL::Locale::String; + +use Rose::Object::MakeMethods::Generic +( + scalar => [ qw(requirement_spec item) ], +); + +# __PACKAGE__->run_before('load_requirement_spec'); +__PACKAGE__->run_before('load_requirement_spec_item', only => [qw(dragged_and_dropped)]); + +# +# actions +# + +sub action_new { + my ($self) = @_; + + eval { + my $type = ($::form->{item_type} || '') =~ m/^ (?: section | (?: sub-)? function-block ) $/x ? $::form->{item_type} : die "Invalid item_type"; + $self->{item} = SL::DB::RequirementSpecItem->new(requirement_spec_id => $::form->{requirement_spec_id}); + my $section_form = $self->presenter->render("requirement_spec_item/_${type}_form", id => create_random_id(), title => t8('Create a new section')); + + $self->render(\to_json({ status => 'ok', html => $section_form }), { type => 'json' }); + 1; + } or do { + $self->render(\to_json({ status => 'failed', error => "Exception:\n" . format_exception() }), { type => 'json' }); + } +} + +sub action_create { + my ($self) = @_; + + my $type = ($::form->{item_type} || '') =~ m/^ (?: section | (?: sub-)? function-block ) $/x ? $::form->{item_type} : die "Invalid item_type"; + + $self->render(\to_json({ status => 'failed', error => 'not good, not good' }), { type => 'json' }); +} + +sub action_dragged_and_dropped { + my ($self) = @_; + + $::lxdebug->dump(0, "form", $::form); + + my $dropped_item = SL::DB::RequirementSpecItem->new(id => $::form->{dropped_id})->load || die "No such dropped item"; + my $position = $::form->{position} =~ m/^ (?: before | after | last ) $/x ? $::form->{position} : die "Unknown 'position' parameter"; + + $self->item->db->do_transaction(sub { + $self->item->remove_from_list; + $self->item->parent_id($position =~ m/before|after/ ? $dropped_item->parent_id : $dropped_item->id); + $self->item->add_to_list(position => $position, reference => $dropped_item->id); + }); + + $self->render(\'', { type => 'json' }); +} + +# +# filters +# + +sub load_requirement_spec { + my ($self) = @_; + $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load || die "No such requirement spec"); +} + +sub load_requirement_spec_item { + my ($self) = @_; + $self->item(SL::DB::RequirementSpecItem->new(id => $::form->{id})->load || die "No such requirement spec item"); +} + +# +# helpers +# + +sub create_random_id { + return join '-', Time::HiRes::gettimeofday(); +} + +sub format_exception { + return join "\n", (split m/\n/, $@)[0..4]; +} + +1; diff --git a/SL/Controller/RequirementSpecTextBlock.pm b/SL/Controller/RequirementSpecTextBlock.pm new file mode 100644 index 000000000..4f5074098 --- /dev/null +++ b/SL/Controller/RequirementSpecTextBlock.pm @@ -0,0 +1,62 @@ +package SL::Controller::RequirementSpecTextBlock; + +use strict; + +use parent qw(SL::Controller::Base); + +use SL::DB::RequirementSpec; +use SL::DB::RequirementSpecTextBlock; +use SL::Helper::Flash; +use SL::Locale::String; + +use Rose::Object::MakeMethods::Generic +( + scalar => [ qw(requirement_spec text_block) ], +); + +# __PACKAGE__->run_before('load_requirement_spec'); +__PACKAGE__->run_before('load_requirement_spec_text_block', only => [qw(dragged_and_dropped)]); + +# +# actions +# + +sub action_dragged_and_dropped { + my ($self) = @_; + + $::lxdebug->dump(0, "form", $::form); + + my $position = $::form->{position} =~ m/^ (?: before | after | last ) $/x ? $::form->{position} : die "Unknown 'position' parameter"; + my $dropped_text_block = $position =~ m/^ (?: before | after ) $/x ? SL::DB::RequirementSpecTextBlock->new(id => $::form->{dropped_id})->load : undef; + + my $dropped_type = $position ne 'last' ? undef : $::form->{dropped_type} =~ m/^ textblocks- (?:front|back) $/x ? $::form->{dropped_type} : die "Unknown 'dropped_type' parameter"; + + $self->text_block->db->do_transaction(sub { + 1; + $self->text_block->remove_from_list; + $self->text_block->output_position($position =~ m/before|after/ ? $dropped_text_block->output_position : $::form->{dropped_type} eq 'textblocks-front' ? 0 : 1); + $self->text_block->add_to_list(position => $position, reference => $dropped_text_block ? $dropped_text_block->id : undef); + }); + + $self->render(\'', { type => 'json' }); +} + +# +# filters +# + +sub load_requirement_spec { + my ($self) = @_; + $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load || die "No such requirement spec"); +} + +sub load_requirement_spec_text_block { + my ($self) = @_; + $self->text_block(SL::DB::RequirementSpecTextBlock->new(id => $::form->{id})->load || die "No such requirement spec text block"); +} + +# +# helpers +# + +1; diff --git a/SL/Presenter.pm b/SL/Presenter.pm index 23b8ad472..f0a0259a2 100644 --- a/SL/Presenter.pm +++ b/SL/Presenter.pm @@ -15,6 +15,7 @@ use SL::Presenter::Order; use SL::Presenter::Part; use SL::Presenter::Project; use SL::Presenter::Record; +use SL::Presenter::RequirementSpec; use SL::Presenter::SepaExport; use SL::Presenter::Text; use SL::Presenter::Tag; diff --git a/SL/Presenter/RequirementSpec.pm b/SL/Presenter/RequirementSpec.pm new file mode 100644 index 000000000..fe9df960c --- /dev/null +++ b/SL/Presenter/RequirementSpec.pm @@ -0,0 +1,39 @@ +package SL::Presenter::RequirementSpec; + +use strict; + +use parent qw(Exporter); + +use Exporter qw(import); +our @EXPORT = qw(requirement_spec_text_block_jstree_data + requirement_spec_item_jstree_data); + +use Carp; + +use SL::JSON; + +sub requirement_spec_text_block_jstree_data { + my ($self, $text_block, %params) = @_; + + return { + data => $text_block->title || '', + metadata => { id => $text_block->id, type => 'textblock' }, + attr => { id => "tb-" . $text_block->id, href => $params{href} || '#' }, + }; +} + +sub requirement_spec_item_jstree_data { + my ($self, $item, %params) = @_; + + my @children = map { $self->requirement_spec_item_jstree_data($_, %params) } @{ $item->sorted_children }; + my $type = !$item->parent_id ? 'section' : 'functionblock'; + + return { + data => join(' ', map { $_ || '' } ($item->fb_number, $item->title)), + metadata => { id => $item->id, type => $type }, + attr => { id => "fb-" . $item->id, href => $params{href} || '#' }, + children => \@children, + }; +} + +1; diff --git a/css/kivitendo/jquery-ui.custom.css b/css/kivitendo/jquery-ui.custom.css index be1686b2b..4f8a19d5c 100644 --- a/css/kivitendo/jquery-ui.custom.css +++ b/css/kivitendo/jquery-ui.custom.css @@ -118,3 +118,8 @@ text-align: left; font-size:125%; } + +/* jstree */ +.jstree a { + border-bottom: none; +} diff --git a/css/requirement_spec.css b/css/requirement_spec.css index 19faf7500..08b6d2be9 100644 --- a/css/requirement_spec.css +++ b/css/requirement_spec.css @@ -2,3 +2,7 @@ input.rs_input_field, select.rs_input_field, table.rs_input_field input, table.rs_input_field select { width: 300px; } + +#content-column { + margin-left: 10px; +} diff --git a/js/requirement_spec.js b/js/requirement_spec.js new file mode 100644 index 000000000..2b0d2007a --- /dev/null +++ b/js/requirement_spec.js @@ -0,0 +1,105 @@ +/* Functions used for the requirement specs tree view */ + +function check_move(data) { + var dragged_type = data.o.data('type'); + var dropped_type = data.r.data('type'); + + // console.debug("dragged " + dragged_type + " dropped " + dropped_type + " dir " + data.p); + + if ((dragged_type == "sections") || (dragged_type == "textblocks-front") || (dragged_type == "textblocks-back")) + return false; + + if (dragged_type == "textblock") { + if ((dropped_type == "textblocks-front") || (dropped_type == "textblocks-back")) + return (data.p == "inside") || (data.p == "last"); + if (dropped_type == "textblock") + return (data.p == "before") || (data.p == "after"); + + return false; + } + + if (dragged_type == "section") { + if (dropped_type == "sections") + return (data.p == "inside") || (data.p == "last"); + if (dropped_type == "section") + return (data.p == "before") || (data.p == "after"); + + return false; + } + + // dragged_type == (sub) function blocks + if ((dropped_type == "textblock") || (dropped_type == "textblocks-front") || (dropped_type == "textblocks-back")) + return false; + + var dropped_depth = dropped_type == "sections" ? 0 : dropped_type == "section" ? 1 : data.r.parent().parent().data('type') != "functionblock" ? 2 : 3; + if ((data.p == "inside") || (data.p == "last")) + dropped_depth++; + + var dragged_depth = 1 + data.o.children('ul').size(); + + // console.debug("dropped_depth " + dropped_depth + " dragged_depth " + dragged_depth); + + return (2 <= dropped_depth) && ((dragged_depth + dropped_depth) <= 4); +} + +function node_moved(event) { + console.debug("node moved"); + var move_obj = $.jstree._reference('#tree')._get_move(); + var dragged = move_obj.o; + var dropped = move_obj.r; + var controller = dragged.data("type") == "textblock" ? "RequirementSpecTextBlock" : "RequirementSpecItem"; + var data = { + action: controller + "/dragged_and_dropped", + requirement_spec_id: $('#requirement_spec_id').val(), + id: dragged.data("id"), + dropped_id: dropped.data("id"), + dropped_type: dropped.data("type"), + position: move_obj.p + }; + // console.debug("controller: " + controller); + // console.debug(data); + + $.ajax({ url: "controller.pl", data: data }); +} + +function section_form_requested(data) { + $('#new-section-button').removeAttr('disabled'); + if (data.status == "ok") + $('#content-column').html(data.html); + else + alert('oh yeah response: ' + data.status + "\n" + data.error); +} + +function section_form_submitted(data) { + alert('oh yeah response: ' + data.status); +} + +function server_side_error(things_to_enable) { + alert('Server-side error.'); + if (things_to_enable) + $(things_to_enable).removeAttr('disabled'); +} + +function new_section_form() { + $('#new-section-button').attr('disabled', 'disabled'); + $.ajax({ + type: 'POST', + url: 'controller.pl', + data: 'action=RequirementSpecItem/new.json&requirement_spec_id=' + $('#requirement_spec_id').val() + '&item_type=section', + success: section_form_requested, + error: function() { server_side_error('#new-section-button'); } + }); +} + +function submit_section_form(id) { + $.ajax({ + type: 'POST', + url: 'controller.pl', + data: 'action=RequirementSpecItem/create.json&' + $('section-form-' + id).serialize(), + success: section_form_submitted + }); +} + +function cancel_section_form(id) { + $('#content-column').html('intentionally empty'); +} diff --git a/js/themes/requirement-spec/d.gif b/js/themes/requirement-spec/d.gif new file mode 100644 index 0000000000000000000000000000000000000000..0e958d38716d93d4050a993398dec77490f836c7 GIT binary patch literal 2944 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 literal 0 HcmV?d00001 diff --git a/js/themes/requirement-spec/d.png b/js/themes/requirement-spec/d.png new file mode 100644 index 0000000000000000000000000000000000000000..8540175a04b0cd303e3966d1727f30ee9b8a7254 GIT binary patch literal 7635 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 z ins { background-position:-72px 0; } +.jstree-requirement-spec .jstree-closed > ins { background-position:-54px 0; } +.jstree-requirement-spec .jstree-leaf > ins { background-position:-36px 0; } + +.jstree-requirement-spec .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; } +.jstree-requirement-spec .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; } +.jstree-requirement-spec a .jstree-icon { background-position:-56px -19px; } +.jstree-requirement-spec a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; } + +.jstree-requirement-spec.jstree-focused { } + +.jstree-requirement-spec .jstree-no-dots li, +.jstree-requirement-spec .jstree-no-dots .jstree-leaf > ins { background:transparent; } +.jstree-requirement-spec .jstree-no-dots .jstree-open > ins { background-position:-18px 0; } +.jstree-requirement-spec .jstree-no-dots .jstree-closed > ins { background-position:0 0; } + +.jstree-requirement-spec .jstree-no-icons a .jstree-icon { display:none; } + +.jstree-requirement-spec .jstree-search { font-style:italic; } + +.jstree-requirement-spec .jstree-no-icons .jstree-checkbox { display:inline-block; } +.jstree-requirement-spec .jstree-no-checkboxes .jstree-checkbox { display:none !important; } +.jstree-requirement-spec .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; } +.jstree-requirement-spec .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; } +.jstree-requirement-spec .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; } +.jstree-requirement-spec .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; } +.jstree-requirement-spec .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; } +.jstree-requirement-spec .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; } + +#vakata-dragged.jstree-requirement-spec ins { background:transparent !important; } +#vakata-dragged.jstree-requirement-spec .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; } +#vakata-dragged.jstree-requirement-spec .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; } +#jstree-marker.jstree-requirement-spec { background:url("d.png") -41px -57px no-repeat !important; text-indent:-100px; } + +.jstree-requirement-spec a.jstree-search { color:aqua; } +.jstree-requirement-spec .jstree-locked a { color:silver; cursor:default; } + +#vakata-contextmenu.jstree-requirement-spec-context, +#vakata-contextmenu.jstree-requirement-spec-context li ul { background:#f0f0f0; border:1px solid #979797; -moz-box-shadow: 1px 1px 2px #999; -webkit-box-shadow: 1px 1px 2px #999; box-shadow: 1px 1px 2px #999; } +#vakata-contextmenu.jstree-requirement-spec-context li { } +#vakata-contextmenu.jstree-requirement-spec-context a { color:black; } +#vakata-contextmenu.jstree-requirement-spec-context a:hover, +#vakata-contextmenu.jstree-requirement-spec-context .vakata-hover > a { padding:0 5px; background:#e8eff7; border:1px solid #aecff7; color:black; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; } +#vakata-contextmenu.jstree-requirement-spec-context li.jstree-contextmenu-disabled a, +#vakata-contextmenu.jstree-requirement-spec-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; } +#vakata-contextmenu.jstree-requirement-spec-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; } +#vakata-contextmenu.jstree-requirement-spec-context li ul { margin-left:-4px; } + +/* IE6 BEGIN */ +.jstree-requirement-spec li, +.jstree-requirement-spec ins, +#vakata-dragged.jstree-requirement-spec .jstree-invalid, +#vakata-dragged.jstree-requirement-spec .jstree-ok, +#jstree-marker.jstree-requirement-spec { _background-image:url("d.gif"); } +.jstree-requirement-spec .jstree-open ins { _background-position:-72px 0; } +.jstree-requirement-spec .jstree-closed ins { _background-position:-54px 0; } +.jstree-requirement-spec .jstree-leaf ins { _background-position:-36px 0; } +.jstree-requirement-spec a ins.jstree-icon { _background-position:-56px -19px; } +#vakata-contextmenu.jstree-requirement-spec-context ins { _display:none; } +#vakata-contextmenu.jstree-requirement-spec-context li { _zoom:1; } +.jstree-requirement-spec .jstree-undetermined a .jstree-checkbox { _background-position:-20px -19px; } +.jstree-requirement-spec .jstree-checked a .jstree-checkbox { _background-position:-38px -19px; } +.jstree-requirement-spec .jstree-unchecked a .jstree-checkbox { _background-position:-2px -19px; } +/* IE6 END */ \ No newline at end of file diff --git a/js/themes/requirement-spec/throbber.gif b/js/themes/requirement-spec/throbber.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/locale/de/all b/locale/de/all index 26fdc38f7..5eb066d2c 100755 --- a/locale/de/all +++ b/locale/de/all @@ -1898,6 +1898,7 @@ $self->{texts} = { 'Searchable' => 'Durchsuchbar', 'Secondary sorting' => 'Untersortierung', 'Section "#1"' => 'Abschnitt "#1"', + 'Sections' => 'Abschnitte', 'Select' => 'auswählen', 'Select a Customer' => 'Endkunde auswählen', 'Select a customer' => 'Einen Kunden auswählen', @@ -2119,6 +2120,8 @@ $self->{texts} = { 'Terms missing in row ' => '+Tage fehlen in Zeile ', 'Test and preview' => 'Test und Vorschau', 'Test database connectivity' => 'Datenbankverbindung testen', + 'Text blocks back' => 'Textblöcke hinten', + 'Text blocks front' => 'Textblöcke vorne', 'Text field' => 'Textfeld', 'Text field variables: \'WIDTH=w HEIGHT=h\' sets the width and height of the text field. They default to 30 and 5 respectively.' => 'Textfelder: \'WIDTH=w HEIGHT=h\' setzen die Breite und die Höhe des Textfeldes. Wenn nicht anders angegeben, so werden sie 30 Zeichen breit und fünf Zeichen hoch dargestellt.', 'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => 'Textzeilen: \'MAXLENGTH=n\' setzt eine Maximallänge von n Zeichen.', diff --git a/templates/webpages/requirement_spec/tree.html b/templates/webpages/requirement_spec/tree.html new file mode 100644 index 000000000..85ac0e35e --- /dev/null +++ b/templates/webpages/requirement_spec/tree.html @@ -0,0 +1,131 @@ +[%- USE HTML %][%- USE L %][%- USE LxERP %][% USE P %][% USE JSON %] + +[%- L.hidden_tag('requirement_spec_id', SELF.requirement_spec.id) -%] + +
+
+
+
+ [% L.button_tag("new_section_form()", LxERP.t8("New section"), id="new-section-button") %] +
+ +
+
+ +
+
+ +
+
+

There's beauty in the breakdown. 0

+

There's beauty in the breakdown. 1

+

There's beauty in the breakdown. 2

+

There's beauty in the breakdown. 3

+

There's beauty in the breakdown. 4

+

There's beauty in the breakdown. 5

+

There's beauty in the breakdown. 6

+

There's beauty in the breakdown. 7

+

There's beauty in the breakdown. 8

+

There's beauty in the breakdown. 9

+

There's beauty in the breakdown. 10

+

There's beauty in the breakdown. 11

+

There's beauty in the breakdown. 12

+

There's beauty in the breakdown. 13

+

There's beauty in the breakdown. 14

+

There's beauty in the breakdown. 15

+

There's beauty in the breakdown. 16

+

There's beauty in the breakdown. 17

+

There's beauty in the breakdown. 18

+

There's beauty in the breakdown. 19

+

There's beauty in the breakdown. 20

+

There's beauty in the breakdown. 21

+

There's beauty in the breakdown. 22

+ + + + + + + + + + + + + +
+
+
+ + diff --git a/templates/webpages/requirement_spec_item/_section_form.html b/templates/webpages/requirement_spec_item/_section_form.html new file mode 100644 index 000000000..12f8e6533 --- /dev/null +++ b/templates/webpages/requirement_spec_item/_section_form.html @@ -0,0 +1,24 @@ +[%- USE HTML %][%- USE L %][%- USE LxERP %] +[%- SET id_base="section-form-" _ HTML.escape(id) %] +[%- IF title %] +
[%- HTML.escape(title) %]
+[%- END -%] + +
+ [% L.hidden_tag("requirment_spec_id", SELF.item.requirement_spec_id, id=(id_base _ "-requirement-spec-id")) %] + +

+ [%- LxERP.t8("Title") %]:
+ [% L.input_tag("title", SELF.item.title, id=(id_base _ "-title")) %] +

+ +

+ [%- LxERP.t8("Description") %]:
+ [% L.textarea_tag("description", SELF.item.description, id=(id_base _ "-title"), rows=8, cols=80) %] +

+ +

+ [% L.button_tag("submit_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Save")) %] + [% L.button_tag("cancel_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Cancel")) %] +

+
-- 2.20.1