Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 54daa586

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 54daa586799871ce5ede8f628a03ea55a9660cf5
  • Vorgänger 34948207
  • Nachfolger c1569bc1

Pflichtenhefte: Erste Version Baumansicht Textblöcke/Abschnitte/Funktionsblöcke

Unterschiede anzeigen:

SL/Controller/RequirementSpec.pm
23 23
);
24 24

  
25 25
__PACKAGE__->run_before('setup');
26
__PACKAGE__->run_before('load_requirement_spec',      only => [ qw(    edit        update destroy) ]);
26
__PACKAGE__->run_before('load_requirement_spec',      only => [ qw(    edit        update destroy tree) ]);
27 27
__PACKAGE__->run_before('load_select_options',        only => [ qw(new edit create update list) ]);
28 28
__PACKAGE__->run_before('load_search_select_options', only => [ qw(                       list) ]);
29 29

  
......
109 109
  $self->render('1;', { type => 'js', inline => 1 });
110 110
}
111 111

  
112
sub action_tree {
113
  my ($self) = @_;
114
  my $r = $self->render('requirement_spec/tree', now => DateTime->now);
115
}
116

  
112 117
#
113 118
# filters
114 119
#
......
117 122
  my ($self) = @_;
118 123

  
119 124
  $::auth->assert('config');
120
  $::request->{layout}->use_stylesheet("requirement_spec.css");
125
  $::request->{layout}->use_stylesheet("${_}.css") for qw(requirement_spec yaml/core/base.min);
126
  $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree requirement_spec);
121 127
  $self->is_template($::form->{is_template} ? 1 : 0);
122 128

  
123 129
  return 1;
124 130
}
125 131

  
132
sub load_requirement_spec {
133
  my ($self) = @_;
134
  $self->{requirement_spec} = SL::DB::RequirementSpec->new(id => $::form->{id})->load || die "No such requirement spec";
135
}
136

  
137
sub load_select_options {
138
  my ($self) = @_;
139

  
140
  my @filter = ('!obsolete' => 1);
141
  if ($self->requirement_spec && $self->requirement_spec->customer_id) {
142
    @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] );
143
  }
144

  
145
  $self->customers(SL::DB::Manager::Customer->get_all_sorted(where => \@filter));
146
  $self->statuses( SL::DB::Manager::RequirementSpecStatus->get_all_sorted);
147
  $self->types(    SL::DB::Manager::RequirementSpecType->get_all_sorted);
148
}
149

  
150
sub load_search_select_options {
151
  my ($self) = @_;
152

  
153
  $self->projects(SL::DB::Manager::Project->get_all_sorted);
154
}
155

  
126 156
#
127 157
# helpers
128 158
#
......
149 179
  $self->redirect_to(action => 'list');
150 180
}
151 181

  
152
sub load_requirement_spec {
153
  my ($self) = @_;
154
  $self->{requirement_spec} = SL::DB::RequirementSpec->new(id => $::form->{id})->load;
155
}
156

  
157
sub load_select_options {
158
  my ($self) = @_;
159

  
160
  my @filter = ('!obsolete' => 1);
161
  if ($self->requirement_spec && $self->requirement_spec->customer_id) {
162
    @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] );
163
  }
164

  
165
  $self->customers(SL::DB::Manager::Customer->get_all_sorted(where => \@filter));
166
  $self->statuses( SL::DB::Manager::RequirementSpecStatus->get_all_sorted);
167
  $self->types(    SL::DB::Manager::RequirementSpecType->get_all_sorted);
168
}
169

  
170
sub load_search_select_options {
171
  my ($self) = @_;
172

  
173
  $self->projects(SL::DB::Manager::Project->get_all_sorted);
174
}
175

  
176 182
sub setup_db_args_from_filter {
177 183
  my ($self) = @_;
178 184

  
SL/Controller/RequirementSpecItem.pm
1
package SL::Controller::RequirementSpecItem;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use Time::HiRes ();
8

  
9
use SL::DB::RequirementSpec;
10
use SL::DB::RequirementSpecItem;
11
use SL::Helper::Flash;
12
use SL::JSON;
13
use SL::Locale::String;
14

  
15
use Rose::Object::MakeMethods::Generic
16
(
17
 scalar => [ qw(requirement_spec item) ],
18
);
19

  
20
# __PACKAGE__->run_before('load_requirement_spec');
21
__PACKAGE__->run_before('load_requirement_spec_item', only => [qw(dragged_and_dropped)]);
22

  
23
#
24
# actions
25
#
26

  
27
sub action_new {
28
  my ($self) = @_;
29

  
30
  eval {
31
    my $type         = ($::form->{item_type} || '') =~ m/^ (?: section | (?: sub-)? function-block ) $/x ? $::form->{item_type} : die "Invalid item_type";
32
    $self->{item}    = SL::DB::RequirementSpecItem->new(requirement_spec_id => $::form->{requirement_spec_id});
33
    my $section_form = $self->presenter->render("requirement_spec_item/_${type}_form", id => create_random_id(), title => t8('Create a new section'));
34

  
35
    $self->render(\to_json({ status => 'ok', html => $section_form }), { type => 'json' });
36
    1;
37
  } or do {
38
    $self->render(\to_json({ status => 'failed', error => "Exception:\n" . format_exception() }), { type => 'json' });
39
  }
40
}
41

  
42
sub action_create {
43
  my ($self) = @_;
44

  
45
  my $type = ($::form->{item_type} || '') =~ m/^ (?: section | (?: sub-)? function-block ) $/x ? $::form->{item_type} : die "Invalid item_type";
46

  
47
  $self->render(\to_json({ status => 'failed', error => 'not good, not good' }), { type => 'json' });
48
}
49

  
50
sub action_dragged_and_dropped {
51
  my ($self)       = @_;
52

  
53
  $::lxdebug->dump(0, "form", $::form);
54

  
55
  my $dropped_item = SL::DB::RequirementSpecItem->new(id => $::form->{dropped_id})->load || die "No such dropped item";
56
  my $position     = $::form->{position} =~ m/^ (?: before | after | last ) $/x ? $::form->{position} : die "Unknown 'position' parameter";
57

  
58
  $self->item->db->do_transaction(sub {
59
    $self->item->remove_from_list;
60
    $self->item->parent_id($position =~ m/before|after/ ? $dropped_item->parent_id : $dropped_item->id);
61
    $self->item->add_to_list(position => $position, reference => $dropped_item->id);
62
  });
63

  
64
  $self->render(\'', { type => 'json' });
65
}
66

  
67
#
68
# filters
69
#
70

  
71
sub load_requirement_spec {
72
  my ($self) = @_;
73
  $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load || die "No such requirement spec");
74
}
75

  
76
sub load_requirement_spec_item {
77
  my ($self) = @_;
78
  $self->item(SL::DB::RequirementSpecItem->new(id => $::form->{id})->load || die "No such requirement spec item");
79
}
80

  
81
#
82
# helpers
83
#
84

  
85
sub create_random_id {
86
  return join '-', Time::HiRes::gettimeofday();
87
}
88

  
89
sub format_exception {
90
  return join "\n", (split m/\n/, $@)[0..4];
91
}
92

  
93
1;
SL/Controller/RequirementSpecTextBlock.pm
1
package SL::Controller::RequirementSpecTextBlock;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use SL::DB::RequirementSpec;
8
use SL::DB::RequirementSpecTextBlock;
9
use SL::Helper::Flash;
10
use SL::Locale::String;
11

  
12
use Rose::Object::MakeMethods::Generic
13
(
14
 scalar => [ qw(requirement_spec text_block) ],
15
);
16

  
17
# __PACKAGE__->run_before('load_requirement_spec');
18
__PACKAGE__->run_before('load_requirement_spec_text_block', only => [qw(dragged_and_dropped)]);
19

  
20
#
21
# actions
22
#
23

  
24
sub action_dragged_and_dropped {
25
  my ($self)       = @_;
26

  
27
  $::lxdebug->dump(0, "form", $::form);
28

  
29
  my $position           = $::form->{position} =~ m/^ (?: before | after | last ) $/x ? $::form->{position}                                                      : die "Unknown 'position' parameter";
30
  my $dropped_text_block = $position           =~ m/^ (?: before | after ) $/x        ? SL::DB::RequirementSpecTextBlock->new(id => $::form->{dropped_id})->load : undef;
31

  
32
  my $dropped_type       = $position ne 'last' ? undef : $::form->{dropped_type} =~ m/^ textblocks- (?:front|back) $/x ? $::form->{dropped_type} : die "Unknown 'dropped_type' parameter";
33

  
34
  $self->text_block->db->do_transaction(sub {
35
    1;
36
    $self->text_block->remove_from_list;
37
    $self->text_block->output_position($position =~ m/before|after/ ? $dropped_text_block->output_position : $::form->{dropped_type} eq 'textblocks-front' ? 0 : 1);
38
    $self->text_block->add_to_list(position => $position, reference => $dropped_text_block ? $dropped_text_block->id : undef);
39
  });
40

  
41
  $self->render(\'', { type => 'json' });
42
}
43

  
44
#
45
# filters
46
#
47

  
48
sub load_requirement_spec {
49
  my ($self) = @_;
50
  $self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load || die "No such requirement spec");
