Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 602e604a

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 602e604a5d2e2b07c142c3d47fc9a2337ca36301
  • Vorgänger bf9adfba
  • Nachfolger f3cfe3bd

Textblöcke bearbeiten

Unterschiede anzeigen:

SL/Controller/RequirementSpecTextBlock.pm
6 6

  
7 7
use SL::ClientJS;
8 8
use SL::DB::RequirementSpec;
9
use SL::DB::RequirementSpecPredefinedText;
9 10
use SL::DB::RequirementSpecTextBlock;
10 11
use SL::Helper::Flash;
11 12
use SL::JSON;
......
16 17
 scalar => [ qw(requirement_spec text_block) ],
17 18
);
18 19

  
19
__PACKAGE__->run_before('load_requirement_spec_text_block', only => [qw(dragged_and_dropped)]);
20
__PACKAGE__->run_before('load_requirement_spec_text_block', only => [qw(ajax_edit update dragged_and_dropped)]);
20 21

  
21 22
#
22 23
# actions
......
41 42
  my $js = SL::ClientJS->new;
42 43

  
43 44
  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);
45
    my $text_blocks = SL::DB::Manager::RequirementSpecTextBlock->get_all_sorted(where => [ output_position => $new_where, requirement_spec_id => $::form->{requirement_spec_id} ]);
46
    my $html        = $self->render('requirement_spec_text_block/ajax_list', { output => 0 }, TEXT_BLOCKS => $text_blocks, output_position => $new_where);
46 47

  
47 48
    $js->html('#column-content', $html)
48 49
  }
......
50 51
  $self->render($js);
