Revision ca7c2f91
Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt
SL/Controller/RequirementSpec.pm | ||
---|---|---|
132 | 132 |
|
133 | 133 |
$::auth->assert('config'); |
134 | 134 |
$::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec); |
135 |
$::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu requirement_spec); |
|
135 |
$::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu client_js requirement_spec);
|
|
136 | 136 |
$self->is_template($::form->{is_template} ? 1 : 0); |
137 | 137 |
|
138 | 138 |
return 1; |
SL/Controller/RequirementSpecTextBlock.pm | ||
---|---|---|
4 | 4 |
|
5 | 5 |
use parent qw(SL::Controller::Base); |
6 | 6 |
|
7 |
use SL::ClientJS; |
|
7 | 8 |
use SL::DB::RequirementSpec; |
8 | 9 |
use SL::DB::RequirementSpecTextBlock; |
9 | 10 |
use SL::Helper::Flash; |
11 |
use SL::JSON; |
|
10 | 12 |
use SL::Locale::String; |
11 | 13 |
|
12 | 14 |
use Rose::Object::MakeMethods::Generic |
... | ... | |
14 | 16 |
scalar => [ qw(requirement_spec text_block) ], |
15 | 17 |
); |
16 | 18 |
|
17 |
# __PACKAGE__->run_before('load_requirement_spec'); |
|
18 | 19 |
__PACKAGE__->run_before('load_requirement_spec_text_block', only => [qw(dragged_and_dropped)]); |
19 | 20 |
|
20 | 21 |
# |
21 | 22 |
# actions |
22 | 23 |
# |
23 | 24 |
|
25 |
sub action_ajax_list { |
|
26 |
my ($self) = @_; |
|
27 |
|
|
28 |
my $result = { }; |
|
29 |
my $current_where = $self->output_position_from_id($::form->{current_content_id}, $::form->{current_content_type}); |
|
30 |
my $new_where; |
|
31 |
|
|
32 |
if ($::form->{clicked_type} =~ m/^textblocks-(front|back)/) { |
|
33 |
$new_where = $1 eq 'front' ? 0 : 1; |
|
34 |
|
|
35 |
} else { |
|
36 |
$new_where = $self->output_position_from_id($::form->{clicked_id}); |
|
37 |
} |
|
38 |
|
|
39 |
# $::lxdebug->message(0, "cur $current_where new $new_where"); |
|
40 |
|
|
41 |
my $js = SL::ClientJS->new; |
|
42 |
|
|
43 |
if (!defined($current_where) || ($new_where != $current_where)) { |
|
44 |
my $text_blocks = SL::DB::Manager::RequirementSpecTextBlock->get_all_sorted(where => [ output_position => $new_where ]); |
|
45 |
my $html = $self->render('requirement_spec_text_block/ajax_list', { output => 0 }, TEXT_BLOCKS => $text_blocks, output_position => $new_where, nownow => DateTime->now_local); |
|
46 |
|
|
47 |
$js->html('#column-content', $html) |
|
48 |
} |
|
49 |
|
|
50 |
$self->render($js); |
|
51 |
} |
|
52 |
|
|
24 | 53 |
sub action_dragged_and_dropped { |
25 | 54 |
my ($self) = @_; |
26 | 55 |
|
27 |
$::lxdebug->dump(0, "form", $::form); |
|
28 |
|
|
29 | 56 |
my $position = $::form->{position} =~ m/^ (?: before | after | last ) $/x ? $::form->{position} : die "Unknown 'position' parameter"; |
30 | 57 |
my $dropped_text_block = $position =~ m/^ (?: before | after ) $/x ? SL::DB::RequirementSpecTextBlock->new(id => $::form->{dropped_id})->load : undef; |
31 | 58 |
|
32 | 59 |
my $dropped_type = $position ne 'last' ? undef : $::form->{dropped_type} =~ m/^ textblocks- (?:front|back) $/x ? $::form->{dropped_type} : die "Unknown 'dropped_type' parameter"; |
60 |
my $old_where = $self->text_block->output_position; |
|
33 | 61 |
|
34 | 62 |
$self->text_block->db->do_transaction(sub { |
35 | 63 |
1; |
... | ... | |
38 | 66 |
$self->text_block->add_to_list(position => $position, reference => $dropped_text_block ? $dropped_text_block->id : undef); |
39 | 67 |
}); |
40 | 68 |
|
41 |
$self->render(\'', { type => 'json' }); |
|
69 |
return $self->render(\'', { type => 'json' }) if $::form->{current_content_type} !~ m/^textblock/; |
|
70 |
|
|
71 |
my $current_where = $self->output_position_from_id($::form->{current_content_id}, $::form->{current_content_type}); |
|
72 |
my $new_where = $self->text_block->output_position; |
|
73 |
my $id = $self->text_block->id; |
|
74 |
my $js = SL::ClientJS->new; |
|
75 |
|
|
76 |
# $::lxdebug->message(0, "old $old_where current $current_where new $new_where current_CID " . $::form->{current_content_id} . ' selfid ' . $self->text_block->id); |
|
77 |
if (($old_where != $new_where) && ($::form->{current_content_id} == $self->text_block->id)) { |
|
78 |
# The currently selected text block is dragged to the opposite |
|
79 |
# text block location. Re-render the whole content column. |
|
80 |
my $text_blocks = SL::DB::Manager::RequirementSpecTextBlock->get_all_sorted(where => [ output_position => $new_where ]); |
|
81 |
my $html = $self->render('requirement_spec_text_block/ajax_list', { output => 0 }, TEXT_BLOCKS => $text_blocks, output_position => $new_where); |
|
82 |
|
|
83 |
$js->val('#current_content_type', 'textblocks-' . ($new_where == 0 ? 'front' : 'back')) |
|
84 |
->html('#column-content', $html); |
|
85 |
|
|
86 |
} else { |
|
87 |
if ($old_where == $current_where) { |
|
88 |
$js->remove('#text-block-' . $self->text_block->id); |
|
89 |
|
|
90 |
if (0 == scalar(@{ SL::DB::Manager::RequirementSpecTextBlock->get_all(where => [ requirement_spec_id => $self->text_block->requirement_spec_id, output_position => $current_where ]) })) { |
|
91 |
$js->show('#text-block-list-empty'); |
|
92 |
} |
|
93 |
} |
|
94 |
|
|
95 |
if ($new_where == $current_where) { |
|
96 |
$js->hide('#text-block-list-empty'); |
|
97 |
|
|
98 |
my $html = "" . $self->render('requirement_spec_text_block/_text_block', { output => 0 }, text_block => $self->text_block); |
|
99 |
$html =~ s/^\s+//; |
|
100 |
my $prior_text_block = $self->text_block->get_previous_in_list; |
|
101 |
|
|
102 |
if ($prior_text_block) { |
|
103 |
$js->insertAfter($html, '#text-block-' . $prior_text_block->id); |
|
104 |
} else { |
|
105 |
$js->appendTo($html, '#text-block-list'); |
|
106 |
} |
|
107 |
} |
|
108 |
} |
|
109 |
|
|
110 |
$::lxdebug->message(0, "old $old_where current $current_where new $new_where"); |
|
111 |
|
|
112 |
$::lxdebug->dump(0, "actions", $js); |
|
113 |
|
|
114 |
$self->render($js); |
|
42 | 115 |
} |
43 | 116 |
|
44 | 117 |
# |
... | ... | |
59 | 132 |
# helpers |
60 | 133 |
# |
61 | 134 |
|
135 |
sub output_position_from_id { |
|
136 |
my ($self, $id, $type, %params) = @_; |
|
137 |
|
|
138 |
if (!$id) { |
|
139 |
return $params{default} unless $type =~ m/-(front|back)/; |
|
140 |
return $1 eq 'front' ? 0 : 1; |
|
141 |
} |
|
142 |
|
|
143 |
my $text_block = SL::DB::Manager::RequirementSpecTextBlock->find_by(id => $id); |
|
144 |
|
|
145 |
return $params{default} unless $text_block; |
|
146 |
return $text_block->output_position unless $params{as} eq 'text'; |
|
147 |
return 1 == $text_block->output_position ? 'front' : 'back'; |
|
148 |
} |
|
149 |
|
|
62 | 150 |
1; |
js/requirement_spec.js | ||
---|---|---|
49 | 49 |
var dropped = move_obj.r; |
50 | 50 |
var controller = dragged.data("type") == "textblock" ? "RequirementSpecTextBlock" : "RequirementSpecItem"; |
51 | 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 |
|
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 |
current_content_type: $('#current_content_type').val(), |
|
59 |
current_content_id: $('#current_content_id').val() |
|
58 | 60 |
}; |
59 | 61 |
// console.debug("controller: " + controller); |
60 | 62 |
// console.debug(data); |
61 | 63 |
|
62 |
$.ajax({ url: "controller.pl", data: data }); |
|
64 |
$.post("controller.pl", data, eval_json_result); |
|
65 |
|
|
66 |
return true; |
|
67 |
} |
|
68 |
|
|
69 |
function node_clicked(event) { |
|
70 |
var node = $.jstree._reference('#tree')._get_node(event.target); |
|
71 |
var type = node ? node.data('type') : undefined; |
|
72 |
|
|
73 |
if (!type) |
|
74 |
return; |
|
75 |
|
|
76 |
if ('sections' == type) { |
|
77 |
$('#current_content_type').val('sections'); |
|
78 |
$('#current_content_id').val(''); |
|
79 |
return; |
|
80 |
} |
|
81 |
|
|
82 |
var url = 'controller.pl?action=' |
|
83 |
$.get('controller.pl', { |
|
84 |
action: (/^textblock/ ? 'RequirementSpecTextBlock' : 'RequirementSpecItem') + '/ajax_list.js', |
|
85 |
current_content_type: $('#current_content_type').val(), |
|
86 |
current_content_id: $('#current_content_id').val(), |
|
87 |
clicked_type: type, |
|
88 |
clicked_id: node.data('id') |
|
89 |
}, function(new_data) { |
|
90 |
$('#current_content_type').val(type); |
|
91 |
$('#current_content_id').val(node.data('id')); |
|
92 |
eval_json_result(new_data); |
|
93 |
}); |
|
63 | 94 |
} |
64 | 95 |
|
65 | 96 |
function section_form_requested(data) { |
templates/webpages/requirement_spec/show.html | ||
---|---|---|
24 | 24 |
</div> |
25 | 25 |
|
26 | 26 |
<div id="content-column" class="clearfix"> |
27 |
<div id="section-container" class="section-container"> |
|
27 |
[% L.hidden_tag('current_content_type', SELF.requirement_spec_item.id ? 'section' : '') %] |
|
28 |
[% L.hidden_tag('current_content_id', SELF.requirement_spec_item.id) %] |
|
28 | 29 |
|
29 |
<div id="section_content" class="section-content"> |
|
30 |
[%- IF SELF.requirement_spec_item && SELF.requirement_spec_item.id -%] |
|
31 |
[%- INCLUDE 'requirement_spec_item/_single_section.html' requirement_spec_item=SELF.requirement_spec_item -%] |
|
32 |
[%- ELSE -%] |
|
33 |
no section |
|
34 |
[%#- render :partial => 'requirement_spec_items/no_section' -%] |
|
35 |
[%- END -%] |
|
36 |
</div> |
|
30 |
<div id="column-content"> |
|
31 |
[%- IF SELF.requirement_spec_item && SELF.requirement_spec_item.id -%] |
|
32 |
[%- INCLUDE 'requirement_spec_item/_single_section.html' requirement_spec_item=SELF.requirement_spec_item -%] |
|
33 |
[%- ELSE -%] |
|
34 |
no section |
|
35 |
[%#- render :partial => 'requirement_spec_items/no_section' -%] |
|
36 |
[%- END -%] |
|
37 | 37 |
</div> |
38 | 38 |
</div> |
39 | 39 |
</div> |
... | ... | |
100 | 100 |
}, |
101 | 101 |
"plugins": [ "themes", "json_data", "ui", "crrm", "dnd" ] |
102 | 102 |
}) |
103 |
.bind("move_node.jstree", node_moved); |
|
104 |
|
|
105 |
$(document).ajaxSend(function() { |
|
106 |
$('#spinner').show(); |
|
107 |
}).ajaxStop(function() { |
|
108 |
$('#spinner').hide(); |
|
109 |
}); |
|
103 |
.bind("move_node.jstree", node_moved) |
|
104 |
.bind("click.jstree", node_clicked) |
|
110 | 105 |
}); |
111 | 106 |
--> |
112 | 107 |
</script> |
templates/webpages/requirement_spec_text_block/_text_block.html | ||
---|---|---|
1 |
[%- USE HTML -%][%- USE L -%][%- USE LxERP -%] |
|
2 |
<div id="text-block-[% HTML.escape(text_block.id) %]" class="requirement-spec-text-block"> |
|
3 |
<h2 class="requirement-spec-text-block-title">[%- HTML.escape(text_block.title) %]</h2> |
|
4 |
|
|
5 |
[% IF !text_block.description %] |
|
6 |
<div class="requirement-spec-text-block-empty-description"> |
|
7 |
[%- LxERP.t8("No description has been entered yet.") %] |
|
8 |
</div> |
|
9 |
[% ELSE %] |
|
10 |
<div class="requirement-spec-text-block-description"> |
|
11 |
[% L.simple_format(text_block.description) %] |
|
12 |
</div> |
|
13 |
[% END %] |
|
14 |
</div> |
templates/webpages/requirement_spec_text_block/ajax_list.html | ||
---|---|---|
1 |
[%- USE LxERP -%][% nownow %] |
|
2 |
<h1> |
|
3 |
[%- IF output_position == 0 %][%- LxERP.t8("Text blocks front") %][%- ELSE %][%- LxERP.t8("Text blocks back") %][%- END %] |
|
4 |
</h1> |
|
5 |
|
|
6 |
<div id="text-block-list-empty"[% IF TEXT_BLOCKS.size %] style="display: none"[% END %]> |
|
7 |
[%- LxERP.t8("No text blocks have been created for this position.") %] |
|
8 |
</div> |
|
9 |
|
|
10 |
<div id="text-block-list"> |
|
11 |
[%- FOREACH text_block = TEXT_BLOCKS %] |
|
12 |
[%- INCLUDE 'requirement_spec_text_block/_text_block.html' %] |
|
13 |
[%- END %] |
|
14 |
</div> |
Auch abrufbar als: Unified diff
Pflichtenhefte: Drag & Drop von Textblöcken