51
}
52

  
53
sub load_requirement_spec_text_block {
54
  my ($self) = @_;
55
  $self->text_block(SL::DB::RequirementSpecTextBlock->new(id => $::form->{id})->load || die "No such requirement spec text block");
56
}
57

  
58
#
59
# helpers
60
#
61

  
62
1;
SL/Presenter.pm
15 15
use SL::Presenter::Part;
16 16
use SL::Presenter::Project;
17 17
use SL::Presenter::Record;
18
use SL::Presenter::RequirementSpec;
18 19
use SL::Presenter::SepaExport;
19 20
use SL::Presenter::Text;
20 21
use SL::Presenter::Tag;
SL/Presenter/RequirementSpec.pm
1
package SL::Presenter::RequirementSpec;
2

  
3
use strict;
4

  
5
use parent qw(Exporter);
6

  
7
use Exporter qw(import);
8
our @EXPORT = qw(requirement_spec_text_block_jstree_data
9
                 requirement_spec_item_jstree_data);
10

  
11
use Carp;
12

  
13
use SL::JSON;
14

  
15
sub requirement_spec_text_block_jstree_data {
16
  my ($self, $text_block, %params) = @_;
17

  
18
  return {
19
    data     => $text_block->title || '',
20
    metadata => { id =>         $text_block->id, type => 'textblock' },
21
    attr     => { id => "tb-" . $text_block->id, href => $params{href} || '#' },
22
  };
23
}
24

  
25
sub requirement_spec_item_jstree_data {
26
  my ($self, $item, %params) = @_;
27

  
28
  my @children = map { $self->requirement_spec_item_jstree_data($_, %params) } @{ $item->sorted_children };
29
  my $type     = !$item->parent_id ? 'section' : 'functionblock';
30

  
31
  return {
32
    data     => join(' ', map { $_ || '' } ($item->fb_number, $item->title)),
33
    metadata => { id =>         $item->id, type => $type },
34
    attr     => { id => "fb-" . $item->id, href => $params{href} || '#' },
35
    children => \@children,
36
  };
37
}
38

  
39
1;
css/kivitendo/jquery-ui.custom.css
118 118
  text-align: left;
119 119
  font-size:125%;
120 120
}
121

  
122
/* jstree */
123
.jstree a {
124
  border-bottom: none;
125
}
css/requirement_spec.css
2 2
table.rs_input_field input, table.rs_input_field select {
3 3
  width: 300px;
4 4
}
5

  
6
#content-column {
7
  margin-left: 10px;