51 52
}
52 53

  
54
sub action_ajax_edit {
55
  my ($self) = @_;
56

  
57
  my $js = SL::ClientJS->new;
58

  
59
  my $current_where = $self->output_position_from_id($::form->{current_content_id}, $::form->{current_content_type}) // -1;
60
  if ($self->text_block->output_position != $current_where) {
61
    my $text_blocks = $self->text_block->get_full_list;
62
    my $html        = $self->render('requirement_spec_text_block/ajax_list', { output => 0 }, TEXT_BLOCKS => $text_blocks, output_position => $self->text_block->output_position);
63

  
64
    $js->html('#column-content', $html)
65
       ->val('#current_content_type', 'text-block')
66
       ->val('#current_content_id',   $self->text_block->id);
67
  }
68

  
69
  my $predefined_texts = SL::DB::Manager::RequirementSpecPredefinedText->get_all_sorted;
70
  my $html             = $self->render('requirement_spec_text_block/_form', { output => 0 }, PREDEFINED_TEXTS => $predefined_texts);
71

  
72
  $js->hide('#text-block-' . $self->text_block->id)
73
     ->insertAfter($html, '#text-block-' . $self->text_block->id)
74
     ->jstree->select_node('#tree', '#tb-' . $self->text_block->id)
75
     ->render($self);
76
}
77

  
78
sub action_update {
79
  my ($self, %params) = @_;
80

  
81
  my $prefix     = $::form->{form_prefix} || 'text_block';
82
  my $attributes = $::form->{$prefix}     || {};
83

  
84
  foreach (qw(requirement_spec_id output_position)) {
85
    delete $attributes->{$_} if !defined $attributes->{$_};
86
  }
87

  
88
  $self->text_block->update_attributes(%{ $attributes });
89

  
90
  my $html = $self->render('requirement_spec_text_block/_text_block', { output => 0 }, text_block => $self->text_block);
91

  
92
  SL::ClientJS->new
93
    ->remove('#' . $prefix . '_form')
94
    ->replaceWith('#text-block-' . $self->text_block->id, $html)
95
    ->jstree->rename_node('#tree', '#tb-' . $self->text_block->id, $self->text_block->title)
96
    ->render($self);
97
}
98

  
99

  
53 100
sub action_dragged_and_dropped {
54 101
  my ($self)       = @_;
55 102

  
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;
19 18
use SL::Presenter::RequirementSpecItem;
19
use SL::Presenter::RequirementSpecTextBlock;
20 20
use SL::Presenter::SepaExport;
21 21
use SL::Presenter::Text;
22 22
use SL::Presenter::Tag;
js/requirement_spec.js
1 1
/* Functions used for the requirement specs tree view */
2 2

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

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

  
45
function node_moved(event) {
45
function requirement_spec_tree_node_moved(event) {
46 46
  console.debug("node moved");
47 47
  var move_obj   = $.jstree._reference('#tree')._get_move();
48 48
  var dragged    = move_obj.o;
......
66 66
  return true;
67 67
}
68 68

  
69
function node_clicked(event) {
69
function requirement_spec_tree_node_clicked(event) {
70 70
  var node = $.jstree._reference('#tree')._get_node(event.target);
71 71
  var type = node ? node.data('type') : undefined;
72 72

  
......
82 82
  var url = 'controller.pl?action='
83 83
  $.get('controller.pl', {
84 84
    action:               (/^textblock/ ? 'RequirementSpecTextBlock' : 'RequirementSpecItem') + '/ajax_list.js',
85
    requirement_spec_id:  $('#requirement_spec_id').val(),
85 86
    current_content_type: $('#current_content_type').val(),
86 87
    current_content_id:   $('#current_content_id').val(),
87 88
    clicked_type:         type,
......
134 135
function cancel_section_form(id) {
135 136
  $('#content-column').html('intentionally empty');
136 137
}
138

  
139
function find_text_block_id(clicked_elt) {
140
  console.log("id: " + $(clicked_elt).attr('id'));
141
  var id = $(clicked_elt).attr('id');
142
  if (/^text-block-\d+$/.test(id)) {
143
    console.log("find_text_block_id: case 1: " + id.substr(11));
144
    return id.substr(11) * 1;
145
  }
146

  
147
  id = $(clicked_elt).closest("[id*=text-block-]").attr('id')
148
  if (/^text-block-\d+$/.test(id)) {
149
    console.log("find_text_block_id: case 2: " + id.substr(11));
150
    return id.substr(11) * 1;
151
  }
152

  
153
  id = $(clicked_elt).closest("[id*=tb-]").attr('id')
154
  if (/^tb-\d+$/.test(id)) {
155
    console.log("find_text_block_id: case 3: " + id.substr(3));
156
    return id.substr(3) * 1;
157
  }
158

  
159
  console.log("find_text_block_id: case undef");
160
  return undefined;
161
}
162

  
163
function find_text_block_output_position(clicked_elt) {
164
  var output_position = $(clicked_elt).closest('#text-block-list-container').find('#text_block_output_position').val();
165
  if (output_position)
166
    return output_position;
167

  
168
  var type = $(clicked_elt).closest('#tb-back,#tb-front').data('type');
169
  if (/^textblocks-(front|back)/.test(type))
170
    return type == "textblocks-front" ? 0 : 1;
171

  
172
  return undefined;
173
}
174

  
175
function disable_edit_text_block_commands(key, opt) {
176
  return find_text_block_id(opt.$trigger) == undefined;
177
}
178

  
179
function edit_text_block(key, opt) {
180
  var data = {
181
    action:               "RequirementSpecTextBlock/ajax_edit",
182
    id:                   find_text_block_id(opt.$trigger),
183
    current_content_type: $('#current_content_type').val(),
184
    current_content_id:   $('#current_content_id').val()
185
  };
186
  $.post("controller.pl", data, eval_json_result);
187
  return true;
188
}
189

  
190
function add_text_block(key, opt) {
191
  return true;
192
}
193

  
194
function delete_text_block(key, opt) {
195
  var data = {
196
    action:               "RequirementSpecTextBlock/ajax_delete",
197
    id:                   find_text_block_id(opt.$trigger),
198
    current_content_type: $('#current_content_type').val(),
199
    current_content_id:   $('#current_content_id').val()
200
  };
201
  $.post("controller.pl", data, eval_json_result);
202
  return true;
203
}
204

  
205
function submit_edit_text_block_form(id_base) {
206
  var url  = "controller.pl?" + $('#' + id_base + '_form').serialize();
207
  var data = {
208
    action:      'RequirementSpecTextBlock/update.js',
209
    id:          $('#' + id_base + '_id').val(),
210
    form_prefix: id_base
211
  };
212
  console.log("posting edit text block: " + url);
213
  console.log(data);
214
  $.post(url, data, eval_json_result);
215
}
216

  
217
function cancel_edit_text_block_form(id_base) {
218
  var id = $('#' + id_base + '_id').val();
219
  $('#' + id_base + '_form').remove();
220
  if (id)
221
    $('#text-block-' + id).show();
222
}
templates/webpages/requirement_spec/show.html
41 41
<script type="text/javascript">
42 42
 <!--
43 43
     var tree_data = [
44
       { "data": [% JSON.json(LxERP.t8("Text blocks front")) %],
45
         "metadata": { "type": "textblocks-front" },
46
         "attr": { "id": "tb-front" },
47
         "children": [
44
       { data:     [% JSON.json(LxERP.t8("Text blocks front")) %],
45
         metadata: { type: "textblocks-front" },
46
         attr:     { id: "tb-front", class: "text-block-context-menu" },
47
         children: [
48 48
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(0) %]
49 49
 [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
50 50
[% END %]
51 51
         ]
52 52
       },
53 53

  
54
       { "data": [% JSON.json(LxERP.t8("Sections")) %],
55
         "metadata": { "type": "sections" },
56
         "attr": { "id": "sections" },
57
         "children": [
54
       { data:     [% JSON.json(LxERP.t8("Sections")) %],
55
         metadata: { type: "sections" },
56
         attr:     { id: "sections" },
57
         children: [
58 58

  
59 59
[% FOREACH section = SELF.requirement_spec.sections %]
60 60
 [% P.requirement_spec_item_jstree_data(section).json %][% IF !loop.last %],[% END %]
......
62 62
         ]
63 63
       },
64 64

  
65
       { "data": [% JSON.json(LxERP.t8("Text blocks back")) %],
66
         "metadata": { "type": "textblocks-back" },
67
         "attr": { "id": "tb-back" },
68
         "children": [
65
       { data:     [% JSON.json(LxERP.t8("Text blocks back")) %],
66
         metadata: { type: "textblocks-back" },
67
         attr:     { id: "tb-back", class: "text-block-context-menu" },
68
         children: [
69 69
[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(1) %]
70 70
 [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
71 71
[% END %]
......
75 75

  
76 76
     $(function() {
77 77
       $('#tree').jstree({
78
         "core": {
79
           "animation": 0,
80
           "initially_open": [ "tb-front", "tb-back", "sections"
78
         core: {
79
           animation: 0,
80
           initially_open: [ "tb-front", "tb-back", "sections"
81 81
[%- FOREACH section = SELF.requirement_spec.sections -%]
82 82
 , "fb-[% section.id %]"
83 83
 [%- FOREACH function_block = section.children -%]
......
86 86
[%- END -%]
87 87
 ]
88 88
         },
89
         "json_data": {
90
           "data": tree_data
89
         json_data: {
90
           data: tree_data
91 91
         },
92
         "crrm": {
93
           "move": {
94
             "check_move": check_move,
95
             "open_move": true
92
         crrm: {
93
           move: {
94
             check_move: requirement_spec_tree_check_move,
95
             open_move:  true
96 96
           }
97 97
         },
98
         "themes": {
99
           "theme": "requirement-spec"
98
         themes: {
99
           theme: "requirement-spec"
100 100
         },
101
         "plugins": [ "themes", "json_data", "ui", "crrm", "dnd" ]
101
         plugins: [ "themes", "json_data", "ui", "crrm", "dnd" ]
102 102
       })
103
       .bind("move_node.jstree", node_moved)
104
       .bind("click.jstree",     node_clicked)
103
       .bind("move_node.jstree", requirement_spec_tree_node_moved)
104
       .bind("click.jstree",     requirement_spec_tree_node_clicked)
105 105
     });
106

  
107
function ask_delete_text_block(key, opt) {
108
  if (confirm("[% LxERP.t8("Are you sure?") %]"))
109
    delete_text_block(key, opt);
110
  return true;
111
}
112

  
113
$(function(){
114
    $.contextMenu({
115
        selector: '.text-block-context-menu',
116
        items: {
117
          add:    { name: "[% LxERP.t8('Add text block') %]", icon: "add", callback: add_text_block },
118
          edit:   { name: "[% LxERP.t8('Edit text block') %]", icon: "edit", callback: edit_text_block, disabled: disable_edit_text_block_commands },
119
          delete: { name: "[% LxERP.t8('Delete text block') %]", icon: "delete", callback: ask_delete_text_block, disabled: disable_edit_text_block_commands },
120
          sep1:   "---------",
121
          copy:   { name: "[% LxERP.t8('Copy') %]", icon: "copy", disabled: disable_edit_text_block_commands },
122
          paste:  { name: "[% LxERP.t8('Paste') %]", icon: "paste", disabled: disable_edit_text_block_commands }
123
        }
124
      });
125
});
126

  
106 127
  -->
107 128
</script>
templates/webpages/requirement_spec_text_block/_form.html
1
[%- USE LxERP -%][%- USE L -%][%- USE HTML -%][%- USE JavaScript -%][% SET style="width: 500px" %]
2
[% DEFAULT id_base = 'edit_text_block_' _ SELF.text_block.id %]
3
<form method="post" id="[% id_base %]_form">
4
 [% L.hidden_tag(id_base _ '_id',                  SELF.text_block.id) %]
5
 [% L.hidden_tag(id_base _ '.requirement_spec_id', SELF.text_block.requirement_spec_id) %]
6
 [% L.hidden_tag(id_base _ '.output_position',     SELF.text_block.output_position) %]
7

  
8
 <table>
9
  <tr>
10
   <th align="right">[%- LxERP.t8("Title") %]:</th>
11
   <td>[% L.input_tag(id_base _ '.title', SELF.text_block.title, style = style) %]</td>
12
  </tr>
13

  
14
 [%- IF PREDEFINED_TEXTS.size %]
15
  <tr>
16
   <th align="right">[%- LxERP.t8("Pre-defined text block") %]:</th>
17
   <td>
18
    [%- L.select_tag(id_base _ '_predefined_text_block', PREDEFINED_TEXTS, title_key='description', style=style) %]
19
    <a href="#" onclick="insert_selected_predefined_text()">[%- LxERP.t8("Insert") %]</a>
20
   </td>
21
  </tr>
22
 [%- END %]
23

  
24
  <tr>
25
   <th align="right" valign="top">[%- LxERP.t8("Description") %]:</th>
26
   <td valign="top">[% L.textarea_tag(id_base _ '.text', SELF.text_block.text, style = style, rows = 10) %]</td>
27
  </tr>
28
 </table>
29

  
30
 <p>
31
  [% L.button_tag('submit_edit_text_block_form("' _ id_base _ '")', LxERP.t8('Save')) %]
32
  <a href="#" onclick="cancel_edit_text_block_form('[% id_base %]')">[%- LxERP.t8("Cancel") %]</a>
33
 </p>
34

  
35
[%- IF PREDEFINED_TEXTS.size %]
36
 <script type="text/javascript">
37
<!--
38
function insert_selected_predefined_text() {
39
  var data = {
40
[%- FOREACH pt = PREDEFINED_TEXTS %]
41
    [% HTML.escape(pt.id) %]: {
42
      title: "[% JavaScript.escape(pt.title) %]",
43
      text: "[% JavaScript.escape(pt.text) %]"
44
    }[% UNLESS loop.last %],[% END %]
45
[% END %]
46
  }
47

  
48
  var id = $('#[% id_base %]_predefined_text_block').val();
49
  var pt = data[id];
50
  if (!pt) {
51
    console.log("insert: case 1; id: " + id);
52
    return false;
53
  }
54

  
55
  var title_ctrl = $('#[% id_base %]_title');
56

  
57
  if (   ((title_ctrl.val() || '') != '')
58
      && ((pt.title         || '') != '')
59
      && confirm('[%- LxERP.t8("Do you want to overwrite your current title?") %]'))
60
    title_ctrl.val(pt.title);
61

  
62
  if ((pt.text || '') != '') {
63
    var text_ctrl = $('#[% id_base %]_text');
64
    var text      = text_ctrl.val() || '';
65
    if (text != '')
66
      text += "\n\n";
67

  
68
    text_ctrl.val(text + pt.text);
69
  }
70

  
71
  return false;
72
}
73
-->
74
 </script>
75
[%- END %]
76
</form>
templates/webpages/requirement_spec_text_block/_text_block.html
1 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>
2
<div id="text-block-[% HTML.escape(text_block.id) %]" class="requirement-spec-text-block text-block-context-menu">
3
 <h2 class="requirement-spec-text-block-title">[% IF !text_block.title %]<span class="dimmed-text">[%- LxERP.t8("No title yet") %]</span>[% END %][%- HTML.escape(text_block.title) %]</h2>
4 4

  
5
 [% IF !text_block.description %]
6
  <div class="requirement-spec-text-block-empty-description">
7
   [%- LxERP.t8("No description has been entered yet.") %]
5
 [% IF !text_block.text %]
6
  <div class="dimmed-text">
7
   [%- LxERP.t8("No text has been entered yet.") %]
8 8
  </div>
9 9
 [% ELSE %]
10
  <div class="requirement-spec-text-block-description">
11
   [% L.simple_format(text_block.description) %]
10
  <div class="requirement-spec-text-block-text">
11
   [% L.simple_format(text_block.text) %]
12 12
  </div>
13 13
 [% END %]
14 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>
1
[%- USE LxERP -%][%- USE L -%]
5 2

  
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>
3
<div id="text-block-list-container">
4
 [% L.hidden_tag('text_block_output_position', output_position) %]
5
 <h1 class="text-block-context-menu">
6
  [%- IF output_position == 0 %][%- LxERP.t8("Text blocks front") %][%- ELSE %][%- LxERP.t8("Text blocks back") %][%- END %]
7
 </h1>
8

  
9
 <div id="text-block-list-empty" class="text-block-context-menu"[% IF TEXT_BLOCKS.size %] style="display: none"[% END %]>
10
  [%- LxERP.t8("No text blocks have been created for this position.") %]
11
 </div>
9 12

  
10
<div id="text-block-list">
11
 [%- FOREACH text_block = TEXT_BLOCKS %]
12
  [%- INCLUDE 'requirement_spec_text_block/_text_block.html' %]
13
 [%- END %]
13
 <div id="text-block-list">
14
  [%- FOREACH text_block = TEXT_BLOCKS %]
15
   [%- INCLUDE 'requirement_spec_text_block/_text_block.html' %]
16
  [%- END %]
17
 </div>
14 18
</div>
19

  
20
<script type="text/javascript">
21
 <!--
22
-->
23
</script>

Auch abrufbar als: Unified diff