+  $self->set_function_blocks_tab_menu_class(class => 'section-context-menu')
+       ->html('#column-content', $html);
+  $self->select_node($item_to_select || $item);
+}
+
+sub select_node {
+  my ($self, $item) = @_;
+
+  $self->js
+    ->val( '#current_content_type', $item->item_type)
+    ->val( '#current_content_id',   $item->id)
+    ->jstree->select_node('#tree', '#fb-' . $item->id);
+}
+
+sub create_dependency_item {
+  my $self = shift;
+  [ $_[0]->id, $self->presenter->truncate(join(' ', grep { $_ } ($_[1], $_[0]->fb_number, $_[0]->description_as_stripped_html))) ];
+}
+
+sub create_dependencies {
+  my ($self) = @_;
+
+  return map { [ $_->fb_number . ' ' . $_->title,
+                 [ map { ( $self->create_dependency_item($_),
+                           map { $self->create_dependency_item($_, '->') } @{ $_->children_sorted })
+                       } @{ $_->children_sorted } ] ]
+             } @{ $self->item->requirement_spec->sections };
+}
+
+sub ensure_section_is_shown {
+  my ($self, %params) = @_;
+
+  return $self->js if $self->is_item_visible;
+
+  # Show section/item to edit if it is not visible.
+  my $new_section = $self->item->section;
+  my $html        = $self->render('requirement_spec_item/_section', { output => 0 }, requirement_spec_item => $new_section);
+
+  return $self->set_function_blocks_tab_menu_class(class => 'section-context-menu')
+    ->html('#column-content', $html)
+    ->val('#current_content_type', 'section')
+    ->val('#current_content_id',   $new_section->id)
+    ->jstree->select_node('#tree', '#fb-' . $new_section->id);
+}
+
+sub add_new_item_form {
+  my ($self, %params) = @_;
+
+  for (qw(insert_position display_reference)) {
+    croak "Missing parameter $_" if !$params{$_};
+  }
+  croak "Missing parameter insert_reference" if ($params{insert_position} eq 'insertAfter') && !$params{insert_reference};
+
+  my $id_base = join('_', 'new_function_block', Time::HiRes::gettimeofday(), int rand 1000000000000);
+  my $html    = $self->render(
+    'requirement_spec_item/_function_block_form',
+    { output => 0 },
+    DEPENDENCIES          => [ $self->create_dependencies ],
+    SELECTED_DEPENDENCIES => [],
+    requirement_spec_item => $self->item,
+    id_base               => $id_base,
+    insert_after          => $params{insert_position} eq 'insertAfter' ? $params{insert_reference} : undef,
+  );
+
+  return $self->js
+    ->action($params{insert_position}, $html, $params{display_reference})
+    ->action_if($self->item->item_type eq 'sub-function-block', 'show', '#sub-function-block-container-' . $self->item->parent_id)
+    ->run('kivi.requirement_spec.init_function_block_keypress_events', "${id_base}_form")
+    ->reinit_widgets
+    ->focus("#${id_base}_description");
+}
+
+sub add_new_item_form_after_create {
+  my ($self, %params) = @_;
+
+  my $created_item    = $self->item;
+
+  my ($new_item_type, $new_parent_id, $insert_position, $insert_reference, $display_reference);
+  if ($created_item->item_type eq 'section') {
+    # $created_item is section, new one will be function-block
+    $new_item_type     = 'function-block';
+    $new_parent_id     = $created_item->id;
+    $insert_position   = 'appendTo';
+    $display_reference = '#section-list';
+
+  } elsif (!$::form->{shift_in_out}) {
+    # $created_item is function-block or sub-function-block, new one will be the same
+    $new_item_type     = $created_item->item_type;
+    $new_parent_id     = $created_item->parent_id;
+    $insert_position   = 'insertAfter';
+    $insert_reference  = $created_item->id;
+    $display_reference = '#' . $created_item->item_type . '-' . $created_item->id;
+
+  } elsif ($created_item->item_type eq 'function-block') {
+    # $created_item is function-block, new one will be sub-function-block
+    $new_item_type     = 'sub-function-block';
+    $new_parent_id     = $created_item->id;
+    $insert_position   = 'appendTo';
+    $display_reference = '#sub-function-block-container-' . $created_item->id;
+
+  } else {
+    # $created_item is sub-function-block, new one will be function-block
+    $new_item_type     = 'function-block';
+    $new_parent_id     = $created_item->parent->parent_id;
+    $insert_position   = 'insertAfter';
+    $insert_reference  = $created_item->parent_id;
+    $display_reference = '#function-block-' . $created_item->parent_id;
+  }
+
+  $::lxdebug->message(LXDebug::DEBUG1(),
+                      "OLD item_type " . $created_item->item_type . " ; NEW item_type $new_item_type ; parent_id $new_parent_id ; " .
+                      "insert_position $insert_position ; insert_reference $insert_reference ; display_reference $display_reference");
+
+  $self->item(SL::DB::RequirementSpecItem->new(
+    requirement_spec_id => $created_item->requirement_spec_id,
+    parent_id           => $new_parent_id,
+    item_type           => $new_item_type,
+  ));
+
+  $self->add_new_item_form(
+    insert_reference  => $insert_reference,
+    insert_position   => $insert_position,
+    display_reference => $display_reference,
+  );
+}
+
+sub add_function_block {
+  my ($self, $new_type) = @_;
+
+  my $clicked_id = $::form->{id} || ($self->visible_item ? $self->visible_item->id : undef);
+
+  die "Invalid new_type '$new_type'"               if $new_type !~ m/^(?:sub-)?function-block$/;
+  die "Missing parameter 'id' and no visible item" if !$clicked_id;
+  die "Missing parameter 'requirement_spec_id'"    if !$::form->{requirement_spec_id};
+
+  my $clicked_item = SL::DB::RequirementSpecItem->new(id => $clicked_id)->load;
+  my $clicked_type = $clicked_item->item_type;
+
+  die "Invalid clicked_type '$clicked_type'" if $clicked_type !~ m/^(?: section | (?:sub-)? function-block )$/x;
+
+  my $case = "${clicked_type}:${new_type}";
+
+  my ($insert_position, $insert_reference, $parent_id, $display_reference)
+    = $case eq 'section:function-block'                ? ( 'appendTo',    $clicked_item->id,        $clicked_item->id,                '#section-list'                  )
+    : $case eq 'function-block:function-block'         ? ( 'insertAfter', $clicked_item->id,        $clicked_item->parent_id,         '#function-block-'               )
+    : $case eq 'function-block:sub-function-block'     ? ( 'appendTo'  ,  $clicked_item->id,        $clicked_item->id,                '#sub-function-block-container-' )
+    : $case eq 'sub-function-block:function-block'     ? ( 'insertAfter', $clicked_item->parent_id, $clicked_item->parent->parent_id, '#function-block-'               )
+    : $case eq 'sub-function-block:sub-function-block' ? ( 'insertAfter', $clicked_item->id,        $clicked_item->parent_id,         '#sub-function-block-'           )
+    :                                                    die "Invalid combination of 'clicked_type (section)/new_type ($new_type)'";
+
+  $display_reference .= $insert_reference if $display_reference =~ m/-$/;
+
+  $self->item(SL::DB::RequirementSpecItem->new(requirement_spec_id => $::form->{requirement_spec_id}, parent_id => $parent_id, item_type => $new_type));
+
+  $self->ensure_section_is_shown;
+  $self->js->show('#sub-function-block-container-' . $parent_id) if $new_type eq 'sub-function-block';
+  $self->add_new_item_form(insert_position => $insert_position, insert_reference => $insert_reference, display_reference => $display_reference);
+
+  $self->js->render;
+}
+
+sub is_item_visible {
+  my ($self, $item) = @_;
+
+  $item ||= $self->item;
+  return $self->visible_section && ($self->visible_section->id == $item->section->id);
+}
+
+sub invalidate_version {
+  my ($self) = @_;
+
+  my $html   = $self->render('requirement_spec/_version', { output => 0 },
+                             requirement_spec => SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id} || $self->item->requirement_spec_id)->load);
+  return $self->js->html('#requirement_spec_version', $html);