Revision 54daa586
Von Moritz Bunkus vor fast 11 Jahren hinzugefügt
SL/Controller/RequirementSpec.pm | ||
---|---|---|
);
|
||
|
||
__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) ]);
|
||
|
||
... | ... | |
$self->render('1;', { type => 'js', inline => 1 });
|
||
}
|
||
|
||
sub action_tree {
|
||
my ($self) = @_;
|
||
my $r = $self->render('requirement_spec/tree', now => DateTime->now);
|
||
}
|
||
|
||
#
|
||
# filters
|
||
#
|
||
... | ... | |
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
|
||
#
|
||
... | ... | |
$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) = @_;
|
||
|
SL/Controller/RequirementSpecItem.pm | ||
---|---|---|
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;
|
SL/Controller/RequirementSpecTextBlock.pm | ||
---|---|---|
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;
|
SL/Presenter.pm | ||
---|---|---|
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;
|
SL/Presenter/RequirementSpec.pm | ||
---|---|---|
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;
|
css/kivitendo/jquery-ui.custom.css | ||
---|---|---|
text-align: left;
|
||
font-size:125%;
|
||
}
|
||
|
||
/* jstree */
|
||
.jstree a {
|
||
border-bottom: none;
|
||
}
|
css/requirement_spec.css | ||
---|---|---|
table.rs_input_field input, table.rs_input_field select {
|
||
width: 300px;
|
||
}
|
||
|
||
#content-column {
|
||
margin-left: 10px;
|
||
}
|
js/requirement_spec.js | ||
---|---|---|
/* 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');
|
||
}
|
js/themes/requirement-spec/style.css | ||
---|---|---|
/*
|
||
* jsTree default theme 1.0
|
||
* Supported features: dots/no-dots, icons/no-icons, focused, loading
|
||
* Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
|
||
*/
|
||
|
||
.jstree-requirement-spec li,
|
||
.jstree-requirement-spec ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
|
||
.jstree-requirement-spec li { background-position:-90px 0; background-repeat:repeat-y; }
|
||
.jstree-requirement-spec li.jstree-last { background:transparent; }
|
||
.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 .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 */
|
locale/de/all | ||
---|---|---|
'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',
|
||
... | ... | |
'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.',
|
templates/webpages/requirement_spec/tree.html | ||
---|---|---|
[%- USE HTML %][%- USE L %][%- USE LxERP %][% USE P %][% USE JSON %]
|
||
|
||
[%- L.hidden_tag('requirement_spec_id', SELF.requirement_spec.id) -%]
|
||
|
||
<div id="page" class="ym-grid ym-equalize">
|
||
<div class="ym-g25 ym-gl" style="border-right: 1px solid black">
|
||
<div style="min-height: 32px; height: 32px;">
|
||
<div style="float: left">
|
||
[% L.button_tag("new_section_form()", LxERP.t8("New section"), id="new-section-button") %]
|
||
</div>
|
||
<div id="spinner" style="float: right; display: none; background:url('js/themes/requirement-spec/throbber.gif') center center no-repeat !important; min-height: 32px; height: 32px; min-width: 32px; width: 32px;"></div>
|
||
<div style="clear: both"></div>
|
||
</div>
|
||
|
||
<div id="tree"></div>
|
||
</div>
|
||
|
||
<div class="ym-gl">
|
||
<div id="content-column">
|
||
<p>There's beauty in the breakdown. 0</p>
|
||
<p>There's beauty in the breakdown. 1</p>
|
||
<p>There's beauty in the breakdown. 2</p>
|
||
<p>There's beauty in the breakdown. 3</p>
|
||
<p>There's beauty in the breakdown. 4</p>
|
||
<p>There's beauty in the breakdown. 5</p>
|
||
<p>There's beauty in the breakdown. 6</p>
|
||
<p>There's beauty in the breakdown. 7</p>
|
||
<p>There's beauty in the breakdown. 8</p>
|
||
<p>There's beauty in the breakdown. 9</p>
|
||
<p>There's beauty in the breakdown. 10</p>
|
||
<p>There's beauty in the breakdown. 11</p>
|
||
<p>There's beauty in the breakdown. 12</p>
|
||
<p>There's beauty in the breakdown. 13</p>
|
||
<p>There's beauty in the breakdown. 14</p>
|
||
<p>There's beauty in the breakdown. 15</p>
|
||
<p>There's beauty in the breakdown. 16</p>
|
||
<p>There's beauty in the breakdown. 17</p>
|
||
<p>There's beauty in the breakdown. 18</p>
|
||
<p>There's beauty in the breakdown. 19</p>
|
||
<p>There's beauty in the breakdown. 20</p>
|
||
<p>There's beauty in the breakdown. 21</p>
|
||
<p>There's beauty in the breakdown. 22</p>
|
||
<!-- <p>There's beauty in the breakdown. 23</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 24</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 25</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 26</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 27</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 28</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 29</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 30</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 31</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 32</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 33</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 34</p> -->
|
||
<!-- <p>There's beauty in the breakdown. 35</p> -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
<!--
|
||
var tree_data = [
|
||
{ "data": [% JSON.json(LxERP.t8("Text blocks front")) %],
|
||
"metadata": { "type": "textblocks-front" },
|
||
"attr": { "id": "tb-front" },
|
||
"children": [
|
||
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(0) %]
|
||
[% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
|
||
[% END %]
|
||
]
|
||
},
|
||
|
||
{ "data": [% JSON.json(LxERP.t8("Sections")) %],
|
||
"metadata": { "type": "sections" },
|
||
"attr": { "id": "sections" },
|
||
"children": [
|
||
|
||
[% FOREACH section = SELF.requirement_spec.sections %]
|
||
[% P.requirement_spec_item_jstree_data(section).json %][% IF !loop.last %],[% END %]
|
||
[% END %]
|
||
]
|
||
},
|
||
|
||
{ "data": [% JSON.json(LxERP.t8("Text blocks back")) %],
|
||
"metadata": { "type": "textblocks-back" },
|
||
"attr": { "id": "tb-back" },
|
||
"children": [
|
||
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(1) %]
|
||
[% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
|
||
[% END %]
|
||
]
|
||
}
|
||
];
|
||
|
||
$(function() {
|
||
$('#tree').jstree({
|
||
"core": {
|
||
"animation": 0,
|
||
"initially_open": [ "tb-front", "tb-back", "sections"
|
||
[%- FOREACH section = SELF.requirement_spec.sections -%]
|
||
, "fb-[% section.id %]"
|
||
[%- FOREACH function_block = section.children -%]
|
||
, "fb-[% function_block.id -%]"
|
||
[%- END -%]
|
||
[%- END -%]
|
||
]
|
||
},
|
||
"json_data": {
|
||
"data": tree_data
|
||
},
|
||
"crrm": {
|
||
"move": {
|
||
"check_move": check_move,
|
||
"open_move": true
|
||
}
|
||
},
|
||
"themes": {
|
||
"theme": "requirement-spec"
|
||
},
|
||
"plugins": [ "themes", "json_data", "ui", "crrm", "dnd" ]
|
||
})
|
||
.bind("move_node.jstree", node_moved);
|
||
});
|
||
|
||
$(document).ajaxSend(function() {
|
||
$('#spinner').show();
|
||
}).ajaxStop(function() {
|
||
$('#spinner').hide();
|
||
});
|
||
-->
|
||
</script>
|
templates/webpages/requirement_spec_item/_section_form.html | ||
---|---|---|
[%- USE HTML %][%- USE L %][%- USE LxERP %]
|
||
[%- SET id_base="section-form-" _ HTML.escape(id) %]
|
||
[%- IF title %]
|
||
<div class="listtop">[%- HTML.escape(title) %]</div>
|
||
[%- END -%]
|
||
|
||
<form id="[% id_base %]">
|
||
[% L.hidden_tag("requirment_spec_id", SELF.item.requirement_spec_id, id=(id_base _ "-requirement-spec-id")) %]
|
||
|
||
<p>
|
||
[%- LxERP.t8("Title") %]:<br>
|
||
[% L.input_tag("title", SELF.item.title, id=(id_base _ "-title")) %]
|
||
</p>
|
||
|
||
<p>
|
||
[%- LxERP.t8("Description") %]:<br>
|
||
[% L.textarea_tag("description", SELF.item.description, id=(id_base _ "-title"), rows=8, cols=80) %]
|
||
</p>
|
||
|
||
<p>
|
||
[% L.button_tag("submit_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Save")) %]
|
||
[% L.button_tag("cancel_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Cancel")) %]
|
||
</p>
|
||
</form>
|
Auch abrufbar als: Unified diff
Pflichtenhefte: Erste Version Baumansicht Textblöcke/Abschnitte/Funktionsblöcke