Skip to content

Commit

Permalink
Merge pull request cypht-org#669 from josaphatim/warn-for-unsaved-cha…
Browse files Browse the repository at this point in the history
…nges

Added a warn when user closes tab or browser with unsaved changes to …
  • Loading branch information
kroky authored Dec 22, 2023
2 parents ee014fd + f5c2b6b commit a7ca9be
Show file tree
Hide file tree
Showing 24 changed files with 283 additions and 22 deletions.
4 changes: 2 additions & 2 deletions language/az.php
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false

'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/de.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/en.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/es.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/et.php
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/fa.php
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/fr.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => 'Déplacer vers le dossier Bloqués',
'Sieve server capabilities' => 'Capacités du serveur Sieve',
'Connection To Sieve Server Failed' => 'Échec de la connexion au serveur Sieve'
'Connection To Sieve Server Failed' => 'Échec de la connexion au serveur Sieve',
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/hu.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/id.php
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/it.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => 'Archivia nella cartella originale',
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/ja.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/nl.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/pt-BR.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/ro.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
3 changes: 2 additions & 1 deletion language/ru.php
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,8 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Connection To Sieve Server Failed' => false
'Connection To Sieve Server Failed' => false,
'Warn for unsaved changes' => false,
);

?>
1 change: 1 addition & 0 deletions language/zh-Hans.php
Original file line number Diff line number Diff line change
Expand Up @@ -575,4 +575,5 @@
'Archive to the original folder' => false,
'Move To Blocked Folder' => false,
'Sieve server capabilities' => false,
'Warn for unsaved changes' => false,
);
17 changes: 17 additions & 0 deletions modules/core/handler_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ public function process() {
}
}
$this->out('mailto_handler', $this->user_config->get('mailto_handler_setting', false));
$this->out('warn_for_unsaved_changes', $this->user_config->get('warn_for_unsaved_changes_setting', false));
$this->out('no_password_save', $this->user_config->get('no_password_save_setting', false));
if (!strstr($this->request->server['REQUEST_URI'], 'page=') && $this->page == 'home') {
$start_page = $this->user_config->get('start_page_setting', false);
Expand Down Expand Up @@ -945,3 +946,19 @@ public function process() {
process_site_setting('drafts_since', $this, 'since_setting_callback');
}
}

