/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* general function, usually for data manipulation pages
*
*/
/**
* @var sql_box_locked lock for the sqlbox textarea in the querybox
*/
var sql_box_locked = false;
/**
* @var array holds elements which content should only selected once
*/
var only_once_elements = [];
/**
* @var int ajax_message_count Number of AJAX messages shown since page load
*/
var ajax_message_count = 0;
/**
* @var codemirror_editor object containing CodeMirror editor of the query editor in SQL tab
*/
var codemirror_editor = false;
/**
* @var codemirror_editor object containing CodeMirror editor of the inline query editor
*/
var codemirror_inline_editor = false;
/**
* @var sql_autocomplete_in_progress bool shows if Table/Column name autocomplete AJAX is in progress
*/
var sql_autocomplete_in_progress = false;
/**
* @var sql_autocomplete object containing list of columns in each table
*/
var sql_autocomplete = false;
/**
* @var sql_autocomplete_default_table string containing default table to autocomplete columns
*/
var sql_autocomplete_default_table = '';
/**
* @var central_column_list array to hold the columns in central list per db.
*/
var central_column_list = [];
/**
* @var primary_indexes array to hold 'Primary' index columns.
*/
var primary_indexes = [];
/**
* @var unique_indexes array to hold 'Unique' index columns.
*/
var unique_indexes = [];
/**
* @var indexes array to hold 'Index' columns.
*/
var indexes = [];
/**
* @var fulltext_indexes array to hold 'Fulltext' columns.
*/
var fulltext_indexes = [];
/**
* @var spatial_indexes array to hold 'Spatial' columns.
*/
var spatial_indexes = [];
/**
* Make sure that ajax requests will not be cached
* by appending a random variable to their parameters
*/
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var nocache = new Date().getTime() + "" + Math.floor(Math.random() * 1000000);
if (typeof options.data == "string") {
options.data += "&_nocache=" + nocache;
} else if (typeof options.data == "object") {
options.data = $.extend(originalOptions.data, {'_nocache' : nocache});
}
});
/*
* Adds a date/time picker to an element
*
* @param object $this_element a jQuery object pointing to the element
*/
function PMA_addDatepicker($this_element, type, options)
{
var showTimepicker = true;
if (type=="date") {
showTimepicker = false;
}
var defaultOptions = {
showOn: 'button',
buttonImage: themeCalendarImage, // defined in js/messages.php
buttonImageOnly: true,
stepMinutes: 1,
stepHours: 1,
showSecond: true,
showMillisec: true,
showMicrosec: true,
showTimepicker: showTimepicker,
showButtonPanel: false,
dateFormat: 'yy-mm-dd', // yy means year with four digits
timeFormat: 'HH:mm:ss.lc',
constrainInput: false,
altFieldTimeOnly: false,
showAnim: '',
beforeShow: function (input, inst) {
// Remember that we came from the datepicker; this is used
// in tbl_change.js by verificationsAfterFieldChange()
$this_element.data('comes_from', 'datepicker');
if ($(input).closest('.cEdit').length > 0) {
setTimeout(function () {
inst.dpDiv.css({
top: 0,
left: 0,
position: 'relative'
});
}, 0);
}
// Fix wrong timepicker z-index, doesn't work without timeout
setTimeout(function () {
$('#ui-timepicker-div').css('z-index', $('#ui-datepicker-div').css('z-index'));
}, 0);
},
onSelect: function() {
$this_element.data('datepicker').inline = true;
},
onClose: function (dateText, dp_inst) {
// The value is no more from the date picker
$this_element.data('comes_from', '');
if (typeof $this_element.data('datepicker') !== 'undefined') {
$this_element.data('datepicker').inline = false;
}
}
};
if (type == "datetime" || type == "timestamp") {
$this_element.datetimepicker($.extend(defaultOptions, options));
}
else if (type == "date") {
$this_element.datetimepicker($.extend(defaultOptions, options));
}
else if (type == "time") {
$this_element.timepicker($.extend(defaultOptions, options));
// Add a tip regarding entering MySQL allowed-values for TIME data-type
PMA_tooltip($this_element, 'input', PMA_messages.strMysqlAllowedValuesTip);
}
}
/**
* Add a date/time picker to each element that needs it
* (only when jquery-ui-timepicker-addon.js is loaded)
*/
function addDateTimePicker() {
if ($.timepicker !== undefined) {
$('input.timefield, input.datefield, input.datetimefield').each(function () {
var decimals = $(this).parent().attr('data-decimals');
var type = $(this).parent().attr('data-type');
var showMillisec = false;
var showMicrosec = false;
var timeFormat = 'HH:mm:ss';
// check for decimal places of seconds
if (decimals > 0 && type.indexOf('time') != -1){
if (decimals > 3) {
showMillisec = true;
showMicrosec = true;
timeFormat = 'HH:mm:ss.lc';
} else {
showMillisec = true;
timeFormat = 'HH:mm:ss.l';
}
}
PMA_addDatepicker($(this), type, {
showMillisec: showMillisec,
showMicrosec: showMicrosec,
timeFormat: timeFormat
});
// Add a tip regarding entering MySQL allowed-values
// for TIME and DATE data-type
if ($(this).hasClass('timefield')) {
PMA_tooltip($(this), 'input', PMA_messages.strMysqlAllowedValuesTipTime);
} else if ($(this).hasClass('datefield')) {
PMA_tooltip($(this), 'input', PMA_messages.strMysqlAllowedValuesTipDate);
}
});
}
}
/**
* Handle redirect and reload flags sent as part of AJAX requests
*
* @param data ajax response data
*/
function PMA_handleRedirectAndReload(data) {
if (parseInt(data.redirect_flag) == 1) {
// add one more GET param to display session expiry msg
if (window.location.href.indexOf('?') === -1) {
window.location.href += '?session_expired=1';
} else {
window.location.href += '&session_expired=1';
}
window.location.reload();
} else if (parseInt(data.reload_flag) == 1) {
// remove the token param and reload
window.location.href = window.location.href.replace(/&?token=[^]*/g, "");
window.location.reload();
}
}
/**
* Creates an SQL editor which supports auto completing etc.
*
* @param $textarea jQuery object wrapping the textarea to be made the editor
* @param options optional options for CodeMirror
* @param resize optional resizing ('vertical', 'horizontal', 'both')
* @param lintOptions additional options for lint
*/
function PMA_getSQLEditor($textarea, options, resize, lintOptions) {
if ($textarea.length > 0 && typeof CodeMirror !== 'undefined') {
// merge options for CodeMirror
var defaults = {
lineNumbers: true,
matchBrackets: true,
extraKeys: {"Ctrl-Space": "autocomplete"},
hintOptions: {"completeSingle": false, "completeOnSingleClick": true},
indentUnit: 4,
mode: "text/x-mysql",
lineWrapping: true
};
if (CodeMirror.sqlLint) {
$.extend(defaults, {
gutters: ["CodeMirror-lint-markers"],
lint: {
"getAnnotations": CodeMirror.sqlLint,
"async": true,
"lintOptions": lintOptions
}
});
}
$.extend(true, defaults, options);
// create CodeMirror editor
var codemirrorEditor = CodeMirror.fromTextArea($textarea[0], defaults);
// allow resizing
if (! resize) {
resize = 'vertical';
}
var handles = '';
if (resize == 'vertical') {
handles = 's';
}
if (resize == 'both') {
handles = 'all';
}
if (resize == 'horizontal') {
handles = 'e, w';
}
$(codemirrorEditor.getWrapperElement())
.css('resize', resize)
.resizable({
handles: handles,
resize: function() {
codemirrorEditor.setSize($(this).width(), $(this).height());
}
});
// enable autocomplete
codemirrorEditor.on("inputRead", codemirrorAutocompleteOnInputRead);
return codemirrorEditor;
}
return null;
}
/**
* Clear text selection
*/
function PMA_clearSelection() {
if (document.selection && document.selection.empty) {
document.selection.empty();
} else if (window.getSelection) {
var sel = window.getSelection();
if (sel.empty) {
sel.empty();
}
if (sel.removeAllRanges) {
sel.removeAllRanges();
}
}
}
/**
* Create a jQuery UI tooltip
*
* @param $elements jQuery object representing the elements
* @param item the item
* (see https://api.jqueryui.com/tooltip/#option-items)
* @param myContent content of the tooltip
* @param additionalOptions to override the default options
*
*/
function PMA_tooltip($elements, item, myContent, additionalOptions)
{
if ($('#no_hint').length > 0) {
return;
}
var defaultOptions = {
content: myContent,
items: item,
tooltipClass: "tooltip",
track: true,
show: false,
hide: false
};
$elements.tooltip($.extend(true, defaultOptions, additionalOptions));
}
/**
* HTML escaping
*/
function escapeHtml(unsafe) {
if (typeof(unsafe) != 'undefined') {
return unsafe
.toString()
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
} else {
return false;
}
}
function escapeJsString(unsafe) {
if (typeof(unsafe) != 'undefined') {
return unsafe
.toString()
.replace("\000", '')
.replace('\\', '\\\\')
.replace('\'', '\\\'')
.replace("'", "\\\'")
.replace('"', '\"')
.replace(""", "\"")
.replace("\n", '\n')
.replace("\r", '\r')
.replace(/<\/script/gi, '\' + \'script')
} else {
return false;
}
}
function PMA_sprintf() {
return sprintf.apply(this, arguments);
}
/**
* Hides/shows the default value input field, depending on the default type
* Ticks the NULL checkbox if NULL is chosen as default value.
*/
function PMA_hideShowDefaultValue($default_type)
{
if ($default_type.val() == 'USER_DEFINED') {
$default_type.siblings('.default_value').show().focus();
} else {
$default_type.siblings('.default_value').hide();
if ($default_type.val() == 'NULL') {
var $null_checkbox = $default_type.closest('tr').find('.allow_null');
$null_checkbox.prop('checked', true);
}
}
}
/**
* Hides/shows the input field for column expression based on whether
* VIRTUAL/PERSISTENT is selected
*
* @param $virtuality virtuality dropdown
*/
function PMA_hideShowExpression($virtuality)
{
if ($virtuality.val() === '') {
$virtuality.siblings('.expression').hide();
} else {
$virtuality.siblings('.expression').show();
}
}
/**
* Show notices for ENUM columns; add/hide the default value
*
*/
function PMA_verifyColumnsProperties()
{
$("select.column_type").each(function () {
PMA_showNoticeForEnum($(this));
});
$("select.default_type").each(function () {
PMA_hideShowDefaultValue($(this));
});
$('select.virtuality').each(function () {
PMA_hideShowExpression($(this));
});
}
/**
* Add a hidden field to the form to indicate that this will be an
* Ajax request (only if this hidden field does not exist)
*
* @param $form object the form
*/
function PMA_prepareForAjaxRequest($form)
{
if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
$form.append('');
}
}
/**
* Generate a new password and copy it to the password input areas
*
* @param passwd_form object the form that holds the password fields
*
* @return boolean always true
*/
function suggestPassword(passwd_form)
{
// restrict the password to just letters and numbers to avoid problems:
// "editors and viewers regard the password as multiple words and
// things like double click no longer work"
var pwchars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWYXZ";
var passwordlength = 16; // do we want that to be dynamic? no, keep it simple :)
var passwd = passwd_form.generated_pw;
var randomWords = new Int32Array(passwordlength);
passwd.value = '';
// First we're going to try to use a built-in CSPRNG
if (window.crypto && window.crypto.getRandomValues) {
window.crypto.getRandomValues(randomWords);
}
// Because of course IE calls it msCrypto instead of being standard
else if (window.msCrypto && window.msCrypto.getRandomValues) {
window.msCrypto.getRandomValues(randomWords);
} else {
// Fallback to Math.random
for (var i = 0; i < passwordlength; i++) {
randomWords[i] = Math.floor(Math.random() * pwchars.length);
}
}
for (var i = 0; i < passwordlength; i++) {
passwd.value += pwchars.charAt(Math.abs(randomWords[i]) % pwchars.length);
}
$jquery_passwd_form = $(passwd_form);
passwd_form.elements['pma_pw'].value = passwd.value;
passwd_form.elements['pma_pw2'].value = passwd.value;
meter_obj = $jquery_passwd_form.find('meter[name="pw_meter"]').first();
meter_obj_label = $jquery_passwd_form.find('span[name="pw_strength"]').first();
checkPasswordStrength(passwd.value, meter_obj, meter_obj_label);
return true;
}
/**
* Version string to integer conversion.
*/
function parseVersionString(str)
{
if (typeof(str) != 'string') { return false; }
var add = 0;
// Parse possible alpha/beta/rc/
var state = str.split('-');
if (state.length >= 2) {
if (state[1].substr(0, 2) == 'rc') {
add = - 20 - parseInt(state[1].substr(2), 10);
} else if (state[1].substr(0, 4) == 'beta') {
add = - 40 - parseInt(state[1].substr(4), 10);
} else if (state[1].substr(0, 5) == 'alpha') {
add = - 60 - parseInt(state[1].substr(5), 10);
} else if (state[1].substr(0, 3) == 'dev') {
/* We don't handle dev, it's git snapshot */
add = 0;
}
}
// Parse version
var x = str.split('.');
// Use 0 for non existing parts
var maj = parseInt(x[0], 10) || 0;
var min = parseInt(x[1], 10) || 0;
var pat = parseInt(x[2], 10) || 0;
var hotfix = parseInt(x[3], 10) || 0;
return maj * 100000000 + min * 1000000 + pat * 10000 + hotfix * 100 + add;
}
/**
* Indicates current available version on main page.
*/
function PMA_current_version(data)
{
if (data && data.version && data.date) {
var current = parseVersionString($('span.version').text());
var latest = parseVersionString(data.version);
var url = 'https://web.phpmyadmin.net/files/' + escapeHtml(encodeURIComponent(data.version)) + '/';
var version_information_message = document.createElement('span');
version_information_message.className = 'latest';
var version_information_message_link = document.createElement('a');
version_information_message_link.href = url;
version_information_message_link.className = 'disableAjax';
version_information_message_link_text = document.createTextNode(data.version);
version_information_message_link.appendChild(version_information_message_link_text);
var prefix_message = document.createTextNode(PMA_messages.strLatestAvailable + ' ');
version_information_message.appendChild(prefix_message);
version_information_message.appendChild(version_information_message_link);
if (latest > current) {
var message = PMA_sprintf(
PMA_messages.strNewerVersion,
escapeHtml(data.version),
escapeHtml(data.date)
);
var htmlClass = 'notice';
if (Math.floor(latest / 10000) === Math.floor(current / 10000)) {
/* Security update */
htmlClass = 'error';
}
$('#newer_version_notice').remove();
var maincontainer_div = document.createElement('div');
maincontainer_div.id = 'newer_version_notice';
maincontainer_div.className = htmlClass;
var maincontainer_div_link = document.createElement('a');
maincontainer_div_link.href = url;
maincontainer_div_link.className = 'disableAjax';
maincontainer_div_link_text = document.createTextNode(message);
maincontainer_div_link.appendChild(maincontainer_div_link_text);
maincontainer_div.appendChild(maincontainer_div_link);
$('#maincontainer').append($(maincontainer_div));
}
if (latest === current) {
version_information_message = document.createTextNode(' (' + PMA_messages.strUpToDate + ')');
}
/* Remove extra whitespace */
var version_info = $('#li_pma_version').contents().get(2);
version_info.textContent = $.trim(version_info.textContent);
var $liPmaVersion = $('#li_pma_version');
$liPmaVersion.find('span.latest').remove();
$liPmaVersion.append($(version_information_message));
}
}
/**
* Loads Git revision data from ajax for index.php
*/
function PMA_display_git_revision()
{
$('#is_git_revision').remove();
$('#li_pma_version_git').remove();
$.get(
"index.php",
{
"server": PMA_commonParams.get('server'),
"token": PMA_commonParams.get('token'),
"git_revision": true,
"ajax_request": true,
"no_debug": true
},
function (data) {
if (typeof data !== 'undefined' && data.success === true) {
$(data.message).insertAfter('#li_pma_version');
}
}
);
}
/**
* for libraries/display_change_password.lib.php
* libraries/user_password.php
*
*/
function displayPasswordGenerateButton()
{
$('#tr_element_before_generate_password').parent().append('
');
}
/**
* selects the content of a given object, f.e. a textarea
*
* @param element object element of which the content will be selected
* @param lock var variable which holds the lock for this element
* or true, if no lock exists
* @param only_once boolean if true this is only done once
* f.e. only on first focus
*/
function selectContent(element, lock, only_once)
{
if (only_once && only_once_elements[element.name]) {
return;
}
only_once_elements[element.name] = true;
if (lock) {
return;
}
element.select();
}
/**
* Displays a confirmation box before submitting a "DROP/DELETE/ALTER" query.
* This function is called while clicking links
*
* @param theLink object the link
* @param theSqlQuery object the sql query to submit
*
* @return boolean whether to run the query or not
*/
function confirmLink(theLink, theSqlQuery)
{
// Confirmation is not required in the configuration file
// or browser is Opera (crappy js implementation)
if (PMA_messages.strDoYouReally === '' || typeof(window.opera) != 'undefined') {
return true;
}
var is_confirmed = confirm(PMA_sprintf(PMA_messages.strDoYouReally, theSqlQuery));
if (is_confirmed) {
if ($(theLink).hasClass('formLinkSubmit')) {
var name = 'is_js_confirmed';
if ($(theLink).attr('href').indexOf('usesubform') != -1) {
var matches = $(theLink).attr('href').substr('#').match(/usesubform\[(\d+)\]/i);
if (matches != null) {
name = 'subform[' + matches[1] + '][is_js_confirmed]';
}
}
$(theLink).parents('form').append('');
} else if (typeof(theLink.href) != 'undefined') {
theLink.href += '&is_js_confirmed=1';
} else if (typeof(theLink.form) != 'undefined') {
theLink.form.action += '?is_js_confirmed=1';
}
}
return is_confirmed;
} // end of the 'confirmLink()' function
/**
* Confirms a "DROP/DELETE/ALTER" query before
* submitting it if required.
* This function is called by the 'checkSqlQuery()' js function.
*
* @param theForm1 object the form
* @param sqlQuery1 string the sql query string
*
* @return boolean whether to run the query or not
*
* @see checkSqlQuery()
*/
function confirmQuery(theForm1, sqlQuery1)
{
// Confirmation is not required in the configuration file
if (PMA_messages.strDoYouReally === '') {
return true;
}
// Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
//
// TODO: find a way (if possible) to use the parser-analyser
// for this kind of verification
// For now, I just added a ^ to check for the statement at
// beginning of expression
var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|PROCEDURE)\\s', 'i');
var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
if (do_confirm_re_0.test(sqlQuery1) ||
do_confirm_re_1.test(sqlQuery1) ||
do_confirm_re_2.test(sqlQuery1) ||
do_confirm_re_3.test(sqlQuery1)) {
var message;
if (sqlQuery1.length > 100) {
message = sqlQuery1.substr(0, 100) + '\n ...';
} else {
message = sqlQuery1;
}
var is_confirmed = confirm(PMA_sprintf(PMA_messages.strDoYouReally, message));
// statement is confirmed -> update the
// "is_js_confirmed" form field so the confirm test won't be
// run on the server side and allows to submit the form
if (is_confirmed) {
theForm1.elements.is_js_confirmed.value = 1;
return true;
}
// statement is rejected -> do not submit the form
else {
window.focus();
return false;
} // end if (handle confirm box result)
} // end if (display confirm box)
return true;
} // end of the 'confirmQuery()' function
/**
* Displays an error message if the user submitted the sql query form with no
* sql query, else checks for "DROP/DELETE/ALTER" statements
*
* @param theForm object the form
*
* @return boolean always false
*
* @see confirmQuery()
*/
function checkSqlQuery(theForm)
{
// get the textarea element containing the query
var sqlQuery;
if (codemirror_editor) {
codemirror_editor.save();
sqlQuery = codemirror_editor.getValue();
} else {
sqlQuery = theForm.elements.sql_query.value;
}
var space_re = new RegExp('\\s+');
if (typeof(theForm.elements.sql_file) != 'undefined' &&
theForm.elements.sql_file.value.replace(space_re, '') !== '') {
return true;
}
if (typeof(theForm.elements.id_bookmark) != 'undefined' &&
(theForm.elements.id_bookmark.value !== null || theForm.elements.id_bookmark.value !== '') &&
theForm.elements.id_bookmark.selectedIndex !== 0) {
return true;
}
var result = false;
// Checks for "DROP/DELETE/ALTER" statements
if (sqlQuery.replace(space_re, '') !== '') {
result = confirmQuery(theForm, sqlQuery);
} else {
alert(PMA_messages.strFormEmpty);
}
if (codemirror_editor) {
codemirror_editor.focus();
} else if (codemirror_inline_editor) {
codemirror_inline_editor.focus();
}
return result;
} // end of the 'checkSqlQuery()' function
/**
* Check if a form's element is empty.
* An element containing only spaces is also considered empty
*
* @param object the form
* @param string the name of the form field to put the focus on
*
* @return boolean whether the form field is empty or not
*/
function emptyCheckTheField(theForm, theFieldName)
{
var theField = theForm.elements[theFieldName];
var space_re = new RegExp('\\s+');
return theField.value.replace(space_re, '') === '';
} // end of the 'emptyCheckTheField()' function
/**
* Ensures a value submitted in a form is numeric and is in a range
*
* @param object the form
* @param string the name of the form field to check
* @param integer the minimum authorized value
* @param integer the maximum authorized value
*
* @return boolean whether a valid number has been submitted or not
*/
function checkFormElementInRange(theForm, theFieldName, message, min, max)
{
var theField = theForm.elements[theFieldName];
var val = parseInt(theField.value, 10);
if (typeof(min) == 'undefined') {
min = 0;
}
if (typeof(max) == 'undefined') {
max = Number.MAX_VALUE;
}
// It's not a number
if (isNaN(val)) {
theField.select();
alert(PMA_messages.strEnterValidNumber);
theField.focus();
return false;
}
// It's a number but it is not between min and max
else if (val < min || val > max) {
theField.select();
alert(PMA_sprintf(message, val));
theField.focus();
return false;
}
// It's a valid number
else {
theField.value = val;
}
return true;
} // end of the 'checkFormElementInRange()' function
function checkTableEditForm(theForm, fieldsCnt)
{
// TODO: avoid sending a message if user just wants to add a line
// on the form but has not completed at least one field name
var atLeastOneField = 0;
var i, elm, elm2, elm3, val, id;
for (i = 0; i < fieldsCnt; i++) {
id = "#field_" + i + "_2";
elm = $(id);
val = elm.val();
if (val == 'VARCHAR' || val == 'CHAR' || val == 'BIT' || val == 'VARBINARY' || val == 'BINARY') {
elm2 = $("#field_" + i + "_3");
val = parseInt(elm2.val(), 10);
elm3 = $("#field_" + i + "_1");
if (isNaN(val) && elm3.val() !== "") {
elm2.select();
alert(PMA_messages.strEnterValidLength);
elm2.focus();
return false;
}
}
if (atLeastOneField === 0) {
id = "field_" + i + "_1";
if (!emptyCheckTheField(theForm, id)) {
atLeastOneField = 1;
}
}
}
if (atLeastOneField === 0) {
var theField = theForm.elements.field_0_1;
alert(PMA_messages.strFormEmpty);
theField.focus();
return false;
}
// at least this section is under jQuery
var $input = $("input.textfield[name='table']");
if ($input.val() === "") {
alert(PMA_messages.strFormEmpty);
$input.focus();
return false;
}
return true;
} // enf of the 'checkTableEditForm()' function
/**
* True if last click is to check a row.
*/
var last_click_checked = false;
/**
* Zero-based index of last clicked row.
* Used to handle the shift + click event in the code above.
*/
var last_clicked_row = -1;
/**
* Zero-based index of last shift clicked row.
*/
var last_shift_clicked_row = -1;
var _idleSecondsCounter = 0;
var IncInterval;
var updateTimeout;
AJAX.registerTeardown('functions.js', function () {
clearTimeout(updateTimeout);
clearInterval(IncInterval);
$(document).off('mousemove');
});
AJAX.registerOnload('functions.js', function () {
document.onclick = function() {
_idleSecondsCounter = 0;
};
$(document).on('mousemove',function() {
_idleSecondsCounter = 0;
});
document.onkeypress = function() {
_idleSecondsCounter = 0;
};
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
function SetIdleTime() {
_idleSecondsCounter++;
}
function UpdateIdleTime() {
var href = 'index.php';
var guid = 'default';
if (isStorageSupported('sessionStorage')) {
guid = window.sessionStorage.guid;
}
var params = {
'ajax_request' : true,
'token' : PMA_commonParams.get('token'),
'server' : PMA_commonParams.get('server'),
'db' : PMA_commonParams.get('db'),
'guid': guid,
'access_time':_idleSecondsCounter
};
$.ajax({
type: 'POST',
url: href,
data: params,
success: function (data) {
if (data.success) {
if (PMA_commonParams.get('LoginCookieValidity') - _idleSecondsCounter < 0) {
/* There is other active window, let's reset counter */
_idleSecondsCounter = 0;
}
var remaining = Math.min(
/* Remaining login validity */
PMA_commonParams.get('LoginCookieValidity') - _idleSecondsCounter,
/* Remaining time till session GC */
PMA_commonParams.get('session_gc_maxlifetime')
);
var interval = 1000;
if (remaining > 5) {
// max value for setInterval() function
interval = Math.min((remaining - 1) * 1000, Math.pow(2, 31) - 1);
}
updateTimeout = window.setTimeout(UpdateIdleTime, interval);
} else { //timeout occurred
clearInterval(IncInterval);
if (isStorageSupported('sessionStorage')){
window.sessionStorage.clear();
}
window.location.reload(true);
}
}
});
}
if (PMA_commonParams.get('logged_in')) {
IncInterval = window.setInterval(SetIdleTime, 1000);
var session_timeout = Math.min(
PMA_commonParams.get('LoginCookieValidity'),
PMA_commonParams.get('session_gc_maxlifetime')
);
if (isStorageSupported('sessionStorage')) {
window.sessionStorage.setItem('guid', guid());
}
var interval = (session_timeout - 5) * 1000;
if (interval > Math.pow(2, 31) - 1) { // max value for setInterval() function
interval = Math.pow(2, 31) - 1;
}
updateTimeout = window.setTimeout(UpdateIdleTime, interval);
}
});
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', 'input:checkbox.checkall');
});
AJAX.registerOnload('functions.js', function () {
/**
* Row marking in horizontal mode (use "on" so that it works also for
* next pages reached via AJAX); a tr may have the class noclick to remove
* this behavior.
*/
$(document).on('click', 'input:checkbox.checkall', function (e) {
$this = $(this);
var $tr = $this.closest('tr');
var $table = $this.closest('table');
if (!e.shiftKey || last_clicked_row == -1) {
// usual click
var $checkbox = $tr.find(':checkbox.checkall');
var checked = $this.prop('checked');
$checkbox.prop('checked', checked).trigger('change');
if (checked) {
$tr.addClass('marked');
} else {
$tr.removeClass('marked');
}
last_click_checked = checked;
// remember the last clicked row
last_clicked_row = last_click_checked ? $table.find('tr:not(.noclick)').index($tr) : -1;
last_shift_clicked_row = -1;
} else {
// handle the shift click
PMA_clearSelection();
var start, end;
// clear last shift click result
if (last_shift_clicked_row >= 0) {
if (last_shift_clicked_row >= last_clicked_row) {
start = last_clicked_row;
end = last_shift_clicked_row;
} else {
start = last_shift_clicked_row;
end = last_clicked_row;
}
$tr.parent().find('tr:not(.noclick)')
.slice(start, end + 1)
.removeClass('marked')
.find(':checkbox')
.prop('checked', false)
.trigger('change');
}
// handle new shift click
var curr_row = $table.find('tr:not(.noclick)').index($tr);
if (curr_row >= last_clicked_row) {
start = last_clicked_row;
end = curr_row;
} else {
start = curr_row;
end = last_clicked_row;
}
$tr.parent().find('tr:not(.noclick)')
.slice(start, end + 1)
.addClass('marked')
.find(':checkbox')
.prop('checked', true)
.trigger('change');
// remember the last shift clicked row
last_shift_clicked_row = curr_row;
}
});
addDateTimePicker();
/**
* Add attribute to text boxes for iOS devices (based on bugID: 3508912)
*/
if (navigator.userAgent.match(/(iphone|ipod|ipad)/i)) {
$('input[type=text]').attr('autocapitalize', 'off').attr('autocorrect', 'off');
}
});
/**
* Row highlighting in horizontal mode (use "on"
* so that it works also for pages reached via AJAX)
*/
/*AJAX.registerOnload('functions.js', function () {
$(document).on('hover', 'tr',function (event) {
var $tr = $(this);
$tr.toggleClass('hover',event.type=='mouseover');
$tr.children().toggleClass('hover',event.type=='mouseover');
});
})*/
/**
* marks all rows and selects its first checkbox inside the given element
* the given element is usually a table or a div containing the table or tables
*
* @param container DOM element
*/
function markAllRows(container_id)
{
$("#" + container_id).find("input:checkbox:enabled").prop('checked', true)
.trigger("change")
.parents("tr").addClass("marked");
return true;
}
/**
* marks all rows and selects its first checkbox inside the given element
* the given element is usually a table or a div containing the table or tables
*
* @param container DOM element
*/
function unMarkAllRows(container_id)
{
$("#" + container_id).find("input:checkbox:enabled").prop('checked', false)
.trigger("change")
.parents("tr").removeClass("marked");
return true;
}
/**
* Checks/unchecks all options of a