Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 3cae447e

Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt

  • ID 3cae447edd6ab367173b9aca8a168be236f9078c
  • Vorgänger c805dfd9
  • Nachfolger 237b14f3

Pflichtenhefte: Copy & Paste für Textblöcke & Items

Unterschiede anzeigen:

SL/Controller/RequirementSpecItem.pm
9 9
use List::Util qw(first);
10 10
use Time::HiRes ();
11 11

  
12
use SL::Clipboard;
12 13
use SL::DB::RequirementSpec;
13 14
use SL::DB::RequirementSpecComplexity;
14 15
use SL::DB::RequirementSpecItem;
......
19 20

  
20 21
use Rose::Object::MakeMethods::Generic
21 22
(
22
  scalar                  => [ qw(item visible_item visible_section) ],
23
  scalar                  => [ qw(item visible_item visible_section clicked_item sections) ],
23 24
  'scalar --get_set_init' => [ qw(complexities risks) ],
24 25
);
25 26

  
26
__PACKAGE__->run_before('load_requirement_spec_item', only => [ qw(dragged_and_dropped ajax_update ajax_edit ajax_delete ajax_flag) ]);
27
__PACKAGE__->run_before('load_requirement_spec_item', only => [ qw(dragged_and_dropped ajax_update ajax_edit ajax_delete ajax_flag ajax_copy) ]);
27 28
__PACKAGE__->run_before('init_visible_section');
28 29

  
29 30
#
......
52 53
  $self->render($js);
53 54
}
54 55

  
56
sub insert_new_item_in_section_view {
57
  my ($self, $js) = @_;
58

  
59
  $js->hide('#section-list-empty');
60

  
61
  my $new_type  = $self->item->item_type;
62
  my $id_prefix = $new_type eq 'sub-function-block' ? 'sub-' : '';
63
  my $template  = 'requirement_spec_item/_' . (apply { s/-/_/g; $_ } $new_type);
64
  my $html      = "" . $self->render($template, { output => 0 }, requirement_spec_item => $self->item);
65
  my $next_item = $self->item->get_next_in_list;
66

  
67
  if ($next_item) {
68
    $js->insertBefore($html, '#' . $id_prefix . 'function-block-' . $next_item->id);
69
  } else {
70
    my $parent_is_section = $self->item->parent->item_type eq 'section';
71
    $js->appendTo($html, $parent_is_section ? '#section-list' : '#sub-function-block-container-' . $self->item->parent_id);
72
    $js->show('#sub-function-block-container-' . $self->item->parent_id) if !$parent_is_section;
73
  }
74

  
75
  $self->replace_bottom($js, $self->item->parent) if $new_type eq 'sub-function-block';
76
}
77

  
55 78
sub action_dragged_and_dropped {
56 79
  my ($self)              = @_;
57 80

  
......
105 128
  }
106 129

  
107 130
  if ($old_visible_section->id == $new_section->id) {
108
    $js->hide('#section-list-empty');
109

  
110
    my $id_prefix = $new_type eq 'sub-function-block' ? 'sub-' : '';
111
    my $template  = 'requirement_spec_item/_' . (apply { s/-/_/g; $_ } $new_type);
112
    my $html      = "" . $self->render($template, { output => 0 }, requirement_spec_item => $self->item);
113
    my $next_item = $self->item->get_next_in_list;
114

  
115
    if ($next_item) {
116
      $js->insertBefore($html, '#' . $id_prefix . 'function-block-' . $next_item->id);
117
    } else {
118
      my $parent_is_section = $self->item->parent->item_type eq 'section';
119
      $js->appendTo($html, $parent_is_section ? '#section-list' : '#sub-function-block-container-' . $self->item->parent_id);
120
      $js->show('#sub-function-block-container-' . $self->item->parent_id) if !$parent_is_section;
121
    }
122

  
123
    $self->replace_bottom($js, $self->item->parent) if $new_type eq 'sub-function-block';
131
    $self->insert_new_item_in_section_view($js);
124 132
  }
