Merge pull request #5354 from opf/fix/24941/warn-before-leaving-page

fix #24941 Warn before leaving page with unsaved data not working
pull/5362/head
Oliver Günther 8 years ago committed by GitHub
commit e4bff6ba3e
  1. 1
      app/assets/javascripts/application.js.erb
  2. 54
      app/assets/javascripts/warn_leaving_unsaved.js
  3. 10
      app/helpers/application_helper.rb
  4. 4
      config/locales/en.yml
  5. 15
      frontend/app/components/wp-edit/wp-edit-mode-state.service.ts
  6. 2
      spec/features/security/angular_xss_spec.rb
  7. 16
      spec/features/work_packages/cancel_editing_spec.rb

@ -48,7 +48,6 @@
//= require top-shelf //= require top-shelf
//= require unsupported-browsers //= require unsupported-browsers
//= require autocomplete_textareas //= require autocomplete_textareas
//= require warn_leaving_unsaved
//= require openproject_plugins //= require openproject_plugins
//= require versions //= require versions
//= require_tree ./specific //= require_tree ./specific

@ -1,54 +0,0 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2017 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
var warnLeavingUnsavedMessage;
var removeChangedData = function(){
jQuery('textarea').removeData('changed');
};
function warnLeavingUnsaved(message) {
warnLeavingUnsavedMessage = message;
jQuery('form').submit(removeChangedData);
jQuery('form button').click(removeChangedData);
jQuery('textarea').change(function(){
jQuery(this).data('changed', 'changed');
});
window.onbeforeunload = function(){
var warn = false;
jQuery('textarea').blur().each(function(){
if (jQuery(this).data('changed')) {
warn = true;
}
});
if (warn) {return warnLeavingUnsavedMessage;}
};
};

@ -611,16 +611,6 @@ module ApplicationHelper
I18n.defaultLocale = "#{I18n.default_locale}"; I18n.defaultLocale = "#{I18n.default_locale}";
I18n.locale = "#{I18n.locale}"; I18n.locale = "#{I18n.locale}";
}) })
if User.current.pref.warn_on_leaving_unsaved?
tags += javascript_tag(%{
jQuery(document).ready(function(){
warnLeavingUnsaved('#{escape_javascript(l(:text_warn_on_leaving_unsaved))}');
jQuery(document).ajaxComplete(function(){
warnLeavingUnsaved('#{escape_javascript(l(:text_warn_on_leaving_unsaved))}')
});
});
})
end
tags.html_safe tags.html_safe
end end

@ -374,7 +374,7 @@ en:
impaired: "Accessibility mode" impaired: "Accessibility mode"
time_zone: "Time zone" time_zone: "Time zone"
auto_hide_popups: "Auto-hide success notifications" auto_hide_popups: "Auto-hide success notifications"
warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" warn_on_leaving_unsaved: "Warn me when leaving a work package with unsaved changes"
version: version:
effective_date: "Due date" effective_date: "Due date"
sharing: "Sharing" sharing: "Sharing"
@ -2024,7 +2024,7 @@ en:
text_unallowed_characters: "Unallowed characters" text_unallowed_characters: "Unallowed characters"
text_user_invited: The user has been invited and is pending registration. text_user_invited: The user has been invited and is pending registration.
text_user_wrote: "%{value} wrote:" text_user_wrote: "%{value} wrote:"
text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." text_warn_on_leaving_unsaved: "The work package contains unsaved text that will be lost if you leave this page."
text_wiki_destroy_confirmation: "Are you sure you want to delete this wiki and all its content?" text_wiki_destroy_confirmation: "Are you sure you want to delete this wiki and all its content?"
text_wiki_page_destroy_children: "Delete child pages and all their descendants" text_wiki_page_destroy_children: "Delete child pages and all their descendants"
text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?"

@ -41,7 +41,6 @@ export class WorkPackageEditModeStateService {
protected $q:ng.IQService, protected $q:ng.IQService,
protected I18n:op.I18n) { protected I18n:op.I18n) {
const confirmText = I18n.t('js.work_packages.confirm_edit_cancel'); const confirmText = I18n.t('js.work_packages.confirm_edit_cancel');
const cancelEventName = 'beforeunload.confirm_cancel';
const requiresConfirmation = ConfigurationService.warnOnLeavingUnsaved(); const requiresConfirmation = ConfigurationService.warnOnLeavingUnsaved();
$rootScope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams) => { $rootScope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams) => {
@ -55,20 +54,6 @@ export class WorkPackageEditModeStateService {
this.cancel(); this.cancel();
} }
}); });
// Show confirmation message when browsing to a new page
angular.element($window).on(cancelEventName, (event:JQueryEventObject):string|void => {
if (requiresConfirmation && this.active) {
(event as any).returnValue = confirmText;
event.preventDefault();
return confirmText;
}
});
$rootScope.$on('$destroy', () => {
return angular.element($window).off(cancelEventName);
});
} }
public start():boolean { public start():boolean {

@ -131,8 +131,6 @@ describe 'Angular expression escaping', type: :feature do
expect(preview.text).to match /\{\{[\s\w]+\}\}/ expect(preview.text).to match /\{\{[\s\w]+\}\}/
btn_cancel.click btn_cancel.click
page.driver.browser.switch_to.alert.accept
expect(page).to have_no_selector('#content_text')
end end
end end

@ -68,10 +68,19 @@ describe 'Cancel editing work package', js: true do
expect(page).to have_selector('h2', text: 'OpenProject') expect(page).to have_selector('h2', text: 'OpenProject')
end end
it 'shows an alert when moving to other pages' do it 'does not show an alert when moving to other pages' do
# This used to show an alert until browsers dropped support
# for `onbeforeunload`.
#
# We want to find a way how to to regain that possibility
# at some later point in time. Until then we keep that block
# and only flip
# move_to_home_page(alert: true)
# to
# move_to_home_page(alert: false)
paths.each do |path| paths.each do |path|
expect_active_edit(path) expect_active_edit(path)
move_to_home_page move_to_home_page(alert: false)
end end
end end
@ -85,9 +94,6 @@ describe 'Cancel editing work package', js: true do
expect(page).to have_selector('.wp-edit-field.subject.-active') expect(page).to have_selector('.wp-edit-field.subject.-active')
expect(wp_page).not_to have_alert_dialog expect(wp_page).not_to have_alert_dialog
# Actually move somewhere to accept the beforeunload
move_to_home_page
end end
it 'cancels the editing when clicking the button' do it 'cancels the editing when clicking the button' do

Loading…
Cancel
Save