8
}
js/requirement_spec.js
1
/* Functions used for the requirement specs tree view */
2

  
3
function check_move(data) {
4
  var dragged_type = data.o.data('type');
5
  var dropped_type = data.r.data('type');
6

  
7
  // console.debug("dragged " + dragged_type + " dropped " + dropped_type + " dir " + data.p);
8

  
9
  if ((dragged_type == "sections") || (dragged_type == "textblocks-front") || (dragged_type == "textblocks-back"))
10
    return false;
11

  
12
  if (dragged_type == "textblock") {
13
    if ((dropped_type == "textblocks-front") || (dropped_type == "textblocks-back"))
14
      return (data.p == "inside") || (data.p == "last");
15
    if (dropped_type == "textblock")
16
      return (data.p == "before") || (data.p == "after");
17

  
18
    return false;
19
  }
20

  
21
  if (dragged_type == "section") {
22
    if (dropped_type == "sections")
23
      return (data.p == "inside") || (data.p == "last");
24
    if (dropped_type == "section")
25
      return (data.p == "before") || (data.p == "after");
26

  
27
    return false;
28
  }
29

  
30
  // dragged_type == (sub) function blocks
31
  if ((dropped_type == "textblock") || (dropped_type == "textblocks-front") || (dropped_type == "textblocks-back"))
32
    return false;
33

  
34
  var dropped_depth = dropped_type == "sections" ? 0 : dropped_type == "section" ? 1 : data.r.parent().parent().data('type') != "functionblock" ? 2 : 3;
35
  if ((data.p == "inside") || (data.p == "last"))
36
    dropped_depth++;
37

  
38
  var dragged_depth = 1 + data.o.children('ul').size();
39

  
40
  // console.debug("dropped_depth " + dropped_depth + " dragged_depth " + dragged_depth);
41

  
42
  return (2 <= dropped_depth) && ((dragged_depth + dropped_depth) <= 4);
43
}
44

  
45
function node_moved(event) {
46
  console.debug("node moved");
47
  var move_obj   = $.jstree._reference('#tree')._get_move();
48
  var dragged    = move_obj.o;
49
  var dropped    = move_obj.r;
50
  var controller = dragged.data("type") == "textblock" ? "RequirementSpecTextBlock" : "RequirementSpecItem";
51
  var data       = {
52
    action:              controller + "/dragged_and_dropped",
53
    requirement_spec_id: $('#requirement_spec_id').val(),
54
    id:                  dragged.data("id"),
55
    dropped_id:          dropped.data("id"),
56
    dropped_type:        dropped.data("type"),
57
    position:            move_obj.p
58
  };
59
  // console.debug("controller: " + controller);
60
  // console.debug(data);
61

  
62
  $.ajax({ url: "controller.pl", data: data });
63
}
64

  
65
function section_form_requested(data) {
66
  $('#new-section-button').removeAttr('disabled');
67
  if (data.status == "ok")
68
    $('#content-column').html(data.html);
69
  else
70
    alert('oh yeah response: ' + data.status + "\n" + data.error);
71
}
72

  
73
function section_form_submitted(data) {
74
  alert('oh yeah response: ' + data.status);
75
}
76

  
77
function server_side_error(things_to_enable) {
78
  alert('Server-side error.');
79
  if (things_to_enable)
80
    $(things_to_enable).removeAttr('disabled');
81
}
82

  
83
function new_section_form() {
84
  $('#new-section-button').attr('disabled', 'disabled');
85
  $.ajax({
86
    type: 'POST',
87
    url: 'controller.pl',
88
    data: 'action=RequirementSpecItem/new.json&requirement_spec_id=' + $('#requirement_spec_id').val() + '&item_type=section',
89
    success: section_form_requested,
90
    error: function() { server_side_error('#new-section-button'); }
91
  });
92
}
93

  
94
function submit_section_form(id) {
95
  $.ajax({
96
    type: 'POST',
97
    url: 'controller.pl',
98
    data: 'action=RequirementSpecItem/create.json&' + $('section-form-' + id).serialize(),
99
    success: section_form_submitted
100
  });
101
}
102

  
103
function cancel_section_form(id) {
104
  $('#content-column').html('intentionally empty');
105
}
js/themes/requirement-spec/style.css
1
/*
2
 * jsTree default theme 1.0
3
 * Supported features: dots/no-dots, icons/no-icons, focused, loading
4
 * Supported plugins: ui (hovered, clicked), checkbox, contextmenu, search
5
 */