/**
* Process warn for unsaved changes in the settings page
* @subpackage core/handler
*/
class Hm_Handler_process_warn_for_unsaved_changes_setting extends Hm_Handler_Module {
/**
* valid values are true and false
*/
public function process() {
function warn_for_unsaved_changes_callback($val) {
return $val;
}
process_site_setting('warn_for_unsaved_changes', $this, 'warn_for_unsaved_changes_callback');
}
}
23 changes: 23 additions & 0 deletions modules/core/output_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,9 @@ protected function output() {
$js_lib = '<script type="text/javascript" src="third_party/cash.min.js"></script>';
$js_lib .= '<script type="text/javascript" src="third_party/resumable.min.js"></script>';
$js_lib .= '<script type="text/javascript" src="third_party/tingle.min.js"></script>';
$js_lib .= '<script type="text/javascript" src="third_party/ays-beforeunload-shim.js"></script>';
$js_lib .= '<script type="text/javascript" src="third_party/jquery.are-you-sure.js"></script>';

if ($this->get('encrypt_ajax_requests', '') || $this->get('encrypt_local_storage', '')) {
$js_lib .= '<script type="text/javascript" src="third_party/forge.min.js"></script>';
}
Expand Down Expand Up @@ -554,6 +557,7 @@ protected function output() {
'var hm_encrypt_local_storage = function() { return "'.$this->html_safe($this->get('encrypt_local_storage', '')).'"; };'.
'var hm_web_root_path = function() { return "'.WEB_ROOT.'"; };'.
'var hm_flag_image_src = function() { return "'.Hm_Image_Sources::$star.'"; };'.
'var hm_check_dirty_flag = function() { return '.($this->get('warn_for_unsaved_changes', '') ? '1' : '0').'; };'.
format_data_sources($this->get('data_sources', array()), $this);

if (!$this->get('disable_delete_prompt')) {
Expand Down Expand Up @@ -1979,3 +1983,22 @@ protected function output() {
'<td>'.message_since_dropdown($since, 'drafts_since', $this).'</td></tr>';
}
}

/**
* Option to warn user when he has unsaved changes.
* @subpackage imap/output
*/
class Hm_Output_warn_for_unsaved_changes_setting extends Hm_Output_Module {
protected function output() {
$checked = '';
$settings = $this->get('user_settings', array());
$reset = '';
if (array_key_exists('warn_for_unsaved_changes', $settings) && $settings['warn_for_unsaved_changes']) {
$checked = ' checked="checked"';
$reset = '<span class="tooltip_restore" restore_aria_label="Restore default value"><img alt="Refresh" class="refresh_list reset_default_value_checkbox" src="'.Hm_Image_Sources::$refresh.'" /></span>';
}
return '<tr class="general_setting"><td><label for="warn_for_unsaved_changes">'.
$this->trans('Warn for unsaved changes').'</label></td>'.
'<td><input type="checkbox" '.$checked.' id="warn_for_unsaved_changes" name="warn_for_unsaved_changes" value="1" />'.$reset.'</td></tr>';
}
}
5 changes: 4 additions & 1 deletion modules/core/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
add_handler('settings', 'process_language_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_list_style_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_timezone_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_warn_for_unsaved_changes_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_unread_since_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_flagged_since_setting', true, 'core', 'date', 'after');
add_handler('settings', 'process_flagged_source_max_setting', true, 'core', 'date', 'after');
Expand Down Expand Up @@ -65,7 +66,8 @@
add_output('settings', 'start_general_settings', true, 'core', 'start_settings_form', 'after');
add_output('settings', 'language_setting', true, 'core', 'start_general_settings', 'after');
add_output('settings', 'timezone_setting', true, 'core', 'language_setting', 'after');
add_output('settings', 'no_folder_icon_setting', true, 'core', 'timezone_setting', 'after');
add_output('settings', 'warn_for_unsaved_changes_setting', true, 'core', 'timezone_setting', 'after');
add_output('settings', 'no_folder_icon_setting', true, 'core', 'warn_for_unsaved_changes_setting', 'after');
add_output('settings', 'mailto_handler_setting', true, 'core', 'no_folder_icon_setting', 'after');
add_output('settings', 'list_style_setting', true, 'core', 'mailto_handler_setting', 'after');
add_output('settings', 'msg_list_icons_setting', true, 'core', 'list_style_setting', 'before');
Expand Down Expand Up @@ -287,6 +289,7 @@
'trash_since' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
'drafts_per_source' => FILTER_VALIDATE_INT,
'drafts_since' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
'warn_for_unsaved_changes' => FILTER_VALIDATE_BOOLEAN
)
);

Expand Down
6 changes: 5 additions & 1 deletion modules/core/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -1802,7 +1802,11 @@ $(function() {
$('.reset_default_value_select').on("click", reset_default_value_select);
$('.reset_default_value_input').on("click", reset_default_value_input);
}


if (hm_check_dirty_flag()) {
$('form:not(.search_terms)').areYouSure();
}

fixLtrInRtl()
});

Expand Down
2 changes: 2 additions & 0 deletions scripts/config_gen.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ function combine_includes($js, $js_compress, $css, $css_compress, $settings) {
$js_lib .= file_get_contents("third_party/forge.min.js");
}
$js_lib .= file_get_contents("third_party/resumable.min.js");
$js_lib .= file_get_contents("third_party/ays-beforeunload-shim.js");
$js_lib .= file_get_contents("third_party/jquery.are-you-sure.js");
file_put_contents('tmp.js', $js);
$js_out = $js_lib.compress($js, $js_compress, 'tmp.js');
$js_hash = build_integrity_hash($js_out);
Expand Down
8 changes: 4 additions & 4 deletions tests/phpunit/modules/core/modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -837,10 +837,10 @@ public function test_js_data() {
$test = new Output_Test('js_data', 'core');
$test->handler_response = array('disable_delete_prompt' => true);
$res = $test->run();
$this->assertEquals(array('<script type="text/javascript">var globals = {};var hm_empty_folder = function() { return "So alone"; };var hm_mobile = function() { return 0; };var hm_debug = function() { return "0"; };var hm_mailto = function() { return 0; };var hm_page_name = function() { return ""; };var hm_language_direction = function() { return "ltr"; };var hm_list_path = function() { return ""; };var hm_list_parent = function() { return ""; };var hm_msg_uid = function() { return Hm_Utils.get_from_global("msg_uid", ""); };var hm_encrypt_ajax_requests = function() { return ""; };var hm_encrypt_local_storage = function() { return ""; };var hm_web_root_path = function() { return ""; };var hm_flag_image_src = function() { return "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D%228%22%20viewBox%3D%220%200%208%208%22%3E%0A%20%20%3Cpath%20d%3D%22M0%200v8h1v-8h-1zm2%200v4h2v1h4l-2-1.969%202-2.031h-3v-1h-3z%22%20%2F%3E%0A%3C%2Fsvg%3E"; };var hm_data_sources = function() { return []; };var hm_delete_prompt = function() { return true; };</script>'), $res->output_response);
$this->assertEquals(array('<script type="text/javascript">var globals = {};var hm_empty_folder = function() { return "So alone"; };var hm_mobile = function() { return 0; };var hm_debug = function() { return "0"; };var hm_mailto = function() { return 0; };var hm_page_name = function() { return ""; };var hm_language_direction = function() { return "ltr"; };var hm_list_path = function() { return ""; };var hm_list_parent = function() { return ""; };var hm_msg_uid = function() { return Hm_Utils.get_from_global("msg_uid", ""); };var hm_encrypt_ajax_requests = function() { return ""; };var hm_encrypt_local_storage = function() { return ""; };var hm_web_root_path = function() { return ""; };var hm_flag_image_src = function() { return "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D%228%22%20viewBox%3D%220%200%208%208%22%3E%0A%20%20%3Cpath%20d%3D%22M0%200v8h1v-8h-1zm2%200v4h2v1h4l-2-1.969%202-2.031h-3v-1h-3z%22%20%2F%3E%0A%3C%2Fsvg%3E"; };var hm_check_dirty_flag = function() { return 0; };var hm_data_sources = function() { return []; };var hm_delete_prompt = function() { return true; };</script>'), $res->output_response);
$test->handler_response = array();
$res = $test->run();
$this->assertEquals(array('<script type="text/javascript">var globals = {};var hm_empty_folder = function() { return "So alone"; };var hm_mobile = function() { return 0; };var hm_debug = function() { return "0"; };var hm_mailto = function() { return 0; };var hm_page_name = function() { return ""; };var hm_language_direction = function() { return "ltr"; };var hm_list_path = function() { return ""; };var hm_list_parent = function() { return ""; };var hm_msg_uid = function() { return Hm_Utils.get_from_global("msg_uid", ""); };var hm_encrypt_ajax_requests = function() { return ""; };var hm_encrypt_local_storage = function() { return ""; };var hm_web_root_path = function() { return ""; };var hm_flag_image_src = function() { return "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D%228%22%20viewBox%3D%220%200%208%208%22%3E%0A%20%20%3Cpath%20d%3D%22M0%200v8h1v-8h-1zm2%200v4h2v1h4l-2-1.969%202-2.031h-3v-1h-3z%22%20%2F%3E%0A%3C%2Fsvg%3E"; };var hm_data_sources = function() { return []; };var hm_delete_prompt = function() { return confirm("Are you sure?"); };</script>'), $res->output_response);
$this->assertEquals(array('<script type="text/javascript">var globals = {};var hm_empty_folder = function() { return "So alone"; };var hm_mobile = function() { return 0; };var hm_debug = function() { return "0"; };var hm_mailto = function() { return 0; };var hm_page_name = function() { return ""; };var hm_language_direction = function() { return "ltr"; };var hm_list_path = function() { return ""; };var hm_list_parent = function() { return ""; };var hm_msg_uid = function() { return Hm_Utils.get_from_global("msg_uid", ""); };var hm_encrypt_ajax_requests = function() { return ""; };var hm_encrypt_local_storage = function() { return ""; };var hm_web_root_path = function() { return ""; };var hm_flag_image_src = function() { return "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%228%22%20height%3D%228%22%20viewBox%3D%220%200%208%208%22%3E%0A%20%20%3Cpath%20d%3D%22M0%200v8h1v-8h-1zm2%200v4h2v1h4l-2-1.969%202-2.031h-3v-1h-3z%22%20%2F%3E%0A%3C%2Fsvg%3E"; };var hm_check_dirty_flag = function() { return 0; };var hm_data_sources = function() { return []; };var hm_delete_prompt = function() { return confirm("Are you sure?"); };</script>'), $res->output_response);
}
/**
* @preserveGlobalState disabled
Expand Down Expand Up @@ -1490,10 +1490,10 @@ public function test_page_js_debug() {
$test = new Output_Test('page_js', 'core');
$test->handler_response = array('encrypt_ajax_requests' => true, 'router_module_list' => array('foo', 'core'));
$res = $test->run();
$this->assertEquals(array('<script type="text/javascript" src="third_party/cash.min.js"></script><script type="text/javascript" src="third_party/resumable.min.js"></script><script type="text/javascript" src="third_party/tingle.min.js"></script><script type="text/javascript" src="third_party/forge.min.js"></script><script type="text/javascript" src="modules/core/site.js"></script>'), $res->output_response);
$this->assertEquals(array('<script type="text/javascript" src="third_party/cash.min.js"></script><script type="text/javascript" src="third_party/resumable.min.js"></script><script type="text/javascript" src="third_party/tingle.min.js"></script><script type="text/javascript" src="third_party/ays-beforeunload-shim.js"></script><script type="text/javascript" src="third_party/jquery.are-you-sure.js"></script><script type="text/javascript" src="third_party/forge.min.js"></script><script type="text/javascript" src="modules/core/site.js"></script>'), $res->output_response);
$test->handler_response = array('encrypt_ajax_requests' => true, 'router_module_list' => array('imap'));
$res = $test->run();
$this->assertEquals(array('<script type="text/javascript" src="third_party/cash.min.js"></script><script type="text/javascript" src="third_party/resumable.min.js"></script><script type="text/javascript" src="third_party/tingle.min.js"></script><script type="text/javascript" src="third_party/forge.min.js"></script><script type="text/javascript" src="modules/core/site.js"></script><script type="text/javascript" src="modules/imap/site.js"></script>'), $res->output_response);
$this->assertEquals(array('<script type="text/javascript" src="third_party/cash.min.js"></script><script type="text/javascript" src="third_party/resumable.min.js"></script><script type="text/javascript" src="third_party/tingle.min.js"></script><script type="text/javascript" src="third_party/ays-beforeunload-shim.js"></script><script type="text/javascript" src="third_party/jquery.are-you-sure.js"></script><script type="text/javascript" src="third_party/forge.min.js"></script><script type="text/javascript" src="modules/core/site.js"></script><script type="text/javascript" src="modules/imap/site.js"></script>'), $res->output_response);
}
/**
* @preserveGlobalState disabled
Expand Down
20 changes: 20 additions & 0 deletions third_party/ays-beforeunload-shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
$(function() {
if (!navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/)) {
return;
}
$('a').on('click', function(evt) {
var href = $(evt.target).closest('a').attr('href');
if (href !== undefined && !(href.match(/^#/) || href.trim() == '')) {
var response = $(window).triggerHandler('beforeunload', response);
if (response && response != "") {
var msg = response + "\n\n"
+ "Press OK to leave this page or Cancel to stay.";
if (!confirm(msg)) {
return false;
}
}
window.location.href = href;
return false;
}
});
});
Loading

0 comments on commit a7ca9be

Please sign in to comment.