125 133

  
126 134
  # $::lxdebug->dump(0, "js", $js->to_array);
......
203 211

  
204 212
  my $js = SL::ClientJS->new;
205 213

  
206
  if (!$self->visible_section || ($self->visible_section->id != $self->item->section->id)) {
214
  if (!$self->is_item_visible) {
207 215
    # Show section/item to edit if it is not visible.
208 216

  
209 217
    my $html = $self->render('requirement_spec_item/_section', { output => 0 }, requirement_spec_item => $self->item);
......
315 323
         ->val('#current_content_id', '')
316 324
    }
317 325

  
318
  } elsif ($self->visible_section && ($self->visible_section->id == $self->item->section->id)) {
326
  } elsif ($self->is_item_visible) {
319 327
    # Item in currently visible section is deleted.
320 328

  
321 329
    my $type = $self->item->item_type;
......
342 350

  
343 351
  $self->item->update_attributes(is_flagged => !$self->item->is_flagged);
344 352

  
345
  my $is_visible = $self->visible_section && ($self->visible_section->id == $self->item->section->id);
346

  
347 353
  SL::ClientJS->new
348
   ->action_if($is_visible, 'toggleClass', '#' . $self->item->item_type . '-' . $self->item->id, 'flagged')
354
   ->action_if($self->is_item_visible, 'toggleClass', '#' . $self->item->item_type . '-' . $self->item->id, 'flagged')
349 355
   ->toggleClass('#fb-' . $self->item->id, 'flagged')
350 356
   ->render($self);
351 357
}
352 358

  
359
sub action_ajax_copy {
360
  my ($self, %params) = @_;
361

  
362
  SL::Clipboard->new->copy($self->item);
363
  SL::ClientJS->new->render($self);
364
}
365

  
366
sub determine_paste_position {
367
  my ($self) = @_;
368

  
369
  if ($self->item->item_type eq 'section') {
370
    # Sections are always pasted either directly after the
371
    # clicked-upon section or at the very end.
372
    return $self->clicked_item ? (undef, $self->clicked_item->section->id) : ();
373

  
374
  } elsif ($self->item->item_type eq 'function-block') {
375
    # A function block:
376
    # - paste on section list: insert into last section as last element
377
    # - paste on section: insert into that section as last element
378
    # - paste on function block: insert after clicked-upon element
379
    # - paste on sub function block: insert after parent function block of clicked-upon element
380
    return !$self->clicked_item                                ? ( $self->sections->[-1]->id,              undef                          )
381
         :  $self->clicked_item->item_type eq 'section'        ? ( $self->clicked_item->id,                undef                          )
382
         :  $self->clicked_item->item_type eq 'function-block' ? ( $self->clicked_item->parent_id,         $self->clicked_item->id        )
383
         :                                                       ( $self->clicked_item->parent->parent_id, $self->clicked_item->parent_id );
384

  
385
  } else {                      # sub-function-block
386
    # A sub function block:
387
    # - paste on section list: promote to function block and insert into last section as last element
388
    # - paste on section: promote to function block and insert into that section as last element
389
    # - paste on function block: insert as last element in clicked-upon element
390
    # - paste on sub function block: insert after clicked-upon element
391

  
392
    # Promote sub function blocks to function blocks when pasting on a
393
    # section or the section list.
394
    $self->item->item_type('function-block') if !$self->clicked_item || ($self->clicked_item->item_type eq 'section');
395

  
396
    return !$self->clicked_item                                ? ( $self->sections->[-1]->id,      undef                   )
397
         :  $self->clicked_item->item_type eq 'section'        ? ( $self->clicked_item->id,        undef                   )
398
         :  $self->clicked_item->item_type eq 'function-block' ? ( $self->clicked_item->id,        undef                   )
399
         :                                                       ( $self->clicked_item->parent_id, $self->clicked_item->id );
400
  }
401
}
402

  
403
sub assign_requirement_spec_id_rec {
404
  my ($self, $item) = @_;
405

  
406
  $item->requirement_spec_id($::form->{requirement_spec_id});
407
  $self->assign_requirement_spec_id_rec($_) for @{ $item->children || [] };
408

  
409
  return $item;
410
}
411

  
412
sub create_and_insert_node_rec {
413
  my ($self, $js, $item, $new_parent_id, $insert_after) = @_;
414

  
415
  my $node = $self->presenter->requirement_spec_item_jstree_data($item);
416
  $js->jstree->create_node('#tree', $insert_after ? ('#fb-' . $insert_after, 'after') : $new_parent_id ? ('#fb-' . $new_parent_id, 'last') : ('#sections', 'last'), $node);
417

  
418
  $self->create_and_insert_node_rec($js, $_, $item->id) for @{ $item->children || [] };
419

  
420
  $js->jstree->open_node('#tree', '#fb-' . $item->id);
421
}
422

  
423
sub action_ajax_paste {
424
  my ($self, %params) = @_;
425

  
426
  my $js     = SL::ClientJS->new;
427
  my $copied = SL::Clipboard->new->get_entry(qr/^RequirementSpecItem$/);
428

  
429
  if (!$copied) {
430
    return $js->error(t8("The clipboard does not contain anything that can be pasted here."))
431
              ->render($self);
432
  }
433

  
434
  $self->item($self->assign_requirement_spec_id_rec($copied->to_object));
435
  my $req_spec = SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load;
436
  $self->sections($req_spec->sections);
437

  
438
  if (($self->item->item_type ne 'section') && !@{ $self->sections }) {
439
    return $js->error(t8("You cannot paste function blocks or sub function blocks if there is no section."))
440
              ->render($self);
441
  }
442

  
443
  $self->clicked_item($::form->{id} ? SL::DB::RequirementSpecItem->new(id => $::form->{id})->load : undef);
444

  
445
  my ($new_parent_id, $insert_after) = $self->determine_paste_position;
446

  
447
  # Store result in database.
448
  $self->item->update_attributes(requirement_spec_id => $::form->{requirement_spec_id}, parent_id => $new_parent_id);
449
  $self->item->add_to_list(position => 'after', reference => $insert_after) if $insert_after;
450

  
451
  # Update the tree: create the node for all pasted objects.
452
  $self->create_and_insert_node_rec($js, $self->item, $new_parent_id, $insert_after);
453

  
454
  # Pasting the very first section?
455
  if (!@{ $self->sections }) {
456
    my $html = $self->render('requirement_spec_item/_section', { output => 0 }, requirement_spec_item => $self->item);
457
    $js->html('#column-content', $html)
458
       ->jstree->select_node('#tree', '#fb-' . $self->item->id)
459
  }
460

  
461
  # Update the current view if required.
462
  $self->insert_new_item_in_section_view($js) if $self->is_item_visible;
463

  
464
  $js->render($self);
465
}
466

  
353 467
#
354 468
# filters
355 469
#
......
483 597
  my $js = SL::ClientJS->new;
484 598

  
485 599
  my $new_section = $self->item->section;
486
  if (!$self->visible_section || ($self->visible_section->id != $new_section->id)) {
600
  if (!$self->is_item_visible) {
487 601
    # Show section/item to edit if it is not visible.
488 602

  
489 603
    $html = $self->render('requirement_spec_item/_section', { output => 0 }, requirement_spec_item => $new_section);
......
503 617
  $js->render($self);
504 618
}
505 619

  
620
sub is_item_visible {
621
  my ($self, $item) = @_;
622

  
623
  $item ||= $self->item;
624
  return $self->visible_section && ($self->visible_section->id == $item->section->id);
625
}
626

  
506 627
1;

Auch abrufbar als: Unified diff