/usr/share/phpmyadmin/js/src
Edit: /usr/share/phpmyadmin/js/src/functions.js (180908B)
/* global isStorageSupported */ // js/config.js
/* global ChartType, ColumnType, DataTable, JQPlotChartFactory */ // js/chart.js
/* global DatabaseStructure */ // js/database/structure.js
/* global mysqlDocBuiltin, mysqlDocKeyword */ // js/doclinks.js
/* global Indexes */ // js/indexes.js
/* global firstDayOfCalendar, maxInputVars, mysqlDocTemplate, themeImagePath */ // templates/javascript/variables.twig
/* global MicroHistory */ // js/microhistory.js
/* global sprintf */ // js/vendor/sprintf.js
/* global zxcvbn */ // js/vendor/zxcvbn.js
/**
* general function, usually for data manipulation pages
*
*/
var Functions = {};
/**
* @var sqlBoxLocked lock for the sqlbox textarea in the querybox
*/
var sqlBoxLocked = false;
/**
* @var {array} holds elements which content should only selected once
*/
var onlyOnceElements = [];
/**
* @var {int} ajaxMessageCount Number of AJAX messages shown since page load
*/
var ajaxMessageCount = 0;
/**
* @var codeMirrorEditor object containing CodeMirror editor of the query editor in SQL tab
*/
var codeMirrorEditor = false;
/**
* @var codeMirrorInlineEditor object containing CodeMirror editor of the inline query editor
*/
var codeMirrorInlineEditor = false;
/**
* @var {boolean} sqlAutoCompleteInProgress shows if Table/Column name autocomplete AJAX is in progress
*/
var sqlAutoCompleteInProgress = false;
/**
* @var sqlAutoComplete object containing list of columns in each table
*/
var sqlAutoComplete = false;
/**
* @var {string} sqlAutoCompleteDefaultTable string containing default table to autocomplete columns
*/
var sqlAutoCompleteDefaultTable = '';
/**
* @var {array} centralColumnList array to hold the columns in central list per db.
*/
var centralColumnList = [];
/**
* @var {array} primaryIndexes array to hold 'Primary' index columns.
*/
// eslint-disable-next-line no-unused-vars
var primaryIndexes = [];
/**
* @var {array} uniqueIndexes array to hold 'Unique' index columns.
*/
// eslint-disable-next-line no-unused-vars
var uniqueIndexes = [];
/**
* @var {array} indexes array to hold 'Index' columns.
*/
// eslint-disable-next-line no-unused-vars
var indexes = [];
/**
* @var {array} fulltextIndexes array to hold 'Fulltext' columns.
*/
// eslint-disable-next-line no-unused-vars
var fulltextIndexes = [];
/**
* @var {array} spatialIndexes array to hold 'Spatial' columns.
*/
// eslint-disable-next-line no-unused-vars
var spatialIndexes = [];
/**
* Make sure that ajax requests will not be cached
* by appending a random variable to their parameters
*/
$.ajaxPrefilter(function (options, originalOptions) {
var nocache = new Date().getTime() + '' + Math.floor(Math.random() * 1000000);
if (typeof options.data === 'string') {
options.data += '&_nocache=' + nocache + '&token=' + encodeURIComponent(CommonParams.get('token'));
} else if (typeof options.data === 'object') {
options.data = $.extend(originalOptions.data, { '_nocache' : nocache, 'token': CommonParams.get('token') });
}
});
/**
* Adds a date/time picker to an element
*
* @param {object} $thisElement a jQuery object pointing to the element
*/
Functions.addDatepicker = function ($thisElement, type, options) {
if (type !== 'date' && type !== 'time' && type !== 'datetime' && type !== 'timestamp') {
return;
}
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: themeImagePath + 'b_calendar.png',
buttonImageOnly: true,
stepMinutes: 1,
stepHours: 1,
showSecond: true,
showMillisec: true,
showMicrosec: true,
showTimepicker: showTimepicker,
showButtonPanel: false,
changeYear: true,
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 table/change.js by verificationsAfterFieldChange()
$thisElement.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 = $thisElement.tooltip('instance');
if (typeof tooltip !== 'undefined') {
tooltip.disable();
var $note = $('
');
$note.text(tooltip.option('content'));
$('div.ui-datepicker').append($note);
}
}, 0);
},
onSelect: function () {
$thisElement.data('datepicker').inline = true;
},
onClose: function () {
// The value is no more from the date picker
$thisElement.data('comes_from', '');
if (typeof $thisElement.data('datepicker') !== 'undefined') {
$thisElement.data('datepicker').inline = false;
}
var tooltip = $thisElement.tooltip('instance');
if (typeof tooltip !== 'undefined') {
tooltip.enable();
}
}
};
if (type === 'time') {
$thisElement.timepicker($.extend(defaultOptions, options));
// Add a tip regarding entering MySQL allowed-values for TIME data-type
Functions.tooltip($thisElement, 'input', Messages.strMysqlAllowedValuesTipTime);
} else {
$thisElement.datetimepicker($.extend(defaultOptions, options));
}
};
/**
* Add a date/time picker to each element that needs it
* (only when jquery-ui-timepicker-addon.js is loaded)
*/
Functions.addDateTimePicker = function () {
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;
}
Functions.addDatepicker($(this), type, {
showMillisec: showMillisec,
showMicrosec: showMicrosec,
timeFormat: timeFormat,
hourMax: hourMax,
firstDay: firstDayOfCalendar
});
// Add a tip regarding entering MySQL allowed-values
// for TIME and DATE data-type
if ($(this).hasClass('timefield')) {
Functions.tooltip($(this), 'input', Messages.strMysqlAllowedValuesTipTime);
} else if ($(this).hasClass('datefield')) {
Functions.tooltip($(this), 'input', Messages.strMysqlAllowedValuesTipDate);
}
});
}
};
/**
* Handle redirect and reload flags sent as part of AJAX requests
*
* @param data ajax response data
*/
Functions.handleRedirectAndReload = function (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 += 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
*/
Functions.getSqlEditor = function ($textarea, options, resize, lintOptions) {
var resizeType = resize;
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 (! resizeType) {
resizeType = 'vertical';
}
var handles = '';
if (resizeType === 'vertical') {
handles = 's';
}
if (resizeType === 'both') {
handles = 'all';
}
if (resizeType === 'horizontal') {
handles = 'e, w';
}
$(codemirrorEditor.getWrapperElement())
.css('resize', resizeType)
.resizable({
handles: handles,
resize: function () {
codemirrorEditor.setSize($(this).width(), $(this).height());
}
});
// enable autocomplete
codemirrorEditor.on('inputRead', Functions.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
*/
Functions.clearSelection = function () {
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
*
*/
Functions.tooltip = function ($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
*/
Functions.escapeHtml = function (unsafe) {
if (typeof(unsafe) !== 'undefined') {
return unsafe
.toString()
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
} else {
return false;
}
};
Functions.escapeJsString = function (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;
}
};
Functions.escapeBacktick = function (s) {
return s.replace('`', '``');
};
Functions.escapeSingleQuote = function (s) {
return s.replace('\\', '\\\\').replace('\'', '\\\'');
};
Functions.sprintf = function () {
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.
*/
Functions.hideShowDefaultValue = function ($defaultType) {
if ($defaultType.val() === 'USER_DEFINED') {
$defaultType.siblings('.default_value').show().trigger('focus');
} else {
$defaultType.siblings('.default_value').hide();
if ($defaultType.val() === 'NULL') {
var $nullCheckbox = $defaultType.closest('tr').find('.allow_null');
$nullCheckbox.prop('checked', true);
}
}
};
/**
* Hides/shows the input field for column expression based on whether
* VIRTUAL/PERSISTENT is selected
*
* @param $virtuality virtuality dropdown
*/
Functions.hideShowExpression = function ($virtuality) {
if ($virtuality.val() === '') {
$virtuality.siblings('.expression').hide();
} else {
$virtuality.siblings('.expression').show();
}
};
/**
* Show notices for ENUM columns; add/hide the default value
*
*/
Functions.verifyColumnsProperties = function () {
$('select.column_type').each(function () {
Functions.showNoticeForEnum($(this));
});
$('select.default_type').each(function () {
Functions.hideShowDefaultValue($(this));
});
$('select.virtuality').each(function () {
Functions.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
*/
Functions.prepareForAjaxRequest = function ($form) {
if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
$form.append('