/* 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 + '&token=' + encodeURIComponent(PMA_commonParams.get('token'));
} else if (typeof options.data === 'object') {
options.data = $.extend(originalOptions.data, { '_nocache' : nocache, 'token': PMA_commonParams.get('token') });
}
});
/*
* 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;
}
// Getting the current Date and time
var currentDateTime = new Date();
var defaultOptions = {
timeInput : true,
hour: currentDateTime.getHours(),
minute: currentDateTime.getMinutes(),
second: currentDateTime.getSeconds(),
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);
}
setTimeout(function () {
// Fix wrong timepicker z-index, doesn't work without timeout
$('#ui-timepicker-div').css('z-index', $('#ui-datepicker-div').css('z-index'));
// Integrate tooltip text into dialog
var tooltip = $this_element.tooltip('instance');
if (typeof tooltip !== 'undefined') {
tooltip.disable();
var $note = $('
');
$note.text(tooltip.option('content'));
$('div.ui-datepicker').append($note);
}
}, 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;
}
var tooltip = $this_element.tooltip('instance');
if (typeof tooltip !== 'undefined') {
tooltip.enable();
}
}
};
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.strMysqlAllowedValuesTipTime);
} else {
$this_element.datetimepicker($.extend(defaultOptions, options));
}
}
/**
* 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';
var hourMax = 23;
// 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';
}
}
if (type === 'time') {
hourMax = 99;
}
PMA_addDatepicker($(this), type, {
showMillisec: showMillisec,
showMicrosec: showMicrosec,
timeFormat: timeFormat,
hourMax: hourMax
});
// 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 += PMA_commonParams.get('arg_separator') + 'session_expired=1';
}
window.location.reload();
} else if (parseInt(data.reload_flag) === 1) {
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);
// page locking
codemirrorEditor.on('change', function (e) {
e.data = {
value: 3,
content: codemirrorEditor.isClean(),
};
AJAX.lockPageHandler(e);
});
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('\x00', '')
.replace('\\', '\\\\')
.replace('\'', '\\\'')
.replace(''', '\\\'')
.replace('"', '\"')
.replace('"', '\"')
.replace('\n', '\n')
.replace('\r', '\r')
.replace(/<\/script/gi, '\' + \'script');
} else {
return false;
}
}
function escapeBacktick (s) {
return s.replace('`', '``');
}
function escapeSingleQuote (s) {
return s.replace('\\', '\\\\').replace('\'', '\\\'');
}
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);
} else if (window.msCrypto && window.msCrypto.getRandomValues) {
// Because of course IE calls it msCrypto instead of being standard
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://www.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);
if (typeof version_info !== 'undefined') {
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'),
'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 PhpMyAdmin\Display\ChangePassword
* libraries/user_password.php
*
*/
function displayPasswordGenerateButton () {
var generatePwdRow = $('
').addClass('vmiddle');
var titleCell = $('
').html(PMA_messages.strGeneratePassword).appendTo(generatePwdRow);
var pwdCell = $('
').appendTo(generatePwdRow);
var pwdButton = $('')
.attr({ type: 'button', id: 'button_generate_password', value: PMA_messages.strGenerate })
.addClass('button')
.on('click', function () {
suggestPassword(this.form);
});
var pwdTextbox = $('')
.attr({ type: 'text', name: 'generated_pw', id: 'generated_pw' });
pwdCell.append(pwdButton).append(pwdTextbox);
if (document.getElementById('button_generate_password') === null) {
$('#tr_element_before_generate_password').parent().append(generatePwdRow);
}
var generatePwdDiv = $('').addClass('item');
var titleLabel = $('').attr({ for: 'button_generate_password' })
.html(PMA_messages.strGeneratePassword + ':')
.appendTo(generatePwdDiv);
var optionsSpan = $('').addClass('options')
.appendTo(generatePwdDiv);
pwdButton.clone(true).appendTo(optionsSpan);
pwdTextbox.clone(true).appendTo(generatePwdDiv);
if (document.getElementById('button_generate_password') === null) {
$('#div_element_before_generate_password').parent().append(generatePwdDiv);
}
}
/**
* 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 (typeof(theLink.href) !== 'undefined') {
theLink.href += PMA_commonParams.get('arg_separator') + '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;
} else {
// statement is rejected -> do not submit the form
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;
}
if (isNaN(val)) {
theField.select();
alert(PMA_messages.strEnterValidNumber);
theField.focus();
return false;
} else if (val < min || val > max) {
theField.select();
alert(PMA_sprintf(message, val));
theField.focus();
return false;
} 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;
var elm;
var elm2;
var elm3;
var val;
var 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,
'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('tbody tr:not(.noclick)').index($tr) : -1;
last_shift_clicked_row = -1;
} else {
// handle the shift click
PMA_clearSelection();
var start;
var 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('tbody 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');
}
});
/**
* Checks/unchecks all options of a