diff --git a/js/ajax.js b/js/ajax.js index 9541e4b7b1..11d7b1bbe1 100644 --- a/js/ajax.js +++ b/js/ajax.js @@ -17,9 +17,9 @@ var AJAX = { */ xhr: null, /** - * @var object array, list of altered targets + * @var object lockedTargets, list of locked targets */ - alteredTargets: [], + lockedTargets: {}, /** * @var function Callback to execute after a successful request * Used by PMA_commonFunctions from common.js @@ -133,20 +133,36 @@ var AJAX = { } }, /** - * Registers a keyup function when changes are made in input field - * @param event for the trigged function + * function to handle lock page mechanism + * + * @param event the event object * * @return void */ - inputAltered: function(event) { - var i; - for(i=0; i < AJAX.alteredTargets.length; i++) { - if(AJAX.alteredTargets[i] == event.target) - break; + lockPageHandler: function(event) { + var lockId = $(this).data('lock-id'); + if (typeof lockId === 'undefined') { + return; } - - if(i == AJAX.alteredTargets.length) { - AJAX.alteredTargets[i] = event.target; + /* + * @todo Fix Code mirror does not give correct full value (query) + * in textarea, it returns only the change in content. + */ + var newHash = AJAX.hash($(this).val()); + var oldHash = $(this).data('val-hash'); + // Set lock if old value != new value + // otherwise release lock + if (oldHash !== newHash) { + AJAX.lockedTargets[lockId] = true; + } else { + delete AJAX.lockedTargets[lockId]; + } + // Show lock icon if locked targets is not empty. + // otherwise remove lock icon + if (!jQuery.isEmptyObject(AJAX.lockedTargets)) { + $('#lock_page_icon').html(PMA_getImage('s_lock.png').toString()); + } else { + $('#lock_page_icon').html(''); } }, /** @@ -166,8 +182,8 @@ var AJAX = { } else if ($(this).attr('target')) { return true; } else if ($(this).hasClass('ajax') || $(this).hasClass('disableAjax')) { - //reset the alteredTarget array, as specified AJAX operation has finished - AJAX.alteredTargets.length = 0; + //reset the lockedTargets object, as specified AJAX operation has finished + AJAX.lockedTargets = {}; return true; } else if (href && href.match(/^#/)) { return true; @@ -184,30 +200,20 @@ var AJAX = { event.stopImmediatePropagation(); } - //sometime we accidently click on a url,refresh button or back button - //operation to confirm if user want to leave page in such cases - //trigger confirm dialog - var isInputAltered = false; - for (var i = 0; i < AJAX.alteredTargets.length; i++) { - if(AJAX.alteredTargets[i].value.length !== 0) { - isInputAltered = true; - break; - } - } - //triggers a confirm dialog if: //the user has performed some operations on loaded page //the user clicks on some link, (won't trigger for buttons) //the click event is not triggered by script if (typeof event !== 'undefined' && event.type === 'click' && event.isTrigger !== true && - isInputAltered && + !jQuery.isEmptyObject(AJAX.lockedTargets) && confirm(PMA_messages.strConfirmNavigation) === false ) { return false; } //reset - AJAX.alteredTargets.length = 0; + AJAX.lockedTargets = {}; + $('#lock_page_icon').html(''); if (AJAX.active === true) { // Cancel the old request if abortable, when the user requests @@ -327,6 +333,7 @@ var AJAX = { .not('#pma_navigation') .not('#floating_menubar') .not('#goto_pagetop') + .not('#lock_page_icon') .not('#page_content') .not('#selflink') .not('#session_debug') @@ -385,6 +392,16 @@ var AJAX = { } AJAX._callback = function () {}; }); + // initializes all lock-page elements lock-id and + // val-hash data property + $('#page_content form.lock-page textarea, ' + + '#page_content form.lock-page input[type="text"]').each(function(i){ + $(this).data('lock-id', i); + // val-hash is the hash of default value of the field + // so that it can be compared with new value hash + // to check whether field was modified or not. + $(this).data('val-hash', AJAX.hash($(this).val())); + }); } else { PMA_ajaxShowMessage(data.error, false); AJAX.active = false; @@ -907,9 +924,14 @@ $('form').live('submit', AJAX.requestHandler); /** * Attach event listener to events when user modify visible - * Input fields to make changes in forms + * Input or Textarea fields to make changes in forms */ -$('#page_content').live("keyup", "input[type='text']:visible", AJAX.inputAltered); +$(document).on( + 'keyup change', + '#page_content form.lock-page textarea, ' + + '#page_content form.lock-page input[type="text"]', + AJAX.lockPageHandler +); /** * Gracefully handle fatal server errors diff --git a/js/messages.php b/js/messages.php index 9e3e86456c..1f3c1edb85 100644 --- a/js/messages.php +++ b/js/messages.php @@ -43,7 +43,7 @@ $js_messages['strDroppingPrimaryKeyIndex'] = __('Dropping Primary Key/Index'); $js_messages['strOperationTakesLongTime'] = __('This operation could take a long time. Proceed anyway?'); $js_messages['strDropUserGroupWarning'] = __('Do you really want to delete user group "%s"?'); $js_messages['strConfirmDeleteQBESearch'] = __('Do you really want to delete the search "%s"?'); -$js_messages['strConfirmNavigation'] = __('Are you sure you want to navigate away from this page? Press OK to continue or Cancel to stay on the current page.'); +$js_messages['strConfirmNavigation'] = __('You have unsaved changes; are you sure you want to leave this page?'); /* For indexes */ $js_messages['strFormEmpty'] = __('Missing value in the form!'); diff --git a/js/tbl_change.js b/js/tbl_change.js index b6efac1c9e..3a9111e96a 100644 --- a/js/tbl_change.js +++ b/js/tbl_change.js @@ -249,8 +249,6 @@ function verificationsAfterFieldChange(urlField, multi_edit, theType) * Unbind all event handlers before tearing down a page */ AJAX.registerTeardown('tbl_change.js', function () { - $("a").die('click'); - $("form#insertForm :input:not([type=hidden])").unbind('change'); $('span.open_gis_editor').die('click'); $("input[name='gis_data[save]']").die('click'); $('input.checkbox_null').die('click'); @@ -259,7 +257,6 @@ AJAX.registerTeardown('tbl_change.js', function () { $("select[name*='funcs']").die('click'); }); - /** * Ajax handlers for Change Table page * @@ -270,35 +267,6 @@ AJAX.registerTeardown('tbl_change.js', function () { AJAX.registerOnload('tbl_change.js', function () { $.datepicker.initialized = false; - // State of the form - var $unsavedForm = false; - - /** - * If user navigates away from the page - * without saving the changes, a prompt - * will be displayed to confirm navigation - */ - $('a').on('click', function(e){ - e.preventDefault(); - - if ($unsavedForm) { - var is_confirmed = confirm(PMA_messages.strConfirmNavigation); - if (! is_confirmed) { - return false; - } else { - unsavedForm = false; - return true; - } - } - }); - - /** - * If any form elements are changed, set $unsavedForm to true - */ - $("form#insertForm :input:not([type=hidden])").change(function(){ - $unsavedForm = true; - }); - $('span.open_gis_editor').live('click', function (event) { event.preventDefault(); diff --git a/libraries/Header.class.php b/libraries/Header.class.php index 3a237dccd2..af3f2d22b5 100644 --- a/libraries/Header.class.php +++ b/libraries/Header.class.php @@ -402,6 +402,7 @@ class PMA_Header $retval .= $this->_getWarnings(); if ($this->_menuEnabled && $GLOBALS['server'] > 0) { $retval .= $this->_menu->getDisplay(); + $retval .= ''; $retval .= sprintf( '%s', __('Click on the bar to scroll to top of page'), diff --git a/libraries/TableSearch.class.php b/libraries/TableSearch.class.php index 0e44043275..aa3f29dcf5 100644 --- a/libraries/TableSearch.class.php +++ b/libraries/TableSearch.class.php @@ -1149,7 +1149,7 @@ EOT; $html_output .= '