From 287e0b5b55598a3bb0431ce5c768b67c9275c217 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Fri, 9 Dec 2016 15:15:42 +0000 Subject: [PATCH 1/6] Enterprise switcher and navigation check --- .../enterprise_controller.js.coffee | 8 +++---- .../directives/enterprise_switcher.js.coffee | 22 +++++++++++++++++++ .../admin/utils/services/form_state.js.coffee | 3 +++ .../utils/services/navigation_check.js.coffee | 3 +-- .../admin/enterprises/_ng_form.html.haml | 3 --- app/views/admin/enterprises/edit.html.haml | 4 ++++ config/locales/en-GB.yml | 1 + config/locales/en.yml | 2 ++ 8 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee create mode 100644 app/assets/javascripts/admin/utils/services/form_state.js.coffee diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee index 0a68ce9d94..d54d0af7b8 100644 --- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee +++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.enterprises") - .controller "enterpriseCtrl", ($scope, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> + .controller "enterpriseCtrl", ($scope, $window, NavigationCheck, FormState, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> $scope.Enterprise = enterprise $scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods $scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods @@ -11,6 +11,7 @@ angular.module("admin.enterprises") $scope.StatusMessage = StatusMessage $scope.$watch 'enterprise_form.$dirty', (newValue) -> + FormState.isDirty = newValue; StatusMessage.display 'notice', 'You have unsaved changes' if newValue $scope.setFormDirty = -> @@ -24,13 +25,12 @@ angular.module("admin.enterprises") $scope.navClear() enterprise_form.submit() - # Provide a callback for generating warning messages displayed before leaving the page. This is passed in # from a directive "nav-check" in the page - if we pass it here it will be called in the test suite, # and on all new uses of this contoller, and we might not want that. enterpriseNavCallback = -> - if $scope.Enterprise.$dirty - "Your changes to the enterprise are not saved yet." + if FormState.isDirty + t('admin.unsaved_confirm_leave') # Register the NavigationCheck callback NavigationCheck.register(enterpriseNavCallback) diff --git a/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee b/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee new file mode 100644 index 0000000000..1dea298923 --- /dev/null +++ b/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee @@ -0,0 +1,22 @@ +angular.module('admin.enterprises').directive 'enterpriseSwitcher', + ['FormState','NavigationCheck', (FormState, NavigationCheck) -> + restrict: 'A' + require: 'ngModel' + link: (scope, element, attr, ngModel) -> + initial = element[0].getAttribute('data-initial') + confirm_message = t('admin.unsaved_confirm_leave') + + element.on 'change', -> + if FormState.isDirty + #Confirm if form is dirty + if !confirm(confirm_message) + #Reset the current dropdown selection if staying on page + ngModel.$setViewValue initial + ngModel.$render() + element.select2 'val', initial + return + + NavigationCheck.clear() #Don't ask twice if leaving + window.location = element[0].querySelector('option[selected]').getAttribute('data-url') + + ] \ No newline at end of file diff --git a/app/assets/javascripts/admin/utils/services/form_state.js.coffee b/app/assets/javascripts/admin/utils/services/form_state.js.coffee new file mode 100644 index 0000000000..d50fbdbb90 --- /dev/null +++ b/app/assets/javascripts/admin/utils/services/form_state.js.coffee @@ -0,0 +1,3 @@ +angular.module('admin.utils').service 'FormState', -> +#Simple service to share form state across different controllers/scopes + { isDirty: false } \ No newline at end of file diff --git a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee index 8bdab1bc9c..9c7646dd64 100644 --- a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee +++ b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.utils") - .factory "NavigationCheck", ($window, $rootScope) -> + .factory "NavigationCheck", ($window, $rootScope, FormState) -> new class NavigationCheck callbacks = [] constructor: -> @@ -10,7 +10,6 @@ angular.module("admin.utils") $rootScope.$on "$locationChangeStart", @locationChangeStartHandler - # Action for regular browser navigation. onBeforeUnloadHandler: ($event) => message = @getMessage() diff --git a/app/views/admin/enterprises/_ng_form.html.haml b/app/views/admin/enterprises/_ng_form.html.haml index ca38b7eca4..9260d0c150 100644 --- a/app/views/admin/enterprises/_ng_form.html.haml +++ b/app/views/admin/enterprises/_ng_form.html.haml @@ -2,7 +2,6 @@ -# ng-change is only valid for inputs, not for a form. -# So we use onchange and have to get the scope to access the ng controller = form_for [main_app, :admin, @enterprise], html: { name: "enterprise_form", - "ng-app" => 'admin.enterprises', "ng-controller" => 'enterpriseCtrl', 'onchange' => 'angular.element(enterprise_form).scope().setFormDirty()', } do |f| @@ -11,8 +10,6 @@ %input.red{ type: "button", value: "Update", ng: { click: "submit()", disabled: "!enterprise_form.$dirty" } } %input{ type: "button", ng: { value: "enterprise_form.$dirty ? 'Cancel' : 'Close'", click: "cancel('#{main_app.admin_enterprises_path}')" } } - - .row .sixteen.columns.alpha .four.columns.alpha diff --git a/app/views/admin/enterprises/edit.html.haml b/app/views/admin/enterprises/edit.html.haml index 5d3a623f40..51c548fc6d 100644 --- a/app/views/admin/enterprises/edit.html.haml +++ b/app/views/admin/enterprises/edit.html.haml @@ -4,7 +4,11 @@ Editing: = @enterprise.name +- content_for :app_wrapper_attrs do + = "ng-app='admin.enterprises'" + - content_for :page_actions do + %li= select :enterprise, :id, options_for_select(managed_enterprises.collect {|e| [e.name, e.id, {:'data-url' => "#{main_app.edit_admin_enterprise_path(e.permalink)}", :'ng-selected' => "selected==#{e.id}"}]}, @enterprise.id ), {}, {:'enterprise-switcher' => '', 'data-initial' => "#{@enterprise.id}", :'ng-init' => "selected='#{@enterprise.id}'", :'ng-model' => 'selected', :id => 'enterprise_switcher', :class => 'select2'} %li= button_link_to "Back to enterprises list", main_app.admin_enterprises_path, icon: 'icon-arrow-left' diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 541070f2fc..ceadbc4355 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -81,6 +81,7 @@ en-GB: tag_has_rules: "Existing rules for this tag: %{num}" has_one_rule: "has one rule" has_n_rules: "has %{num} rules" + unsaved_confirm_leave: "There are unsaved changed on this page. Continue without saving?" customers: index: add_customer: "Add Customer" diff --git a/config/locales/en.yml b/config/locales/en.yml index 6f04c26284..382b9354f3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -109,6 +109,8 @@ en: has_one_rule: "has one rule" has_n_rules: "has %{num} rules" + unsaved_confirm_leave: "There are unsaved changed on this page. Continue without saving?" + customers: index: add_customer: "Add Customer" From 5150025641d5a91d1986d660be3dc67bf1e1a893 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Tue, 10 Jan 2017 22:54:22 +0000 Subject: [PATCH 2/6] Updated tag rules UI --- .../tag_rules_controller.js.coffee | 2 +- .../admin/enterprise_index_panels.css.scss | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee b/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee index 460d8565eb..6fe83c49e9 100644 --- a/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee +++ b/app/assets/javascripts/admin/tag_rules/controllers/tag_rules_controller.js.coffee @@ -38,7 +38,6 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil newRule.peferred_exchange_tags = [] newRule.preferred_matched_order_cycles_visibility = "visible" tagGroup.rules.push(newRule) - $scope.enterprise_form.$setDirty() $scope.updateRuleCounts() $scope.addNewTag = -> @@ -58,3 +57,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil .success -> tagGroup.rules.splice(index, 1) $scope.updateRuleCounts() + $scope.enterprise_form.$setDirty() \ No newline at end of file diff --git a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss index 2ce2916497..92a1d10048 100644 --- a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss +++ b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss @@ -111,3 +111,27 @@ } } } + +tags-input .tags li.tag-item { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -ms-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; + margin: 2px 0 2px 3px; + background-image: none; + background-color: #5fa5e8; + border: none; + box-shadow: none; + color: white !important; + font-size: 85%; + height: 25px; +} + +tags-input .tags .tag-item .remove-button { + color: white; +} + +table th.actions .no-text[class*="icon-"], table td.actions .no-text[class*="icon-"] { + cursor: pointer; +} \ No newline at end of file From e021afdd8a53dd914852a9cfa869f1cdadd2642d Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Tue, 10 Jan 2017 23:53:13 +0000 Subject: [PATCH 3/6] Updated spec --- .../tag_rules/controllers/tag_rules_controller_spec.js.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee b/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee index 7ac5cc8fbc..280ef457b7 100644 --- a/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/tag_rules/controllers/tag_rules_controller_spec.js.coffee @@ -28,8 +28,6 @@ describe "TagRulesCtrl", -> scope.addNewRuleTo(scope.tagGroups[0], "DiscountOrder") it "adds a new rule of the specified type to the rules array for the tagGroup", -> - expect(scope.enterprise_form.$setDirty).toHaveBeenCalled() - expect(scope.tagGroups[0].rules.length).toEqual 3 expect(scope.tagGroups[0].rules[2].type).toEqual "TagRule::DiscountOrder" From 6bed94a09bd521538edaec8f40f124b154b7ec63 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Sun, 22 Jan 2017 18:42:23 +0000 Subject: [PATCH 4/6] Include E2E permissions --- app/helpers/enterprises_helper.rb | 6 ++++++ app/views/admin/enterprises/edit.html.haml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/helpers/enterprises_helper.rb b/app/helpers/enterprises_helper.rb index cc2b966b01..0e2a630fff 100644 --- a/app/helpers/enterprises_helper.rb +++ b/app/helpers/enterprises_helper.rb @@ -32,6 +32,12 @@ module EnterprisesHelper Enterprise.managed_by(spree_current_user) end + def editable_enterprises + OpenFoodNetwork::Permissions.new(spree_current_user). + editable_enterprises. + order('is_primary_producer ASC, name') + end + def enterprises_options enterprises enterprises.map { |enterprise| [enterprise.name + ": " + enterprise.address.address1 + ", " + enterprise.address.city, enterprise.id.to_i] } end diff --git a/app/views/admin/enterprises/edit.html.haml b/app/views/admin/enterprises/edit.html.haml index 51c548fc6d..482587add9 100644 --- a/app/views/admin/enterprises/edit.html.haml +++ b/app/views/admin/enterprises/edit.html.haml @@ -8,8 +8,8 @@ = "ng-app='admin.enterprises'" - content_for :page_actions do - %li= select :enterprise, :id, options_for_select(managed_enterprises.collect {|e| [e.name, e.id, {:'data-url' => "#{main_app.edit_admin_enterprise_path(e.permalink)}", :'ng-selected' => "selected==#{e.id}"}]}, @enterprise.id ), {}, {:'enterprise-switcher' => '', 'data-initial' => "#{@enterprise.id}", :'ng-init' => "selected='#{@enterprise.id}'", :'ng-model' => 'selected', :id => 'enterprise_switcher', :class => 'select2'} - %li= button_link_to "Back to enterprises list", main_app.admin_enterprises_path, icon: 'icon-arrow-left' + %li= select :enterprise, :id, options_for_select(editable_enterprises.collect {|e| [e.name, e.id, {:'data-url' => "#{main_app.edit_admin_enterprise_path(e.permalink)}", :'ng-selected' => "selected==#{e.id}"}]}, @enterprise.id ), {}, {:'enterprise-switcher' => '', 'data-initial' => "#{@enterprise.id}", :'ng-init' => "selected='#{@enterprise.id}'", :'ng-model' => 'selected', :id => 'enterprise_switcher', :class => 'select2'} + %li= button_link_to t('.back_link'), main_app.admin_enterprises_path, icon: 'icon-arrow-left' = render 'admin/enterprises/form_data' From 931e528e14a755325ba4c3447852503720d2a1f7 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Sun, 22 Jan 2017 18:55:28 +0000 Subject: [PATCH 5/6] Code review changes --- .../enterprises/controllers/enterprise_controller.js.coffee | 2 +- .../javascripts/admin/utils/services/navigation_check.js.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee index d54d0af7b8..135f488855 100644 --- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee +++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee @@ -11,7 +11,7 @@ angular.module("admin.enterprises") $scope.StatusMessage = StatusMessage $scope.$watch 'enterprise_form.$dirty', (newValue) -> - FormState.isDirty = newValue; + FormState.isDirty = newValue StatusMessage.display 'notice', 'You have unsaved changes' if newValue $scope.setFormDirty = -> diff --git a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee index 9c7646dd64..51086c1829 100644 --- a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee +++ b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.utils") - .factory "NavigationCheck", ($window, $rootScope, FormState) -> + .factory "NavigationCheck", ($window, $rootScope) -> new class NavigationCheck callbacks = [] constructor: -> From b8622e95b7b3b3779cb5ea2bd0fb8e2198f1cb7f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 11 Jan 2017 15:54:00 +1100 Subject: [PATCH 6/6] Re-use NavigationCheck logic The enterprise switcher now uses the same code as NavigationCheck to confirm leaving a changed form. This makes FormState obsolete. Conflicts: app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee --- .../enterprise_controller.js.coffee | 7 ++-- .../directives/enterprise_switcher.js.coffee | 34 ++++++++----------- .../admin/utils/services/form_state.js.coffee | 3 -- .../utils/services/navigation_check.js.coffee | 8 +++-- config/locales/en.yml | 1 + 5 files changed, 24 insertions(+), 29 deletions(-) delete mode 100644 app/assets/javascripts/admin/utils/services/form_state.js.coffee diff --git a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee index 135f488855..32c8f7734b 100644 --- a/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee +++ b/app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.enterprises") - .controller "enterpriseCtrl", ($scope, $window, NavigationCheck, FormState, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> + .controller "enterpriseCtrl", ($scope, $window, NavigationCheck, enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu, StatusMessage) -> $scope.Enterprise = enterprise $scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods $scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods @@ -11,8 +11,7 @@ angular.module("admin.enterprises") $scope.StatusMessage = StatusMessage $scope.$watch 'enterprise_form.$dirty', (newValue) -> - FormState.isDirty = newValue - StatusMessage.display 'notice', 'You have unsaved changes' if newValue + StatusMessage.display 'notice', t('admin.unsaved_changes') if newValue $scope.setFormDirty = -> $scope.$apply -> @@ -29,7 +28,7 @@ angular.module("admin.enterprises") # from a directive "nav-check" in the page - if we pass it here it will be called in the test suite, # and on all new uses of this contoller, and we might not want that. enterpriseNavCallback = -> - if FormState.isDirty + if $scope.enterprise_form.$dirty t('admin.unsaved_confirm_leave') # Register the NavigationCheck callback diff --git a/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee b/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee index 1dea298923..a9c030a823 100644 --- a/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee +++ b/app/assets/javascripts/admin/enterprises/directives/enterprise_switcher.js.coffee @@ -1,22 +1,16 @@ -angular.module('admin.enterprises').directive 'enterpriseSwitcher', - ['FormState','NavigationCheck', (FormState, NavigationCheck) -> - restrict: 'A' - require: 'ngModel' - link: (scope, element, attr, ngModel) -> - initial = element[0].getAttribute('data-initial') - confirm_message = t('admin.unsaved_confirm_leave') +angular.module('admin.enterprises').directive 'enterpriseSwitcher', (NavigationCheck) -> + restrict: 'A' + require: 'ngModel' + link: (scope, element, attr, ngModel) -> + initial = element[0].getAttribute('data-initial') - element.on 'change', -> - if FormState.isDirty - #Confirm if form is dirty - if !confirm(confirm_message) - #Reset the current dropdown selection if staying on page - ngModel.$setViewValue initial - ngModel.$render() - element.select2 'val', initial - return + element.on 'change', -> + if not NavigationCheck.confirmLeave() + # Reset the current dropdown selection if staying on page + ngModel.$setViewValue initial + ngModel.$render() + element.select2 'val', initial + return - NavigationCheck.clear() #Don't ask twice if leaving - window.location = element[0].querySelector('option[selected]').getAttribute('data-url') - - ] \ No newline at end of file + NavigationCheck.clear() # Don't ask twice if leaving + window.location = element[0].querySelector('option[selected]').getAttribute('data-url') diff --git a/app/assets/javascripts/admin/utils/services/form_state.js.coffee b/app/assets/javascripts/admin/utils/services/form_state.js.coffee deleted file mode 100644 index d50fbdbb90..0000000000 --- a/app/assets/javascripts/admin/utils/services/form_state.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -angular.module('admin.utils').service 'FormState', -> -#Simple service to share form state across different controllers/scopes - { isDirty: false } \ No newline at end of file diff --git a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee index 51086c1829..89ebd5b90e 100644 --- a/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee +++ b/app/assets/javascripts/admin/utils/services/navigation_check.js.coffee @@ -20,13 +20,17 @@ angular.module("admin.utils") # Action for angular navigation. locationChangeStartHandler: ($event) => - message = @getMessage() - if message and not $window.confirm(message) + if not @confirmLeave() $event.stopPropagation() if $event.stopPropagation $event.preventDefault() if $event.preventDefault $event.cancelBubble = true $event.returnValue = false + # Check if leaving is okay + confirmLeave: => + message = @getMessage() + !message or $window.confirm(message) + # Runs callback functions to retreive most recently added non-empty message. getMessage: -> message = null diff --git a/config/locales/en.yml b/config/locales/en.yml index 1c5db7e97f..0c96b5d42a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -118,6 +118,7 @@ en: has_n_rules: "has %{num} rules" unsaved_confirm_leave: "There are unsaved changed on this page. Continue without saving?" + unsaved_changes: "You have unsaved changes" customers: index: