use Rose::Object::MakeMethods::Generic
(
- scalar => [ qw(requirement_spec customers projects types statuses db_args flat_filter is_template) ],
+ scalar => [ qw(requirement_spec requirement_spec_item customers projects types statuses db_args flat_filter is_template) ],
);
__PACKAGE__->run_before('setup');
-__PACKAGE__->run_before('load_requirement_spec', only => [ qw( edit update destroy tree) ]);
+__PACKAGE__->run_before('load_requirement_spec', only => [ qw( edit update show destroy tree) ]);
__PACKAGE__->run_before('load_select_options', only => [ qw(new edit create update list) ]);
__PACKAGE__->run_before('load_search_select_options', only => [ qw( list) ]);
$self->render('requirement_spec/form', title => t8('Edit requirement spec'));
}
+sub action_show {
+ my ($self) = @_;
+
+ my $item = $::form->{requirement_spec_item_id} ? SL::DB::RequirementSpecItem->new(id => $::form->{requirement_spec_item_id})->load : @{ $self->requirement_spec->sections }[0];
+ $self->requirement_spec_item($item);
+
+ $self->render('requirement_spec/show', title => t8('Show requirement spec'));
+}
+
sub action_create {
my ($self) = @_;
my ($self) = @_;
$::auth->assert('config');
- $::request->{layout}->use_stylesheet("${_}.css") for qw(requirement_spec yaml/core/base.min);
- $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree requirement_spec);
+ $::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec);
+ $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu requirement_spec);
$self->is_template($::form->{is_template} ? 1 : 0);
return 1;
);
# __PACKAGE__->run_before('load_requirement_spec');
-__PACKAGE__->run_before('load_requirement_spec_item', only => [qw(dragged_and_dropped)]);
+__PACKAGE__->run_before('load_requirement_spec_item', only => [qw(dragged_and_dropped edit_section update_section)]);
#
# actions
$self->render(\'', { type => 'json' });
}
+sub action_edit_section {
+ my ($self, %params) = @_;
+ $self->render('requirement_spec_item/_section_form', { layout => 0 });
+}
+
+sub action_update_section {
+ my ($self, %params) = @_;
+
+ $self->item->update_attributes(title => $::form->{title}, description => $::form->{description});
+
+ my $result = {
+ id => $self->item->id,
+ header_html => $self->render('requirement_spec_item/_section_header', { layout => 0, output => 0 }, requirement_spec_item => $self->item),
+ node_name => join(' ', map { $_ || '' } ($self->item->fb_number, $self->item->title)),
+ };
+ $self->render(\to_json($result), { type => 'json' });
+}
+
#
# filters
#
return [ sort { $a->position <=> $b->position } grep { !$_->parent_id } @{ $self->items } ];
}
+sub displayable_name {
+ my ($self) = @_;
+
+ return sprintf('%s: "%s"', $self->type->description, $self->title);
+}
+
1;
use SL::Presenter::Project;
use SL::Presenter::Record;
use SL::Presenter::RequirementSpec;
+use SL::Presenter::RequirementSpecItem;
use SL::Presenter::SepaExport;
use SL::Presenter::Text;
use SL::Presenter::Tag;
use parent qw(Exporter);
use Exporter qw(import);
-our @EXPORT = qw(requirement_spec_text_block_jstree_data
- requirement_spec_item_jstree_data);
+our @EXPORT = qw(requirement_spec_text_block_jstree_data);
use Carp;
};
}
-sub requirement_spec_item_jstree_data {
- my ($self, $item, %params) = @_;
-
- my @children = map { $self->requirement_spec_item_jstree_data($_, %params) } @{ $item->sorted_children };
- my $type = !$item->parent_id ? 'section' : 'functionblock';
-
- return {
- data => join(' ', map { $_ || '' } ($item->fb_number, $item->title)),
- metadata => { id => $item->id, type => $type },
- attr => { id => "fb-" . $item->id, href => $params{href} || '#' },
- children => \@children,
- };
-}
-
1;
--- /dev/null
+package SL::Presenter::RequirementSpecItem;
+
+use strict;
+
+use parent qw(Exporter);
+
+use Exporter qw(import);
+our @EXPORT = qw(requirement_spec_item_jstree_data requirement_spec_item_dependency_list);
+
+use Carp;
+
+sub requirement_spec_item_jstree_data {
+ my ($self, $item, %params) = @_;
+
+ my @children = map { $self->requirement_spec_item_jstree_data($_, %params) } @{ $item->sorted_children };
+ my $type = !$item->parent_id ? 'section' : 'functionblock';
+
+ return {
+ data => join(' ', map { $_ || '' } ($item->fb_number, $item->title)),
+ metadata => { id => $item->id, type => $type },
+ attr => { id => "fb-" . $item->id, href => $params{href} || '#' },
+ children => \@children,
+ };
+}
+
+sub requirement_spec_item_dependency_list {
+ my ($self, $item) = @_;
+
+ $::locale->language_join([ map { $_->fb_number } @{ $item->dependencies } ]);
+}
+
+1;
width: 300px;
}
+#column-container {
+ width: 100%;
+ padding-left: 0;
+ padding-right: 0;
+ margin-left: 0;
+ margin-right: 0;
+}
+
+#tree-column {
+ float: left;
+ width: 25%;
+ border-right: 1px solid black;
+}
+
#content-column {
- margin-left: 10px;
+ float: left;
+ padding-left: 10px;
+}
+
+.section-empty-description {
+ color: #bbb;
}
--- /dev/null
+[%- USE L -%][%- USE LxERP -%][%- USE HTML -%]
+[% L.stuff %]
+[% LxERP.t8("Current version") %]:
+[% IF !requirement_spec.version_id %]
+ [% LxERP.t8("Working copy without version") %]
+[% ELSE %]
+ [% LxERP.t8("Version") %] [% HTML.escape(requirement_spec.version.version_number) %]
+ [% LxERP.t8("dated") %] [% HTML.escape(requirement_spec.version.itime.displayable_date) %]
+[%- END -%]
--- /dev/null
+[%- USE JSON -%][%- USE HTML %][%- USE L %][%- USE LxERP %][%- USE P -%]
+
+<h1>[%- HTML.escape(SELF.requirement_spec.displayable_name('format', 'with_customer')) %]
+ [% LxERP.t8("for") %]
+ [% HTML.escape(SELF.requirement_spec.customer.displayable_name) -%]
+</h1>
+
+[%- L.hidden_tag('requirement_spec_id', SELF.requirement_spec.id) -%]
+
+<div id="requirement_spec_version">
+ [%- INCLUDE 'requirement_spec/_version.html' requirement_spec=SELF.requirement_spec -%]
+</div>
+
+<div id="column-container">
+ <div id="tree-column" style="border-right: 1px solid black">
+ <div style="min-height: 32px; height: 32px;">
+ <div style="float: left">
+ [% L.button_tag("new_section_form()", LxERP.t8("New section"), id="new-section-button") %]
+ </div>
+ <div id="spinner" class="clearfix" 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>
+ </div>
+
+ <div id="tree"></div>
+ </div>
+
+ <div id="content-column" class="clearfix">
+ <div id="section-container" class="section-container">
+
+ <div id="section_content" class="section-content">
+ [%- IF SELF.requirement_spec_item && SELF.requirement_spec_item.id -%]
+ [%- INCLUDE 'requirement_spec_item/_single_section.html' requirement_spec_item=SELF.requirement_spec_item -%]
+ [%- ELSE -%]
+ no section
+ [%#- render :partial => 'requirement_spec_items/no_section' -%]
+ [%- END -%]
+ </div>
+ </div>
+ </div>
+</div>
+
+<script type="text/javascript">
+ <!--
+ var tree_data = [
+ { "data": [% JSON.json(LxERP.t8("Text blocks front")) %],
+ "metadata": { "type": "textblocks-front" },
+ "attr": { "id": "tb-front" },
+ "children": [
+[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(0) %]
+ [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
+[% END %]
+ ]
+ },
+
+ { "data": [% JSON.json(LxERP.t8("Sections")) %],
+ "metadata": { "type": "sections" },
+ "attr": { "id": "sections" },
+ "children": [
+
+[% FOREACH section = SELF.requirement_spec.sections %]
+ [% P.requirement_spec_item_jstree_data(section).json %][% IF !loop.last %],[% END %]
+[% END %]
+ ]
+ },
+
+ { "data": [% JSON.json(LxERP.t8("Text blocks back")) %],
+ "metadata": { "type": "textblocks-back" },
+ "attr": { "id": "tb-back" },
+ "children": [
+[% FOREACH tb = SELF.requirement_spec.text_blocks_for_position(1) %]
+ [% P.requirement_spec_text_block_jstree_data(tb).json %][% IF !loop.last %],[% END %]
+[% END %]
+ ]
+ }
+ ];
+
+ $(function() {
+ $('#tree').jstree({
+ "core": {
+ "animation": 0,
+ "initially_open": [ "tb-front", "tb-back", "sections"
+[%- FOREACH section = SELF.requirement_spec.sections -%]
+ , "fb-[% section.id %]"
+ [%- FOREACH function_block = section.children -%]
+ , "fb-[% function_block.id -%]"
+ [%- END -%]
+[%- END -%]
+ ]
+ },
+ "json_data": {
+ "data": tree_data
+ },
+ "crrm": {
+ "move": {
+ "check_move": check_move,
+ "open_move": true
+ }
+ },
+ "themes": {
+ "theme": "requirement-spec"
+ },
+ "plugins": [ "themes", "json_data", "ui", "crrm", "dnd" ]
+ })
+ .bind("move_node.jstree", node_moved);
+
+ $(document).ajaxSend(function() {
+ $('#spinner').show();
+ }).ajaxStop(function() {
+ $('#spinner').hide();
+ });
+ });
+ -->
+</script>
[%- L.hidden_tag('requirement_spec_id', SELF.requirement_spec.id) -%]
-<div id="page" class="ym-grid ym-equalize">
- <div class="ym-g25 ym-gl" style="border-right: 1px solid black">
+<div id="column-container">
+ <div id="tree-column">
<div style="min-height: 32px; height: 32px;">
<div style="float: left">
[% L.button_tag("new_section_form()", LxERP.t8("New section"), id="new-section-button") %]
</div>
- <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>
<div style="clear: both"></div>
</div>
<div id="tree"></div>
</div>
- <div class="ym-gl">
- <div id="content-column">
- <p>There's beauty in the breakdown. 0</p>
- <p>There's beauty in the breakdown. 1</p>
- <p>There's beauty in the breakdown. 2</p>
- <p>There's beauty in the breakdown. 3</p>
- <p>There's beauty in the breakdown. 4</p>
- <p>There's beauty in the breakdown. 5</p>
- <p>There's beauty in the breakdown. 6</p>
- <p>There's beauty in the breakdown. 7</p>
- <p>There's beauty in the breakdown. 8</p>
- <p>There's beauty in the breakdown. 9</p>
- <p>There's beauty in the breakdown. 10</p>
- <p>There's beauty in the breakdown. 11</p>
- <p>There's beauty in the breakdown. 12</p>
- <p>There's beauty in the breakdown. 13</p>
- <p>There's beauty in the breakdown. 14</p>
- <p>There's beauty in the breakdown. 15</p>
- <p>There's beauty in the breakdown. 16</p>
- <p>There's beauty in the breakdown. 17</p>
- <p>There's beauty in the breakdown. 18</p>
- <p>There's beauty in the breakdown. 19</p>
- <p>There's beauty in the breakdown. 20</p>
- <p>There's beauty in the breakdown. 21</p>
- <p>There's beauty in the breakdown. 22</p>
- <!-- <p>There's beauty in the breakdown. 23</p> -->
- <!-- <p>There's beauty in the breakdown. 24</p> -->
- <!-- <p>There's beauty in the breakdown. 25</p> -->
- <!-- <p>There's beauty in the breakdown. 26</p> -->
- <!-- <p>There's beauty in the breakdown. 27</p> -->
- <!-- <p>There's beauty in the breakdown. 28</p> -->
- <!-- <p>There's beauty in the breakdown. 29</p> -->
- <!-- <p>There's beauty in the breakdown. 30</p> -->
- <!-- <p>There's beauty in the breakdown. 31</p> -->
- <!-- <p>There's beauty in the breakdown. 32</p> -->
- <!-- <p>There's beauty in the breakdown. 33</p> -->
- <!-- <p>There's beauty in the breakdown. 34</p> -->
- <!-- <p>There's beauty in the breakdown. 35</p> -->
- </div>
+ <div id="content-column" class="clearfix">
+ <p>There's beauty in the breakdown. 0</p>
+ <p>There's beauty in the breakdown. 1</p>
+ <p>There's beauty in the breakdown. 2</p>
+ <p>There's beauty in the breakdown. 3</p>
+ <p>There's beauty in the breakdown. 4</p>
+ <p>There's beauty in the breakdown. 5</p>
+ <p>There's beauty in the breakdown. 6</p>
+ <p>There's beauty in the breakdown. 7</p>
+ <p>There's beauty in the breakdown. 8</p>
+ <p>There's beauty in the breakdown. 9</p>
+ <p>There's beauty in the breakdown. 10</p>
+ <p>There's beauty in the breakdown. 11</p>
+ <p>There's beauty in the breakdown. 12</p>
+ <p>There's beauty in the breakdown. 13</p>
+ <p>There's beauty in the breakdown. 14</p>
+ <p>There's beauty in the breakdown. 15</p>
+ <p>There's beauty in the breakdown. 16</p>
+ <p>There's beauty in the breakdown. 17</p>
+ <p>There's beauty in the breakdown. 18</p>
+ <p>There's beauty in the breakdown. 19</p>
+ <p>There's beauty in the breakdown. 20</p>
+ <p>There's beauty in the breakdown. 21</p>
+ <p>There's beauty in the breakdown. 22</p>
+ <!-- <p>There's beauty in the breakdown. 23</p> -->
+ <!-- <p>There's beauty in the breakdown. 24</p> -->
+ <!-- <p>There's beauty in the breakdown. 25</p> -->
+ <!-- <p>There's beauty in the breakdown. 26</p> -->
+ <!-- <p>There's beauty in the breakdown. 27</p> -->
+ <!-- <p>There's beauty in the breakdown. 28</p> -->
+ <!-- <p>There's beauty in the breakdown. 29</p> -->
+ <!-- <p>There's beauty in the breakdown. 30</p> -->
+ <!-- <p>There's beauty in the breakdown. 31</p> -->
+ <!-- <p>There's beauty in the breakdown. 32</p> -->
+ <!-- <p>There's beauty in the breakdown. 33</p> -->
+ <!-- <p>There's beauty in the breakdown. 34</p> -->
+ <!-- <p>There's beauty in the breakdown. 35</p> -->
</div>
</div>
})
.bind("move_node.jstree", node_moved);
});
-
- $(document).ajaxSend(function() {
- $('#spinner').show();
- }).ajaxStop(function() {
- $('#spinner').hide();
- });
-->
</script>
[%- USE HTML %][%- USE L %][%- USE LxERP %]
-[%- SET id_base="section-form-" _ HTML.escape(id) %]
-[%- IF title %]
- <div class="listtop">[%- HTML.escape(title) %]</div>
-[%- END -%]
+[%- SET id_base="section-form" %]
+<div id="[% id_base %]">
+ <h1>[%- LxERP.t8("Edit section #1", SELF.item.fb_number) %]</h1>
-<form id="[% id_base %]">
- [% L.hidden_tag("requirment_spec_id", SELF.item.requirement_spec_id, id=(id_base _ "-requirement-spec-id")) %]
+ <form>
+ [% L.hidden_tag("requirement_spec_id", SELF.item.requirement_spec_id, id=(id_base _ "-requirement-spec-id")) %]
+ [% L.hidden_tag("id", SELF.item.id, id=(id_base _ "-requirement-spec-item-id")) %]
- <p>
- [%- LxERP.t8("Title") %]:<br>
- [% L.input_tag("title", SELF.item.title, id=(id_base _ "-title")) %]
- </p>
+ <p>
+ [%- LxERP.t8("Title") %]:<br>
+ [% L.input_tag("title", SELF.item.title, id=(id_base _ "-title")) %]
+ </p>
- <p>
- [%- LxERP.t8("Description") %]:<br>
- [% L.textarea_tag("description", SELF.item.description, id=(id_base _ "-title"), rows=8, cols=80) %]
- </p>
+ <p>
+ [%- LxERP.t8("Description") %]:<br>
+ [% L.textarea_tag("description", SELF.item.description, id=(id_base _ "-description"), rows=8, cols=80) %]
+ </p>
- <p>
- [% L.button_tag("submit_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Save")) %]
- [% L.button_tag("cancel_section_form('" _ HTML.escape(id) _ "')", LxERP.t8("Cancel")) %]
- </p>
-</form>
+ <p>
+ [% L.button_tag("submit_section_form()", LxERP.t8("Save")) %]
+ <a href="#" onclick="cancel_section_form()">[% LxERP.t8("Cancel") %]</a>
+ </p>
+ </form>
+</div>
--- /dev/null
+[%- USE HTML -%][%- USE L -%][%- USE LxERP -%]
+<h1>
+ [%- HTML.escape(requirement_spec_item.fb_number) %]: [% HTML.escape(requirement_spec_item.title) -%]
+</h1>
+
+[% IF requirement_spec_item.description %]
+ <div class="section-description">
+ [%- L.simple_format(requirement_spec_item.description) -%]
+ </div>
+[%- ELSE %]
+ <div class="section-empty-description">[%- LxERP.t8("No description has been entered yet.") %]</div>
+[%- END %]
--- /dev/null
+[%- USE HTML -%][%- USE LxERP -%][%- USE L -%]
+<div class="section-context-menu" id="section-header">
+ [%- INCLUDE 'requirement_spec_item/_section_header.html' %]
+</div>
+
+[%- L.hidden_tag('active_section_id', requirement_spec_item.id) -%]
+
+<ul id="section" class="section function-block-context-menu">
+ [%- FOREACH subitem = requirement_spec_item.children -%]
+ [%- INCLUDE 'requirement_spec_item/_single_subitem.html' requirement_spec_item=subitem -%]
+ [%- END -%]
+</ul>
+
+<div id="new_subitem_form" class="subitem-form clearfix">
+</div>
+<div id="new_subitem_link" class="highlight-box" style="[%- 'display:none' IF requirement_spec_item.children.size -%]">
+ [%#- link_to_remote LxERP.t8("FIXME no_function_blocks_have_been_created_for_this_section_yet) + " " + t(:create_a_function_block_now"),
+ :url => new_requirement_spec_requirement_spec_item_url(requirement_spec_item.requirement_spec,
+ :requirement_spec_item_id => requirement_spec_item.id),
+ :method => :get,
+ :update => "new_subitem_form",
+ :loading => "$('new_subitem_link').hide();" -%]
+</div>
+
+<script type="text/javascript">
+ <!--
+$(function(){
+ $.contextMenu({
+ selector: '.section-context-menu',
+ callback: function(key, options) {
+ var m = "clicked: " + key;
+ window.console && console.log(m) || alert(m);
+ },
+ items: {
+ edit: { name: "[% LxERP.t8('Edit section') %]", icon: "edit", callback: edit_section_header },
+ delete: { name: "[% LxERP.t8('Delete section') %]", icon: "delete" },
+ sep1: "---------",
+ copy: { name: "[% LxERP.t8('Copy') %]", icon: "copy" },
+ paste: { name: "[% LxERP.t8('Paste') %]", icon: "paste" }
+ }
+ });
+
+ $.contextMenu({
+ selector: '.function-block-context-menu',
+ callback: function(key, options) {
+ var m = "clicked: " + key;
+ window.console && console.log(m) || alert(m);
+ },
+ items: {
+ new_item: { name: "[% LxERP.t8('New function block') %]", icon: "add"},
+ new_sub_item: { name: "[% LxERP.t8('New sub function block') %]", icon: "add"},
+ sep1: "---------",
+ edit: { name: "[% LxERP.t8('Edit') %]", icon: "edit"},
+ delete: { name: "[% LxERP.t8('Delete') %]", icon: "delete"},
+ sep2: "---------",
+ copy: { name: "[% LxERP.t8('Copy') %]", icon: "copy" },
+ paste: { name: "[% LxERP.t8('Paste') %]", icon: "paste" }
+ }
+ });
+
+ $('.section-context-menu').on('click', function(e){
+ console.log('clicked', this);
+ });
+});
+
+function edit_section_header() {
+ $.post("controller.pl?action=RequirementSpecItem/edit_section&id=" + encodeURIComponent($('#active_section_id').val()), function(data) {
+ var header = $('#section-header');
+ header.data('old-elements', header.children().detach());
+ header.html(data);
+ });
+}
+
+function submit_section_form() {
+ $.post("controller.pl?action=RequirementSpecItem/update_section&id=" + $('#section-form form').serialize(), function(data) {
+ var header = $('#section-header');
+ header.removeData('old-elements');
+ header.html(data['header_html']);
+ $('#tree').jstree('rename_node', '#fb-' + data['id'], data['node_name']);
+ });
+}
+
+function cancel_section_form() {
+ var header = $('#section-header');
+ header.empty();
+ header.append(header.data('old-elements'));
+ header.removeData('old-elements');
+}
+-->
+</script>
--- /dev/null
+[%- USE HTML -%][%- USE LxERP -%][%- USE P -%]
+<li id="subitem_[%- requirement_spec_item.id -%]" class="subitem">
+
+ <div id="subitem_content_[%- requirement_spec_item.id -%]" class="subitem-content[%- IF requirement_spec_item.flagged -%] flagged[%- END -%]">
+
+ [%#- IF !@requirement_spec.project.nil? -%]
+ [%#- link_to image_tag("chronometer.png"), account_time_requirement_spec_requirement_spec_item_path(requirement_spec_item.requirement_spec, requirement_spec_item) -%]
+ [%#- END -%]
+ [%#- link_to_new_sub(requirement_spec_item.parent) -%]
+ [%#- link_to_remote image_tag("new_subsub.png"),
+ :url => new_requirement_spec_requirement_spec_item_url(requirement_spec_item.requirement_spec, :requirement_spec_item_id => requirement_spec_item.id),
+ :method => :get,
+ :condition => "check_for_editbox()",
+ :update => "new_subsubitem_form_#{requirement_spec_item.id}" -%]
+
+ <b>[%- HTML.escape(requirement_spec_item.fb_number) -%]</b>
+ [%- HTML.escape(requirement_spec_item.description) -%]
+
+ <div class="subsubitem-container" id="subsubitem_container_[%- requirement_spec_item.id -%]">
+ <div class="subsubitem-header" id="subsubitem_header_[%- requirement_spec_item.id -%]"[%- IF !requirement_spec_item.children.size -%] style="display: none"[%- END -%]>
+ [%- LxERP.t8("Sub function blocks") -%]
+ </div>
+ [%- IF requirement_spec_item.children.size -%]
+ [%- FOREACH subsubitem = requirement_spec_item.children -%]
+ [%#- render :partial => "requirement_spec_items/single_subsubitem", :locals => {:requirement_spec_item => subsubitem} -%]
+ [%- END -%]
+ [%- END -%]
+ </div>
+
+ <div id="new_subsubitem_form_[%- requirement_spec_item.id -%]" class="subsubitem_form"></div>
+
+ <div class="smaller" style="text-align:right">
+ [%- IF requirement_spec_item.dependencies.size -%]
+ <span class="gray">
+ [%- LxERP.t8("Dependencies") -%]: [%- P.requirement_spec_item_dependency_list(requirement_spec_item.dependencies) -%]
+ </span><br>
+ [%- END -%]
+ <span class="gray">
+ [%- LxERP.t8("Complexity") -%]: [%- requirement_spec_item.requirement_spec_complexity.description IF requirement_spec_item.requirement_spec_complexity -%]
+ |
+ [%- LxERP.t8("Risk") -%]: [%- requirement_spec_item.requirement_spec_risk.description IF requirement_spec_item.requirement_spec_risk -%]
+ |
+ [%- LxERP.t8("Effort") -%]: [%#- render :partial => 'requirement_spec_items/time_estimation_item', :locals => { :item => requirement_spec_item } -%]
+ </span>
+
+ </div>
+ </div>
+</li>