Revision d41efcfe
Von Sven Schöling vor etwa 9 Jahren hinzugefügt
SL/Controller/RequirementSpec.pm | ||
---|---|---|
7 | 7 |
|
8 | 8 |
use File::Spec (); |
9 | 9 |
|
10 |
use SL::ClientJS; |
|
11 | 10 |
use SL::Common (); |
12 | 11 |
use SL::Controller::Helper::GetModels; |
13 | 12 |
use SL::Controller::Helper::ReportGenerator; |
... | ... | |
29 | 28 |
use Rose::Object::MakeMethods::Generic |
30 | 29 |
( |
31 | 30 |
scalar => [ qw(requirement_spec_item visible_item visible_section) ], |
32 |
'scalar --get_set_init' => [ qw(requirement_spec customers types statuses complexities risks projects project_types project_statuses default_project_type default_project_status copy_source js
|
|
31 |
'scalar --get_set_init' => [ qw(requirement_spec customers types statuses complexities risks projects project_types project_statuses default_project_type default_project_status copy_source |
|
33 | 32 |
current_text_block_output_position models time_based_units html_template cvar_configs includeable_cvar_configs include_cvars) ], |
34 | 33 |
); |
35 | 34 |
|
... | ... | |
84 | 83 |
$self->js |
85 | 84 |
->hide('#basic_settings') |
86 | 85 |
->after('#basic_settings', $html) |
87 |
->render($self);
|
|
86 |
->render; |
|
88 | 87 |
} |
89 | 88 |
|
90 | 89 |
sub action_ajax_edit_project_link { |
... | ... | |
95 | 94 |
$self->js |
96 | 95 |
->hide('#basic_settings') |
97 | 96 |
->after('#basic_settings', $html) |
98 |
->render($self);
|
|
97 |
->render; |
|
99 | 98 |
} |
100 | 99 |
|
101 | 100 |
sub action_ajax_show_time_and_cost_estimate { |
... | ... | |
116 | 115 |
->after('#time_cost_estimate', $html) |
117 | 116 |
->on('#time_cost_estimate INPUT[type=text]', 'keydown', 'kivi.requirement_spec.time_cost_estimate_input_key_down') |
118 | 117 |
->action_if($first && $first->id, 'focus', '#time_and_cost_estimate_form_complexity_id_' . $first->id) |
119 |
->render($self);
|
|
118 |
->render; |
|
120 | 119 |
} |
121 | 120 |
|
122 | 121 |
sub action_ajax_save_time_and_cost_estimate { |
... | ... | |
140 | 139 |
my $html = $self->render('requirement_spec/_show_time_and_cost_estimate', { output => 0 }, initially_hidden => !!$::form->{keep_open}); |
141 | 140 |
$self->js->replaceWith('#time_cost_estimate', $html); |
142 | 141 |
|
143 |
return $self->js->render($self) if $::form->{keep_open};
|
|
142 |
return $self->js->render if $::form->{keep_open}; |
|
144 | 143 |
|
145 | 144 |
$self->js->remove('#time_cost_estimate_form_container'); |
146 | 145 |
|
... | ... | |
149 | 148 |
$self->js->html('#column-content', $html); |
150 | 149 |
} |
151 | 150 |
|
152 |
$self->js->render($self);
|
|
151 |
$self->js->render; |
|
153 | 152 |
} |
154 | 153 |
|
155 | 154 |
sub action_show { |
... | ... | |
200 | 199 |
sub action_revert_to { |
201 | 200 |
my ($self, %params) = @_; |
202 | 201 |
|
203 |
return $self->js->error(t8('Cannot revert a versioned copy.'))->render($self) if $self->requirement_spec->working_copy_id;
|
|
202 |
return $self->js->error(t8('Cannot revert a versioned copy.'))->render if $self->requirement_spec->working_copy_id; |
|
204 | 203 |
|
205 | 204 |
my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load; |
206 | 205 |
|
... | ... | |
209 | 208 |
$version->update_attributes(working_copy_id => $self->requirement_spec->id); |
210 | 209 |
|
211 | 210 |
flash_later('info', t8('The requirement spec has been reverted to version #1.', $versioned_copy->version->version_number)); |
212 |
$self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render($self);
|
|
211 |
$self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render; |
|
213 | 212 |
} |
214 | 213 |
|
215 | 214 |
sub action_create_pdf { |
... | ... | |
269 | 268 |
my $template = SL::DB::RequirementSpec->new(id => $::form->{template_id})->load; |
270 | 269 |
my %result = $self->requirement_spec->paste_template($template); |
271 | 270 |
|
272 |
return $self->js->error($self->requirement_spec->error)->render($self) if !%result;
|
|
271 |
return $self->js->error($self->requirement_spec->error)->render if !%result; |
|
273 | 272 |
|
274 | 273 |
$self->render_pasted_text_block($_) for sort { $a->position <=> $b->position } @{ $result{text_blocks} }; |
275 | 274 |
$self->render_pasted_section($_) for sort { $a->position <=> $b->position } @{ $result{sections} }; |
... | ... | |
284 | 283 |
->show( '#additional_parts_list_container') |
285 | 284 |
->remove( '#additional_parts_form_container'); |
286 | 285 |
|
287 |
$self->invalidate_version->render($self);
|
|
286 |
$self->invalidate_version->render; |
|
288 | 287 |
} |
289 | 288 |
|
290 | 289 |
sub action_renumber_sections { |
... | ... | |
329 | 328 |
return 1; |
330 | 329 |
} |
331 | 330 |
|
332 |
sub init_js { SL::ClientJS->new } |
|
333 | 331 |
sub init_complexities { SL::DB::Manager::RequirementSpecComplexity->get_all_sorted } |
334 | 332 |
sub init_default_project_status { SL::DB::Manager::ProjectStatus->find_by(name => 'planning') } |
335 | 333 |
sub init_default_project_type { SL::DB::ProjectType->new(id => 1)->load } |
... | ... | |
411 | 409 |
my @errors = $self->requirement_spec->validate; |
412 | 410 |
|
413 | 411 |
if (@errors) { |
414 |
return $self->js->error(@errors)->render($self) if $::request->is_ajax;
|
|
412 |
return $self->js->error(@errors)->render if $::request->is_ajax; |
|
415 | 413 |
|
416 | 414 |
flash('error', @errors); |
417 | 415 |
$self->render('requirement_spec/new', title => $title); |
... | ... | |
428 | 426 |
})) { |
429 | 427 |
$::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error); |
430 | 428 |
@errors = ($::locale->text('Saving failed. Error message from the database: #1', $db->error)); |
431 |
return $self->js->error(@errors)->render($self) if $::request->is_ajax;
|
|
429 |
return $self->js->error(@errors)->render if $::request->is_ajax; |
|
432 | 430 |
|
433 | 431 |
$self->requirement_spec->id(undef) if $is_new; |
434 | 432 |
flash('error', @errors); |
... | ... | |
445 | 443 |
->replaceWith('#basic_settings', $basics_html) |
446 | 444 |
->remove('#basic_settings_form') |
447 | 445 |
->flash('info', $info) |
448 |
->render($self);
|
|
446 |
->render; |
|
449 | 447 |
} |
450 | 448 |
|
451 | 449 |
flash_later('info', $info); |
... | ... | |
612 | 610 |
->replaceWith('#basic_settings', $self->render('requirement_spec/_show_basic_settings', { output => 0 })) |
613 | 611 |
->remove('#project_link_form') |
614 | 612 |
->flash('info', t8('The project link has been updated.')) |
615 |
->render($self);
|
|
613 |
->render; |
|
616 | 614 |
} |
617 | 615 |
|
618 | 616 |
sub update_project_link_new { |
... | ... | |
620 | 618 |
|
621 | 619 |
return $self->js |
622 | 620 |
->replaceWith('#project_link_form', $self->render('requirement_spec/_new_project_form', { output => 0 })) |
623 |
->render($self);
|
|
621 |
->render; |
|
624 | 622 |
} |
625 | 623 |
|
626 | 624 |
sub update_project_link_create { |
... | ... | |
634 | 632 |
|
635 | 633 |
my @errors = $project->validate; |
636 | 634 |
|
637 |
return $self->js->error(@errors)->render($self) if @errors;
|
|
635 |
return $self->js->error(@errors)->render if @errors; |
|
638 | 636 |
|
639 | 637 |
my $db = $self->requirement_spec->db; |
640 | 638 |
if (!$db->do_transaction(sub { |
... | ... | |
643 | 641 |
|
644 | 642 |
})) { |
645 | 643 |
$::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error); |
646 |
return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render($self);
|
|
644 |
return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render; |
|
647 | 645 |
} |
648 | 646 |
|
649 | 647 |
return $self->invalidate_version |
... | ... | |
651 | 649 |
->remove('#project_link_form') |
652 | 650 |
->flash('info', t8('The project has been created.')) |
653 | 651 |
->flash('info', t8('The project link has been updated.')) |
654 |
->render($self);
|
|
652 |
->render; |
|
655 | 653 |
} |
656 | 654 |
|
657 | 655 |
sub init_models { |
SL/Controller/RequirementSpecItem.pm | ||
---|---|---|
23 | 23 |
use Rose::Object::MakeMethods::Generic |
24 | 24 |
( |
25 | 25 |
scalar => [ qw(item visible_item visible_section clicked_item sections) ], |
26 |
'scalar --get_set_init' => [ qw(complexities risks js predefined_texts) ],
|
|
26 |
'scalar --get_set_init' => [ qw(complexities risks predefined_texts) ], |
|
27 | 27 |
); |
28 | 28 |
|
29 | 29 |
__PACKAGE__->run_before('check_auth'); |
... | ... | |
39 | 39 |
|
40 | 40 |
if (!$::form->{clicked_id}) { |
41 | 41 |
# Clicked on "sections" in the tree. Do nothing. |
42 |
return $self->render($self->js);
|
|
42 |
return $self->render; |
|
43 | 43 |
} |
44 | 44 |
|
45 | 45 |
my $clicked_item = SL::DB::RequirementSpecItem->new(id => $::form->{clicked_id})->load; |
... | ... | |
98 | 98 |
my $new_section = $self->item->section; |
99 | 99 |
my $new_visible_section = SL::DB::RequirementSpecItem->new(id => $self->visible_item->id)->load->section; |
100 | 100 |
|
101 |
return $self->invalidate_version->render($self) if !$old_visible_section || ($new_type eq 'section');
|
|
101 |
return $self->invalidate_version->render if !$old_visible_section || ($new_type eq 'section'); |
|
102 | 102 |
|
103 | 103 |
# From here on $old_visible_section is definitely set. |
104 | 104 |
|
... | ... | |
533 | 533 |
return SL::DB::Manager::RequirementSpecPredefinedText->get_all_sorted(where => [ useable_for_sections => 1 ]); |
534 | 534 |
} |
535 | 535 |
|
536 |
sub init_js { |
|
537 |
my ($self) = @_; |
|
538 |
$self->js(SL::ClientJS->new); |
|
539 |
} |
|
540 |
|
|
541 | 536 |
sub replace_bottom { |
542 | 537 |
my ($self, $item_or_id) = @_; |
543 | 538 |
|
... | ... | |
709 | 704 |
$self->js->show('#sub-function-block-container-' . $parent_id) if $new_type eq 'sub-function-block'; |
710 | 705 |
$self->add_new_item_form(insert_position => $insert_position, insert_reference => $insert_reference, display_reference => $display_reference); |
711 | 706 |
|
712 |
$self->js->render($self);
|
|
707 |
$self->js->render; |
|
713 | 708 |
} |
714 | 709 |
|
715 | 710 |
sub is_item_visible { |
SL/Controller/RequirementSpecOrder.pm | ||
---|---|---|
8 | 8 |
use List::MoreUtils qw(uniq); |
9 | 9 |
use List::Util qw(first); |
10 | 10 |
|
11 |
use SL::ClientJS; |
|
12 | 11 |
use SL::DB::Customer; |
13 | 12 |
use SL::DB::Order; |
14 | 13 |
use SL::DB::Part; |
... | ... | |
23 | 22 |
use Rose::Object::MakeMethods::Generic |
24 | 23 |
( |
25 | 24 |
scalar => [ qw(parts) ], |
26 |
'scalar --get_set_init' => [ qw(requirement_spec rs_order js h_unit_name all_customers all_parts_time_unit section_order_part) ],
|
|
25 |
'scalar --get_set_init' => [ qw(requirement_spec rs_order h_unit_name all_customers all_parts_time_unit section_order_part) ], |
|
27 | 26 |
); |
28 | 27 |
|
29 | 28 |
__PACKAGE__->run_before('setup'); |
... | ... | |
42 | 41 |
my ($self) = @_; |
43 | 42 |
|
44 | 43 |
if (!@{ $self->all_parts_time_unit }) { |
45 |
return $self->js->flash('error', t8('This function requires the presence of articles with a time-based unit such as "h" or "min".'))->render($self);
|
|
44 |
return $self->js->flash('error', t8('This function requires the presence of articles with a time-based unit such as "h" or "min".'))->render; |
|
46 | 45 |
} |
47 | 46 |
|
48 | 47 |
my $html = $self->render('requirement_spec_order/new', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); |
49 | 48 |
$self->js->hide(LIST_SELECTOR()) |
50 | 49 |
->after(LIST_SELECTOR(), $html) |
51 |
->render($self);
|
|
50 |
->render; |
|
52 | 51 |
} |
53 | 52 |
|
54 | 53 |
sub action_create { |
55 | 54 |
my ($self) = @_; |
56 | 55 |
|
57 | 56 |
if (!$::auth->assert($::form->{quotation} ? 'sales_quotation_edit' : 'sales_order_edit', 1)) { |
58 |
return $self->js->flash('error', t8("You do not have the permissions to access this function."))->render($self);
|
|
57 |
return $self->js->flash('error', t8("You do not have the permissions to access this function."))->render; |
|
59 | 58 |
} |
60 | 59 |
|
61 | 60 |
# 1. Update sections with selected part IDs. |
... | ... | |
85 | 84 |
$self->js->replaceWith(LIST_SELECTOR(), $html) |
86 | 85 |
->remove(FORMS_SELECTOR()) |
87 | 86 |
->flash('info', $::form->{quotation} ? t8('Sales quotation #1 has been created.', $order->quonumber) : t8('Sales order #1 has been created.', $order->ordnumber)) |
88 |
->render($self);
|
|
87 |
->render; |
|
89 | 88 |
} |
90 | 89 |
|
91 | 90 |
sub action_update { |
... | ... | |
95 | 94 |
my $sections = $self->requirement_spec->sections_sorted; |
96 | 95 |
|
97 | 96 |
if (!$::auth->assert($order->quotation ? 'sales_quotation_edit' : 'sales_order_edit', 1)) { |
98 |
return $self->js->flash('error', t8("You do not have the permissions to access this function."))->render($self);
|
|
97 |
return $self->js->flash('error', t8("You do not have the permissions to access this function."))->render; |
|
99 | 98 |
} |
100 | 99 |
|
101 | 100 |
my (@orderitems, %sections_seen); |
... | ... | |
116 | 115 |
|
117 | 116 |
$self->js->hide(LIST_SELECTOR()) |
118 | 117 |
->after(LIST_SELECTOR(), $html) |
119 |
->render($self);
|
|
118 |
->render; |
|
120 | 119 |
} |
121 | 120 |
|
122 | 121 |
sub action_do_update { |
... | ... | |
143 | 142 |
$self->js->replaceWith(LIST_SELECTOR(), $html) |
144 | 143 |
->remove(FORMS_SELECTOR()) |
145 | 144 |
->flash('info', $::form->{quotation} ? t8('Sales quotation #1 has been updated.', $order->quonumber) : t8('Sales order #1 has been updated.', $order->ordnumber)) |
146 |
->render($self);
|
|
145 |
->render; |
|
147 | 146 |
} |
148 | 147 |
|
149 | 148 |
sub action_edit_assignment { |
150 | 149 |
my ($self) = @_; |
151 | 150 |
|
152 | 151 |
if (!@{ $self->all_parts_time_unit }) { |
153 |
return $self->js->flash('error', t8('This function requires the presence of articles with a time-based unit such as "h" or "min".'))->render($self);
|
|
152 |
return $self->js->flash('error', t8('This function requires the presence of articles with a time-based unit such as "h" or "min".'))->render; |
|
154 | 153 |
} |
155 | 154 |
|
156 | 155 |
my $html = $self->render('requirement_spec_order/edit_assignment', { output => 0 }, make_part_title => sub { $_[0]->partnumber . ' ' . $_[0]->description }); |
157 | 156 |
$self->js->hide(LIST_SELECTOR()) |
158 | 157 |
->after(LIST_SELECTOR(), $html) |
159 | 158 |
->reinit_widgets |
160 |
->render($self);
|
|
159 |
->render; |
|
161 | 160 |
} |
162 | 161 |
|
163 | 162 |
sub action_save_assignment { |
... | ... | |
168 | 167 |
my $html = $self->render('requirement_spec_order/list', { output => 0 }); |
169 | 168 |
$self->js->replaceWith(LIST_SELECTOR(), $html) |
170 | 169 |
->remove(FORMS_SELECTOR()) |
171 |
->render($self);
|
|
170 |
->render; |
|
172 | 171 |
} |
173 | 172 |
|
174 | 173 |
sub action_delete { |
... | ... | |
182 | 181 |
my $html = $self->render('requirement_spec_order/list', { output => 0 }); |
183 | 182 |
$self->js->replaceWith(LIST_SELECTOR(), $html) |
184 | 183 |
->flash('info', $order->quotation ? t8('Sales quotation #1 has been deleted.', $order->quonumber) : t8('Sales order #1 has been deleted.', $order->ordnumber)) |
185 |
->render($self);
|
|
184 |
->render; |
|
186 | 185 |
} |
187 | 186 |
|
188 | 187 |
# |
... | ... | |
204 | 203 |
$self->requirement_spec(SL::DB::RequirementSpec->new(id => $::form->{requirement_spec_id})->load) if $::form->{requirement_spec_id}; |
205 | 204 |
} |
206 | 205 |
|
207 |
sub init_js { |
|
208 |
my ($self) = @_; |
|
209 |
$self->js(SL::ClientJS->new); |
|
210 |
} |
|
211 |
|
|
212 | 206 |
sub init_all_customers { SL::DB::Manager::Customer->get_all_sorted } |
213 | 207 |
sub init_h_unit_name { SL::DB::Manager::Unit->find_h_unit->name }; |
214 | 208 |
sub init_rs_order { SL::DB::RequirementSpecOrder->new(id => $::form->{rs_order_id})->load }; |
SL/Controller/RequirementSpecTextBlock.pm | ||
---|---|---|
8 | 8 |
use Params::Validate (); |
9 | 9 |
use Time::HiRes (); |
10 | 10 |
|
11 |
use SL::ClientJS; |
|
12 | 11 |
use SL::Clipboard; |
13 | 12 |
use SL::Controller::Helper::RequirementSpec; |
14 | 13 |
use SL::DB::RequirementSpec; |
... | ... | |
23 | 22 |
use Rose::Object::MakeMethods::Generic |
24 | 23 |
( |
25 | 24 |
scalar => [ qw(text_block) ], |
26 |
'scalar --get_set_init' => [ qw(predefined_texts js picture) ],
|
|
25 |
'scalar --get_set_init' => [ qw(predefined_texts picture) ], |
|
27 | 26 |
); |
28 | 27 |
|
29 | 28 |
__PACKAGE__->run_before('check_auth'); |
... | ... | |
66 | 65 |
|
67 | 66 |
$self->add_new_text_block_form(output_position => $new_where, insert_after_id => $::form->{id}, requirement_spec_id => $::form->{requirement_spec_id}); |
68 | 67 |
|
69 |
$self->invalidate_version->render($self);
|
|
68 |
$self->invalidate_version->render; |
|
70 | 69 |
} |
71 | 70 |
|
72 | 71 |
sub action_ajax_edit { |
... | ... | |
434 | 433 |
return SL::DB::RequirementSpecPicture->new(id => $::form->{picture_id} || $::form->{id})->load; |
435 | 434 |
} |
436 | 435 |
|
437 |
sub init_js { |
|
438 |
my ($self) = @_; |
|
439 |
$self->js(SL::ClientJS->new); |
|
440 |
} |
|
441 |
|
|
442 | 436 |
sub invalidate_version { |
443 | 437 |
my ($self) = @_; |
444 | 438 |
|
... | ... | |
495 | 489 |
$self->text_block->save; |
496 | 490 |
})) { |
497 | 491 |
$::lxdebug->message(LXDebug::WARN(), "Error: " . $self->text_block->db->error); |
498 |
return $self->js->error($::locale->text('Saving failed. Error message from the database: #1', $self->text_block->db->error))->render($self);
|
|
492 |
return $self->js->error($::locale->text('Saving failed. Error message from the database: #1', $self->text_block->db->error))->render; |
|
499 | 493 |
} |
500 | 494 |
|
501 | 495 |
my $html = $self->render('requirement_spec_text_block/_text_block_picture', { output => 0 }, picture => $self->picture); |
... | ... | |
503 | 497 |
$self->invalidate_version |
504 | 498 |
->append('#text-block-' . $self->text_block->id . '-pictures', $html) |
505 | 499 |
->show('#text-block-' . $self->text_block->id . '-pictures') |
506 |
->render($self);
|
|
500 |
->render; |
|
507 | 501 |
} |
508 | 502 |
|
509 | 503 |
1; |
SL/Controller/RequirementSpecVersion.pm | ||
---|---|---|
7 | 7 |
use Carp; |
8 | 8 |
use List::MoreUtils qw(any); |
9 | 9 |
|
10 |
use SL::ClientJS; |
|
11 | 10 |
use SL::DB::Customer; |
12 | 11 |
use SL::DB::Project; |
13 | 12 |
use SL::DB::RequirementSpec; |
... | ... | |
17 | 16 |
|
18 | 17 |
use Rose::Object::MakeMethods::Generic |
19 | 18 |
( |
20 |
'scalar --get_set_init' => [ qw(requirement_spec version js) ],
|
|
19 |
'scalar --get_set_init' => [ qw(requirement_spec version) ], |
|
21 | 20 |
); |
22 | 21 |
|
23 | 22 |
__PACKAGE__->run_before('check_auth'); |
... | ... | |
69 | 68 |
my %attributes = %{ delete($::form->{rs_version}) || {} }; |
70 | 69 |
my @errors = SL::DB::RequirementSpecVersion->new(%attributes, version_number => 1)->validate; |
71 | 70 |
|
72 |
return $self->js->error(@errors)->render($self) if @errors;
|
|
71 |
return $self->js->error(@errors)->render if @errors; |
|
73 | 72 |
|
74 | 73 |
my $db = $self->requirement_spec->db; |
75 | 74 |
my @result = $self->requirement_spec->create_version(%attributes); |
76 | 75 |
|
77 | 76 |
if (!@result) { |
78 | 77 |
$::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error); |
79 |
return $self->js->error($::locale->text('Saving failed. Error message from the database: #1'), $db->error)->render($self);
|
|
78 |
return $self->js->error($::locale->text('Saving failed. Error message from the database: #1'), $db->error)->render; |
|
80 | 79 |
} |
81 | 80 |
|
82 | 81 |
$self->version($result[0]); |
... | ... | |
87 | 86 |
->html('#requirement_spec_version', $version_info_html) |
88 | 87 |
->html('#versioned_copies_list', $version_list_html) |
89 | 88 |
->dialog->close('#jqueryui_popup_dialog') |
90 |
->render($self);
|
|
89 |
->render; |
|
91 | 90 |
} |
92 | 91 |
|
93 | 92 |
# |
... | ... | |
113 | 112 |
$self->version(SL::DB::RequirementSpecVersion->new(id => $::form->{id})->load) if $::form->{id}; |
114 | 113 |
} |
115 | 114 |
|
116 |
sub init_js { |
|
117 |
my ($self, %params) = @_; |
|
118 |
$self->js(SL::ClientJS->new); |
|
119 |
} |
|
120 |
|
|
121 | 115 |
sub has_item_changed { |
122 | 116 |
my ($previous, $current) = @_; |
123 | 117 |
croak "Missing previous/current" if !$previous || !$current; |
Auch abrufbar als: Unified diff
RequirementSpecs: js accessor angepasst