diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rwxr-xr-x | bin/browser-tests | 7 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin/Bodies.pm | 9 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report/New.pm | 8 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/BathNES.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Borsetshire.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Buckinghamshire.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Default.pm | 24 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/FixMyStreet.pm | 2 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Lincolnshire.pm | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/Cobrand/Northamptonshire.pm | 2 | ||||
-rw-r--r-- | perllib/Open311/PopulateServiceList.pm | 31 | ||||
-rw-r--r-- | t/app/controller/admin/bodies.t | 43 | ||||
-rw-r--r-- | t/app/controller/report_new.t | 8 | ||||
-rw-r--r-- | t/open311/populate-service-list.t | 165 | ||||
-rw-r--r-- | templates/web/base/admin/bodies/contact-form.html | 14 | ||||
-rw-r--r-- | web/cobrands/fixmystreet/admin.js | 10 |
17 files changed, 284 insertions, 48 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index a8bda116e..7ffa67eb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Mobile users can now filter the pins on the `/around` map view. #2366 - Admin improvements: - Add new roles system, to group permissions and apply to users. + - New features: + - Categories can be listed under more than one group #2475 - Bugfixes: - Prevent creation of two templates with same title. - Fix bug going between report/new pages client side diff --git a/bin/browser-tests b/bin/browser-tests index 99af08ee1..b5241490e 100755 --- a/bin/browser-tests +++ b/bin/browser-tests @@ -88,6 +88,9 @@ sub run { ALLOWED_COBRANDS => $cobrand, MAPIT_URL => $mapit_url, BASE_URL => 'http://fixmystreet.localhost:3001', + COBRAND_FEATURES => { + category_groups => { map { $_ => 1 } @$cobrand }, + } }); $ENV{FMS_OVERRIDE_CONFIG} = $config_out; @@ -112,10 +115,8 @@ sub run { kill 'TERM', $pid if $pid; exit $exit >> 8; } else { - require Test::MockModule; - my $c = Test::MockModule->new('FixMyStreet::Cobrand::FixMyStreet'); - $c->mock('enable_category_groups', sub { 1 }); # Child, run the server on port 3001 + require FixMyStreet; FixMyStreet->test_mode(1); # So email doesn't try to send local $ENV{FIXMYSTREET_APP_DEBUG} = 0; require Plack::Runner; diff --git a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm index 0e47d2238..2ff69b3b5 100644 --- a/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm +++ b/perllib/FixMyStreet/App/Controller/Admin/Bodies.pm @@ -273,8 +273,13 @@ sub update_contacts : Private { if ( $c->get_param('reputation_threshold') ) { $contact->set_extra_metadata( reputation_threshold => int($c->get_param('reputation_threshold')) ); } - if ( my $group = $c->get_param('group') ) { - $contact->set_extra_metadata( group => $group ); + if ( my @group = $c->get_param_list('group') ) { + @group = grep { $_ } @group; + if (scalar @group == 0) { + $contact->unset_extra_metadata( 'group' ); + } else { + $contact->set_extra_metadata( group => \@group ); + } } else { $contact->unset_extra_metadata( 'group' ); } diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 6a6040865..7c7ebd202 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -741,11 +741,13 @@ sub setup_categories_and_bodies : Private { $c->stash->{missing_details_bodies} = \@missing_details_bodies; $c->stash->{missing_details_body_names} = \@missing_details_body_names; - if ( $c->cobrand->call_hook('enable_category_groups') ) { + if ( $c->cobrand->enable_category_groups ) { my %category_groups = (); for my $category (@category_options) { - my $group = $category->{group} // $category->get_extra_metadata('group') // ''; - push @{$category_groups{$group}}, $category; + my $group = $category->{group} // $category->get_extra_metadata('group') // ['']; + # this could be an array ref or a string + my @groups = ref $group eq 'ARRAY' ? @$group : ($group); + push( @{$category_groups{$_}}, $category ) for @groups; } my @category_groups = (); diff --git a/perllib/FixMyStreet/Cobrand/BathNES.pm b/perllib/FixMyStreet/Cobrand/BathNES.pm index d726c671e..ea9b26e7a 100644 --- a/perllib/FixMyStreet/Cobrand/BathNES.pm +++ b/perllib/FixMyStreet/Cobrand/BathNES.pm @@ -74,8 +74,6 @@ sub pin_colour { sub send_questionnaires { 0 } -sub enable_category_groups { 1 } - sub default_map_zoom { 3 } sub map_js_extra { diff --git a/perllib/FixMyStreet/Cobrand/Borsetshire.pm b/perllib/FixMyStreet/Cobrand/Borsetshire.pm index a99d2e7b4..f8650169d 100644 --- a/perllib/FixMyStreet/Cobrand/Borsetshire.pm +++ b/perllib/FixMyStreet/Cobrand/Borsetshire.pm @@ -27,6 +27,4 @@ sub send_questionnaires { sub bypass_password_checks { 1 } -sub enable_category_groups { 1 } - 1; diff --git a/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm b/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm index 486e9603d..4c1d0108b 100644 --- a/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm +++ b/perllib/FixMyStreet/Cobrand/Buckinghamshire.pm @@ -185,8 +185,6 @@ sub map_type { 'Buckinghamshire' } sub default_map_zoom { 3 } -sub enable_category_groups { 1 } - sub _dashboard_export_add_columns { my $self = shift; my $c = $self->{c}; diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index cc7f03adb..eaf27e3bc 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -1085,6 +1085,30 @@ sub show_unconfirmed_reports { 0; } +=item enable_category_groups + +Whether body category groups should be displayed on the new report form. If this is +not enabled then any groups will be ignored and a flat list of categories displayed. + +=cut + +sub enable_category_groups { + my $self = shift; + return $self->feature('category_groups'); +} + +=item enable_multiple_category_groups + +Whether a category can be included in multiple groups. Required enable_category_groups +to alse be true. + +=cut + +sub enable_multiple_category_groups { + my $self = shift; + return $self->enable_category_groups && $self->feature('multiple_category_groups'); +} + sub default_problem_state { 'unconfirmed' } sub state_groups_admin { diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm index e01f3e23b..7c51eddd1 100644 --- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm +++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm @@ -10,8 +10,6 @@ use constant COUNCIL_ID_BROMLEY => 2482; sub on_map_default_status { return 'open'; } -sub enable_category_groups { 1 } - # Special extra sub path_to_web_templates { my $self = shift; diff --git a/perllib/FixMyStreet/Cobrand/Lincolnshire.pm b/perllib/FixMyStreet/Cobrand/Lincolnshire.pm index 3b731b273..ca88f6b8e 100644 --- a/perllib/FixMyStreet/Cobrand/Lincolnshire.pm +++ b/perllib/FixMyStreet/Cobrand/Lincolnshire.pm @@ -18,7 +18,6 @@ sub council_name { return 'Lincolnshire County Council'; } sub council_url { return 'lincolnshire'; } sub is_two_tier { 1 } -sub enable_category_groups { 1 } sub send_questionnaires { 0 } sub report_sent_confirmation_email { 'external_id' } diff --git a/perllib/FixMyStreet/Cobrand/Northamptonshire.pm b/perllib/FixMyStreet/Cobrand/Northamptonshire.pm index 3d5d4b6f2..21a145326 100644 --- a/perllib/FixMyStreet/Cobrand/Northamptonshire.pm +++ b/perllib/FixMyStreet/Cobrand/Northamptonshire.pm @@ -47,8 +47,6 @@ sub privacy_policy_url { 'https://www3.northamptonshire.gov.uk/councilservices/council-and-democracy/transparency/information-policies/privacy-notice/place/Pages/street-doctor.aspx' } -sub enable_category_groups { 1 } - sub is_two_tier { 1 } sub get_geocoder { 'OSM' } diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm index 2da67e9cd..5f7ca10a3 100644 --- a/perllib/Open311/PopulateServiceList.pm +++ b/perllib/Open311/PopulateServiceList.pm @@ -2,6 +2,7 @@ package Open311::PopulateServiceList; use Moo; use Open311; +use Text::CSV; has bodies => ( is => 'ro' ); has found_contacts => ( is => 'rw', default => sub { [] } ); @@ -262,11 +263,22 @@ sub _normalize_service_name { sub _set_contact_group { my ($self, $contact) = @_; - my $groups_enabled = $self->_current_body_cobrand && $self->_current_body_cobrand->call_hook('enable_category_groups'); + my $groups_enabled = $self->_current_body_cobrand && $self->_current_body_cobrand->enable_category_groups; + my $multi_groups_enabled = $self->_current_body_cobrand && $self->_current_body_cobrand->enable_multiple_category_groups; my $old_group = $contact->get_extra_metadata('group') || ''; my $new_group = $groups_enabled ? $self->_current_service->{group} || '' : ''; - if ($old_group ne $new_group) { + if ($multi_groups_enabled && $new_group =~ /,/) { + my $csv = Text::CSV->new; + if ( $csv->parse($new_group) ) { + $new_group = [ $csv->fields ]; + } else { + warn "error parsing groups for " . $self->_current_body_cobrand->moniker . "contact " . $contact->category . ": $new_group\n"; + $new_group = [ $new_group ]; + } + } + + if ($self->_groups_different($old_group, $new_group)) { if ($new_group) { $contact->set_extra_metadata(group => $new_group); $contact->update({ @@ -300,6 +312,21 @@ sub _set_contact_non_public { }) if $keywords{private}; } +sub _groups_different { + my ($self, $old, $new) = @_; + + my $diff = 1; + if ($old && $new) { + $old = [ $old ] unless ref $old eq 'ARRAY'; + $new = [ $new ] unless ref $new eq 'ARRAY'; + $diff = join( ',', sort(@$old) ) ne join( ',', sort(@$new) ); + } elsif (!$old && !$new) { + $diff = 0; + } + + return $diff; +} + sub _delete_contacts_not_in_service_list { my $self = shift; diff --git a/t/app/controller/admin/bodies.t b/t/app/controller/admin/bodies.t index f67e45bf6..db53b7cda 100644 --- a/t/app/controller/admin/bodies.t +++ b/t/app/controller/admin/bodies.t @@ -1,10 +1,3 @@ -package FixMyStreet::Cobrand::Tester; - -use parent 'FixMyStreet::Cobrand::Default'; - -sub enable_category_groups { 1 } - -package main; use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; @@ -210,10 +203,12 @@ subtest 'check text output' => sub { }; # END of override wrap FixMyStreet::override_config { - ALLOWED_COBRANDS => ['tester'], MAPIT_URL => 'http://mapit.uk/', MAPIT_TYPES => [ 'UTA' ], BASE_URL => 'http://www.example.org', + COBRAND_FEATURES => { + category_groups => { default => 1 }, + } }, sub { subtest 'group editing works' => sub { $mech->get_ok('/admin/body/' . $body->id); @@ -229,7 +224,7 @@ FixMyStreet::override_config { } } ); my $contact = $body->contacts->find({ category => 'grouped category' }); - is $contact->get_extra_metadata('group'), 'group a', "group stored correctly"; + is_deeply $contact->get_extra_metadata('group'), ['group a'], "group stored correctly"; }; subtest 'group can be unset' => sub { @@ -251,5 +246,35 @@ FixMyStreet::override_config { }; +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + MAPIT_TYPES => [ 'UTA' ], + BASE_URL => 'http://www.example.org', + COBRAND_FEATURES => { + category_groups => { default => 1 }, + multiple_category_groups => { default => 1 }, + } +}, sub { + subtest 'multi group editing works' => sub { + $mech->get_ok('/admin/body/' . $body->id); + $mech->content_contains( 'group</strong> is used for the top-level category' ); + + # have to do this as a post as adding a second group requires + # javascript + $mech->post_ok( '/admin/body/' . $body->id, { + posted => 'new', + token => $mech->form_id('category_edit')->value('token'), + category => 'grouped category', + email => 'test@example.com', + note => 'test note', + 'group' => [ 'group a', 'group b'], + non_public => undef, + state => 'unconfirmed', + } ); + + my $contact = $body->contacts->find({ category => 'grouped category' }); + is_deeply $contact->get_extra_metadata('group'), ['group a', 'group b'], "group stored correctly"; + }; +}; done_testing(); diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t index 848529686..f65ca243d 100644 --- a/t/app/controller/report_new.t +++ b/t/app/controller/report_new.t @@ -1271,16 +1271,18 @@ subtest "Test inactive categories" => sub { }; subtest "category groups" => sub { - my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::FixMyStreet'); - $cobrand->mock('enable_category_groups', sub { 1 }); FixMyStreet::override_config { ALLOWED_COBRANDS => 'fixmystreet', MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + category_groups => { fixmystreet => 1 } + } }, sub { - $contact2->update( { extra => { group => 'Roads' } } ); + $contact2->update( { extra => { group => ['Roads','Pavements'] } } ); $contact9->update( { extra => { group => 'Roads' } } ); $contact10->update( { extra => { group => 'Roads' } } ); $mech->get_ok("/report/new?lat=$saved_lat&lon=$saved_lon"); + $mech->content_like(qr{<optgroup label="Pavements">\s*<option value='Potholes'>Potholes</option></optgroup>}); $mech->content_like(qr{<optgroup label="Roads">\s*<option value='Potholes'>Potholes</option>\s*<option value='Street lighting'>Street lighting</option></optgroup>}); }; }; diff --git a/t/open311/populate-service-list.t b/t/open311/populate-service-list.t index c67fae9bd..9f8b4d9f0 100644 --- a/t/open311/populate-service-list.t +++ b/t/open311/populate-service-list.t @@ -5,20 +5,11 @@ use parent 'FixMyStreet::Cobrand::Default'; sub council_area_id { 1 } - -package FixMyStreet::Cobrand::TesterGroups; - -use parent 'FixMyStreet::Cobrand::Default'; - -sub council_area_id { 1 } - -sub enable_category_groups { 1 } - - package main; use FixMyStreet::Test; use FixMyStreet::DB; +use Test::Warn; use utf8; use_ok( 'Open311::PopulateServiceList' ); @@ -51,13 +42,16 @@ $bucks->body_areas->create({ }); for my $test ( - { desc => 'groups not set for new contacts', cobrand => 'tester', groups => 0, delete => 1 }, - { desc => 'groups set for new contacts', cobrand => 'testergroups', groups => 1, delete => 1}, - { desc => 'groups removed for existing contacts', cobrand => 'tester', groups => 0, delete => 0 }, - { desc => 'groups added for existing contacts', cobrand => 'testergroups', groups => 1, delete => 0}, + { desc => 'groups not set for new contacts', enable_groups => 0, groups => 0, delete => 1 }, + { desc => 'groups set for new contacts', enable_groups => 1, groups => 1, delete => 1}, + { desc => 'groups removed for existing contacts', enable_groups => 0, groups => 0, delete => 0 }, + { desc => 'groups added for existing contacts', enable_groups => 1, groups => 1, delete => 0}, ) { FixMyStreet::override_config { - ALLOWED_COBRANDS => [ $test->{cobrand} ], + ALLOWED_COBRANDS => [ 'tester' ], + COBRAND_FEATURES => { + category_groups => { tester => $test->{enable_groups} }, + } }, sub { subtest 'check basic functionality, ' . $test->{desc} => sub { FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete() if $test->{delete}; @@ -83,6 +77,147 @@ for my $test ( }; } +my $last_update = {}; +for my $test ( + { desc => 'set multiple groups for contact', enable_multi => 1, groups => ['sanitation', 'street'] }, + { desc => 'groups not edited if unchanged', enable_multi => 1, groups => ['sanitation', 'street'], unchanged => 1 }, + { desc => 'multiple groups has to be configured', enable_multi => 0, groups => 'sanitation,street'}, +) { + subtest $test->{desc} => sub { + FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete(); + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords>lorem, ipsum, dolor</keywords> + <group>sanitation,street</group> + </service> + <service> + <service_code>002</service_code> + <metadata>false</metadata> + <type>realtime</type> + <keywords>lorem, ipsum, dolor</keywords> + <group>street</group> + <service_name>Construction plate shifted</service_name> + <description>Metal construction plate covering the street or sidewalk has been moved.</description> + </service> + </services> + '; + + my $service_list = get_xml_simple_object($services_xml); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'tester' ], + COBRAND_FEATURES => { + category_groups => { tester => 1 }, + multiple_category_groups => { tester => $test->{enable_multi} }, + } + }, sub { + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + $processor->process_services( $service_list ); + }; + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 2, 'correct number of contacts'; + + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id, email => 100 } )->first; + is_deeply $contact->get_extra->{group}, $test->{groups}, "Multi groups set correctly"; + if ($test->{unchanged}) { + is $contact->whenedited, $last_update->{100}, "contact unchanged"; + } + $last_update->{100} = $contact->whenedited; + + $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id, email => '002'} )->first; + is $contact->get_extra->{group}, 'street', "Single groups set correctly"; + if ($test->{unchanged}) { + is $contact->whenedited, $last_update->{002}, "contact unchanged"; + } + $last_update->{002} = $contact->whenedited; + }; +} + +subtest "set multiple groups with quoted csv" => sub { + FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete(); + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords>lorem, ipsum, dolor</keywords> + <group>"sanitation & cleaning",street</group> + </service> + </services> + '; + + my $service_list = get_xml_simple_object($services_xml); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'tester' ], + COBRAND_FEATURES => { + category_groups => { tester => 1 }, + multiple_category_groups => { tester => 1 }, + } + }, sub { + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + $processor->process_services( $service_list ); + }; + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 1, 'correct number of contacts'; + + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id, email => 100 } )->first; + is_deeply $contact->get_extra->{group}, ['sanitation & cleaning','street'], "groups set correctly"; +}; + +subtest "set multiple groups with bad csv" => sub { + FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete(); + + my $services_xml = '<?xml version="1.0" encoding="utf-8"?> + <services> + <service> + <service_code>100</service_code> + <service_name>Cans left out 24x7</service_name> + <description>Garbage or recycling cans that have been left out for more than 24 hours after collection. Violators will be cited.</description> + <metadata>false</metadata> + <type>realtime</type> + <keywords>lorem, ipsum, dolor</keywords> + <group>"sanitation,street</group> + </service> + </services> + '; + + my $service_list = get_xml_simple_object($services_xml); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'tester' ], + COBRAND_FEATURES => { + category_groups => { tester => 1 }, + multiple_category_groups => { tester => 1 }, + } + }, sub { + my $processor = Open311::PopulateServiceList->new(); + $processor->_current_body( $body ); + warning_like { + $processor->process_services( $service_list ); + } qr/error parsing groups for testercontact Cans left out 24x7: "sanitation,street/, + "warning printed for bad csv"; + }; + my $contact_count = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->count(); + is $contact_count, 1, 'correct number of contacts'; + + my $contact = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id, email => 100 } )->first; + is_deeply $contact->get_extra->{group}, ['"sanitation,street'], "groups set correctly"; +}; + subtest 'check non open311 contacts marked as deleted' => sub { FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } )->delete(); diff --git a/templates/web/base/admin/bodies/contact-form.html b/templates/web/base/admin/bodies/contact-form.html index c55c5c036..efc576b24 100644 --- a/templates/web/base/admin/bodies/contact-form.html +++ b/templates/web/base/admin/bodies/contact-form.html @@ -132,7 +132,21 @@ as well.") %] <p> <label> [% loc('Group') %] + [% IF body.get_cobrand_handler.enable_multiple_category_groups %] + [% IF contact.extra.group %] + [% FOR group IN contact.extra.group %] + <input class="form-control" type="text" name="group" value="[% group | html %]" size="30"> + [% END %] + [% ELSE %] + <input class="form-control" type="text" name="group" value="" size="30"> + [% END %] + <input class="hidden-js js-group-item-template form-control" type="text" name="group" value="" size="30"> + <p class="hidden-nojs"> + <button class="btn btn--small js-group-item-add">[% loc('Add group') %]</button> + </p> + [% ELSE %] <input class="form-control" type="text" name="group" value="[% contact.extra.group | html %]" size="30"> + [% END %] </label> </p> [% END %] diff --git a/web/cobrands/fixmystreet/admin.js b/web/cobrands/fixmystreet/admin.js index 8bc956c57..25c7651eb 100644 --- a/web/cobrands/fixmystreet/admin.js +++ b/web/cobrands/fixmystreet/admin.js @@ -165,6 +165,16 @@ $(function(){ return true; }); + $(".js-group-item-add").on("click", function(e) { + e.preventDefault(); + var $template_item = $(".js-group-item-template"); + var $new_item = $template_item.clone(); + $new_item.removeClass("hidden-js js-group-item-template"); + $new_item.insertBefore($template_item); + $new_item.focus(); + return true; + }); + // Fields can be added/removed $(".js-metadata-item-add").on("click", function(e) { e.preventDefault(); |