6

  
7
.jstree-requirement-spec li,
8
.jstree-requirement-spec ins { background-image:url("d.png"); background-repeat:no-repeat; background-color:transparent; }
9
.jstree-requirement-spec li { background-position:-90px 0; background-repeat:repeat-y; }
10
.jstree-requirement-spec li.jstree-last { background:transparent; }
11
.jstree-requirement-spec .jstree-open > ins { background-position:-72px 0; }
12
.jstree-requirement-spec .jstree-closed > ins { background-position:-54px 0; }
13
.jstree-requirement-spec .jstree-leaf > ins { background-position:-36px 0; }
14

  
15
.jstree-requirement-spec .jstree-hovered { background:#e7f4f9; border:1px solid #d8f0fa; padding:0 2px 0 1px; }
16
.jstree-requirement-spec .jstree-clicked { background:#beebff; border:1px solid #99defd; padding:0 2px 0 1px; }
17
.jstree-requirement-spec a .jstree-icon { background-position:-56px -19px; }
18
.jstree-requirement-spec a.jstree-loading .jstree-icon { background:url("throbber.gif") center center no-repeat !important; }
19

  
20
.jstree-requirement-spec.jstree-focused { }
21

  
22
.jstree-requirement-spec .jstree-no-dots li,
23
.jstree-requirement-spec .jstree-no-dots .jstree-leaf > ins { background:transparent; }
24
.jstree-requirement-spec .jstree-no-dots .jstree-open > ins { background-position:-18px 0; }
25
.jstree-requirement-spec .jstree-no-dots .jstree-closed > ins { background-position:0 0; }
26

  
27
.jstree-requirement-spec .jstree-no-icons a .jstree-icon { display:none; }
28

  
29
.jstree-requirement-spec .jstree-search { font-style:italic; }
30

  
31
.jstree-requirement-spec .jstree-no-icons .jstree-checkbox { display:inline-block; }
32
.jstree-requirement-spec .jstree-no-checkboxes .jstree-checkbox { display:none !important; }
33
.jstree-requirement-spec .jstree-checked > a > .jstree-checkbox { background-position:-38px -19px; }
34
.jstree-requirement-spec .jstree-unchecked > a > .jstree-checkbox { background-position:-2px -19px; }
35
.jstree-requirement-spec .jstree-undetermined > a > .jstree-checkbox { background-position:-20px -19px; }
36
.jstree-requirement-spec .jstree-checked > a > .jstree-checkbox:hover { background-position:-38px -37px; }
37
.jstree-requirement-spec .jstree-unchecked > a > .jstree-checkbox:hover { background-position:-2px -37px; }
38
.jstree-requirement-spec .jstree-undetermined > a > .jstree-checkbox:hover { background-position:-20px -37px; }
39

  
40
#vakata-dragged.jstree-requirement-spec ins { background:transparent !important; }
41
#vakata-dragged.jstree-requirement-spec .jstree-ok { background:url("d.png") -2px -53px no-repeat !important; }
42
#vakata-dragged.jstree-requirement-spec .jstree-invalid { background:url("d.png") -18px -53px no-repeat !important; }
43
#jstree-marker.jstree-requirement-spec { background:url("d.png") -41px -57px no-repeat !important; text-indent:-100px; }
44

  
45
.jstree-requirement-spec a.jstree-search { color:aqua; }
46
.jstree-requirement-spec .jstree-locked a { color:silver; cursor:default; }
47

  
48
#vakata-contextmenu.jstree-requirement-spec-context,
49
#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; }
50
#vakata-contextmenu.jstree-requirement-spec-context li { }
51
#vakata-contextmenu.jstree-requirement-spec-context a { color:black; }
52
#vakata-contextmenu.jstree-requirement-spec-context a:hover,
53
#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; }
54
#vakata-contextmenu.jstree-requirement-spec-context li.jstree-contextmenu-disabled a,
55
#vakata-contextmenu.jstree-requirement-spec-context li.jstree-contextmenu-disabled a:hover { color:silver; background:transparent; border:0; padding:1px 4px; }
56
#vakata-contextmenu.jstree-requirement-spec-context li.vakata-separator { background:white; border-top:1px solid #e0e0e0; margin:0; }
57
#vakata-contextmenu.jstree-requirement-spec-context li ul { margin-left:-4px; }
58

  
59
/* IE6 BEGIN */
60
.jstree-requirement-spec li,
61
.jstree-requirement-spec ins,
62
#vakata-dragged.jstree-requirement-spec .jstree-invalid,
63
#vakata-dragged.jstree-requirement-spec .jstree-ok,
64
#jstree-marker.jstree-requirement-spec { _background-image:url("d.gif"); }
65
.jstree-requirement-spec .jstree-open ins { _background-position:-72px 0; }
66
.jstree-requirement-spec .jstree-closed ins { _background-position:-54px 0; }
67
.jstree-requirement-spec .jstree-leaf ins { _background-position:-36px 0; }
68
.jstree-requirement-spec a ins.jstree-icon { _background-position:-56px -19px; }
69
#vakata-contextmenu.jstree-requirement-spec-context ins { _display:none; }
70
#vakata-contextmenu.jstree-requirement-spec-context li { _zoom:1; }
71
.jstree-requirement-spec .jstree-undetermined a .jstree-checkbox { _background-position:-20px -19px; }
72
.jstree-requirement-spec .jstree-checked a .jstree-checkbox { _background-position:-38px -19px; }
73
.jstree-requirement-spec .jstree-unchecked a .jstree-checkbox { _background-position:-2px -19px; }
74
/* IE6 END */
locale/de/all
1898 1898
  'Searchable'                  => 'Durchsuchbar',
1899 1899
  'Secondary sorting'           => 'Untersortierung',
1900 1900
  'Section "#1"'                => 'Abschnitt "#1"',
1901
  'Sections'                    => 'Abschnitte',
1901 1902
  'Select'                      => 'auswählen',
1902 1903
  'Select a Customer'           => 'Endkunde auswählen',
1903 1904
  'Select a customer'           => 'Einen Kunden ausw&auml;hlen',
......
2119 2120
  'Terms missing in row '       => '+Tage fehlen in Zeile ',
2120 2121
  'Test and preview'            => 'Test und Vorschau',
2121 2122
  'Test database connectivity'  => 'Datenbankverbindung testen',
2123
  'Text blocks back'            => 'Textblöcke hinten',
2124
  'Text blocks front'           => 'Textblöcke vorne',
2122 2125
  'Text field'                  => 'Textfeld',
2123 2126
  '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&ouml;he des Textfeldes. Wenn nicht anders angegeben, so werden sie 30 Zeichen breit und f&uuml;nf Zeichen hoch dargestellt.',
2124 2127
  'Text variables: \'MAXLENGTH=n\' sets the maximum entry length to \'n\'.' => 'Textzeilen: \'MAXLENGTH=n\' setzt eine Maximall&auml;nge von n Zeichen.',
templates/webpages/requirement_spec/tree.html
1
[%- USE HTML %][%- USE L %][%- USE LxERP %][% USE P %][% USE JSON %]
2

  
3
[%- L.hidden_tag('requirement_spec_id', SELF.requirement_spec.id) -%]
4

  
5
<div id="page" class="ym-grid ym-equalize">
6
 <div class="ym-g25 ym-gl" style="border-right: 1px solid black">
7
  <div style="min-height: 32px; height: 32px;">
8
   <div style="float: left">
9
    [% L.button_tag("new_section_form()", LxERP.t8("New section"), id="new-section-button") %]
10
   </div>
11
   <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>
12
   <div style="clear: both"></div>
13
  </div>
14

  
15
  <div id="tree"></div>
16
 </div>
17

  
18
 <div class="ym-gl">
19
  <div id="content-column">
20
   <p>There's beauty in the breakdown. 0</p>
21
   <p>There's beauty in the breakdown. 1</p>
22
   <p>There's beauty in the breakdown. 2</p>
23
   <p>There's beauty in the breakdown. 3</p>
24
   <p>There's beauty in the breakdown. 4</p>
25
   <p>There's beauty in the breakdown. 5</p>
26
   <p>There's beauty in the breakdown. 6</p>
27
   <p>There's beauty in the breakdown. 7</p>
28
   <p>There's beauty in the breakdown. 8</p>
29
   <p>There's beauty in the breakdown. 9</p>
30
   <p>There's beauty in the breakdown. 10</p>
31
   <p>There's beauty in the breakdown. 11</p>
32
   <p>There's beauty in the breakdown. 12</p>
33
   <p>There's beauty in the breakdown. 13</p>
34
   <p>There's beauty in the breakdown. 14</p>
35
   <p>There's beauty in the breakdown. 15</p>
36
   <p>There's beauty in the breakdown. 16</p>
37
   <p>There's beauty in the breakdown. 17</p>
38
   <p>There's beauty in the breakdown. 18</p>
39
   <p>There's beauty in the breakdown. 19</p>
40
   <p>There's beauty in the breakdown. 20</p>
41
   <p>There's beauty in the breakdown. 21</p>
42
   <p>There's beauty in the breakdown. 22</p>
43
   <!-- <p>There's beauty in the breakdown. 23</p> -->
44
   <!-- <p>There's beauty in the breakdown. 24</p> -->
45
   <!-- <p>There's beauty in the breakdown. 25</p> -->
46
   <!-- <p>There's beauty in the breakdown. 26</p> -->
47
   <!-- <p>There's beauty in the breakdown. 27</p> -->
48
   <!-- <p>There's beauty in the breakdown. 28</p> -->
49
   <!-- <p>There's beauty in the breakdown. 29</p> -->
50
   <!-- <p>There's beauty in the breakdown. 30</p> -->
51
   <!-- <p>There's beauty in the breakdown. 31</p> -->
52
   <!-- <p>There's beauty in the breakdown. 32</p> -->
53
   <!-- <p>There's beauty in the breakdown. 33</p> -->
54
   <!-- <p>There's beauty in the breakdown. 34</p> -->
55
   <!-- <p>There's beauty in the breakdown. 35</p> -->
56
  </div>
57
 </div>
58
</div>
59

  
60
<script type="text/javascript">
61
 <!--
62
     var tree_data = [
63
       { "data": [% JSON.json(LxERP.t8("Text blocks front")) %],
64
         "metadata": { "type": "textblocks-front" },
65
         "attr": { "id": "tb-front" },
66
         "children": [
67
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(0) %]
68
 [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
69
[% END %]
70
         ]
71
       },
72

  
73
       { "data": [% JSON.json(LxERP.t8("Sections")) %],
74
         "metadata": { "type": "sections" },
75
         "attr": { "id": "sections" },
76
         "children": [
77

  
78
[% FOREACH section = SELF.requirement_spec.sections %]
79
 [% P.requirement_spec_item_jstree_data(section).json %][% IF !loop.last %],[% END %]
80
[% END %]
81
         ]
82
       },
83

  
84
       { "data": [% JSON.json(LxERP.t8("Text blocks back")) %],
85
         "metadata": { "type": "textblocks-back" },
86
         "attr": { "id": "tb-back" },
87
         "children": [
88
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(1) %]
89
 [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
90
[% END %]
91
         ]
92
       }
93
     ];
94

  
95
     $(function() {
96
       $('#tree').jstree({
97
         "core": {
98
           "animation": 0,
99
           "initially_open": [ "tb-front", "tb-back", "sections"
100
[%- FOREACH section = SELF.requirement_spec.sections -%]
101
 , "fb-[% section.id %]"
102
 [%- FOREACH function_block = section.children -%]
103
  , "fb-[% function_block.id -%]"
104
 [%- END -%]
105
[%- END -%]
106
 ]
107
         },
108
         "json_data": {
109
           "data": tree_data
110
         },
111
         "crrm": {
112
           "move": {
113
             "check_move": check_move,
114
             "open_move": true
115
           }
116
         },
117
         "themes": {
118
           "theme": "requirement-spec"
119
         },
120
         "plugins": [ "themes", "json_data", "ui", "crrm", "dnd" ]
121
       })
122
       .bind("move_node.jstree", node_moved);
123
     });
124

  
125
     $(document).ajaxSend(function() {
126
       $('#spinner').show();
127
     }).ajaxStop(function() {
128
       $('#spinner').hide();
129
     });
130
  -->
131
</script>
templates/webpages/requirement_spec_item/_section_form.html
1
[%- USE HTML %][%- USE L %][%- USE LxERP %]
2
[%- SET id_base="section-form-" _ HTML.escape(id) %]
3
[%- IF title %]
4
 <div class="listtop">[%- HTML.escape(title) %]</div>
5
[%- END -%]
6

  
7
<form id="[% id_base %]">
8
 [% L.hidden_tag("requirment_spec_id", SELF.item.requirement_spec_id, id=(id_base _ "-requirement-spec-id")) %]
9

  
10
 <p>
11
  [%- LxERP.t8("Title") %]:<br>
12
  [% L.input_tag("title", SELF.item.title, id=(id_base _ "-title")) %]
13
 </p>
14

  
15
 <p>
16
  [%- LxERP.t8("Description") %]:<br>
17
  [% L.textarea_tag("description", SELF.item.description, id=(id_base _ "-title"), rows=8, cols=80) %]
18
 </p>
19

  
20
 <p>
21
  [% L.button_tag("submit_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Save")) %]
22
  [% L.button_tag("cancel_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Cancel")) %]
23
 </p>
24
</form>

Auch abrufbar als: Unified diff