]> source.dussan.org Git - redmine.git/commitdiff
Warning on leaving a page with unsaved content in textarea (#2910).
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Mon, 21 Feb 2011 09:53:29 +0000 (09:53 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Mon, 21 Feb 2011 09:53:29 +0000 (09:53 +0000)
The warning can be turned off in the user's preference.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4900 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/helpers/application_helper.rb
app/models/user_preference.rb
app/views/layouts/base.rhtml
app/views/users/_preferences.html.erb
config/locales/en.yml
config/locales/fr.yml
public/javascripts/application.js
test/functional/welcome_controller_test.rb

index c6d88487fdf7512a146f77d92944414e08bd9f21..be0ebaec1ae79ea9197de8f2a87795c50b6cab67 100644 (file)
@@ -894,6 +894,15 @@ module ApplicationHelper
       ''
     end
   end
+  
+  # Returns the javascript tags that are included in the html layout head
+  def javascript_heads
+    tags = javascript_include_tag(:defaults)
+    unless User.current.pref.warn_on_leaving_unsaved == '0'
+      tags << "\n" + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
+    end
+    tags
+  end
 
   def favicon
     "<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
index 3daa7a740eb8b37cec9f2f1342801efc2ec3c9df..85236ff645c1e731db853d57565e5179954e4aeb 100644 (file)
@@ -51,4 +51,7 @@ class UserPreference < ActiveRecord::Base
   
   def comments_sorting; self[:comments_sorting] end
   def comments_sorting=(order); self[:comments_sorting]=order end
+  
+  def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end
+  def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end
 end
index b59f1e280f2731e0704fc77f03f446a82d0123e3..d6d3400aaabb97165df0d40f161664a7a489e93a 100644 (file)
@@ -8,7 +8,7 @@
 <%= favicon %>
 <%= stylesheet_link_tag 'application', :media => 'all' %>
 <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
-<%= javascript_include_tag :defaults %>
+<%= javascript_heads %>
 <%= heads_for_theme %>
 <%= heads_for_wiki_formatter %>
 <!--[if IE 6]>
index 85b5990e388d918c41dbff891b738c30aab8abe0..57f050b102510708f3c53045e28da302afc35f94 100644 (file)
@@ -2,5 +2,6 @@
 <p><%= pref_fields.check_box :hide_mail %></p>
 <p><%= pref_fields.select :time_zone, ActiveSupport::TimeZone.all.collect {|z| [ z.to_s, z.name ]}, :include_blank => true %></p>
 <p><%= pref_fields.select :comments_sorting, [[l(:label_chronological_order), 'asc'], [l(:label_reverse_chronological_order), 'desc']] %></p>
+<p><%= pref_fields.check_box :warn_on_leaving_unsaved %></p>
 <% end %>
 
index d32a2bdbd7817f48bb4639a2de6a4e10a5db3749..1757c1517208fd55cf60403dd04a000b85c23b26 100644 (file)
@@ -303,6 +303,7 @@ en:
   field_assigned_to_role: "Assignee's role"
   field_text: Text field
   field_visible: Visible
+  field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
   
   setting_app_title: Application title
   setting_app_subtitle: Application subtitle
@@ -908,6 +909,7 @@ en:
   text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?"
   text_zoom_in: Zoom in
   text_zoom_out: Zoom out
+  text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page."
   
   default_role_manager: Manager
   default_role_developer: Developer
index c154dd35d2e1193334c977339996bf2a36e22776..aa5815a2fc4d39042020116d77179a928f12e53b 100644 (file)
@@ -307,6 +307,7 @@ fr:
   field_active: Actif
   field_parent_issue: Tâche parente
   field_visible: Visible
+  field_warn_on_leaving_unsaved: "M'avertir lorsque je quitte une page contenant du texte non sauvegardé"
   
   setting_app_title: Titre de l'application
   setting_app_subtitle: Sous-titre de l'application
@@ -889,6 +890,7 @@ fr:
   text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes"
   text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page"
   text_own_membership_delete_confirmation: "Vous allez supprimer tout ou partie de vos permissions sur ce projet et ne serez peut-être plus autorisé à modifier ce projet.\nEtes-vous sûr de vouloir continuer ?"
+  text_warn_on_leaving_unsaved: "Cette page contient du texte non sauvegardé qui sera perdu si vous quittez la page."
   
   default_role_manager: "Manager "
   default_role_developer: "Développeur "
index 6cea8f3dd18ea378e63f7b047470edb3692210a1..a88856ea62fd149ba1977885f4835d0f46006a95 100644 (file)
@@ -255,6 +255,49 @@ function observeProjectModules() {
   Event.observe('project_enabled_module_names_issue_tracking', 'change', f);
 }
 
+/*
+ * Class used to warn user when leaving a page with unsaved textarea
+ * Author: mathias.fischer@berlinonline.de
+*/
+
+var WarnLeavingUnsaved = Class.create({
+       observedForms: false,
+       observedElements: false,
+       changedForms: false,
+       message: null,
+       
+       initialize: function(message){
+               this.observedForms = $$('form');
+               this.observedElements =  $$('textarea');
+               this.message = message;
+               
+               this.observedElements.each(this.observeChange.bind(this));
+               this.observedForms.each(this.submitAction.bind(this));
+               
+               window.onbeforeunload = this.unload.bind(this);
+       },
+       
+       unload: function(){
+               if(this.changedForms)
+      return this.message;
+       },
+       
+       setChanged: function(){
+    this.changedForms = true;
+       },
+       
+       setUnchanged: function(){
+    this.changedForms = false;
+       },
+       
+       observeChange: function(element){
+    element.observe('change',this.setChanged.bindAsEventListener(this));
+       },
+       
+       submitAction: function(element){
+    element.observe('submit',this.setUnchanged.bindAsEventListener(this));
+       }
+});
 
 /* shows and hides ajax indicator */
 Ajax.Responders.register({
index 7a53c8b6a63ee289447fb3396b8e5647b72ecd12..86542829b1ce7fe494c01d1abce9665dd192c957 100644 (file)
@@ -67,4 +67,28 @@ class WelcomeControllerTest < ActionController::TestCase
     assert_equal 'text/plain', @response.content_type
     assert @response.body.match(%r{^Disallow: /projects/ecookbook/issues\r?$})
   end
+  
+  def test_warn_on_leaving_unsaved_turn_on
+    user = User.find(2)
+    user.pref.warn_on_leaving_unsaved = '1'
+    user.pref.save!
+    @request.session[:user_id] = 2
+    
+    get :index
+    assert_tag 'script',
+      :attributes => {:type => "text/javascript"},
+      :content => %r{new WarnLeavingUnsaved}
+  end
+  
+  def test_warn_on_leaving_unsaved_turn_off
+    user = User.find(2)
+    user.pref.warn_on_leaving_unsaved = '0'
+    user.pref.save!
+    @request.session[:user_id] = 2
+    
+    get :index
+    assert_no_tag 'script',
+      :attributes => {:type => "text/javascript"},
+      :content => %r{new WarnLeavingUnsaved}
+  end
 end