= 0) {
+ // Remove column from other indexes (if any).
+ Indexes.removeColumnFromIndex(colIndex);
+ }
+ var indexName = $('input[name="index[Key_name]"]').val();
+ var indexComment = $('input[name="index[Index_comment]"]').val();
+ var keyBlockSize = $('input[name="index[Key_block_size]"]').val();
+ var parser = $('input[name="index[Parser]"]').val();
+ var indexType = $('select[name="index[Index_type]"]').val();
+ var columns = [];
+ $('#index_columns').find('tbody').find('tr').each(function () {
+ // Get columns in particular order.
+ var colIndex = $(this).find('select[name="index[columns][names][]"]').val();
+ var size = $(this).find('input[name="index[columns][sub_parts][]"]').val();
+ columns.push({
+ 'col_index': colIndex,
+ 'size': size
+ });
+ });
+
+ // Update or create an index.
+ sourceArray[arrayIndex] = {
+ 'Key_name': indexName,
+ 'Index_comment': indexComment,
+ 'Index_choice': indexChoice.toUpperCase(),
+ 'Key_block_size': keyBlockSize,
+ 'Parser': parser,
+ 'Index_type': indexType,
+ 'columns': columns
+ };
+
+ // Display index name (or column list)
+ var displayName = indexName;
+ if (displayName === '') {
+ var columnNames = [];
+ $.each(columns, function () {
+ columnNames.push($('input[name="field_name[' + this.col_index + ']"]').val());
+ });
+ displayName = '[' + columnNames.join(', ') + ']';
+ }
+ $.each(columns, function () {
+ var id = 'index_name_' + this.col_index + '_8';
+ var $name = $('#' + id);
+ if ($name.length === 0) {
+ $name = $(' ');
+ $name.insertAfter($('select[name="field_key[' + this.col_index + ']"]'));
+ }
+ var $text = $('').text(displayName);
+ $name.html($text);
+ });
+ if (colIndex >= 0) {
+ // Update index details on form.
+ $('select[name="field_key[' + colIndex + ']"]').attr('data-index', indexChoice + ',' + arrayIndex);
+ }
+ Indexes.setIndexFormParameters(sourceArray, indexChoice.toLowerCase());
+};
+
+/**
+ * Get choices list for a column to create a composite index with.
+ *
+ * @param {any[]} sourceArray Array hodling columns for particular index
+ * @param {string} colIndex Choice of index
+ *
+ * @return {JQuery} jQuery Object
+ */
+Indexes.getCompositeIndexList = function (sourceArray, colIndex) {
+ // Remove any previous list.
+ if ($('#composite_index_list').length) {
+ $('#composite_index_list').remove();
+ }
+
+ // Html list.
+ var $compositeIndexList = $('');
+
+ // Add each column to list available for composite index.
+ var sourceLength = sourceArray.length;
+ var alreadyPresent = false;
+ for (var i = 0; i < sourceLength; i++) {
+ var subArrayLen = sourceArray[i].columns.length;
+ var columnNames = [];
+ for (var j = 0; j < subArrayLen; j++) {
+ columnNames.push($('input[name="field_name[' + sourceArray[i].columns[j].col_index + ']"]').val());
+ if (colIndex === sourceArray[i].columns[j].col_index) {
+ alreadyPresent = true;
+ }
+ }
+ $compositeIndexList.append('' + ' ' + '' + columnNames.join(', ') + ' ' + ' ');
+ }
+ return $compositeIndexList;
+};
+
+/**
+ * Shows 'Add Index' dialog.
+ *
+ * @param {any[]} sourceArray Array holding particular index
+ * @param {string} arrayIndex Index of an INDEX in array
+ * @param {any[]} targetColumns Columns for an INDEX
+ * @param {string} colIndex Index of column on form
+ * @param {object} index Index detail object
+ * @param {boolean} showDialog Whether to show index creation dialog or not
+ *
+ * @return {void}
+ */
+Indexes.showAddIndexDialog = function (sourceArray, arrayIndex, targetColumns, colIndex, index, showDialog) {
+ var showDialogLocal = typeof showDialog !== 'undefined' ? showDialog : true;
+ // Prepare post-data.
+ var $table = $('input[name="table"]');
+ var table = $table.length > 0 ? $table.val() : '';
+ var postData = {
+ 'server': CommonParams.get('server'),
+ 'db': $('input[name="db"]').val(),
+ 'table': table,
+ 'ajax_request': 1,
+ 'create_edit_table': 1,
+ 'index': index
+ };
+ var columns = {};
+ for (var i = 0; i < targetColumns.length; i++) {
+ var columnName = $('input[name="field_name[' + targetColumns[i] + ']"]').val();
+ var columnType = $('select[name="field_type[' + targetColumns[i] + ']"]').val().toLowerCase();
+ columns[columnName] = [columnType, targetColumns[i]];
+ }
+ postData.columns = JSON.stringify(columns);
+ var buttonOptions = {
+ [Messages.strGo]: {
+ text: Messages.strGo,
+ class: 'btn btn-primary'
+ },
+ [Messages.strCancel]: {
+ text: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }
+ };
+ buttonOptions[Messages.strGo].click = function () {
+ var isMissingValue = false;
+ $('select[name="index[columns][names][]"]').each(function () {
+ if ($(this).val() === '') {
+ isMissingValue = true;
+ }
+ });
+ if (!isMissingValue) {
+ Indexes.addColumnToIndex(sourceArray, arrayIndex, index.Index_choice, colIndex);
+ } else {
+ Functions.ajaxShowMessage(' ' + Messages.strMissingColumn + '
', false);
+ return false;
+ }
+ $(this).remove();
+ };
+ buttonOptions[Messages.strCancel].click = function () {
+ if (colIndex >= 0) {
+ // Handle state on 'Cancel'.
+ var $selectList = $('select[name="field_key[' + colIndex + ']"]');
+ if (!$selectList.attr('data-index').length) {
+ $selectList.find('option[value*="none"]').attr('selected', 'selected');
+ } else {
+ var previousIndex = $selectList.attr('data-index').split(',');
+ $selectList.find('option[value*="' + previousIndex[0].toLowerCase() + '"]').attr('selected', 'selected');
+ }
+ }
+ $(this).dialog('close');
+ };
+ var $msgbox = Functions.ajaxShowMessage();
+ $.post('index.php?route=/table/indexes', postData, function (data) {
+ if (data.success === false) {
+ // in the case of an error, show the error message returned.
+ Functions.ajaxShowMessage(data.error, false);
+ } else {
+ Functions.ajaxRemoveMessage($msgbox);
+ var $div = $('
');
+ if (showDialogLocal) {
+ // Show dialog if the request was successful
+ if ($('#addIndex').length > 0) {
+ $('#addIndex').remove();
+ }
+ $div.append(data.message).dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strAddIndex,
+ width: 450,
+ minHeight: 250,
+ create: function () {
+ $(this).on('keypress', function (e) {
+ if (e.which === 13 || e.keyCode === 13 || window.event.keyCode === 13) {
+ e.preventDefault();
+ buttonOptions[Messages.strGo]();
+ $(this).remove();
+ }
+ });
+ },
+ open: function () {
+ Functions.checkIndexName('index_frm');
+ Functions.showHints($div);
+ $('#index_columns').find('td').each(function () {
+ $(this).css('width', $(this).width() + 'px');
+ });
+ $('#index_columns').find('tbody').sortable({
+ axis: 'y',
+ containment: $('#index_columns').find('tbody'),
+ tolerance: 'pointer'
+ });
+ },
+ modal: true,
+ buttons: buttonOptions,
+ close: function () {
+ $(this).remove();
+ }
+ });
+ } else {
+ $div.append(data.message);
+ $div.css({
+ 'display': 'none'
+ });
+ $div.appendTo($('body'));
+ $div.attr({
+ 'id': 'addIndex'
+ });
+ var isMissingValue = false;
+ $('select[name="index[columns][names][]"]').each(function () {
+ if ($(this).val() === '') {
+ isMissingValue = true;
+ }
+ });
+ if (!isMissingValue) {
+ Indexes.addColumnToIndex(sourceArray, arrayIndex, index.Index_choice, colIndex);
+ } else {
+ Functions.ajaxShowMessage(' ' + Messages.strMissingColumn + '
', false);
+ return false;
+ }
+ }
+ }
+ });
+};
+
+/**
+ * Creates a advanced index type selection dialog.
+ *
+ * @param {any[]} sourceArray Array holding a particular type of indexes
+ * @param {string} indexChoice Choice of index
+ * @param {string} colIndex Index of new column on form
+ *
+ * @return {void}
+ */
+Indexes.indexTypeSelectionDialog = function (sourceArray, indexChoice, colIndex) {
+ var $singleColumnRadio = $(' ' + '' + Messages.strCreateSingleColumnIndex + ' ');
+ var $compositeIndexRadio = $(' ' + '' + Messages.strCreateCompositeIndex + ' ');
+ var $dialogContent = $(' ');
+ $dialogContent.append('' + indexChoice.toUpperCase() + ' ');
+
+ // For UNIQUE/INDEX type, show choice for single-column and composite index.
+ $dialogContent.append($singleColumnRadio);
+ $dialogContent.append($compositeIndexRadio);
+ var buttonOptions = {
+ [Messages.strGo]: {
+ text: Messages.strGo,
+ class: 'btn btn-primary'
+ },
+ [Messages.strCancel]: {
+ text: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }
+ };
+
+ // 'OK' operation.
+ buttonOptions[Messages.strGo].click = function () {
+ if ($('#single_column').is(':checked')) {
+ var index = {
+ 'Key_name': indexChoice === 'primary' ? 'PRIMARY' : '',
+ 'Index_choice': indexChoice.toUpperCase()
+ };
+ Indexes.showAddIndexDialog(sourceArray, sourceArray.length, [colIndex], colIndex, index);
+ }
+ if ($('#composite_index').is(':checked')) {
+ if ($('input[name="composite_with"]').length !== 0 && $('input[name="composite_with"]:checked').length === 0) {
+ Functions.ajaxShowMessage(' ' + Messages.strFormEmpty + '
', false);
+ return false;
+ }
+ var arrayIndex = $('input[name="composite_with"]:checked').val();
+ var sourceLength = sourceArray[arrayIndex].columns.length;
+ var targetColumns = [];
+ for (var i = 0; i < sourceLength; i++) {
+ targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
+ }
+ targetColumns.push(colIndex);
+ Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, colIndex, sourceArray[arrayIndex]);
+ }
+ $(this).remove();
+ };
+ buttonOptions[Messages.strCancel].click = function () {
+ // Handle state on 'Cancel'.
+ var $selectList = $('select[name="field_key[' + colIndex + ']"]');
+ if (!$selectList.attr('data-index').length) {
+ $selectList.find('option[value*="none"]').attr('selected', 'selected');
+ } else {
+ var previousIndex = $selectList.attr('data-index').split(',');
+ $selectList.find('option[value*="' + previousIndex[0].toLowerCase() + '"]').attr('selected', 'selected');
+ }
+ $(this).remove();
+ };
+ $('
').append($dialogContent).dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ minWidth: 525,
+ minHeight: 200,
+ modal: true,
+ title: Messages.strAddIndex,
+ resizable: false,
+ buttons: buttonOptions,
+ open: function () {
+ $('#composite_index').on('change', function () {
+ if ($(this).is(':checked')) {
+ $dialogContent.append(Indexes.getCompositeIndexList(sourceArray, colIndex));
+ }
+ });
+ $('#single_column').on('change', function () {
+ if ($(this).is(':checked')) {
+ if ($('#composite_index_list').length) {
+ $('#composite_index_list').remove();
+ }
+ }
+ });
+ },
+ close: function () {
+ $('#composite_index').off('change');
+ $('#single_column').off('change');
+ $(this).remove();
+ }
+ });
+};
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('indexes.js', function () {
+ $(document).off('click', '#save_index_frm');
+ $(document).off('click', '#preview_index_frm');
+ $(document).off('change', '#select_index_choice');
+ $(document).off('click', 'a.drop_primary_key_index_anchor.ajax');
+ $(document).off('click', '#table_index tbody tr td.edit_index.ajax, #index_div .add_index.ajax');
+ $(document).off('click', '#table_index tbody tr td.rename_index.ajax');
+ $(document).off('click', '#index_frm input[type=submit]');
+ $('body').off('change', 'select[name*="field_key"]');
+ $(document).off('click', '.show_index_dialog');
+});
+
+/**
+ * @description Ajax scripts for table index page
+ *
+ * Actions ajaxified here:
+ *
+ * Showing/hiding inputs depending on the index type chosen
+ * create/edit/drop indexes
+ *
+ */
+AJAX.registerOnload('indexes.js', function () {
+ // Re-initialize variables.
+ primaryIndexes = [];
+ uniqueIndexes = [];
+ indexes = [];
+ fulltextIndexes = [];
+ spatialIndexes = [];
+
+ // for table creation form
+ var $engineSelector = $('.create_table_form select[name=tbl_storage_engine]');
+ if ($engineSelector.length) {
+ Functions.hideShowConnection($engineSelector);
+ }
+ var $form = $('#index_frm');
+ if ($form.length > 0) {
+ Functions.showIndexEditDialog($form);
+ }
+ $(document).on('click', '#save_index_frm', function (event) {
+ event.preventDefault();
+ var $form = $('#index_frm');
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'do_save_data=1' + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ });
+ $(document).on('click', '#preview_index_frm', function (event) {
+ event.preventDefault();
+ Functions.previewSql($('#index_frm'));
+ });
+ $(document).on('change', '#select_index_choice', function (event) {
+ event.preventDefault();
+ Indexes.checkIndexType();
+ Functions.checkIndexName('index_frm');
+ });
+
+ /**
+ * Ajax Event handler for 'Drop Index'
+ */
+ $(document).on('click', 'a.drop_primary_key_index_anchor.ajax', function (event) {
+ event.preventDefault();
+ var $anchor = $(this);
+ /**
+ * @var $currRow Object containing reference to the current field's row
+ */
+ var $currRow = $anchor.parents('tr');
+ /** @var {number} rows Number of columns in the key */
+ var rows = $anchor.parents('td').attr('rowspan') || 1;
+ /** @var {number} $rowsToHide Rows that should be hidden */
+ var $rowsToHide = $currRow;
+ for (var i = 1, $lastRow = $currRow.next(); i < rows; i++, $lastRow = $lastRow.next()) {
+ $rowsToHide = $rowsToHide.add($lastRow);
+ }
+ var question = $currRow.children('td').children('.drop_primary_key_index_msg').val();
+ Functions.confirmPreviewSql(question, $anchor.attr('href'), function (url) {
+ var $msg = Functions.ajaxShowMessage(Messages.strDroppingPrimaryKeyIndex, false);
+ var params = Functions.getJsConfirmCommonParam(this, $anchor.getPostData());
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxRemoveMessage($msg);
+ var $tableRef = $rowsToHide.closest('table');
+ if ($rowsToHide.length === $tableRef.find('tbody > tr').length) {
+ // We are about to remove all rows from the table
+ $tableRef.hide('medium', function () {
+ $('div.no_indexes_defined').show('medium');
+ $rowsToHide.remove();
+ });
+ $tableRef.siblings('.alert-primary').hide('medium');
+ } else {
+ // We are removing some of the rows only
+ $rowsToHide.hide('medium', function () {
+ $(this).remove();
+ });
+ }
+ if ($('.result_query').length) {
+ $('.result_query').remove();
+ }
+ if (data.sql_query) {
+ $('
').html(data.sql_query).prependTo('#structure_content');
+ Functions.highlightSql($('#page_content'));
+ }
+ Navigation.reload();
+ CommonActions.refreshMain('index.php?route=/table/structure');
+ } else {
+ Functions.ajaxShowMessage(Messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ });
+ }); // end Drop Primary Key/Index
+
+ /**
+ * Ajax event handler for index edit
+ **/
+ $(document).on('click', '#table_index tbody tr td.edit_index.ajax, #index_div .add_index.ajax', function (event) {
+ event.preventDefault();
+ var url;
+ var title;
+ if ($(this).find('a').length === 0) {
+ // Add index
+ var valid = Functions.checkFormElementInRange($(this).closest('form')[0], 'added_fields', 'Column count has to be larger than zero.');
+ if (!valid) {
+ return;
+ }
+ url = $(this).closest('form').serialize();
+ title = Messages.strAddIndex;
+ } else {
+ // Edit index
+ url = $(this).find('a').getPostData();
+ title = Messages.strEditIndex;
+ }
+ url += CommonParams.get('arg_separator') + 'ajax_request=true';
+ Functions.indexEditorDialog(url, title, function (data) {
+ CommonParams.set('db', data.params.db);
+ CommonParams.set('table', data.params.table);
+ CommonActions.refreshMain('index.php?route=/table/structure');
+ });
+ });
+
+ /**
+ * Ajax event handler for index rename
+ **/
+ $(document).on('click', '#table_index tbody tr td.rename_index.ajax', function (event) {
+ event.preventDefault();
+ var url = $(this).find('a').getPostData();
+ var title = Messages.strRenameIndex;
+ url += CommonParams.get('arg_separator') + 'ajax_request=true';
+ Functions.indexRenameDialog(url, title, function (data) {
+ CommonParams.set('db', data.params.db);
+ CommonParams.set('table', data.params.table);
+ CommonActions.refreshMain('index.php?route=/table/structure');
+ });
+ });
+
+ /**
+ * Ajax event handler for advanced index creation during table creation
+ * and column addition.
+ */
+ $('body').on('change', 'select[name*="field_key"]', function (e, showDialog) {
+ var showDialogLocal = typeof showDialog !== 'undefined' ? showDialog : true;
+ // Index of column on Table edit and create page.
+ var colIndex = /\d+/.exec($(this).attr('name'));
+ colIndex = colIndex[0];
+ // Choice of selected index.
+ var indexChoice = /[a-z]+/.exec($(this).val());
+ indexChoice = indexChoice[0];
+ // Array containing corresponding indexes.
+ var sourceArray = null;
+ if (indexChoice === 'none') {
+ Indexes.removeColumnFromIndex(colIndex);
+ var id = 'index_name_' + '0' + '_8';
+ var $name = $('#' + id);
+ if ($name.length === 0) {
+ $name = $(' ');
+ $name.insertAfter($('select[name="field_key[' + '0' + ']"]'));
+ }
+ $name.html('');
+ return false;
+ }
+
+ // Select a source array.
+ sourceArray = Indexes.getIndexArray(indexChoice);
+ if (sourceArray === null) {
+ return;
+ }
+ if (sourceArray.length === 0) {
+ var index = {
+ 'Key_name': indexChoice === 'primary' ? 'PRIMARY' : '',
+ 'Index_choice': indexChoice.toUpperCase()
+ };
+ Indexes.showAddIndexDialog(sourceArray, 0, [colIndex], colIndex, index, showDialogLocal);
+ } else {
+ if (indexChoice === 'primary') {
+ var arrayIndex = 0;
+ var sourceLength = sourceArray[arrayIndex].columns.length;
+ var targetColumns = [];
+ for (var i = 0; i < sourceLength; i++) {
+ targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
+ }
+ targetColumns.push(colIndex);
+ Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, colIndex, sourceArray[arrayIndex], showDialogLocal);
+ } else {
+ // If there are multiple columns selected for an index, show advanced dialog.
+ Indexes.indexTypeSelectionDialog(sourceArray, indexChoice, colIndex);
+ }
+ }
+ });
+ $(document).on('click', '.show_index_dialog', function (e) {
+ e.preventDefault();
+
+ // Get index details.
+ var previousIndex = $(this).prev('select').attr('data-index').split(',');
+ var indexChoice = previousIndex[0];
+ var arrayIndex = previousIndex[1];
+ var sourceArray = Indexes.getIndexArray(indexChoice);
+ if (sourceArray !== null) {
+ var sourceLength = sourceArray[arrayIndex].columns.length;
+ var targetColumns = [];
+ for (var i = 0; i < sourceLength; i++) {
+ targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
+ }
+ Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, -1, sourceArray[arrayIndex]);
+ }
+ });
+ $('#index_frm').on('submit', function () {
+ if (typeof this.elements['index[Key_name]'].disabled !== 'undefined') {
+ this.elements['index[Key_name]'].disabled = false;
+ }
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jqplot/plugins/jqplot.byteFormatter.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jqplot/plugins/jqplot.byteFormatter.js
new file mode 100644
index 000000000..1f8143c20
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jqplot/plugins/jqplot.byteFormatter.js
@@ -0,0 +1,43 @@
+/**
+ * jqplot formatter for byte values
+ *
+ * @package phpMyAdmin
+ */
+(function ($) {
+ 'use strict';
+
+ var formatByte = function (value, index) {
+ var val = value;
+ var i = index;
+ var units = [Messages.strB, Messages.strKiB, Messages.strMiB, Messages.strGiB, Messages.strTiB, Messages.strPiB, Messages.strEiB];
+ while (val >= 1024 && i <= 6) {
+ val /= 1024;
+ i++;
+ }
+ var format = '%.1f';
+ if (Math.floor(val) === val) {
+ format = '%.0f';
+ }
+ return $.jqplot.sprintf(format + ' ' + units[i], val);
+ };
+ /**
+ * The index indicates what unit the incoming data will be in.
+ * 0 for bytes, 1 for kilobytes and so on...
+ *
+ * @param index
+ *
+ * @return {String}
+ */
+ $.jqplot.byteFormatter = function (index) {
+ var i = index || 0;
+ return function (format, value) {
+ var val = value;
+ if (typeof val === 'number') {
+ val = parseFloat(val) || 0;
+ return formatByte(val, i);
+ } else {
+ return String(val);
+ }
+ };
+ };
+})(jQuery);
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jquery.sortable-table.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jquery.sortable-table.js
new file mode 100644
index 000000000..1545cac7d
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/jquery.sortable-table.js
@@ -0,0 +1,271 @@
+/**
+ * This file is internal to phpMyAdmin.
+ * @license see the main phpMyAdmin license.
+ *
+ * @fileoverview A jquery plugin that allows drag&drop sorting in tables.
+ * Coded because JQuery UI sortable doesn't support tables. Also it has no animation
+ *
+ * @name Sortable Table JQuery plugin
+ *
+ * @requires jQuery
+ */
+
+/**
+ * Options:
+ *
+ * $('table').sortableTable({
+ * ignoreRect: { top, left, width, height } - Relative coordinates on each element. If the user clicks
+ * in this area, it is not seen as a drag&drop request. Useful for toolbars etc.
+ * events: {
+ * start: callback function when the user starts dragging
+ * drop: callback function after an element has been dropped
+ * }
+ * })
+ */
+
+/**
+ * Commands:
+ *
+ * $('table').sortableTable('init') - equivalent to $('table').sortableTable()
+ * $('table').sortableTable('refresh') - if the table has been changed, refresh correctly assigns all events again
+ * $('table').sortableTable('destroy') - removes all events from the table
+ */
+
+/**
+ * Setup:
+ *
+ * Can be applied on any table, there is just one convention.
+ * Each cell () has to contain one and only one element (preferably div or span)
+ * which is the actually draggable element.
+ */
+(function ($) {
+ jQuery.fn.sortableTable = function (method) {
+ var methods = {
+ init: function (options) {
+ var tb = new SortableTableInstance(this, options);
+ tb.init();
+ $(this).data('sortableTable', tb);
+ },
+ refresh: function () {
+ $(this).data('sortableTable').refresh();
+ },
+ destroy: function () {
+ $(this).data('sortableTable').destroy();
+ }
+ };
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method) {
+ return methods.init.apply(this, arguments);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.sortableTable');
+ }
+ function SortableTableInstance(table) {
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ var down = false;
+ var $draggedEl;
+ var oldCell;
+ var previewMove;
+ var id;
+
+ /* Mouse handlers on the child elements */
+ var onMouseUp = function (e) {
+ dropAt(e.pageX, e.pageY);
+ };
+ var onMouseDown = function (e) {
+ $draggedEl = $(this).children();
+ if ($draggedEl.length === 0) {
+ return;
+ }
+ if (options.ignoreRect && insideRect({
+ x: e.pageX - $draggedEl.offset().left,
+ y: e.pageY - $draggedEl.offset().top
+ }, options.ignoreRect)) {
+ return;
+ }
+ down = true;
+ oldCell = this;
+ if (options.events && options.events.start) {
+ options.events.start(this);
+ }
+ return false;
+ };
+ var globalMouseMove = function (e) {
+ if (down) {
+ move(e.pageX, e.pageY);
+ if (inside($(oldCell), e.pageX, e.pageY)) {
+ if (previewMove !== null) {
+ moveTo(previewMove);
+ previewMove = null;
+ }
+ } else {
+ $(table).find('td').each(function () {
+ if (inside($(this), e.pageX, e.pageY)) {
+ if ($(previewMove).attr('class') !== $(this).children().first().attr('class')) {
+ if (previewMove !== null) {
+ moveTo(previewMove);
+ }
+ previewMove = $(this).children().first();
+ if (previewMove.length > 0) {
+ moveTo($(previewMove), {
+ pos: {
+ top: $(oldCell).offset().top - $(previewMove).parent().offset().top,
+ left: $(oldCell).offset().left - $(previewMove).parent().offset().left
+ }
+ });
+ }
+ }
+ return false;
+ }
+ });
+ }
+ }
+ return false;
+ };
+ var globalMouseOut = function () {
+ if (down) {
+ down = false;
+ if (previewMove) {
+ moveTo(previewMove);
+ }
+ moveTo($draggedEl);
+ previewMove = null;
+ }
+ };
+
+ // Initialize sortable table
+ this.init = function () {
+ id = 1;
+ // Add some required css to each child element in the s
+ $(table).find('td').children().each(function () {
+ // Remove any old occurrences of our added draggable-num class
+ $(this).attr('class', $(this).attr('class').replace(/\s*draggable-\d+/g, ''));
+ $(this).addClass('draggable-' + id++);
+ });
+
+ // Mouse events
+ $(table).find('td').on('mouseup', onMouseUp);
+ $(table).find('td').on('mousedown', onMouseDown);
+ $(document).on('mousemove', globalMouseMove);
+ $(document).on('mouseleave', globalMouseOut);
+ };
+
+ // Call this when the table has been updated
+ this.refresh = function () {
+ this.destroy();
+ this.init();
+ };
+ this.destroy = function () {
+ // Add some required css to each child element in the s
+ $(table).find('td').children().each(function () {
+ // Remove any old occurrences of our added draggable-num class
+ $(this).attr('class', $(this).attr('class').replace(/\s*draggable-\d+/g, ''));
+ });
+
+ // Mouse events
+ $(table).find('td').off('mouseup', onMouseUp);
+ $(table).find('td').off('mousedown', onMouseDown);
+ $(document).off('mousemove', globalMouseMove);
+ $(document).off('mouseleave', globalMouseOut);
+ };
+ function switchElement(drag, dropTo) {
+ var dragPosDiff = {
+ left: $(drag).children().first().offset().left - $(dropTo).offset().left,
+ top: $(drag).children().first().offset().top - $(dropTo).offset().top
+ };
+ var dropPosDiff = null;
+ if ($(dropTo).children().length > 0) {
+ dropPosDiff = {
+ left: $(dropTo).children().first().offset().left - $(drag).offset().left,
+ top: $(dropTo).children().first().offset().top - $(drag).offset().top
+ };
+ }
+
+ /* I love you append(). It moves the DOM Elements so gracefully <3 */
+ // Put the element in the way to old place
+ $(drag).append($(dropTo).children().first()).children().stop(true, true).on('mouseup', onMouseUp);
+ if (dropPosDiff) {
+ $(drag).append($(dropTo).children().first()).children().css('left', dropPosDiff.left + 'px').css('top', dropPosDiff.top + 'px');
+ }
+
+ // Put our dragged element into the space we just freed up
+ $(dropTo).append($(drag).children().first()).children().on('mouseup', onMouseUp).css('left', dragPosDiff.left + 'px').css('top', dragPosDiff.top + 'px');
+ moveTo($(dropTo).children().first(), {
+ duration: 100
+ });
+ moveTo($(drag).children().first(), {
+ duration: 100
+ });
+ if (options.events && options.events.drop) {
+ // Drop event. The drag child element is moved into the drop element
+ // and vice versa. So the parameters are switched.
+
+ // Calculate row and column index
+ const colIdx = $(dropTo).prevAll().length;
+ const rowIdx = $(dropTo).parent().prevAll().length;
+ options.events.drop(drag, dropTo, {
+ col: colIdx,
+ row: rowIdx
+ });
+ }
+ }
+ function move(x, y) {
+ $draggedEl.offset({
+ top: Math.min($(document).height(), Math.max(0, y - $draggedEl.height() / 2)),
+ left: Math.min($(document).width(), Math.max(0, x - $draggedEl.width() / 2))
+ });
+ }
+ function inside($el, x, y) {
+ var off = $el.offset();
+ return y >= off.top && x >= off.left && x < off.left + $el.width() && y < off.top + $el.height();
+ }
+ function insideRect(pos, r) {
+ return pos.y > r.top && pos.x > r.left && pos.y < r.top + r.height && pos.x < r.left + r.width;
+ }
+ function dropAt(x, y) {
+ if (!down) {
+ return;
+ }
+ down = false;
+ var switched = false;
+ $(table).find('td').each(function () {
+ if ($(this).children().first().attr('class') !== $(oldCell).children().first().attr('class') && inside($(this), x, y)) {
+ switchElement(oldCell, this);
+ switched = true;
+ }
+ });
+ if (!switched) {
+ if (previewMove) {
+ moveTo(previewMove);
+ }
+ moveTo($draggedEl);
+ }
+ previewMove = null;
+ }
+ function moveTo(elem) {
+ let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ if (!opts.pos) {
+ opts.pos = {
+ left: 0,
+ top: 0
+ };
+ }
+ if (!opts.duration) {
+ opts.duration = 200;
+ }
+ $(elem).css('position', 'relative');
+ $(elem).animate({
+ top: opts.pos.top,
+ left: opts.pos.left
+ }, {
+ duration: opts.duration,
+ complete: function () {
+ if (opts.pos.left === 0 && opts.pos.top === 0) {
+ $(elem).css('position', '').css('left', '').css('top', '');
+ }
+ }
+ });
+ }
+ }
+ };
+})(jQuery);
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/keyhandler.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/keyhandler.js
new file mode 100644
index 000000000..e9dc06b6c
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/keyhandler.js
@@ -0,0 +1,92 @@
+// global var that holds: 0- if ctrl key is not pressed 1- if ctrl key is pressed
+var ctrlKeyHistory = 0;
+
+/**
+ * Allows moving around inputs/select by Ctrl+arrows
+ *
+ * @param {object} event data
+ */
+function onKeyDownArrowsHandler(event) {
+ var e = event || window.event;
+ var o = e.srcElement || e.target;
+ if (!o) {
+ return;
+ }
+ if (o.tagName !== 'TEXTAREA' && o.tagName !== 'INPUT' && o.tagName !== 'SELECT') {
+ return;
+ }
+ if (e.which !== 17 && e.which !== 37 && e.which !== 38 && e.which !== 39 && e.which !== 40) {
+ return;
+ }
+ if (!o.id) {
+ return;
+ }
+ if (e.type === 'keyup') {
+ if (e.which === 17) {
+ ctrlKeyHistory = 0;
+ }
+ return;
+ } else if (e.type === 'keydown') {
+ if (e.which === 17) {
+ ctrlKeyHistory = 1;
+ }
+ }
+ if (ctrlKeyHistory !== 1) {
+ return;
+ }
+ e.preventDefault();
+ var pos = o.id.split('_');
+ if (pos[0] !== 'field' || typeof pos[2] === 'undefined') {
+ return;
+ }
+ var x = pos[2];
+ var y = pos[1];
+ switch (e.keyCode) {
+ case 38:
+ // up
+ y--;
+ break;
+ case 40:
+ // down
+ y++;
+ break;
+ case 37:
+ // left
+ x--;
+ break;
+ case 39:
+ // right
+ x++;
+ break;
+ default:
+ return;
+ }
+ var id = 'field_' + y + '_' + x;
+ var nO = document.getElementById(id);
+ if (!nO) {
+ id = 'field_' + y + '_' + x + '_0';
+ nO = document.getElementById(id);
+ }
+
+ // skip non existent fields
+ if (!nO) {
+ return;
+ }
+ nO.focus();
+ if (nO.tagName !== 'SELECT') {
+ nO.select();
+ }
+ e.returnValue = false;
+}
+AJAX.registerTeardown('keyhandler.js', function () {
+ $(document).off('keydown keyup', '#table_columns');
+ $(document).off('keydown keyup', 'table.insertRowTable');
+});
+AJAX.registerOnload('keyhandler.js', function () {
+ $(document).on('keydown keyup', '#table_columns', function (event) {
+ onKeyDownArrowsHandler(event.originalEvent);
+ });
+ $(document).on('keydown keyup', 'table.insertRowTable', function (event) {
+ onKeyDownArrowsHandler(event.originalEvent);
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/makegrid.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/makegrid.js
new file mode 100644
index 000000000..41ebb8e73
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/makegrid.js
@@ -0,0 +1,2213 @@
+/* global firstDayOfCalendar */ // templates/javascript/variables.twig
+
+/**
+ * Create advanced table (resize, reorder, and show/hide columns; and also grid editing).
+ * This function is designed mainly for table DOM generated from browsing a table in the database.
+ * For using this function in other table DOM, you may need to:
+ * - add "draggable" class in the table header , in order to make it resizable, sortable or hidable
+ * - have at least one non-"draggable" header in the table DOM for placing column visibility drop-down arrow
+ * - pass the value "false" for the parameter "enableGridEdit"
+ * - adjust other parameter value, to select which features that will be enabled
+ *
+ * @param t the table DOM element
+ * @param enableResize Optional, if false, column resizing feature will be disabled
+ * @param enableReorder Optional, if false, column reordering feature will be disabled
+ * @param enableVisib Optional, if false, show/hide column feature will be disabled
+ * @param enableGridEdit Optional, if false, grid editing feature will be disabled
+ */
+// eslint-disable-next-line no-unused-vars
+var makeGrid = function (t, enableResize, enableReorder, enableVisib, enableGridEdit) {
+ var isResizeEnabled = enableResize === undefined ? true : enableResize;
+ var isReorderEnabled = enableReorder === undefined ? true : enableReorder;
+ var isVisibEnabled = enableVisib === undefined ? true : enableVisib;
+ var isGridEditEnabled = enableGridEdit === undefined ? true : enableGridEdit;
+ var g = {
+ /** *********
+ * Constant
+ ***********/
+ minColWidth: 15,
+ /** *********
+ * Variables, assigned with default value, changed later
+ ***********/
+ actionSpan: 5,
+ // number of colspan in Actions header in a table
+ tableCreateTime: null,
+ // table creation time, used for saving column order and visibility to server, only available in "Browse tab"
+
+ // Column reordering variables
+ colOrder: [],
+ // array of column order
+
+ // Column visibility variables
+ colVisib: [],
+ // array of column visibility
+ showAllColText: '',
+ // string, text for "show all" button under column visibility list
+ visibleHeadersCount: 0,
+ // number of visible data headers
+
+ // Table hint variables
+ reorderHint: '',
+ // string, hint for column reordering
+ sortHint: '',
+ // string, hint for column sorting
+ markHint: '',
+ // string, hint for column marking
+ copyHint: '',
+ // string, hint for copy column name
+ showReorderHint: false,
+ showSortHint: false,
+ showMarkHint: false,
+ // Grid editing
+ isCellEditActive: false,
+ // true if current focus is in edit cell
+ isEditCellTextEditable: false,
+ // true if current edit cell is editable in the text input box (not textarea)
+ currentEditCell: null,
+ // reference to that currently being edited
+ cellEditHint: '',
+ // hint shown when doing grid edit
+ gotoLinkText: '',
+ // "Go to link" text
+ wasEditedCellNull: false,
+ // true if last value of the edited cell was NULL
+ maxTruncatedLen: 0,
+ // number of characters that can be displayed in a cell
+ saveCellsAtOnce: false,
+ // $cfg[saveCellsAtOnce]
+ isCellEdited: false,
+ // true if at least one cell has been edited
+ saveCellWarning: '',
+ // string, warning text when user want to leave a page with unsaved edited data
+ lastXHR: null,
+ // last XHR object used in AJAX request
+ isSaving: false,
+ // true when currently saving edited data, used to handle double posting caused by pressing ENTER in grid edit text box in Chrome browser
+ alertNonUnique: '',
+ // string, alert shown when saving edited nonunique table
+
+ // Common hidden inputs
+ token: null,
+ server: null,
+ db: null,
+ table: null,
+ /** **********
+ * Functions
+ ************/
+
+ /**
+ * Start to resize column. Called when clicking on column separator.
+ *
+ * @param e event
+ * @param obj dragged div object
+ */
+ dragStartRsz: function (e, obj) {
+ var n = $(g.cRsz).find('div').index(obj); // get the index of separator (i.e., column index)
+ $(obj).addClass('colborder_active');
+ g.colRsz = {
+ x0: e.pageX,
+ n: n,
+ obj: obj,
+ objLeft: $(obj).position().left,
+ objWidth: $(g.t).find('th.draggable:visible').eq(n).find('span').outerWidth()
+ };
+ // eslint-disable-next-line compat/compat
+ $(document.body).css('cursor', 'col-resize').noSelect();
+ if (g.isCellEditActive) {
+ g.hideEditCell();
+ }
+ },
+ /**
+ * Start to reorder column. Called when clicking on table header.
+ *
+ * @param e event
+ * @param obj table header object
+ */
+ dragStartReorder: function (e, obj) {
+ // prepare the cCpy (column copy) and cPointer (column pointer) from the dragged column
+ $(g.cCpy).text($(obj).text());
+ var objPos = $(obj).position();
+ $(g.cCpy).css({
+ top: objPos.top + 20,
+ left: objPos.left,
+ height: $(obj).height(),
+ width: $(obj).width()
+ });
+ $(g.cPointer).css({
+ top: objPos.top
+ });
+
+ // get the column index, zero-based
+ var n = g.getHeaderIdx(obj);
+ g.colReorder = {
+ x0: e.pageX,
+ y0: e.pageY,
+ n: n,
+ newn: n,
+ obj: obj,
+ objTop: objPos.top,
+ objLeft: objPos.left
+ };
+
+ // eslint-disable-next-line compat/compat
+ $(document.body).css('cursor', 'move').noSelect();
+ if (g.isCellEditActive) {
+ g.hideEditCell();
+ }
+ },
+ /**
+ * Handle mousemove event when dragging.
+ *
+ * @param e event
+ */
+ dragMove: function (e) {
+ var dx;
+ if (g.colRsz) {
+ dx = e.pageX - g.colRsz.x0;
+ if (g.colRsz.objWidth + dx > g.minColWidth) {
+ $(g.colRsz.obj).css('left', g.colRsz.objLeft + dx + 'px');
+ }
+ } else if (g.colReorder) {
+ // dragged column animation
+ dx = e.pageX - g.colReorder.x0;
+ $(g.cCpy).css('left', g.colReorder.objLeft + dx).show();
+
+ // pointer animation
+ var hoveredCol = g.getHoveredCol(e);
+ if (hoveredCol) {
+ var newn = g.getHeaderIdx(hoveredCol);
+ g.colReorder.newn = newn;
+ if (newn !== g.colReorder.n) {
+ // show the column pointer in the right place
+ var colPos = $(hoveredCol).position();
+ var newleft = newn < g.colReorder.n ? colPos.left : colPos.left + $(hoveredCol).outerWidth();
+ $(g.cPointer).css({
+ left: newleft,
+ visibility: 'visible'
+ });
+ } else {
+ // no movement to other column, hide the column pointer
+ $(g.cPointer).css('visibility', 'hidden');
+ }
+ }
+ }
+ },
+ /**
+ * Stop the dragging action.
+ *
+ * @param e event
+ */
+ dragEnd: function (e) {
+ if (g.colRsz) {
+ var dx = e.pageX - g.colRsz.x0;
+ var nw = g.colRsz.objWidth + dx;
+ if (nw < g.minColWidth) {
+ nw = g.minColWidth;
+ }
+ var n = g.colRsz.n;
+ // do the resizing
+ g.resize(n, nw);
+ g.reposRsz();
+ g.reposDrop();
+ g.colRsz = false;
+ $(g.cRsz).find('div').removeClass('colborder_active');
+ } else if (g.colReorder) {
+ // shift columns
+ if (g.colReorder.newn !== g.colReorder.n) {
+ g.shiftCol(g.colReorder.n, g.colReorder.newn);
+ // assign new position
+ var objPos = $(g.colReorder.obj).position();
+ g.colReorder.objTop = objPos.top;
+ g.colReorder.objLeft = objPos.left;
+ g.colReorder.n = g.colReorder.newn;
+ // send request to server to remember the column order
+ if (g.tableCreateTime) {
+ g.sendColPrefs();
+ }
+ g.refreshRestoreButton();
+ }
+
+ // animate new column position
+ $(g.cCpy).stop(true, true).animate({
+ top: g.colReorder.objTop,
+ left: g.colReorder.objLeft
+ }, 'fast').fadeOut();
+ $(g.cPointer).css('visibility', 'hidden');
+ g.colReorder = false;
+ }
+ // eslint-disable-next-line compat/compat
+ $(document.body).css('cursor', 'inherit').noSelect(false);
+ },
+ /**
+ * Resize column n to new width "nw"
+ *
+ * @param n zero-based column index
+ * @param nw new width of the column in pixel
+ */
+ resize: function (n, nw) {
+ $(g.t).find('tr').each(function () {
+ $(this).find('th.draggable:visible').eq(n).find('span').add($(this).find('td:visible').eq(g.actionSpan + n).find('span')).css('width', nw);
+ });
+ },
+ /**
+ * Reposition column resize bars.
+ */
+ reposRsz: function () {
+ $(g.cRsz).find('div').hide();
+ var $firstRowCols = $(g.t).find('tr').first().find('th.draggable:visible');
+ var $resizeHandles = $(g.cRsz).find('div').removeClass('condition');
+ $(g.t).find('table.pma_table').find('thead th').first().removeClass('before-condition');
+ for (var n = 0, l = $firstRowCols.length; n < l; n++) {
+ var $col = $($firstRowCols[n]);
+ var colWidth;
+ if (navigator.userAgent.toLowerCase().indexOf('safari') !== -1) {
+ colWidth = $col.outerWidth();
+ } else {
+ colWidth = $col.outerWidth(true);
+ }
+ $($resizeHandles[n]).css('left', $col.position().left + colWidth).show();
+ if ($col.hasClass('condition')) {
+ $($resizeHandles[n]).addClass('condition');
+ if (n > 0) {
+ $($resizeHandles[n - 1]).addClass('condition');
+ }
+ }
+ }
+ if ($($resizeHandles[0]).hasClass('condition')) {
+ $(g.t).find('thead th').first().addClass('before-condition');
+ }
+ $(g.cRsz).css('height', $(g.t).height());
+ },
+ /**
+ * Shift column from index oldn to newn.
+ *
+ * @param oldn old zero-based column index
+ * @param newn new zero-based column index
+ */
+ shiftCol: function (oldn, newn) {
+ $(g.t).find('tr').each(function () {
+ if (newn < oldn) {
+ $(this).find('th.draggable').eq(newn).add($(this).find('td').eq(g.actionSpan + newn)).before($(this).find('th.draggable').eq(oldn).add($(this).find('td').eq(g.actionSpan + oldn)));
+ } else {
+ $(this).find('th.draggable').eq(newn).add($(this).find('td').eq(g.actionSpan + newn)).after($(this).find('th.draggable').eq(oldn).add($(this).find('td').eq(g.actionSpan + oldn)));
+ }
+ });
+ // reposition the column resize bars
+ g.reposRsz();
+
+ // adjust the column visibility list
+ if (newn < oldn) {
+ $(g.cList).find('.lDiv div').eq(newn).before($(g.cList).find('.lDiv div').eq(oldn));
+ } else {
+ $(g.cList).find('.lDiv div').eq(newn).after($(g.cList).find('.lDiv div').eq(oldn));
+ }
+ // adjust the colOrder
+ var tmp = g.colOrder[oldn];
+ g.colOrder.splice(oldn, 1);
+ g.colOrder.splice(newn, 0, tmp);
+ // adjust the colVisib
+ if (g.colVisib.length > 0) {
+ tmp = g.colVisib[oldn];
+ g.colVisib.splice(oldn, 1);
+ g.colVisib.splice(newn, 0, tmp);
+ }
+ },
+ /**
+ * Find currently hovered table column's header (excluding actions column).
+ *
+ * @param e event
+ * @return {object|undefined} the hovered column's th object or undefined if no hovered column found.
+ */
+ getHoveredCol: function (e) {
+ var hoveredCol;
+ var $headers = $(g.t).find('th.draggable:visible');
+ $headers.each(function () {
+ var left = $(this).offset().left;
+ var right = left + $(this).outerWidth();
+ if (left <= e.pageX && e.pageX <= right) {
+ hoveredCol = this;
+ }
+ });
+ return hoveredCol;
+ },
+ /**
+ * Get a zero-based index from a tag in a table.
+ *
+ * @param obj table header object
+ * @return {number} zero-based index of the specified table header in the set of table headers (visible or not)
+ */
+ getHeaderIdx: function (obj) {
+ return $(obj).parents('tr').find('th.draggable').index(obj);
+ },
+ /**
+ * Reposition the columns back to normal order.
+ */
+ restoreColOrder: function () {
+ // use insertion sort, since we already have shiftCol function
+ for (var i = 1; i < g.colOrder.length; i++) {
+ var x = g.colOrder[i];
+ var j = i - 1;
+ while (j >= 0 && x < g.colOrder[j]) {
+ j--;
+ }
+ if (j !== i - 1) {
+ g.shiftCol(i, j + 1);
+ }
+ }
+ if (g.tableCreateTime) {
+ // send request to server to remember the column order
+ g.sendColPrefs();
+ }
+ g.refreshRestoreButton();
+ },
+ /**
+ * Send column preferences (column order and visibility) to the server.
+ */
+ sendColPrefs: function () {
+ if ($(g.t).is('.ajax')) {
+ // only send preferences if ajax class
+ if (typeof g.db !== 'string' && typeof g.table !== 'string') {
+ // The server has nothing to do with it
+ // Issue: https://github.com/phpmyadmin/phpmyadmin/issues/15658
+ return;
+ }
+ var postParams = {
+ 'ajax_request': true,
+ 'db': g.db,
+ 'table': g.table,
+ 'token': g.token,
+ 'server': g.server,
+ 'table_create_time': g.tableCreateTime
+ };
+ if (g.colOrder.length > 0) {
+ $.extend(postParams, {
+ 'col_order': g.colOrder.toString()
+ });
+ }
+ if (g.colVisib.length > 0) {
+ $.extend(postParams, {
+ 'col_visib': g.colVisib.toString()
+ });
+ }
+ $.post('index.php?route=/sql/set-column-preferences', postParams, function (data) {
+ if (data.success !== true) {
+ var $tempDiv = $(document.createElement('div'));
+ $tempDiv.html(data.error);
+ $tempDiv.addClass('alert alert-danger');
+ Functions.ajaxShowMessage($tempDiv, false);
+ }
+ });
+ }
+ },
+ /**
+ * Refresh restore button state.
+ * Make restore button disabled if the table is similar with initial state.
+ */
+ refreshRestoreButton: function () {
+ // check if table state is as initial state
+ var isInitial = true;
+ for (var i = 0; i < g.colOrder.length; i++) {
+ if (g.colOrder[i] !== i) {
+ isInitial = false;
+ break;
+ }
+ }
+ // check if only one visible column left
+ var isOneColumn = g.visibleHeadersCount === 1;
+ // enable or disable restore button
+ if (isInitial || isOneColumn) {
+ $(g.o).find('div.restore_column').hide();
+ } else {
+ $(g.o).find('div.restore_column').show();
+ }
+ },
+ /**
+ * Update current hint using the boolean values (showReorderHint, showSortHint, etc.).
+ *
+ * @return {string}
+ *
+ */
+ updateHint: function () {
+ var text = '';
+ if (!g.colRsz && !g.colReorder) {
+ // if not resizing or dragging
+ if (g.visibleHeadersCount > 1) {
+ g.showReorderHint = true;
+ }
+ if ($(t).find('th.marker').length > 0) {
+ g.showMarkHint = true;
+ }
+ if (g.showSortHint && g.sortHint) {
+ text += text.length > 0 ? ' ' : '';
+ text += '- ' + g.sortHint;
+ }
+ if (g.showMultiSortHint && g.strMultiSortHint) {
+ text += text.length > 0 ? ' ' : '';
+ text += '- ' + g.strMultiSortHint;
+ }
+ if (g.showMarkHint && g.markHint && !g.showSortHint &&
+ // we do not show mark hint, when sort hint is shown
+ g.showReorderHint && g.reorderHint) {
+ text += text.length > 0 ? ' ' : '';
+ text += '- ' + g.reorderHint;
+ text += text.length > 0 ? ' ' : '';
+ text += '- ' + g.markHint;
+ text += text.length > 0 ? ' ' : '';
+ text += '- ' + g.copyHint;
+ }
+ }
+ return text;
+ },
+ /**
+ * Toggle column's visibility.
+ * After calling this function and it returns true, afterToggleCol() must be called.
+ *
+ * @param {number} n
+ *
+ * @return {boolean} True if the column is toggled successfully.
+ */
+ toggleCol: function (n) {
+ if (g.colVisib[n]) {
+ // can hide if more than one column is visible
+ if (g.visibleHeadersCount > 1) {
+ $(g.t).find('tr').each(function () {
+ $(this).find('th.draggable').eq(n).add($(this).find('td').eq(g.actionSpan + n)).hide();
+ });
+ g.colVisib[n] = 0;
+ $(g.cList).find('.lDiv div').eq(n).find('input').prop('checked', false);
+ } else {
+ // cannot hide, force the checkbox to stay checked
+ $(g.cList).find('.lDiv div').eq(n).find('input').prop('checked', true);
+ return false;
+ }
+ } else {
+ // column n is not visible
+ $(g.t).find('tr').each(function () {
+ $(this).find('th.draggable').eq(n).add($(this).find('td').eq(g.actionSpan + n)).show();
+ });
+ g.colVisib[n] = 1;
+ $(g.cList).find('.lDiv div').eq(n).find('input').prop('checked', true);
+ }
+ return true;
+ },
+ /**
+ * This must be called if toggleCol() returns is true.
+ *
+ * This function is separated from toggleCol because, sometimes, we want to toggle
+ * some columns together at one time and do just one adjustment after it, e.g. in showAllColumns().
+ */
+ afterToggleCol: function () {
+ // some adjustments after hiding column
+ g.reposRsz();
+ g.reposDrop();
+ g.sendColPrefs();
+
+ // check visible first row headers count
+ g.visibleHeadersCount = $(g.t).find('tr').first().find('th.draggable:visible').length;
+ g.refreshRestoreButton();
+
+ // Display minimum of one column - disable checkbox for hiding last column
+ if (g.visibleHeadersCount <= 1) {
+ $(g.cList).find('.lDiv div').each(function () {
+ $(this).find('input:checkbox:checked').prop('disabled', true);
+ });
+ } else {
+ // Remove disabled property if showing more than one column
+ $(g.cList).find('.lDiv div').each(function () {
+ $(this).find('input:checkbox:disabled').prop('disabled', false);
+ });
+ }
+ },
+ /**
+ * Show columns' visibility list.
+ *
+ * @param obj The drop down arrow of column visibility list
+ */
+ showColList: function (obj) {
+ // only show when not resizing or reordering
+ if (!g.colRsz && !g.colReorder) {
+ var pos = $(obj).position();
+ $(g.cList).css({
+ top: pos.top + $(obj).outerHeight(true)
+ }).show();
+ $(obj).addClass('coldrop-hover');
+ }
+ },
+ /**
+ * Hide columns' visibility list.
+ */
+ hideColList: function () {
+ $(g.cList).hide();
+ $(g.cDrop).find('.coldrop-hover').removeClass('coldrop-hover');
+ },
+ /**
+ * Reposition the column visibility drop-down arrow.
+ */
+ reposDrop: function () {
+ var $th = $(t).find('th:not(.draggable)');
+ for (var i = 0; i < $th.length; i++) {
+ var $cd = $(g.cDrop).find('div').eq(i); // column drop-down arrow
+ var pos = $($th[i]).position();
+ $cd.css({
+ left: pos.left + $($th[i]).width() - $cd.width(),
+ top: pos.top
+ });
+ }
+ },
+ /**
+ * Show all hidden columns.
+ */
+ showAllColumns: function () {
+ for (var i = 0; i < g.colVisib.length; i++) {
+ if (!g.colVisib[i]) {
+ g.toggleCol(i);
+ }
+ }
+ g.afterToggleCol();
+ },
+ /**
+ * Show edit cell, if it can be shown
+ *
+ * @param cell element to be edited
+ */
+ showEditCell: function (cell) {
+ // destroy the date picker instance left if any, see: #17703
+ var $datePickerInstance = $(g.cEdit).find('.hasDatepicker');
+ if ($datePickerInstance.length > 0) {
+ $datePickerInstance.datepicker('destroy');
+ }
+ if ($(cell).is('.grid_edit') && !g.colRsz && !g.colReorder) {
+ if (!g.isCellEditActive) {
+ var $cell = $(cell);
+ if ('string' === $cell.attr('data-type') || 'blob' === $cell.attr('data-type') || 'json' === $cell.attr('data-type')) {
+ g.cEdit = g.cEditTextarea;
+ } else {
+ g.cEdit = g.cEditStd;
+ }
+
+ // remove all edit area and hide it
+ $(g.cEdit).find('.edit_area').empty().hide();
+ // reposition the cEdit element
+ $(g.cEdit).css({
+ top: $cell.position().top,
+ left: $cell.position().left
+ }).show().find('.edit_box').css({
+ width: $cell.outerWidth(),
+ height: $cell.outerHeight()
+ });
+ // fill the cell edit with text from
+ var value = Functions.getCellValue(cell);
+ if ($cell.attr('data-type') === 'json' && $cell.is('.truncated') === false) {
+ value = Functions.stringifyJSON(value, null, 4);
+ }
+ $(g.cEdit).find('.edit_box').val(value);
+ g.currentEditCell = cell;
+ $(g.cEdit).find('.edit_box').trigger('focus');
+ moveCursorToEnd($(g.cEdit).find('.edit_box'));
+ $(g.cEdit).find('*').prop('disabled', false);
+ }
+ }
+ function moveCursorToEnd(input) {
+ var originalValue = input.val();
+ var originallength = originalValue.length;
+ input.val('');
+ input.trigger('blur').trigger('focus').val(originalValue);
+ input[0].setSelectionRange(originallength, originallength);
+ }
+ },
+ /**
+ * Remove edit cell and the edit area, if it is shown.
+ *
+ * @param force Optional, force to hide edit cell without saving edited field.
+ * @param data Optional, data from the POST AJAX request to save the edited field
+ * or just specify "true", if we want to replace the edited field with the new value.
+ * @param field Optional, the edited . If not specified, the function will
+ * use currently edited from g.currentEditCell.
+ * @param options Optional, this object contains a boolean named move (true, if called from move* functions)
+ * and a to which the grid_edit should move
+ */
+ hideEditCell: function (force, data, field, options) {
+ if (g.isCellEditActive && !force) {
+ // cell is being edited, save or post the edited data
+ if (options !== undefined) {
+ g.saveOrPostEditedCell(options);
+ } else {
+ g.saveOrPostEditedCell();
+ }
+ return;
+ }
+
+ // cancel any previous request
+ if (g.lastXHR !== null) {
+ g.lastXHR.abort();
+ g.lastXHR = null;
+ }
+ if (data) {
+ if (g.currentEditCell) {
+ // save value of currently edited cell
+ // replace current edited field with the new value
+ var $thisField = $(g.currentEditCell);
+ var isNull = $thisField.data('value') === null;
+ if (isNull) {
+ $thisField.find('span').html('NULL');
+ $thisField.addClass('null');
+ } else {
+ $thisField.removeClass('null');
+ var value = data.isNeedToRecheck ? data.truncatableFieldValue : $thisField.data('value');
+
+ // Truncates the text.
+ $thisField.removeClass('truncated');
+ if (CommonParams.get('pftext') === 'P' && value.length > g.maxTruncatedLen) {
+ $thisField.addClass('truncated');
+ value = value.substring(0, g.maxTruncatedLen) + '...';
+ }
+
+ // Add before carriage return.
+ var newHtml = Functions.escapeHtml(value);
+ newHtml = newHtml.replace(/\n/g, ' \n');
+ var decimals = parseInt($thisField.attr('data-decimals'));
+
+ // remove decimal places if column type not supported
+ if (decimals === 0 && $thisField.attr('data-type').indexOf('time') !== -1) {
+ newHtml = newHtml.substring(0, newHtml.indexOf('.'));
+ }
+
+ // remove additional decimal places
+ if (decimals > 0 && $thisField.attr('data-type').indexOf('time') !== -1) {
+ newHtml = newHtml.substring(0, newHtml.length - (6 - decimals));
+ }
+ var selector = 'span';
+ if ($thisField.hasClass('hex') && $thisField.find('a').length) {
+ selector = 'a';
+ }
+
+ // Updates the code keeping highlighting (if any).
+ var $target = $thisField.find(selector);
+ if (!Functions.updateCode($target, newHtml, value)) {
+ $target.html(newHtml);
+ }
+ }
+ if ($thisField.is('.bit')) {
+ $thisField.find('span').text($thisField.data('value'));
+ }
+ }
+ if (data.transformations !== undefined) {
+ $.each(data.transformations, function (cellIndex, value) {
+ var $thisField = $(g.t).find('.to_be_saved').eq(cellIndex);
+ $thisField.find('span').html(value);
+ });
+ }
+ if (data.relations !== undefined) {
+ $.each(data.relations, function (cellIndex, value) {
+ var $thisField = $(g.t).find('.to_be_saved').eq(cellIndex);
+ $thisField.find('span').html(value);
+ });
+ }
+
+ // refresh the grid
+ g.reposRsz();
+ g.reposDrop();
+ }
+
+ // hide the cell editing area
+ $(g.cEdit).hide();
+ $(g.cEdit).find('.edit_box').trigger('blur');
+ g.isCellEditActive = false;
+ g.currentEditCell = null;
+ // destroy datepicker in edit area, if exist
+ var $dp = $(g.cEdit).find('.hasDatepicker');
+ if ($dp.length > 0) {
+ // eslint-disable-next-line no-underscore-dangle
+ $(document).on('mousedown', $.datepicker._checkExternalClick);
+ $dp.datepicker('refresh');
+
+ // change the cursor in edit box back to normal
+ // (the cursor become a hand pointer when we add datepicker)
+ $(g.cEdit).find('.edit_box').css('cursor', 'inherit');
+ }
+ },
+ /**
+ * Show drop-down edit area when edit cell is focused.
+ */
+ showEditArea: function () {
+ if (!g.isCellEditActive) {
+ // make sure the edit area has not been shown
+ g.isCellEditActive = true;
+ g.isEditCellTextEditable = false;
+ /**
+ * @var $td current edited cell
+ */
+ var $td = $(g.currentEditCell);
+ /**
+ * @var $editArea the editing area
+ */
+ var $editArea = $(g.cEdit).find('.edit_area');
+ /**
+ * @var whereClause WHERE clause for the edited cell
+ */
+ var whereClause = $td.parent('tr').find('.where_clause').val();
+ /**
+ * @var fieldName String containing the name of this field.
+ * @see Sql.getFieldName()
+ */
+ var fieldName = Sql.getFieldName($(t), $td);
+ /**
+ * @var relationCurrValue String current value of the field (for fields that are foreign keyed).
+ */
+ var relationCurrValue = $td.text();
+ /**
+ * @var relationKeyOrDisplayColumn String relational key if in 'Relational display column' mode,
+ * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
+ */
+ var relationKeyOrDisplayColumn = $td.find('a').attr('title');
+ /**
+ * @var currValue String current value of the field (for fields that are of type enum or set).
+ */
+ var currValue = $td.find('span').text();
+
+ // empty all edit area, then rebuild it based on $td classes
+ $editArea.empty();
+
+ // remember this instead of testing more than once
+ var isNull = $td.is('.null');
+
+ // add goto link, if this cell contains a link
+ if ($td.find('a').length > 0) {
+ var gotoLink = document.createElement('div');
+ gotoLink.className = 'goto_link';
+ $(gotoLink).append(g.gotoLinkText + ' ').append($td.find('a').clone());
+ $editArea.append(gotoLink);
+ }
+ g.wasEditedCellNull = false;
+ if ($td.is(':not(.not_null)')) {
+ // append a null checkbox
+ $editArea.append('NULL:
');
+ var $checkbox = $editArea.find('.null_div input');
+ // check if current is NULL
+ if (isNull) {
+ $checkbox.prop('checked', true);
+ g.wasEditedCellNull = true;
+ }
+
+ // if the select/editor is changed un-check the 'checkbox_null__'.
+ if ($td.is('.enum, .set')) {
+ $editArea.on('change', 'select', function () {
+ $checkbox.prop('checked', false);
+ });
+ } else if ($td.is('.relation')) {
+ $editArea.on('change', 'select', function () {
+ $checkbox.prop('checked', false);
+ });
+ $editArea.on('click', '.browse_foreign', function () {
+ $checkbox.prop('checked', false);
+ });
+ } else {
+ $(g.cEdit).on('keypress change paste', '.edit_box', function () {
+ $checkbox.prop('checked', false);
+ });
+ // Capture ctrl+v (on IE and Chrome)
+ $(g.cEdit).on('keydown', '.edit_box', function (e) {
+ if (e.ctrlKey && e.which === 86) {
+ $checkbox.prop('checked', false);
+ }
+ });
+ $editArea.on('keydown', 'textarea', function () {
+ $checkbox.prop('checked', false);
+ });
+ }
+ // if some text is written in textbox automatically unmark the null checkbox and if it is emptied again mark the checkbox.
+ $(g.cEdit).find('.edit_box').on('input', function () {
+ if ($(g.cEdit).find('.edit_box').val() !== '') {
+ $checkbox.prop('checked', false);
+ } else {
+ $checkbox.prop('checked', true);
+ }
+ });
+ // if null checkbox is clicked empty the corresponding select/editor.
+ $checkbox.on('click', function () {
+ if ($td.is('.enum')) {
+ $editArea.find('select').val('');
+ } else if ($td.is('.set')) {
+ $editArea.find('select').find('option').each(function () {
+ var $option = $(this);
+ $option.prop('selected', false);
+ });
+ } else if ($td.is('.relation')) {
+ // if the dropdown is there to select the foreign value
+ if ($editArea.find('select').length > 0) {
+ $editArea.find('select').val('');
+ }
+ } else {
+ $editArea.find('textarea').val('');
+ }
+ $(g.cEdit).find('.edit_box').val('');
+ });
+ }
+
+ // reset the position of the edit_area div after closing datetime picker
+ $(g.cEdit).find('.edit_area').css({
+ 'top': '0',
+ 'position': ''
+ });
+ var postParams;
+ if ($td.is('.relation')) {
+ // handle relations
+ $editArea.addClass('edit_area_loading');
+
+ // initialize the original data
+ $td.data('original_data', null);
+
+ /**
+ * @var postParams Object containing parameters for the POST request
+ */
+ postParams = {
+ 'ajax_request': true,
+ 'server': g.server,
+ 'db': g.db,
+ 'table': g.table,
+ 'column': fieldName,
+ 'curr_value': relationCurrValue,
+ 'relation_key_or_display_column': relationKeyOrDisplayColumn
+ };
+ g.lastXHR = $.post('index.php?route=/sql/get-relational-values', postParams, function (data) {
+ g.lastXHR = null;
+ $editArea.removeClass('edit_area_loading');
+ if ($(data.dropdown).is('select')) {
+ // save original_data
+ var value = $(data.dropdown).val();
+ $td.data('original_data', value);
+ // update the text input field, in case where the "Relational display column" is checked
+ $(g.cEdit).find('.edit_box').val(value);
+ }
+ $editArea.append(data.dropdown);
+ $editArea.append('' + g.cellEditHint + '
');
+
+ // for 'Browse foreign values' options,
+ // hide the value next to 'Browse foreign values' link
+ $editArea.find('span.curr_value').hide();
+ // handle update for new values selected from new window
+ $editArea.find('span.curr_value').on('change', function () {
+ $(g.cEdit).find('.edit_box').val($(this).text());
+ });
+ }); // end $.post()
+
+ $editArea.show();
+ $editArea.on('change', 'select', function () {
+ $(g.cEdit).find('.edit_box').val($(this).val());
+ });
+ g.isEditCellTextEditable = true;
+ } else if ($td.is('.enum')) {
+ // handle enum fields
+ $editArea.addClass('edit_area_loading');
+
+ /**
+ * @var postParams Object containing parameters for the POST request
+ */
+ postParams = {
+ 'ajax_request': true,
+ 'server': g.server,
+ 'db': g.db,
+ 'table': g.table,
+ 'column': fieldName,
+ 'curr_value': currValue
+ };
+ g.lastXHR = $.post('index.php?route=/sql/get-enum-values', postParams, function (data) {
+ g.lastXHR = null;
+ if (typeof data === 'object' && data.success === false) {
+ Functions.ajaxShowMessage(data.error, undefined, 'error');
+ return;
+ }
+ $editArea.removeClass('edit_area_loading');
+ $editArea.append(data.dropdown);
+ $editArea.append('' + g.cellEditHint + '
');
+ }); // end $.post()
+
+ $editArea.show();
+ $editArea.on('change', 'select', function () {
+ $(g.cEdit).find('.edit_box').val($(this).val());
+ });
+ } else if ($td.is('.set')) {
+ // handle set fields
+ $editArea.addClass('edit_area_loading');
+
+ // if the data is truncated, get the full data
+ if ($td.is('.truncated')) {
+ postParams = {
+ 'ajax_request': true,
+ 'server': g.server,
+ 'db': g.db,
+ 'table': g.table,
+ 'column': fieldName,
+ 'curr_value': currValue,
+ 'get_full_values': true,
+ 'where_clause': whereClause
+ };
+ } else {
+ postParams = {
+ 'ajax_request': true,
+ 'server': g.server,
+ 'db': g.db,
+ 'table': g.table,
+ 'column': fieldName,
+ 'curr_value': currValue
+ };
+ }
+ g.lastXHR = $.post('index.php?route=/sql/get-set-values', postParams, function (data) {
+ g.lastXHR = null;
+ if (typeof data === 'object' && data.success === false) {
+ Functions.ajaxShowMessage(data.error, undefined, 'error');
+ return;
+ }
+ $editArea.removeClass('edit_area_loading');
+ $editArea.append(data.select);
+ $td.data('original_data', $(data.select).val().join());
+ $editArea.append('' + g.cellEditHint + '
');
+ }); // end $.post()
+
+ $editArea.show();
+ $editArea.on('change', 'select', function () {
+ $(g.cEdit).find('.edit_box').val($(this).val());
+ });
+ } else if ($td.is('.truncated, .transformed')) {
+ if ($td.is('.to_be_saved')) {
+ // cell has been edited
+ var value = $td.data('value');
+ $(g.cEdit).find('.edit_box').val(value);
+ $editArea.append('');
+ $editArea.find('textarea').val(value);
+ $editArea.on('keyup', 'textarea', function () {
+ $(g.cEdit).find('.edit_box').val($(this).val());
+ });
+ $(g.cEdit).on('keyup', '.edit_box', function () {
+ $editArea.find('textarea').val($(this).val());
+ });
+ $editArea.append('' + g.cellEditHint + '
');
+ } else {
+ // handle truncated/transformed values values
+ $editArea.addClass('edit_area_loading');
+
+ // initialize the original data
+ $td.data('original_data', null);
+
+ /**
+ * @var sqlQuery String containing the SQL query used to retrieve value of truncated/transformed data
+ */
+ var sqlQuery = 'SELECT `' + fieldName + '` FROM `' + g.table + '` WHERE ' + whereClause;
+
+ // Make the Ajax call and get the data, wrap it and insert it
+ g.lastXHR = $.post('index.php?route=/sql', {
+ 'server': g.server,
+ 'db': g.db,
+ 'ajax_request': true,
+ 'sql_query': sqlQuery,
+ 'grid_edit': true
+ }, function (data) {
+ g.lastXHR = null;
+ $editArea.removeClass('edit_area_loading');
+ if (typeof data !== 'undefined' && data.success === true) {
+ if ($td.attr('data-type') === 'json') {
+ data.value = Functions.stringifyJSON(data.value, null, 4);
+ }
+ $td.data('original_data', data.value);
+ $(g.cEdit).find('.edit_box').val(data.value);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }
+
+ g.isEditCellTextEditable = true;
+ } else if ($td.is('.timefield, .datefield, .datetimefield, .timestampfield')) {
+ var $inputField = $(g.cEdit).find('.edit_box');
+
+ // remember current datetime value in $input_field, if it is not null
+ var datetimeValue = !isNull ? $inputField.val() : '';
+ var showMillisec = false;
+ var showMicrosec = false;
+ var timeFormat = 'HH:mm:ss';
+ // check for decimal places of seconds
+ if ($td.attr('data-decimals') > 0 && $td.attr('data-type').indexOf('time') !== -1) {
+ if (datetimeValue && datetimeValue.indexOf('.') === false) {
+ datetimeValue += '.';
+ }
+ if ($td.attr('data-decimals') > 3) {
+ showMillisec = true;
+ showMicrosec = true;
+ timeFormat = 'HH:mm:ss.lc';
+ if (datetimeValue) {
+ datetimeValue += '000000';
+ datetimeValue = datetimeValue.substring(0, datetimeValue.indexOf('.') + 7);
+ $inputField.val(datetimeValue);
+ }
+ } else {
+ showMillisec = true;
+ timeFormat = 'HH:mm:ss.l';
+ if (datetimeValue) {
+ datetimeValue += '000';
+ datetimeValue = datetimeValue.substring(0, datetimeValue.indexOf('.') + 4);
+ $inputField.val(datetimeValue);
+ }
+ }
+ }
+
+ // add datetime picker
+ Functions.addDatepicker($inputField, $td.attr('data-type'), {
+ showMillisec: showMillisec,
+ showMicrosec: showMicrosec,
+ timeFormat: timeFormat,
+ firstDay: firstDayOfCalendar
+ });
+ $inputField.on('keyup', function (e) {
+ if (e.which === 13) {
+ // post on pressing "Enter"
+ e.preventDefault();
+ e.stopPropagation();
+ g.saveOrPostEditedCell();
+ } else if (e.which !== 27) {
+ Functions.toggleDatepickerIfInvalid($td, $inputField);
+ }
+ });
+ $inputField.datepicker('show');
+ Functions.toggleDatepickerIfInvalid($td, $inputField);
+
+ // unbind the mousedown event to prevent the problem of
+ // datepicker getting closed, needs to be checked for any
+ // change in names when updating
+ // eslint-disable-next-line no-underscore-dangle
+ $(document).off('mousedown', $.datepicker._checkExternalClick);
+
+ // move ui-datepicker-div inside cEdit div
+ var datepickerDiv = $('#ui-datepicker-div');
+ datepickerDiv.css({
+ 'top': 0,
+ 'left': 0,
+ 'position': 'relative'
+ });
+ $(g.cEdit).append(datepickerDiv);
+
+ // cancel any click on the datepicker element
+ $editArea.find('> *').on('click', function (e) {
+ e.stopPropagation();
+ });
+ g.isEditCellTextEditable = true;
+ } else {
+ g.isEditCellTextEditable = true;
+ // only append edit area hint if there is a null checkbox
+ if ($editArea.children().length > 0) {
+ $editArea.append('' + g.cellEditHint + '
');
+ }
+ }
+ if ($editArea.children().length > 0) {
+ $editArea.show();
+ }
+ }
+ },
+ /**
+ * Post the content of edited cell.
+ *
+ * @param options Optional, this object contains a boolean named move (true, if called from move* functions)
+ * and a to which the grid_edit should move
+ */
+ postEditedCell: function (options) {
+ if (g.isSaving) {
+ return;
+ }
+ g.isSaving = true;
+ /**
+ * @var relationFields Array containing the name/value pairs of relational fields
+ */
+ var relationFields = {};
+ /**
+ * @var relationalDisplay string 'K' if relational key, 'D' if relational display column
+ */
+ var relationalDisplay = $(g.o).find('input[name=relational_display]:checked').val();
+ /**
+ * @var transformFields Array containing the name/value pairs for transformed fields
+ */
+ var transformFields = {};
+ /**
+ * @var transformationFields Boolean, if there are any transformed fields in the edited cells
+ */
+ var transformationFields = false;
+ /**
+ * @var fullSqlQuery String containing the complete SQL query to update this table
+ */
+ var fullSqlQuery = '';
+ /**
+ * @var relFieldsList String, url encoded representation of {@link relations_fields}
+ */
+ var relFieldsList = '';
+ /**
+ * @var transformFieldsList String, url encoded representation of {@link transformFields}
+ */
+ var transformFieldsList = '';
+ /**
+ * @var fullWhereClause Array containing where clause for updated fields
+ */
+ var fullWhereClause = [];
+ /**
+ * @var isUnique Boolean, whether the rows in this table is unique or not
+ */
+ var isUnique = $(g.t).find('td.edit_row_anchor').is('.nonunique') ? 0 : 1;
+ /**
+ * multi edit variables
+ */
+ var multiEditFieldsName = [];
+ var multiEditFieldsType = [];
+ var multiEditFields = [];
+ var multiEditFieldsNull = [];
+
+ // alert user if edited table is not unique
+ if (!isUnique) {
+ alert(g.alertNonUnique);
+ }
+
+ // loop each edited row
+ $(g.t).find('td.to_be_saved').parents('tr').each(function () {
+ var $tr = $(this);
+ var whereClause = $tr.find('.where_clause').val();
+ if (typeof whereClause === 'undefined') {
+ whereClause = '';
+ }
+ fullWhereClause.push(whereClause);
+ var conditionArray = JSON.parse($tr.find('.condition_array').val());
+
+ /**
+ * multi edit variables, for current row
+ * @TODO array indices are still not correct, they should be md5 of field's name
+ */
+ var fieldsName = [];
+ var fieldsType = [];
+ var fields = [];
+ var fieldsNull = [];
+
+ // loop each edited cell in a row
+ $tr.find('.to_be_saved').each(function () {
+ /**
+ * @var $thisField Object referring to the td that is being edited
+ */
+ var $thisField = $(this);
+
+ /**
+ * @var fieldName String containing the name of this field.
+ * @see Sql.getFieldName()
+ */
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+
+ /**
+ * @var thisFieldParams Array temporary storage for the name/value of current field
+ */
+ var thisFieldParams = {};
+ if ($thisField.is('.transformed')) {
+ transformationFields = true;
+ }
+ thisFieldParams[fieldName] = $thisField.data('value');
+
+ /**
+ * @var isNull String capturing whether 'checkbox_null__' is checked.
+ */
+ var isNull = thisFieldParams[fieldName] === null;
+ fieldsName.push(fieldName);
+ if (isNull) {
+ fieldsNull.push('on');
+ fields.push('');
+ } else {
+ if ($thisField.is('.bit')) {
+ fieldsType.push('bit');
+ } else if ($thisField.hasClass('hex')) {
+ fieldsType.push('hex');
+ }
+ fieldsNull.push('');
+ if ($thisField.attr('data-type') !== 'json') {
+ fields.push($thisField.data('value'));
+ } else {
+ const JSONString = Functions.stringifyJSON($thisField.data('value'));
+ fields.push(JSONString);
+ }
+ var cellIndex = $thisField.index('.to_be_saved');
+ if ($thisField.is(':not(.relation, .enum, .set, .bit)')) {
+ if ($thisField.is('.transformed')) {
+ transformFields[cellIndex] = {};
+ $.extend(transformFields[cellIndex], thisFieldParams);
+ }
+ } else if ($thisField.is('.relation')) {
+ relationFields[cellIndex] = {};
+ $.extend(relationFields[cellIndex], thisFieldParams);
+ }
+ }
+ // check if edited field appears in WHERE clause
+ if (whereClause.indexOf(Sql.urlEncode(fieldName)) > -1) {
+ var fieldStr = '`' + g.table + '`.' + '`' + fieldName + '`';
+ for (var field in conditionArray) {
+ if (field.indexOf(fieldStr) > -1) {
+ conditionArray[field] = isNull ? 'IS NULL' : '= \'' + thisFieldParams[fieldName].replace(/'/g, '\'\'') + '\'';
+ break;
+ }
+ }
+ }
+ }); // end of loop for every edited cells in a row
+
+ // save new_clause
+ var newClause = '';
+ for (var field in conditionArray) {
+ newClause += field + ' ' + conditionArray[field] + ' AND ';
+ }
+ newClause = newClause.substring(0, newClause.length - 5); // remove the last AND
+ $tr.data('new_clause', newClause);
+ // save condition_array
+ $tr.find('.condition_array').val(JSON.stringify(conditionArray));
+ multiEditFieldsName.push(fieldsName);
+ multiEditFieldsType.push(fieldsType);
+ multiEditFields.push(fields);
+ multiEditFieldsNull.push(fieldsNull);
+ }); // end of loop for every edited rows
+
+ relFieldsList = $.param(relationFields);
+ transformFieldsList = $.param(transformFields);
+
+ // Make the Ajax post after setting all parameters
+ /**
+ * @var postParams Object containing parameters for the POST request
+ */
+ var postParams = {
+ 'ajax_request': true,
+ 'sql_query': fullSqlQuery,
+ 'server': g.server,
+ 'db': g.db,
+ 'table': g.table,
+ 'clause_is_unique': isUnique,
+ 'where_clause': fullWhereClause,
+ 'fields[multi_edit]': multiEditFields,
+ 'fields_name[multi_edit]': multiEditFieldsName,
+ 'fields_type[multi_edit]': multiEditFieldsType,
+ 'fields_null[multi_edit]': multiEditFieldsNull,
+ 'rel_fields_list': relFieldsList,
+ 'do_transformations': transformationFields,
+ 'transform_fields_list': transformFieldsList,
+ 'relational_display': relationalDisplay,
+ 'goto': encodeURIComponent('index.php?route=/sql'),
+ 'submit_type': 'save'
+ };
+ if (!g.saveCellsAtOnce) {
+ $(g.cEdit).find('*').prop('disabled', true);
+ $(g.cEdit).find('.edit_box').addClass('edit_box_posting');
+ } else {
+ $(g.o).find('div.save_edited').addClass('saving_edited_data').find('input').prop('disabled', true); // disable the save button
+ }
+
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/table/replace',
+ data: postParams,
+ success: function (data) {
+ g.isSaving = false;
+ if (!g.saveCellsAtOnce) {
+ $(g.cEdit).find('*').prop('disabled', false);
+ $(g.cEdit).find('.edit_box').removeClass('edit_box_posting');
+ } else {
+ $(g.o).find('div.save_edited').removeClass('saving_edited_data').find('input').prop('disabled', false); // enable the save button back
+ }
+
+ if (typeof data !== 'undefined' && data.success === true) {
+ if (typeof options === 'undefined' || !options.move) {
+ Functions.ajaxShowMessage(data.message);
+ }
+
+ // update where_clause related data in each edited row
+ $(g.t).find('td.to_be_saved').parents('tr').each(function () {
+ var newClause = $(this).data('new_clause');
+ var $whereClause = $(this).find('.where_clause');
+ var oldClause = $whereClause.val();
+ var decodedOldClause = oldClause;
+ var decodedNewClause = newClause;
+ $whereClause.val(newClause);
+ // update Edit, Copy, and Delete links also
+ $(this).find('a').each(function () {
+ $(this).attr('href', $(this).attr('href').replace(oldClause, newClause));
+ // update delete confirmation in Delete link
+ if ($(this).attr('href').indexOf('DELETE') > -1) {
+ $(this).removeAttr('onclick').off('click').on('click', function () {
+ return Functions.confirmLink(this, 'DELETE FROM `' + g.db + '`.`' + g.table + '` WHERE ' + decodedNewClause + (isUnique ? '' : ' LIMIT 1'));
+ });
+ }
+ });
+ // update the multi edit checkboxes
+ $(this).find('input[type=checkbox]').each(function () {
+ var $checkbox = $(this);
+ var checkboxName = $checkbox.attr('name');
+ var checkboxValue = $checkbox.val();
+ $checkbox.attr('name', checkboxName.replace(oldClause, newClause));
+ $checkbox.val(checkboxValue.replace(decodedOldClause, decodedNewClause));
+ });
+ });
+ // update the display of executed SQL query command
+ if (typeof data.sql_query !== 'undefined') {
+ // extract query box
+ var $resultQuery = $($.parseHTML(data.sql_query));
+ var sqlOuter = $resultQuery.find('.sqlOuter').wrap('').parent().html();
+ var tools = $resultQuery.find('.tools').wrap('
').parent().html();
+ // sqlOuter and tools will not be present if 'Show SQL queries' configuration is off
+ if (typeof sqlOuter !== 'undefined' && typeof tools !== 'undefined') {
+ $(g.o).find('.result_query').not($(g.o).find('.result_query').last()).remove();
+ var $existingQuery = $(g.o).find('.result_query');
+ // If two query box exists update query in second else add a second box
+ if ($existingQuery.find('div.sqlOuter').length > 1) {
+ $existingQuery.children().eq(3).remove();
+ $existingQuery.children().eq(3).remove();
+ $existingQuery.append(sqlOuter + tools);
+ } else {
+ $existingQuery.append(sqlOuter + tools);
+ }
+ Functions.highlightSql($existingQuery);
+ }
+ }
+ // hide and/or update the successfully saved cells
+ g.hideEditCell(true, data);
+
+ // remove the "Save edited cells" button
+ $(g.o).find('div.save_edited').hide();
+ // update saved fields
+ $(g.t).find('.to_be_saved').removeClass('to_be_saved').data('value', null).data('original_data', null);
+ g.isCellEdited = false;
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ if (!g.saveCellsAtOnce) {
+ $(g.t).find('.to_be_saved').removeClass('to_be_saved');
+ }
+ }
+ }
+ }).done(function () {
+ if (options !== undefined && options.move) {
+ g.showEditCell(options.cell);
+ }
+ }); // end $.ajax()
+ },
+
+ /**
+ * Save edited cell, so it can be posted later.
+ *
+ * @return {bool}
+ */
+ saveEditedCell: function () {
+ /**
+ * @var $thisField Object referring to the td that is being edited
+ */
+ var $thisField = $(g.currentEditCell);
+ var $testElement = ''; // to test the presence of a element
+
+ var needToPost = false;
+
+ /**
+ * @var fieldName String containing the name of this field.
+ * @see Sql.getFieldName()
+ */
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+
+ /**
+ * @var thisFieldParams Array temporary storage for the name/value of current field
+ */
+ var thisFieldParams = {};
+
+ /**
+ * @var isNull String capturing whether 'checkbox_null__' is checked.
+ */
+ var isNull = $(g.cEdit).find('input:checkbox').is(':checked');
+ if ($(g.cEdit).find('.edit_area').is('.edit_area_loading')) {
+ // the edit area is still loading (retrieving cell data), no need to post
+ needToPost = false;
+ } else if (isNull) {
+ if (!g.wasEditedCellNull) {
+ thisFieldParams[fieldName] = null;
+ needToPost = true;
+ }
+ } else {
+ if ($thisField.is('.bit')) {
+ thisFieldParams[fieldName] = $(g.cEdit).find('.edit_box').val();
+ } else if ($thisField.is('.set')) {
+ $testElement = $(g.cEdit).find('select');
+ thisFieldParams[fieldName] = $testElement.map(function () {
+ return $(this).val();
+ }).get().join(',');
+ } else if ($thisField.is('.relation, .enum')) {
+ // for relation and enumeration, take the results from edit box value,
+ // because selected value from drop-down, new window or multiple
+ // selection list will always be updated to the edit box
+ thisFieldParams[fieldName] = $(g.cEdit).find('.edit_box').val();
+ } else if ($thisField.hasClass('hex')) {
+ if ($(g.cEdit).find('.edit_box').val().match(/^(0x)?[a-f0-9]*$/i) !== null) {
+ thisFieldParams[fieldName] = $(g.cEdit).find('.edit_box').val();
+ } else {
+ var hexError = '' + Messages.strEnterValidHex + '
';
+ Functions.ajaxShowMessage(hexError, false);
+ thisFieldParams[fieldName] = Functions.getCellValue(g.currentEditCell);
+ }
+ } else {
+ thisFieldParams[fieldName] = $(g.cEdit).find('.edit_box').val();
+ }
+ let isValueUpdated;
+ if ($thisField.attr('data-type') !== 'json') {
+ isValueUpdated = thisFieldParams[fieldName] !== Functions.getCellValue(g.currentEditCell);
+ } else {
+ const JSONString = Functions.stringifyJSON(thisFieldParams[fieldName]);
+ isValueUpdated = JSONString !== JSON.stringify(JSON.parse(Functions.getCellValue(g.currentEditCell)));
+ }
+ if (g.wasEditedCellNull || isValueUpdated) {
+ needToPost = true;
+ }
+ }
+ if (needToPost) {
+ $(g.currentEditCell).addClass('to_be_saved').data('value', thisFieldParams[fieldName]);
+ if (g.saveCellsAtOnce) {
+ $(g.o).find('div.save_edited').show();
+ }
+ g.isCellEdited = true;
+ }
+ return needToPost;
+ },
+ /**
+ * Save or post currently edited cell, depending on the "saveCellsAtOnce" configuration.
+ *
+ * @param options Optional, this object contains a boolean named move (true, if called from move* functions)
+ * and a to which the grid_edit should move
+ */
+ saveOrPostEditedCell: function (options) {
+ var saved = g.saveEditedCell();
+ // Check if $cfg['SaveCellsAtOnce'] is false
+ if (!g.saveCellsAtOnce) {
+ // Check if need_to_post is true
+ if (saved) {
+ // Check if this function called from 'move' functions
+ if (options !== undefined && options.move) {
+ g.postEditedCell(options);
+ } else {
+ g.postEditedCell();
+ }
+ // need_to_post is false
+ } else {
+ // Check if this function called from 'move' functions
+ if (options !== undefined && options.move) {
+ g.hideEditCell(true);
+ g.showEditCell(options.cell);
+ // NOT called from 'move' functions
+ } else {
+ g.hideEditCell(true);
+ }
+ }
+ // $cfg['SaveCellsAtOnce'] is true
+ } else {
+ // If need_to_post
+ if (saved) {
+ // If this function called from 'move' functions
+ if (options !== undefined && options.move) {
+ g.hideEditCell(true, true, false, options);
+ g.showEditCell(options.cell);
+ // NOT called from 'move' functions
+ } else {
+ g.hideEditCell(true, true);
+ }
+ } else {
+ // If this function called from 'move' functions
+ if (options !== undefined && options.move) {
+ g.hideEditCell(true, false, false, options);
+ g.showEditCell(options.cell);
+ // NOT called from 'move' functions
+ } else {
+ g.hideEditCell(true);
+ }
+ }
+ }
+ },
+ /**
+ * Initialize column resize feature.
+ */
+ initColResize: function () {
+ // create column resizer div
+ g.cRsz = document.createElement('div');
+ g.cRsz.className = 'cRsz';
+
+ // get data columns in the first row of the table
+ var $firstRowCols = $(g.t).find('tr').first().find('th.draggable');
+
+ // create column borders
+ $firstRowCols.each(function () {
+ var cb = document.createElement('div'); // column border
+ $(cb).addClass('colborder').on('mousedown', function (e) {
+ g.dragStartRsz(e, this);
+ });
+ $(g.cRsz).append(cb);
+ });
+ g.reposRsz();
+
+ // attach to global div
+ $(g.gDiv).prepend(g.cRsz);
+ },
+ /**
+ * Initialize column reordering feature.
+ */
+ initColReorder: function () {
+ g.cCpy = document.createElement('div'); // column copy, to store copy of dragged column header
+ g.cPointer = document.createElement('div'); // column pointer, used when reordering column
+
+ // adjust g.cCpy
+ g.cCpy.className = 'cCpy';
+ $(g.cCpy).hide();
+
+ // adjust g.cPointer
+ g.cPointer.className = 'cPointer';
+ $(g.cPointer).css('visibility', 'hidden'); // set visibility to hidden instead of calling hide() to force browsers to cache the image in cPointer class
+
+ // assign column reordering hint
+ g.reorderHint = Messages.strColOrderHint;
+
+ // get data columns in the first row of the table
+ var $firstRowCols = $(g.t).find('tr').first().find('th.draggable');
+
+ // initialize column order
+ var $colOrder = $(g.o).find('.col_order'); // check if column order is passed from PHP
+ var i;
+ if ($colOrder.length > 0) {
+ g.colOrder = $colOrder.val().split(',');
+ for (i = 0; i < g.colOrder.length; i++) {
+ g.colOrder[i] = parseInt(g.colOrder[i], 10);
+ }
+ } else {
+ g.colOrder = [];
+ for (i = 0; i < $firstRowCols.length; i++) {
+ g.colOrder.push(i);
+ }
+ }
+
+ // register events
+ $(g.t).find('th.draggable').on('mousedown', function (e) {
+ $(g.o).addClass('turnOffSelect');
+ if (g.visibleHeadersCount > 1) {
+ g.dragStartReorder(e, this);
+ }
+ }).on('mouseenter', function () {
+ if (g.visibleHeadersCount > 1) {
+ $(this).css('cursor', 'move');
+ } else {
+ $(this).css('cursor', 'inherit');
+ }
+ }).on('mouseleave', function () {
+ g.showReorderHint = false;
+ $(this).uiTooltip('option', {
+ content: g.updateHint()
+ });
+ }).on('dblclick', function (e) {
+ e.preventDefault();
+ var res = Functions.copyToClipboard($(this).data('column'));
+ if (res) {
+ Functions.ajaxShowMessage(Messages.strCopyColumnSuccess, false, 'success');
+ } else {
+ Functions.ajaxShowMessage(Messages.strCopyColumnFailure, false, 'error');
+ }
+ });
+ $(g.t).find('th.draggable a').on('dblclick', function (e) {
+ e.stopPropagation();
+ });
+ // restore column order when the restore button is clicked
+ $(g.o).find('div.restore_column').on('click', function () {
+ g.restoreColOrder();
+ });
+
+ // attach to global div
+ $(g.gDiv).append(g.cPointer);
+ $(g.gDiv).append(g.cCpy);
+
+ // prevent default "dragstart" event when dragging a link
+ $(g.t).find('th a').on('dragstart', function () {
+ return false;
+ });
+
+ // refresh the restore column button state
+ g.refreshRestoreButton();
+ },
+ /**
+ * Initialize column visibility feature.
+ */
+ initColVisib: function () {
+ g.cDrop = document.createElement('div'); // column drop-down arrows
+ g.cList = document.createElement('div'); // column visibility list
+
+ // adjust g.cDrop
+ g.cDrop.className = 'cDrop';
+
+ // adjust g.cList
+ g.cList.className = 'cList';
+ $(g.cList).hide();
+
+ // assign column visibility related hints
+ g.showAllColText = Messages.strShowAllCol;
+
+ // get data columns in the first row of the table
+ var $firstRowCols = $(g.t).find('tr').first().find('th.draggable');
+ var i;
+ // initialize column visibility
+ var $colVisib = $(g.o).find('.col_visib'); // check if column visibility is passed from PHP
+ if ($colVisib.length > 0) {
+ g.colVisib = $colVisib.val().split(',');
+ for (i = 0; i < g.colVisib.length; i++) {
+ g.colVisib[i] = parseInt(g.colVisib[i], 10);
+ }
+ } else {
+ g.colVisib = [];
+ for (i = 0; i < $firstRowCols.length; i++) {
+ g.colVisib.push(1);
+ }
+ }
+
+ // make sure we have more than one column
+ if ($firstRowCols.length > 1) {
+ var $colVisibTh = $(g.t).find('th:not(.draggable)').slice(0, 1);
+ Functions.tooltip($colVisibTh, 'th', Messages.strColVisibHint);
+
+ // create column visibility drop-down arrow(s)
+ $colVisibTh.each(function () {
+ var cd = document.createElement('div'); // column drop-down arrow
+ $(cd).addClass('coldrop').on('click', function () {
+ if (g.cList.style.display === 'none') {
+ g.showColList(this);
+ } else {
+ g.hideColList();
+ }
+ });
+ $(g.cDrop).append(cd);
+ });
+
+ // add column visibility control
+ g.cList.innerHTML = '
';
+ var $listDiv = $(g.cList).find('div');
+ var tempClick = function () {
+ if (g.toggleCol($(this).index())) {
+ g.afterToggleCol();
+ }
+ };
+ for (i = 0; i < $firstRowCols.length; i++) {
+ var currHeader = $firstRowCols[i];
+ var listElmt = document.createElement('div');
+ $(listElmt).text($(currHeader).text()).prepend(' ');
+ $listDiv.append(listElmt);
+ // add event on click
+ $(listElmt).on('click', tempClick);
+ }
+ // add "show all column" button
+ var showAll = document.createElement('div');
+ $(showAll).addClass('showAllColBtn').text(g.showAllColText);
+ $(g.cList).append(showAll);
+ $(showAll).on('click', function () {
+ g.showAllColumns();
+ });
+ // prepend "show all column" button at top if the list is too long
+ if ($firstRowCols.length > 10) {
+ var clone = showAll.cloneNode(true);
+ $(g.cList).prepend(clone);
+ $(clone).on('click', function () {
+ g.showAllColumns();
+ });
+ }
+ }
+
+ // hide column visibility list if we move outside the list
+ $(g.t).find('td, th.draggable').on('mouseenter', function () {
+ g.hideColList();
+ });
+
+ // attach to first row first col of the grid
+ var thFirst = $(g.t).find('th.d-print-none');
+ $(thFirst).append(g.cDrop);
+ $(thFirst).append(g.cList);
+
+ // some adjustment
+ g.reposDrop();
+ },
+ /**
+ * Move currently Editing Cell to Up
+ *
+ * @param e
+ *
+ */
+ moveUp: function (e) {
+ e.preventDefault();
+ var $thisField = $(g.currentEditCell);
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+ var whereClause = $thisField.parents('tr').first().find('.where_clause').val();
+ if (typeof whereClause === 'undefined') {
+ whereClause = '';
+ }
+ var found = false;
+ var $prevRow;
+ $thisField.parents('tr').first().parents('tbody').children().each(function () {
+ if ($(this).find('.where_clause').val() === whereClause) {
+ found = true;
+ }
+ if (!found) {
+ $prevRow = $(this);
+ }
+ });
+ var newCell;
+ if (found && $prevRow) {
+ $prevRow.children('td').each(function () {
+ if (Sql.getFieldName($(g.t), $(this)) === fieldName) {
+ newCell = this;
+ }
+ });
+ }
+ if (newCell) {
+ g.hideEditCell(false, false, false, {
+ move: true,
+ cell: newCell
+ });
+ }
+ },
+ /**
+ * Move currently Editing Cell to Down
+ *
+ * @param e
+ *
+ */
+ moveDown: function (e) {
+ e.preventDefault();
+ var $thisField = $(g.currentEditCell);
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+ var whereClause = $thisField.parents('tr').first().find('.where_clause').val();
+ if (typeof whereClause === 'undefined') {
+ whereClause = '';
+ }
+ var found = false;
+ var $nextRow;
+ var j = 0;
+ var nextRowFound = false;
+ $thisField.parents('tr').first().parents('tbody').children().each(function () {
+ if ($(this).find('.where_clause').val() === whereClause) {
+ found = true;
+ }
+ if (found) {
+ if (j >= 1 && !nextRowFound) {
+ $nextRow = $(this);
+ nextRowFound = true;
+ } else {
+ j++;
+ }
+ }
+ });
+ var newCell;
+ if (found && $nextRow) {
+ $nextRow.children('td').each(function () {
+ if (Sql.getFieldName($(g.t), $(this)) === fieldName) {
+ newCell = this;
+ }
+ });
+ }
+ if (newCell) {
+ g.hideEditCell(false, false, false, {
+ move: true,
+ cell: newCell
+ });
+ }
+ },
+ /**
+ * Move currently Editing Cell to Left
+ *
+ * @param e
+ *
+ */
+ moveLeft: function (e) {
+ e.preventDefault();
+ var $thisField = $(g.currentEditCell);
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+ var whereClause = $thisField.parents('tr').first().find('.where_clause').val();
+ if (typeof whereClause === 'undefined') {
+ whereClause = '';
+ }
+ var found = false;
+ var $foundRow;
+ $thisField.parents('tr').first().parents('tbody').children().each(function () {
+ if ($(this).find('.where_clause').val() === whereClause) {
+ found = true;
+ $foundRow = $(this);
+ }
+ });
+ var leftCell;
+ var cellFound = false;
+ if (found) {
+ $foundRow.children('td.grid_edit').each(function () {
+ if (Sql.getFieldName($(g.t), $(this)) === fieldName) {
+ cellFound = true;
+ }
+ if (!cellFound) {
+ leftCell = this;
+ }
+ });
+ }
+ if (leftCell) {
+ g.hideEditCell(false, false, false, {
+ move: true,
+ cell: leftCell
+ });
+ }
+ },
+ /**
+ * Move currently Editing Cell to Right
+ *
+ * @param e
+ *
+ */
+ moveRight: function (e) {
+ e.preventDefault();
+ var $thisField = $(g.currentEditCell);
+ var fieldName = Sql.getFieldName($(g.t), $thisField);
+ var whereClause = $thisField.parents('tr').first().find('.where_clause').val();
+ if (typeof whereClause === 'undefined') {
+ whereClause = '';
+ }
+ var found = false;
+ var $foundRow;
+ var j = 0;
+ $thisField.parents('tr').first().parents('tbody').children().each(function () {
+ if ($(this).find('.where_clause').val() === whereClause) {
+ found = true;
+ $foundRow = $(this);
+ }
+ });
+ var rightCell;
+ var cellFound = false;
+ var nextCellFound = false;
+ if (found) {
+ $foundRow.children('td.grid_edit').each(function () {
+ if (Sql.getFieldName($(g.t), $(this)) === fieldName) {
+ cellFound = true;
+ }
+ if (cellFound) {
+ if (j >= 1 && !nextCellFound) {
+ rightCell = this;
+ nextCellFound = true;
+ } else {
+ j++;
+ }
+ }
+ });
+ }
+ if (rightCell) {
+ g.hideEditCell(false, false, false, {
+ move: true,
+ cell: rightCell
+ });
+ }
+ },
+ /**
+ * Initialize grid editing feature.
+ */
+ initGridEdit: function () {
+ function startGridEditing(e, cell) {
+ if (g.isCellEditActive) {
+ g.saveOrPostEditedCell();
+ } else {
+ g.showEditCell(cell);
+ }
+ e.stopPropagation();
+ }
+ function handleCtrlNavigation(e) {
+ if (e.ctrlKey && e.which === 38 || e.altKey && e.which === 38) {
+ g.moveUp(e);
+ } else if (e.ctrlKey && e.which === 40 || e.altKey && e.which === 40) {
+ g.moveDown(e);
+ } else if (e.ctrlKey && e.which === 37 || e.altKey && e.which === 37) {
+ g.moveLeft(e);
+ } else if (e.ctrlKey && e.which === 39 || e.altKey && e.which === 39) {
+ g.moveRight(e);
+ }
+ }
+
+ // create cell edit wrapper element
+ g.cEditStd = document.createElement('div');
+ g.cEdit = g.cEditStd;
+ g.cEditTextarea = document.createElement('div');
+
+ // adjust g.cEditStd
+ g.cEditStd.className = 'cEdit';
+ $(g.cEditStd).html('
');
+ $(g.cEditStd).hide();
+
+ // adjust g.cEdit
+ g.cEditTextarea.className = 'cEdit';
+ $(g.cEditTextarea).html('
');
+ $(g.cEditTextarea).hide();
+
+ // assign cell editing hint
+ g.cellEditHint = Messages.strCellEditHint;
+ g.saveCellWarning = Messages.strSaveCellWarning;
+ g.alertNonUnique = Messages.strAlertNonUnique;
+ g.gotoLinkText = Messages.strGoToLink;
+
+ // initialize cell editing configuration
+ g.saveCellsAtOnce = $(g.o).find('.save_cells_at_once').val();
+ g.maxTruncatedLen = CommonParams.get('LimitChars');
+
+ // register events
+ $(g.t).find('td.data.click1').on('click', function (e) {
+ startGridEditing(e, this);
+ // prevent default action when clicking on "link" in a table
+ if ($(e.target).is('.grid_edit a')) {
+ e.preventDefault();
+ }
+ });
+ $(g.t).find('td.data.click2').on('click', function (e) {
+ var $cell = $(this);
+ // In the case of relational link, We want single click on the link
+ // to goto the link and double click to start grid-editing.
+ var $link = $(e.target);
+ if ($link.is('.grid_edit.relation a')) {
+ e.preventDefault();
+ // get the click count and increase
+ var clicks = $cell.data('clicks');
+ clicks = typeof clicks === 'undefined' ? 1 : clicks + 1;
+ if (clicks === 1) {
+ // if there are no previous clicks,
+ // start the single click timer
+ var timer = setTimeout(function () {
+ // temporarily remove ajax class so the page loader will not handle it,
+ // submit and then add it back
+ $link.removeClass('ajax');
+ AJAX.requestHandler.call($link[0]);
+ $link.addClass('ajax');
+ $cell.data('clicks', 0);
+ }, 700);
+ $cell.data('clicks', clicks);
+ $cell.data('timer', timer);
+ } else {
+ // When double clicking a link, switch to edit mode
+ // this is a double click, cancel the single click timer
+ // and make the click count 0
+ clearTimeout($cell.data('timer'));
+ $cell.data('clicks', 0);
+ // start grid-editing
+ startGridEditing(e, this);
+ }
+ }
+ }).on('dblclick', function (e) {
+ if ($(e.target).is('.grid_edit a')) {
+ e.preventDefault();
+ } else {
+ startGridEditing(e, this);
+ }
+ });
+ $(g.cEditStd).on('keydown', 'input.edit_box, select', handleCtrlNavigation);
+ $(g.cEditStd).find('.edit_box').on('focus', function () {
+ g.showEditArea();
+ });
+ $(g.cEditStd).on('keydown', '.edit_box, select', function (e) {
+ if (e.which === 13) {
+ // post on pressing "Enter"
+ e.preventDefault();
+ g.saveOrPostEditedCell();
+ }
+ });
+ $(g.cEditStd).on('keydown', function (e) {
+ if (!g.isEditCellTextEditable) {
+ // prevent text editing
+ e.preventDefault();
+ }
+ });
+ $(g.cEditTextarea).on('keydown', 'textarea.edit_box, select', handleCtrlNavigation);
+ $(g.cEditTextarea).find('.edit_box').on('focus', function () {
+ g.showEditArea();
+ });
+ $(g.cEditTextarea).on('keydown', '.edit_box, select', function (e) {
+ if (e.which === 13 && !e.shiftKey) {
+ // post on pressing "Enter"
+ e.preventDefault();
+ g.saveOrPostEditedCell();
+ }
+ });
+ $(g.cEditTextarea).on('keydown', function (e) {
+ if (!g.isEditCellTextEditable) {
+ // prevent text editing
+ e.preventDefault();
+ }
+ });
+ $('html').on('click', function (e) {
+ // hide edit cell if the click is not fromDat edit area
+ if ($(e.target).parents().index($(g.cEdit)) === -1 && !$(e.target).parents('.ui-datepicker-header').length && !$('.browse_foreign_modal.ui-dialog:visible').length && !$(e.target).closest('.dismissable').length) {
+ g.hideEditCell();
+ }
+ }).on('keydown', function (e) {
+ if (e.which === 27 && g.isCellEditActive) {
+ // cancel on pressing "Esc"
+ g.hideEditCell(true);
+ }
+ });
+ $(g.o).find('div.save_edited').on('click', function () {
+ g.hideEditCell();
+ g.postEditedCell();
+ });
+ $(window).on('beforeunload', function () {
+ if (g.isCellEdited) {
+ return g.saveCellWarning;
+ }
+ });
+
+ // attach to global div
+ $(g.gDiv).append(g.cEditStd);
+ $(g.gDiv).append(g.cEditTextarea);
+
+ // add hint for grid editing feature when hovering "Edit" link in each table row
+ if (Messages.strGridEditFeatureHint !== undefined) {
+ Functions.tooltip($(g.t).find('.edit_row_anchor a'), 'a', Messages.strGridEditFeatureHint);
+ }
+ }
+ };
+
+ /** ****************
+ * Initialize grid
+ ******************/
+
+ // wrap all truncated data cells with span indicating the original length
+ // todo update the original length after a grid edit
+ $(t).find('td.data.truncated:not(:has(span))').wrapInner(function () {
+ return ' ';
+ });
+
+ // wrap remaining cells, except actions cell, with span
+ $(t).find('th, td:not(:has(span))').wrapInner(' ');
+
+ // create grid elements
+ g.gDiv = document.createElement('div'); // create global div
+
+ // initialize the table variable
+ g.t = t;
+
+ // enclosing .sqlqueryresults div
+ g.o = $(t).parents('.sqlqueryresults');
+
+ // get data columns in the first row of the table
+ var $firstRowCols = $(t).find('tr').first().find('th.draggable');
+
+ // initialize visible headers count
+ g.visibleHeadersCount = $firstRowCols.filter(':visible').length;
+
+ // assign first column (actions) span
+ if (!$(t).find('tr').first().find('th').first().hasClass('draggable')) {
+ // action header exist
+ g.actionSpan = $(t).find('tr').first().find('th').first().prop('colspan');
+ } else {
+ g.actionSpan = 0;
+ }
+
+ // assign table create time
+ // table_create_time will only available if we are in "Browse" tab
+ g.tableCreateTime = $(g.o).find('.table_create_time').val();
+
+ // assign the hints
+ g.sortHint = Messages.strSortHint;
+ g.strMultiSortHint = Messages.strMultiSortHint;
+ g.markHint = Messages.strColMarkHint;
+ g.copyHint = Messages.strColNameCopyHint;
+
+ // assign common hidden inputs
+ var $commonHiddenInputs = $(g.o).find('div.common_hidden_inputs');
+ g.server = $commonHiddenInputs.find('input[name=server]').val();
+ g.db = $commonHiddenInputs.find('input[name=db]').val();
+ g.table = $commonHiddenInputs.find('input[name=table]').val();
+
+ // add table class
+ $(t).addClass('pma_table');
+
+ // add relative position to global div so that resize handlers are correctly positioned
+ $(g.gDiv).css('position', 'relative');
+
+ // link the global div
+ $(t).before(g.gDiv);
+ $(g.gDiv).append(t);
+
+ // FEATURES
+ if (isResizeEnabled) {
+ g.initColResize();
+ }
+ // disable reordering for result from EXPLAIN or SHOW syntax, which do not have a table navigation panel
+ if (isReorderEnabled && $(g.o).find('table.navigation').length > 0) {
+ g.initColReorder();
+ }
+ if (isVisibEnabled) {
+ g.initColVisib();
+ }
+ // make sure we have the ajax class
+ if (isGridEditEnabled && $(t).is('.ajax')) {
+ g.initGridEdit();
+ }
+
+ // create tooltip for each with draggable class
+ Functions.tooltip($(t).find('th.draggable'), 'th', g.updateHint());
+
+ // register events for hint tooltip (anchors inside draggable th)
+ $(t).find('th.draggable a').on('mouseenter', function () {
+ g.showSortHint = true;
+ g.showMultiSortHint = true;
+ $(t).find('th.draggable').uiTooltip('option', {
+ content: g.updateHint()
+ });
+ }).on('mouseleave', function () {
+ g.showSortHint = false;
+ g.showMultiSortHint = false;
+ $(t).find('th.draggable').uiTooltip('option', {
+ content: g.updateHint()
+ });
+ });
+
+ // register events for dragging-related feature
+ if (isResizeEnabled || isReorderEnabled) {
+ $(document).on('mousemove', function (e) {
+ g.dragMove(e);
+ });
+ $(document).on('mouseup', function (e) {
+ $(g.o).removeClass('turnOffSelect');
+ g.dragEnd(e);
+ });
+ }
+
+ // some adjustment
+ $(t).removeClass('data');
+ $(g.gDiv).addClass('data');
+};
+
+/**
+ * jQuery plugin to cancel selection in HTML code.
+ */
+(function ($) {
+ $.fn.noSelect = function (p) {
+ // no select plugin by Paulo P.Marinas
+ var prevent = p === null ? true : p;
+ /* eslint-disable compat/compat */
+ var isMsie = navigator.userAgent.indexOf('MSIE') > -1 || !!window.navigator.userAgent.match(/Trident.*rv:11\./);
+ var isFirefox = navigator.userAgent.indexOf('Firefox') > -1;
+ var isSafari = navigator.userAgent.indexOf('Safari') > -1;
+ var isOpera = navigator.userAgent.indexOf('Presto') > -1;
+ /* eslint-enable compat/compat */
+ if (prevent) {
+ return this.each(function () {
+ if (isMsie || isSafari) {
+ $(this).on('selectstart', false);
+ } else if (isFirefox) {
+ $(this).css('MozUserSelect', 'none');
+ $('body').trigger('focus');
+ } else if (isOpera) {
+ $(this).on('mousedown', false);
+ } else {
+ $(this).attr('unselectable', 'on');
+ }
+ });
+ } else {
+ return this.each(function () {
+ if (isMsie || isSafari) {
+ $(this).off('selectstart');
+ } else if (isFirefox) {
+ $(this).css('MozUserSelect', 'inherit');
+ } else if (isOpera) {
+ $(this).off('mousedown');
+ } else {
+ $(this).removeAttr('unselectable');
+ }
+ });
+ }
+ }; // end noSelect
+})(jQuery);
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/menu_resizer.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/menu_resizer.js
new file mode 100644
index 000000000..3f80d1d62
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/menu_resizer.js
@@ -0,0 +1,191 @@
+/**
+ * Handles the resizing of a menu according to the available screen width
+ *
+ * Uses themes/original/css/resizable-menu.css.php
+ *
+ * To initialize:
+ * $('#myMenu').menuResizer(function () {
+ * // This function will be called to find out how much
+ * // available horizontal space there is for the menu
+ * return $('body').width() - 5; // Some extra margin for good measure
+ * });
+ *
+ * To trigger a resize operation:
+ * $('#myMenu').menuResizer('resize'); // Bind this to $(window).resize()
+ *
+ * To restore the menu to a state like before it was initialized:
+ * $('#myMenu').menuResizer('destroy');
+ *
+ * @package PhpMyAdmin
+ */
+(function ($) {
+ function MenuResizer($container, widthCalculator) {
+ var self = this;
+ self.$container = $container;
+ self.widthCalculator = widthCalculator;
+ var windowWidth = $(window).width();
+ if (windowWidth < 768) {
+ $('#pma_navigation_resizer').css({
+ 'width': '0px'
+ });
+ }
+
+ // create submenu container
+ var link = $(' ', {
+ 'href': '#',
+ 'class': 'nav-link dropdown-toggle',
+ 'id': 'navbarDropdown',
+ 'role': 'button',
+ 'data-bs-toggle': 'dropdown',
+ 'aria-haspopup': 'true',
+ 'aria-expanded': 'false'
+ }).text(Messages.strMore);
+ var img = $container.find('li img');
+ if (img.length) {
+ $(Functions.getImage('b_more').toString()).prependTo(link);
+ }
+ var $submenu = $(' ', {
+ 'class': 'nav-item dropdown d-none'
+ }).append(link).append($('', {
+ 'class': 'dropdown-menu dropdown-menu-end',
+ 'aria-labelledby': 'navbarDropdown'
+ }));
+ $container.append($submenu);
+ setTimeout(function () {
+ self.resize();
+ }, 4);
+ }
+ MenuResizer.prototype.resize = function () {
+ var wmax = this.widthCalculator.call(this.$container);
+ var windowWidth = $(window).width();
+ var $submenu = this.$container.find('.nav-item.dropdown').last();
+ var submenuW = $submenu.outerWidth(true);
+ var $submenuUl = $submenu.find('.dropdown-menu');
+ var $li = this.$container.find('> li');
+ var $li2 = $submenuUl.find('.dropdown-item');
+ var moreShown = $li2.length > 0;
+ // Calculate the total width used by all the shown tabs
+ var totalLen = moreShown ? submenuW : 0;
+ var l = $li.length - 1;
+ var i;
+ for (i = 0; i < l; i++) {
+ totalLen += $($li[i]).outerWidth(true);
+ }
+
+ // eslint-disable-next-line compat/compat
+ var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
+ if (hasVScroll) {
+ windowWidth += 15;
+ }
+ if (windowWidth < 768) {
+ wmax = 2000;
+ }
+
+ // Now hide menu elements that don't fit into the menubar
+ var hidden = false; // Whether we have hidden any tabs
+ while (totalLen >= wmax && --l >= 0) {
+ // Process the tabs backwards
+ hidden = true;
+ var el = $($li[l]);
+ el.removeClass('nav-item').addClass('dropdown-item');
+ var elWidth = el.outerWidth(true);
+ el.data('width', elWidth);
+ if (!moreShown) {
+ totalLen -= elWidth;
+ el.prependTo($submenuUl);
+ totalLen += submenuW;
+ moreShown = true;
+ } else {
+ totalLen -= elWidth;
+ el.prependTo($submenuUl);
+ }
+ }
+ // If we didn't hide any tabs, then there might be some space to show some
+ if (!hidden) {
+ // Show menu elements that do fit into the menubar
+ for (i = 0, l = $li2.length; i < l; i++) {
+ totalLen += $($li2[i]).data('width');
+ // item fits or (it is the last item
+ // and it would fit if More got removed)
+ if (totalLen < wmax || i === $li2.length - 1 && totalLen - submenuW < wmax) {
+ $($li2[i]).removeClass('dropdown-item').addClass('nav-item');
+ $($li2[i]).insertBefore($submenu);
+ } else {
+ break;
+ }
+ }
+ }
+ // Show/hide the "More" tab as needed
+ if (windowWidth < 768) {
+ $('.navbar-collapse').css({
+ 'width': windowWidth - 80 - $('#pma_navigation').width()
+ });
+ $submenu.addClass('d-none');
+ $('.navbar-collapse').css({
+ 'overflow': 'hidden'
+ });
+ } else {
+ $('.navbar-collapse').css({
+ 'width': 'auto'
+ });
+ $('.navbar-collapse').css({
+ 'overflow': 'visible'
+ });
+ if ($submenuUl.find('li').length > 0) {
+ $submenu.removeClass('d-none');
+ } else {
+ $submenu.addClass('d-none');
+ }
+ }
+ };
+ MenuResizer.prototype.destroy = function () {
+ var $submenu = this.$container.find('.nav-item.dropdown').removeData();
+ $submenu.find('li').appendTo(this.$container);
+ $submenu.remove();
+ };
+
+ /** Public API */
+ var methods = {
+ init: function (widthCalculator) {
+ return this.each(function () {
+ var $this = $(this);
+ if (!$this.data('menuResizer')) {
+ $this.data('menuResizer', new MenuResizer($this, widthCalculator));
+ }
+ });
+ },
+ resize: function () {
+ return this.each(function () {
+ var self = $(this).data('menuResizer');
+ if (self) {
+ self.resize();
+ }
+ });
+ },
+ destroy: function () {
+ return this.each(function () {
+ var self = $(this).data('menuResizer');
+ if (self) {
+ self.destroy();
+ }
+ });
+ }
+ };
+
+ /**
+ * Extend jQuery
+ *
+ * @param {string} method
+ *
+ * @return {any}
+ */
+ $.fn.menuResizer = function (method) {
+ if (methods[method]) {
+ return methods[method].call(this);
+ } else if (typeof method === 'function') {
+ return methods.init.apply(this, [method]);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.menuResizer');
+ }
+ };
+})(jQuery);
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/multi_column_sort.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/multi_column_sort.js
new file mode 100644
index 000000000..f22925164
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/multi_column_sort.js
@@ -0,0 +1,31 @@
+/**
+ * @fileoverview Implements the shiftkey + click remove column
+ * from order by clause functionality
+ * @name columndelete
+ *
+ * @requires jQuery
+ */
+
+AJAX.registerOnload('keyhandler.js', function () {
+ $('th.draggable.column_heading.pointer.marker a').on('click', function (event) {
+ var orderUrlRemove = $(this).parent().find('input[name="url-remove-order"]').val();
+ var orderUrlAdd = $(this).parent().find('input[name="url-add-order"]').val();
+ var argsep = CommonParams.get('arg_separator');
+ if (event.ctrlKey || event.altKey) {
+ event.preventDefault();
+ AJAX.source = $(this);
+ Functions.ajaxShowMessage();
+ orderUrlRemove += argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ $.post('index.php?route=/sql', orderUrlRemove, AJAX.responseHandler);
+ } else if (event.shiftKey) {
+ event.preventDefault();
+ AJAX.source = $(this);
+ Functions.ajaxShowMessage();
+ orderUrlAdd += argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ $.post('index.php?route=/sql', orderUrlAdd, AJAX.responseHandler);
+ }
+ });
+});
+AJAX.registerTeardown('keyhandler.js', function () {
+ $(document).off('click', 'th.draggable.column_heading.pointer.marker a');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/name-conflict-fixes.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/name-conflict-fixes.js
new file mode 100644
index 000000000..46f68fb30
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/name-conflict-fixes.js
@@ -0,0 +1 @@
+$.widget.bridge('uiTooltip', $.ui.tooltip);
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/navigation.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/navigation.js
new file mode 100644
index 000000000..6260d2af5
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/navigation.js
@@ -0,0 +1,1490 @@
+/**
+ * function used in or for navigation panel
+ *
+ * @package phpMyAdmin-Navigation
+ */
+
+/* global isStorageSupported, setupRestoreField, setupValidation */ // js/config.js
+
+var Navigation = {};
+
+/**
+ * updates the tree state in sessionStorage
+ *
+ * @return {void}
+ */
+Navigation.treeStateUpdate = function () {
+ // update if session storage is supported
+ if (isStorageSupported('sessionStorage')) {
+ var storage = window.sessionStorage;
+ // try catch necessary here to detect whether
+ // content to be stored exceeds storage capacity
+ try {
+ storage.setItem('navTreePaths', JSON.stringify(Navigation.traverseForPaths()));
+ storage.setItem('server', CommonParams.get('server'));
+ storage.setItem('token', CommonParams.get('token'));
+ } catch (error) {
+ // storage capacity exceeded & old navigation tree
+ // state is no more valid, so remove it
+ storage.removeItem('navTreePaths');
+ storage.removeItem('server');
+ storage.removeItem('token');
+ }
+ }
+};
+
+/**
+ * updates the filter state in sessionStorage
+ *
+ * @param {string} filterName
+ * @param {string} filterValue
+ *
+ * @return {void}
+ */
+Navigation.filterStateUpdate = function (filterName, filterValue) {
+ if (isStorageSupported('sessionStorage')) {
+ var storage = window.sessionStorage;
+ try {
+ var currentFilter = $.extend({}, JSON.parse(storage.getItem('navTreeSearchFilters')));
+ var filter = {};
+ filter[filterName] = filterValue;
+ currentFilter = $.extend(currentFilter, filter);
+ storage.setItem('navTreeSearchFilters', JSON.stringify(currentFilter));
+ } catch (error) {
+ storage.removeItem('navTreeSearchFilters');
+ }
+ }
+};
+
+/**
+ * restores the filter state on navigation reload
+ *
+ * @return {void}
+ */
+Navigation.filterStateRestore = function () {
+ if (isStorageSupported('sessionStorage') && typeof window.sessionStorage.navTreeSearchFilters !== 'undefined') {
+ var searchClauses = JSON.parse(window.sessionStorage.navTreeSearchFilters);
+ if (Object.keys(searchClauses).length < 1) {
+ return;
+ }
+ // restore database filter if present and not empty
+ if (searchClauses.hasOwnProperty('dbFilter') && searchClauses.dbFilter.length) {
+ var $obj = $('#pma_navigation_tree');
+ if (!$obj.data('fastFilter')) {
+ $obj.data('fastFilter', new Navigation.FastFilter.Filter($obj, ''));
+ }
+ $obj.find('li.fast_filter.db_fast_filter input.searchClause').val(searchClauses.dbFilter).trigger('keyup');
+ }
+ // find all table filters present in the tree
+ var $tableFilters = $('#pma_navigation_tree li.database').children('div.list_container').find('li.fast_filter input.searchClause');
+ // restore table filters
+ $tableFilters.each(function () {
+ $obj = $(this).closest('div.list_container');
+ // aPath associated with this filter
+ var filterName = $(this).siblings('input[name=aPath]').val();
+ // if this table's filter has a state stored in storage
+ if (searchClauses.hasOwnProperty(filterName) && searchClauses[filterName].length) {
+ // clear state if item is not visible,
+ // happens when table filter becomes invisible
+ // as db filter has already been applied
+ if (!$obj.is(':visible')) {
+ Navigation.filterStateUpdate(filterName, '');
+ return true;
+ }
+ if (!$obj.data('fastFilter')) {
+ $obj.data('fastFilter', new Navigation.FastFilter.Filter($obj, ''));
+ }
+ $(this).val(searchClauses[filterName]).trigger('keyup');
+ }
+ });
+ }
+};
+
+/**
+ * Loads child items of a node and executes a given callback
+ *
+ * @param isNode
+ * @param $expandElem expander
+ * @param callback callback function
+ *
+ * @return {void}
+ */
+Navigation.loadChildNodes = function (isNode, $expandElem, callback) {
+ var $destination = null;
+ var params = null;
+ if (isNode) {
+ if (!$expandElem.hasClass('expander')) {
+ return;
+ }
+ $destination = $expandElem.closest('li');
+ var pos2Name = $expandElem.find('span.pos2_nav');
+ var pathsNav = $expandElem.find('span.paths_nav');
+ params = {
+ 'server': CommonParams.get('server'),
+ 'aPath': pathsNav.attr('data-apath'),
+ 'vPath': pathsNav.attr('data-vpath'),
+ 'pos': pathsNav.attr('data-pos'),
+ 'pos2_name': pos2Name.attr('data-name'),
+ 'pos2_value': pos2Name.attr('data-value'),
+ 'searchClause': '',
+ 'searchClause2': ''
+ };
+ if ($expandElem.closest('ul').hasClass('search_results')) {
+ params.searchClause = Navigation.FastFilter.getSearchClause();
+ params.searchClause2 = Navigation.FastFilter.getSearchClause2($expandElem);
+ }
+ } else {
+ $destination = $('#pma_navigation_tree_content');
+ params = {
+ 'server': CommonParams.get('server'),
+ 'aPath': $expandElem.attr('data-apath'),
+ 'vPath': $expandElem.attr('data-vpath'),
+ 'pos': $expandElem.attr('data-pos'),
+ 'pos2_name': '',
+ 'pos2_value': '',
+ 'searchClause': '',
+ 'searchClause2': ''
+ };
+ }
+ $.post('index.php?route=/navigation&ajax_request=1', params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ $destination.find('div.list_container').remove(); // FIXME: Hack, there shouldn't be a list container there
+ if (isNode) {
+ $destination.append(data.message);
+ $expandElem.addClass('loaded');
+ } else {
+ $destination.html(data.message);
+ $destination.children().first().css({
+ border: '0px',
+ margin: '0em',
+ padding: '0em'
+ }).slideDown('slow');
+ }
+ if (data.errors) {
+ var $errors = $(data.errors);
+ if ($errors.children().length > 0) {
+ $('#pma_errors').replaceWith(data.errors);
+ }
+ }
+ if (callback && typeof callback === 'function') {
+ callback(data);
+ }
+ } else if (typeof data !== 'undefined' && data.redirect_flag === '1') {
+ 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 {
+ var $throbber = $expandElem.find('img.throbber');
+ $throbber.hide();
+ var $icon = $expandElem.find('img.ic_b_plus');
+ $icon.show();
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+};
+
+/**
+ * Collapses a node in navigation tree.
+ *
+ * @param $expandElem expander
+ *
+ * @return {void}
+ */
+Navigation.collapseTreeNode = function ($expandElem) {
+ var $children = $expandElem.closest('li').children('div.list_container');
+ var $icon = $expandElem.find('img');
+ if ($expandElem.hasClass('loaded')) {
+ if ($icon.is('.ic_b_minus')) {
+ $icon.removeClass('ic_b_minus').addClass('ic_b_plus');
+ $children.slideUp('fast');
+ }
+ }
+ $expandElem.trigger('blur');
+ $children.promise().done(Navigation.treeStateUpdate);
+};
+
+/**
+ * Traverse the navigation tree backwards to generate all the actual
+ * and virtual paths, as well as the positions in the pagination at
+ * various levels, if necessary.
+ *
+ * @return {object}
+ */
+Navigation.traverseForPaths = function () {
+ var params = {
+ pos: $('#pma_navigation_tree').find('div.dbselector select').val()
+ };
+ if ($('#navi_db_select').length) {
+ return params;
+ }
+ var count = 0;
+ $('#pma_navigation_tree').find('a.expander:visible').each(function () {
+ if ($(this).find('img').is('.ic_b_minus') && $(this).closest('li').find('div.list_container .ic_b_minus').length === 0) {
+ var pathsNav = $(this).find('span.paths_nav');
+ params['n' + count + '_aPath'] = pathsNav.attr('data-apath');
+ params['n' + count + '_vPath'] = pathsNav.attr('data-vpath');
+ var pos2Nav = $(this).find('span.pos2_nav');
+ if (pos2Nav.length === 0) {
+ pos2Nav = $(this).parent().parent().find('span.pos2_nav').last();
+ }
+ params['n' + count + '_pos2_name'] = pos2Nav.attr('data-name');
+ params['n' + count + '_pos2_value'] = pos2Nav.attr('data-value');
+ var pos3Nav = $(this).find('span.pos3_nav');
+ params['n' + count + '_pos3_name'] = pos3Nav.attr('data-name');
+ params['n' + count + '_pos3_value'] = pos3Nav.attr('data-value');
+ count++;
+ }
+ });
+ return params;
+};
+
+/**
+ * Executed on page load
+ */
+$(function () {
+ if (!$('#pma_navigation').length) {
+ // Don't bother running any code if the navigation is not even on the page
+ return;
+ }
+
+ // Do not let the page reload on submitting the fast filter
+ $(document).on('submit', '.fast_filter', function (event) {
+ event.preventDefault();
+ });
+
+ // Fire up the resize handlers
+ new Navigation.ResizeHandler();
+
+ /**
+ * opens/closes (hides/shows) tree elements
+ * loads data via ajax
+ */
+ $(document).on('click', '#pma_navigation_tree a.expander', function (event) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ var $icon = $(this).find('img');
+ if ($icon.is('.ic_b_plus')) {
+ Navigation.expandTreeNode($(this));
+ } else {
+ Navigation.collapseTreeNode($(this));
+ }
+ });
+
+ /**
+ * Register event handler for click on the reload
+ * navigation icon at the top of the panel
+ */
+ $(document).on('click', '#pma_navigation_reload', function (event) {
+ event.preventDefault();
+
+ // Find the loading symbol and show it
+ var $iconThrobberSrc = $('#pma_navigation').find('.throbber');
+ $iconThrobberSrc.show();
+ // TODO Why is a loading symbol both hidden, and invisible?
+ $iconThrobberSrc.css('visibility', '');
+
+ // Callback to be used to hide the loading symbol when done reloading
+ function hideNav() {
+ $iconThrobberSrc.hide();
+ }
+
+ // Reload the navigation
+ Navigation.reload(hideNav);
+ });
+ $(document).on('change', '#navi_db_select', function () {
+ if (!$(this).val()) {
+ CommonParams.set('db', '');
+ Navigation.reload();
+ }
+ $(this).closest('form').trigger('submit');
+ });
+
+ /**
+ * Register event handler for click on the collapse all
+ * navigation icon at the top of the navigation tree
+ */
+ $(document).on('click', '#pma_navigation_collapse', function (event) {
+ event.preventDefault();
+ $('#pma_navigation_tree').find('a.expander').each(function () {
+ var $icon = $(this).find('img');
+ if ($icon.is('.ic_b_minus')) {
+ $(this).trigger('click');
+ }
+ });
+ });
+
+ /**
+ * Register event handler to toggle
+ * the 'link with main panel' icon on mouseenter.
+ */
+ $(document).on('mouseenter', '#pma_navigation_sync', function (event) {
+ event.preventDefault();
+ var synced = $('#pma_navigation_tree').hasClass('synced');
+ var $img = $('#pma_navigation_sync').children('img');
+ if (synced) {
+ $img.removeClass('ic_s_link').addClass('ic_s_unlink');
+ } else {
+ $img.removeClass('ic_s_unlink').addClass('ic_s_link');
+ }
+ });
+
+ /**
+ * Register event handler to toggle
+ * the 'link with main panel' icon on mouseout.
+ */
+ $(document).on('mouseout', '#pma_navigation_sync', function (event) {
+ event.preventDefault();
+ var synced = $('#pma_navigation_tree').hasClass('synced');
+ var $img = $('#pma_navigation_sync').children('img');
+ if (synced) {
+ $img.removeClass('ic_s_unlink').addClass('ic_s_link');
+ } else {
+ $img.removeClass('ic_s_link').addClass('ic_s_unlink');
+ }
+ });
+
+ /**
+ * Register event handler to toggle
+ * the linking with main panel behavior
+ */
+ $(document).on('click', '#pma_navigation_sync', function (event) {
+ event.preventDefault();
+ var synced = $('#pma_navigation_tree').hasClass('synced');
+ var $img = $('#pma_navigation_sync').children('img');
+ if (synced) {
+ $img.removeClass('ic_s_unlink').addClass('ic_s_link').attr('alt', Messages.linkWithMain).attr('title', Messages.linkWithMain);
+ $('#pma_navigation_tree').removeClass('synced').find('li.selected').removeClass('selected');
+ } else {
+ $img.removeClass('ic_s_link').addClass('ic_s_unlink').attr('alt', Messages.unlinkWithMain).attr('title', Messages.unlinkWithMain);
+ $('#pma_navigation_tree').addClass('synced');
+ Navigation.showCurrent();
+ }
+ });
+
+ /**
+ * Bind all "fast filter" events
+ */
+ $('#pma_navigation_tree').on('click', 'li.fast_filter button.searchClauseClear', Navigation.FastFilter.events.clear);
+ $('#pma_navigation_tree').on('focus', 'li.fast_filter input.searchClause', Navigation.FastFilter.events.focus);
+ $('#pma_navigation_tree').on('blur', 'li.fast_filter input.searchClause', Navigation.FastFilter.events.blur);
+ $('#pma_navigation_tree').on('keyup', 'li.fast_filter input.searchClause', Navigation.FastFilter.events.keyup);
+
+ /**
+ * Ajax handler for pagination
+ */
+ $('#pma_navigation_tree').on('click', 'div.pageselector a.ajax', function (event) {
+ event.preventDefault();
+ Navigation.treePagination($(this));
+ });
+
+ /**
+ * Node highlighting
+ */
+ $('#pma_navigation_tree.highlight').on('mouseover', 'li:not(.fast_filter)', function () {
+ if ($('li:visible', this).length === 0) {
+ $(this).addClass('activePointer');
+ }
+ });
+ $('#pma_navigation_tree.highlight').on('mouseout', 'li:not(.fast_filter)', function () {
+ $(this).removeClass('activePointer');
+ });
+
+ /** New view */
+ $(document).on('click', 'li.new_view a.ajax', function (event) {
+ event.preventDefault();
+ Functions.createViewModal($(this));
+ });
+
+ /** Hide navigation tree item */
+ $(document).on('click', 'a.hideNavItem.ajax', function (event) {
+ event.preventDefault();
+ var argSep = CommonParams.get('arg_separator');
+ var params = $(this).getPostData();
+ params += argSep + 'ajax_request=true' + argSep + 'server=' + CommonParams.get('server');
+ $.ajax({
+ type: 'POST',
+ data: params,
+ url: $(this).attr('href'),
+ success: function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ }
+ }
+ });
+ });
+
+ /** Display a dialog to choose hidden navigation items to show */
+ $(document).on('click', 'a.showUnhide.ajax', function (event) {
+ event.preventDefault();
+ var $msg = Functions.ajaxShowMessage();
+ var argSep = CommonParams.get('arg_separator');
+ var params = $(this).getPostData();
+ params += argSep + 'ajax_request=true';
+ $.post($(this).attr('href'), params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxRemoveMessage($msg);
+ $('#unhideNavItemModal').modal('show');
+ $('#unhideNavItemModal').find('.modal-body').first().html(data.message);
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ }
+ });
+ });
+
+ /** Show a hidden navigation tree item */
+ $(document).on('click', 'a.unhideNavItem.ajax', function (event) {
+ event.preventDefault();
+ var $tr = $(this).parents('tr');
+ var $hiddenTableCount = $tr.parents('tbody').children().length;
+ var $hideDialogBox = $tr.closest('div.ui-dialog');
+ var $msg = Functions.ajaxShowMessage();
+ var argSep = CommonParams.get('arg_separator');
+ var params = $(this).getPostData();
+ params += argSep + 'ajax_request=true' + argSep + 'server=' + CommonParams.get('server');
+ $.ajax({
+ type: 'POST',
+ data: params,
+ url: $(this).attr('href'),
+ success: function (data) {
+ Functions.ajaxRemoveMessage($msg);
+ if (typeof data !== 'undefined' && data.success === true) {
+ $tr.remove();
+ if ($hiddenTableCount === 1) {
+ $hideDialogBox.remove();
+ }
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ }
+ }
+ });
+ });
+
+ // Add/Remove favorite table using Ajax.
+ $(document).on('click', '.favorite_table_anchor', function (event) {
+ event.preventDefault();
+ var $self = $(this);
+ var anchorId = $self.attr('id');
+ if ($self.data('favtargetn') !== null) {
+ var $dataFavTargets = $('a[data-favtargets="' + $self.data('favtargetn') + '"]');
+ if ($dataFavTargets.length > 0) {
+ $dataFavTargets.trigger('click');
+ return;
+ }
+ }
+ var hasLocalStorage = isStorageSupported('localStorage') && typeof window.localStorage.favoriteTables !== 'undefined';
+ $.ajax({
+ url: $self.attr('href'),
+ cache: false,
+ type: 'POST',
+ data: {
+ 'favoriteTables': hasLocalStorage ? window.localStorage.favoriteTables : '',
+ 'server': CommonParams.get('server')
+ },
+ success: function (data) {
+ if (data.changes) {
+ $('#pma_favorite_list').html(data.list);
+ $('#' + anchorId).parent().html(data.anchor);
+ Functions.tooltip($('#' + anchorId), 'a', $('#' + anchorId).attr('title'));
+ // Update localStorage.
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.favoriteTables = data.favoriteTables;
+ }
+ } else {
+ Functions.ajaxShowMessage(data.message);
+ }
+ }
+ });
+ });
+ // Check if session storage is supported
+ if (isStorageSupported('sessionStorage')) {
+ var storage = window.sessionStorage;
+ // remove tree from storage if Navi_panel config form is submitted
+ $(document).on('submit', 'form.config-form', function () {
+ storage.removeItem('navTreePaths');
+ });
+ // Initialize if no previous state is defined
+ if ($('#pma_navigation_tree_content').length && typeof storage.navTreePaths === 'undefined') {
+ Navigation.reload();
+ } else if (CommonParams.get('server') === storage.server && CommonParams.get('token') === storage.token) {
+ // Reload the tree to the state before page refresh
+ Navigation.reload(Navigation.filterStateRestore, JSON.parse(storage.navTreePaths));
+ } else {
+ // If the user is different
+ Navigation.treeStateUpdate();
+ Navigation.reload();
+ }
+ }
+});
+
+/**
+ * Expands a node in navigation tree.
+ *
+ * @param $expandElem expander
+ * @param callback callback function
+ *
+ * @return {void}
+ */
+Navigation.expandTreeNode = function ($expandElem, callback) {
+ var $children = $expandElem.closest('li').children('div.list_container');
+ var $icon = $expandElem.find('img');
+ if ($expandElem.hasClass('loaded')) {
+ if ($icon.is('.ic_b_plus')) {
+ $icon.removeClass('ic_b_plus').addClass('ic_b_minus');
+ $children.slideDown('fast');
+ }
+ if (callback && typeof callback === 'function') {
+ callback.call();
+ }
+ $children.promise().done(Navigation.treeStateUpdate);
+ } else {
+ var $throbber = $('#pma_navigation').find('.throbber').first().clone().css({
+ visibility: 'visible',
+ display: 'block'
+ }).on('click', false);
+ $icon.hide();
+ $throbber.insertBefore($icon);
+ Navigation.loadChildNodes(true, $expandElem, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ var $destination = $expandElem.closest('li');
+ $icon.removeClass('ic_b_plus').addClass('ic_b_minus');
+ $children = $destination.children('div.list_container');
+ $children.slideDown('fast');
+ if ($destination.find('ul > li').length === 1) {
+ $destination.find('ul > li').find('a.expander.container').trigger('click');
+ }
+ if (callback && typeof callback === 'function') {
+ callback.call();
+ }
+ Navigation.showFullName($destination);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ $icon.show();
+ $throbber.remove();
+ $children.promise().done(Navigation.treeStateUpdate);
+ });
+ }
+ $expandElem.trigger('blur');
+};
+
+/**
+ * Auto-scrolls the newly chosen database
+ *
+ * @param {object} $element The element to set to view
+ * @param {bool} $forceToTop Whether to force scroll to top
+ *
+ */
+Navigation.scrollToView = function ($element, $forceToTop) {
+ Navigation.filterStateRestore();
+ var $container = $('#pma_navigation_tree_content');
+ var elemTop = $element.offset().top - $container.offset().top;
+ var textHeight = 20;
+ var scrollPadding = 20; // extra padding from top of bottom when scrolling to view
+ if (elemTop < 0 || $forceToTop) {
+ $container.stop().animate({
+ scrollTop: elemTop + $container.scrollTop() - scrollPadding
+ });
+ } else if (elemTop + textHeight > $container.height()) {
+ $container.stop().animate({
+ scrollTop: elemTop + textHeight - $container.height() + $container.scrollTop() + scrollPadding
+ });
+ }
+};
+
+/**
+ * Expand the navigation and highlight the current database or table/view
+ *
+ * @return {void}
+ */
+Navigation.showCurrent = function () {
+ var db = CommonParams.get('db');
+ var table = CommonParams.get('table');
+ var autoexpand = $('#pma_navigation_tree').hasClass('autoexpand');
+ $('#pma_navigation_tree').find('li.selected').removeClass('selected');
+ var $dbItem;
+ if (db) {
+ $dbItem = findLoadedItem($('#pma_navigation_tree').find('> div'), db, 'database', !table);
+ if ($('#navi_db_select').length && $('option:selected', $('#navi_db_select')).length) {
+ if (!Navigation.selectCurrentDatabase()) {
+ return;
+ }
+ // If loaded database in navigation is not same as current one
+ if ($('#pma_navigation_tree_content').find('span.loaded_db').first().text() !== $('#navi_db_select').val()) {
+ Navigation.loadChildNodes(false, $('option:selected', $('#navi_db_select')), function () {
+ handleTableOrDb(table, $('#pma_navigation_tree_content'));
+ var $children = $('#pma_navigation_tree_content').children('div.list_container');
+ $children.promise().done(Navigation.treeStateUpdate);
+ });
+ } else {
+ handleTableOrDb(table, $('#pma_navigation_tree_content'));
+ }
+ } else if ($dbItem) {
+ fullExpand(table, $dbItem);
+ }
+ } else if ($('#navi_db_select').length && $('#navi_db_select').val()) {
+ $('#navi_db_select').val('').hide().trigger('change');
+ } else if (autoexpand && $('#pma_navigation_tree_content > ul > li.database').length === 1) {
+ // automatically expand the list if there is only single database
+
+ // find the name of the database
+ var dbItemName = '';
+ $('#pma_navigation_tree_content > ul > li.database').children('a').each(function () {
+ var name = $(this).text();
+ if (!dbItemName && name.trim()) {
+ // if the name is not empty, it is the desired element
+ dbItemName = name;
+ }
+ });
+ $dbItem = findLoadedItem($('#pma_navigation_tree').find('> div'), dbItemName, 'database', !table);
+ fullExpand(table, $dbItem);
+ }
+ Navigation.showFullName($('#pma_navigation_tree'));
+ function fullExpand(table, $dbItem) {
+ var $expander = $dbItem.children('div').first().children('a.expander');
+ // if not loaded or loaded but collapsed
+ if (!$expander.hasClass('loaded') || $expander.find('img').is('.ic_b_plus')) {
+ Navigation.expandTreeNode($expander, function () {
+ handleTableOrDb(table, $dbItem);
+ });
+ } else {
+ handleTableOrDb(table, $dbItem);
+ }
+ }
+ function handleTableOrDb(table, $dbItem) {
+ if (table) {
+ loadAndHighlightTableOrView($dbItem, table);
+ } else {
+ var $container = $dbItem.children('div.list_container');
+ var $tableContainer = $container.children('ul').children('li.tableContainer');
+ if ($tableContainer.length > 0) {
+ var $expander = $tableContainer.children('div').first().children('a.expander');
+ $tableContainer.addClass('selected');
+ Navigation.expandTreeNode($expander, function () {
+ Navigation.scrollToView($dbItem, true);
+ });
+ } else {
+ Navigation.scrollToView($dbItem, true);
+ }
+ }
+ }
+ function findLoadedItem($container, name, clazz, doSelect) {
+ var ret = false;
+ $container.children('ul').children('li').each(function () {
+ var $li = $(this);
+ // this is a navigation group, recurse
+ if ($li.is('.navGroup')) {
+ var $container = $li.children('div.list_container');
+ var $childRet = findLoadedItem($container, name, clazz, doSelect);
+ if ($childRet) {
+ ret = $childRet;
+ return false;
+ }
+ } else {
+ // this is a real navigation item
+ // name and class matches
+ if ((clazz && $li.is('.' + clazz) || !clazz) && $li.children('a').text() === name) {
+ if (doSelect) {
+ $li.addClass('selected');
+ }
+ // traverse up and expand and parent navigation groups
+ $li.parents('.navGroup').each(function () {
+ var $cont = $(this).children('div.list_container');
+ if (!$cont.is(':visible')) {
+ $(this).children('div').first().children('a.expander').trigger('click');
+ }
+ });
+ ret = $li;
+ return false;
+ }
+ }
+ });
+ return ret;
+ }
+ function loadAndHighlightTableOrView($dbItem, itemName) {
+ var $container = $dbItem.children('div.list_container');
+ var $expander;
+ var $whichItem = isItemInContainer($container, itemName, 'li.nav_node_table, li.view');
+ // If item already there in some container
+ if ($whichItem) {
+ // get the relevant container while may also be a subcontainer
+ var $relatedContainer = $whichItem.closest('li.subContainer').length ? $whichItem.closest('li.subContainer') : $dbItem;
+ $whichItem = findLoadedItem($relatedContainer.children('div.list_container'), itemName, null, true);
+ // Show directly
+ showTableOrView($whichItem, $relatedContainer.children('div').first().children('a.expander'));
+ // else if item not there, try loading once
+ } else {
+ var $subContainers = $dbItem.find('.subContainer');
+ // If there are subContainers i.e. tableContainer or viewContainer
+ if ($subContainers.length > 0) {
+ var $containers = [];
+ $subContainers.each(function (index) {
+ $containers[index] = $(this);
+ $expander = $containers[index].children('div').first().children('a.expander');
+ if (!$expander.hasClass('loaded')) {
+ loadAndShowTableOrView($expander, $containers[index], itemName);
+ }
+ });
+ // else if no subContainers
+ } else {
+ $expander = $dbItem.children('div').first().children('a.expander');
+ if (!$expander.hasClass('loaded')) {
+ loadAndShowTableOrView($expander, $dbItem, itemName);
+ }
+ }
+ }
+ }
+ function loadAndShowTableOrView($expander, $relatedContainer, itemName) {
+ Navigation.loadChildNodes(true, $expander, function () {
+ var $whichItem = findLoadedItem($relatedContainer.children('div.list_container'), itemName, null, true);
+ if ($whichItem) {
+ showTableOrView($whichItem, $expander);
+ }
+ });
+ }
+ function showTableOrView($whichItem, $expander) {
+ Navigation.expandTreeNode($expander, function () {
+ if ($whichItem) {
+ Navigation.scrollToView($whichItem, false);
+ }
+ });
+ }
+ function isItemInContainer($container, name, clazz) {
+ var $whichItem = null;
+ var $items = $container.find(clazz);
+ $items.each(function () {
+ if ($(this).children('a').text() === name) {
+ $whichItem = $(this);
+ return false;
+ }
+ });
+ return $whichItem;
+ }
+};
+
+/**
+ * Disable navigation panel settings
+ *
+ * @return {void}
+ */
+Navigation.disableSettings = function () {
+ $('#pma_navigation_settings_icon').addClass('hide');
+ $('#pma_navigation_settings').remove();
+};
+
+/**
+ * Ensure that navigation panel settings is properly setup.
+ * If not, set it up
+ *
+ * @param {string} selflink
+ *
+ * @return {void}
+ */
+Navigation.ensureSettings = function (selflink) {
+ $('#pma_navigation_settings_icon').removeClass('hide');
+ if (!$('#pma_navigation_settings').length) {
+ var params = {
+ getNaviSettings: true,
+ server: CommonParams.get('server')
+ };
+ $.post('index.php?route=/navigation&ajax_request=1', params, function (data) {
+ if (typeof data !== 'undefined' && data.success) {
+ $('#pma_navi_settings_container').html(data.message);
+ setupRestoreField();
+ setupValidation();
+ $('#pma_navigation_settings').find('form').attr('action', selflink);
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ }
+ });
+ } else {
+ $('#pma_navigation_settings').find('form').attr('action', selflink);
+ }
+};
+
+/**
+ * Reloads the whole navigation tree while preserving its state
+ *
+ * @param {Function} callback the callback function
+ * @param {object} paths stored navigation paths
+ *
+ * @return {void}
+ */
+Navigation.reload = function (callback, paths) {
+ var params = {
+ 'reload': true,
+ 'no_debug': true,
+ 'server': CommonParams.get('server')
+ };
+ var pathsLocal = paths || Navigation.traverseForPaths();
+ $.extend(params, pathsLocal);
+ if ($('#navi_db_select').length) {
+ params.db = CommonParams.get('db');
+ requestNaviReload(params);
+ return;
+ }
+ requestNaviReload(params);
+ function requestNaviReload(params) {
+ $.post('index.php?route=/navigation&ajax_request=1', params, function (data) {
+ if (typeof data !== 'undefined' && data.success) {
+ $('#pma_navigation_tree').html(data.message).children('div').show();
+ if ($('#pma_navigation_tree').hasClass('synced')) {
+ Navigation.selectCurrentDatabase();
+ Navigation.showCurrent();
+ }
+ // Fire the callback, if any
+ if (typeof callback === 'function') {
+ callback.call();
+ }
+ Navigation.treeStateUpdate();
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ }
+ });
+ }
+};
+Navigation.selectCurrentDatabase = function () {
+ var $naviDbSelect = $('#navi_db_select');
+ if (!$naviDbSelect.length) {
+ return false;
+ }
+ if (CommonParams.get('db')) {
+ // db selected
+ $naviDbSelect.show();
+ }
+ $naviDbSelect.val(CommonParams.get('db'));
+ return $naviDbSelect.val() === CommonParams.get('db');
+};
+
+/**
+ * Handles any requests to change the page in a branch of a tree
+ *
+ * This can be called from link click or select change event handlers
+ *
+ * @param {object} $this A jQuery object that points to the element that
+ * initiated the action of changing the page
+ *
+ * @return {void}
+ */
+Navigation.treePagination = function ($this) {
+ var $msgbox = Functions.ajaxShowMessage();
+ var isDbSelector = $this.closest('div.pageselector').is('.dbselector');
+ var url = 'index.php?route=/navigation';
+ var params = 'ajax_request=true';
+ if ($this[0].tagName === 'A') {
+ params += CommonParams.get('arg_separator') + $this.getPostData();
+ } else {
+ // tagName === 'SELECT'
+ params += CommonParams.get('arg_separator') + $this.closest('form').serialize();
+ }
+ var searchClause = Navigation.FastFilter.getSearchClause();
+ if (searchClause) {
+ params += CommonParams.get('arg_separator') + 'searchClause=' + encodeURIComponent(searchClause);
+ }
+ if (isDbSelector) {
+ params += CommonParams.get('arg_separator') + 'full=true';
+ } else {
+ var searchClause2 = Navigation.FastFilter.getSearchClause2($this);
+ if (searchClause2) {
+ params += CommonParams.get('arg_separator') + 'searchClause2=' + encodeURIComponent(searchClause2);
+ }
+ }
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success) {
+ Functions.ajaxRemoveMessage($msgbox);
+ var val;
+ if (isDbSelector) {
+ val = Navigation.FastFilter.getSearchClause();
+ $('#pma_navigation_tree').html(data.message).children('div').show();
+ if (val) {
+ $('#pma_navigation_tree').find('li.fast_filter input.searchClause').val(val);
+ }
+ } else {
+ var $parent = $this.closest('div.list_container').parent();
+ val = Navigation.FastFilter.getSearchClause2($this);
+ $this.closest('div.list_container').html($(data.message).children().show());
+ if (val) {
+ $parent.find('li.fast_filter input.searchClause').val(val);
+ }
+ $parent.find('span.pos2_value').first().text($parent.find('span.pos2_value').last().text());
+ $parent.find('span.pos3_value').first().text($parent.find('span.pos3_value').last().text());
+ }
+ } else {
+ Functions.ajaxShowMessage(data.error);
+ Functions.handleRedirectAndReload(data);
+ }
+ Navigation.treeStateUpdate();
+ });
+};
+
+/**
+ * ResizeHandler Custom object that manages the resizing of the navigation
+ *
+ * XXX: Must only be ever instanciated once
+ * XXX: Inside event handlers the 'this' object is accessed as 'event.data.resize_handler'
+ */
+Navigation.ResizeHandler = function () {
+ /**
+ * @var {number} panelWidth Used by the collapser to know where to go
+ * back to when uncollapsing the panel
+ */
+ this.panelWidth = 0;
+ /**
+ * @var {string} left Used to provide support for RTL languages
+ */
+ this.left = $('html').attr('dir') === 'ltr' ? 'left' : 'right';
+ /**
+ * Adjusts the width of the navigation panel to the specified value
+ *
+ * @param {number} position Navigation width in pixels
+ *
+ * @return {void}
+ */
+ this.setWidth = function (position) {
+ var pos = position;
+ if (typeof pos !== 'number') {
+ pos = 240;
+ }
+ var $resizer = $('#pma_navigation_resizer');
+ var resizerWidth = $resizer.width();
+ var $collapser = $('#pma_navigation_collapser');
+ var windowWidth = $(window).width();
+ $('#pma_navigation').width(pos);
+ $('body').css('margin-' + this.left, pos + 'px');
+ // Issue #15127 : Adding fixed positioning to menubar
+ // Issue #15570 : Panels on homescreen go underneath of floating menubar
+ $('#floating_menubar').css('margin-' + this.left, $('#pma_navigation').width() + $('#pma_navigation_resizer').width()).css(this.left, 0).css({
+ 'position': 'fixed',
+ 'top': 0,
+ 'width': '100%',
+ 'z-index': 99
+ }).append($('#server-breadcrumb')).append($('#topmenucontainer'));
+ // Allow the DOM to render, then adjust the padding on the body
+ setTimeout(function () {
+ $('body').css('padding-top', $('#floating_menubar').outerHeight(true));
+ }, 2);
+ $('#pma_console').css('margin-' + this.left, pos + resizerWidth + 'px');
+ $resizer.css(this.left, pos + 'px');
+ if (pos === 0) {
+ $collapser.css(this.left, pos + resizerWidth).html(this.getSymbol(pos)).prop('title', Messages.strShowPanel);
+ } else if (windowWidth > 768) {
+ $collapser.css(this.left, pos).html(this.getSymbol(pos)).prop('title', Messages.strHidePanel);
+ $('#pma_navigation_resizer').css({
+ 'width': '3px'
+ });
+ } else {
+ $collapser.css(this.left, windowWidth - 22).html(this.getSymbol(100)).prop('title', Messages.strHidePanel);
+ $('#pma_navigation').width(windowWidth);
+ $('body').css('margin-' + this.left, '0px');
+ $('#pma_navigation_resizer').css({
+ 'width': '0px'
+ });
+ }
+ setTimeout(function () {
+ $(window).trigger('resize');
+ }, 4);
+ };
+ /**
+ * Returns the horizontal position of the mouse,
+ * relative to the outer side of the navigation panel
+ *
+ * @param {MouseEvent} event
+ *
+ * @return {number} Navigation width in pixels
+ */
+ this.getPos = function (event) {
+ var pos = event.pageX;
+ var windowWidth = $(window).width();
+ var windowScroll = $(window).scrollLeft();
+ pos = pos - windowScroll;
+ if (this.left !== 'left') {
+ pos = windowWidth - event.pageX;
+ }
+ if (pos < 0) {
+ pos = 0;
+ } else if (pos + 100 >= windowWidth) {
+ pos = windowWidth - 100;
+ } else {
+ this.panelWidth = 0;
+ }
+ return pos;
+ };
+ /**
+ * Returns the HTML code for the arrow symbol used in the collapser
+ *
+ * @param {number} width The width of the panel
+ *
+ * @return {string}
+ */
+ this.getSymbol = function (width) {
+ if (this.left === 'left') {
+ if (width === 0) {
+ return '→';
+ } else {
+ return '←';
+ }
+ } else {
+ if (width === 0) {
+ return '←';
+ } else {
+ return '→';
+ }
+ }
+ };
+ /**
+ * Event handler for initiating a resize of the panel
+ *
+ * @param {object} event Event data (contains a reference to Navigation.ResizeHandler)
+ *
+ * @return {void}
+ */
+ this.mousedown = function (event) {
+ event.preventDefault();
+ $(document).on('mousemove', {
+ 'resize_handler': event.data.resize_handler
+ }, $.throttle(event.data.resize_handler.mousemove, 4)).on('mouseup', {
+ 'resize_handler': event.data.resize_handler
+ }, event.data.resize_handler.mouseup);
+ $('body').css('cursor', 'col-resize');
+ };
+ /**
+ * Event handler for terminating a resize of the panel
+ *
+ * @param {object} event Event data (contains a reference to Navigation.ResizeHandler)
+ *
+ * @return {void}
+ */
+ this.mouseup = function (event) {
+ $('body').css('cursor', '');
+ Functions.configSet('NavigationWidth', event.data.resize_handler.getPos(event));
+ $('#topmenu').menuResizer('resize');
+ $(document).off('mousemove').off('mouseup');
+ };
+ /**
+ * Event handler for updating the panel during a resize operation
+ *
+ * @param {object} event Event data (contains a reference to Navigation.ResizeHandler)
+ *
+ * @return {void}
+ */
+ this.mousemove = function (event) {
+ event.preventDefault();
+ if (event.data && event.data.resize_handler) {
+ var pos = event.data.resize_handler.getPos(event);
+ event.data.resize_handler.setWidth(pos);
+ }
+ };
+ /**
+ * Event handler for collapsing the panel
+ *
+ * @param {object} event Event data (contains a reference to Navigation.ResizeHandler)
+ *
+ * @return {void}
+ */
+ this.collapse = function (event) {
+ event.preventDefault();
+ var panelWidth = event.data.resize_handler.panelWidth;
+ var width = $('#pma_navigation').width();
+ if (width === 0 && panelWidth === 0) {
+ panelWidth = 240;
+ }
+ Functions.configSet('NavigationWidth', panelWidth);
+ event.data.resize_handler.setWidth(panelWidth);
+ event.data.resize_handler.panelWidth = width;
+ };
+ /**
+ * Event handler for resizing the navigation tree height on window resize
+ *
+ * @return {void}
+ */
+ this.treeResize = function () {
+ var $nav = $('#pma_navigation');
+ var $navTree = $('#pma_navigation_tree');
+ var $navHeader = $('#pma_navigation_header');
+ var $navTreeContent = $('#pma_navigation_tree_content');
+ var height = $nav.height() - $navHeader.height();
+ height = height > 50 ? height : 800; // keep min. height
+ $navTree.height(height);
+ if ($navTreeContent.length > 0) {
+ $navTreeContent.height(height - $navTreeContent.position().top);
+ } else {
+ // TODO: in fast filter search response there is no #pma_navigation_tree_content, needs to be added in php
+ $navTree.css({
+ 'overflow-y': 'auto'
+ });
+ }
+ // Set content bottom space because of console
+ $('body').css('margin-bottom', $('#pma_console').height() + 'px');
+ };
+ /**
+ * Init handlers for the tree resizers
+ *
+ * @return {void}
+ */
+ this.treeInit = function () {
+ const isLoadedOnMobile = $(window).width() < 768;
+ // Hide the pma_navigation initially when loaded on mobile
+ if (isLoadedOnMobile) {
+ this.setWidth(0);
+ }
+ // Register the events for the resizer and the collapser
+ $(document).on('mousedown', '#pma_navigation_resizer', {
+ 'resize_handler': this
+ }, this.mousedown);
+ $(document).on('click', '#pma_navigation_collapser', {
+ 'resize_handler': this
+ }, this.collapse);
+
+ // Add the correct arrow symbol to the collapser
+ $('#pma_navigation_collapser').html(this.getSymbol($('#pma_navigation').width()));
+ // Fix navigation tree height
+ $(window).on('resize', this.treeResize);
+ // need to call this now and then, browser might decide
+ // to show/hide horizontal scrollbars depending on page content width
+ setInterval(this.treeResize, 2000);
+ this.treeResize();
+ const callbackSuccessGetConfigValue = data => {
+ this.setWidth(data);
+ $('#topmenu').menuResizer('resize');
+ };
+ // Skip mobile
+ if (isLoadedOnMobile === false) {
+ // Make an init using the default found value
+ const initialResizeValue = $('#pma_navigation').data('config-navigation-width');
+ callbackSuccessGetConfigValue(initialResizeValue);
+ }
+ Functions.configGet('NavigationWidth', false, callbackSuccessGetConfigValue);
+ };
+ this.treeInit();
+};
+
+/**
+ * @var {object} FastFilter Handles the functionality that allows filtering
+ * of the items in a branch of the navigation tree
+ */
+Navigation.FastFilter = {
+ /**
+ * Construct for the asynchronous fast filter functionality
+ *
+ * @param {object} $this A jQuery object pointing to the list container
+ * which is the nearest parent of the fast filter
+ * @param {string} searchClause The query string for the filter
+ *
+ * @return {void}
+ */
+ Filter: function ($this, searchClause) {
+ /**
+ * @var {object} $this A jQuery object pointing to the list container
+ * which is the nearest parent of the fast filter
+ */
+ this.$this = $this;
+ /**
+ * @var {boolean} searchClause The query string for the filter
+ */
+ this.searchClause = searchClause;
+ /**
+ * @var {object} $clone A clone of the original contents
+ * of the navigation branch before
+ * the fast filter was applied
+ */
+ this.$clone = $this.clone();
+ /**
+ * @var {object} xhr A reference to the ajax request that is currently running
+ * @type {JQuery.jqXHR | null}
+ */
+ this.xhr = null;
+ /**
+ * @var {number} timeout Used to delay the request for asynchronous search
+ */
+ this.timeout = null;
+ var $filterInput = $this.find('li.fast_filter input.searchClause');
+ if ($filterInput.length !== 0 && $filterInput.val() !== '' && $filterInput.val() !== $filterInput[0].defaultValue) {
+ this.request();
+ }
+ },
+ /**
+ * Gets the query string from the database fast filter form
+ *
+ * @return {string}
+ */
+ getSearchClause: function () {
+ var retval = '';
+ var $input = $('#pma_navigation_tree').find('li.fast_filter.db_fast_filter input.searchClause');
+ if ($input.length && $input.val() !== $input[0].defaultValue) {
+ retval = $input.val();
+ }
+ return retval;
+ },
+ /**
+ * Gets the query string from a second level item's fast filter form
+ * The retrieval is done by traversing the navigation tree backwards
+ *
+ * @param $this
+ *
+ * @return {string}
+ */
+ getSearchClause2: function ($this) {
+ var $filterContainer = $this.closest('div.list_container');
+ var $filterInput = $([]);
+ if ($filterContainer.find('li.fast_filter:not(.db_fast_filter) input.searchClause').length !== 0) {
+ $filterInput = $filterContainer.find('li.fast_filter:not(.db_fast_filter) input.searchClause');
+ }
+ var searchClause2 = '';
+ if ($filterInput.length !== 0 && $filterInput.first().val() !== $filterInput[0].defaultValue) {
+ searchClause2 = $filterInput.val();
+ }
+ return searchClause2;
+ },
+ /**
+ * @var hash events A list of functions that are bound to DOM events
+ * at the top of this file
+ */
+ events: {
+ focus: function () {
+ var $obj = $(this).closest('div.list_container');
+ if (!$obj.data('fastFilter')) {
+ $obj.data('fastFilter', new Navigation.FastFilter.Filter($obj, $(this).val()));
+ }
+ if ($(this).val() === this.defaultValue) {
+ $(this).val('');
+ } else {
+ $(this).trigger('select');
+ }
+ },
+ blur: function () {
+ if ($(this).val() === '') {
+ $(this).val(this.defaultValue);
+ }
+ var $obj = $(this).closest('div.list_container');
+ if ($(this).val() === this.defaultValue && $obj.data('fastFilter')) {
+ $obj.data('fastFilter').restore();
+ }
+ },
+ keyup: function (event) {
+ var $obj = $(this).closest('div.list_container');
+ var str = '';
+ if ($(this).val() !== this.defaultValue && $(this).val() !== '') {
+ $obj.find('div.pageselector').hide();
+ str = $(this).val();
+ }
+
+ /**
+ * FIXME at the server level a value match is done while on
+ * the client side it is a regex match. These two should be aligned
+ */
+
+ // regex used for filtering.
+ var regex;
+ try {
+ regex = new RegExp(str, 'i');
+ } catch (err) {
+ return;
+ }
+
+ // this is the div that houses the items to be filtered by this filter.
+ var outerContainer;
+ if ($(this).closest('li.fast_filter').is('.db_fast_filter')) {
+ outerContainer = $('#pma_navigation_tree_content');
+ } else {
+ outerContainer = $obj;
+ }
+
+ // filters items that are directly under the div as well as grouped in
+ // groups. Does not filter child items (i.e. a database search does
+ // not filter tables)
+ var itemFilter = function ($curr) {
+ $curr.children('ul').children('li.navGroup').each(function () {
+ $(this).children('div.list_container').each(function () {
+ itemFilter($(this)); // recursive
+ });
+ });
+
+ $curr.children('ul').children('li').children('a').not('.container').each(function () {
+ if (regex.test($(this).text())) {
+ $(this).parent().show().removeClass('hidden');
+ } else {
+ $(this).parent().hide().addClass('hidden');
+ }
+ });
+ };
+ itemFilter(outerContainer);
+
+ // hides containers that does not have any visible children
+ var containerFilter = function ($curr) {
+ $curr.children('ul').children('li.navGroup').each(function () {
+ var $group = $(this);
+ $group.children('div.list_container').each(function () {
+ containerFilter($(this)); // recursive
+ });
+
+ $group.show().removeClass('hidden');
+ if ($group.children('div.list_container').children('ul').children('li').not('.hidden').length === 0) {
+ $group.hide().addClass('hidden');
+ }
+ });
+ };
+ containerFilter(outerContainer);
+ if ($(this).val() !== this.defaultValue && $(this).val() !== '') {
+ if (!$obj.data('fastFilter')) {
+ $obj.data('fastFilter', new Navigation.FastFilter.Filter($obj, $(this).val()));
+ } else {
+ if (event.keyCode === 13) {
+ $obj.data('fastFilter').update($(this).val());
+ }
+ }
+ } else if ($obj.data('fastFilter')) {
+ $obj.data('fastFilter').restore(true);
+ }
+ // update filter state
+ var filterName;
+ if ($(this).attr('name') === 'searchClause2') {
+ filterName = $(this).siblings('input[name=aPath]').val();
+ } else {
+ filterName = 'dbFilter';
+ }
+ Navigation.filterStateUpdate(filterName, $(this).val());
+ },
+ clear: function (event) {
+ event.stopPropagation();
+ // Clear the input and apply the fast filter with empty input
+ var filter = $(this).closest('div.list_container').data('fastFilter');
+ if (filter) {
+ filter.restore();
+ }
+ var value = $(this).prev()[0].defaultValue;
+ $(this).prev().val(value).trigger('keyup');
+ }
+ }
+};
+/**
+ * Handles a change in the search clause
+ *
+ * @param {string} searchClause The query string for the filter
+ *
+ * @return {void}
+ */
+Navigation.FastFilter.Filter.prototype.update = function (searchClause) {
+ if (this.searchClause !== searchClause) {
+ this.searchClause = searchClause;
+ this.request();
+ }
+};
+/**
+ * After a delay of 250mS, initiates a request to retrieve search results
+ * Multiple calls to this function will always abort the previous request
+ *
+ * @return {void}
+ */
+Navigation.FastFilter.Filter.prototype.request = function () {
+ var self = this;
+ if (self.$this.find('li.fast_filter').find('img.throbber').length === 0) {
+ self.$this.find('li.fast_filter').append($('
').append($('#pma_navigation_content').find('img.throbber').clone().css({
+ visibility: 'visible',
+ display: 'block'
+ })));
+ }
+ if (self.xhr) {
+ self.xhr.abort();
+ }
+ var params = self.$this.find('> ul > li > form.fast_filter').first().serialize();
+ if (self.$this.find('> ul > li > form.fast_filter').first().find('input[name=searchClause]').length === 0) {
+ var $input = $('#pma_navigation_tree').find('li.fast_filter.db_fast_filter input.searchClause');
+ if ($input.length && $input.val() !== $input[0].defaultValue) {
+ params += CommonParams.get('arg_separator') + 'searchClause=' + encodeURIComponent($input.val());
+ }
+ }
+ self.xhr = $.ajax({
+ url: 'index.php?route=/navigation&ajax_request=1&server=' + CommonParams.get('server'),
+ type: 'post',
+ dataType: 'json',
+ data: params,
+ complete: function (jqXHR, status) {
+ if (status !== 'abort') {
+ var data = JSON.parse(jqXHR.responseText);
+ self.$this.find('li.fast_filter').find('div.throbber').remove();
+ if (data && data.results) {
+ self.swap.apply(self, [data.message]);
+ }
+ }
+ }
+ });
+};
+/**
+ * Replaces the contents of the navigation branch with the search results
+ *
+ * @param {string} list The search results
+ *
+ * @return {void}
+ */
+Navigation.FastFilter.Filter.prototype.swap = function (list) {
+ this.$this.html($(list).html()).children().show().end().find('li.fast_filter input.searchClause').val(this.searchClause);
+ this.$this.data('fastFilter', this);
+};
+/**
+ * Restores the navigation to the original state after the fast filter is cleared
+ *
+ * @param {boolean} focus Whether to also focus the input box of the fast filter
+ *
+ * @return {void}
+ */
+Navigation.FastFilter.Filter.prototype.restore = function (focus) {
+ if (this.$this.children('ul').first().hasClass('search_results')) {
+ this.$this.html(this.$clone.html()).children().show();
+ this.$this.data('fastFilter', this);
+ if (focus) {
+ this.$this.find('li.fast_filter input.searchClause').trigger('focus');
+ }
+ }
+ this.searchClause = '';
+ this.$this.find('div.pageselector').show();
+ this.$this.find('div.throbber').remove();
+};
+
+/**
+ * Show full name when cursor hover and name not shown completely
+ *
+ * @param {object} $containerELem Container element
+ *
+ * @return {void}
+ */
+Navigation.showFullName = function ($containerELem) {
+ $containerELem.find('.hover_show_full').on('mouseenter', function () {
+ /** mouseenter */
+ var $this = $(this);
+ var thisOffset = $this.offset();
+ if ($this.text() === '') {
+ return;
+ }
+ var $parent = $this.parent();
+ if ($parent.offset().left + $parent.outerWidth() < thisOffset.left + $this.outerWidth()) {
+ var $fullNameLayer = $('#full_name_layer');
+ if ($fullNameLayer.length === 0) {
+ $('body').append('
');
+ $('#full_name_layer').on('mouseleave', function () {
+ /** mouseleave */
+ $(this).addClass('hide').removeClass('hovering');
+ }).on('mouseenter', function () {
+ /** mouseenter */
+ $(this).addClass('hovering');
+ });
+ $fullNameLayer = $('#full_name_layer');
+ }
+ $fullNameLayer.removeClass('hide');
+ $fullNameLayer.css({
+ left: thisOffset.left,
+ top: thisOffset.top
+ });
+ $fullNameLayer.html($this.clone());
+ setTimeout(function () {
+ if (!$fullNameLayer.hasClass('hovering')) {
+ $fullNameLayer.trigger('mouseleave');
+ }
+ }, 200);
+ }
+ });
+};
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/normalization.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/normalization.js
new file mode 100644
index 000000000..43ca63010
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/normalization.js
@@ -0,0 +1,715 @@
+/**
+ * @fileoverview events handling from normalization page
+ * @name normalization
+ *
+ * @requires jQuery
+ */
+
+// eslint-disable-next-line no-unused-vars
+/* global centralColumnList:writable */ // js/functions.js
+
+/**
+ * AJAX scripts for normalization
+ *
+ */
+
+var normalizeto = '1nf';
+var primaryKey;
+var dataParsed = null;
+function appendHtmlColumnsList() {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'getColumns': true
+ }, function (data) {
+ if (data.success === true) {
+ $('select[name=makeAtomic]').html(data.message);
+ }
+ });
+}
+function goTo3NFStep1(newTables) {
+ var tables = newTables;
+ if (Object.keys(tables).length === 1) {
+ tables = [CommonParams.get('table')];
+ }
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'server': CommonParams.get('server'),
+ 'tables': tables,
+ 'step': '3.1'
+ }, function (data) {
+ $('#page_content').find('h3').html(Messages.str3NFNormalization);
+ $('#mainContent').find('legend').html(data.legendText);
+ $('#mainContent').find('h4').html(data.headText);
+ $('#mainContent').find('p').html(data.subText);
+ $('#mainContent').find('#extra').html(data.extra);
+ $('#extra').find('form').each(function () {
+ var formId = $(this).attr('id');
+ var colName = $(this).data('colname');
+ $('#' + formId + ' input[value=\'' + colName + '\']').next().remove();
+ $('#' + formId + ' input[value=\'' + colName + '\']').remove();
+ });
+ $('#mainContent').find('#newCols').html('');
+ $('.tblFooters').html('');
+ if (data.subText !== '') {
+ $(' ').attr({
+ type: 'button',
+ value: Messages.strDone,
+ class: 'btn btn-primary'
+ }).on('click', function () {
+ processDependencies('', true);
+ }).appendTo('.tblFooters');
+ }
+ });
+}
+function goTo2NFStep1() {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'step': '2.1'
+ }, function (data) {
+ $('#page_content h3').html(Messages.str2NFNormalization);
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html(data.subText);
+ $('#mainContent #extra').html(data.extra);
+ $('#mainContent #newCols').html('');
+ if (data.subText !== '') {
+ $(' ').attr({
+ type: 'submit',
+ value: Messages.strDone,
+ class: 'btn btn-primary'
+ }).on('click', function () {
+ processDependencies(data.primary_key);
+ }).appendTo('.tblFooters');
+ } else {
+ if (normalizeto === '3nf') {
+ $('#mainContent #newCols').html(Messages.strToNextStep);
+ setTimeout(function () {
+ goTo3NFStep1([CommonParams.get('table')]);
+ }, 3000);
+ }
+ }
+ });
+}
+function goToFinish1NF() {
+ if (normalizeto !== '1nf') {
+ goTo2NFStep1();
+ return true;
+ }
+ $('#mainContent legend').html(Messages.strEndStep);
+ $('#mainContent h4').html('' + Functions.sprintf(Messages.strFinishMsg, Functions.escapeHtml(CommonParams.get('table'))) + ' ');
+ $('#mainContent p').html('');
+ $('#mainContent #extra').html('');
+ $('#mainContent #newCols').html('');
+ $('.tblFooters').html('');
+}
+
+// eslint-disable-next-line no-unused-vars
+function goToStep4() {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'step4': true
+ }, function (data) {
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html(data.subText);
+ $('#mainContent #extra').html(data.extra);
+ $('#mainContent #newCols').html('');
+ $('.tblFooters').html('');
+ for (var pk in primaryKey) {
+ $('#extra input[value=\'' + Functions.escapeJsString(primaryKey[pk]) + '\']').attr('disabled', 'disabled');
+ }
+ });
+}
+function goToStep3() {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'step3': true
+ }, function (data) {
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html(data.subText);
+ $('#mainContent #extra').html(data.extra);
+ $('#mainContent #newCols').html('');
+ $('.tblFooters').html('');
+ primaryKey = JSON.parse(data.primary_key);
+ for (var pk in primaryKey) {
+ $('#extra input[value=\'' + Functions.escapeJsString(primaryKey[pk]) + '\']').attr('disabled', 'disabled');
+ }
+ });
+}
+function goToStep2(extra) {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'step2': true
+ }, function (data) {
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html(data.subText);
+ $('#mainContent #extra,#mainContent #newCols').html('');
+ $('.tblFooters').html('');
+ if (data.hasPrimaryKey === '1') {
+ if (extra === 'goToStep3') {
+ $('#mainContent h4').html(Messages.strPrimaryKeyAdded);
+ $('#mainContent p').html(Messages.strToNextStep);
+ }
+ if (extra === 'goToFinish1NF') {
+ goToFinish1NF();
+ } else {
+ setTimeout(function () {
+ goToStep3();
+ }, 3000);
+ }
+ } else {
+ // form to select columns to make primary
+ $('#mainContent #extra').html(data.extra);
+ }
+ });
+}
+function goTo2NFFinish(pd) {
+ var tables = {};
+ for (var dependson in pd) {
+ tables[dependson] = $('#extra input[name="' + dependson + '"]').val();
+ }
+ var datastring = {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'pd': JSON.stringify(pd),
+ 'newTablesName': JSON.stringify(tables),
+ 'createNewTables2NF': 1
+ };
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/normalization',
+ data: datastring,
+ async: false,
+ success: function (data) {
+ if (data.success === true) {
+ if (data.queryError === false) {
+ if (normalizeto === '3nf') {
+ $('#pma_navigation_reload').trigger('click');
+ goTo3NFStep1(tables);
+ return true;
+ }
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html('');
+ $('#mainContent #extra').html('');
+ $('.tblFooters').html('');
+ } else {
+ Functions.ajaxShowMessage(data.extra, false);
+ }
+ $('#pma_navigation_reload').trigger('click');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+}
+function goTo3NFFinish(newTables) {
+ for (var table in newTables) {
+ for (var newtbl in newTables[table]) {
+ var updatedname = $('#extra input[name="' + newtbl + '"]').val();
+ newTables[table][updatedname] = newTables[table][newtbl];
+ if (updatedname !== newtbl) {
+ delete newTables[table][newtbl];
+ }
+ }
+ }
+ var datastring = {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'server': CommonParams.get('server'),
+ 'newTables': JSON.stringify(newTables),
+ 'createNewTables3NF': 1
+ };
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/normalization',
+ data: datastring,
+ async: false,
+ success: function (data) {
+ if (data.success === true) {
+ if (data.queryError === false) {
+ $('#mainContent legend').html(data.legendText);
+ $('#mainContent h4').html(data.headText);
+ $('#mainContent p').html('');
+ $('#mainContent #extra').html('');
+ $('.tblFooters').html('');
+ } else {
+ Functions.ajaxShowMessage(data.extra, false);
+ }
+ $('#pma_navigation_reload').trigger('click');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+}
+var backup = '';
+function goTo2NFStep2(pd, primaryKey) {
+ $('#newCols').html('');
+ $('#mainContent legend').html(Messages.strStep + ' 2.2 ' + Messages.strConfirmPd);
+ $('#mainContent h4').html(Messages.strSelectedPd);
+ $('#mainContent p').html(Messages.strPdHintNote);
+ var extra = '';
+ var pdFound = false;
+ for (var dependson in pd) {
+ if (dependson !== primaryKey) {
+ pdFound = true;
+ extra += '
' + Functions.escapeHtml(dependson) + ' -> ' + Functions.escapeHtml(pd[dependson].toString()) + '
';
+ }
+ }
+ if (!pdFound) {
+ extra += '
' + Messages.strNoPdSelected + '
';
+ extra += '
';
+ } else {
+ extra += '';
+ var datastring = {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'pd': JSON.stringify(pd),
+ 'getNewTables2NF': 1
+ };
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/normalization',
+ data: datastring,
+ async: false,
+ success: function (data) {
+ if (data.success === true) {
+ extra += data.message;
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+ }
+ $('#mainContent #extra').html(extra);
+ $('.tblFooters').html(' ');
+ $('#goTo2NFFinish').on('click', function () {
+ goTo2NFFinish(pd);
+ });
+}
+function goTo3NFStep2(pd, tablesTds) {
+ $('#newCols').html('');
+ $('#mainContent legend').html(Messages.strStep + ' 3.2 ' + Messages.strConfirmTd);
+ $('#mainContent h4').html(Messages.strSelectedTd);
+ $('#mainContent p').html(Messages.strPdHintNote);
+ var extra = '';
+ var pdFound = false;
+ for (var table in tablesTds) {
+ for (var i in tablesTds[table]) {
+ var dependson = tablesTds[table][i];
+ if (dependson !== '' && dependson !== table) {
+ pdFound = true;
+ extra += '
' + Functions.escapeHtml(dependson) + ' -> ' + Functions.escapeHtml(pd[dependson].toString()) + '
';
+ }
+ }
+ }
+ if (!pdFound) {
+ extra += '
' + Messages.strNoTdSelected + '
';
+ extra += '
';
+ } else {
+ extra += '';
+ var datastring = {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'tables': JSON.stringify(tablesTds),
+ 'server': CommonParams.get('server'),
+ 'pd': JSON.stringify(pd),
+ 'getNewTables3NF': 1
+ };
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/normalization',
+ data: datastring,
+ async: false,
+ success: function (data) {
+ dataParsed = data;
+ if (data.success === true) {
+ extra += dataParsed.html;
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+ }
+ $('#mainContent #extra').html(extra);
+ $('.tblFooters').html(' ');
+ $('#goTo3NFFinish').on('click', function () {
+ if (!pdFound) {
+ goTo3NFFinish([]);
+ } else {
+ goTo3NFFinish(dataParsed.newTables);
+ }
+ });
+}
+function processDependencies(primaryKey, isTransitive) {
+ var pk = primaryKey;
+ var pd = {};
+ var tablesTds = {};
+ var dependsOn;
+ pd[pk] = [];
+ $('#extra form').each(function () {
+ var tblname;
+ if (isTransitive === true) {
+ tblname = $(this).data('tablename');
+ pk = tblname;
+ if (!(tblname in tablesTds)) {
+ tablesTds[tblname] = [];
+ }
+ tablesTds[tblname].push(pk);
+ }
+ var formId = $(this).attr('id');
+ $('#' + formId + ' input[type=checkbox]:not(:checked)').prop('checked', false);
+ dependsOn = '';
+ $('#' + formId + ' input[type=checkbox]:checked').each(function () {
+ dependsOn += $(this).val() + ', ';
+ $(this).attr('checked', 'checked');
+ });
+ if (dependsOn === '') {
+ dependsOn = pk;
+ } else {
+ dependsOn = dependsOn.slice(0, -2);
+ }
+ if (!(dependsOn in pd)) {
+ pd[dependsOn] = [];
+ }
+ pd[dependsOn].push($(this).data('colname'));
+ if (isTransitive === true) {
+ if (!(tblname in tablesTds)) {
+ tablesTds[tblname] = [];
+ }
+ if ($.inArray(dependsOn, tablesTds[tblname]) === -1) {
+ tablesTds[tblname].push(dependsOn);
+ }
+ }
+ });
+ backup = $('#mainContent').html();
+ if (isTransitive === true) {
+ goTo3NFStep2(pd, tablesTds);
+ } else {
+ goTo2NFStep2(pd, pk);
+ }
+ return false;
+}
+function moveRepeatingGroup(repeatingCols) {
+ var newTable = $('input[name=repeatGroupTable]').val();
+ var newColumn = $('input[name=repeatGroupColumn]').val();
+ if (!newTable) {
+ $('input[name=repeatGroupTable]').trigger('focus');
+ return false;
+ }
+ if (!newColumn) {
+ $('input[name=repeatGroupColumn]').trigger('focus');
+ return false;
+ }
+ var datastring = {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'repeatingColumns': repeatingCols,
+ 'newTable': newTable,
+ 'newColumn': newColumn,
+ 'primary_columns': primaryKey.toString()
+ };
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/normalization',
+ data: datastring,
+ async: false,
+ success: function (data) {
+ if (data.success === true) {
+ if (data.queryError === false) {
+ goToStep3();
+ }
+ Functions.ajaxShowMessage(data.message, false);
+ $('#pma_navigation_reload').trigger('click');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+}
+AJAX.registerTeardown('normalization.js', function () {
+ $('#extra').off('click', '#selectNonAtomicCol');
+ $('#splitGo').off('click');
+ $('.tblFooters').off('click', '#saveSplit');
+ $('#extra').off('click', '#addNewPrimary');
+ $('.tblFooters').off('click', '#saveNewPrimary');
+ $('#extra').off('click', '#removeRedundant');
+ $('#mainContent p').off('click', '#createPrimaryKey');
+ $('#mainContent').off('click', '#backEditPd');
+ $('#mainContent').off('click', '#showPossiblePd');
+ $('#mainContent').off('click', '.pickPd');
+});
+AJAX.registerOnload('normalization.js', function () {
+ var selectedCol;
+ normalizeto = $('#mainContent').data('normalizeto');
+ $('#extra').on('click', '#selectNonAtomicCol', function () {
+ if ($(this).val() === 'no_such_col') {
+ goToStep2();
+ } else {
+ selectedCol = $(this).val();
+ }
+ });
+ $('#splitGo').on('click', function () {
+ if (!selectedCol || selectedCol === '') {
+ return false;
+ }
+ var numField = $('#numField').val();
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'splitColumn': true,
+ 'numFields': numField
+ }, function (data) {
+ if (data.success === true) {
+ $('#newCols').html(data.message);
+ $('.default_value').hide();
+ $('.enum_notice').hide();
+ $(' ').attr({
+ type: 'submit',
+ id: 'saveSplit',
+ value: Messages.strSave,
+ class: 'btn btn-primary'
+ }).appendTo('.tblFooters');
+ $(' ').attr({
+ type: 'submit',
+ id: 'cancelSplit',
+ value: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }).on('click', function () {
+ $('#newCols').html('');
+ $(this).parent().html('');
+ }).appendTo('.tblFooters');
+ }
+ });
+ return false;
+ });
+ $('.tblFooters').on('click', '#saveSplit', function () {
+ centralColumnList = [];
+ if ($('#newCols #field_0_1').val() === '') {
+ $('#newCols #field_0_1').trigger('focus');
+ return false;
+ }
+ var argsep = CommonParams.get('arg_separator');
+ var datastring = $('#newCols :input').serialize();
+ datastring += argsep + 'ajax_request=1' + argsep + 'do_save_data=1' + argsep + 'field_where=last';
+ $.post('index.php?route=/table/add-field', datastring, function (data) {
+ if (data.success) {
+ $.post('index.php?route=/sql', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'dropped_column': selectedCol,
+ 'purge': 1,
+ 'sql_query': 'ALTER TABLE `' + CommonParams.get('table') + '` DROP `' + selectedCol + '`;',
+ 'is_js_confirmed': 1
+ }, function (data) {
+ if (data.success === true) {
+ appendHtmlColumnsList();
+ $('#newCols').html('');
+ $('.tblFooters').html('');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ selectedCol = '';
+ });
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+ $('#extra').on('click', '#addNewPrimary', function () {
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'addNewPrimary': true
+ }, function (data) {
+ if (data.success === true) {
+ $('#newCols').html(data.message);
+ $('.default_value').hide();
+ $('.enum_notice').hide();
+ $(' ').attr({
+ type: 'submit',
+ id: 'saveNewPrimary',
+ value: Messages.strSave,
+ class: 'btn btn-primary'
+ }).appendTo('.tblFooters');
+ $(' ').attr({
+ type: 'submit',
+ id: 'cancelSplit',
+ value: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }).on('click', function () {
+ $('#newCols').html('');
+ $(this).parent().html('');
+ }).appendTo('.tblFooters');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ return false;
+ });
+ $('.tblFooters').on('click', '#saveNewPrimary', function () {
+ var datastring = $('#newCols :input').serialize();
+ var argsep = CommonParams.get('arg_separator');
+ datastring += argsep + 'field_key[0]=primary_0' + argsep + 'ajax_request=1' + argsep + 'do_save_data=1' + argsep + 'field_where=last';
+ $.post('index.php?route=/table/add-field', datastring, function (data) {
+ if (data.success === true) {
+ $('#mainContent h4').html(Messages.strPrimaryKeyAdded);
+ $('#mainContent p').html(Messages.strToNextStep);
+ $('#mainContent #extra').html('');
+ $('#mainContent #newCols').html('');
+ $('.tblFooters').html('');
+ setTimeout(function () {
+ goToStep3();
+ }, 2000);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+ $('#extra').on('click', '#removeRedundant', function () {
+ var dropQuery = 'ALTER TABLE `' + CommonParams.get('table') + '` ';
+ $('#extra input[type=checkbox]:checked').each(function () {
+ dropQuery += 'DROP `' + $(this).val() + '`, ';
+ });
+ dropQuery = dropQuery.slice(0, -2);
+ $.post('index.php?route=/sql', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'sql_query': dropQuery,
+ 'is_js_confirmed': 1
+ }, function (data) {
+ if (data.success === true) {
+ goToStep2('goToFinish1NF');
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+ $('#extra').on('click', '#moveRepeatingGroup', function () {
+ var repeatingCols = '';
+ $('#extra input[type=checkbox]:checked').each(function () {
+ repeatingCols += $(this).val() + ', ';
+ });
+ if (repeatingCols !== '') {
+ var newColName = $('#extra input[type=checkbox]:checked').first().val();
+ repeatingCols = repeatingCols.slice(0, -2);
+ var confirmStr = Functions.sprintf(Messages.strMoveRepeatingGroup, Functions.escapeHtml(repeatingCols), Functions.escapeHtml(CommonParams.get('table')));
+ confirmStr += ' ' + '( ' + Functions.escapeHtml(primaryKey.toString()) + ', )' + '';
+ $('#newCols').html(confirmStr);
+ $(' ').attr({
+ type: 'submit',
+ value: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }).on('click', function () {
+ $('#newCols').html('');
+ $('#extra input[type=checkbox]').prop('checked', false);
+ }).appendTo('.tblFooters');
+ $(' ').attr({
+ type: 'submit',
+ value: Messages.strGo,
+ class: 'btn btn-primary'
+ }).on('click', function () {
+ moveRepeatingGroup(repeatingCols);
+ }).appendTo('.tblFooters');
+ }
+ });
+ $('#mainContent p').on('click', '#createPrimaryKey', function (event) {
+ event.preventDefault();
+ var url = {
+ 'create_index': 1,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'added_fields': 1,
+ 'add_fields': 1,
+ 'index': {
+ 'Key_name': 'PRIMARY'
+ },
+ 'ajax_request': true
+ };
+ var title = Messages.strAddPrimaryKey;
+ Functions.indexEditorDialog(url, title, function () {
+ // on success
+ $('.sqlqueryresults').remove();
+ $('.result_query').remove();
+ $('.tblFooters').html('');
+ goToStep2('goToStep3');
+ });
+ return false;
+ });
+ $('#mainContent').on('click', '#backEditPd', function () {
+ $('#mainContent').html(backup);
+ });
+ $('#mainContent').on('click', '#showPossiblePd', function () {
+ if ($(this).hasClass('hideList')) {
+ $(this).html('+ ' + Messages.strShowPossiblePd);
+ $(this).removeClass('hideList');
+ $('#newCols').slideToggle('slow');
+ return false;
+ }
+ if ($('#newCols').html() !== '') {
+ $('#showPossiblePd').html('- ' + Messages.strHidePd);
+ $('#showPossiblePd').addClass('hideList');
+ $('#newCols').slideToggle('slow');
+ return false;
+ }
+ $('#newCols').insertAfter('#mainContent h4');
+ $('#newCols').html('' + Messages.strLoading + ' ' + Messages.strWaitForPd + '
');
+ $.post('index.php?route=/normalization', {
+ 'ajax_request': true,
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'server': CommonParams.get('server'),
+ 'findPdl': true
+ }, function (data) {
+ $('#showPossiblePd').html('- ' + Messages.strHidePd);
+ $('#showPossiblePd').addClass('hideList');
+ $('#newCols').html(data.message);
+ });
+ });
+ $('#mainContent').on('click', '.pickPd', function () {
+ var strColsLeft = $(this).next('.determinants').html();
+ var colsLeft = strColsLeft.split(',');
+ var strColsRight = $(this).next().next().html();
+ var colsRight = strColsRight.split(',');
+ for (var i in colsRight) {
+ $('form[data-colname="' + colsRight[i].trim() + '"] input[type="checkbox"]').prop('checked', false);
+ for (var j in colsLeft) {
+ $('form[data-colname="' + colsRight[i].trim() + '"] input[value="' + colsLeft[j].trim() + '"]').prop('checked', true);
+ }
+ }
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/ol.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/ol.js
new file mode 100644
index 000000000..bff13484d
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/ol.js
@@ -0,0 +1,62 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.default = void 0;
+var _control = require("ol/control.js");
+var _coordinate = require("ol/coordinate.js");
+var _extent = require("ol/extent.js");
+var _geom = require("ol/geom.js");
+var _layer = require("ol/layer.js");
+var _proj = require("ol/proj.js");
+var _source = require("ol/source.js");
+var _style = require("ol/style.js");
+var _ol = require("ol");
+const ol = {
+ control: {
+ Attribution: _control.Attribution,
+ MousePosition: _control.MousePosition,
+ Zoom: _control.Zoom
+ },
+ coordinate: {
+ createStringXY: _coordinate.createStringXY
+ },
+ extent: {
+ boundingExtent: _extent.boundingExtent
+ },
+ geom: {
+ LineString: _geom.LineString,
+ LinearRing: _geom.LinearRing,
+ MultiLineString: _geom.MultiLineString,
+ MultiPoint: _geom.MultiPoint,
+ MultiPolygon: _geom.MultiPolygon,
+ Point: _geom.Point,
+ Polygon: _geom.Polygon
+ },
+ layer: {
+ Tile: _layer.Tile,
+ Vector: _layer.Vector
+ },
+ proj: {
+ fromLonLat: _proj.fromLonLat,
+ get: _proj.get,
+ transformExtent: _proj.transformExtent
+ },
+ source: {
+ OSM: _source.OSM,
+ Vector: _source.Vector
+ },
+ style: {
+ Circle: _style.Circle,
+ Fill: _style.Fill,
+ Stroke: _style.Stroke,
+ Style: _style.Style,
+ Text: _style.Text
+ },
+ Feature: _ol.Feature,
+ Map: _ol.Map,
+ View: _ol.View
+};
+var _default = ol;
+exports.default = _default;
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/page_settings.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/page_settings.js
new file mode 100644
index 000000000..ae1cb993c
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/page_settings.js
@@ -0,0 +1,64 @@
+/**
+ * @fileoverview function used for page-related settings
+ * @name Page-related settings
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @required js/functions.js
+ */
+
+function showSettings(selector) {
+ var buttons = {
+ [Messages.strApply]: {
+ text: Messages.strApply,
+ class: 'btn btn-primary'
+ },
+ [Messages.strCancel]: {
+ text: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }
+ };
+ buttons[Messages.strApply].click = function () {
+ $('.config-form').trigger('submit');
+ };
+ buttons[Messages.strCancel].click = function () {
+ $(this).dialog('close');
+ };
+
+ // Keeping a clone to restore in case the user cancels the operation
+ var $clone = $(selector + ' .page_settings').clone(true);
+ $(selector).dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strPageSettings,
+ width: 700,
+ minHeight: 250,
+ modal: true,
+ open: function () {
+ $(this).dialog('option', 'maxHeight', $(window).height() - $(this).offset().top);
+ },
+ close: function () {
+ $(selector + ' .page_settings').replaceWith($clone);
+ },
+ buttons: buttons
+ });
+}
+function showPageSettings() {
+ showSettings('#page_settings_modal');
+}
+function showNaviSettings() {
+ showSettings('#pma_navigation_settings');
+}
+AJAX.registerTeardown('page_settings.js', function () {
+ $('#page_settings_icon').css('display', 'none');
+ $('#page_settings_icon').off('click');
+ $('#pma_navigation_settings_icon').off('click');
+});
+AJAX.registerOnload('page_settings.js', function () {
+ if ($('#page_settings_modal').length) {
+ $('#page_settings_icon').css('display', 'inline');
+ $('#page_settings_icon').on('click', showPageSettings);
+ }
+ $('#pma_navigation_settings_icon').on('click', showNaviSettings);
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/replication.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/replication.js
new file mode 100644
index 000000000..f9bbb1876
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/replication.js
@@ -0,0 +1,102 @@
+/**
+ * @fileoverview Javascript functions used in server replication page
+ * @name Server Replication
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ */
+
+var randomServerId = Math.floor(Math.random() * 10000000);
+var confPrefix = 'server-id=' + randomServerId + '\nlog_bin=mysql-bin\nlog_error=mysql-bin.err\n';
+function updateConfig() {
+ var confIgnore = 'binlog_ignore_db=';
+ var confDo = 'binlog_do_db=';
+ var databaseList = '';
+ if ($('#db_select option:selected').length === 0) {
+ $('#rep').text(confPrefix);
+ } else if ($('#db_type option:selected').val() === 'all') {
+ $('#db_select option:selected').each(function () {
+ databaseList += confIgnore + $(this).val() + '\n';
+ });
+ $('#rep').text(confPrefix + databaseList);
+ } else {
+ $('#db_select option:selected').each(function () {
+ databaseList += confDo + $(this).val() + '\n';
+ });
+ $('#rep').text(confPrefix + databaseList);
+ }
+}
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('replication.js', function () {
+ $('#db_type').off('change');
+ $('#db_select').off('change');
+ $('#primary_status_href').off('click');
+ $('#primary_replicas_href').off('click');
+ $('#replica_status_href').off('click');
+ $('#replica_control_href').off('click');
+ $('#replica_errormanagement_href').off('click');
+ $('#replica_synchronization_href').off('click');
+ $('#db_reset_href').off('click');
+ $('#db_select_href').off('click');
+ $('#reset_replica').off('click');
+});
+AJAX.registerOnload('replication.js', function () {
+ $('#rep').text(confPrefix);
+ $('#db_type').on('change', updateConfig);
+ $('#db_select').on('change', updateConfig);
+ $('#primary_status_href').on('click', function () {
+ $('#replication_primary_section').toggle();
+ });
+ $('#primary_replicas_href').on('click', function () {
+ $('#replication_replicas_section').toggle();
+ });
+ $('#replica_status_href').on('click', function () {
+ $('#replication_replica_section').toggle();
+ });
+ $('#replica_control_href').on('click', function () {
+ $('#replica_control_gui').toggle();
+ });
+ $('#replica_errormanagement_href').on('click', function () {
+ $('#replica_errormanagement_gui').toggle();
+ });
+ $('#replica_synchronization_href').on('click', function () {
+ $('#replica_synchronization_gui').toggle();
+ });
+ $('#db_reset_href').on('click', function () {
+ $('#db_select option:selected').prop('selected', false);
+ $('#db_select').trigger('change');
+ });
+ $('#db_select_href').on('click', function () {
+ $('#db_select option').prop('selected', true);
+ $('#db_select').trigger('change');
+ });
+ $('#reset_replica').on('click', function (e) {
+ e.preventDefault();
+ var $anchor = $(this);
+ var question = Messages.strResetReplicaWarning;
+ $anchor.confirm(question, $anchor.attr('href'), function (url) {
+ Functions.ajaxShowMessage();
+ AJAX.source = $anchor;
+ var params = Functions.getJsConfirmCommonParam({
+ 'ajax_page_request': true,
+ 'ajax_request': true
+ }, $anchor.getPostData());
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+ $('#button_generate_password').on('click', function () {
+ Functions.suggestPassword(this.form);
+ });
+ $('#nopass_1').on('click', function () {
+ this.form.pma_pw.value = '';
+ this.form.pma_pw2.value = '';
+ this.checked = true;
+ });
+ $('#nopass_0').on('click', function () {
+ document.getElementById('text_pma_change_pw').focus();
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/databases.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/databases.js
new file mode 100644
index 000000000..bf5435a8d
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/databases.js
@@ -0,0 +1,125 @@
+/**
+ * @fileoverview functions used on the server databases list page
+ * @name Server Databases
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @required js/functions.js
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/databases.js', function () {
+ $(document).off('submit', '#dbStatsForm');
+ $(document).off('submit', '#create_database_form.ajax');
+});
+
+/**
+ * AJAX scripts for /server/databases
+ *
+ * Actions ajaxified here:
+ * Drop Databases
+ *
+ */
+AJAX.registerOnload('server/databases.js', function () {
+ /**
+ * Attach Event Handler for 'Drop Databases'
+ */
+ $(document).on('submit', '#dbStatsForm', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+
+ /**
+ * @var selected_dbs Array containing the names of the checked databases
+ */
+ var selectedDbs = [];
+ // loop over all checked checkboxes, except the .checkall_box checkbox
+ $form.find('input:checkbox:checked:not(.checkall_box)').each(function () {
+ $(this).closest('tr').addClass('removeMe');
+ selectedDbs[selectedDbs.length] = 'DROP DATABASE `' + Functions.escapeHtml($(this).val()) + '`;';
+ });
+ if (!selectedDbs.length) {
+ Functions.ajaxShowMessage($('
').text(Messages.strNoDatabasesSelected), 2000);
+ return;
+ }
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = Messages.strDropDatabaseStrongWarning + ' ' + Functions.sprintf(Messages.strDoYouReally, selectedDbs.join(' '));
+ const modal = $('#dropDatabaseModal');
+ modal.find('.modal-body').html(question);
+ modal.modal('show');
+ const url = 'index.php?route=/server/databases/destroy&' + $(this).serialize();
+ $('#dropDatabaseModalDropButton').on('click', function () {
+ Functions.ajaxShowMessage(Messages.strProcessingRequest, false);
+ var parts = url.split('?');
+ var params = Functions.getJsConfirmCommonParam(this, parts[1]);
+ $.post(parts[0], params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxShowMessage(data.message);
+ var $rowsToRemove = $form.find('tr.removeMe');
+ var $databasesCount = $('#filter-rows-count');
+ var newCount = parseInt($databasesCount.text(), 10) - $rowsToRemove.length;
+ $databasesCount.text(newCount);
+ $rowsToRemove.remove();
+ $form.find('tbody').sortTable('.name');
+ if ($form.find('tbody').find('tr').length === 0) {
+ // user just dropped the last db on this page
+ CommonActions.refreshMain();
+ }
+ Navigation.reload();
+ } else {
+ $form.find('tr.removeMe').removeClass('removeMe');
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ modal.modal('hide');
+ $('#dropDatabaseModalDropButton').off('click');
+ });
+ });
+
+ /**
+ * Attach Ajax event handlers for 'Create Database'.
+ */
+ $(document).on('submit', '#create_database_form.ajax', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+
+ // TODO Remove this section when all browsers support HTML5 "required" property
+ var newDbNameInput = $form.find('input[name=new_db]');
+ if (newDbNameInput.val() === '') {
+ newDbNameInput.trigger('focus');
+ alert(Messages.strFormEmpty);
+ return;
+ }
+ // end remove
+
+ Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ Functions.prepareForAjaxRequest($form);
+ $.post($form.attr('action'), $form.serialize(), function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxShowMessage(data.message);
+ var $databasesCountObject = $('#filter-rows-count');
+ var databasesCount = parseInt($databasesCountObject.text(), 10) + 1;
+ $databasesCountObject.text(databasesCount);
+ Navigation.reload();
+
+ // make ajax request to load db structure page - taken from ajax.js
+ var dbStructUrl = data.url;
+ dbStructUrl = dbStructUrl.replace(/amp;/ig, '');
+ var params = 'ajax_request=true' + CommonParams.get('arg_separator') + 'ajax_page_request=true';
+ $.get(dbStructUrl, params, AJAX.responseHandler);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }); // end $(document).on()
+
+ var tableRows = $('.server_databases');
+ $.each(tableRows, function () {
+ $(this).on('click', function () {
+ CommonActions.setDb($(this).attr('data'));
+ });
+ });
+}); // end $()
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/plugins.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/plugins.js
new file mode 100644
index 000000000..7da318049
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/plugins.js
@@ -0,0 +1,16 @@
+/**
+ * Functions used in server plugins pages
+ */
+AJAX.registerOnload('server/plugins.js', function () {
+ // Make columns sortable, but only for tables with more than 1 data row
+ var $tables = $('#plugins_plugins table:has(tbody tr + tr)');
+ $tables.tablesorter({
+ sortList: [[0, 0]],
+ headers: {
+ 1: {
+ sorter: false
+ }
+ }
+ });
+ $tables.find('thead th').append('
');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/privileges.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/privileges.js
new file mode 100644
index 000000000..83ced42b1
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/privileges.js
@@ -0,0 +1,435 @@
+/**
+ * @fileoverview functions used in server privilege pages
+ * @name Server Privileges
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ *
+ */
+
+/**
+ * Validates the "add a user" form
+ *
+ * @param theForm
+ *
+ * @return {bool} whether the form is validated or not
+ */
+function checkAddUser(theForm) {
+ if (theForm.elements.hostname.value === '') {
+ alert(Messages.strHostEmpty);
+ theForm.elements.hostname.focus();
+ return false;
+ }
+ if (theForm.elements.pred_username && theForm.elements.pred_username.value === 'userdefined' && theForm.elements.username.value === '') {
+ alert(Messages.strUserEmpty);
+ theForm.elements.username.focus();
+ return false;
+ }
+ return Functions.checkPassword($(theForm));
+}
+
+/**
+ * Export privileges modal handler
+ *
+ * @param {object} data
+ *
+ * @param {JQuery} msgbox
+ *
+ */
+function exportPrivilegesModalHandler(data, msgbox) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ var modal = $('#exportPrivilegesModal');
+ // Remove any previous privilege modal data, if any
+ modal.find('.modal-body').first().html('');
+ $('#exportPrivilegesModalLabel').first().html('Loading');
+ modal.modal('show');
+ modal.on('shown.bs.modal', function () {
+ modal.find('.modal-body').first().html(data.message);
+ $('#exportPrivilegesModalLabel').first().html(data.title);
+ Functions.ajaxRemoveMessage(msgbox);
+ // Attach syntax highlighted editor to export dialog
+ Functions.getSqlEditor(modal.find('textarea'));
+ });
+ return;
+ }
+ Functions.ajaxShowMessage(data.error, false);
+}
+
+/**
+ * @implements EventListener
+ */
+const EditUserGroup = {
+ /**
+ * @param {MouseEvent} event
+ */
+ handleEvent: function (event) {
+ const editUserGroupModal = document.getElementById('editUserGroupModal');
+ const button = event.relatedTarget;
+ const username = button.getAttribute('data-username');
+ $.get('index.php?route=/server/user-groups/edit-form', {
+ 'username': username,
+ 'server': CommonParams.get('server')
+ }, data => {
+ if (typeof data === 'undefined' || data.success !== true) {
+ Functions.ajaxShowMessage(data.error, false, 'error');
+ return;
+ }
+ const modal = bootstrap.Modal.getInstance(editUserGroupModal);
+ const modalBody = editUserGroupModal.querySelector('.modal-body');
+ const saveButton = editUserGroupModal.querySelector('#editUserGroupModalSaveButton');
+ modalBody.innerHTML = data.message;
+ saveButton.addEventListener('click', () => {
+ const form = $(editUserGroupModal.querySelector('#changeUserGroupForm'));
+ $.post('index.php?route=/server/privileges', form.serialize() + CommonParams.get('arg_separator') + 'ajax_request=1', data => {
+ if (typeof data === 'undefined' || data.success !== true) {
+ Functions.ajaxShowMessage(data.error, false, 'error');
+ return;
+ }
+ const userGroup = form.serializeArray().find(el => el.name === 'userGroup').value;
+ // button -> td -> tr -> td.usrGroup
+ const userGroupTableCell = button.parentElement.parentElement.querySelector('.usrGroup');
+ userGroupTableCell.textContent = userGroup;
+ });
+ modal.hide();
+ });
+ });
+ }
+};
+
+/**
+ * @implements EventListener
+ */
+const AccountLocking = {
+ handleEvent: function () {
+ const button = this;
+ const isLocked = button.dataset.isLocked === 'true';
+ const url = isLocked ? 'index.php?route=/server/privileges/account-unlock' : 'index.php?route=/server/privileges/account-lock';
+ const params = {
+ 'username': button.dataset.userName,
+ 'hostname': button.dataset.hostName,
+ 'ajax_request': true,
+ 'server': CommonParams.get('server')
+ };
+ $.post(url, params, data => {
+ if (data.success === false) {
+ Functions.ajaxShowMessage(data.error);
+ return;
+ }
+ if (isLocked) {
+ const lockIcon = Functions.getImage('s_lock', Messages.strLock, {}).toString();
+ button.innerHTML = '' + lockIcon + ' ' + Messages.strLock + ' ';
+ button.title = Messages.strLockAccount;
+ button.dataset.isLocked = 'false';
+ } else {
+ const unlockIcon = Functions.getImage('s_unlock', Messages.strUnlock, {}).toString();
+ button.innerHTML = '' + unlockIcon + ' ' + Messages.strUnlock + ' ';
+ button.title = Messages.strUnlockAccount;
+ button.dataset.isLocked = 'true';
+ }
+ Functions.ajaxShowMessage(data.message);
+ });
+ }
+};
+
+/**
+ * AJAX scripts for /server/privileges page.
+ *
+ * Actions ajaxified here:
+ * Add user
+ * Revoke a user
+ * Edit privileges
+ * Export privileges
+ * Paginate table of users
+ * Flush privileges
+ *
+ * @memberOf jQuery
+ * @name document.ready
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/privileges.js', function () {
+ $('#fieldset_add_user_login').off('change', 'input[name=\'username\']');
+ $(document).off('click', '#deleteUserCard .btn.ajax');
+ const editUserGroupModal = document.getElementById('editUserGroupModal');
+ if (editUserGroupModal) {
+ editUserGroupModal.removeEventListener('show.bs.modal', EditUserGroup);
+ }
+ $(document).off('click', 'button.mult_submit[value=export]');
+ $(document).off('click', 'a.export_user_anchor.ajax');
+ $('button.jsAccountLocking').off('click');
+ $('#dropUsersDbCheckbox').off('click');
+ $(document).off('click', '.checkall_box');
+ $(document).off('change', '#checkbox_SSL_priv');
+ $(document).off('change', 'input[name="ssl_type"]');
+ $(document).off('change', '#select_authentication_plugin');
+});
+AJAX.registerOnload('server/privileges.js', function () {
+ /**
+ * Display a warning if there is already a user by the name entered as the username.
+ */
+ $('#fieldset_add_user_login').on('change', 'input[name=\'username\']', function () {
+ var username = $(this).val();
+ var $warning = $('#user_exists_warning');
+ if ($('#select_pred_username').val() === 'userdefined' && username !== '') {
+ var href = $('form[name=\'usersForm\']').attr('action');
+ var params = {
+ 'ajax_request': true,
+ 'server': CommonParams.get('server'),
+ 'validate_username': true,
+ 'username': username
+ };
+ $.get(href, params, function (data) {
+ if (data.user_exists) {
+ $warning.show();
+ } else {
+ $warning.hide();
+ }
+ });
+ } else {
+ $warning.hide();
+ }
+ });
+
+ /**
+ * Indicating password strength
+ */
+ $('#text_pma_pw').on('keyup', function () {
+ var meterObj = $('#password_strength_meter');
+ var meterObjLabel = $('#password_strength');
+ var username = $('input[name="username"]');
+ username = username.val();
+ Functions.checkPasswordStrength($(this).val(), meterObj, meterObjLabel, username);
+ });
+
+ /**
+ * Automatically switching to 'Use Text field' from 'No password' once start writing in text area
+ */
+ $('#text_pma_pw').on('input', function () {
+ if ($('#text_pma_pw').val() !== '') {
+ $('#select_pred_password').val('userdefined');
+ }
+ });
+ $('#text_pma_change_pw').on('keyup', function () {
+ var meterObj = $('#change_password_strength_meter');
+ var meterObjLabel = $('#change_password_strength');
+ Functions.checkPasswordStrength($(this).val(), meterObj, meterObjLabel, CommonParams.get('user'));
+ });
+
+ /**
+ * Display a notice if sha256_password is selected
+ */
+ $(document).on('change', '#select_authentication_plugin', function () {
+ var selectedPlugin = $(this).val();
+ if (selectedPlugin === 'sha256_password') {
+ $('#ssl_reqd_warning').show();
+ } else {
+ $('#ssl_reqd_warning').hide();
+ }
+ });
+
+ /**
+ * AJAX handler for 'Revoke User'
+ *
+ * @see Functions.ajaxShowMessage()
+ * @memberOf jQuery
+ * @name revoke_user_click
+ */
+ $(document).on('click', '#deleteUserCard .btn.ajax', function (event) {
+ event.preventDefault();
+ var $thisButton = $(this);
+ var $form = $('#usersForm');
+ $thisButton.confirm(Messages.strDropUserWarning, $form.attr('action'), function (url) {
+ var $dropUsersDbCheckbox = $('#dropUsersDbCheckbox');
+ if ($dropUsersDbCheckbox.is(':checked')) {
+ var isConfirmed = confirm(Messages.strDropDatabaseStrongWarning + '\n' + Functions.sprintf(Messages.strDoYouReally, 'DROP DATABASE'));
+ if (!isConfirmed) {
+ // Uncheck the drop users database checkbox
+ $dropUsersDbCheckbox.prop('checked', false);
+ }
+ }
+ Functions.ajaxShowMessage(Messages.strRemovingSelectedUsers);
+ var argsep = CommonParams.get('arg_separator');
+ $.post(url, $form.serialize() + argsep + 'delete=' + $thisButton.val() + argsep + 'ajax_request=true', function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxShowMessage(data.message);
+ // Refresh navigation, if we dropped some databases with the name
+ // that is the same as the username of the deleted user
+ if ($('#dropUsersDbCheckbox:checked').length) {
+ Navigation.reload();
+ }
+ // Remove the revoked user from the users list
+ $form.find('input:checkbox:checked').parents('tr').slideUp('medium', function () {
+ var thisUserInitial = $(this).find('input:checkbox').val().charAt(0).toUpperCase();
+ $(this).remove();
+
+ // If this is the last user with thisUserInitial, remove the link from #userAccountsPagination
+ if ($('#userRightsTable').find('input:checkbox[value^="' + thisUserInitial + '"], input:checkbox[value^="' + thisUserInitial.toLowerCase() + '"]').length === 0) {
+ $('#userAccountsPagination').find('.page-item > .page-link:contains(' + thisUserInitial + ')').parent('.page-item').addClass('disabled').html('' + thisUserInitial + ' ');
+ }
+
+ // Re-check the classes of each row
+ $form.find('tbody').find('tr').each(function (index) {
+ if (index >= 0 && index % 2 === 0) {
+ $(this).removeClass('odd').addClass('even');
+ } else if (index >= 0 && index % 2 !== 0) {
+ $(this).removeClass('even').addClass('odd');
+ }
+ });
+ // update the checkall checkbox
+ $(Functions.checkboxesSel).trigger('change');
+ });
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ });
+ }); // end Revoke User
+
+ const editUserGroupModal = document.getElementById('editUserGroupModal');
+ if (editUserGroupModal) {
+ editUserGroupModal.addEventListener('show.bs.modal', EditUserGroup);
+ }
+
+ /**
+ * AJAX handler for 'Export Privileges'
+ *
+ * @see Functions.ajaxShowMessage()
+ * @memberOf jQuery
+ * @name export_user_click
+ */
+ $(document).on('click', 'button.mult_submit[value=export]', function (event) {
+ event.preventDefault();
+ // can't export if no users checked
+ if ($(this.form).find('input:checked').length === 0) {
+ Functions.ajaxShowMessage(Messages.strNoAccountSelected, 2000, 'success');
+ return;
+ }
+ var msgbox = Functions.ajaxShowMessage();
+ var argsep = CommonParams.get('arg_separator');
+ var serverId = CommonParams.get('server');
+ var selectedUsers = $('#usersForm input[name*=\'selected_usr\']:checkbox').serialize();
+ var postStr = selectedUsers + '&submit_mult=export' + argsep + 'ajax_request=true&server=' + serverId;
+ $.post($(this.form).prop('action'), postStr, function (data) {
+ exportPrivilegesModalHandler(data, msgbox);
+ }); // end $.post
+ });
+ // if exporting non-ajax, highlight anyways
+ Functions.getSqlEditor($('textarea.export'));
+ $(document).on('click', 'a.export_user_anchor.ajax', function (event) {
+ event.preventDefault();
+ var msgbox = Functions.ajaxShowMessage();
+ $.get($(this).attr('href'), {
+ 'ajax_request': true
+ }, function (data) {
+ exportPrivilegesModalHandler(data, msgbox);
+ }); // end $.get
+ }); // end export privileges
+
+ $('button.jsAccountLocking').on('click', AccountLocking.handleEvent);
+ $(document).on('change', 'input[name="ssl_type"]', function () {
+ var $div = $('#specified_div');
+ if ($('#ssl_type_SPECIFIED').is(':checked')) {
+ $div.find('input').prop('disabled', false);
+ } else {
+ $div.find('input').prop('disabled', true);
+ }
+ });
+ $(document).on('change', '#checkbox_SSL_priv', function () {
+ var $div = $('#require_ssl_div');
+ if ($(this).is(':checked')) {
+ $div.find('input').prop('disabled', false);
+ $('#ssl_type_SPECIFIED').trigger('change');
+ } else {
+ $div.find('input').prop('disabled', true);
+ }
+ });
+ $('#checkbox_SSL_priv').trigger('change');
+
+ /*
+ * Create submenu for simpler interface
+ */
+ var addOrUpdateSubmenu = function () {
+ var $subNav = $('.nav-pills');
+ var $editUserDialog = $('#edit_user_dialog');
+ var submenuLabel;
+ var submenuLink;
+ var linkNumber;
+
+ // if submenu exists yet, remove it first
+ if ($subNav.length > 0) {
+ $subNav.remove();
+ }
+
+ // construct a submenu from the existing fieldsets
+ $subNav = $('').prop('class', 'nav nav-pills m-2');
+ $('#edit_user_dialog .submenu-item').each(function () {
+ submenuLabel = $(this).find('legend[data-submenu-label]').data('submenu-label');
+ submenuLink = $(' ').prop('class', 'nav-link').prop('href', '#').html(submenuLabel);
+ $(' ').prop('class', 'nav-item').append(submenuLink).appendTo($subNav);
+ });
+
+ // click handlers for submenu
+ $subNav.find('a').on('click', function (e) {
+ e.preventDefault();
+ // if already active, ignore click
+ if ($(this).hasClass('active')) {
+ return;
+ }
+ $subNav.find('a').removeClass('active');
+ $(this).addClass('active');
+
+ // which section to show now?
+ linkNumber = $subNav.find('a').index($(this));
+ // hide all sections but the one to show
+ $('#edit_user_dialog .submenu-item').hide().eq(linkNumber).show();
+ });
+
+ // make first menu item active
+ // TODO: support URL hash history
+ $subNav.find('> :first-child a').addClass('active');
+ $editUserDialog.prepend($subNav);
+
+ // hide all sections but the first
+ $('#edit_user_dialog .submenu-item').hide().eq(0).show();
+
+ // scroll to the top
+ $('html, body').animate({
+ scrollTop: 0
+ }, 'fast');
+ };
+ $('input.autofocus').trigger('focus');
+ $(Functions.checkboxesSel).trigger('change');
+ Functions.displayPasswordGenerateButton();
+ if ($('#edit_user_dialog').length > 0) {
+ addOrUpdateSubmenu();
+ }
+
+ /**
+ * Select all privileges
+ *
+ * @param {HTMLElement} e
+ * @return {void}
+ */
+ var tableSelectAll = function (e) {
+ const method = e.target.getAttribute('data-select-target');
+ var options = $(method).first().children();
+ options.each(function (_, obj) {
+ obj.selected = true;
+ });
+ };
+ $('#select_priv_all').on('click', tableSelectAll);
+ $('#insert_priv_all').on('click', tableSelectAll);
+ $('#update_priv_all').on('click', tableSelectAll);
+ $('#references_priv_all').on('click', tableSelectAll);
+ var windowWidth = $(window).width();
+ $('.jsresponsive').css('max-width', windowWidth - 35 + 'px');
+ $('#addUsersForm').on('submit', function () {
+ return checkAddUser(this);
+ });
+ $('#copyUserForm').on('submit', function () {
+ return checkAddUser(this);
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/monitor.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/monitor.js
new file mode 100644
index 000000000..700768d2a
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/monitor.js
@@ -0,0 +1,2156 @@
+/**
+ * @fileoverview Javascript functions used in server status monitor page
+ * @name Server Status Monitor
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ */
+
+/* global isStorageSupported */ // js/config.js
+/* global codeMirrorEditor:writable */ // js/functions.js
+/* global firstDayOfCalendar, themeImagePath */ // templates/javascript/variables.twig
+/* global variableNames */ // templates/server/status/monitor/index.twig
+
+var runtime = {};
+var serverTimeDiff;
+var serverOs;
+var isSuperUser;
+var serverDbIsLocal;
+var chartSize;
+var monitorSettings;
+function serverResponseError() {
+ var btns = {
+ [Messages.strReloadPage]: {
+ text: Messages.strReloadPage,
+ class: 'btn btn-primary',
+ click: function () {
+ window.location.reload();
+ }
+ }
+ };
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strRefreshFailed
+ });
+ $('#emptyDialog').html(Functions.getImage('s_attention') + Messages.strInvalidResponseExplanation);
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ buttons: btns
+ });
+}
+
+/**
+ * Destroys all monitor related resources
+ */
+function destroyGrid() {
+ if (runtime.charts) {
+ $.each(runtime.charts, function (key, value) {
+ try {
+ value.chart.destroy();
+ } catch (err) {
+ // continue regardless of error
+ }
+ });
+ }
+ try {
+ runtime.refreshRequest.abort();
+ } catch (err) {
+ // continue regardless of error
+ }
+ try {
+ clearTimeout(runtime.refreshTimeout);
+ } catch (err) {
+ // continue regardless of error
+ }
+ $('#chartGrid').html('');
+ runtime.charts = null;
+ runtime.chartAI = 0;
+ monitorSettings = null;
+}
+AJAX.registerOnload('server/status/monitor.js', function () {
+ var $jsDataForm = $('#js_data');
+ serverTimeDiff = new Date().getTime() - $jsDataForm.find('input[name=server_time]').val();
+ serverOs = $jsDataForm.find('input[name=server_os]').val();
+ isSuperUser = $jsDataForm.find('input[name=is_superuser]').val();
+ serverDbIsLocal = $jsDataForm.find('input[name=server_db_isLocal]').val();
+});
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/status/monitor.js', function () {
+ $('#emptyDialog').remove();
+ $('a.popupLink').off('click');
+ $('body').off('click');
+});
+/**
+ * Popup behaviour
+ */
+AJAX.registerOnload('server/status/monitor.js', function () {
+ $('
').attr('id', 'emptyDialog').appendTo('#page_content');
+ $('a.popupLink').on('click', function () {
+ var $link = $(this);
+ $('div.' + $link.attr('href').substr(1)).show().offset({
+ top: $link.offset().top + $link.height() + 5,
+ left: $link.offset().left
+ }).addClass('openedPopup');
+ return false;
+ });
+ $('body').on('click', function (event) {
+ $('div.openedPopup').each(function () {
+ var $cnt = $(this);
+ var pos = $cnt.offset();
+ // Hide if the mouseclick is outside the popupcontent
+ if (event.pageX > pos.left + $cnt.outerWidth() || event.pageY > pos.top + $cnt.outerHeight()) {
+ $cnt.hide().removeClass('openedPopup');
+ }
+ });
+ });
+});
+AJAX.registerTeardown('server/status/monitor.js', function () {
+ $('a[href="#rearrangeCharts"], a[href="#endChartEditMode"]').off('click');
+ $('div.popupContent select[name="chartColumns"]').off('change');
+ $('div.popupContent select[name="gridChartRefresh"]').off('change');
+ $('a[href="#addNewChart"]').off('click');
+ $('a[href="#exportMonitorConfig"]').off('click');
+ $('a[href="#importMonitorConfig"]').off('click');
+ $('a[href="#clearMonitorConfig"]').off('click');
+ $('a[href="#pauseCharts"]').off('click');
+ $('a[href="#monitorInstructionsDialog"]').off('click');
+ $('input[name="chartType"]').off('click');
+ $('input[name="useDivisor"]').off('click');
+ $('input[name="useUnit"]').off('click');
+ $('select[name="varChartList"]').off('click');
+ $('a[href="#kibDivisor"]').off('click');
+ $('a[href="#mibDivisor"]').off('click');
+ $('a[href="#submitClearSeries"]').off('click');
+ $('a[href="#submitAddSeries"]').off('click');
+ // $("input#variableInput").destroy();
+ $('#chartPreset').off('click');
+ $('#chartStatusVar').off('click');
+ destroyGrid();
+});
+AJAX.registerOnload('server/status/monitor.js', function () {
+ // Show tab links
+ $('div.tabLinks').show();
+ $('#loadingMonitorIcon').remove();
+ // Codemirror is loaded on demand so we might need to initialize it
+ if (!codeMirrorEditor) {
+ var $elm = $('#sqlquery');
+ if ($elm.length > 0 && typeof CodeMirror !== 'undefined') {
+ codeMirrorEditor = CodeMirror.fromTextArea($elm[0], {
+ lineNumbers: true,
+ matchBrackets: true,
+ indentUnit: 4,
+ mode: 'text/x-mysql',
+ lineWrapping: true
+ });
+ }
+ }
+ // Timepicker is loaded on demand so we need to initialize
+ // datetime fields from the 'load log' dialog
+ $('#logAnalyseDialog').find('.datetimefield').each(function () {
+ Functions.addDatepicker($(this));
+ });
+
+ /** ** Monitor charting implementation ****/
+ /* Saves the previous ajax response for differential values */
+ var oldChartData = null;
+ // Holds about to be created chart
+ var newChart = null;
+ var chartSpacing;
+
+ // Whenever the monitor object (runtime.charts) or the settings object
+ // (monitorSettings) changes in a way incompatible to the previous version,
+ // increase this number. It will reset the users monitor and settings object
+ // in their localStorage to the default configuration
+ var monitorProtocolVersion = '1.0';
+
+ // Runtime parameter of the monitor, is being fully set in initGrid()
+ runtime = {
+ // Holds all visible charts in the grid
+ charts: null,
+ // Stores the timeout handler so it can be cleared
+ refreshTimeout: null,
+ // Stores the GET request to refresh the charts
+ refreshRequest: null,
+ // Chart auto increment
+ chartAI: 0,
+ // To play/pause the monitor
+ redrawCharts: false,
+ // Object that contains a list of nodes that need to be retrieved
+ // from the server for chart updates
+ dataList: [],
+ // Current max points per chart (needed for auto calculation)
+ gridMaxPoints: 20,
+ // displayed time frame
+ xmin: -1,
+ xmax: -1
+ };
+ monitorSettings = null;
+ var defaultMonitorSettings = {
+ columns: 3,
+ chartSize: {
+ width: 295,
+ height: 250
+ },
+ // Max points in each chart. Settings it to 'auto' sets
+ // gridMaxPoints to (chartwidth - 40) / 12
+ gridMaxPoints: 'auto',
+ /* Refresh rate of all grid charts in ms */
+ gridRefresh: 5000
+ };
+
+ // Allows drag and drop rearrange and print/edit icons on charts
+ var editMode = false;
+
+ /* List of preconfigured charts that the user may select */
+ var presetCharts = {
+ // Query cache efficiency
+ 'qce': {
+ title: Messages.strQueryCacheEfficiency,
+ series: [{
+ label: Messages.strQueryCacheEfficiency
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Qcache_hits'
+ }, {
+ type: 'statusvar',
+ name: 'Com_select'
+ }],
+ transformFn: 'qce'
+ }],
+ maxYLabel: 0
+ },
+ // Query cache usage
+ 'qcu': {
+ title: Messages.strQueryCacheUsage,
+ series: [{
+ label: Messages.strQueryCacheUsed
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Qcache_free_memory'
+ }, {
+ type: 'servervar',
+ name: 'query_cache_size'
+ }],
+ transformFn: 'qcu'
+ }],
+ maxYLabel: 0
+ }
+ };
+
+ // time span selection
+ var selectionTimeDiff = [];
+ var selectionStartX;
+ var selectionStartY;
+ var drawTimeSpan = false;
+
+ /* Add OS specific system info charts to the preset chart list */
+ switch (serverOs) {
+ case 'WINNT':
+ $.extend(presetCharts, {
+ 'cpu': {
+ title: Messages.strSystemCPUUsage,
+ series: [{
+ label: Messages.strAverageLoad
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'cpu',
+ name: 'loadavg'
+ }]
+ }],
+ maxYLabel: 100
+ },
+ 'memory': {
+ title: Messages.strSystemMemory,
+ series: [{
+ dataType: 'memory',
+ label: Messages.strUsedMemory,
+ fill: true
+ }, {
+ label: Messages.strFreeMemory,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ },
+ 'swap': {
+ title: Messages.strSystemSwap,
+ series: [{
+ label: Messages.strUsedSwap,
+ fill: true
+ }, {
+ label: Messages.strFreeSwap,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ }
+ });
+ break;
+ case 'Linux':
+ $.extend(presetCharts, {
+ 'cpu': {
+ title: Messages.strSystemCPUUsage,
+ series: [{
+ label: Messages.strAverageLoad
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'cpu',
+ name: 'irrelevant'
+ }],
+ transformFn: 'cpu-linux'
+ }],
+ maxYLabel: 0
+ },
+ 'memory': {
+ title: Messages.strSystemMemory,
+ series: [{
+ label: Messages.strBufferedMemory,
+ fill: true
+ }, {
+ label: Messages.strUsedMemory,
+ fill: true
+ }, {
+ label: Messages.strCachedMemory,
+ fill: true
+ }, {
+ label: Messages.strFreeMemory,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'Buffers'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'Cached'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ },
+ 'swap': {
+ title: Messages.strSystemSwap,
+ series: [{
+ label: Messages.strCachedSwap,
+ fill: true
+ }, {
+ label: Messages.strUsedSwap,
+ fill: true
+ }, {
+ label: Messages.strFreeSwap,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapCached'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ }
+ });
+ break;
+ case 'SunOS':
+ $.extend(presetCharts, {
+ 'cpu': {
+ title: Messages.strSystemCPUUsage,
+ series: [{
+ label: Messages.strAverageLoad
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'cpu',
+ name: 'loadavg'
+ }]
+ }],
+ maxYLabel: 0
+ },
+ 'memory': {
+ title: Messages.strSystemMemory,
+ series: [{
+ label: Messages.strUsedMemory,
+ fill: true
+ }, {
+ label: Messages.strFreeMemory,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'MemFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ },
+ 'swap': {
+ title: Messages.strSystemSwap,
+ series: [{
+ label: Messages.strUsedSwap,
+ fill: true
+ }, {
+ label: Messages.strFreeSwap,
+ fill: true
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapUsed'
+ }],
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'memory',
+ name: 'SwapFree'
+ }],
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ }
+ });
+ break;
+ }
+
+ // Default setting for the chart grid
+ var defaultChartGrid = {
+ 'c0': {
+ title: Messages.strQuestions,
+ series: [{
+ label: Messages.strQuestions
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Questions'
+ }],
+ display: 'differential'
+ }],
+ maxYLabel: 0
+ },
+ 'c1': {
+ title: Messages.strChartConnectionsTitle,
+ series: [{
+ label: Messages.strConnections
+ }, {
+ label: Messages.strProcesses
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Connections'
+ }],
+ display: 'differential'
+ }, {
+ dataPoints: [{
+ type: 'proc',
+ name: 'processes'
+ }]
+ }],
+ maxYLabel: 0
+ },
+ 'c2': {
+ title: Messages.strTraffic,
+ series: [{
+ label: Messages.strBytesSent
+ }, {
+ label: Messages.strBytesReceived
+ }],
+ nodes: [{
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Bytes_sent'
+ }],
+ display: 'differential',
+ valueDivisor: 1024
+ }, {
+ dataPoints: [{
+ type: 'statusvar',
+ name: 'Bytes_received'
+ }],
+ display: 'differential',
+ valueDivisor: 1024
+ }],
+ maxYLabel: 0
+ }
+ };
+
+ // Server is localhost => We can add cpu/memory/swap to the default chart
+ if (serverDbIsLocal && typeof presetCharts.cpu !== 'undefined') {
+ defaultChartGrid.c3 = presetCharts.cpu;
+ defaultChartGrid.c4 = presetCharts.memory;
+ defaultChartGrid.c5 = presetCharts.swap;
+ }
+ $('a[href="#rearrangeCharts"], a[href="#endChartEditMode"]').on('click', function (event) {
+ event.preventDefault();
+ editMode = !editMode;
+ if ($(this).attr('href') === '#endChartEditMode') {
+ editMode = false;
+ }
+ $('a[href="#endChartEditMode"]').toggle(editMode);
+ if (editMode) {
+ // Close the settings popup
+ $('div.popupContent').hide().removeClass('openedPopup');
+ $('#chartGrid').sortableTable({
+ ignoreRect: {
+ top: 8,
+ left: chartSize.width - 63,
+ width: 54,
+ height: 24
+ }
+ });
+ } else {
+ $('#chartGrid').sortableTable('destroy');
+ }
+ saveMonitor(); // Save settings
+ return false;
+ });
+
+ // global settings
+ $('div.popupContent select[name="chartColumns"]').on('change', function () {
+ monitorSettings.columns = parseInt(this.value, 10);
+ calculateChartSize();
+ // Empty cells should keep their size so you can drop onto them
+ $('#chartGrid').find('tr td').css('width', chartSize.width + 'px');
+ $('#chartGrid').find('.monitorChart').css({
+ width: chartSize.width + 'px',
+ height: chartSize.height + 'px'
+ });
+
+ /* Reorder all charts that it fills all column cells */
+ var numColumns;
+ var $tr = $('#chartGrid').find('tr').first();
+ var tempManageCols = function () {
+ if (numColumns > monitorSettings.columns) {
+ if ($tr.next().length === 0) {
+ $tr.after(' ');
+ }
+ $tr.next().prepend($(this));
+ }
+ numColumns++;
+ };
+ var tempAddCol = function () {
+ if ($(this).next().length !== 0) {
+ $(this).append($(this).next().find('td').first());
+ }
+ };
+ while ($tr.length !== 0) {
+ numColumns = 1;
+ // To many cells in one row => put into next row
+ $tr.find('td').each(tempManageCols);
+
+ // To little cells in one row => for each cell to little,
+ // move all cells backwards by 1
+ if ($tr.next().length > 0) {
+ var cnt = monitorSettings.columns - $tr.find('td').length;
+ for (var i = 0; i < cnt; i++) {
+ $tr.append($tr.next().find('td').first());
+ $tr.nextAll().each(tempAddCol);
+ }
+ }
+ $tr = $tr.next();
+ }
+ if (monitorSettings.gridMaxPoints === 'auto') {
+ runtime.gridMaxPoints = Math.round((chartSize.width - 40) / 12);
+ }
+ runtime.xmin = new Date().getTime() - serverTimeDiff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
+ runtime.xmax = new Date().getTime() - serverTimeDiff + monitorSettings.gridRefresh;
+ if (editMode) {
+ $('#chartGrid').sortableTable('refresh');
+ }
+ refreshChartGrid();
+ saveMonitor(); // Save settings
+ });
+
+ $('div.popupContent select[name="gridChartRefresh"]').on('change', function () {
+ monitorSettings.gridRefresh = parseInt(this.value, 10) * 1000;
+ clearTimeout(runtime.refreshTimeout);
+ if (runtime.refreshRequest) {
+ runtime.refreshRequest.abort();
+ }
+ runtime.xmin = new Date().getTime() - serverTimeDiff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
+ // fixing chart shift towards left on refresh rate change
+ // runtime.xmax = new Date().getTime() - serverTimeDiff + monitorSettings.gridRefresh;
+ runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh);
+ saveMonitor(); // Save settings
+ });
+
+ $('a[href="#addNewChart"]').on('click', function (event) {
+ event.preventDefault();
+ $('#addChartButton').on('click', function () {
+ var type = $('input[name="chartType"]:checked').val();
+ if (type === 'preset') {
+ newChart = presetCharts[$('#addChartModal').find('select[name="presetCharts"]').prop('value')];
+ } else {
+ // If user builds their own chart, it's being set/updated
+ // each time they add a series
+ // So here we only warn if they didn't add a series yet
+ if (!newChart || !newChart.nodes || newChart.nodes.length === 0) {
+ alert(Messages.strAddOneSeriesWarning);
+ return;
+ }
+ }
+ newChart.title = $('input[name="chartTitle"]').val();
+ // Add a cloned object to the chart grid
+ addChart($.extend(true, {}, newChart));
+ newChart = null;
+ saveMonitor(); // Save settings
+
+ $('#closeModalButton').off('click');
+ });
+ $('#closeModalButton').on('click', function () {
+ newChart = null;
+ $('span#clearSeriesLink').hide();
+ $('#seriesPreview').html('');
+ $('#closeModalButton').off('click');
+ });
+ var $presetList = $('#addChartModal').find('select[name="presetCharts"]');
+ if ($presetList.html().length === 0) {
+ $.each(presetCharts, function (key, value) {
+ $presetList.append('' + value.title + ' ');
+ });
+ $presetList.on('change', function () {
+ $('input[name="chartTitle"]').val($presetList.find(':selected').text());
+ $('#chartPreset').prop('checked', true);
+ });
+ $('#chartPreset').on('click', function () {
+ $('input[name="chartTitle"]').val($presetList.find(':selected').text());
+ });
+ $('#chartStatusVar').on('click', function () {
+ $('input[name="chartTitle"]').val($('#chartSeries').find(':selected').text().replace(/_/g, ' '));
+ });
+ $('#chartSeries').on('change', function () {
+ $('input[name="chartTitle"]').val($('#chartSeries').find(':selected').text().replace(/_/g, ' '));
+ });
+ }
+ $('#addChartModal').modal('show');
+ $('#seriesPreview').html('' + Messages.strNone + ' ');
+ return false;
+ });
+ $('a[href="#exportMonitorConfig"]').on('click', function (event) {
+ event.preventDefault();
+ var gridCopy = {};
+ $.each(runtime.charts, function (key, elem) {
+ gridCopy[key] = {};
+ gridCopy[key].nodes = elem.nodes;
+ gridCopy[key].series = elem.series;
+ gridCopy[key].settings = elem.settings;
+ gridCopy[key].title = elem.title;
+ gridCopy[key].maxYLabel = elem.maxYLabel;
+ });
+ var exportData = {
+ monitorCharts: gridCopy,
+ monitorSettings: monitorSettings
+ };
+ var blob = new Blob([JSON.stringify(exportData)], {
+ type: 'application/octet-stream'
+ });
+ var url = null;
+ var fileName = 'monitor-config.json';
+ if (window.navigator && window.navigator.msSaveOrOpenBlob) {
+ window.navigator.msSaveOrOpenBlob(blob, fileName);
+ } else {
+ url = URL.createObjectURL(blob);
+ window.location.href = url;
+ }
+ setTimeout(function () {
+ // For some browsers it is necessary to delay revoking the ObjectURL
+ if (url !== null) {
+ window.URL.revokeObjectURL(url);
+ }
+ url = undefined;
+ blob = undefined;
+ }, 100);
+ });
+ $('a[href="#importMonitorConfig"]').on('click', function (event) {
+ event.preventDefault();
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strImportDialogTitle
+ });
+ $('#emptyDialog').html(Messages.strImportDialogMessage + ' ');
+ var dlgBtns = {
+ [Messages.strImport]: {
+ text: Messages.strImport,
+ class: 'btn btn-primary'
+ },
+ [Messages.strCancel]: {
+ text: Messages.strCancel,
+ class: 'btn btn-secondary'
+ }
+ };
+ dlgBtns[Messages.strImport].click = function () {
+ var input = $('#emptyDialog').find('#import_file')[0];
+ var reader = new FileReader();
+ reader.onerror = function (event) {
+ alert(Messages.strFailedParsingConfig + '\n' + event.target.error.code);
+ };
+ reader.onload = function (e) {
+ var data = e.target.result;
+ var json = null;
+ // Try loading config
+ try {
+ json = JSON.parse(data);
+ } catch (err) {
+ alert(Messages.strFailedParsingConfig);
+ $('#emptyDialog').dialog('close');
+ return;
+ }
+
+ // Basic check, is this a monitor config json?
+ if (!json || !json.monitorCharts || !json.monitorCharts) {
+ alert(Messages.strFailedParsingConfig);
+ $('#emptyDialog').dialog('close');
+ return;
+ }
+
+ // If json ok, try applying config
+ try {
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.monitorCharts = JSON.stringify(json.monitorCharts);
+ window.localStorage.monitorSettings = JSON.stringify(json.monitorSettings);
+ }
+ rebuildGrid();
+ } catch (err) {
+ alert(Messages.strFailedBuildingGrid);
+ // If an exception is thrown, load default again
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.removeItem('monitorCharts');
+ window.localStorage.removeItem('monitorSettings');
+ }
+ rebuildGrid();
+ }
+ $('#emptyDialog').dialog('close');
+ };
+ reader.readAsText(input.files[0]);
+ };
+ dlgBtns[Messages.strCancel].click = function () {
+ $(this).dialog('close');
+ };
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: 'auto',
+ height: 'auto',
+ buttons: dlgBtns
+ });
+ });
+ $('a[href="#clearMonitorConfig"]').on('click', function (event) {
+ event.preventDefault();
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.removeItem('monitorCharts');
+ window.localStorage.removeItem('monitorSettings');
+ window.localStorage.removeItem('monitorVersion');
+ }
+ $(this).hide();
+ rebuildGrid();
+ });
+ $('a[href="#pauseCharts"]').on('click', function (event) {
+ event.preventDefault();
+ runtime.redrawCharts = !runtime.redrawCharts;
+ if (!runtime.redrawCharts) {
+ $(this).html(Functions.getImage('play') + Messages.strResumeMonitor);
+ } else {
+ $(this).html(Functions.getImage('pause') + Messages.strPauseMonitor);
+ if (!runtime.charts) {
+ initGrid();
+ $('a[href="#settingsPopup"]').show();
+ }
+ }
+ return false;
+ });
+ $('a[href="#monitorInstructionsDialog"]').on('click', function (event) {
+ event.preventDefault();
+ var $dialog = $('#monitorInstructionsDialog');
+ var dlgBtns = {
+ [Messages.strClose]: {
+ text: Messages.strClose,
+ class: 'btn btn-primary',
+ click: function () {
+ $(this).dialog('close');
+ }
+ }
+ };
+ $dialog.dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: '60%',
+ height: 'auto',
+ buttons: dlgBtns
+ }).find('img.ajaxIcon').show();
+ var loadLogVars = function (getvars) {
+ var vars = {
+ 'ajax_request': true,
+ 'server': CommonParams.get('server')
+ };
+ if (getvars) {
+ $.extend(vars, getvars);
+ }
+ $.post('index.php?route=/server/status/monitor/log-vars', vars, function (data) {
+ var logVars;
+ if (typeof data !== 'undefined' && data.success === true) {
+ logVars = data.message;
+ } else {
+ return serverResponseError();
+ }
+ var icon = Functions.getImage('s_success');
+ var msg = '';
+ var str = '';
+ if (logVars.general_log === 'ON') {
+ if (logVars.slow_query_log === 'ON') {
+ msg = Messages.strBothLogOn;
+ } else {
+ msg = Messages.strGenLogOn;
+ }
+ }
+ if (msg.length === 0 && logVars.slow_query_log === 'ON') {
+ msg = Messages.strSlowLogOn;
+ }
+ if (msg.length === 0) {
+ icon = Functions.getImage('s_error');
+ msg = Messages.strBothLogOff;
+ }
+ str = '' + Messages.strCurrentSettings + ' ';
+ str += icon + msg + ' ';
+ if (logVars.log_output !== 'TABLE') {
+ str += Functions.getImage('s_error') + ' ' + Messages.strLogOutNotTable + ' ';
+ } else {
+ str += Functions.getImage('s_success') + ' ' + Messages.strLogOutIsTable + ' ';
+ }
+ if (logVars.slow_query_log === 'ON') {
+ if (logVars.long_query_time > 2) {
+ str += Functions.getImage('s_attention') + ' ';
+ str += Functions.sprintf(Messages.strSmallerLongQueryTimeAdvice, logVars.long_query_time);
+ str += ' ';
+ }
+ if (logVars.long_query_time < 2) {
+ str += Functions.getImage('s_success') + ' ';
+ str += Functions.sprintf(Messages.strLongQueryTimeSet, logVars.long_query_time);
+ str += ' ';
+ }
+ }
+ str += '
';
+ if (isSuperUser) {
+ str += '
' + Messages.strChangeSettings + ' ';
+ str += '';
+ $dialog.find('div.monitorUse').toggle(logVars.log_output === 'TABLE' && (logVars.slow_query_log === 'ON' || logVars.general_log === 'ON'));
+ $dialog.find('div.ajaxContent').html(str);
+ $dialog.find('img.ajaxIcon').hide();
+ $dialog.find('a.set').on('click', function () {
+ var nameValue = $(this).attr('href').split('-');
+ loadLogVars({
+ varName: nameValue[0].substr(1),
+ varValue: nameValue[1]
+ });
+ $dialog.find('img.ajaxIcon').show();
+ });
+ });
+ };
+ loadLogVars();
+ return false;
+ });
+ $('input[name="chartType"]').on('change', function () {
+ $('#chartVariableSettings').toggle(this.checked && this.value === 'variable');
+ var title = $('input[name="chartTitle"]').val();
+ if (title === Messages.strChartTitle || title === $('label[for="' + $('input[name="chartTitle"]').data('lastRadio') + '"]').text()) {
+ $('input[name="chartTitle"]').data('lastRadio', $(this).attr('id')).val($('label[for="' + $(this).attr('id') + '"]').text());
+ }
+ });
+ $('input[name="useDivisor"]').on('change', function () {
+ $('span.divisorInput').toggle(this.checked);
+ });
+ $('input[name="useUnit"]').on('change', function () {
+ $('span.unitInput').toggle(this.checked);
+ });
+ $('select[name="varChartList"]').on('change', function () {
+ if (this.selectedIndex !== 0) {
+ $('#variableInput').val(this.value);
+ }
+ });
+ $('a[href="#kibDivisor"]').on('click', function (event) {
+ event.preventDefault();
+ $('input[name="valueDivisor"]').val(1024);
+ $('input[name="valueUnit"]').val(Messages.strKiB);
+ $('span.unitInput').toggle(true);
+ $('input[name="useUnit"]').prop('checked', true);
+ return false;
+ });
+ $('a[href="#mibDivisor"]').on('click', function (event) {
+ event.preventDefault();
+ $('input[name="valueDivisor"]').val(1024 * 1024);
+ $('input[name="valueUnit"]').val(Messages.strMiB);
+ $('span.unitInput').toggle(true);
+ $('input[name="useUnit"]').prop('checked', true);
+ return false;
+ });
+ $('a[href="#submitClearSeries"]').on('click', function (event) {
+ event.preventDefault();
+ $('#seriesPreview').html('' + Messages.strNone + ' ');
+ newChart = null;
+ $('#clearSeriesLink').hide();
+ });
+ $('a[href="#submitAddSeries"]').on('click', function (event) {
+ event.preventDefault();
+ if ($('#variableInput').val() === '') {
+ return false;
+ }
+ if (newChart === null) {
+ $('#seriesPreview').html('');
+ newChart = {
+ title: $('input[name="chartTitle"]').val(),
+ nodes: [],
+ series: [],
+ maxYLabel: 0
+ };
+ }
+ var serie = {
+ dataPoints: [{
+ type: 'statusvar',
+ name: $('#variableInput').val()
+ }],
+ display: $('input[name="differentialValue"]').prop('checked') ? 'differential' : ''
+ };
+ if (serie.dataPoints[0].name === 'Processes') {
+ serie.dataPoints[0].type = 'proc';
+ }
+ if ($('input[name="useDivisor"]').prop('checked')) {
+ serie.valueDivisor = parseInt($('input[name="valueDivisor"]').val(), 10);
+ }
+ if ($('input[name="useUnit"]').prop('checked')) {
+ serie.unit = $('input[name="valueUnit"]').val();
+ }
+ var str = serie.display === 'differential' ? ', ' + Messages.strDifferential : '';
+ str += serie.valueDivisor ? ', ' + Functions.sprintf(Messages.strDividedBy, serie.valueDivisor) : '';
+ str += serie.unit ? ', ' + Messages.strUnit + ': ' + serie.unit : '';
+ var newSeries = {
+ label: $('#variableInput').val().replace(/_/g, ' ')
+ };
+ newChart.series.push(newSeries);
+ $('#seriesPreview').append('- ' + Functions.escapeHtml(newSeries.label + str) + ' ');
+ newChart.nodes.push(serie);
+ $('#variableInput').val('');
+ $('input[name="differentialValue"]').prop('checked', true);
+ $('input[name="useDivisor"]').prop('checked', false);
+ $('input[name="useUnit"]').prop('checked', false);
+ $('input[name="useDivisor"]').trigger('change');
+ $('input[name="useUnit"]').trigger('change');
+ $('select[name="varChartList"]').get(0).selectedIndex = 0;
+ $('#clearSeriesLink').show();
+ return false;
+ });
+ $('#variableInput').autocomplete({
+ source: variableNames
+ });
+
+ /* Initializes the monitor, called only once */
+ function initGrid() {
+ var i;
+
+ /* Apply default values & config */
+ if (isStorageSupported('localStorage')) {
+ if (typeof window.localStorage.monitorCharts !== 'undefined') {
+ runtime.charts = JSON.parse(window.localStorage.monitorCharts);
+ }
+ if (typeof window.localStorage.monitorSettings !== 'undefined') {
+ monitorSettings = JSON.parse(window.localStorage.monitorSettings);
+ }
+ $('a[href="#clearMonitorConfig"]').toggle(runtime.charts !== null);
+ if (runtime.charts !== null && typeof window.localStorage.monitorVersion !== 'undefined' && monitorProtocolVersion !== window.localStorage.monitorVersion) {
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strIncompatibleMonitorConfig
+ });
+ $('#emptyDialog').html(Messages.strIncompatibleMonitorConfigDescription);
+ var dlgBtns = {
+ [Messages.strClose]: {
+ text: Messages.strClose,
+ class: 'btn btn-primary',
+ click: function () {
+ $(this).dialog('close');
+ }
+ }
+ };
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: 400,
+ buttons: dlgBtns
+ });
+ }
+ }
+ if (runtime.charts === null) {
+ runtime.charts = defaultChartGrid;
+ }
+ if (monitorSettings === null) {
+ monitorSettings = defaultMonitorSettings;
+ }
+ $('select[name="gridChartRefresh"]').val(monitorSettings.gridRefresh / 1000);
+ $('select[name="chartColumns"]').val(monitorSettings.columns);
+ if (monitorSettings.gridMaxPoints === 'auto') {
+ runtime.gridMaxPoints = Math.round((monitorSettings.chartSize.width - 40) / 12);
+ } else {
+ runtime.gridMaxPoints = monitorSettings.gridMaxPoints;
+ }
+ runtime.xmin = new Date().getTime() - serverTimeDiff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
+ runtime.xmax = new Date().getTime() - serverTimeDiff + monitorSettings.gridRefresh;
+
+ /* Calculate how much spacing there is between each chart */
+ $('#chartGrid').html(' ');
+ chartSpacing = {
+ width: $('#chartGrid').find('td').eq(1).offset().left - $('#chartGrid').find('td').eq(0).offset().left,
+ height: $('#chartGrid').find('tr').eq(1).find('td').eq(1).offset().top - $('#chartGrid').find('tr').eq(0).find('td').eq(0).offset().top
+ };
+ $('#chartGrid').html('');
+
+ /* Add all charts - in correct order */
+ var keys = [];
+ $.each(runtime.charts, function (key) {
+ keys.push(key);
+ });
+ keys.sort();
+ for (i = 0; i < keys.length; i++) {
+ addChart(runtime.charts[keys[i]], true);
+ }
+
+ /* Fill in missing cells */
+ var numCharts = $('#chartGrid').find('.monitorChart').length;
+ var numMissingCells = (monitorSettings.columns - numCharts % monitorSettings.columns) % monitorSettings.columns;
+ for (i = 0; i < numMissingCells; i++) {
+ $('#chartGrid').find('tr').last().append(' ');
+ }
+
+ // Empty cells should keep their size so you can drop onto them
+ calculateChartSize();
+ $('#chartGrid').find('tr td').css('width', chartSize.width + 'px');
+ buildRequiredDataList();
+ refreshChartGrid();
+ }
+
+ /* Calls destroyGrid() and initGrid(), but before doing so it saves the chart
+ * data from each chart and restores it after the monitor is initialized again */
+ function rebuildGrid() {
+ var oldData = null;
+ if (runtime.charts) {
+ oldData = {};
+ $.each(runtime.charts, function (key, chartObj) {
+ for (var i = 0, l = chartObj.nodes.length; i < l; i++) {
+ oldData[chartObj.nodes[i].dataPoint] = [];
+ for (var j = 0, ll = chartObj.chart.series[i].data.length; j < ll; j++) {
+ oldData[chartObj.nodes[i].dataPoint].push([chartObj.chart.series[i].data[j].x, chartObj.chart.series[i].data[j].y]);
+ }
+ }
+ });
+ }
+ destroyGrid();
+ initGrid();
+ }
+
+ /* Calculates the dynamic chart size that depends on the column width */
+ function calculateChartSize() {
+ var panelWidth;
+ if ($('body').height() > $(window).height()) {
+ // has vertical scroll bar
+ panelWidth = $('#logTable').innerWidth();
+ } else {
+ panelWidth = $('#logTable').innerWidth() - 10; // leave some space for vertical scroll bar
+ }
+
+ var wdt = panelWidth;
+ var windowWidth = $(window).width();
+ if (windowWidth > 768) {
+ wdt = (panelWidth - monitorSettings.columns * Math.abs(chartSpacing.width)) / monitorSettings.columns;
+ }
+ chartSize = {
+ width: Math.floor(wdt),
+ height: Math.floor(0.75 * wdt)
+ };
+ }
+
+ /* Adds a chart to the chart grid */
+ function addChart(chartObj, initialize) {
+ var i;
+ var settings = {
+ title: Functions.escapeHtml(chartObj.title),
+ grid: {
+ drawBorder: false,
+ shadow: false,
+ background: 'rgba(0,0,0,0)'
+ },
+ axes: {
+ xaxis: {
+ renderer: $.jqplot.DateAxisRenderer,
+ tickOptions: {
+ formatString: '%H:%M:%S',
+ showGridline: false
+ },
+ min: runtime.xmin,
+ max: runtime.xmax
+ },
+ yaxis: {
+ min: 0,
+ max: 100,
+ tickInterval: 20
+ }
+ },
+ seriesDefaults: {
+ rendererOptions: {
+ smooth: true
+ },
+ showLine: true,
+ lineWidth: 2,
+ markerOptions: {
+ size: 6
+ }
+ },
+ highlighter: {
+ show: true
+ }
+ };
+ if (settings.title === Messages.strSystemCPUUsage || settings.title === Messages.strQueryCacheEfficiency) {
+ settings.axes.yaxis.tickOptions = {
+ formatString: '%d %%'
+ };
+ } else if (settings.title === Messages.strSystemMemory || settings.title === Messages.strSystemSwap) {
+ settings.stackSeries = true;
+ settings.axes.yaxis.tickOptions = {
+ formatter: $.jqplot.byteFormatter(2) // MiB
+ };
+ } else if (settings.title === Messages.strTraffic) {
+ settings.axes.yaxis.tickOptions = {
+ formatter: $.jqplot.byteFormatter(1) // KiB
+ };
+ } else if (settings.title === Messages.strQuestions || settings.title === Messages.strConnections) {
+ settings.axes.yaxis.tickOptions = {
+ formatter: function (format, val) {
+ if (Math.abs(val) >= 1000000) {
+ return $.jqplot.sprintf('%.3g M', val / 1000000);
+ } else if (Math.abs(val) >= 1000) {
+ return $.jqplot.sprintf('%.3g k', val / 1000);
+ } else {
+ return $.jqplot.sprintf('%d', val);
+ }
+ }
+ };
+ }
+ settings.series = chartObj.series;
+ if ($('#' + 'gridchart' + runtime.chartAI).length === 0) {
+ var numCharts = $('#chartGrid').find('.monitorChart').length;
+ if (numCharts === 0 || numCharts % monitorSettings.columns === 0) {
+ $('#chartGrid').append(' ');
+ }
+ if (!chartSize) {
+ calculateChartSize();
+ }
+ $('#chartGrid').find('tr').last().append(' ');
+ }
+
+ // Set series' data as [0,0], smooth lines won't plot with data array having null values.
+ // also chart won't plot initially with no data and data comes on refreshChartGrid()
+ var series = [];
+ for (i in chartObj.series) {
+ series.push([[0, 0]]);
+ }
+ var tempTooltipContentEditor = function (str, seriesIndex, pointIndex, plot) {
+ var j;
+ // TODO: move style to theme CSS
+ var tooltipHtml = '';
+ // x value i.e. time
+ var timeValue = str.split(',')[0];
+ var seriesValue;
+ tooltipHtml += 'Time: ' + timeValue;
+ tooltipHtml += '';
+ // Add y values to the tooltip per series
+ for (j in plot.series) {
+ // get y value if present
+ if (plot.series[j].data.length > pointIndex) {
+ seriesValue = plot.series[j].data[pointIndex][1];
+ } else {
+ return;
+ }
+ var seriesLabel = plot.series[j].label;
+ var seriesColor = plot.series[j].color;
+ // format y value
+ if (plot.series[0]._yaxis.tickOptions.formatter) {
+ // eslint-disable-line no-underscore-dangle
+ // using formatter function
+ // eslint-disable-next-line no-underscore-dangle
+ seriesValue = plot.series[0]._yaxis.tickOptions.formatter('%s', seriesValue);
+ } else if (plot.series[0]._yaxis.tickOptions.formatString) {
+ // eslint-disable-line no-underscore-dangle
+ // using format string
+ // eslint-disable-next-line no-underscore-dangle
+ seriesValue = Functions.sprintf(plot.series[0]._yaxis.tickOptions.formatString, seriesValue);
+ }
+ tooltipHtml += '' + seriesLabel + ': ' + seriesValue + ' ';
+ }
+ tooltipHtml += '
';
+ return tooltipHtml;
+ };
+
+ // set Tooltip for each series
+ for (i in settings.series) {
+ settings.series[i].highlighter = {
+ show: true,
+ tooltipContentEditor: tempTooltipContentEditor
+ };
+ }
+ chartObj.chart = $.jqplot('gridchart' + runtime.chartAI, series, settings);
+ // remove [0,0] after plotting
+ for (i in chartObj.chart.series) {
+ chartObj.chart.series[i].data.shift();
+ }
+ var $legend = $('
').css('padding', '0.5em');
+ for (i in chartObj.chart.series) {
+ $legend.append($('
').append($('').css({
+ width: '1em',
+ height: '1em',
+ background: chartObj.chart.seriesColors[i]
+ }).addClass('float-start')).append($('
').text(chartObj.chart.series[i].label).addClass('float-start')).append($('
')).addClass('float-start'));
+ }
+ $('#gridchart' + runtime.chartAI).parent().append($legend);
+ if (initialize !== true) {
+ runtime.charts['c' + runtime.chartAI] = chartObj;
+ buildRequiredDataList();
+ }
+
+ // time span selection
+ $('#gridchart' + runtime.chartAI).on('jqplotMouseDown', function (ev, gridpos, datapos) {
+ drawTimeSpan = true;
+ selectionTimeDiff.push(datapos.xaxis);
+ if ($('#selection_box').length) {
+ $('#selection_box').remove();
+ }
+ var selectionBox = $('
');
+ // eslint-disable-next-line compat/compat
+ $(document.body).append(selectionBox);
+ selectionStartX = ev.pageX;
+ selectionStartY = ev.pageY;
+ selectionBox.attr({
+ id: 'selection_box'
+ }).css({
+ top: selectionStartY - gridpos.y,
+ left: selectionStartX
+ }).fadeIn();
+ });
+ $('#gridchart' + runtime.chartAI).on('jqplotMouseUp', function (ev, gridpos, datapos) {
+ if (!drawTimeSpan || editMode) {
+ return;
+ }
+ selectionTimeDiff.push(datapos.xaxis);
+ if (selectionTimeDiff[1] <= selectionTimeDiff[0]) {
+ selectionTimeDiff = [];
+ return;
+ }
+ // get date from timestamp
+ var min = new Date(Math.ceil(selectionTimeDiff[0]));
+ var max = new Date(Math.ceil(selectionTimeDiff[1]));
+ getLogAnalyseDialog(min, max);
+ selectionTimeDiff = [];
+ drawTimeSpan = false;
+ });
+ $('#gridchart' + runtime.chartAI).on('jqplotMouseMove', function (ev) {
+ if (!drawTimeSpan || editMode) {
+ return;
+ }
+ if (selectionStartX !== undefined) {
+ $('#selection_box').css({
+ width: Math.ceil(ev.pageX - selectionStartX)
+ }).fadeIn();
+ }
+ });
+ $('#gridchart' + runtime.chartAI).on('jqplotMouseLeave', function () {
+ drawTimeSpan = false;
+ });
+
+ // eslint-disable-next-line compat/compat
+ $(document.body).on('mouseup', function () {
+ if ($('#selection_box').length) {
+ $('#selection_box').remove();
+ }
+ });
+
+ // Edit, Print icon only in edit mode
+ $('#chartGrid').find('div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode);
+ runtime.chartAI++;
+ }
+ function getLogAnalyseDialog(min, max) {
+ var $logAnalyseDialog = $('#logAnalyseDialog');
+ var $dateStart = $logAnalyseDialog.find('input[name="dateStart"]');
+ var $dateEnd = $logAnalyseDialog.find('input[name="dateEnd"]');
+ $dateStart.prop('readonly', true);
+ $dateEnd.prop('readonly', true);
+ var dlgBtns = {
+ [Messages.strFromSlowLog]: {
+ text: Messages.strFromSlowLog,
+ class: 'btn btn-secondary'
+ },
+ [Messages.strFromGeneralLog]: {
+ text: Messages.strFromGeneralLog,
+ class: 'btn btn-secondary'
+ }
+ };
+ dlgBtns[Messages.strFromSlowLog].click = function () {
+ loadLog('slow', min, max);
+ $(this).dialog('close');
+ };
+ dlgBtns[Messages.strFromGeneralLog].click = function () {
+ loadLog('general', min, max);
+ $(this).dialog('close');
+ };
+ $logAnalyseDialog.dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: 'auto',
+ height: 'auto',
+ buttons: dlgBtns
+ });
+ Functions.addDatepicker($dateStart, 'datetime', {
+ showMillisec: false,
+ showMicrosec: false,
+ timeFormat: 'HH:mm:ss',
+ firstDay: firstDayOfCalendar
+ });
+ Functions.addDatepicker($dateEnd, 'datetime', {
+ showMillisec: false,
+ showMicrosec: false,
+ timeFormat: 'HH:mm:ss',
+ firstDay: firstDayOfCalendar
+ });
+ $dateStart.datepicker('setDate', min);
+ $dateEnd.datepicker('setDate', max);
+ }
+ function loadLog(type, min, max) {
+ var dateStart = Date.parse($('#logAnalyseDialog').find('input[name="dateStart"]').datepicker('getDate')) || min;
+ var dateEnd = Date.parse($('#logAnalyseDialog').find('input[name="dateEnd"]').datepicker('getDate')) || max;
+ loadLogStatistics({
+ src: type,
+ start: dateStart,
+ end: dateEnd,
+ removeVariables: $('#removeVariables').prop('checked'),
+ limitTypes: $('#limitTypes').prop('checked')
+ });
+ }
+
+ /* Called in regular intervals, this function updates the values of each chart in the grid */
+ function refreshChartGrid() {
+ /* Send to server */
+ runtime.refreshRequest = $.post('index.php?route=/server/status/monitor/chart', {
+ 'ajax_request': true,
+ 'requiredData': JSON.stringify(runtime.dataList),
+ 'server': CommonParams.get('server')
+ }, function (data) {
+ var chartData;
+ if (typeof data !== 'undefined' && data.success === true) {
+ chartData = data.message;
+ } else {
+ return serverResponseError();
+ }
+ var value;
+ var i = 0;
+ var diff;
+ var total;
+
+ /* Update values in each graph */
+ $.each(runtime.charts, function (orderKey, elem) {
+ var key = elem.chartID;
+ // If newly added chart, we have no data for it yet
+ if (!chartData[key]) {
+ return;
+ }
+ // Draw all series
+ total = 0;
+ for (var j = 0; j < elem.nodes.length; j++) {
+ // Update x-axis
+ if (i === 0 && j === 0) {
+ if (oldChartData === null) {
+ diff = chartData.x - runtime.xmax;
+ } else {
+ diff = parseInt(chartData.x - oldChartData.x, 10);
+ }
+ runtime.xmin += diff;
+ runtime.xmax += diff;
+ }
+
+ // elem.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false);
+ /* Calculate y value */
+
+ // If transform function given, use it
+ if (elem.nodes[j].transformFn) {
+ value = chartValueTransform(elem.nodes[j].transformFn, chartData[key][j],
+ // Check if first iteration (oldChartData==null), or if newly added chart oldChartData[key]==null
+
+ oldChartData === null || oldChartData[key] === null || oldChartData[key] === undefined ? null : oldChartData[key][j]);
+
+ // Otherwise use original value and apply differential and divisor if given,
+ // in this case we have only one data point per series - located at chartData[key][j][0]
+ } else {
+ value = parseFloat(chartData[key][j][0].value);
+ if (elem.nodes[j].display === 'differential') {
+ if (oldChartData === null || oldChartData[key] === null || oldChartData[key] === undefined) {
+ continue;
+ }
+ value -= oldChartData[key][j][0].value;
+ }
+ if (elem.nodes[j].valueDivisor) {
+ value = value / elem.nodes[j].valueDivisor;
+ }
+ }
+
+ // Set y value, if defined
+ if (value !== undefined) {
+ elem.chart.series[j].data.push([chartData.x, value]);
+ if (value > elem.maxYLabel) {
+ elem.maxYLabel = value;
+ } else if (elem.maxYLabel === 0) {
+ elem.maxYLabel = 0.5;
+ }
+ // free old data point values and update maxYLabel
+ if (elem.chart.series[j].data.length > runtime.gridMaxPoints && elem.chart.series[j].data[0][0] < runtime.xmin) {
+ // check if the next freeable point is highest
+ if (elem.maxYLabel <= elem.chart.series[j].data[0][1]) {
+ elem.chart.series[j].data.splice(0, elem.chart.series[j].data.length - runtime.gridMaxPoints);
+ elem.maxYLabel = getMaxYLabel(elem.chart.series[j].data);
+ } else {
+ elem.chart.series[j].data.splice(0, elem.chart.series[j].data.length - runtime.gridMaxPoints);
+ }
+ }
+ if (elem.title === Messages.strSystemMemory || elem.title === Messages.strSystemSwap) {
+ total += value;
+ }
+ }
+ }
+
+ // update chart options
+ // keep ticks number/positioning consistent while refreshrate changes
+ var tickInterval = (runtime.xmax - runtime.xmin) / 5;
+ elem.chart.axes.xaxis.ticks = [runtime.xmax - tickInterval * 4, runtime.xmax - tickInterval * 3, runtime.xmax - tickInterval * 2, runtime.xmax - tickInterval, runtime.xmax];
+ if (elem.title !== Messages.strSystemCPUUsage && elem.title !== Messages.strQueryCacheEfficiency && elem.title !== Messages.strSystemMemory && elem.title !== Messages.strSystemSwap) {
+ elem.chart.axes.yaxis.max = Math.ceil(elem.maxYLabel * 1.1);
+ elem.chart.axes.yaxis.tickInterval = Math.ceil(elem.maxYLabel * 1.1 / 5);
+ } else if (elem.title === Messages.strSystemMemory || elem.title === Messages.strSystemSwap) {
+ elem.chart.axes.yaxis.max = Math.ceil(total * 1.1 / 100) * 100;
+ elem.chart.axes.yaxis.tickInterval = Math.ceil(total * 1.1 / 5);
+ }
+ i++;
+ if (runtime.redrawCharts) {
+ elem.chart.replot();
+ }
+ });
+ oldChartData = chartData;
+ runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh);
+ });
+ }
+
+ /* Function to get highest plotted point's y label, to scale the chart,
+ * TODO: make jqplot's autoscale:true work here
+ */
+ function getMaxYLabel(dataValues) {
+ var maxY = dataValues[0][1];
+ $.each(dataValues, function (k, v) {
+ maxY = v[1] > maxY ? v[1] : maxY;
+ });
+ return maxY;
+ }
+
+ /* Function that supplies special value transform functions for chart values */
+ function chartValueTransform(name, cur, prev) {
+ switch (name) {
+ case 'cpu-linux':
+ if (prev === null) {
+ return undefined;
+ }
+ // cur and prev are datapoint arrays, but containing
+ // only 1 element for cpu-linux
+ var newCur = cur[0];
+ var newPrev = prev[0];
+ var diffTotal = newCur.busy + newCur.idle - (newPrev.busy + newPrev.idle);
+ var diffIdle = newCur.idle - newPrev.idle;
+ return 100 * (diffTotal - diffIdle) / diffTotal;
+
+ // Query cache efficiency (%)
+ case 'qce':
+ if (prev === null) {
+ return undefined;
+ }
+ // cur[0].value is Qcache_hits, cur[1].value is Com_select
+ var diffQHits = cur[0].value - prev[0].value;
+ // No NaN please :-)
+ if (cur[1].value - prev[1].value === 0) {
+ return 0;
+ }
+ return diffQHits / (cur[1].value - prev[1].value + diffQHits) * 100;
+
+ // Query cache usage (%)
+ case 'qcu':
+ if (cur[1].value === 0) {
+ return 0;
+ }
+ // cur[0].value is Qcache_free_memory, cur[1].value is query_cache_size
+ return 100 - cur[0].value / cur[1].value * 100;
+ }
+ return undefined;
+ }
+
+ /* Build list of nodes that need to be retrieved from server.
+ * It creates something like a stripped down version of the runtime.charts object.
+ */
+ function buildRequiredDataList() {
+ runtime.dataList = {};
+ // Store an own id, because the property name is subject of reordering,
+ // thus destroying our mapping with runtime.charts <=> runtime.dataList
+ var chartID = 0;
+ $.each(runtime.charts, function (key, chart) {
+ runtime.dataList[chartID] = [];
+ for (var i = 0, l = chart.nodes.length; i < l; i++) {
+ runtime.dataList[chartID][i] = chart.nodes[i].dataPoints;
+ }
+ runtime.charts[key].chartID = chartID;
+ chartID++;
+ });
+ }
+
+ /* Loads the log table data, generates the table and handles the filters */
+ function loadLogStatistics(opts) {
+ var logRequest = null;
+ if (!opts.removeVariables) {
+ opts.removeVariables = false;
+ }
+ if (!opts.limitTypes) {
+ opts.limitTypes = false;
+ }
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strAnalysingLogsTitle
+ });
+ $('#emptyDialog').html(Messages.strAnalysingLogs + '
');
+ var dlgBtns = {
+ [Messages.strCancelRequest]: {
+ text: Messages.strCancelRequest,
+ class: 'btn btn-primary'
+ }
+ };
+ dlgBtns[Messages.strCancelRequest].click = function () {
+ if (logRequest !== null) {
+ logRequest.abort();
+ }
+ $(this).dialog('close');
+ };
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: 'auto',
+ height: 'auto',
+ buttons: dlgBtns
+ });
+ var url = 'index.php?route=/server/status/monitor/slow-log';
+ if (opts.src === 'general') {
+ url = 'index.php?route=/server/status/monitor/general-log';
+ }
+ logRequest = $.post(url, {
+ 'ajax_request': true,
+ 'time_start': Math.round(opts.start / 1000),
+ 'time_end': Math.round(opts.end / 1000),
+ 'removeVariables': opts.removeVariables,
+ 'limitTypes': opts.limitTypes,
+ 'server': CommonParams.get('server')
+ }, function (data) {
+ var logData;
+ var dlgBtns = {
+ [Messages.strClose]: {
+ text: Messages.strClose,
+ class: 'btn btn-primary'
+ }
+ };
+ if (typeof data !== 'undefined' && data.success === true) {
+ logData = data.message;
+ } else {
+ return serverResponseError();
+ }
+ if (logData.rows.length === 0) {
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strNoDataFoundTitle
+ });
+ $('#emptyDialog').html('
' + Messages.strNoDataFound + '
');
+ dlgBtns[Messages.strClose].click = function () {
+ $(this).dialog('close');
+ };
+ $('#emptyDialog').dialog('option', 'buttons', dlgBtns);
+ return;
+ }
+ runtime.logDataCols = buildLogTable(logData, opts.removeVariables);
+
+ /* Show some stats in the dialog */
+ $('#emptyDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strLoadingLogs
+ });
+ $('#emptyDialog').html('
' + Messages.strLogDataLoaded + '
');
+ $.each(logData.sum, function (key, value) {
+ var newKey = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
+ if (newKey === 'Total') {
+ newKey = '
' + newKey + ' ';
+ }
+ $('#emptyDialog').append(newKey + ': ' + value + '
');
+ });
+
+ /* Add filter options if more than a bunch of rows there to filter */
+ if (logData.numRows > 12) {
+ $('#logTable').prepend('
' + ' ' + Messages.strFiltersForLogTable + ' ' + ' ' + ' ' + Messages.strFilterByWordRegexp + ' ' + ' ' + '
' + (logData.numRows > 250 ? ' ' + Messages.strFilter + '
' : '') + ' ' + ' ' + ' ' + Messages.strIgnoreWhereAndGroup + ' ' + '
');
+ $('#noWHEREData').on('change', function () {
+ filterQueries(true);
+ });
+ if (logData.numRows > 250) {
+ $('#startFilterQueryText').on('click', filterQueries);
+ } else {
+ $('#filterQueryText').on('keyup', filterQueries);
+ }
+ }
+ dlgBtns[Messages.strJumpToTable] = {
+ text: Messages.strJumpToTable,
+ class: 'btn btn-secondary',
+ click: function () {
+ $(this).dialog('close');
+ $(document).scrollTop($('#logTable').offset().top);
+ }
+ };
+ $('#emptyDialog').dialog('option', 'buttons', dlgBtns);
+ });
+
+ /**
+ * Handles the actions performed when the user uses any of the
+ * log table filters which are the filter by name and grouping
+ * with ignoring data in WHERE clauses
+ *
+ * @param {boolean} varFilterChange Should be true when the users enabled or disabled
+ * to group queries ignoring data in WHERE clauses
+ */
+ function filterQueries(varFilterChange) {
+ var textFilter;
+ var val = $('#filterQueryText').val();
+ if (val.length === 0) {
+ textFilter = null;
+ } else {
+ try {
+ textFilter = new RegExp(val, 'i');
+ $('#filterQueryText').removeClass('error');
+ } catch (e) {
+ if (e instanceof SyntaxError) {
+ $('#filterQueryText').addClass('error');
+ textFilter = null;
+ }
+ }
+ }
+ var rowSum = 0;
+ var totalSum = 0;
+ var i = 0;
+ var q;
+ var noVars = $('#noWHEREData').prop('checked');
+ var equalsFilter = /([^=]+)=(\d+|(('|"|).*?[^\\])\4((\s+)|$))/gi;
+ var functionFilter = /([a-z0-9_]+)\(.+?\)/gi;
+ var filteredQueries = {};
+ var filteredQueriesLines = {};
+ var hide = false;
+ var rowData;
+ var queryColumnName = runtime.logDataCols[runtime.logDataCols.length - 2];
+ var sumColumnName = runtime.logDataCols[runtime.logDataCols.length - 1];
+ var isSlowLog = opts.src === 'slow';
+ var columnSums = {};
+
+ // For the slow log we have to count many columns (query_time, lock_time, rows_examined, rows_sent, etc.)
+ var countRow = function (query, row) {
+ var cells = row.match(/(.*?)<\/td>/gi);
+ if (!columnSums[query]) {
+ columnSums[query] = [0, 0, 0, 0];
+ }
+
+ // lock_time and query_time and displayed in timespan format
+ columnSums[query][0] += timeToSec(cells[2].replace(/( |<\/td>)/gi, ''));
+ columnSums[query][1] += timeToSec(cells[3].replace(/( |<\/td>)/gi, ''));
+ // rows_examind and rows_sent are just numbers
+ columnSums[query][2] += parseInt(cells[4].replace(/( |<\/td>)/gi, ''), 10);
+ columnSums[query][3] += parseInt(cells[5].replace(/( |<\/td>)/gi, ''), 10);
+ };
+
+ // We just assume the sql text is always in the second last column, and that the total count is right of it
+ $('#logTable').find('table tbody tr td.queryCell').each(function () {
+ var $t = $(this);
+ // If query is a SELECT and user enabled or disabled to group
+ // queries ignoring data in where statements, we
+ // need to re-calculate the sums of each row
+ if (varFilterChange && $t.html().match(/^SELECT/i)) {
+ if (noVars) {
+ // Group on => Sum up identical columns, and hide all but 1
+
+ q = $t.text().replace(equalsFilter, '$1=...$6').trim();
+ q = q.replace(functionFilter, ' $1(...)');
+
+ // Js does not specify a limit on property name length,
+ // so we can abuse it as index :-)
+ if (filteredQueries[q]) {
+ filteredQueries[q] += parseInt($t.next().text(), 10);
+ totalSum += parseInt($t.next().text(), 10);
+ hide = true;
+ } else {
+ filteredQueries[q] = parseInt($t.next().text(), 10);
+ filteredQueriesLines[q] = i;
+ $t.text(q);
+ }
+ if (isSlowLog) {
+ countRow(q, $t.parent().html());
+ }
+ } else {
+ // Group off: Restore original columns
+
+ rowData = $t.parent().data('query');
+ // Restore SQL text
+ $t.text(rowData[queryColumnName]);
+ // Restore total count
+ $t.next().text(rowData[sumColumnName]);
+ // Restore slow log columns
+ if (isSlowLog) {
+ $t.parent().children('td').eq(2).text(rowData.query_time);
+ $t.parent().children('td').eq(3).text(rowData.lock_time);
+ $t.parent().children('td').eq(4).text(rowData.rows_sent);
+ $t.parent().children('td').eq(5).text(rowData.rows_examined);
+ }
+ }
+ }
+
+ // If not required to be hidden, do we need
+ // to hide because of a not matching text filter?
+ if (!hide && textFilter !== null && !textFilter.exec($t.text())) {
+ hide = true;
+ }
+
+ // Now display or hide this column
+ if (hide) {
+ $t.parent().css('display', 'none');
+ } else {
+ totalSum += parseInt($t.next().text(), 10);
+ rowSum++;
+ $t.parent().css('display', '');
+ }
+ hide = false;
+ i++;
+ });
+
+ // We finished summarizing counts => Update count values of all grouped entries
+ if (varFilterChange) {
+ if (noVars) {
+ var numCol;
+ var row;
+ var $table = $('#logTable').find('table tbody');
+ $.each(filteredQueriesLines, function (key, value) {
+ if (filteredQueries[key] <= 1) {
+ return;
+ }
+ row = $table.children('tr').eq(value);
+ numCol = row.children().eq(runtime.logDataCols.length - 1);
+ numCol.text(filteredQueries[key]);
+ if (isSlowLog) {
+ row.children('td').eq(2).text(secToTime(columnSums[key][0]));
+ row.children('td').eq(3).text(secToTime(columnSums[key][1]));
+ row.children('td').eq(4).text(columnSums[key][2]);
+ row.children('td').eq(5).text(columnSums[key][3]);
+ }
+ });
+ }
+ $('#logTable').find('table').trigger('update');
+ setTimeout(function () {
+ $('#logTable').find('table').trigger('sorton', [[[runtime.logDataCols.length - 1, 1]]]);
+ }, 0);
+ }
+
+ // Display some stats at the bottom of the table
+ $('#logTable').find('table tfoot tr').html(' ' + Messages.strSumRows + ' ' + rowSum + '' + Messages.strTotal + ' ' + totalSum + ' ');
+ }
+ }
+
+ /* Turns a timespan (12:12:12) into a number */
+ function timeToSec(timeStr) {
+ var time = timeStr.split(':');
+ return parseInt(time[0], 10) * 3600 + parseInt(time[1], 10) * 60 + parseInt(time[2], 10);
+ }
+
+ /* Turns a number into a timespan (100 into 00:01:40) */
+ function secToTime(timeInt) {
+ var time = timeInt;
+ var hours = Math.floor(time / 3600);
+ time -= hours * 3600;
+ var minutes = Math.floor(time / 60);
+ time -= minutes * 60;
+ if (hours < 10) {
+ hours = '0' + hours;
+ }
+ if (minutes < 10) {
+ minutes = '0' + minutes;
+ }
+ if (time < 10) {
+ time = '0' + time;
+ }
+ return hours + ':' + minutes + ':' + time;
+ }
+
+ /* Constructs the log table out of the retrieved server data */
+ function buildLogTable(data, groupInserts) {
+ var rows = data.rows;
+ var cols = [];
+ var $table = $('');
+ var $tBody;
+ var $tRow;
+ var $tCell;
+ $('#logTable').html($table);
+ var tempPushKey = function (key) {
+ cols.push(key);
+ };
+ var formatValue = function (name, value) {
+ if (name === 'user_host') {
+ return value.replace(/(\[.*?\])+/g, '');
+ }
+ return Functions.escapeHtml(value);
+ };
+ for (var i = 0, l = rows.length; i < l; i++) {
+ if (i === 0) {
+ $.each(rows[0], tempPushKey);
+ $table.append('' + '' + cols.join(' ') + ' ' + ' ');
+ $table.append($tBody = $(' '));
+ }
+ $tBody.append($tRow = $(' '));
+ for (var j = 0, ll = cols.length; j < ll; j++) {
+ // Assuming the query column is the second last
+ if (j === cols.length - 2 && rows[i][cols[j]].match(/^SELECT/i)) {
+ $tRow.append($tCell = $('' + formatValue(cols[j], rows[i][cols[j]]) + ' '));
+ $tCell.on('click', openQueryAnalyzer);
+ } else {
+ $tRow.append('' + formatValue(cols[j], rows[i][cols[j]]) + ' ');
+ }
+ $tRow.data('query', rows[i]);
+ }
+ }
+ $table.append('' + '' + Messages.strSumRows + ' ' + data.numRows + '' + Messages.strTotal + ' ' + data.sum.TOTAL + ' ');
+
+ // Append a tooltip to the count column, if there exist one
+ if ($('#logTable').find('tr').first().find('th').last().text().indexOf('#') > -1) {
+ $('#logTable').find('tr').first().find('th').last().append(' ' + Functions.getImage('b_help', '', {
+ 'class': 'qroupedQueryInfoIcon'
+ }));
+ var tooltipContent = Messages.strCountColumnExplanation;
+ if (groupInserts) {
+ tooltipContent += '' + Messages.strMoreCountColumnExplanation + '
';
+ }
+ Functions.tooltip($('img.qroupedQueryInfoIcon'), 'img', tooltipContent);
+ }
+ $('#logTable').find('table').tablesorter({
+ sortList: [[cols.length - 1, 1]],
+ widgets: ['fast-zebra']
+ });
+ $('#logTable').find('table thead th').append('
');
+ return cols;
+ }
+
+ /* Opens the query analyzer dialog */
+ function openQueryAnalyzer() {
+ var rowData = $(this).parent().data('query');
+ var query = rowData.argument || rowData.sql_text;
+ if (codeMirrorEditor) {
+ // TODO: somehow Functions.sqlPrettyPrint messes up the query, needs be fixed
+ // query = Functions.sqlPrettyPrint(query);
+ codeMirrorEditor.setValue(query);
+ // Codemirror is bugged, it doesn't refresh properly sometimes.
+ // Following lines seem to fix that
+ setTimeout(function () {
+ codeMirrorEditor.refresh();
+ }, 50);
+ } else {
+ $('#sqlquery').val(query);
+ }
+ var profilingChart = null;
+ var dlgBtns = {
+ [Messages.strAnalyzeQuery]: {
+ text: Messages.strAnalyzeQuery,
+ class: 'btn btn-primary'
+ },
+ [Messages.strClose]: {
+ text: Messages.strClose,
+ class: 'btn btn-secondary'
+ }
+ };
+ dlgBtns[Messages.strAnalyzeQuery].click = function () {
+ profilingChart = loadQueryAnalysis(rowData);
+ };
+ dlgBtns[Messages.strClose].click = function () {
+ $(this).dialog('close');
+ };
+ $('#queryAnalyzerDialog').dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ width: 'auto',
+ height: 'auto',
+ resizable: false,
+ buttons: dlgBtns,
+ close: function () {
+ if (profilingChart !== null) {
+ profilingChart.destroy();
+ }
+ $('#queryAnalyzerDialog').find('div.placeHolder').html('');
+ if (codeMirrorEditor) {
+ codeMirrorEditor.setValue('');
+ } else {
+ $('#sqlquery').val('');
+ }
+ }
+ });
+ }
+
+ /* Loads and displays the analyzed query data */
+ function loadQueryAnalysis(rowData) {
+ var db = rowData.db || '';
+ var profilingChart = null;
+ $('#queryAnalyzerDialog').find('div.placeHolder').html(Messages.strAnalyzing + ' ');
+ $.post('index.php?route=/server/status/monitor/query', {
+ 'ajax_request': true,
+ 'query': codeMirrorEditor ? codeMirrorEditor.getValue() : $('#sqlquery').val(),
+ 'database': db,
+ 'server': CommonParams.get('server')
+ }, function (responseData) {
+ var data = responseData;
+ var i;
+ var l;
+ if (typeof data !== 'undefined' && data.success === true) {
+ data = data.message;
+ }
+ if (data.error) {
+ if (data.error.indexOf('1146') !== -1 || data.error.indexOf('1046') !== -1) {
+ data.error = Messages.strServerLogError;
+ }
+ $('#queryAnalyzerDialog').find('div.placeHolder').html('' + data.error + '
');
+ return;
+ }
+ var totalTime = 0;
+ // Float sux, I'll use table :(
+ $('#queryAnalyzerDialog').find('div.placeHolder').html('');
+ var explain = '' + Messages.strExplainOutput + ' ' + $('#explain_docu').html();
+ if (data.explain.length > 1) {
+ explain += ' (';
+ for (i = 0; i < data.explain.length; i++) {
+ if (i > 0) {
+ explain += ', ';
+ }
+ explain += '' + i + ' ';
+ }
+ explain += ')';
+ }
+ explain += '
';
+ var tempExplain = function (key, value) {
+ var newValue = value === null ? 'null' : Functions.escapeHtml(value);
+ if (key === 'type' && newValue.toLowerCase() === 'all') {
+ newValue = '' + newValue + ' ';
+ }
+ if (key === 'Extra') {
+ newValue = newValue.replace(/(using (temporary|filesort))/gi, '$1 ');
+ }
+ explain += key + ': ' + newValue + ' ';
+ };
+ for (i = 0, l = data.explain.length; i < l; i++) {
+ explain += ' 0 ? 'style="display:none;"' : '') + '>';
+ $.each(data.explain[i], tempExplain);
+ explain += '
';
+ }
+ explain += '' + Messages.strAffectedRows + ' ' + data.affectedRows;
+ $('#queryAnalyzerDialog').find('div.placeHolder td.explain').append(explain);
+ $('#queryAnalyzerDialog').find('div.placeHolder a[href*="#showExplain"]').on('click', function () {
+ var id = $(this).attr('href').split('-')[1];
+ $(this).parent().find('div[class*="explain"]').hide();
+ $(this).parent().find('div[class*="explain-' + id + '"]').show();
+ });
+ if (data.profiling) {
+ var chartData = [];
+ var numberTable = '
' + Messages.strStatus + ' ' + Messages.strTime + ' ';
+ var duration;
+ var otherTime = 0;
+ for (i = 0, l = data.profiling.length; i < l; i++) {
+ duration = parseFloat(data.profiling[i].duration);
+ totalTime += duration;
+ numberTable += '' + data.profiling[i].state + ' ' + Functions.prettyProfilingNum(duration, 2) + ' ';
+ }
+
+ // Only put those values in the pie which are > 2%
+ for (i = 0, l = data.profiling.length; i < l; i++) {
+ duration = parseFloat(data.profiling[i].duration);
+ if (duration / totalTime > 0.02) {
+ chartData.push([Functions.prettyProfilingNum(duration, 2) + ' ' + data.profiling[i].state, duration]);
+ } else {
+ otherTime += duration;
+ }
+ }
+ if (otherTime > 0) {
+ chartData.push([Functions.prettyProfilingNum(otherTime, 2) + ' ' + Messages.strOther, otherTime]);
+ }
+ numberTable += '' + Messages.strTotalTime + ' ' + Functions.prettyProfilingNum(totalTime, 2) + ' ';
+ numberTable += '
';
+ $('#queryAnalyzerDialog').find('div.placeHolder td.chart').append('' + Messages.strProfilingResults + ' ' + $('#profiling_docu').html() + ' ' + '(' + Messages.strTable + ' , ' + Messages.strChart + ' ) ' + numberTable + '
');
+ $('#queryAnalyzerDialog').find('div.placeHolder a[href="#showNums"]').on('click', function () {
+ $('#queryAnalyzerDialog').find('#queryProfiling').hide();
+ $('#queryAnalyzerDialog').find('table.queryNums').show();
+ return false;
+ });
+ $('#queryAnalyzerDialog').find('div.placeHolder a[href="#showChart"]').on('click', function () {
+ $('#queryAnalyzerDialog').find('#queryProfiling').show();
+ $('#queryAnalyzerDialog').find('table.queryNums').hide();
+ return false;
+ });
+ profilingChart = Functions.createProfilingChart('queryProfiling', chartData);
+ }
+ });
+ return profilingChart;
+ }
+
+ /* Saves the monitor to localstorage */
+ function saveMonitor() {
+ var gridCopy = {};
+ $.each(runtime.charts, function (key, elem) {
+ gridCopy[key] = {};
+ gridCopy[key].nodes = elem.nodes;
+ gridCopy[key].settings = elem.settings;
+ gridCopy[key].title = elem.title;
+ gridCopy[key].series = elem.series;
+ gridCopy[key].maxYLabel = elem.maxYLabel;
+ });
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.monitorCharts = JSON.stringify(gridCopy);
+ window.localStorage.monitorSettings = JSON.stringify(monitorSettings);
+ window.localStorage.monitorVersion = monitorProtocolVersion;
+ }
+ $('a[href="#clearMonitorConfig"]').show();
+ }
+});
+
+// Run the monitor once loaded
+AJAX.registerOnload('server/status/monitor.js', function () {
+ $('a[href="#pauseCharts"]').trigger('click');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/processes.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/processes.js
new file mode 100644
index 000000000..af4b6fd26
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/processes.js
@@ -0,0 +1,182 @@
+/**
+ * Server Status Processes
+ *
+ * @package PhpMyAdmin
+ */
+
+// object to store process list state information
+var processList = {
+ // denotes whether auto refresh is on or off
+ autoRefresh: false,
+ // stores the GET request which refresh process list
+ refreshRequest: null,
+ // stores the timeout id returned by setTimeout
+ refreshTimeout: null,
+ // the refresh interval in seconds
+ refreshInterval: null,
+ // the refresh URL (required to save last used option)
+ // i.e. full or sorting url
+ refreshUrl: null,
+ /**
+ * Handles killing of a process
+ *
+ * @return {void}
+ */
+ init: function () {
+ processList.setRefreshLabel();
+ if (processList.refreshUrl === null) {
+ processList.refreshUrl = 'index.php?route=/server/status/processes/refresh';
+ }
+ if (processList.refreshInterval === null) {
+ processList.refreshInterval = $('#id_refreshRate').val();
+ } else {
+ $('#id_refreshRate').val(processList.refreshInterval);
+ }
+ },
+ /**
+ * Handles killing of a process
+ *
+ * @param {object} event the event object
+ *
+ * @return {void}
+ */
+ killProcessHandler: function (event) {
+ event.preventDefault();
+ var argSep = CommonParams.get('arg_separator');
+ var params = $(this).getPostData();
+ params += argSep + 'ajax_request=1' + argSep + 'server=' + CommonParams.get('server');
+ // Get row element of the process to be killed.
+ var $tr = $(this).closest('tr');
+ $.post($(this).attr('href'), params, function (data) {
+ // Check if process was killed or not.
+ if (data.hasOwnProperty('success') && data.success) {
+ // remove the row of killed process.
+ $tr.remove();
+ // As we just removed a row, reapply odd-even classes
+ // to keep table stripes consistent
+ var $tableProcessListTr = $('#tableprocesslist').find('> tbody > tr');
+ $tableProcessListTr.each(function (index) {
+ if (index >= 0 && index % 2 === 0) {
+ $(this).removeClass('odd').addClass('even');
+ } else if (index >= 0 && index % 2 !== 0) {
+ $(this).removeClass('even').addClass('odd');
+ }
+ });
+ // Show process killed message
+ Functions.ajaxShowMessage(data.message, false);
+ } else {
+ // Show process error message
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }, 'json');
+ },
+ /**
+ * Handles Auto Refreshing
+ * @return {void}
+ */
+ refresh: function () {
+ // abort any previous pending requests
+ // this is necessary, it may go into
+ // multiple loops causing unnecessary
+ // requests even after leaving the page.
+ processList.abortRefresh();
+ // if auto refresh is enabled
+ if (processList.autoRefresh) {
+ // Only fetch the table contents
+ processList.refreshUrl = 'index.php?route=/server/status/processes/refresh';
+ var interval = parseInt(processList.refreshInterval, 10) * 1000;
+ var urlParams = processList.getUrlParams();
+ processList.refreshRequest = $.post(processList.refreshUrl, urlParams, function (data) {
+ if (data.hasOwnProperty('success') && data.success) {
+ var $newTable = $(data.message);
+ $('#tableprocesslist').html($newTable.html());
+ Functions.highlightSql($('#tableprocesslist'));
+ }
+ processList.refreshTimeout = setTimeout(processList.refresh, interval);
+ });
+ }
+ },
+ /**
+ * Stop current request and clears timeout
+ *
+ * @return {void}
+ */
+ abortRefresh: function () {
+ if (processList.refreshRequest !== null) {
+ processList.refreshRequest.abort();
+ processList.refreshRequest = null;
+ }
+ clearTimeout(processList.refreshTimeout);
+ },
+ /**
+ * Set label of refresh button
+ * change between play & pause
+ *
+ * @return {void}
+ */
+ setRefreshLabel: function () {
+ var img = 'play';
+ var label = Messages.strStartRefresh;
+ if (processList.autoRefresh) {
+ img = 'pause';
+ label = Messages.strStopRefresh;
+ processList.refresh();
+ }
+ $('a#toggleRefresh').html(Functions.getImage(img) + Functions.escapeHtml(label));
+ },
+ /**
+ * Return the Url Parameters
+ * for autorefresh request,
+ * includes showExecuting if the filter is checked
+ *
+ * @return {object} urlParams - url parameters with autoRefresh request
+ */
+ getUrlParams: function () {
+ var urlParams = {
+ 'server': CommonParams.get('server'),
+ 'ajax_request': true,
+ 'refresh': true,
+ 'full': $('input[name="full"]').val(),
+ 'order_by_field': $('input[name="order_by_field"]').val(),
+ 'column_name': $('input[name="column_name"]').val(),
+ 'sort_order': $('input[name="sort_order"]').val()
+ };
+ if ($('#showExecuting').is(':checked')) {
+ urlParams.showExecuting = true;
+ return urlParams;
+ }
+ return urlParams;
+ }
+};
+AJAX.registerOnload('server/status/processes.js', function () {
+ processList.init();
+ // Bind event handler for kill_process
+ $('#tableprocesslist').on('click', 'a.kill_process', processList.killProcessHandler);
+ // Bind event handler for toggling refresh of process list
+ $('a#toggleRefresh').on('click', function (event) {
+ event.preventDefault();
+ processList.autoRefresh = !processList.autoRefresh;
+ processList.setRefreshLabel();
+ });
+ // Bind event handler for change in refresh rate
+ $('#id_refreshRate').on('change', function () {
+ processList.refreshInterval = $(this).val();
+ processList.refresh();
+ });
+ // Bind event handler for table header links
+ $('#tableprocesslist').on('click', 'thead a', function () {
+ processList.refreshUrl = $(this).attr('href');
+ });
+});
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/status/processes.js', function () {
+ $('#tableprocesslist').off('click', 'a.kill_process');
+ $('a#toggleRefresh').off('click');
+ $('#id_refreshRate').off('change');
+ $('#tableprocesslist').off('click', 'thead a');
+ // stop refreshing further
+ processList.abortRefresh();
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/queries.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/queries.js
new file mode 100644
index 000000000..4e275f984
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/queries.js
@@ -0,0 +1,37 @@
+/**
+ * @fileoverview Javascript functions used in server status query page
+ * @name Server Status Query
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ */
+
+/* global initTableSorter */ // js/server/status/sorter.js
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/status/queries.js', function () {
+ if (document.getElementById('serverstatusquerieschart') !== null) {
+ var queryPieChart = $('#serverstatusquerieschart').data('queryPieChart');
+ if (queryPieChart) {
+ queryPieChart.destroy();
+ }
+ }
+});
+AJAX.registerOnload('server/status/queries.js', function () {
+ // Build query statistics chart
+ var cdata = [];
+ try {
+ if (document.getElementById('serverstatusquerieschart') !== null) {
+ $.each($('#serverstatusquerieschart').data('chart'), function (key, value) {
+ cdata.push([key, parseInt(value, 10)]);
+ });
+ $('#serverstatusquerieschart').data('queryPieChart', Functions.createProfilingChart('serverstatusquerieschart', cdata));
+ }
+ } catch (exception) {
+ // Could not load chart, no big deal...
+ }
+ initTableSorter('statustabs_queries');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/sorter.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/sorter.js
new file mode 100644
index 000000000..d3320cf21
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/sorter.js
@@ -0,0 +1,67 @@
+// TODO: tablesorter shouldn't sort already sorted columns
+// eslint-disable-next-line no-unused-vars
+function initTableSorter(tabid) {
+ var $table;
+ var opts;
+ switch (tabid) {
+ case 'statustabs_queries':
+ $table = $('#serverStatusQueriesDetails');
+ opts = {
+ sortList: [[3, 1]],
+ headers: {
+ 1: {
+ sorter: 'fancyNumber'
+ },
+ 2: {
+ sorter: 'fancyNumber'
+ }
+ }
+ };
+ break;
+ }
+ $table.tablesorter(opts);
+ $table.find('tr').first().find('th').append('
');
+}
+$(function () {
+ $.tablesorter.addParser({
+ id: 'fancyNumber',
+ is: function (s) {
+ return /^[0-9]?[0-9,\\.]*\s?(k|M|G|T|%)?$/.test(s);
+ },
+ format: function (s) {
+ var num = jQuery.tablesorter.formatFloat(s.replace(Messages.strThousandsSeparator, '').replace(Messages.strDecimalSeparator, '.'));
+ var factor = 1;
+ switch (s.charAt(s.length - 1)) {
+ case '%':
+ factor = -2;
+ break;
+ // Todo: Complete this list (as well as in the regexp a few lines up)
+ case 'k':
+ factor = 3;
+ break;
+ case 'M':
+ factor = 6;
+ break;
+ case 'G':
+ factor = 9;
+ break;
+ case 'T':
+ factor = 12;
+ break;
+ }
+ return num * Math.pow(10, factor);
+ },
+ type: 'numeric'
+ });
+ $.tablesorter.addParser({
+ id: 'withinSpanNumber',
+ is: function (s) {
+ return /(.*)?<\/span>/);
+ return res && res.length >= 3 ? res[2] : 0;
+ },
+ type: 'numeric'
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/variables.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/variables.js
new file mode 100644
index 000000000..fcb31543c
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/status/variables.js
@@ -0,0 +1,89 @@
+/**
+ *
+ *
+ * @package PhpMyAdmin
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/status/variables.js', function () {
+ $('#filterAlert').off('change');
+ $('#filterText').off('keyup');
+ $('#filterCategory').off('change');
+ $('#dontFormat').off('change');
+});
+AJAX.registerOnload('server/status/variables.js', function () {
+ // Filters for status variables
+ var textFilter = null;
+ var alertFilter = $('#filterAlert').prop('checked');
+ var categoryFilter = $('#filterCategory').find(':selected').val();
+ var text = ''; // Holds filter text
+
+ /* 3 Filtering functions */
+ $('#filterAlert').on('change', function () {
+ alertFilter = this.checked;
+ filterVariables();
+ });
+ $('#filterCategory').on('change', function () {
+ categoryFilter = $(this).val();
+ filterVariables();
+ });
+ $('#dontFormat').on('change', function () {
+ // Hiding the table while changing values speeds up the process a lot
+ const serverStatusVariables = $('#serverStatusVariables');
+ serverStatusVariables.hide();
+ serverStatusVariables.find('td.value span.original').toggle(this.checked);
+ serverStatusVariables.find('td.value span.formatted').toggle(!this.checked);
+ serverStatusVariables.show();
+ }).trigger('change');
+ $('#filterText').on('keyup', function () {
+ var word = $(this).val().replace(/_/g, ' ');
+ if (word.length === 0 || word.length >= 32768) {
+ textFilter = null;
+ } else {
+ try {
+ textFilter = new RegExp('(^| )' + word, 'i');
+ $(this).removeClass('error');
+ } catch (e) {
+ if (e instanceof SyntaxError) {
+ $(this).addClass('error');
+ textFilter = null;
+ }
+ }
+ }
+ text = word;
+ filterVariables();
+ }).trigger('keyup');
+
+ /* Filters the status variables by name/category/alert in the variables tab */
+ function filterVariables() {
+ var usefulLinks = 0;
+ var section = text;
+ if (categoryFilter.length > 0) {
+ section = categoryFilter;
+ }
+ if (section.length > 1) {
+ $('#linkSuggestions').find('span').each(function () {
+ if ($(this).attr('class').indexOf('status_' + section) !== -1) {
+ usefulLinks++;
+ $(this).css('display', '');
+ } else {
+ $(this).css('display', 'none');
+ }
+ });
+ }
+ if (usefulLinks > 0) {
+ $('#linkSuggestions').css('display', '');
+ } else {
+ $('#linkSuggestions').css('display', 'none');
+ }
+ $('#serverStatusVariables').find('th.name').each(function () {
+ if ((textFilter === null || textFilter.exec($(this).text())) && (!alertFilter || $(this).next().find('span.text-danger').length > 0) && (categoryFilter.length === 0 || $(this).parent().hasClass('s_' + categoryFilter))) {
+ $(this).parent().css('display', '');
+ } else {
+ $(this).parent().css('display', 'none');
+ }
+ });
+ }
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/user_groups.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/user_groups.js
new file mode 100644
index 000000000..28677d8d4
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/user_groups.js
@@ -0,0 +1,35 @@
+/**
+ * @fileoverview Javascript functions used in server user groups page
+ * @name Server User Groups
+ *
+ * @requires jQuery
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/user_groups.js', function () {
+ $('#deleteUserGroupModal').off('show.bs.modal');
+});
+
+/**
+ * Bind event handlers
+ */
+AJAX.registerOnload('server/user_groups.js', function () {
+ const deleteUserGroupModal = $('#deleteUserGroupModal');
+ deleteUserGroupModal.on('show.bs.modal', function (event) {
+ const userGroupName = $(event.relatedTarget).data('user-group');
+ this.querySelector('.modal-body').innerText = Functions.sprintf(Messages.strDropUserGroupWarning, Functions.escapeHtml(userGroupName));
+ });
+ deleteUserGroupModal.on('shown.bs.modal', function (event) {
+ const userGroupName = $(event.relatedTarget).data('user-group');
+ $('#deleteUserGroupConfirm').on('click', function () {
+ $.post('index.php?route=/server/user-groups', {
+ 'deleteUserGroup': true,
+ 'userGroup': userGroupName,
+ 'ajax_request': true
+ }, AJAX.responseHandler);
+ $('#deleteUserGroupModal').modal('hide');
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/variables.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/variables.js
new file mode 100644
index 000000000..d6abb16ce
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/server/variables.js
@@ -0,0 +1,98 @@
+/**
+ * @fileoverview Javascript functions used in server variables page
+ * @name Server Replication
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ */
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('server/variables.js', function () {
+ $(document).off('click', 'a.editLink');
+ $('#serverVariables').find('.var-name').find('a img').remove();
+});
+AJAX.registerOnload('server/variables.js', function () {
+ var $saveLink = $('a.saveLink');
+ var $cancelLink = $('a.cancelLink');
+ $('#serverVariables').find('.var-name').find('a').append($('#docImage').clone().css('display', 'inline-block'));
+
+ /* Launches the variable editor */
+ $(document).on('click', 'a.editLink', function (event) {
+ event.preventDefault();
+ editVariable(this);
+ });
+
+ /* Allows the user to edit a server variable */
+ function editVariable(link) {
+ var $link = $(link);
+ var $cell = $link.parent();
+ var $valueCell = $link.parents('.var-row').find('.var-value');
+ var varName = $link.data('variable');
+ var $mySaveLink = $saveLink.clone().css('display', 'inline-block');
+ var $myCancelLink = $cancelLink.clone().css('display', 'inline-block');
+ var $msgbox = Functions.ajaxShowMessage();
+ var $myEditLink = $cell.find('a.editLink');
+ $cell.addClass('edit'); // variable is being edited
+ $myEditLink.remove(); // remove edit link
+
+ $mySaveLink.on('click', function () {
+ var $msgbox = Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ $.post('index.php?route=/server/variables/set/' + encodeURIComponent(varName), {
+ 'ajax_request': true,
+ 'server': CommonParams.get('server'),
+ 'varValue': $valueCell.find('input').val()
+ }, function (data) {
+ if (data.success) {
+ $valueCell.html(data.variable).data('content', data.variable);
+ Functions.ajaxRemoveMessage($msgbox);
+ } else {
+ if (data.error === '') {
+ Functions.ajaxShowMessage(Messages.strRequestFailed, false);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ $valueCell.html($valueCell.data('content'));
+ }
+ $cell.removeClass('edit').html($myEditLink);
+ });
+ return false;
+ });
+ $myCancelLink.on('click', function () {
+ $valueCell.html($valueCell.data('content'));
+ $cell.removeClass('edit').html($myEditLink);
+ return false;
+ });
+ $.get('index.php?route=/server/variables/get/' + encodeURIComponent(varName), {
+ 'ajax_request': true,
+ 'server': CommonParams.get('server')
+ }, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ var $links = $('
').append($myCancelLink).append(' ').append($mySaveLink);
+ var $editor = $('
', {
+ 'class': 'serverVariableEditor'
+ }).append($('
').append($(' ', {
+ type: 'text',
+ 'class': 'form-control form-control-sm'
+ }).val(data.message)));
+ // Save and replace content
+ $cell.html($links).children().css('display', 'flex');
+ $valueCell.data('content', $valueCell.html()).html($editor).find('input').trigger('focus').on('keydown', function (event) {
+ // Keyboard shortcuts
+ if (event.keyCode === 13) {
+ // Enter key
+ $mySaveLink.trigger('click');
+ } else if (event.keyCode === 27) {
+ // Escape key
+ $myCancelLink.trigger('click');
+ }
+ });
+ Functions.ajaxRemoveMessage($msgbox);
+ } else {
+ $cell.removeClass('edit').html($myEditLink);
+ Functions.ajaxShowMessage(data.error);
+ }
+ });
+ }
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/ajax.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/ajax.js
new file mode 100644
index 000000000..e5e41c344
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/ajax.js
@@ -0,0 +1,10 @@
+/* eslint-disable no-unused-vars */
+/**
+ * Dummy implementation of the ajax page loader
+ */
+var AJAX = {
+ registerOnload: function (idx, func) {
+ $(func);
+ },
+ registerTeardown: function (idx, func) {}
+};
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/scripts.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/scripts.js
new file mode 100644
index 000000000..705184651
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/setup/scripts.js
@@ -0,0 +1,235 @@
+/**
+ * Functions used in Setup configuration forms
+ */
+
+/* global displayErrors, getAllValues, getIdPrefix, validators */ // js/config.js
+
+// show this window in top frame
+if (top !== self) {
+ window.top.location.href = location;
+}
+
+// ------------------------------------------------------------------
+// Messages
+//
+
+$(function () {
+ if (window.location.protocol === 'https:') {
+ $('#no_https').remove();
+ } else {
+ $('#no_https a').on('click', function () {
+ var oldLocation = window.location;
+ window.location.href = 'https:' + oldLocation.href.substring(oldLocation.protocol.length);
+ return false;
+ });
+ }
+ var hiddenMessages = $('.hiddenmessage');
+ if (hiddenMessages.length > 0) {
+ hiddenMessages.hide();
+ var link = $('#show_hidden_messages');
+ link.on('click', function (e) {
+ e.preventDefault();
+ hiddenMessages.show();
+ $(this).remove();
+ });
+ link.html(link.html().replace('#MSG_COUNT', hiddenMessages.length));
+ link.show();
+ }
+});
+
+// set document width
+$(function () {
+ var width = 0;
+ $('ul.tabs li').each(function () {
+ width += $(this).width() + 10;
+ });
+ var contentWidth = width;
+ width += 250;
+ $('body').css('min-width', width);
+ $('.tabs_contents').css('min-width', contentWidth);
+});
+
+//
+// END: Messages
+// ------------------------------------------------------------------
+
+// ------------------------------------------------------------------
+// Form validation and field operations
+//
+
+/**
+ * Calls server-side validation procedures
+ *
+ * @param {Element} parent input field in or
+ * @param {String} id validator id
+ * @param {object} values values hash {element1_id: value, ...}
+ *
+ * @return {bool|void}
+ */
+function ajaxValidate(parent, id, values) {
+ var $parent = $(parent);
+ // ensure that parent is a fieldset
+ if ($parent.attr('tagName') !== 'FIELDSET') {
+ $parent = $parent.closest('fieldset');
+ if ($parent.length === 0) {
+ return false;
+ }
+ }
+ if ($parent.data('ajax') !== null) {
+ $parent.data('ajax').abort();
+ }
+ $parent.data('ajax', $.ajax({
+ url: 'validate.php',
+ cache: false,
+ type: 'POST',
+ data: {
+ token: $parent.closest('form').find('input[name=token]').val(),
+ id: id,
+ values: JSON.stringify(values)
+ },
+ success: function (response) {
+ if (response === null) {
+ return;
+ }
+ var error = {};
+ if (typeof response !== 'object') {
+ error[$parent.id] = [response];
+ } else if (typeof response.error !== 'undefined') {
+ error[$parent.id] = [response.error];
+ } else {
+ for (var key in response) {
+ var value = response[key];
+ error[key] = Array.isArray(value) ? value : [value];
+ }
+ }
+ displayErrors(error);
+ },
+ complete: function () {
+ $parent.removeData('ajax');
+ }
+ }));
+ return true;
+}
+
+/**
+ * Automatic form submission on change.
+ */
+$(document).on('change', '.autosubmit', function (e) {
+ e.target.form.submit();
+});
+$.extend(true, validators, {
+ // field validators
+ field: {
+ /**
+ * hide_db field
+ *
+ * @param {boolean} isKeyUp
+ *
+ * @return {true}
+ */
+ hide_db: function (isKeyUp) {
+ // eslint-disable-line camelcase
+ if (!isKeyUp && this.value !== '') {
+ var data = {};
+ data[this.id] = this.value;
+ ajaxValidate(this, 'Servers/1/hide_db', data);
+ }
+ return true;
+ },
+ /**
+ * TrustedProxies field
+ *
+ * @param {boolean} isKeyUp
+ *
+ * @return {true}
+ */
+ TrustedProxies: function (isKeyUp) {
+ if (!isKeyUp && this.value !== '') {
+ var data = {};
+ data[this.id] = this.value;
+ ajaxValidate(this, 'TrustedProxies', data);
+ }
+ return true;
+ }
+ },
+ // fieldset validators
+ fieldset: {
+ /**
+ * Validates Server fieldset
+ *
+ * @param {boolean} isKeyUp
+ *
+ * @return {true}
+ */
+ Server: function (isKeyUp) {
+ if (!isKeyUp) {
+ ajaxValidate(this, 'Server', getAllValues());
+ }
+ return true;
+ },
+ /**
+ * Validates Server_login_options fieldset
+ *
+ * @param {boolean} isKeyUp
+ *
+ * @return {true}
+ */
+ Server_login_options: function (isKeyUp) {
+ // eslint-disable-line camelcase
+ return validators.fieldset.Server.apply(this, [isKeyUp]);
+ },
+ /**
+ * Validates Server_pmadb fieldset
+ *
+ * @param {boolean} isKeyUp
+ *
+ * @return {true}
+ */
+ Server_pmadb: function (isKeyUp) {
+ // eslint-disable-line camelcase
+ if (isKeyUp) {
+ return true;
+ }
+ var prefix = getIdPrefix($(this).find('input'));
+ if ($('#' + prefix + 'pmadb').val() !== '') {
+ ajaxValidate(this, 'Server_pmadb', getAllValues());
+ }
+ return true;
+ }
+ }
+});
+
+//
+// END: Form validation and field operations
+// ------------------------------------------------------------------
+
+// ------------------------------------------------------------------
+// User preferences allow/disallow UI
+//
+
+$(function () {
+ $('.userprefs-allow').on('click', function (e) {
+ if (this !== e.target) {
+ return;
+ }
+ var el = $(this).find('input');
+ if (el.prop('disabled')) {
+ return;
+ }
+ el.prop('checked', !el.prop('checked'));
+ });
+});
+
+//
+// END: User preferences allow/disallow UI
+// ------------------------------------------------------------------
+
+$(function () {
+ $('.delete-server').on('click', function (e) {
+ e.preventDefault();
+ var $this = $(this);
+ $.post($this.attr('href'), $this.attr('data-post'), function () {
+ window.location.replace('index.php');
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/shortcuts_handler.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/shortcuts_handler.js
new file mode 100644
index 000000000..16075f104
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/shortcuts_handler.js
@@ -0,0 +1,111 @@
+/**
+ * @fileoverview Handle shortcuts in various pages
+ * @name Shortcuts handler
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ */
+
+/* global Console */ // js/console.js
+
+/**
+ * Register key events on load
+ */
+$(function () {
+ var databaseOp = false;
+ var tableOp = false;
+ var keyD = 68;
+ var keyT = 84;
+ var keyK = 75;
+ var keyS = 83;
+ var keyF = 70;
+ var keyE = 69;
+ var keyH = 72;
+ var keyC = 67;
+ var keyBackSpace = 8;
+ $(document).on('keyup', function (e) {
+ // is a string but is also a boolean according to https://api.jquery.com/prop/
+ if ($(e.target).prop('contenteditable') === 'true' || $(e.target).prop('contenteditable') === true) {
+ return;
+ }
+ if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' || e.target.nodeName === 'SELECT') {
+ return;
+ }
+ if (e.keyCode === keyD) {
+ setTimeout(function () {
+ databaseOp = false;
+ }, 2000);
+ } else if (e.keyCode === keyT) {
+ setTimeout(function () {
+ tableOp = false;
+ }, 2000);
+ }
+ });
+ $(document).on('keydown', function (e) {
+ // is a string but is also a boolean according to https://api.jquery.com/prop/
+ if ($(e.target).prop('contenteditable') === 'true' || $(e.target).prop('contenteditable') === true) {
+ return;
+ }
+
+ // disable the shortcuts when session has timed out.
+ if ($('#modalOverlay').length > 0) {
+ return;
+ }
+ if (e.ctrlKey && e.altKey && e.keyCode === keyC) {
+ Console.toggle();
+ }
+ if (e.ctrlKey && e.keyCode === keyK) {
+ e.preventDefault();
+ Console.toggle();
+ }
+ if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' || e.target.nodeName === 'SELECT') {
+ return;
+ }
+ var isTable;
+ var isDb;
+ if (e.keyCode === keyD) {
+ databaseOp = true;
+ } else if (e.keyCode === keyK) {
+ e.preventDefault();
+ Console.toggle();
+ } else if (e.keyCode === keyS) {
+ if (databaseOp === true) {
+ isTable = CommonParams.get('table');
+ isDb = CommonParams.get('db');
+ if (isDb && !isTable) {
+ $('.nav-link .ic_b_props').first().trigger('click');
+ }
+ } else if (tableOp === true) {
+ isTable = CommonParams.get('table');
+ isDb = CommonParams.get('db');
+ if (isDb && isTable) {
+ $('.nav-link .ic_b_props').first().trigger('click');
+ }
+ } else {
+ $('#pma_navigation_settings_icon').trigger('click');
+ }
+ } else if (e.keyCode === keyF) {
+ if (databaseOp === true) {
+ isTable = CommonParams.get('table');
+ isDb = CommonParams.get('db');
+ if (isDb && !isTable) {
+ $('.nav-link .ic_b_search').first().trigger('click');
+ }
+ } else if (tableOp === true) {
+ isTable = CommonParams.get('table');
+ isDb = CommonParams.get('db');
+ if (isDb && isTable) {
+ $('.nav-link .ic_b_search').first().trigger('click');
+ }
+ }
+ } else if (e.keyCode === keyT) {
+ tableOp = true;
+ } else if (e.keyCode === keyE) {
+ $('.ic_b_export').first().trigger('click');
+ } else if (e.keyCode === keyBackSpace) {
+ window.history.back();
+ } else if (e.keyCode === keyH) {
+ $('.ic_b_home').first().trigger('click');
+ }
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/sql.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/sql.js
new file mode 100644
index 000000000..9bd6362f9
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/sql.js
@@ -0,0 +1,1007 @@
+/**
+ * @fileoverview functions used wherever an sql query form is used
+ *
+ * @requires jQuery
+ * @requires js/functions.js
+ *
+ * @test-module Sql
+ */
+
+/* global isStorageSupported */ // js/config.js
+/* global codeMirrorEditor */ // js/functions.js
+/* global makeGrid */ // js/makegrid.js
+/* global sqlBoxLocked */ // js/functions.js
+
+var Sql = {};
+
+/**
+ * decode a string URL_encoded
+ *
+ * @param {string} str
+ * @return {string} the URL-decoded string
+ */
+Sql.urlDecode = function (str) {
+ if (typeof str !== 'undefined') {
+ return decodeURIComponent(str.replace(/\+/g, '%20'));
+ }
+};
+
+/**
+ * encode a string URL_decoded
+ *
+ * @param {string} str
+ * @return {string} the URL-encoded string
+ */
+Sql.urlEncode = function (str) {
+ if (typeof str !== 'undefined') {
+ return encodeURIComponent(str).replace(/%20/g, '+');
+ }
+};
+
+/**
+ * Saves SQL query in local storage or cookie
+ *
+ * @param {string} query SQL query
+ * @return {void}
+ */
+Sql.autoSave = function (query) {
+ if (query) {
+ var key = Sql.getAutoSavedKey();
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.setItem(key, query);
+ } else {
+ Cookies.set(key, query);
+ }
+ }
+};
+
+/**
+ * Saves SQL query in local storage or cookie
+ *
+ * @param {string} db database name
+ * @param {string} table table name
+ * @param {string} query SQL query
+ * @return {void}
+ */
+Sql.showThisQuery = function (db, table, query) {
+ var showThisQueryObject = {
+ 'db': db,
+ 'table': table,
+ 'query': query
+ };
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.showThisQuery = 1;
+ window.localStorage.showThisQueryObject = JSON.stringify(showThisQueryObject);
+ } else {
+ Cookies.set('showThisQuery', 1);
+ Cookies.set('showThisQueryObject', JSON.stringify(showThisQueryObject));
+ }
+};
+
+/**
+ * Set query to codemirror if show this query is
+ * checked and query for the db and table pair exists
+ */
+Sql.setShowThisQuery = function () {
+ var db = $('input[name="db"]').val();
+ var table = $('input[name="table"]').val();
+ if (isStorageSupported('localStorage')) {
+ if (window.localStorage.showThisQueryObject !== undefined) {
+ var storedDb = JSON.parse(window.localStorage.showThisQueryObject).db;
+ var storedTable = JSON.parse(window.localStorage.showThisQueryObject).table;
+ var storedQuery = JSON.parse(window.localStorage.showThisQueryObject).query;
+ }
+ if (window.localStorage.showThisQuery !== undefined && window.localStorage.showThisQuery === '1') {
+ $('input[name="show_query"]').prop('checked', true);
+ if (db === storedDb && table === storedTable) {
+ if (codeMirrorEditor) {
+ codeMirrorEditor.setValue(storedQuery);
+ } else if (document.sqlform) {
+ document.sqlform.sql_query.value = storedQuery;
+ }
+ }
+ } else {
+ $('input[name="show_query"]').prop('checked', false);
+ }
+ }
+};
+
+/**
+ * Saves SQL query with sort in local storage or cookie
+ *
+ * @param {string} query SQL query
+ * @return {void}
+ */
+Sql.autoSaveWithSort = function (query) {
+ if (query) {
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.setItem('autoSavedSqlSort', query);
+ } else {
+ Cookies.set('autoSavedSqlSort', query);
+ }
+ }
+};
+
+/**
+ * Clear saved SQL query with sort in local storage or cookie
+ *
+ * @return {void}
+ */
+Sql.clearAutoSavedSort = function () {
+ if (isStorageSupported('localStorage')) {
+ window.localStorage.removeItem('autoSavedSqlSort');
+ } else {
+ Cookies.set('autoSavedSqlSort', '');
+ }
+};
+
+/**
+ * Get the field name for the current field. Required to construct the query
+ * for grid editing
+ *
+ * @param $tableResults enclosing results table
+ * @param $thisField jQuery object that points to the current field's tr
+ *
+ * @return {string}
+ */
+Sql.getFieldName = function ($tableResults, $thisField) {
+ var thisFieldIndex = $thisField.index();
+ // ltr or rtl direction does not impact how the DOM was generated
+ // check if the action column in the left exist
+ var leftActionExist = !$tableResults.find('th').first().hasClass('draggable');
+ // number of column span for checkbox and Actions
+ var leftActionSkip = leftActionExist ? $tableResults.find('th').first().attr('colspan') - 1 : 0;
+
+ // If this column was sorted, the text of the a element contains something
+ // like 1 that is useful to indicate the order in case
+ // of a sort on multiple columns; however, we dont want this as part
+ // of the column name so we strip it ( .clone() to .end() )
+ var fieldName = $tableResults.find('thead').find('th').eq(thisFieldIndex - leftActionSkip).find('a').clone() // clone the element
+ .children() // select all the children
+ .remove() // remove all of them
+ .end() // go back to the selected element
+ .text(); // grab the text
+ // happens when just one row (headings contain no a)
+ if (fieldName === '') {
+ var $heading = $tableResults.find('thead').find('th').eq(thisFieldIndex - leftActionSkip).children('span');
+ // may contain column comment enclosed in a span - detach it temporarily to read the column name
+ var $tempColComment = $heading.children().detach();
+ fieldName = $heading.text();
+ // re-attach the column comment
+ $heading.append($tempColComment);
+ }
+ fieldName = fieldName.trim();
+ return fieldName;
+};
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('sql.js', function () {
+ $(document).off('click', 'a.delete_row.ajax');
+ $(document).off('submit', '.bookmarkQueryForm');
+ $('input#bkm_label').off('input');
+ $(document).off('makegrid', '.sqlqueryresults');
+ $('#togglequerybox').off('click');
+ $(document).off('click', '#button_submit_query');
+ $(document).off('change', '#id_bookmark');
+ $('input[name=\'bookmark_variable\']').off('keypress');
+ $(document).off('submit', '#sqlqueryform.ajax');
+ $(document).off('click', 'input[name=navig].ajax');
+ $(document).off('submit', 'form[name=\'displayOptionsForm\'].ajax');
+ $(document).off('mouseenter', 'th.column_heading.pointer');
+ $(document).off('mouseleave', 'th.column_heading.pointer');
+ $(document).off('click', 'th.column_heading.marker');
+ $(document).off('scroll', window);
+ $(document).off('keyup', '.filter_rows');
+ if (codeMirrorEditor) {
+ codeMirrorEditor.off('change');
+ } else {
+ $('#sqlquery').off('input propertychange');
+ }
+ $('body').off('click', '.navigation .showAllRows');
+ $('body').off('click', 'a.browse_foreign');
+ $('body').off('click', '#simulate_dml');
+ $('body').off('keyup', '#sqlqueryform');
+ $('body').off('click', 'form[name="resultsForm"].ajax button[name="submit_mult"], form[name="resultsForm"].ajax input[name="submit_mult"]');
+ $(document).off('submit', '.maxRowsForm');
+ $(document).off('click', '#view_as');
+ $(document).off('click', '#sqlquery');
+});
+
+/**
+ * @description Ajax scripts for sql and browse pages
+ *
+ * Actions ajaxified here:
+ *
+ * Retrieve results of an SQL query
+ * Paginate the results table
+ * Sort the results table
+ * Change table according to display options
+ * Grid editing of data
+ * Saving a bookmark
+ *
+ *
+ * @name document.ready
+ * @memberOf jQuery
+ */
+AJAX.registerOnload('sql.js', function () {
+ if (codeMirrorEditor || document.sqlform) {
+ Sql.setShowThisQuery();
+ }
+ $(function () {
+ if (codeMirrorEditor) {
+ codeMirrorEditor.on('change', function () {
+ Sql.autoSave(codeMirrorEditor.getValue());
+ });
+ } else {
+ $('#sqlquery').on('input propertychange', function () {
+ Sql.autoSave($('#sqlquery').val());
+ });
+ var useLocalStorageValue = isStorageSupported('localStorage') && typeof window.localStorage.autoSavedSqlSort !== 'undefined';
+ // Save sql query with sort
+ if ($('#RememberSorting') !== undefined && $('#RememberSorting').is(':checked')) {
+ $('select[name="sql_query"]').on('change', function () {
+ Sql.autoSaveWithSort($(this).val());
+ });
+ $('.sortlink').on('click', function () {
+ Sql.clearAutoSavedSort();
+ });
+ } else {
+ Sql.clearAutoSavedSort();
+ }
+ // If sql query with sort for current table is stored, change sort by key select value
+ var sortStoredQuery = useLocalStorageValue ? window.localStorage.autoSavedSqlSort : Cookies.get('autoSavedSqlSort');
+ if (typeof sortStoredQuery !== 'undefined' && sortStoredQuery !== $('select[name="sql_query"]').val() && $('select[name="sql_query"] option[value="' + sortStoredQuery + '"]').length !== 0) {
+ $('select[name="sql_query"]').val(sortStoredQuery).trigger('change');
+ }
+ }
+ });
+
+ // Delete row from SQL results
+ $(document).on('click', 'a.delete_row.ajax', function (e) {
+ e.preventDefault();
+ var question = Functions.sprintf(Messages.strDoYouReally, Functions.escapeHtml($(this).closest('td').find('div').text()));
+ var $link = $(this);
+ $link.confirm(question, $link.attr('href'), function (url) {
+ Functions.ajaxShowMessage();
+ var argsep = CommonParams.get('arg_separator');
+ var params = 'ajax_request=1' + argsep + 'is_js_confirmed=1';
+ var postData = $link.getPostData();
+ if (postData) {
+ params += argsep + postData;
+ }
+ $.post(url, params, function (data) {
+ if (data.success) {
+ Functions.ajaxShowMessage(data.message);
+ $link.closest('tr').remove();
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+ });
+
+ // Ajaxification for 'Bookmark this SQL query'
+ $(document).on('submit', '.bookmarkQueryForm', function (e) {
+ e.preventDefault();
+ Functions.ajaxShowMessage();
+ var argsep = CommonParams.get('arg_separator');
+ $.post($(this).attr('action'), 'ajax_request=1' + argsep + $(this).serialize(), function (data) {
+ if (data.success) {
+ Functions.ajaxShowMessage(data.message);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+
+ /* Hides the bookmarkoptions checkboxes when the bookmark label is empty */
+ $('input#bkm_label').on('input', function () {
+ $('input#id_bkm_all_users, input#id_bkm_replace').parent().toggle($(this).val().length > 0);
+ }).trigger('input');
+
+ /**
+ * Attach Event Handler for 'Copy to clipboard'
+ */
+ $(document).on('click', '#copyToClipBoard', function (event) {
+ event.preventDefault();
+ var textArea = document.createElement('textarea');
+
+ //
+ // *** This styling is an extra step which is likely not required. ***
+ //
+ // Why is it here? To ensure:
+ // 1. the element is able to have focus and selection.
+ // 2. if element was to flash render it has minimal visual impact.
+ // 3. less flakyness with selection and copying which **might** occur if
+ // the textarea element is not visible.
+ //
+ // The likelihood is the element won't even render, not even a flash,
+ // so some of these are just precautions. However in IE the element
+ // is visible whilst the popup box asking the user for permission for
+ // the web page to copy to the clipboard.
+ //
+
+ // Place in top-left corner of screen regardless of scroll position.
+ textArea.style.position = 'fixed';
+ textArea.style.top = 0;
+ textArea.style.left = 0;
+
+ // Ensure it has a small width and height. Setting to 1px / 1em
+ // doesn't work as this gives a negative w/h on some browsers.
+ textArea.style.width = '2em';
+ textArea.style.height = '2em';
+
+ // We don't need padding, reducing the size if it does flash render.
+ textArea.style.padding = 0;
+
+ // Clean up any borders.
+ textArea.style.border = 'none';
+ textArea.style.outline = 'none';
+ textArea.style.boxShadow = 'none';
+
+ // Avoid flash of white box if rendered for any reason.
+ textArea.style.background = 'transparent';
+ textArea.value = '';
+ $('#server-breadcrumb a').each(function () {
+ textArea.value += $(this).data('raw-text') + '/';
+ });
+ textArea.value += '\t\t' + window.location.href;
+ textArea.value += '\n';
+ $('.alert-success').each(function () {
+ textArea.value += $(this).text() + '\n\n';
+ });
+ $('.sql pre').each(function () {
+ textArea.value += $(this).text() + '\n\n';
+ });
+ $('.table_results .column_heading a').each(function () {
+ // Don't copy ordering number text within tag
+ textArea.value += $(this).clone().find('small').remove().end().text() + '\t';
+ });
+ textArea.value += '\n';
+ $('.table_results tbody tr').each(function () {
+ $(this).find('.data span').each(function () {
+ // Extract tag for NULL values before converting to string to not mess up formatting
+ var data = $(this).find('em').length !== 0 ? $(this).find('em')[0] : this;
+ textArea.value += $(data).text() + '\t';
+ });
+ textArea.value += '\n';
+ });
+
+ // eslint-disable-next-line compat/compat
+ document.body.appendChild(textArea);
+ textArea.select();
+ try {
+ document.execCommand('copy');
+ } catch (err) {
+ alert('Sorry! Unable to copy');
+ }
+
+ // eslint-disable-next-line compat/compat
+ document.body.removeChild(textArea);
+ }); // end of Copy to Clipboard action
+
+ /**
+ * Attach the {@link makegrid} function to a custom event, which will be
+ * triggered manually everytime the table of results is reloaded
+ * @memberOf jQuery
+ */
+ $(document).on('makegrid', '.sqlqueryresults', function () {
+ $('.table_results').each(function () {
+ makeGrid(this);
+ });
+ });
+
+ /**
+ * Append the "Show/Hide query box" message to the query input form
+ *
+ * @memberOf jQuery
+ * @name appendToggleSpan
+ */
+ // do not add this link more than once
+ if (!$('#sqlqueryform').find('button').is('#togglequerybox')) {
+ $(' ').html(Messages.strHideQueryBox).appendTo('#sqlqueryform')
+ // initially hidden because at this point, nothing else
+ // appears under the link
+ .hide();
+
+ // Attach the toggling of the query box visibility to a click
+ $('#togglequerybox').on('click', function () {
+ var $link = $(this);
+ $link.siblings().slideToggle('fast');
+ if ($link.text() === Messages.strHideQueryBox) {
+ $link.text(Messages.strShowQueryBox);
+ // cheap trick to add a spacer between the menu tabs
+ // and "Show query box"; feel free to improve!
+ $('#togglequerybox_spacer').remove();
+ $link.before(' ');
+ } else {
+ $link.text(Messages.strHideQueryBox);
+ }
+ // avoid default click action
+ return false;
+ });
+ }
+
+ /**
+ * Event handler for sqlqueryform.ajax button_submit_query
+ *
+ * @memberOf jQuery
+ */
+ $(document).on('click', '#button_submit_query', function () {
+ $('.alert-success,.alert-danger').hide();
+ // hide already existing error or success message
+ var $form = $(this).closest('form');
+ // the Go button related to query submission was clicked,
+ // instead of the one related to Bookmarks, so empty the
+ // id_bookmark selector to avoid misinterpretation in
+ // /import about what needs to be done
+ $form.find('select[name=id_bookmark]').val('');
+ var isShowQuery = $('input[name="show_query"]').is(':checked');
+ if (isShowQuery) {
+ window.localStorage.showThisQuery = '1';
+ var db = $('input[name="db"]').val();
+ var table = $('input[name="table"]').val();
+ var query;
+ if (codeMirrorEditor) {
+ query = codeMirrorEditor.getValue();
+ } else {
+ query = $('#sqlquery').val();
+ }
+ Sql.showThisQuery(db, table, query);
+ } else {
+ window.localStorage.showThisQuery = '0';
+ }
+ });
+
+ /**
+ * Event handler to show appropriate number of variable boxes
+ * based on the bookmarked query
+ */
+ $(document).on('change', '#id_bookmark', function () {
+ var varCount = $(this).find('option:selected').data('varcount');
+ if (typeof varCount === 'undefined') {
+ varCount = 0;
+ }
+ var $varDiv = $('#bookmarkVariables');
+ $varDiv.empty();
+ for (var i = 1; i <= varCount; i++) {
+ $varDiv.append($(''));
+ $varDiv.append($('' + Functions.sprintf(Messages.strBookmarkVariable, i) + ' '));
+ $varDiv.append($(' '));
+ $varDiv.append($('
'));
+ }
+ if (varCount === 0) {
+ $varDiv.parent().hide();
+ } else {
+ $varDiv.parent().show();
+ }
+ });
+
+ /**
+ * Event handler for hitting enter on sqlqueryform bookmark_variable
+ * (the Variable textfield in Bookmarked SQL query section)
+ *
+ * @memberOf jQuery
+ */
+ $('input[name=bookmark_variable]').on('keypress', function (event) {
+ // force the 'Enter Key' to implicitly click the #button_submit_bookmark
+ var keycode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
+ if (keycode === 13) {
+ // keycode for enter key
+ // When you press enter in the sqlqueryform, which
+ // has 2 submit buttons, the default is to run the
+ // #button_submit_query, because of the tabindex
+ // attribute.
+ // This submits #button_submit_bookmark instead,
+ // because when you are in the Bookmarked SQL query
+ // section and hit enter, you expect it to do the
+ // same action as the Go button in that section.
+ $('#button_submit_bookmark').trigger('click');
+ return false;
+ } else {
+ return true;
+ }
+ });
+
+ /**
+ * Ajax Event handler for 'SQL Query Submit'
+ *
+ * @see Functions.ajaxShowMessage()
+ * @memberOf jQuery
+ * @name sqlqueryform_submit
+ */
+ $(document).on('submit', '#sqlqueryform.ajax', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ if (codeMirrorEditor) {
+ $form[0].elements.sql_query.value = codeMirrorEditor.getValue();
+ }
+ if (!Functions.checkSqlQuery($form[0])) {
+ return false;
+ }
+
+ // remove any div containing a previous error message
+ $('.alert-danger').remove();
+ var $msgbox = Functions.ajaxShowMessage();
+ var $sqlqueryresultsouter = $('#sqlqueryresultsouter');
+ Functions.prepareForAjaxRequest($form);
+ var argsep = CommonParams.get('arg_separator');
+ $.post($form.attr('action'), $form.serialize() + argsep + 'ajax_page_request=true', function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ // success happens if the query returns rows or not
+
+ // show a message that stays on screen
+ if (typeof data.action_bookmark !== 'undefined') {
+ // view only
+ if ('1' === data.action_bookmark) {
+ $('#sqlquery').text(data.sql_query);
+ // send to codemirror if possible
+ Functions.setQuery(data.sql_query);
+ }
+ // delete
+ if ('2' === data.action_bookmark) {
+ $('#id_bookmark option[value=\'' + data.id_bookmark + '\']').remove();
+ // if there are no bookmarked queries now (only the empty option),
+ // remove the bookmark section
+ if ($('#id_bookmark option').length === 1) {
+ $('#fieldsetBookmarkOptions').hide();
+ $('#fieldsetBookmarkOptionsFooter').hide();
+ }
+ }
+ }
+ $sqlqueryresultsouter.show().html(data.message);
+ Functions.highlightSql($sqlqueryresultsouter);
+ if (data.menu) {
+ history.replaceState({
+ menu: data.menu
+ }, null);
+ AJAX.handleMenu.replace(data.menu);
+ }
+ if (data.params) {
+ CommonParams.setAll(data.params);
+ }
+ if (typeof data.ajax_reload !== 'undefined') {
+ if (data.ajax_reload.reload) {
+ if (data.ajax_reload.table_name) {
+ CommonParams.set('table', data.ajax_reload.table_name);
+ CommonActions.refreshMain();
+ } else {
+ Navigation.reload();
+ }
+ }
+ } else if (typeof data.reload !== 'undefined') {
+ // this happens if a USE or DROP command was typed
+ CommonActions.setDb(data.db);
+ var url;
+ if (data.db) {
+ if (data.table) {
+ url = 'index.php?route=/table/sql';
+ } else {
+ url = 'index.php?route=/database/sql';
+ }
+ } else {
+ url = 'index.php?route=/server/sql';
+ }
+ CommonActions.refreshMain(url, function () {
+ $('#sqlqueryresultsouter').show().html(data.message);
+ Functions.highlightSql($('#sqlqueryresultsouter'));
+ });
+ }
+ $('.sqlqueryresults').trigger('makegrid');
+ $('#togglequerybox').show();
+ if (typeof data.action_bookmark === 'undefined') {
+ if ($('#sqlqueryform input[name="retain_query_box"]').is(':checked') !== true) {
+ if ($('#togglequerybox').siblings(':visible').length > 0) {
+ $('#togglequerybox').trigger('click');
+ }
+ }
+ }
+ } else if (typeof data !== 'undefined' && data.success === false) {
+ // show an error message that stays on screen
+ $sqlqueryresultsouter.show().html(data.error);
+ $('html, body').animate({
+ scrollTop: $(document).height()
+ }, 200);
+ }
+ Functions.ajaxRemoveMessage($msgbox);
+ }); // end $.post()
+ }); // end SQL Query submit
+
+ /**
+ * Ajax Event handler for the display options
+ * @memberOf jQuery
+ * @name displayOptionsForm_submit
+ */
+ $(document).on('submit', 'form[name=\'displayOptionsForm\'].ajax', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ var $msgbox = Functions.ajaxShowMessage();
+ var argsep = CommonParams.get('arg_separator');
+ $.post($form.attr('action'), $form.serialize() + argsep + 'ajax_request=true', function (data) {
+ Functions.ajaxRemoveMessage($msgbox);
+ var $sqlqueryresults = $form.parents('.sqlqueryresults');
+ $sqlqueryresults.html(data.message).trigger('makegrid');
+ Functions.highlightSql($sqlqueryresults);
+ }); // end $.post()
+ }); // end displayOptionsForm handler
+
+ // Filter row handling. --STARTS--
+ $(document).on('keyup', '.filter_rows', function () {
+ var uniqueId = $(this).data('for');
+ var $targetTable = $('.table_results[data-uniqueId=\'' + uniqueId + '\']');
+ var $headerCells = $targetTable.find('th[data-column]');
+ var targetColumns = [];
+
+ // To handle colspan=4, in case of edit, copy, etc options (Table row links). Add 3 dummy elements - only when the Table row links are NOT on the "Right"
+ var rowLinksLocation = $targetTable.find('thead > tr > th').first();
+ var dummyTh = rowLinksLocation[0].getAttribute('colspan') !== null ? ' ' : ''; // Selecting columns that will be considered for filtering and searching.
+
+ // Selecting columns that will be considered for filtering and searching.
+ $headerCells.each(function () {
+ targetColumns.push($(this).text().trim());
+ });
+ var phrase = $(this).val();
+ // Set same value to both Filter rows fields.
+ $('.filter_rows[data-for=\'' + uniqueId + '\']').not(this).val(phrase);
+ // Handle colspan.
+ $targetTable.find('thead > tr').prepend(dummyTh);
+ $.uiTableFilter($targetTable, phrase, targetColumns);
+ $targetTable.find('th.dummy_th').remove();
+ });
+ // Filter row handling. --ENDS--
+
+ // Prompt to confirm on Show All
+ $('body').on('click', '.navigation .showAllRows', function (e) {
+ e.preventDefault();
+ var $form = $(this).parents('form');
+ Sql.submitShowAllForm = function () {
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ Functions.ajaxShowMessage();
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ };
+ if (!$(this).is(':checked')) {
+ // already showing all rows
+ Sql.submitShowAllForm();
+ } else {
+ $form.confirm(Messages.strShowAllRowsWarning, $form.attr('action'), function () {
+ Sql.submitShowAllForm();
+ });
+ }
+ });
+ $('body').on('keyup', '#sqlqueryform', function () {
+ Functions.handleSimulateQueryButton();
+ });
+
+ /**
+ * Ajax event handler for 'Simulate DML'.
+ */
+ $('body').on('click', '#simulate_dml', function () {
+ var $form = $('#sqlqueryform');
+ var query = '';
+ var delimiter = $('#id_sql_delimiter').val();
+ var dbName = $form.find('input[name="db"]').val();
+ if (codeMirrorEditor) {
+ query = codeMirrorEditor.getValue();
+ } else {
+ query = $('#sqlquery').val();
+ }
+ if (query.length === 0) {
+ alert(Messages.strFormEmpty);
+ $('#sqlquery').trigger('focus');
+ return false;
+ }
+ var $msgbox = Functions.ajaxShowMessage();
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/import/simulate-dml',
+ data: {
+ 'server': CommonParams.get('server'),
+ 'db': dbName,
+ 'ajax_request': '1',
+ 'sql_query': query,
+ 'sql_delimiter': delimiter
+ },
+ success: function (response) {
+ Functions.ajaxRemoveMessage($msgbox);
+ if (response.success) {
+ var dialogContent = '';
+ if (response.sql_data) {
+ var len = response.sql_data.length;
+ for (var i = 0; i < len; i++) {
+ dialogContent += '
' + Messages.strSQLQuery + ' ' + response.sql_data[i].sql_query + Messages.strMatchedRows + '
' + response.sql_data[i].matched_rows + ' ';
+ if (i < len - 1) {
+ dialogContent += '
';
+ }
+ }
+ } else {
+ dialogContent += response.message;
+ }
+ dialogContent += '
';
+ var $dialogContent = $(dialogContent);
+ var modal = $('#simulateDmlModal');
+ modal.modal('show');
+ modal.find('.modal-body').first().html($dialogContent);
+ modal.on('shown.bs.modal', function () {
+ Functions.highlightSql(modal);
+ });
+ } else {
+ Functions.ajaxShowMessage(response.error);
+ }
+ },
+ error: function () {
+ Functions.ajaxShowMessage(Messages.strErrorProcessingRequest);
+ }
+ });
+ });
+
+ /**
+ * Handles multi submits of results browsing page such as edit, delete and export
+ */
+ $('body').on('click', 'form[name="resultsForm"].ajax button[name="submit_mult"], form[name="resultsForm"].ajax input[name="submit_mult"]', function (e) {
+ e.preventDefault();
+ var $button = $(this);
+ var action = $button.val();
+ var $form = $button.closest('form');
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true' + argsep;
+ Functions.ajaxShowMessage();
+ AJAX.source = $form;
+ var url;
+ if (action === 'edit') {
+ submitData = submitData + argsep + 'default_action=update';
+ url = 'index.php?route=/table/change/rows';
+ } else if (action === 'copy') {
+ submitData = submitData + argsep + 'default_action=insert';
+ url = 'index.php?route=/table/change/rows';
+ } else if (action === 'export') {
+ url = 'index.php?route=/table/export/rows';
+ } else if (action === 'delete') {
+ url = 'index.php?route=/table/delete/confirm';
+ } else {
+ return;
+ }
+ $.post(url, submitData, AJAX.responseHandler);
+ });
+ $(document).on('submit', '.maxRowsForm', function () {
+ var unlimNumRows = $(this).find('input[name="unlim_num_rows"]').val();
+ var maxRowsCheck = Functions.checkFormElementInRange(this, 'session_max_rows', Messages.strNotValidRowNumber, 1);
+ var posCheck = Functions.checkFormElementInRange(this, 'pos', Messages.strNotValidRowNumber, 0, unlimNumRows > 0 ? unlimNumRows - 1 : null);
+ return maxRowsCheck && posCheck;
+ });
+ $('#insertBtn').on('click', function () {
+ Functions.insertValueQuery();
+ });
+ $('#view_as').on('click', function () {
+ Functions.selectContent(this, sqlBoxLocked, true);
+ });
+ $('#sqlquery').on('click', function () {
+ if ($(this).data('textarea-auto-select') === true) {
+ Functions.selectContent(this, sqlBoxLocked, true);
+ }
+ });
+}); // end $()
+
+/**
+ * Starting from some th, change the class of all td under it.
+ * If isAddClass is specified, it will be used to determine whether to add or remove the class.
+ *
+ * @param $thisTh
+ * @param {string} newClass
+ * @param isAddClass
+ */
+Sql.changeClassForColumn = function ($thisTh, newClass, isAddClass) {
+ // index 0 is the th containing the big T
+ var thIndex = $thisTh.index();
+ var hasBigT = $thisTh.closest('tr').children().first().hasClass('column_action');
+ // .eq() is zero-based
+ if (hasBigT) {
+ thIndex--;
+ }
+ var $table = $thisTh.parents('.table_results');
+ if (!$table.length) {
+ $table = $thisTh.parents('table').siblings('.table_results');
+ }
+ var $tds = $table.find('tbody tr').find('td.data').eq(thIndex);
+ if (isAddClass === undefined) {
+ $tds.toggleClass(newClass);
+ } else {
+ $tds.toggleClass(newClass, isAddClass);
+ }
+};
+
+/**
+ * Handles browse foreign values modal dialog
+ *
+ * @param {object} $thisA reference to the browse foreign value link
+ */
+Sql.browseForeignDialog = function ($thisA) {
+ var formId = '#browse_foreign_form';
+ var showAllId = '#foreign_showAll';
+ var tableId = '#browse_foreign_table';
+ var filterId = '#input_foreign_filter';
+ var $dialog = null;
+ var argSep = CommonParams.get('arg_separator');
+ var params = $thisA.getPostData();
+ params += argSep + 'ajax_request=true';
+ $.post($thisA.attr('href'), params, function (data) {
+ // Creates browse foreign value dialog
+ $dialog = $('').append(data.message).dialog({
+ classes: {
+ 'ui-dialog-titlebar-close': 'btn-close'
+ },
+ title: Messages.strBrowseForeignValues,
+ width: Math.min($(window).width() - 100, 700),
+ maxHeight: $(window).height() - 100,
+ dialogClass: 'browse_foreign_modal',
+ close: function () {
+ // remove event handlers attached to elements related to dialog
+ $(tableId).off('click', 'td a.foreign_value');
+ $(formId).off('click', showAllId);
+ $(formId).off('submit');
+ // remove dialog itself
+ $(this).remove();
+ },
+ modal: true
+ });
+ }).done(function () {
+ var showAll = false;
+ $(tableId).on('click', 'td a.foreign_value', function (e) {
+ e.preventDefault();
+ var $input = $thisA.prev('input[type=text]');
+ // Check if input exists or get CEdit edit_box
+ if ($input.length === 0) {
+ $input = $thisA.closest('.edit_area').prev('.edit_box');
+ }
+ // Set selected value as input value
+ $input.val($(this).data('key'));
+ // Unchecks the Ignore checkbox for the current row
+ $input.trigger('change');
+ $dialog.dialog('close');
+ });
+ $(formId).on('click', showAllId, function () {
+ showAll = true;
+ });
+ $(formId).on('submit', function (e) {
+ e.preventDefault();
+ // if filter value is not equal to old value
+ // then reset page number to 1
+ if ($(filterId).val() !== $(filterId).data('old')) {
+ $(formId).find('select[name=pos]').val('0');
+ }
+ var postParams = $(this).serializeArray();
+ // if showAll button was clicked to submit form then
+ // add showAll button parameter to form
+ if (showAll) {
+ postParams.push({
+ name: $(showAllId).attr('name'),
+ value: $(showAllId).val()
+ });
+ }
+ // updates values in dialog
+ $.post($(this).attr('action') + '&ajax_request=1', postParams, function (data) {
+ var $obj = $('
').html(data.message);
+ $(formId).html($obj.find(formId).html());
+ $(tableId).html($obj.find(tableId).html());
+ });
+ showAll = false;
+ });
+ });
+};
+
+/**
+ * Get the auto saved query key
+ * @return {String}
+ */
+Sql.getAutoSavedKey = function () {
+ var db = $('input[name="db"]').val();
+ var table = $('input[name="table"]').val();
+ var key = db;
+ if (table !== undefined) {
+ key += '.' + table;
+ }
+ return 'autoSavedSql_' + key;
+};
+Sql.checkSavedQuery = function () {
+ var key = Sql.getAutoSavedKey();
+ if (isStorageSupported('localStorage') && typeof window.localStorage.getItem(key) === 'string') {
+ Functions.ajaxShowMessage(Messages.strPreviousSaveQuery);
+ } else if (Cookies.get(key)) {
+ Functions.ajaxShowMessage(Messages.strPreviousSaveQuery);
+ }
+};
+AJAX.registerOnload('sql.js', function () {
+ $('body').on('click', 'a.browse_foreign', function (e) {
+ e.preventDefault();
+ Sql.browseForeignDialog($(this));
+ });
+
+ /**
+ * vertical column highlighting in horizontal mode when hovering over the column header
+ */
+ $(document).on('mouseenter', 'th.column_heading.pointer', function () {
+ Sql.changeClassForColumn($(this), 'hover', true);
+ });
+ $(document).on('mouseleave', 'th.column_heading.pointer', function () {
+ Sql.changeClassForColumn($(this), 'hover', false);
+ });
+
+ /**
+ * vertical column marking in horizontal mode when clicking the column header
+ */
+ $(document).on('click', 'th.column_heading.marker', function () {
+ Sql.changeClassForColumn($(this), 'marked');
+ });
+
+ /**
+ * create resizable table
+ */
+ $('.sqlqueryresults').trigger('makegrid');
+
+ /**
+ * Check if there is any saved query
+ */
+ if (codeMirrorEditor || document.sqlform) {
+ Sql.checkSavedQuery();
+ }
+});
+
+/**
+ * Profiling Chart
+ */
+Sql.makeProfilingChart = function () {
+ if ($('#profilingchart').length === 0 || $('#profilingchart').html().length !== 0 || !$.jqplot || !$.jqplot.Highlighter || !$.jqplot.PieRenderer) {
+ return;
+ }
+ var data = [];
+ $.each(JSON.parse($('#profilingChartData').html()), function (key, value) {
+ data.push([key, parseFloat(value)]);
+ });
+
+ // Remove chart and data divs contents
+ $('#profilingchart').html('').show();
+ $('#profilingChartData').html('');
+ Functions.createProfilingChart('profilingchart', data);
+};
+
+/**
+ * initialize profiling data tables
+ */
+Sql.initProfilingTables = function () {
+ if (!$.tablesorter) {
+ return;
+ }
+ // Added to allow two direction sorting
+ $('#profiletable').find('thead th').off('click mousedown');
+ $('#profiletable').tablesorter({
+ widgets: ['zebra'],
+ sortList: [[0, 0]],
+ textExtraction: function (node) {
+ if (node.children.length > 0) {
+ return node.children[0].innerHTML;
+ } else {
+ return node.innerHTML;
+ }
+ }
+ });
+ // Added to allow two direction sorting
+ $('#profilesummarytable').find('thead th').off('click mousedown');
+ $('#profilesummarytable').tablesorter({
+ widgets: ['zebra'],
+ sortList: [[1, 1]],
+ textExtraction: function (node) {
+ if (node.children.length > 0) {
+ return node.children[0].innerHTML;
+ } else {
+ return node.innerHTML;
+ }
+ }
+ });
+};
+AJAX.registerOnload('sql.js', function () {
+ Sql.makeProfilingChart();
+ Sql.initProfilingTables();
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/change.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/change.js
new file mode 100644
index 000000000..8b9b77b0b
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/change.js
@@ -0,0 +1,767 @@
+/**
+ * @fileoverview function used in table data manipulation pages
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ *
+ */
+
+/* global extendingValidatorMessages */ // templates/javascript/variables.twig
+/* global openGISEditor, gisEditorLoaded, loadJSAndGISEditor, loadGISEditor */ // js/gis_data_editor.js
+
+/**
+ * Modify form controls when the "NULL" checkbox is checked
+ *
+ * @param {string} theType the MySQL field type
+ * @param {string} urlField the urlencoded field name - OBSOLETE
+ * @param {string} md5Field the md5 hashed field name
+ * @param {string} multiEdit the multi_edit row sequence number
+ *
+ * @return {boolean} always true
+ */
+function nullify(theType, urlField, md5Field, multiEdit) {
+ var rowForm = document.forms.insertForm;
+ if (typeof rowForm.elements['funcs' + multiEdit + '[' + md5Field + ']'] !== 'undefined') {
+ rowForm.elements['funcs' + multiEdit + '[' + md5Field + ']'].selectedIndex = -1;
+ }
+
+ // "ENUM" field with more than 20 characters
+ if (Number(theType) === 1) {
+ rowForm.elements['fields' + multiEdit + '[' + md5Field + ']'][1].selectedIndex = -1;
+ // Other "ENUM" field
+ } else if (Number(theType) === 2) {
+ var elts = rowForm.elements['fields' + multiEdit + '[' + md5Field + ']'];
+ // when there is just one option in ENUM:
+ if (elts.checked) {
+ elts.checked = false;
+ } else {
+ var eltsCnt = elts.length;
+ for (var i = 0; i < eltsCnt; i++) {
+ elts[i].checked = false;
+ } // end for
+ } // end if
+ // "SET" field
+ } else if (Number(theType) === 3) {
+ rowForm.elements['fields' + multiEdit + '[' + md5Field + '][]'].selectedIndex = -1;
+ // Foreign key field (drop-down)
+ } else if (Number(theType) === 4) {
+ rowForm.elements['fields' + multiEdit + '[' + md5Field + ']'].selectedIndex = -1;
+ // foreign key field (with browsing icon for foreign values)
+ } else if (Number(theType) === 6) {
+ rowForm.elements['fields' + multiEdit + '[' + md5Field + ']'].value = '';
+ // Other field types
+ } else /* if (theType === 5)*/{
+ rowForm.elements['fields' + multiEdit + '[' + md5Field + ']'].value = '';
+ } // end if... else if... else
+
+ return true;
+} // end of the 'nullify()' function
+
+/**
+ * javascript DateTime format validation.
+ * its used to prevent adding default (0000-00-00 00:00:00) to database when user enter wrong values
+ * Start of validation part
+ */
+// function checks the number of days in febuary
+function daysInFebruary(year) {
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0) ? 29 : 28;
+}
+// function to convert single digit to double digit
+function fractionReplace(number) {
+ var num = parseInt(number, 10);
+ return num >= 1 && num <= 9 ? '0' + num : '00';
+}
+
+/* function to check the validity of date
+* The following patterns are accepted in this validation (accepted in mysql as well)
+* 1) 2001-12-23
+* 2) 2001-1-2
+* 3) 02-12-23
+* 4) And instead of using '-' the following punctuations can be used (+,.,*,^,@,/) All these are accepted by mysql as well. Therefore no issues
+*/
+function isDate(val, tmstmp) {
+ var value = val.replace(/[.|*|^|+|//|@]/g, '-');
+ var arrayVal = value.split('-');
+ for (var a = 0; a < arrayVal.length; a++) {
+ if (arrayVal[a].length === 1) {
+ arrayVal[a] = fractionReplace(arrayVal[a]);
+ }
+ }
+ value = arrayVal.join('-');
+ var pos = 2;
+ var dtexp = new RegExp(/^([0-9]{4})-(((01|03|05|07|08|10|12)-((0[0-9])|([1-2][0-9])|(3[0-1])))|((02|04|06|09|11)-((0[0-9])|([1-2][0-9])|30))|((00)-(00)))$/);
+ if (value.length === 8) {
+ pos = 0;
+ }
+ if (dtexp.test(value)) {
+ var month = parseInt(value.substring(pos + 3, pos + 5), 10);
+ var day = parseInt(value.substring(pos + 6, pos + 8), 10);
+ var year = parseInt(value.substring(0, pos + 2), 10);
+ if (month === 2 && day > daysInFebruary(year)) {
+ return false;
+ }
+ if (value.substring(0, pos + 2).length === 2) {
+ year = parseInt('20' + value.substring(0, pos + 2), 10);
+ }
+ if (tmstmp === true) {
+ if (year < 1978) {
+ return false;
+ }
+ if (year > 2038 || year > 2037 && day > 19 && month >= 1 || year > 2037 && month > 1) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+/* function to check the validity of time
+* The following patterns are accepted in this validation (accepted in mysql as well)
+* 1) 2:3:4
+* 2) 2:23:43
+* 3) 2:23:43.123456
+*/
+function isTime(val) {
+ var arrayVal = val.split(':');
+ for (var a = 0, l = arrayVal.length; a < l; a++) {
+ if (arrayVal[a].length === 1) {
+ arrayVal[a] = fractionReplace(arrayVal[a]);
+ }
+ }
+ var newVal = arrayVal.join(':');
+ var tmexp = new RegExp(/^(-)?(([0-7]?[0-9][0-9])|(8[0-2][0-9])|(83[0-8])):((0[0-9])|([1-5][0-9])):((0[0-9])|([1-5][0-9]))(\.[0-9]{1,6}){0,1}$/);
+ return tmexp.test(newVal);
+}
+
+/**
+ * To check whether insert section is ignored or not
+ * @param {string} multiEdit
+ * @return {boolean}
+ */
+function checkForCheckbox(multiEdit) {
+ if ($('#insert_ignore_' + multiEdit).length) {
+ return $('#insert_ignore_' + multiEdit).is(':unchecked');
+ }
+ return true;
+}
+
+// used in Search page mostly for INT fields
+// eslint-disable-next-line no-unused-vars
+function verifyAfterSearchFieldChange(index, searchFormId) {
+ var $thisInput = $('input[name=\'criteriaValues[' + index + ']\']');
+ // Add data-skip-validators attribute to skip validation in changeValueFieldType function
+ if ($('#fieldID_' + index).data('data-skip-validators')) {
+ $(searchFormId).validate().destroy();
+ return;
+ }
+ // validation for integer type
+ if ($thisInput.data('type') === 'INT' || $thisInput.data('type') === 'TINYINT') {
+ // Trim spaces if it's an integer
+ $thisInput.val($thisInput.val().trim());
+ var hasMultiple = $thisInput.prop('multiple');
+ if (hasMultiple) {
+ $(searchFormId).validate({
+ // update errors as we write
+ onkeyup: function (element) {
+ $(element).valid();
+ }
+ });
+ // validator method for IN(...), NOT IN(...)
+ // BETWEEN and NOT BETWEEN
+ jQuery.validator.addMethod('validationFunctionForMultipleInt', function (value) {
+ return value.match(/^(?:(?:\d\s*)|\s*)+(?:,\s*\d+)*$/i) !== null;
+ }, Messages.strEnterValidNumber);
+ validateMultipleIntField($thisInput, true);
+ } else {
+ $(searchFormId).validate({
+ // update errors as we write
+ onkeyup: function (element) {
+ $(element).valid();
+ }
+ });
+ validateIntField($thisInput, true);
+ }
+ // Update error on dropdown change
+ $thisInput.valid();
+ }
+}
+
+/**
+ * Validate the an input contains multiple int values
+ * @param {jQuery} jqueryInput the Jquery object
+ * @param {boolean} returnValueIfFine the value to return if the validator passes
+ * @return {void}
+ */
+function validateMultipleIntField(jqueryInput, returnValueIfFine) {
+ // removing previous rules
+ jqueryInput.rules('remove');
+ jqueryInput.rules('add', {
+ validationFunctionForMultipleInt: {
+ param: jqueryInput.value,
+ depends: function () {
+ return returnValueIfFine;
+ }
+ }
+ });
+}
+
+/**
+ * Validate the an input contains an int value
+ * @param {jQuery} jqueryInput the Jquery object
+ * @param {boolean} returnValueIfIsNumber the value to return if the validator passes
+ * @return {void}
+ */
+function validateIntField(jqueryInput, returnValueIfIsNumber) {
+ var mini = parseInt(jqueryInput.data('min'));
+ var maxi = parseInt(jqueryInput.data('max'));
+ // removing previous rules
+ jqueryInput.rules('remove');
+ jqueryInput.rules('add', {
+ number: {
+ param: true,
+ depends: function () {
+ return returnValueIfIsNumber;
+ }
+ },
+ min: {
+ param: mini,
+ depends: function () {
+ if (isNaN(jqueryInput.val())) {
+ return false;
+ } else {
+ return returnValueIfIsNumber;
+ }
+ }
+ },
+ max: {
+ param: maxi,
+ depends: function () {
+ if (isNaN(jqueryInput.val())) {
+ return false;
+ } else {
+ return returnValueIfIsNumber;
+ }
+ }
+ }
+ });
+}
+function verificationsAfterFieldChange(urlField, multiEdit, theType) {
+ var evt = window.event || arguments.callee.caller.arguments[0];
+ var target = evt.target || evt.srcElement;
+ var $thisInput = $(':input[name^=\'fields[multi_edit][' + multiEdit + '][' + urlField + ']\']');
+ // the function drop-down that corresponds to this input field
+ var $thisFunction = $('select[name=\'funcs[multi_edit][' + multiEdit + '][' + urlField + ']\']');
+ var functionSelected = false;
+ if (typeof $thisFunction.val() !== 'undefined' && $thisFunction.val() !== null && $thisFunction.val().length > 0) {
+ functionSelected = true;
+ }
+
+ // To generate the textbox that can take the salt
+ var newSaltBox = '
';
+
+ // If encrypting or decrypting functions that take salt as input is selected append the new textbox for salt
+ if (target.value === 'AES_ENCRYPT' || target.value === 'AES_DECRYPT' || target.value === 'DES_ENCRYPT' || target.value === 'DES_DECRYPT' || target.value === 'ENCRYPT') {
+ if (!$('#salt_' + target.id).length) {
+ $thisInput.after(newSaltBox);
+ }
+ } else {
+ // Remove the textbox for salt
+ $('#salt_' + target.id).prev('br').remove();
+ $('#salt_' + target.id).remove();
+ }
+
+ // Remove possible blocking rules if the user changed functions
+ $('#' + target.id).rules('remove', 'validationFunctionForMd5');
+ $('#' + target.id).rules('remove', 'validationFunctionForAesDesEncrypt');
+ if (target.value === 'MD5') {
+ $('#' + target.id).rules('add', {
+ validationFunctionForMd5: {
+ param: $thisInput,
+ depends: function () {
+ return checkForCheckbox(multiEdit);
+ }
+ }
+ });
+ }
+ if (target.value === 'DES_ENCRYPT' || target.value === 'AES_ENCRYPT') {
+ $('#' + target.id).rules('add', {
+ validationFunctionForAesDesEncrypt: {
+ param: $thisInput,
+ depends: function () {
+ return checkForCheckbox(multiEdit);
+ }
+ }
+ });
+ }
+ if (target.value === 'HEX' && theType.substring(0, 3) === 'int') {
+ // Add note when HEX function is selected on a int
+ var newHexInfo = '
' + Messages.HexConversionInfo + '
';
+ if (!$('#note' + target.id).length) {
+ $thisInput.after(newHexInfo);
+ }
+ } else {
+ $('#note' + target.id).prev('br').remove();
+ $('#note' + target.id).remove();
+ }
+ // Unchecks the corresponding "NULL" control
+ $('input[name=\'fields_null[multi_edit][' + multiEdit + '][' + urlField + ']\']').prop('checked', false);
+
+ // Unchecks the Ignore checkbox for the current row
+ $('input[name=\'insert_ignore_' + multiEdit + '\']').prop('checked', false);
+ var charExceptionHandling;
+ if (theType.substring(0, 4) === 'char') {
+ charExceptionHandling = theType.substring(5, 6);
+ } else if (theType.substring(0, 7) === 'varchar') {
+ charExceptionHandling = theType.substring(8, 9);
+ }
+ if (functionSelected) {
+ $thisInput.removeAttr('min');
+ $thisInput.removeAttr('max');
+ // @todo: put back attributes if corresponding function is deselected
+ }
+
+ if ($thisInput.data('rulesadded') === null && !functionSelected) {
+ // call validate before adding rules
+ $($thisInput[0].form).validate();
+ // validate for date time
+ if (theType === 'datetime' || theType === 'time' || theType === 'date' || theType === 'timestamp') {
+ $thisInput.rules('add', {
+ validationFunctionForDateTime: {
+ param: theType,
+ depends: function () {
+ return checkForCheckbox(multiEdit);
+ }
+ }
+ });
+ }
+ // validation for integer type
+ if ($thisInput.data('type') === 'INT') {
+ validateIntField($thisInput, checkForCheckbox(multiEdit));
+ // validation for CHAR types
+ } else if ($thisInput.data('type') === 'CHAR') {
+ var maxlen = $thisInput.data('maxlength');
+ if (typeof maxlen !== 'undefined') {
+ if (maxlen <= 4) {
+ maxlen = charExceptionHandling;
+ }
+ $thisInput.rules('add', {
+ maxlength: {
+ param: maxlen,
+ depends: function () {
+ return checkForCheckbox(multiEdit);
+ }
+ }
+ });
+ }
+ // validate binary & blob types
+ } else if ($thisInput.data('type') === 'HEX') {
+ $thisInput.rules('add', {
+ validationFunctionForHex: {
+ param: true,
+ depends: function () {
+ return checkForCheckbox(multiEdit);
+ }
+ }
+ });
+ }
+ $thisInput.data('rulesadded', true);
+ } else if ($thisInput.data('rulesadded') === true && functionSelected) {
+ // remove any rules added
+ $thisInput.rules('remove');
+ // remove any error messages
+ $thisInput.removeClass('error').removeAttr('aria-invalid').siblings('.error').remove();
+ $thisInput.data('rulesadded', null);
+ }
+}
+/* End of fields validation*/
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/change.js', function () {
+ $(document).off('click', 'span.open_gis_editor');
+ $(document).off('click', 'input[name^=\'insert_ignore_\']');
+ $(document).off('click', 'input[name=\'gis_data[save]\']');
+ $(document).off('click', 'input.checkbox_null');
+ $('select[name="submit_type"]').off('change');
+ $(document).off('change', '#insert_rows');
+});
+
+/**
+ * Ajax handlers for Change Table page
+ *
+ * Actions Ajaxified here:
+ * Submit Data to be inserted into the table.
+ * Restart insertion with 'N' rows.
+ */
+AJAX.registerOnload('table/change.js', function () {
+ if ($('#insertForm').length) {
+ // validate the comment form when it is submitted
+ $('#insertForm').validate();
+ jQuery.validator.addMethod('validationFunctionForHex', function (value) {
+ return value.match(/^[a-f0-9]*$/i) !== null;
+ });
+ jQuery.validator.addMethod('validationFunctionForMd5', function (value, element, options) {
+ return !(value.substring(0, 3) === 'MD5' && typeof options.data('maxlength') !== 'undefined' && options.data('maxlength') < 32);
+ });
+ jQuery.validator.addMethod('validationFunctionForAesDesEncrypt', function (value, element, options) {
+ var funType = value.substring(0, 3);
+ if (funType !== 'AES' && funType !== 'DES') {
+ return false;
+ }
+ var dataType = options.data('type');
+ if (dataType === 'HEX' || dataType === 'CHAR') {
+ return true;
+ }
+ return false;
+ });
+ jQuery.validator.addMethod('validationFunctionForDateTime', function (value, element, options) {
+ var dtValue = value;
+ var theType = options;
+ if (theType === 'date') {
+ return isDate(dtValue);
+ } else if (theType === 'time') {
+ return isTime(dtValue);
+ } else if (theType === 'datetime' || theType === 'timestamp') {
+ var tmstmp = false;
+ dtValue = dtValue.trim();
+ if (dtValue === 'CURRENT_TIMESTAMP' || dtValue === 'current_timestamp()') {
+ return true;
+ }
+ if (theType === 'timestamp') {
+ tmstmp = true;
+ }
+ if (dtValue === '0000-00-00 00:00:00') {
+ return true;
+ }
+ var dv = dtValue.indexOf(' ');
+ if (dv === -1) {
+ // Only the date component, which is valid
+ return isDate(dtValue, tmstmp);
+ }
+ return isDate(dtValue.substring(0, dv), tmstmp) && isTime(dtValue.substring(dv + 1));
+ }
+ });
+ }
+
+ /*
+ * message extending script must be run
+ * after initiation of functions
+ */
+ extendingValidatorMessages();
+ $.datepicker.initialized = false;
+ $(document).on('click', 'span.open_gis_editor', function (event) {
+ event.preventDefault();
+ var $span = $(this);
+ // Current value
+ var value = $span.parent('td').children('input[type=\'text\']').val();
+ // Field name
+ var field = $span.parents('tr').children('td').first().find('input[type=\'hidden\']').val();
+ // Column type
+ var type = $span.parents('tr').find('span.column_type').text();
+ // Names of input field and null checkbox
+ var inputName = $span.parent('td').children('input[type=\'text\']').attr('name');
+ openGISEditor();
+ if (!gisEditorLoaded) {
+ loadJSAndGISEditor(value, field, type, inputName);
+ } else {
+ loadGISEditor(value, field, type, inputName);
+ }
+ });
+
+ /**
+ * Forced validation check of fields
+ */
+ $(document).on('click', 'input[name^=\'insert_ignore_\']', function () {
+ $('#insertForm').valid();
+ });
+
+ /**
+ * Uncheck the null checkbox as geometry data is placed on the input field
+ */
+ $(document).on('click', 'input[name=\'gis_data[save]\']', function () {
+ var inputName = $('form#gis_data_editor_form').find('input[name=\'input_name\']').val();
+ var currentRow = $('input[name=\'' + inputName + '\']').parents('tr');
+ var $nullCheckbox = currentRow.find('.checkbox_null');
+ $nullCheckbox.prop('checked', false);
+ var rowId = currentRow.find('.open_gis_editor').data('row-id');
+
+ // Unchecks the Ignore checkbox for the current row
+ $('input[name=\'insert_ignore_' + rowId + '\']').prop('checked', false);
+ });
+
+ /**
+ * Handles all current checkboxes for Null; this only takes care of the
+ * checkboxes on currently displayed rows as the rows generated by
+ * "Continue insertion" are handled in the "Continue insertion" code
+ *
+ */
+ $(document).on('click', 'input.checkbox_null', function () {
+ nullify(
+ // use hidden fields populated by /table/change
+ $(this).siblings('.nullify_code').val(), $(this).closest('tr').find('input:hidden').first().val(), $(this).siblings('.hashed_field').val(), $(this).siblings('.multi_edit').val());
+ });
+
+ /**
+ * Reset the auto_increment column to 0 when selecting any of the
+ * insert options in submit_type-dropdown. Only perform the reset
+ * when we are in edit-mode, and not in insert-mode(no previous value
+ * available).
+ */
+ $('select[name="submit_type"]').on('change', function () {
+ var thisElemSubmitTypeVal = $(this).val();
+ var $table = $('table.insertRowTable');
+ var autoIncrementColumn = $table.find('input[name^="auto_increment"]');
+ autoIncrementColumn.each(function () {
+ var $thisElemAIField = $(this);
+ var thisElemName = $thisElemAIField.attr('name');
+ var prevValueField = $table.find('input[name="' + thisElemName.replace('auto_increment', 'fields_prev') + '"]');
+ var valueField = $table.find('input[name="' + thisElemName.replace('auto_increment', 'fields') + '"]');
+ var previousValue = $(prevValueField).val();
+ if (previousValue !== undefined) {
+ if (thisElemSubmitTypeVal === 'insert' || thisElemSubmitTypeVal === 'insertignore' || thisElemSubmitTypeVal === 'showinsert') {
+ $(valueField).val(null);
+ } else {
+ $(valueField).val(previousValue);
+ }
+ }
+ });
+ });
+
+ /**
+ * Handle ENTER key when press on Continue insert with field
+ */
+ $('#insert_rows').on('keypress', function (e) {
+ var key = e.which;
+ if (key === 13) {
+ addNewContinueInsertionFields(e);
+ }
+ });
+
+ /**
+ * Continue Insertion form
+ */
+ $(document).on('change', '#insert_rows', addNewContinueInsertionFields);
+});
+function addNewContinueInsertionFields(event) {
+ event.preventDefault();
+ /**
+ * @var columnCount Number of number of columns table has.
+ */
+ var columnCount = $('table.insertRowTable').first().find('tr').has('input[name*=\'fields_name\']').length;
+ /**
+ * @var curr_rows Number of current insert rows already on page
+ */
+ var currRows = $('table.insertRowTable').length;
+ /**
+ * @var target_rows Number of rows the user wants
+ */
+ var targetRows = $('#insert_rows').val();
+
+ // remove all datepickers
+ $('input.datefield, input.datetimefield').each(function () {
+ $(this).datepicker('destroy');
+ });
+ if (currRows < targetRows) {
+ var tempIncrementIndex = function () {
+ var $thisElement = $(this);
+ /**
+ * Extract the index from the name attribute for all input/select fields and increment it
+ * name is of format funcs[multi_edit][10][
]
+ */
+
+ /**
+ * @var this_name String containing name of the input/select elements
+ */
+ var thisName = $thisElement.attr('name');
+ /** split {@link thisName} at [10], so we have the parts that can be concatenated later */
+ var nameParts = thisName.split(/\[\d+\]/);
+ /** extract the [10] from {@link nameParts} */
+ var oldRowIndexString = thisName.match(/\[\d+\]/)[0];
+ /** extract 10 - had to split into two steps to accomodate double digits */
+ var oldRowIndex = parseInt(oldRowIndexString.match(/\d+/)[0], 10);
+
+ /** calculate next index i.e. 11 */
+ newRowIndex = oldRowIndex + 1;
+ /** generate the new name i.e. funcs[multi_edit][11][foobarbaz] */
+ var newName = nameParts[0] + '[' + newRowIndex + ']' + nameParts[1];
+ var hashedField = nameParts[1].match(/\[(.+)\]/)[1];
+ $thisElement.attr('name', newName);
+
+ /** If element is select[name*='funcs'], update id */
+ if ($thisElement.is('select[name*=\'funcs\']')) {
+ var thisId = $thisElement.attr('id');
+ var idParts = thisId.split(/_/);
+ var oldIdIndex = idParts[1];
+ var prevSelectedValue = $('#field_' + oldIdIndex + '_1').val();
+ var newIdIndex = parseInt(oldIdIndex) + columnCount;
+ var newId = 'field_' + newIdIndex + '_1';
+ $thisElement.attr('id', newId);
+ $thisElement.find('option').filter(function () {
+ return $(this).text() === prevSelectedValue;
+ }).attr('selected', 'selected');
+
+ // If salt field is there then update its id.
+ var nextSaltInput = $thisElement.parent().next('td').next('td').find('input[name*=\'salt\']');
+ if (nextSaltInput.length !== 0) {
+ nextSaltInput.attr('id', 'salt_' + newId);
+ }
+ }
+
+ // handle input text fields and textareas
+ if ($thisElement.is('.textfield') || $thisElement.is('.char') || $thisElement.is('textarea')) {
+ // do not remove the 'value' attribute for ENUM columns
+ // special handling for radio fields after updating ids to unique - see below
+ if ($thisElement.closest('tr').find('span.column_type').html() !== 'enum') {
+ $thisElement.val($thisElement.closest('tr').find('span.default_value').html());
+ }
+ $thisElement.off('change')
+ // Remove onchange attribute that was placed
+ // by /table/change; it refers to the wrong row index
+ .attr('onchange', null)
+ // Keep these values to be used when the element
+ // will change
+ .data('hashed_field', hashedField).data('new_row_index', newRowIndex).on('change', function () {
+ var $changedElement = $(this);
+ verificationsAfterFieldChange($changedElement.data('hashed_field'), $changedElement.data('new_row_index'), $changedElement.closest('tr').find('span.column_type').html());
+ });
+ }
+ if ($thisElement.is('.checkbox_null')) {
+ $thisElement
+ // this event was bound earlier by jQuery but
+ // to the original row, not the cloned one, so unbind()
+ .off('click')
+ // Keep these values to be used when the element
+ // will be clicked
+ .data('hashed_field', hashedField).data('new_row_index', newRowIndex).on('click', function () {
+ var $changedElement = $(this);
+ nullify($changedElement.siblings('.nullify_code').val(), $thisElement.closest('tr').find('input:hidden').first().val(), $changedElement.data('hashed_field'), '[multi_edit][' + $changedElement.data('new_row_index') + ']');
+ });
+ }
+ };
+ var tempReplaceAnchor = function () {
+ var $anchor = $(this);
+ var newValue = 'rownumber=' + newRowIndex;
+ // needs improvement in case something else inside
+ // the href contains this pattern
+ var newHref = $anchor.attr('href').replace(/rownumber=\d+/, newValue);
+ $anchor.attr('href', newHref);
+ };
+ var restoreValue = function () {
+ if ($(this).closest('tr').find('span.column_type').html() === 'enum') {
+ if ($(this).val() === $checkedValue) {
+ $(this).prop('checked', true);
+ } else {
+ $(this).prop('checked', false);
+ }
+ }
+ };
+ while (currRows < targetRows) {
+ /**
+ * @var $last_row Object referring to the last row
+ */
+ var $lastRow = $('#insertForm').find('.insertRowTable').last();
+
+ // need to access this at more than one level
+ // (also needs improvement because it should be calculated
+ // just once per cloned row, not once per column)
+ var newRowIndex = 0;
+ var $checkedValue = $lastRow.find('input:checked').val();
+
+ // Clone the insert tables
+ $lastRow.clone(true, true).insertBefore('#actions_panel').find('input[name*=multi_edit],select[name*=multi_edit],textarea[name*=multi_edit]').each(tempIncrementIndex).end().find('.foreign_values_anchor').each(tempReplaceAnchor);
+ var $oldRow = $lastRow.find('.textfield');
+ $oldRow.each(restoreValue);
+
+ // set the value of enum field of new row to default
+ var $newRow = $('#insertForm').find('.insertRowTable').last();
+ $newRow.find('.textfield').each(function () {
+ if ($(this).closest('tr').find('span.column_type').html() === 'enum') {
+ if ($(this).val() === $(this).closest('tr').find('span.default_value').html()) {
+ $(this).prop('checked', true);
+ } else {
+ $(this).prop('checked', false);
+ }
+ }
+ });
+
+ // Insert/Clone the ignore checkboxes
+ if (currRows === 1) {
+ $(' ').insertBefore($('table.insertRowTable').last()).after('' + Messages.strIgnore + ' ');
+ } else {
+ /**
+ * @var $last_checkbox Object reference to the last checkbox in #insertForm
+ */
+ var $lastCheckbox = $('#insertForm').children('input:checkbox').last();
+
+ /** name of {@link $lastCheckbox} */
+ var lastCheckboxName = $lastCheckbox.attr('name');
+ /** index of {@link $lastCheckbox} */
+ var lastCheckboxIndex = parseInt(lastCheckboxName.match(/\d+/), 10);
+ /** name of new {@link $lastCheckbox} */
+ var newName = lastCheckboxName.replace(/\d+/, lastCheckboxIndex + 1);
+ $('
').insertBefore($('table.insertRowTable').last());
+ $lastCheckbox.clone().attr({
+ 'id': newName,
+ 'name': newName
+ }).prop('checked', true).insertBefore($('table.insertRowTable').last());
+ $('label[for^=insert_ignore]').last().clone().attr('for', newName).insertBefore($('table.insertRowTable').last());
+ $(' ').insertBefore($('table.insertRowTable').last());
+ }
+ currRows++;
+ }
+ // recompute tabindex for text fields and other controls at footer;
+ // IMO it's not really important to handle the tabindex for
+ // function and Null
+ var tabIndex = 0;
+ $('.textfield, .char, textarea').each(function () {
+ tabIndex++;
+ $(this).attr('tabindex', tabIndex);
+ // update the IDs of textfields to ensure that they are unique
+ $(this).attr('id', 'field_' + tabIndex + '_3');
+ });
+ $('.control_at_footer').each(function () {
+ tabIndex++;
+ $(this).attr('tabindex', tabIndex);
+ });
+ } else if (currRows > targetRows) {
+ /**
+ * Displays alert if data loss possible on decrease
+ * of rows.
+ */
+ var checkLock = jQuery.isEmptyObject(AJAX.lockedTargets);
+ if (checkLock || confirm(Messages.strConfirmRowChange) === true) {
+ while (currRows > targetRows) {
+ $('input[id^=insert_ignore]').last().nextUntil('fieldset').addBack().remove();
+ currRows--;
+ }
+ } else {
+ document.getElementById('insert_rows').value = currRows;
+ }
+ }
+ // Add all the required datepickers back
+ Functions.addDateTimePicker();
+}
+
+// eslint-disable-next-line no-unused-vars
+function changeValueFieldType(elem, searchIndex) {
+ var fieldsValue = $('input#fieldID_' + searchIndex);
+ if (0 === fieldsValue.size()) {
+ return;
+ }
+ var type = $(elem).val();
+ if ('LIKE' === type || 'LIKE %...%' === type || 'NOT LIKE' === type || 'NOT LIKE %...%' === type) {
+ $('#fieldID_' + searchIndex).data('data-skip-validators', true);
+ return;
+ } else {
+ $('#fieldID_' + searchIndex).data('data-skip-validators', false);
+ }
+ if ('IN (...)' === type || 'NOT IN (...)' === type || 'BETWEEN' === type || 'NOT BETWEEN' === type) {
+ $('#fieldID_' + searchIndex).prop('multiple', true);
+ } else {
+ $('#fieldID_' + searchIndex).prop('multiple', false);
+ }
+}
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/chart.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/chart.js
new file mode 100644
index 000000000..6c498197a
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/chart.js
@@ -0,0 +1,403 @@
+/* global ColumnType, DataTable, JQPlotChartFactory */ // js/chart.js
+/* global codeMirrorEditor */ // js/functions.js
+
+var chartData = {};
+var tempChartTitle;
+var currentChart = null;
+var currentSettings = null;
+var dateTimeCols = [];
+var numericCols = [];
+function extractDate(dateString) {
+ var matches;
+ var match;
+ var dateTimeRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/;
+ var dateRegExp = /[0-9]{4}-[0-9]{2}-[0-9]{2}/;
+ matches = dateTimeRegExp.exec(dateString);
+ if (matches !== null && matches.length > 0) {
+ match = matches[0];
+ return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2), match.substr(11, 2), match.substr(14, 2), match.substr(17, 2));
+ } else {
+ matches = dateRegExp.exec(dateString);
+ if (matches !== null && matches.length > 0) {
+ match = matches[0];
+ return new Date(match.substr(0, 4), parseInt(match.substr(5, 2), 10) - 1, match.substr(8, 2));
+ }
+ }
+ return null;
+}
+function queryChart(data, columnNames, settings) {
+ if ($('#querychart').length === 0) {
+ return;
+ }
+ var plotSettings = {
+ title: {
+ text: settings.title,
+ escapeHtml: true
+ },
+ grid: {
+ drawBorder: false,
+ shadow: false,
+ background: 'rgba(0,0,0,0)'
+ },
+ legend: {
+ show: true,
+ placement: 'outsideGrid',
+ location: 'e',
+ rendererOptions: {
+ numberColumns: 2
+ }
+ },
+ axes: {
+ xaxis: {
+ label: Functions.escapeHtml(settings.xaxisLabel)
+ },
+ yaxis: {
+ label: settings.yaxisLabel
+ }
+ },
+ stackSeries: settings.stackSeries
+ };
+
+ // create the chart
+ var factory = new JQPlotChartFactory();
+ var chart = factory.createChart(settings.type, 'querychart');
+
+ // create the data table and add columns
+ var dataTable = new DataTable();
+ if (settings.type === 'timeline') {
+ dataTable.addColumn(ColumnType.DATE, columnNames[settings.mainAxis]);
+ } else if (settings.type === 'scatter') {
+ dataTable.addColumn(ColumnType.NUMBER, columnNames[settings.mainAxis]);
+ } else {
+ dataTable.addColumn(ColumnType.STRING, columnNames[settings.mainAxis]);
+ }
+ var i;
+ var values = [];
+ if (settings.seriesColumn === null) {
+ $.each(settings.selectedSeries, function (index, element) {
+ dataTable.addColumn(ColumnType.NUMBER, columnNames[element]);
+ });
+
+ // set data to the data table
+ var columnsToExtract = [settings.mainAxis];
+ $.each(settings.selectedSeries, function (index, element) {
+ columnsToExtract.push(element);
+ });
+ var newRow;
+ var row;
+ var col;
+ for (i = 0; i < data.length; i++) {
+ row = data[i];
+ newRow = [];
+ for (var j = 0; j < columnsToExtract.length; j++) {
+ col = columnNames[columnsToExtract[j]];
+ if (j === 0) {
+ if (settings.type === 'timeline') {
+ // first column is date type
+ newRow.push(extractDate(row[col]));
+ } else if (settings.type === 'scatter') {
+ newRow.push(parseFloat(row[col]));
+ } else {
+ // first column is string type
+ newRow.push(row[col]);
+ }
+ } else {
+ // subsequent columns are of type, number
+ newRow.push(parseFloat(row[col]));
+ }
+ }
+ values.push(newRow);
+ }
+ dataTable.setData(values);
+ } else {
+ var seriesNames = {};
+ var seriesNumber = 1;
+ var seriesColumnName = columnNames[settings.seriesColumn];
+ for (i = 0; i < data.length; i++) {
+ if (!seriesNames[data[i][seriesColumnName]]) {
+ seriesNames[data[i][seriesColumnName]] = seriesNumber;
+ seriesNumber++;
+ }
+ }
+ $.each(seriesNames, function (seriesName) {
+ dataTable.addColumn(ColumnType.NUMBER, seriesName);
+ });
+ var valueMap = {};
+ var xValue;
+ var value;
+ var mainAxisName = columnNames[settings.mainAxis];
+ var valueColumnName = columnNames[settings.valueColumn];
+ for (i = 0; i < data.length; i++) {
+ xValue = data[i][mainAxisName];
+ value = valueMap[xValue];
+ if (!value) {
+ value = [xValue];
+ valueMap[xValue] = value;
+ }
+ seriesNumber = seriesNames[data[i][seriesColumnName]];
+ value[seriesNumber] = parseFloat(data[i][valueColumnName]);
+ }
+ $.each(valueMap, function (index, value) {
+ values.push(value);
+ });
+ dataTable.setData(values);
+ }
+
+ // draw the chart and return the chart object
+ chart.draw(dataTable, plotSettings);
+ return chart;
+}
+function drawChart() {
+ currentSettings.width = $('#resizer').width() - 20;
+ currentSettings.height = $('#resizer').height() - 20;
+
+ // TODO: a better way using .redraw() ?
+ if (currentChart !== null) {
+ currentChart.destroy();
+ }
+ var columnNames = [];
+ $('#chartXAxisSelect option').each(function () {
+ columnNames.push(Functions.escapeHtml($(this).text()));
+ });
+ try {
+ currentChart = queryChart(chartData, columnNames, currentSettings);
+ if (currentChart !== null) {
+ $('#saveChart').attr('href', currentChart.toImageString());
+ }
+ } catch (err) {
+ Functions.ajaxShowMessage(err.message, false);
+ }
+}
+function getSelectedSeries() {
+ var val = $('#chartSeriesSelect').val() || [];
+ var ret = [];
+ $.each(val, function (i, v) {
+ ret.push(parseInt(v, 10));
+ });
+ return ret;
+}
+function onXAxisChange() {
+ var $xAxisSelect = $('#chartXAxisSelect');
+ currentSettings.mainAxis = parseInt($xAxisSelect.val(), 10);
+ if (dateTimeCols.indexOf(currentSettings.mainAxis) !== -1) {
+ document.getElementById('timelineChartType').classList.remove('d-none');
+ } else {
+ document.getElementById('timelineChartType').classList.add('d-none');
+ if (currentSettings.type === 'timeline') {
+ $('#lineChartTypeRadio').prop('checked', true);
+ currentSettings.type = 'line';
+ }
+ }
+ if (numericCols.indexOf(currentSettings.mainAxis) !== -1) {
+ document.getElementById('scatterChartType').classList.remove('d-none');
+ } else {
+ document.getElementById('scatterChartType').classList.add('d-none');
+ if (currentSettings.type === 'scatter') {
+ $('#lineChartTypeRadio').prop('checked', true);
+ currentSettings.type = 'line';
+ }
+ }
+ var xAxisTitle = $xAxisSelect.children('option:selected').text();
+ $('#xAxisLabelInput').val(xAxisTitle);
+ currentSettings.xaxisLabel = xAxisTitle;
+}
+function onDataSeriesChange() {
+ var $seriesSelect = $('#chartSeriesSelect');
+ currentSettings.selectedSeries = getSelectedSeries();
+ var yAxisTitle;
+ if (currentSettings.selectedSeries.length === 1) {
+ document.getElementById('pieChartType').classList.remove('d-none');
+ yAxisTitle = $seriesSelect.children('option:selected').text();
+ } else {
+ document.getElementById('pieChartType').classList.add('d-none');
+ if (currentSettings.type === 'pie') {
+ $('#lineChartTypeRadio').prop('checked', true);
+ currentSettings.type = 'line';
+ }
+ yAxisTitle = Messages.strYValues;
+ }
+ $('#yAxisLabelInput').val(yAxisTitle);
+ currentSettings.yaxisLabel = yAxisTitle;
+}
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/chart.js', function () {
+ $('input[name="chartType"]').off('click');
+ $('#barStackedCheckbox').off('click');
+ $('#seriesColumnCheckbox').off('click');
+ $('#chartTitleInput').off('focus').off('keyup').off('blur');
+ $('#chartXAxisSelect').off('change');
+ $('#chartSeriesSelect').off('change');
+ $('#chartSeriesColumnSelect').off('change');
+ $('#chartValueColumnSelect').off('change');
+ $('#xAxisLabelInput').off('keyup');
+ $('#yAxisLabelInput').off('keyup');
+ $('#resizer').off('resizestop');
+ $('#tblchartform').off('submit');
+});
+AJAX.registerOnload('table/chart.js', function () {
+ // handle manual resize
+ $('#resizer').on('resizestop', function () {
+ // make room so that the handle will still appear
+ $('#querychart').height($('#resizer').height() * 0.96);
+ $('#querychart').width($('#resizer').width() * 0.96);
+ if (currentChart !== null) {
+ currentChart.redraw({
+ resetAxes: true
+ });
+ }
+ });
+
+ // handle chart type changes
+ $('input[name="chartType"]').on('click', function () {
+ var type = currentSettings.type = $(this).val();
+ if (type === 'bar' || type === 'column' || type === 'area') {
+ document.getElementById('barStacked').classList.remove('d-none');
+ } else {
+ $('#barStackedCheckbox').prop('checked', false);
+ $.extend(true, currentSettings, {
+ stackSeries: false
+ });
+ document.getElementById('barStacked').classList.add('d-none');
+ }
+ drawChart();
+ });
+
+ // handle chosing alternative data format
+ $('#seriesColumnCheckbox').on('click', function () {
+ var $seriesColumn = $('#chartSeriesColumnSelect');
+ var $valueColumn = $('#chartValueColumnSelect');
+ var $chartSeries = $('#chartSeriesSelect');
+ if ($(this).is(':checked')) {
+ $seriesColumn.prop('disabled', false);
+ $valueColumn.prop('disabled', false);
+ $chartSeries.prop('disabled', true);
+ currentSettings.seriesColumn = parseInt($seriesColumn.val(), 10);
+ currentSettings.valueColumn = parseInt($valueColumn.val(), 10);
+ } else {
+ $seriesColumn.prop('disabled', true);
+ $valueColumn.prop('disabled', true);
+ $chartSeries.prop('disabled', false);
+ currentSettings.seriesColumn = null;
+ currentSettings.valueColumn = null;
+ }
+ drawChart();
+ });
+
+ // handle stacking for bar, column and area charts
+ $('#barStackedCheckbox').on('click', function () {
+ if ($(this).is(':checked')) {
+ $.extend(true, currentSettings, {
+ stackSeries: true
+ });
+ } else {
+ $.extend(true, currentSettings, {
+ stackSeries: false
+ });
+ }
+ drawChart();
+ });
+
+ // handle changes in chart title
+ $('#chartTitleInput').on('focus', function () {
+ tempChartTitle = $(this).val();
+ }).on('keyup', function () {
+ currentSettings.title = $('#chartTitleInput').val();
+ drawChart();
+ }).on('blur', function () {
+ if ($(this).val() !== tempChartTitle) {
+ drawChart();
+ }
+ });
+
+ // handle changing the x-axis
+ $('#chartXAxisSelect').on('change', function () {
+ onXAxisChange();
+ drawChart();
+ });
+
+ // handle changing the selected data series
+ $('#chartSeriesSelect').on('change', function () {
+ onDataSeriesChange();
+ drawChart();
+ });
+
+ // handle changing the series column
+ $('#chartSeriesColumnSelect').on('change', function () {
+ currentSettings.seriesColumn = parseInt($(this).val(), 10);
+ drawChart();
+ });
+
+ // handle changing the value column
+ $('#chartValueColumnSelect').on('change', function () {
+ currentSettings.valueColumn = parseInt($(this).val(), 10);
+ drawChart();
+ });
+
+ // handle manual changes to the chart x-axis labels
+ $('#xAxisLabelInput').on('keyup', function () {
+ currentSettings.xaxisLabel = $(this).val();
+ drawChart();
+ });
+
+ // handle manual changes to the chart y-axis labels
+ $('#yAxisLabelInput').on('keyup', function () {
+ currentSettings.yaxisLabel = $(this).val();
+ drawChart();
+ });
+
+ // handler for ajax form submission
+ $('#tblchartform').on('submit', function () {
+ var $form = $(this);
+ if (codeMirrorEditor) {
+ $form[0].elements.sql_query.value = codeMirrorEditor.getValue();
+ }
+ if (!Functions.checkSqlQuery($form[0])) {
+ return false;
+ }
+ var $msgbox = Functions.ajaxShowMessage();
+ Functions.prepareForAjaxRequest($form);
+ $.post($form.attr('action'), $form.serialize(), function (data) {
+ if (typeof data !== 'undefined' && data.success === true && typeof data.chartData !== 'undefined') {
+ chartData = JSON.parse(data.chartData);
+ drawChart();
+ Functions.ajaxRemoveMessage($msgbox);
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }, 'json'); // end $.post()
+
+ return false;
+ });
+
+ // from jQuery UI
+ $('#resizer').resizable({
+ minHeight: 240,
+ minWidth: 300
+ }).width($('#div_view_options').width() - 50).trigger('resizestop');
+ currentSettings = {
+ type: 'line',
+ width: $('#resizer').width() - 20,
+ height: $('#resizer').height() - 20,
+ xaxisLabel: $('#xAxisLabelInput').val(),
+ yaxisLabel: $('#yAxisLabelInput').val(),
+ title: $('#chartTitleInput').val(),
+ stackSeries: false,
+ mainAxis: parseInt($('#chartXAxisSelect').val(), 10),
+ selectedSeries: getSelectedSeries(),
+ seriesColumn: null
+ };
+ var vals = $('input[name="dateTimeCols"]').val().split(' ');
+ $.each(vals, function (i, v) {
+ dateTimeCols.push(parseInt(v, 10));
+ });
+ vals = $('input[name="numericCols"]').val().split(' ');
+ $.each(vals, function (i, v) {
+ numericCols.push(parseInt(v, 10));
+ });
+ onXAxisChange();
+ onDataSeriesChange();
+ $('#tblchartform').trigger('submit');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/find_replace.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/find_replace.js
new file mode 100644
index 000000000..528da9ede
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/find_replace.js
@@ -0,0 +1,40 @@
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/find_replace.js', function () {
+ $('#find_replace_form').off('submit');
+ $('#toggle_find').off('click');
+});
+
+/**
+ * Bind events
+ */
+AJAX.registerOnload('table/find_replace.js', function () {
+ $('').insertAfter('#find_replace_form').hide();
+ $('#toggle_find').html(Messages.strHideFindNReplaceCriteria).on('click', function () {
+ var $link = $(this);
+ $('#find_replace_form').slideToggle();
+ if ($link.text() === Messages.strHideFindNReplaceCriteria) {
+ $link.text(Messages.strShowFindNReplaceCriteria);
+ } else {
+ $link.text(Messages.strHideFindNReplaceCriteria);
+ }
+ return false;
+ });
+ $('#find_replace_form').on('submit', function (e) {
+ e.preventDefault();
+ var findReplaceForm = $('#find_replace_form');
+ Functions.prepareForAjaxRequest(findReplaceForm);
+ var $msgbox = Functions.ajaxShowMessage();
+ $.post(findReplaceForm.attr('action'), findReplaceForm.serialize(), function (data) {
+ Functions.ajaxRemoveMessage($msgbox);
+ if (data.success === true) {
+ $('#toggle_find_div').show();
+ $('#toggle_find').trigger('click');
+ $('#sqlqueryresultsouter').html(data.preview);
+ } else {
+ $('#sqlqueryresultsouter').html(data.error);
+ }
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/gis_visualization.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/gis_visualization.js
new file mode 100644
index 000000000..b82602de9
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/gis_visualization.js
@@ -0,0 +1,330 @@
+/**
+ * @fileoverview functions used for visualizing GIS data
+ *
+ * @requires jquery
+ */
+
+/* global drawOpenLayers PASSIVE_EVENT_LISTENERS */ // templates/table/gis_visualization/gis_visualization.twig
+
+// Constants
+var zoomFactor = 1.5;
+var defaultX = 0;
+var defaultY = 0;
+var defaultScale = 1;
+
+// Variables
+var x = defaultX;
+var y = defaultY;
+var scale = defaultScale;
+
+/** @type {SVGElement|undefined} */
+var gisSvg;
+/** @type {ol.Map|undefined} */
+var map;
+
+/**
+ * Zooms and pans the visualization.
+ */
+function zoomAndPan() {
+ var g = gisSvg.getElementById('groupPanel');
+ if (!g) {
+ return;
+ }
+ $('#groupPanel', gisSvg).attr('transform', 'translate(' + x + ', ' + y + ') scale(' + scale + ')');
+ $('circle.vector', gisSvg).attr('r', 3 / scale);
+ $('circle.vector', gisSvg).attr('stroke-width', 2 / scale);
+ $('polyline.vector', gisSvg).attr('stroke-width', 2 / scale);
+ $('path.vector', gisSvg).attr('stroke-width', 0.5 / scale);
+}
+
+/**
+ * Initially loads either SVG or OSM visualization based on the choice.
+ */
+function selectVisualization() {
+ if ($('#choice').prop('checked') !== true) {
+ $('#openlayersmap').hide();
+ } else {
+ $('#placeholder').hide();
+ }
+}
+
+/**
+ * Adds necessary styles to the div that contains the openStreetMap.
+ */
+function styleOSM() {
+ var $placeholder = $('#placeholder');
+ var cssObj = {
+ 'border': '1px solid #aaa',
+ 'width': $placeholder.width(),
+ 'height': $placeholder.height(),
+ 'float': 'right'
+ };
+ $('#openlayersmap').css(cssObj);
+}
+
+/**
+ * Store a reference to the gis svg element.
+ */
+function storeGisSvgRef() {
+ gisSvg = $('#placeholder').find('svg').get(0);
+}
+
+/**
+ * Adds controls for zooming and panning.
+ */
+function addZoomPanControllers() {
+ if (!gisSvg) {
+ return;
+ }
+ var themeImagePath = $('#themeImagePath').val();
+ $('#placeholder').append(
+ // pan arrows
+ ' ', ' ', ' ', ' ',
+ // zoom controls
+ ' ', ' ', ' ');
+}
+
+/**
+ * Resizes the GIS visualization to fit into the space available.
+ */
+function resizeGISVisualization() {
+ var $placeholder = $('#placeholder');
+ var oldWidth = $placeholder.width();
+ var visWidth = $('#div_view_options').width() - 48;
+
+ // Assign new value for width
+ $placeholder.width(visWidth);
+ $(gisSvg).attr('width', visWidth);
+
+ // Assign the offset created due to resizing to defaultX and center the svg.
+ defaultX = (visWidth - oldWidth) / 2;
+ x = defaultX;
+ y = defaultY;
+ scale = defaultScale;
+}
+
+/**
+ * Initialize the GIS visualization.
+ */
+function initGISVisualization() {
+ storeGisSvgRef();
+ // Loads either SVG or OSM visualization based on the choice
+ selectVisualization();
+ // Resizes the GIS visualization to fit into the space available
+ resizeGISVisualization();
+ if (typeof ol !== 'undefined') {
+ // Adds necessary styles to the div that contains the openStreetMap
+ styleOSM();
+ }
+ // Adds controllers for zooming and panning
+ addZoomPanControllers();
+ zoomAndPan();
+}
+function drawOpenLayerMap() {
+ $('#placeholder').hide();
+ $('#openlayersmap').show();
+ // Function doesn't work properly if #openlayersmap is hidden
+ if (typeof map !== 'object') {
+ // Draws openStreetMap with openLayers
+ map = drawOpenLayers();
+ }
+}
+function getRelativeCoords(e) {
+ var position = $('#placeholder').offset();
+ return {
+ x: e.pageX - position.left,
+ y: e.pageY - position.top
+ };
+}
+
+/**
+ * @param {WheelEvent} event
+ */
+function onGisMouseWheel(event) {
+ if (event.deltaY === 0) {
+ return;
+ }
+ event.preventDefault();
+ var relCoords = getRelativeCoords(event);
+ var factor = event.deltaY > 0 ? zoomFactor : 1 / zoomFactor;
+ // zoom
+ scale *= factor;
+ // zooming keeping the position under mouse pointer unmoved.
+ x = relCoords.x - (relCoords.x - x) * factor;
+ y = relCoords.y - (relCoords.y - y) * factor;
+ zoomAndPan();
+}
+
+/**
+ * Ajax handlers for GIS visualization page
+ *
+ * Actions Ajaxified here:
+ *
+ * Zooming in and zooming out on mouse wheel movement.
+ * Panning the visualization on dragging.
+ * Zooming in on double clicking.
+ * Zooming out on clicking the zoom out button.
+ * Panning on clicking the arrow buttons.
+ * Displaying tooltips for GIS objects.
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/gis_visualization.js', function () {
+ $(document).off('click', '#choice');
+ $(document).off('dragstart', 'svg');
+ $(document).off('mouseup', 'svg');
+ $(document).off('drag', 'svg');
+ $(document).off('dblclick', '#placeholder');
+ $(document).off('click', '#zoom_in');
+ $(document).off('click', '#zoom_world');
+ $(document).off('click', '#zoom_out');
+ $(document).off('click', '#left_arrow');
+ $(document).off('click', '#right_arrow');
+ $(document).off('click', '#up_arrow');
+ $(document).off('click', '#down_arrow');
+ $('.vector').off('mousemove').off('mouseout');
+ $('#placeholder').get(0).removeEventListener('wheel', onGisMouseWheel, PASSIVE_EVENT_LISTENERS ? {
+ passive: false
+ } : undefined);
+ if (map) {
+ // Removes ol.Map's resize listener from window
+ map.setTarget(null);
+ map = undefined;
+ }
+});
+AJAX.registerOnload('table/gis_visualization.js', function () {
+ // If we are in GIS visualization, initialize it
+ if ($('#gis_div').length > 0) {
+ initGISVisualization();
+ }
+ if ($('#choice').prop('checked') === true) {
+ drawOpenLayerMap();
+ }
+ if (typeof ol === 'undefined') {
+ $('#choice, #labelChoice').hide();
+ }
+ $(document).on('click', '#choice', function () {
+ if ($(this).prop('checked') === false) {
+ $('#placeholder').show();
+ $('#openlayersmap').hide();
+ } else {
+ drawOpenLayerMap();
+ }
+ });
+ $('#placeholder').get(0).addEventListener('wheel', onGisMouseWheel, PASSIVE_EVENT_LISTENERS ? {
+ passive: false
+ } : undefined);
+ var dragX = 0;
+ var dragY = 0;
+ $('svg').draggable({
+ helper: function () {
+ return $(''); // Give a fake element to be used for dragging display
+ }
+ });
+
+ $(document).on('dragstart', 'svg', function (event, dd) {
+ $('#placeholder').addClass('placeholderDrag');
+ dragX = Math.round(dd.offset.left);
+ dragY = Math.round(dd.offset.top);
+ });
+ $(document).on('mouseup', 'svg', function () {
+ $('#placeholder').removeClass('placeholderDrag');
+ });
+ $(document).on('drag', 'svg', function (event, dd) {
+ var newX = Math.round(dd.offset.left);
+ x += newX - dragX;
+ dragX = newX;
+ var newY = Math.round(dd.offset.top);
+ y += newY - dragY;
+ dragY = newY;
+ zoomAndPan();
+ });
+ $(document).on('dblclick', '#placeholder', function (event) {
+ if (event.target.classList.contains('button')) {
+ return;
+ }
+ scale *= zoomFactor;
+ // zooming in keeping the position under mouse pointer unmoved.
+ var relCoords = getRelativeCoords(event);
+ x = relCoords.x - (relCoords.x - x) * zoomFactor;
+ y = relCoords.y - (relCoords.y - y) * zoomFactor;
+ zoomAndPan();
+ });
+ $(document).on('click', '#zoom_in', function (e) {
+ e.preventDefault();
+ // zoom in
+ scale *= zoomFactor;
+ var width = $(gisSvg).attr('width');
+ var height = $(gisSvg).attr('height');
+ // zooming in keeping the center unmoved.
+ x = width / 2 - (width / 2 - x) * zoomFactor;
+ y = height / 2 - (height / 2 - y) * zoomFactor;
+ zoomAndPan();
+ });
+ $(document).on('click', '#zoom_world', function (e) {
+ e.preventDefault();
+ scale = 1;
+ x = defaultX;
+ y = defaultY;
+ zoomAndPan();
+ });
+ $(document).on('click', '#zoom_out', function (e) {
+ e.preventDefault();
+ // zoom out
+ scale /= zoomFactor;
+ var width = $(gisSvg).attr('width');
+ var height = $(gisSvg).attr('height');
+ // zooming out keeping the center unmoved.
+ x = width / 2 - (width / 2 - x) / zoomFactor;
+ y = height / 2 - (height / 2 - y) / zoomFactor;
+ zoomAndPan();
+ });
+ $(document).on('click', '#left_arrow', function (e) {
+ e.preventDefault();
+ x += 100;
+ zoomAndPan();
+ });
+ $(document).on('click', '#right_arrow', function (e) {
+ e.preventDefault();
+ x -= 100;
+ zoomAndPan();
+ });
+ $(document).on('click', '#up_arrow', function (e) {
+ e.preventDefault();
+ y += 100;
+ zoomAndPan();
+ });
+ $(document).on('click', '#down_arrow', function (e) {
+ e.preventDefault();
+ y -= 100;
+ zoomAndPan();
+ });
+
+ /**
+ * Detect the mousemove event and show tooltips.
+ */
+ $('.vector').on('mousemove', function (event) {
+ var contents = Functions.escapeHtml($(this).attr('name')).trim();
+ $('#tooltip').remove();
+ if (contents !== '') {
+ $('
' + contents + '
').css({
+ position: 'absolute',
+ top: event.pageY + 10,
+ left: event.pageX + 10,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.90
+ }).appendTo('body').fadeIn(200);
+ }
+ });
+
+ /**
+ * Detect the mouseout event and hide tooltips.
+ */
+ $('.vector').on('mouseout', function () {
+ $('#tooltip').remove();
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/operations.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/operations.js
new file mode 100644
index 000000000..0bd292688
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/operations.js
@@ -0,0 +1,308 @@
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/operations.js', function () {
+ $(document).off('submit', '#copyTable.ajax');
+ $(document).off('submit', '#moveTableForm');
+ $(document).off('submit', '#tableOptionsForm');
+ $(document).off('submit', '#partitionsForm');
+ $(document).off('click', '#tbl_maintenance li a.maintain_action.ajax');
+ $(document).off('click', '#drop_tbl_anchor.ajax');
+ $(document).off('click', '#drop_view_anchor.ajax');
+ $(document).off('click', '#truncate_tbl_anchor.ajax');
+ $(document).off('click', '#delete_tbl_anchor.ajax');
+});
+
+/**
+ * Confirm and send POST request
+ *
+ * @param {JQuery} linkObject
+ * @param {'TRUNCATE'|'DELETE'} action
+ *
+ * @return {void}
+ */
+var confirmAndPost = function (linkObject, action) {
+ /**
+ * @var {String} question String containing the question to be asked for confirmation
+ */
+ var question = '';
+ if (action === 'TRUNCATE') {
+ question += Messages.strTruncateTableStrongWarning + ' ';
+ } else if (action === 'DELETE') {
+ question += Messages.strDeleteTableStrongWarning + ' ';
+ }
+ question += Functions.sprintf(Messages.strDoYouReally, linkObject.data('query'));
+ question += Functions.getForeignKeyCheckboxLoader();
+ linkObject.confirm(question, linkObject.attr('href'), function (url) {
+ Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ var params = Functions.getJsConfirmCommonParam(this, linkObject.getPostData());
+ $.post(url, params, function (data) {
+ if ($('.sqlqueryresults').length !== 0) {
+ $('.sqlqueryresults').remove();
+ }
+ if ($('.result_query').length !== 0) {
+ $('.result_query').remove();
+ }
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxShowMessage(data.message);
+ $('
').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.sql_query);
+ Functions.highlightSql($('#page_content'));
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ }, Functions.loadForeignKeyCheckbox);
+};
+
+/**
+ * jQuery coding for 'Table operations'. Used on /table/operations
+ * Attach Ajax Event handlers for Table operations
+ */
+AJAX.registerOnload('table/operations.js', function () {
+ /**
+ * Ajax action for submitting the "Copy table"
+ */
+ $(document).on('submit', '#copyTable.ajax', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ Functions.prepareForAjaxRequest($form);
+ var argsep = CommonParams.get('arg_separator');
+ $.post($form.attr('action'), $form.serialize() + argsep + 'submit_copy=Go', function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ if ($form.find('input[name=\'switch_to_new\']').prop('checked')) {
+ CommonParams.set('db', $form.find('select[name=\'target_db\'],input[name=\'target_db\']').val());
+ CommonParams.set('table', $form.find('input[name=\'new_name\']').val());
+ CommonActions.refreshMain(false, function () {
+ Functions.ajaxShowMessage(data.message);
+ });
+ } else {
+ Functions.ajaxShowMessage(data.message);
+ }
+ // Refresh navigation when the table is copied
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }); // end of copyTable ajax submit
+
+ /**
+ * Ajax action for submitting the "Move table"
+ */
+ $(document).on('submit', '#moveTableForm', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ Functions.prepareForAjaxRequest($form);
+ var argsep = CommonParams.get('arg_separator');
+ $.post($form.attr('action'), $form.serialize() + argsep + 'submit_move=1', function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ CommonParams.set('db', data.params.db);
+ CommonParams.set('table', data.params.table);
+ CommonActions.refreshMain('index.php?route=/table/sql', function () {
+ Functions.ajaxShowMessage(data.message);
+ });
+ // Refresh navigation when the table is copied
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+
+ /**
+ * Ajax action for submitting the "Table options"
+ */
+ $(document).on('submit', '#tableOptionsForm', function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ var $form = $(this);
+ var $tblNameField = $form.find('input[name=new_name]');
+ var $tblCollationField = $form.find('select[name=tbl_collation]');
+ var collationOrigValue = $('select[name="tbl_collation"] option[selected]').val();
+ var $changeAllColumnCollationsCheckBox = $('#checkbox_change_all_collations');
+ var question = Messages.strChangeAllColumnCollationsWarning;
+ if ($tblNameField.val() !== $tblNameField[0].defaultValue) {
+ // reload page and navigation if the table has been renamed
+ Functions.prepareForAjaxRequest($form);
+ if ($tblCollationField.val() !== collationOrigValue && $changeAllColumnCollationsCheckBox.is(':checked')) {
+ $form.confirm(question, $form.attr('action'), function () {
+ submitOptionsForm();
+ });
+ } else {
+ submitOptionsForm();
+ }
+ } else {
+ if ($tblCollationField.val() !== collationOrigValue && $changeAllColumnCollationsCheckBox.is(':checked')) {
+ $form.confirm(question, $form.attr('action'), function () {
+ $form.removeClass('ajax').trigger('submit').addClass('ajax');
+ });
+ } else {
+ $form.removeClass('ajax').trigger('submit').addClass('ajax');
+ }
+ }
+ function submitOptionsForm() {
+ $.post($form.attr('action'), $form.serialize(), function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ CommonParams.set('table', data.params.table);
+ CommonActions.refreshMain(false, function () {
+ $('#page_content').html(data.message);
+ Functions.highlightSql($('#page_content'));
+ });
+ // Refresh navigation when the table is renamed
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ }
+ });
+
+ /**
+ * Ajax events for actions in the "Table maintenance"
+ */
+ $(document).on('click', '#tbl_maintenance li a.maintain_action.ajax', function (event) {
+ event.preventDefault();
+ var $link = $(this);
+ if ($('.sqlqueryresults').length !== 0) {
+ $('.sqlqueryresults').remove();
+ }
+ if ($('.result_query').length !== 0) {
+ $('.result_query').remove();
+ }
+ // variables which stores the common attributes
+ var params = $.param({
+ 'ajax_request': 1,
+ 'server': CommonParams.get('server')
+ });
+ var postData = $link.getPostData();
+ if (postData) {
+ params += CommonParams.get('arg_separator') + postData;
+ }
+ $.post($link.attr('href'), params, function (data) {
+ function scrollToTop() {
+ $('html, body').animate({
+ scrollTop: 0
+ });
+ }
+ var $tempDiv;
+ if (typeof data !== 'undefined' && data.success === true && data.sql_query !== undefined) {
+ Functions.ajaxShowMessage(data.message);
+ $('
').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.sql_query);
+ Functions.highlightSql($('#page_content'));
+ scrollToTop();
+ } else if (typeof data !== 'undefined' && data.success === true) {
+ $tempDiv = $('
');
+ $tempDiv.html(data.message);
+ var $success = $tempDiv.find('.result_query .alert-success');
+ Functions.ajaxShowMessage($success);
+ $('
').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.message);
+ Functions.highlightSql($('#page_content'));
+ $('.sqlqueryresults').children('fieldset,br').remove();
+ scrollToTop();
+ } else {
+ $tempDiv = $('
');
+ $tempDiv.html(data.error);
+ var $error;
+ if ($tempDiv.find('.error code').length !== 0) {
+ $error = $tempDiv.find('.error code').addClass('error');
+ } else {
+ $error = $tempDiv;
+ }
+ Functions.ajaxShowMessage($error, false);
+ }
+ }); // end $.post()
+ }); // end of table maintenance ajax click
+
+ /**
+ * Ajax action for submitting the "Partition Maintenance"
+ * Also, asks for confirmation when DROP partition is submitted
+ */
+ $(document).on('submit', '#partitionsForm', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ function submitPartitionMaintenance() {
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ }
+ if ($('#partitionOperationRadioDrop').is(':checked')) {
+ $form.confirm(Messages.strDropPartitionWarning, $form.attr('action'), function () {
+ submitPartitionMaintenance();
+ });
+ } else if ($('#partitionOperationRadioTruncate').is(':checked')) {
+ $form.confirm(Messages.strTruncatePartitionWarning, $form.attr('action'), function () {
+ submitPartitionMaintenance();
+ });
+ } else {
+ submitPartitionMaintenance();
+ }
+ });
+ $(document).on('click', '#drop_tbl_anchor.ajax', function (event) {
+ event.preventDefault();
+ var $link = $(this);
+ /**
+ * @var {String} question String containing the question to be asked for confirmation
+ */
+ var question = Messages.strDropTableStrongWarning + ' ';
+ question += Functions.sprintf(Messages.strDoYouReally, $link[0].getAttribute('data-query'));
+ question += Functions.getForeignKeyCheckboxLoader();
+ $(this).confirm(question, $(this).attr('href'), function (url) {
+ var $msgbox = Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ var params = Functions.getJsConfirmCommonParam(this, $link.getPostData());
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxRemoveMessage($msgbox);
+ // Table deleted successfully, refresh both the frames
+ Navigation.reload();
+ CommonParams.set('table', '');
+ CommonActions.refreshMain(CommonParams.get('opendb_url'), function () {
+ Functions.ajaxShowMessage(data.message);
+ });
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ }, Functions.loadForeignKeyCheckbox);
+ }); // end of Drop Table Ajax action
+
+ $(document).on('click', '#drop_view_anchor.ajax', function (event) {
+ event.preventDefault();
+ var $link = $(this);
+ /**
+ * @var {String} question String containing the question to be asked for confirmation
+ */
+ var question = Messages.strDropTableStrongWarning + ' ';
+ question += Functions.sprintf(Messages.strDoYouReally, 'DROP VIEW `' + Functions.escapeHtml(CommonParams.get('table') + '`'));
+ $(this).confirm(question, $(this).attr('href'), function (url) {
+ var $msgbox = Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ var params = Functions.getJsConfirmCommonParam(this, $link.getPostData());
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxRemoveMessage($msgbox);
+ // Table deleted successfully, refresh both the frames
+ Navigation.reload();
+ CommonParams.set('table', '');
+ CommonActions.refreshMain(CommonParams.get('opendb_url'), function () {
+ Functions.ajaxShowMessage(data.message);
+ });
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ });
+ });
+ }); // end of Drop View Ajax action
+
+ $(document).on('click', '#truncate_tbl_anchor.ajax', function (event) {
+ event.preventDefault();
+ confirmAndPost($(this), 'TRUNCATE');
+ });
+ $(document).on('click', '#delete_tbl_anchor.ajax', function (event) {
+ event.preventDefault();
+ confirmAndPost($(this), 'DELETE');
+ });
+}); // end $(document).ready for 'Table operations'
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/relation.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/relation.js
new file mode 100644
index 000000000..1810d34cf
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/relation.js
@@ -0,0 +1,208 @@
+/**
+ * for table relation
+ */
+
+var TableRelation = {};
+TableRelation.showHideClauses = function ($thisDropdown) {
+ if ($thisDropdown.val() === '') {
+ $thisDropdown.parent().nextAll('span').hide();
+ } else {
+ if ($thisDropdown.is('select[name^="destination_foreign_column"]')) {
+ $thisDropdown.parent().nextAll('span').show();
+ }
+ }
+};
+
+/**
+ * Sets dropdown options to values
+ * @param $dropdown
+ * @param values
+ * @param selectedValue
+ * @return {void}
+ */
+TableRelation.setDropdownValues = function ($dropdown, values, selectedValue) {
+ $dropdown.empty();
+ var optionsAsString = '';
+ // add an empty string to the beginning for empty selection
+ values.unshift('');
+ $.each(values, function () {
+ optionsAsString += '
' + Functions.escapeHtml(this) + ' ';
+ });
+ $dropdown.append($(optionsAsString));
+};
+
+/**
+ * Retrieves and populates dropdowns to the left based on the selected value
+ *
+ * @param $dropdown the dropdown whose value got changed
+ * @return {void}
+ */
+TableRelation.getDropdownValues = function ($dropdown) {
+ var foreignDb = null;
+ var foreignTable = null;
+ var $databaseDd;
+ var $tableDd;
+ var $columnDd;
+ var foreign = '';
+ // if the changed dropdown is for foreign key constraints
+ if ($dropdown.is('select[name^="destination_foreign"]')) {
+ $databaseDd = $dropdown.parent().parent().parent().find('select[name^="destination_foreign_db"]');
+ $tableDd = $dropdown.parent().parent().parent().find('select[name^="destination_foreign_table"]');
+ $columnDd = $dropdown.parent().parent().parent().find('select[name^="destination_foreign_column"]');
+ foreign = '_foreign';
+ } else {
+ // internal relations
+ $databaseDd = $dropdown.parent().find('select[name^="destination_db"]');
+ $tableDd = $dropdown.parent().find('select[name^="destination_table"]');
+ $columnDd = $dropdown.parent().find('select[name^="destination_column"]');
+ }
+
+ // if the changed dropdown is a database selector
+ if ($dropdown.is('select[name^="destination' + foreign + '_db"]')) {
+ foreignDb = $dropdown.val();
+ // if no database is selected empty table and column dropdowns
+ if (foreignDb === '') {
+ TableRelation.setDropdownValues($tableDd, []);
+ TableRelation.setDropdownValues($columnDd, []);
+ return;
+ }
+ } else {
+ // if a table selector
+ foreignDb = $databaseDd.val();
+ foreignTable = $dropdown.val();
+ // if no table is selected empty the column dropdown
+ if (foreignTable === '') {
+ TableRelation.setDropdownValues($columnDd, []);
+ return;
+ }
+ }
+ var $msgbox = Functions.ajaxShowMessage();
+ var $form = $dropdown.parents('form');
+ var $db = $form.find('input[name="db"]').val();
+ var $table = $form.find('input[name="table"]').val();
+ var argsep = CommonParams.get('arg_separator');
+ var params = 'getDropdownValues=true' + argsep + 'ajax_request=true' + argsep + 'db=' + encodeURIComponent($db) + argsep + 'table=' + encodeURIComponent($table) + argsep + 'foreign=' + (foreign !== '') + argsep + 'foreignDb=' + encodeURIComponent(foreignDb) + (foreignTable !== null ? argsep + 'foreignTable=' + encodeURIComponent(foreignTable) : '');
+ var $server = $form.find('input[name="server"]');
+ if ($server.length > 0) {
+ params += argsep + 'server=' + $form.find('input[name="server"]').val();
+ }
+ $.ajax({
+ type: 'POST',
+ url: 'index.php?route=/table/relation',
+ data: params,
+ dataType: 'json',
+ success: function (data) {
+ Functions.ajaxRemoveMessage($msgbox);
+ if (typeof data !== 'undefined' && data.success) {
+ // if the changed dropdown is a database selector
+ if (foreignTable === null) {
+ // set values for table and column dropdowns
+ TableRelation.setDropdownValues($tableDd, data.tables);
+ TableRelation.setDropdownValues($columnDd, []);
+ } else {
+ // if a table selector
+ // set values for the column dropdown
+ var primary = null;
+ if (typeof data.primary !== 'undefined' && 1 === data.primary.length) {
+ primary = data.primary[0];
+ }
+ TableRelation.setDropdownValues($columnDd.first(), data.columns, primary);
+ TableRelation.setDropdownValues($columnDd.slice(1), data.columns);
+ }
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+};
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/relation.js', function () {
+ $('body').off('change', 'select[name^="destination_db"], ' + 'select[name^="destination_table"], ' + 'select[name^="destination_foreign_db"], ' + 'select[name^="destination_foreign_table"]');
+ $('body').off('click', 'a.add_foreign_key_field');
+ $('body').off('click', 'a.add_foreign_key');
+ $('a.drop_foreign_key_anchor.ajax').off('click');
+});
+AJAX.registerOnload('table/relation.js', function () {
+ /**
+ * Ajax event handler to fetch table/column dropdown values.
+ */
+ $('body').on('change', 'select[name^="destination_db"], ' + 'select[name^="destination_table"], ' + 'select[name^="destination_foreign_db"], ' + 'select[name^="destination_foreign_table"]', function () {
+ TableRelation.getDropdownValues($(this));
+ });
+
+ /**
+ * Ajax event handler to add a column to a foreign key constraint.
+ */
+ $('body').on('click', 'a.add_foreign_key_field', function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ // Add field.
+ $(this).prev('span').clone(true, true).insertBefore($(this)).find('select').val('');
+
+ // Add foreign field.
+ var $sourceElem = $('select[name^="destination_foreign_column[' + $(this).attr('data-index') + ']"]').last().parent();
+ $sourceElem.clone(true, true).insertAfter($sourceElem).find('select').val('');
+ });
+
+ /**
+ * Ajax event handler to add a foreign key constraint.
+ */
+ $('body').on('click', 'a.add_foreign_key', function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ var $prevRow = $(this).closest('tr').prev('tr');
+ var $newRow = $prevRow.clone(true, true);
+
+ // Update serial number.
+ var currIndex = $newRow.find('a.add_foreign_key_field').attr('data-index');
+ var newIndex = parseInt(currIndex) + 1;
+ $newRow.find('a.add_foreign_key_field').attr('data-index', newIndex);
+
+ // Update form parameter names.
+ $newRow.find('select[name^="foreign_key_fields_name"]').not($newRow.find('select[name^="foreign_key_fields_name"]').first()).find('select[name^="destination_foreign_column"]').not($newRow.find('select[name^="foreign_key_fields_name"]').not($newRow.find('select[name^="foreign_key_fields_name"]').first()).find('select[name^="destination_foreign_column"]').first()).each(function () {
+ $(this).parent().remove();
+ });
+ $newRow.find('input, select').each(function () {
+ $(this).attr('name', $(this).attr('name').replace(/\d/, newIndex));
+ });
+ $newRow.find('input[type="text"]').each(function () {
+ $(this).val('');
+ });
+ // Finally add the row.
+ $newRow.insertAfter($prevRow);
+ });
+
+ /**
+ * Ajax Event handler for 'Drop Foreign key'
+ */
+ $('a.drop_foreign_key_anchor.ajax').on('click', function (event) {
+ event.preventDefault();
+ var $anchor = $(this);
+
+ // Object containing reference to the current field's row
+ var $currRow = $anchor.parents('tr');
+ var dropQuery = Functions.escapeHtml($currRow.children('td').children('.drop_foreign_key_msg').val());
+ var question = Functions.sprintf(Messages.strDoYouReally, dropQuery);
+ $anchor.confirm(question, $anchor.attr('href'), function (url) {
+ var $msg = Functions.ajaxShowMessage(Messages.strDroppingForeignKey, false);
+ var params = Functions.getJsConfirmCommonParam(this, $anchor.getPostData());
+ $.post(url, params, function (data) {
+ if (data.success === true) {
+ Functions.ajaxRemoveMessage($msg);
+ CommonActions.refreshMain(false, function () {
+ // Do nothing
+ });
+ } else {
+ Functions.ajaxShowMessage(Messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ });
+ }); // end Drop Foreign key
+
+ var windowWidth = $(window).width();
+ $('.jsresponsive').css('max-width', windowWidth - 35 + 'px');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/select.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/select.js
new file mode 100644
index 000000000..08f569c32
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/select.js
@@ -0,0 +1,299 @@
+/**
+ * @fileoverview JavaScript functions used on /table/search
+ *
+ * @requires jQuery
+ * @requires js/functions.js
+ */
+
+/* global changeValueFieldType, verifyAfterSearchFieldChange */ // js/table/change.js
+/* global openGISEditor, gisEditorLoaded, loadJSAndGISEditor, loadGISEditor */ // js/gis_data_editor.js
+
+var TableSelect = {};
+
+/**
+ * Checks if given data-type is numeric or date.
+ *
+ * @param {string} dataType Column data-type
+ *
+ * @return {boolean | string}
+ */
+TableSelect.checkIfDataTypeNumericOrDate = function (dataType) {
+ // To test for numeric data-types.
+ var numericRegExp = new RegExp('TINYINT|SMALLINT|MEDIUMINT|INT|BIGINT|DECIMAL|FLOAT|DOUBLE|REAL', 'i');
+
+ // To test for date data-types.
+ var dateRegExp = new RegExp('DATETIME|DATE|TIMESTAMP|TIME|YEAR', 'i');
+
+ // Return matched data-type
+ if (numericRegExp.test(dataType)) {
+ return numericRegExp.exec(dataType)[0];
+ }
+ if (dateRegExp.test(dataType)) {
+ return dateRegExp.exec(dataType)[0];
+ }
+ return false;
+};
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/select.js', function () {
+ $('#togglesearchformlink').off('click');
+ $(document).off('submit', '#tbl_search_form.ajax');
+ $('select.geom_func').off('change');
+ $(document).off('click', 'span.open_search_gis_editor');
+ $('body').off('change', 'select[name*="criteriaColumnOperators"]'); // Fix for bug #13778, changed 'click' to 'change'
+});
+
+AJAX.registerOnload('table/select.js', function () {
+ /**
+ * Prepare a div containing a link, otherwise it's incorrectly displayed
+ * after a couple of clicks
+ */
+ $('
').insertAfter('#tbl_search_form')
+ // don't show it until we have results on-screen
+ .hide();
+ $('#togglesearchformlink').html(Messages.strShowSearchCriteria).on('click', function () {
+ var $link = $(this);
+ $('#tbl_search_form').slideToggle();
+ if ($link.text() === Messages.strHideSearchCriteria) {
+ $link.text(Messages.strShowSearchCriteria);
+ } else {
+ $link.text(Messages.strHideSearchCriteria);
+ }
+ // avoid default click action
+ return false;
+ });
+ var tableRows = $('#fieldset_table_qbe select.column-operator');
+ $.each(tableRows, function (index, item) {
+ $(item).on('change', function () {
+ changeValueFieldType(this, index);
+ verifyAfterSearchFieldChange(index, '#tbl_search_form');
+ });
+ });
+
+ /**
+ * Ajax event handler for Table search
+ */
+ $(document).on('submit', '#tbl_search_form.ajax', function (event) {
+ var unaryFunctions = ['IS NULL', 'IS NOT NULL', '= \'\'', '!= \'\''];
+ var geomUnaryFunctions = ['IsEmpty', 'IsSimple', 'IsRing', 'IsClosed'];
+
+ // jQuery object to reuse
+ var $searchForm = $(this);
+ event.preventDefault();
+
+ // empty previous search results while we are waiting for new results
+ $('#sqlqueryresultsouter').empty();
+ var $msgbox = Functions.ajaxShowMessage(Messages.strSearching, false);
+ Functions.prepareForAjaxRequest($searchForm);
+ var values = {};
+ $searchForm.find(':input').each(function () {
+ var $input = $(this);
+ if ($input.attr('type') === 'checkbox' || $input.attr('type') === 'radio') {
+ if ($input.is(':checked')) {
+ values[this.name] = $input.val();
+ }
+ } else {
+ values[this.name] = $input.val();
+ }
+ });
+ var columnCount = $('select[name="columnsToDisplay[]"] option').length;
+ // Submit values only for the columns that have unary column operator or a search criteria
+ for (var a = 0; a < columnCount; a++) {
+ if ($.inArray(values['criteriaColumnOperators[' + a + ']'], unaryFunctions) >= 0) {
+ continue;
+ }
+ if (values['geom_func[' + a + ']'] && $.inArray(values['geom_func[' + a + ']'], geomUnaryFunctions) >= 0) {
+ continue;
+ }
+ if (values['criteriaValues[' + a + ']'] === '' || values['criteriaValues[' + a + ']'] === null) {
+ delete values['criteriaValues[' + a + ']'];
+ delete values['criteriaColumnOperators[' + a + ']'];
+ delete values['criteriaColumnNames[' + a + ']'];
+ delete values['criteriaColumnTypes[' + a + ']'];
+ delete values['criteriaColumnCollations[' + a + ']'];
+ }
+ }
+ // If all columns are selected, use a single parameter to indicate that
+ if (values['columnsToDisplay[]'] !== null) {
+ if (values['columnsToDisplay[]'].length === columnCount) {
+ delete values['columnsToDisplay[]'];
+ values.displayAllColumns = true;
+ }
+ } else {
+ values.displayAllColumns = true;
+ }
+ $.post($searchForm.attr('action'), values, function (data) {
+ Functions.ajaxRemoveMessage($msgbox);
+ if (typeof data !== 'undefined' && data.success === true) {
+ if (typeof data.sql_query !== 'undefined') {
+ // zero rows
+ $('#sqlqueryresultsouter').html(data.sql_query);
+ } else {
+ // results found
+ $('#sqlqueryresultsouter').html(data.message);
+ $('.sqlqueryresults').trigger('makegrid');
+ }
+ $('#tbl_search_form')
+ // workaround for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
+ .slideToggle().hide();
+ $('#togglesearchformlink')
+ // always start with the Show message
+ .text(Messages.strShowSearchCriteria);
+ $('#togglesearchformdiv')
+ // now it's time to show the div containing the link
+ .show();
+ $('html, body').animate({
+ scrollTop: 0
+ }, 'fast');
+ } else {
+ $('#sqlqueryresultsouter').html(data.error);
+ }
+ Functions.highlightSql($('#sqlqueryresultsouter'));
+ }); // end $.post()
+ });
+
+ // Following section is related to the 'function based search' for geometry data types.
+ // Initially hide all the open_gis_editor spans
+ $('span.open_search_gis_editor').hide();
+ $('select.geom_func').on('change', function () {
+ var $geomFuncSelector = $(this);
+ var binaryFunctions = ['Contains', 'Crosses', 'Disjoint', 'Equals', 'Intersects', 'Overlaps', 'Touches', 'Within', 'MBRContains', 'MBRDisjoint', 'MBREquals', 'MBRIntersects', 'MBROverlaps', 'MBRTouches', 'MBRWithin', 'ST_Contains', 'ST_Crosses', 'ST_Disjoint', 'ST_Equals', 'ST_Intersects', 'ST_Overlaps', 'ST_Touches', 'ST_Within'];
+ var tempArray = ['Envelope', 'EndPoint', 'StartPoint', 'ExteriorRing', 'Centroid', 'PointOnSurface'];
+ var outputGeomFunctions = binaryFunctions.concat(tempArray);
+
+ // If the chosen function takes two geometry objects as parameters
+ var $operator = $geomFuncSelector.parents('tr').find('td').eq(4).find('select');
+ if ($.inArray($geomFuncSelector.val(), binaryFunctions) >= 0) {
+ $operator.prop('readonly', true);
+ } else {
+ $operator.prop('readonly', false);
+ }
+
+ // if the chosen function's output is a geometry, enable GIS editor
+ var $editorSpan = $geomFuncSelector.parents('tr').find('span.open_search_gis_editor');
+ if ($.inArray($geomFuncSelector.val(), outputGeomFunctions) >= 0) {
+ $editorSpan.show();
+ } else {
+ $editorSpan.hide();
+ }
+ });
+ $(document).on('click', 'span.open_search_gis_editor', function (event) {
+ event.preventDefault();
+ var $span = $(this);
+ // Current value
+ var value = $span.parent('td').children('input[type=\'text\']').val();
+ // Field name
+ var field = 'Parameter';
+ // Column type
+ var geomFunc = $span.parents('tr').find('.geom_func').val();
+ var type;
+ if (geomFunc === 'Envelope') {
+ type = 'polygon';
+ } else if (geomFunc === 'ExteriorRing') {
+ type = 'linestring';
+ } else {
+ type = 'point';
+ }
+ // Names of input field and null checkbox
+ var inputName = $span.parent('td').children('input[type=\'text\']').attr('name');
+ // Token
+
+ openGISEditor();
+ if (!gisEditorLoaded) {
+ loadJSAndGISEditor(value, field, type, inputName);
+ } else {
+ loadGISEditor(value, field, type, inputName);
+ }
+ });
+
+ /**
+ * Ajax event handler for Range-Search.
+ */
+ $('body').on('change', 'select[name*="criteriaColumnOperators"]', function () {
+ // Fix for bug #13778, changed 'click' to 'change'
+ var $sourceSelect = $(this);
+ // Get the column name.
+ var columnName = $(this).closest('tr').find('th').first().text();
+
+ // Get the data-type of column excluding size.
+ var dataType = $(this).closest('tr').find('td[data-type]').attr('data-type');
+ dataType = TableSelect.checkIfDataTypeNumericOrDate(dataType);
+
+ // Get the operator.
+ var operator = $(this).val();
+ if ((operator === 'BETWEEN' || operator === 'NOT BETWEEN') && dataType) {
+ var $msgbox = Functions.ajaxShowMessage();
+ $.ajax({
+ url: 'index.php?route=/table/search',
+ type: 'POST',
+ data: {
+ 'server': CommonParams.get('server'),
+ 'ajax_request': 1,
+ 'db': $('input[name="db"]').val(),
+ 'table': $('input[name="table"]').val(),
+ 'column': columnName,
+ 'range_search': 1
+ },
+ success: function (response) {
+ Functions.ajaxRemoveMessage($msgbox);
+ if (response.success) {
+ // Get the column min value.
+ var min = response.column_data.min ? '(' + Messages.strColumnMin + ' ' + response.column_data.min + ')' : '';
+ // Get the column max value.
+ var max = response.column_data.max ? '(' + Messages.strColumnMax + ' ' + response.column_data.max + ')' : '';
+ $('#rangeSearchModal').modal('show');
+ $('#rangeSearchLegend').first().html(operator);
+ $('#rangeSearchMin').first().text(min);
+ $('#rangeSearchMax').first().text(max);
+ // Reset input values on reuse
+ $('#min_value').first().val('');
+ $('#max_value').first().val('');
+ // Add datepicker wherever required.
+ Functions.addDatepicker($('#min_value'), dataType);
+ Functions.addDatepicker($('#max_value'), dataType);
+ $('#rangeSearchModalGo').on('click', function () {
+ var minValue = $('#min_value').val();
+ var maxValue = $('#max_value').val();
+ var finalValue = '';
+ if (minValue.length && maxValue.length) {
+ finalValue = minValue + ', ' + maxValue;
+ }
+ var $targetField = $sourceSelect.closest('tr').find('[name*="criteriaValues"]');
+
+ // If target field is a select list.
+ if ($targetField.is('select')) {
+ $targetField.val(finalValue);
+ var $options = $targetField.find('option');
+ var $closestMin = null;
+ var $closestMax = null;
+ // Find closest min and max value.
+ $options.each(function () {
+ if ($closestMin === null || Math.abs($(this).val() - minValue) < Math.abs($closestMin.val() - minValue)) {
+ $closestMin = $(this);
+ }
+ if ($closestMax === null || Math.abs($(this).val() - maxValue) < Math.abs($closestMax.val() - maxValue)) {
+ $closestMax = $(this);
+ }
+ });
+ $closestMin.attr('selected', 'selected');
+ $closestMax.attr('selected', 'selected');
+ } else {
+ $targetField.val(finalValue);
+ }
+ $('#rangeSearchModal').modal('hide');
+ });
+ } else {
+ Functions.ajaxShowMessage(response.error);
+ }
+ },
+ error: function () {
+ Functions.ajaxShowMessage(Messages.strErrorProcessingRequest);
+ }
+ });
+ }
+ });
+ var windowWidth = $(window).width();
+ $('.jsresponsive').css('max-width', windowWidth - 69 + 'px');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/structure.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/structure.js
new file mode 100644
index 000000000..8ea84caf0
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/structure.js
@@ -0,0 +1,416 @@
+/**
+ * @fileoverview functions used on the table structure page
+ * @name Table Structure
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @required js/functions.js
+ */
+
+// eslint-disable-next-line no-unused-vars
+/* global primaryIndexes:writable, indexes:writable, fulltextIndexes:writable, spatialIndexes:writable */ // js/functions.js
+/* global sprintf */ // js/vendor/sprintf.js
+
+/**
+ * AJAX scripts for /table/structure
+ *
+ * Actions ajaxified here:
+ * Drop Column
+ * Add Primary Key
+ * Drop Primary Key/Index
+ *
+ */
+
+/**
+ * Reload fields table
+ */
+function reloadFieldForm() {
+ $.post($('#fieldsForm').attr('action'), $('#fieldsForm').serialize() + CommonParams.get('arg_separator') + 'ajax_request=true', function (formData) {
+ var $tempDiv = $('
').append(formData.message);
+ $('#fieldsForm').replaceWith($tempDiv.find('#fieldsForm'));
+ $('#addColumns').replaceWith($tempDiv.find('#addColumns'));
+ $('#move_columns_dialog').find('ul').replaceWith($tempDiv.find('#move_columns_dialog ul'));
+ });
+ $('#page_content').show();
+}
+function checkFirst() {
+ if ($('select[name=after_field] option:selected').data('pos') === 'first') {
+ $('input[name=field_where]').val('first');
+ } else {
+ $('input[name=field_where]').val('after');
+ }
+}
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/structure.js', function () {
+ $(document).off('click', 'a.drop_column_anchor.ajax');
+ $(document).off('click', 'a.add_key.ajax');
+ $(document).off('click', '#move_columns_anchor');
+ $(document).off('submit', '.append_fields_form.ajax');
+ $('body').off('click', '#fieldsForm button.mult_submit');
+ $(document).off('click', 'a[id^=partition_action].ajax');
+ $(document).off('click', '#remove_partitioning.ajax');
+});
+AJAX.registerOnload('table/structure.js', function () {
+ // Re-initialize variables.
+ primaryIndexes = [];
+ indexes = [];
+ fulltextIndexes = [];
+ spatialIndexes = [];
+
+ /**
+ *Ajax action for submitting the "Column Change" and "Add Column" form
+ */
+ $('.append_fields_form.ajax').off();
+ $(document).on('submit', '.append_fields_form.ajax', function (event) {
+ event.preventDefault();
+ /**
+ * @var form object referring to the export form
+ */
+ var $form = $(this);
+ var fieldCnt = $form.find('input[name=orig_num_fields]').val();
+ function submitForm() {
+ var $msg = Functions.ajaxShowMessage(Messages.strProcessingRequest);
+ $.post($form.attr('action'), $form.serialize() + CommonParams.get('arg_separator') + 'do_save_data=1', function (data) {
+ if ($('.sqlqueryresults').length !== 0) {
+ $('.sqlqueryresults').remove();
+ } else if ($('.error:not(.tab)').length !== 0) {
+ $('.error:not(.tab)').remove();
+ }
+ if (typeof data.success !== 'undefined' && data.success === true) {
+ $('#page_content').empty().append(data.message).show();
+ Functions.highlightSql($('#page_content'));
+ $('.result_query .alert-primary').remove();
+ if (typeof data.structure_refresh_route !== 'string') {
+ // Do not reload the form when the code below freshly filled it
+ reloadFieldForm();
+ }
+ $form.remove();
+ Functions.ajaxRemoveMessage($msg);
+ Navigation.reload();
+ if (typeof data.structure_refresh_route === 'string') {
+ // Fetch the table structure right after adding a new column
+ $.get(data.structure_refresh_route, function (data) {
+ if (typeof data.success !== 'undefined' && data.success === true) {
+ $('#page_content').append(data.message).show();
+ }
+ });
+ } else {
+ CommonActions.refreshMain('index.php?route=/table/structure');
+ }
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }
+
+ function checkIfConfirmRequired($form) {
+ var i = 0;
+ var id;
+ var elm;
+ var val;
+ var nameOrig;
+ var elmOrig;
+ var valOrig;
+ var checkRequired = false;
+ for (i = 0; i < fieldCnt; i++) {
+ id = '#field_' + i + '_5';
+ elm = $(id);
+ val = elm.val();
+ nameOrig = 'input[name=field_collation_orig\\[' + i + '\\]]';
+ elmOrig = $form.find(nameOrig);
+ valOrig = elmOrig.val();
+ if (val && valOrig && val !== valOrig) {
+ checkRequired = true;
+ break;
+ }
+ }
+ return checkRequired;
+ }
+
+ /*
+ * First validate the form; if there is a problem, avoid submitting it
+ *
+ * Functions.checkTableEditForm() needs a pure element and not a jQuery object,
+ * this is why we pass $form[0] as a parameter (the jQuery object
+ * is actually an array of DOM elements)
+ */
+ if (Functions.checkTableEditForm($form[0], fieldCnt)) {
+ // OK, form passed validation step
+
+ Functions.prepareForAjaxRequest($form);
+ if (Functions.checkReservedWordColumns($form)) {
+ // User wants to submit the form
+
+ // If Collation is changed, Warn and Confirm
+ if (checkIfConfirmRequired($form)) {
+ var question = sprintf(Messages.strChangeColumnCollation, 'https://wiki.phpmyadmin.net/pma/Garbled_data');
+ $form.confirm(question, $form.attr('action'), function () {
+ submitForm();
+ });
+ } else {
+ submitForm();
+ }
+ }
+ }
+ }); // end change table button "do_save_data"
+
+ /**
+ * Attach Event Handler for 'Drop Column'
+ */
+ $(document).on('click', 'a.drop_column_anchor.ajax', function (event) {
+ event.preventDefault();
+ /**
+ * @var currTableName String containing the name of the current table
+ */
+ var currTableName = $(this).closest('form').find('input[name=table]').val();
+ /**
+ * @var currRow Object reference to the currently selected row (i.e. field in the table)
+ */
+ var $currRow = $(this).parents('tr');
+ /**
+ * @var currColumnName String containing name of the field referred to by {@link curr_row}
+ */
+ var currColumnName = $currRow.children('th').children('label').text().trim();
+ currColumnName = Functions.escapeHtml(currColumnName);
+ /**
+ * @var $afterFieldItem Corresponding entry in the 'After' field.
+ */
+ var $afterFieldItem = $('select[name=\'after_field\'] option[value=\'' + currColumnName + '\']');
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = Functions.sprintf(Messages.strDoYouReally, 'ALTER TABLE `' + currTableName + '` DROP `' + currColumnName + '`;');
+ var $thisAnchor = $(this);
+ $thisAnchor.confirm(question, $thisAnchor.attr('href'), function (url) {
+ var $msg = Functions.ajaxShowMessage(Messages.strDroppingColumn, false);
+ var params = Functions.getJsConfirmCommonParam(this, $thisAnchor.getPostData());
+ params += CommonParams.get('arg_separator') + 'ajax_page_request=1';
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ Functions.ajaxRemoveMessage($msg);
+ if ($('.result_query').length) {
+ $('.result_query').remove();
+ }
+ if (data.sql_query) {
+ $('
').html(data.sql_query).prependTo('#structure_content');
+ Functions.highlightSql($('#page_content'));
+ }
+ // Adjust the row numbers
+ for (var $row = $currRow.next(); $row.length > 0; $row = $row.next()) {
+ var newVal = parseInt($row.find('td').eq(1).text(), 10) - 1;
+ $row.find('td').eq(1).text(newVal);
+ }
+ $afterFieldItem.remove();
+ $currRow.hide('medium').remove();
+
+ // Remove the dropped column from select menu for 'after field'
+ $('select[name=after_field]').find('[value="' + currColumnName + '"]').remove();
+
+ // by default select the (new) last option to add new column
+ // (in case last column is dropped)
+ $('select[name=after_field] option').last().attr('selected', 'selected');
+
+ // refresh table stats
+ if (data.tableStat) {
+ $('#tablestatistics').html(data.tableStat);
+ }
+ // refresh the list of indexes (comes from /sql)
+ $('.index_info').replaceWith(data.indexes_list);
+ Navigation.reload();
+ } else {
+ Functions.ajaxShowMessage(Messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ });
+ }); // end of Drop Column Anchor action
+
+ /**
+ * Ajax Event handler for adding keys
+ */
+ $(document).on('click', 'a.add_key.ajax', function (event) {
+ event.preventDefault();
+ var $this = $(this);
+ var currTableName = $this.closest('form').find('input[name=table]').val();
+ var currColumnName = $this.parents('tr').children('th').children('label').text().trim();
+ var addClause = '';
+ if ($this.is('.add_primary_key_anchor')) {
+ addClause = 'ADD PRIMARY KEY';
+ } else if ($this.is('.add_index_anchor')) {
+ addClause = 'ADD INDEX';
+ } else if ($this.is('.add_unique_anchor')) {
+ addClause = 'ADD UNIQUE';
+ } else if ($this.is('.add_spatial_anchor')) {
+ addClause = 'ADD SPATIAL';
+ } else if ($this.is('.add_fulltext_anchor')) {
+ addClause = 'ADD FULLTEXT';
+ }
+ var question = Functions.sprintf(Messages.strDoYouReally, 'ALTER TABLE `' + Functions.escapeHtml(currTableName) + '` ' + addClause + '(`' + Functions.escapeHtml(currColumnName) + '`);');
+ var $thisAnchor = $(this);
+ $thisAnchor.confirm(question, $thisAnchor.attr('href'), function (url) {
+ Functions.ajaxShowMessage();
+ AJAX.source = $this;
+ var params = Functions.getJsConfirmCommonParam(this, $thisAnchor.getPostData());
+ params += CommonParams.get('arg_separator') + 'ajax_page_request=1';
+ $.post(url, params, AJAX.responseHandler);
+ });
+ }); // end Add key
+
+ /**
+ * Inline move columns
+ **/
+ $(document).on('click', '#move_columns_anchor', function (e) {
+ e.preventDefault();
+ var buttonOptionsError = {};
+ buttonOptionsError[Messages.strOK] = function () {
+ $(this).dialog('close').remove();
+ };
+ var columns = [];
+ $('#tablestructure').find('tbody tr').each(function () {
+ var colName = $(this).find('input:checkbox').eq(0).val();
+ var hiddenInput = $('
').prop({
+ name: 'move_columns[]',
+ type: 'hidden'
+ }).val(colName);
+ columns[columns.length] = $('
').addClass('placeholderDrag').text(colName).append(hiddenInput);
+ });
+ var colList = $('#move_columns_dialog').find('ul').find('li').remove().end();
+ for (var i in columns) {
+ colList.append(columns[i]);
+ }
+ colList.sortable({
+ axis: 'y',
+ containment: $('#move_columns_dialog').find('div'),
+ tolerance: 'pointer'
+ }).disableSelection();
+ var $form = $('#move_columns_dialog').find('form');
+ $form.data('serialized-unmoved', $form.serialize());
+ const designerModalPreviewModal = document.getElementById('designerModalPreviewModal');
+ designerModalPreviewModal.addEventListener('shown.bs.modal', () => {
+ const modalBody = designerModalPreviewModal.querySelector('.modal-body');
+ const $form = $('#move_column_form');
+ const formUrl = $form.attr('action');
+ const sep = CommonParams.get('arg_separator');
+ const formData = $form.serialize() + sep + 'preview_sql=1' + sep + 'ajax_request=1';
+ $.post({
+ url: formUrl,
+ data: formData,
+ success: response => {
+ if (!response.success) {
+ modalBody.innerHTML = '
' + Messages.strErrorProcessingRequest + '
';
+ return;
+ }
+ modalBody.innerHTML = response.sql_data;
+ Functions.highlightSql($('#designerModalPreviewModal'));
+ },
+ error: () => {
+ modalBody.innerHTML = '
' + Messages.strErrorProcessingRequest + '
';
+ }
+ });
+ });
+ designerModalPreviewModal.addEventListener('hidden.bs.modal', () => {
+ designerModalPreviewModal.querySelector('.modal-body').innerHTML = '
' + '' + Messages.strLoading + '
';
+ });
+ $('#moveColumnsModal').modal('show');
+ $('#designerModalGoButton').off('click'); // Unregister previous modals
+ $('#designerModalGoButton').on('click', function () {
+ event.preventDefault();
+ var $msgbox = Functions.ajaxShowMessage();
+ var $this = $('#moveColumnsModal');
+ var $form = $this.find('form');
+ var serialized = $form.serialize();
+ // check if any columns were moved at all
+ $('#moveColumnsModal').modal('hide');
+ if (serialized === $form.data('serialized-unmoved')) {
+ Functions.ajaxRemoveMessage($msgbox);
+ return;
+ }
+ $.post($form.prop('action'), serialized + CommonParams.get('arg_separator') + 'ajax_request=true', function (data) {
+ if (data.success === false) {
+ Functions.ajaxRemoveMessage($msgbox);
+ var errorModal = $('#moveColumnsErrorModal');
+ errorModal.modal('show');
+ errorModal.find('.modal-body').first().html(data.error);
+ } else {
+ // sort the fields table
+ var $fieldsTable = $('table#tablestructure tbody');
+ // remove all existing rows and remember them
+ var $rows = $fieldsTable.find('tr').remove();
+ // loop through the correct order
+ for (var i in data.columns) {
+ var theColumn = data.columns[i];
+ var $theRow = $rows.find('input:checkbox[value=\'' + theColumn + '\']').closest('tr');
+ // append the row for this column to the table
+ $fieldsTable.append($theRow);
+ }
+ var $firstrow = $fieldsTable.find('tr').eq(0);
+ // Adjust the row numbers and colors
+ for (var $row = $firstrow; $row.length > 0; $row = $row.next()) {
+ $row.find('td').eq(1).text($row.index() + 1).end().removeClass('odd even').addClass($row.index() % 2 === 0 ? 'odd' : 'even');
+ }
+ Functions.ajaxShowMessage(data.message);
+ }
+ });
+ });
+ });
+
+ /**
+ * Handles multi submits in table structure page such as change, browse, drop, primary etc.
+ */
+ $('body').on('click', '#fieldsForm button.mult_submit', function (e) {
+ e.preventDefault();
+ var $form = $(this).parents('form');
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ Functions.ajaxShowMessage();
+ AJAX.source = $form;
+ $.post(this.formAction, submitData, AJAX.responseHandler);
+ });
+
+ /**
+ * Handles clicks on Action links in partition table
+ */
+ $(document).on('click', 'a[id^=partition_action].ajax', function (e) {
+ e.preventDefault();
+ var $link = $(this);
+ function submitPartitionAction(url) {
+ var params = 'ajax_request=true&ajax_page_request=true&' + $link.getPostData();
+ Functions.ajaxShowMessage();
+ AJAX.source = $link;
+ $.post(url, params, AJAX.responseHandler);
+ }
+ if ($link.is('#partition_action_DROP')) {
+ $link.confirm(Messages.strDropPartitionWarning, $link.attr('href'), function (url) {
+ submitPartitionAction(url);
+ });
+ } else if ($link.is('#partition_action_TRUNCATE')) {
+ $link.confirm(Messages.strTruncatePartitionWarning, $link.attr('href'), function (url) {
+ submitPartitionAction(url);
+ });
+ } else {
+ submitPartitionAction($link.attr('href'));
+ }
+ });
+
+ /**
+ * Handles remove partitioning
+ */
+ $(document).on('click', '#remove_partitioning.ajax', function (e) {
+ e.preventDefault();
+ var $link = $(this);
+ var question = Messages.strRemovePartitioningWarning;
+ $link.confirm(question, $link.attr('href'), function (url) {
+ var params = Functions.getJsConfirmCommonParam({
+ 'ajax_request': true,
+ 'ajax_page_request': true
+ }, $link.getPostData());
+ Functions.ajaxShowMessage();
+ AJAX.source = $link;
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+ $(document).on('change', 'select[name=after_field]', function () {
+ checkFirst();
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/tracking.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/tracking.js
new file mode 100644
index 000000000..ecd116a9e
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/tracking.js
@@ -0,0 +1,123 @@
+/**
+ * Unbind all event handlers before tearing down the page
+ */
+AJAX.registerTeardown('table/tracking.js', function () {
+ $('body').off('click', '#versionsForm.ajax button[name="submit_mult"], #versionsForm.ajax input[name="submit_mult"]');
+ $('body').off('click', 'a.delete_version_anchor.ajax');
+ $('body').off('click', 'a.delete_entry_anchor.ajax');
+});
+
+/**
+ * Bind event handlers
+ */
+AJAX.registerOnload('table/tracking.js', function () {
+ $('#versions tr').first().find('th').append($('
'));
+ $('#versions').tablesorter({
+ sortList: [[1, 0]],
+ headers: {
+ 0: {
+ sorter: false
+ },
+ 1: {
+ sorter: 'integer'
+ },
+ 5: {
+ sorter: false
+ },
+ 6: {
+ sorter: false
+ }
+ }
+ });
+ if ($('#ddl_versions tbody tr').length > 0) {
+ $('#ddl_versions tr').first().find('th').append($('
'));
+ $('#ddl_versions').tablesorter({
+ sortList: [[0, 0]],
+ headers: {
+ 0: {
+ sorter: 'integer'
+ },
+ 3: {
+ sorter: false
+ },
+ 4: {
+ sorter: false
+ }
+ }
+ });
+ }
+ if ($('#dml_versions tbody tr').length > 0) {
+ $('#dml_versions tr').first().find('th').append($('
'));
+ $('#dml_versions').tablesorter({
+ sortList: [[0, 0]],
+ headers: {
+ 0: {
+ sorter: 'integer'
+ },
+ 3: {
+ sorter: false
+ },
+ 4: {
+ sorter: false
+ }
+ }
+ });
+ }
+
+ /**
+ * Handles multi submit for tracking versions
+ */
+ $('body').on('click', '#versionsForm.ajax button[name="submit_mult"], #versionsForm.ajax input[name="submit_mult"]', function (e) {
+ e.preventDefault();
+ var $button = $(this);
+ var $form = $button.parent('form');
+ var argsep = CommonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true' + argsep + 'submit_mult=' + $button.val();
+ if ($button.val() === 'delete_version') {
+ var question = Messages.strDeleteTrackingVersionMultiple;
+ $button.confirm(question, $form.attr('action'), function (url) {
+ Functions.ajaxShowMessage();
+ AJAX.source = $form;
+ $.post(url, submitData, AJAX.responseHandler);
+ });
+ } else {
+ Functions.ajaxShowMessage();
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ }
+ });
+
+ /**
+ * Ajax Event handler for 'Delete version'
+ */
+ $('body').on('click', 'a.delete_version_anchor.ajax', function (e) {
+ e.preventDefault();
+ var $anchor = $(this);
+ var question = Messages.strDeleteTrackingVersion;
+ $anchor.confirm(question, $anchor.attr('href'), function (url) {
+ Functions.ajaxShowMessage();
+ AJAX.source = $anchor;
+ var argSep = CommonParams.get('arg_separator');
+ var params = Functions.getJsConfirmCommonParam(this, $anchor.getPostData());
+ params += argSep + 'ajax_page_request=1';
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+
+ /**
+ * Ajax Event handler for 'Delete tracking report entry'
+ */
+ $('body').on('click', 'a.delete_entry_anchor.ajax', function (e) {
+ e.preventDefault();
+ var $anchor = $(this);
+ var question = Messages.strDeletingTrackingEntry;
+ $anchor.confirm(question, $anchor.attr('href'), function (url) {
+ Functions.ajaxShowMessage();
+ AJAX.source = $anchor;
+ var argSep = CommonParams.get('arg_separator');
+ var params = Functions.getJsConfirmCommonParam(this, $anchor.getPostData());
+ params += argSep + 'ajax_page_request=1';
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/zoom_plot_jqplot.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/zoom_plot_jqplot.js
new file mode 100644
index 000000000..56fc7bb27
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/table/zoom_plot_jqplot.js
@@ -0,0 +1,590 @@
+// TODO: change the axis
+/**
+ * @fileoverview JavaScript functions used on /table/search
+ *
+ * @requires jQuery
+ * @requires js/functions.js
+ **/
+
+/* global changeValueFieldType, verifyAfterSearchFieldChange */ // js/table/change.js
+
+/**
+ * Display Help/Info
+ * @return {false}
+ **/
+function displayHelp() {
+ var modal = $('#helpModal');
+ modal.modal('show');
+ modal.find('.modal-body').first().html(Messages.strDisplayHelp);
+ $('#helpModalLabel').first().html(Messages.strHelpTitle);
+ return false;
+}
+
+/**
+ * Extend the array object for max function
+ * @param {number[]} array
+ * @return {int}
+ **/
+Array.max = function (array) {
+ return Math.max.apply(Math, array);
+};
+
+/**
+ * Extend the array object for min function
+ * @param {number[]} array
+ * @return {int}
+ **/
+Array.min = function (array) {
+ return Math.min.apply(Math, array);
+};
+
+/**
+ * Checks if a string contains only numeric value
+ * @param {string} n (to be checked)
+ * @return {bool}
+ **/
+function isNumeric(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+}
+
+/**
+ ** Checks if an object is empty
+ * @param {object} obj (to be checked)
+ * @return {bool}
+ **/
+function isEmpty(obj) {
+ var name;
+ for (name in obj) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Converts a date/time into timestamp
+ * @param {string} val Date
+ * @param {string} type Field type(datetime/timestamp/time/date)
+ * @return {any} A value
+ **/
+function getTimeStamp(val, type) {
+ if (type.toString().search(/datetime/i) !== -1 || type.toString().search(/timestamp/i) !== -1) {
+ return $.datepicker.parseDateTime('yy-mm-dd', 'HH:mm:ss', val);
+ } else if (type.toString().search(/time/i) !== -1) {
+ return $.datepicker.parseDateTime('yy-mm-dd', 'HH:mm:ss', '1970-01-01 ' + val);
+ } else if (type.toString().search(/date/i) !== -1) {
+ return $.datepicker.parseDate('yy-mm-dd', val);
+ }
+}
+
+/**
+ * Classifies the field type into numeric,timeseries or text
+ * @param {object} field field type (as in database structure)
+ * @return {'text'|'numeric'|'time'}
+ **/
+function getType(field) {
+ if (field.toString().search(/int/i) !== -1 || field.toString().search(/decimal/i) !== -1 || field.toString().search(/year/i) !== -1) {
+ return 'numeric';
+ } else if (field.toString().search(/time/i) !== -1 || field.toString().search(/date/i) !== -1) {
+ return 'time';
+ } else {
+ return 'text';
+ }
+}
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('table/zoom_plot_jqplot.js', function () {
+ $('#tableid_0').off('change');
+ $('#tableid_1').off('change');
+ $('#tableid_2').off('change');
+ $('#tableid_3').off('change');
+ $('#inputFormSubmitId').off('click');
+ $('#togglesearchformlink').off('click');
+ $(document).off('keydown', '#dataDisplay :input');
+ $('button.button-reset').off('click');
+ $('div#resizer').off('resizestop');
+ $('div#querychart').off('jqplotDataClick');
+});
+AJAX.registerOnload('table/zoom_plot_jqplot.js', function () {
+ var currentChart = null;
+ var searchedDataKey = null;
+ var xLabel = $('#tableid_0').val();
+ var yLabel = $('#tableid_1').val();
+ // will be updated via Ajax
+ var xType = $('#types_0').val();
+ var yType = $('#types_1').val();
+ var dataLabel = $('#dataLabel').val();
+
+ // Get query result
+ var searchedData;
+ try {
+ searchedData = JSON.parse($('#querydata').html());
+ } catch (err) {
+ searchedData = null;
+ }
+
+ // adding event listener on select after AJAX request
+ var comparisonOperatorOnChange = function () {
+ var tableRows = $('#inputSection select.column-operator');
+ $.each(tableRows, function (index, item) {
+ $(item).on('change', function () {
+ changeValueFieldType(this, index);
+ verifyAfterSearchFieldChange(index, '#zoom_search_form');
+ });
+ });
+ };
+
+ /**
+ ** Input form submit on field change
+ **/
+
+ // first column choice corresponds to the X axis
+ $('#tableid_0').on('change', function () {
+ // AJAX request for field type, collation, operators, and value field
+ $.post('index.php?route=/table/zoom-search', {
+ 'ajax_request': true,
+ 'change_tbl_info': true,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'field': $('#tableid_0').val(),
+ 'it': 0
+ }, function (data) {
+ $('#tableFieldsId').find('tr').eq(1).find('td').eq(0).html(data.field_type);
+ $('#tableFieldsId').find('tr').eq(1).find('td').eq(1).html(data.field_collation);
+ $('#tableFieldsId').find('tr').eq(1).find('td').eq(2).html(data.field_operators);
+ $('#tableFieldsId').find('tr').eq(1).find('td').eq(3).html(data.field_value);
+ xLabel = $('#tableid_0').val();
+ $('#types_0').val(data.field_type);
+ xType = data.field_type;
+ $('#collations_0').val(data.field_collations);
+ comparisonOperatorOnChange();
+ Functions.addDateTimePicker();
+ });
+ });
+
+ // second column choice corresponds to the Y axis
+ $('#tableid_1').on('change', function () {
+ // AJAX request for field type, collation, operators, and value field
+ $.post('index.php?route=/table/zoom-search', {
+ 'ajax_request': true,
+ 'change_tbl_info': true,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'field': $('#tableid_1').val(),
+ 'it': 1
+ }, function (data) {
+ $('#tableFieldsId').find('tr').eq(2).find('td').eq(0).html(data.field_type);
+ $('#tableFieldsId').find('tr').eq(2).find('td').eq(1).html(data.field_collation);
+ $('#tableFieldsId').find('tr').eq(2).find('td').eq(2).html(data.field_operators);
+ $('#tableFieldsId').find('tr').eq(2).find('td').eq(3).html(data.field_value);
+ yLabel = $('#tableid_1').val();
+ $('#types_1').val(data.field_type);
+ yType = data.field_type;
+ $('#collations_1').val(data.field_collations);
+ comparisonOperatorOnChange();
+ Functions.addDateTimePicker();
+ });
+ });
+ $('#tableid_2').on('change', function () {
+ // AJAX request for field type, collation, operators, and value field
+ $.post('index.php?route=/table/zoom-search', {
+ 'ajax_request': true,
+ 'change_tbl_info': true,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'field': $('#tableid_2').val(),
+ 'it': 2
+ }, function (data) {
+ $('#tableFieldsId').find('tr').eq(4).find('td').eq(0).html(data.field_type);
+ $('#tableFieldsId').find('tr').eq(4).find('td').eq(1).html(data.field_collation);
+ $('#tableFieldsId').find('tr').eq(4).find('td').eq(2).html(data.field_operators);
+ $('#tableFieldsId').find('tr').eq(4).find('td').eq(3).html(data.field_value);
+ $('#types_2').val(data.field_type);
+ $('#collations_2').val(data.field_collations);
+ comparisonOperatorOnChange();
+ Functions.addDateTimePicker();
+ });
+ });
+ $('#tableid_3').on('change', function () {
+ // AJAX request for field type, collation, operators, and value field
+ $.post('index.php?route=/table/zoom-search', {
+ 'ajax_request': true,
+ 'change_tbl_info': true,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'field': $('#tableid_3').val(),
+ 'it': 3
+ }, function (data) {
+ $('#tableFieldsId').find('tr').eq(5).find('td').eq(0).html(data.field_type);
+ $('#tableFieldsId').find('tr').eq(5).find('td').eq(1).html(data.field_collation);
+ $('#tableFieldsId').find('tr').eq(5).find('td').eq(2).html(data.field_operators);
+ $('#tableFieldsId').find('tr').eq(5).find('td').eq(3).html(data.field_value);
+ $('#types_3').val(data.field_type);
+ $('#collations_3').val(data.field_collations);
+ comparisonOperatorOnChange();
+ Functions.addDateTimePicker();
+ });
+ });
+
+ /**
+ * Input form validation
+ **/
+ $('#inputFormSubmitId').on('click', function () {
+ if ($('#tableid_0').get(0).selectedIndex === 0 || $('#tableid_1').get(0).selectedIndex === 0) {
+ Functions.ajaxShowMessage(Messages.strInputNull);
+ } else if (xLabel === yLabel) {
+ Functions.ajaxShowMessage(Messages.strSameInputs);
+ }
+ });
+
+ /**
+ ** Prepare a div containing a link, otherwise it's incorrectly displayed
+ ** after a couple of clicks
+ **/
+ $('
').insertAfter('#zoom_search_form')
+ // don't show it until we have results on-screen
+ .hide();
+ $('#togglesearchformlink').html(Messages.strShowSearchCriteria).on('click', function () {
+ var $link = $(this);
+ $('#zoom_search_form').slideToggle();
+ if ($link.text() === Messages.strHideSearchCriteria) {
+ $link.text(Messages.strShowSearchCriteria);
+ } else {
+ $link.text(Messages.strHideSearchCriteria);
+ }
+ // avoid default click action
+ return false;
+ });
+
+ /**
+ * Handle saving of a row in the editor
+ */
+ var dataPointSave = function () {
+ // Find changed values by comparing form values with selectedRow Object
+ var newValues = {}; // Stores the values changed from original
+ var sqlTypes = {};
+ var it = 0;
+ var xChange = false;
+ var yChange = false;
+ var key;
+ var tempGetVal = function () {
+ return $(this).val();
+ };
+ for (key in selectedRow) {
+ var oldVal = selectedRow[key];
+ var newVal = $('#edit_fields_null_id_' + it).prop('checked') ? null : $('#edit_fieldID_' + it).val();
+ if (newVal instanceof Array) {
+ // when the column is of type SET
+ newVal = $('#edit_fieldID_' + it).map(tempGetVal).get().join(',');
+ }
+ if (oldVal !== newVal) {
+ selectedRow[key] = newVal;
+ newValues[key] = newVal;
+ if (key === xLabel) {
+ xChange = true;
+ searchedData[searchedDataKey][xLabel] = newVal;
+ } else if (key === yLabel) {
+ yChange = true;
+ searchedData[searchedDataKey][yLabel] = newVal;
+ }
+ }
+ var $input = $('#edit_fieldID_' + it);
+ if ($input.hasClass('bit')) {
+ sqlTypes[key] = 'bit';
+ } else {
+ sqlTypes[key] = null;
+ }
+ it++;
+ } // End data update
+
+ // Update the chart series and replot
+ if (xChange || yChange) {
+ // Logic similar to plot generation, replot only if xAxis changes or yAxis changes.
+ // Code includes a lot of checks so as to replot only when necessary
+ if (xChange) {
+ xCord[searchedDataKey] = selectedRow[xLabel];
+ // [searchedDataKey][0] contains the x value
+ if (xType === 'numeric') {
+ series[0][searchedDataKey][0] = selectedRow[xLabel];
+ } else if (xType === 'time') {
+ series[0][searchedDataKey][0] = getTimeStamp(selectedRow[xLabel], $('#types_0').val());
+ } else {
+ series[0][searchedDataKey][0] = '';
+ // TODO: text values
+ }
+
+ currentChart.series[0].data = series[0];
+ // TODO: axis changing
+ currentChart.replot();
+ }
+ if (yChange) {
+ yCord[searchedDataKey] = selectedRow[yLabel];
+ // [searchedDataKey][1] contains the y value
+ if (yType === 'numeric') {
+ series[0][searchedDataKey][1] = selectedRow[yLabel];
+ } else if (yType === 'time') {
+ series[0][searchedDataKey][1] = getTimeStamp(selectedRow[yLabel], $('#types_1').val());
+ } else {
+ series[0][searchedDataKey][1] = '';
+ // TODO: text values
+ }
+
+ currentChart.series[0].data = series[0];
+ // TODO: axis changing
+ currentChart.replot();
+ }
+ } // End plot update
+
+ // Generate SQL query for update
+ if (!isEmpty(newValues)) {
+ var sqlQuery = 'UPDATE `' + CommonParams.get('table') + '` SET ';
+ for (key in newValues) {
+ sqlQuery += '`' + key + '`=';
+ var value = newValues[key];
+
+ // null
+ if (value === null) {
+ sqlQuery += 'NULL, ';
+
+ // empty
+ } else if (value.trim() === '') {
+ sqlQuery += '\'\', ';
+
+ // other
+ } else {
+ // type explicitly identified
+ if (sqlTypes[key] !== null) {
+ if (sqlTypes[key] === 'bit') {
+ sqlQuery += 'b\'' + value + '\', ';
+ }
+ // type not explicitly identified
+ } else {
+ if (!isNumeric(value)) {
+ sqlQuery += '\'' + value + '\', ';
+ } else {
+ sqlQuery += value + ', ';
+ }
+ }
+ }
+ }
+ // remove two extraneous characters ', '
+ sqlQuery = sqlQuery.substring(0, sqlQuery.length - 2);
+ sqlQuery += ' WHERE ' + Sql.urlDecode(searchedData[searchedDataKey].where_clause);
+ $.post('index.php?route=/sql', {
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'ajax_request': true,
+ 'sql_query': sqlQuery,
+ 'inline_edit': false
+ }, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ $('#sqlqueryresultsouter').html(data.sql_query);
+ Functions.highlightSql($('#sqlqueryresultsouter'));
+ } else {
+ Functions.ajaxShowMessage(data.error, false);
+ }
+ }); // End $.post
+ } // End database update
+ };
+
+ $('#dataPointSaveButton').on('click', function () {
+ dataPointSave();
+ });
+ $('#dataPointModalLabel').first().html(Messages.strDataPointContent);
+
+ /**
+ * Attach Ajax event handlers for input fields
+ * in the dialog. Used to submit the Ajax
+ * request when the ENTER key is pressed.
+ */
+ $(document).on('keydown', '#dataDisplay :input', function (e) {
+ if (e.which === 13) {
+ // 13 is the ENTER key
+ e.preventDefault();
+ if (typeof dataPointSave === 'function') {
+ dataPointSave();
+ }
+ }
+ });
+
+ /*
+ * Generate plot using jqplot
+ */
+
+ if (searchedData !== null) {
+ $('#zoom_search_form').slideToggle().hide();
+ $('#togglesearchformlink').text(Messages.strShowSearchCriteria);
+ $('#togglesearchformdiv').show();
+ var selectedRow;
+ var series = [];
+ var xCord = [];
+ var yCord = [];
+ var xVal;
+ var yVal;
+ var format;
+ var options = {
+ series: [
+ // for a scatter plot
+ {
+ showLine: false
+ }],
+ grid: {
+ drawBorder: false,
+ shadow: false,
+ background: 'rgba(0,0,0,0)'
+ },
+ axes: {
+ xaxis: {
+ label: $('#tableid_0').val(),
+ labelRenderer: $.jqplot.CanvasAxisLabelRenderer
+ },
+ yaxis: {
+ label: $('#tableid_1').val(),
+ labelRenderer: $.jqplot.CanvasAxisLabelRenderer
+ }
+ },
+ highlighter: {
+ show: true,
+ tooltipAxes: 'y',
+ yvalues: 2,
+ // hide the first y value
+ formatString: '
%s %s'
+ },
+ cursor: {
+ show: true,
+ zoom: true,
+ showTooltip: false
+ }
+ };
+
+ // If data label is not set, do not show tooltips
+ if (dataLabel === '') {
+ options.highlighter.show = false;
+ }
+
+ // Classify types as either numeric,time,text
+ xType = getType(xType);
+ yType = getType(yType);
+
+ // could have multiple series but we'll have just one
+ series[0] = [];
+ if (xType === 'time') {
+ var originalXType = $('#types_0').val();
+ if (originalXType === 'date') {
+ format = '%Y-%m-%d';
+ }
+ // TODO: does not seem to work
+ // else if (originalXType === 'time') {
+ // format = '%H:%M';
+ // } else {
+ // format = '%Y-%m-%d %H:%M';
+ // }
+ $.extend(options.axes.xaxis, {
+ renderer: $.jqplot.DateAxisRenderer,
+ tickOptions: {
+ formatString: format
+ }
+ });
+ }
+ if (yType === 'time') {
+ var originalYType = $('#types_1').val();
+ if (originalYType === 'date') {
+ format = '%Y-%m-%d';
+ }
+ $.extend(options.axes.yaxis, {
+ renderer: $.jqplot.DateAxisRenderer,
+ tickOptions: {
+ formatString: format
+ }
+ });
+ }
+ $.each(searchedData, function (key, value) {
+ if (xType === 'numeric') {
+ xVal = parseFloat(value[xLabel]);
+ }
+ if (xType === 'time') {
+ xVal = getTimeStamp(value[xLabel], originalXType);
+ }
+ if (yType === 'numeric') {
+ yVal = parseFloat(value[yLabel]);
+ }
+ if (yType === 'time') {
+ yVal = getTimeStamp(value[yLabel], originalYType);
+ }
+ series[0].push([xVal, yVal,
+ // extra Y values
+ value[dataLabel],
+ // for highlighter
+ // (may set an undefined value)
+ value.where_clause,
+ // for click on point
+ key,
+ // key from searchedData
+ value.where_clause_sign]);
+ });
+
+ // under IE 8, the initial display is mangled; after a manual
+ // resizing, it's ok
+ // under IE 9, everything is fine
+ currentChart = $.jqplot('querychart', series, options);
+ currentChart.resetZoom();
+ $('button.button-reset').on('click', function (event) {
+ event.preventDefault();
+ currentChart.resetZoom();
+ });
+ $('div#resizer').resizable();
+ $('div#resizer').on('resizestop', function () {
+ // make room so that the handle will still appear
+ $('div#querychart').height($('div#resizer').height() * 0.96);
+ $('div#querychart').width($('div#resizer').width() * 0.96);
+ currentChart.replot({
+ resetAxes: true
+ });
+ });
+ $('div#querychart').on('jqplotDataClick', function (event, seriesIndex, pointIndex, data) {
+ searchedDataKey = data[4]; // key from searchedData (global)
+ var fieldId = 0;
+ var postParams = {
+ 'ajax_request': true,
+ 'get_data_row': true,
+ 'server': CommonParams.get('server'),
+ 'db': CommonParams.get('db'),
+ 'table': CommonParams.get('table'),
+ 'where_clause': data[3],
+ 'where_clause_sign': data[5]
+ };
+ $.post('index.php?route=/table/zoom-search', postParams, function (data) {
+ // Row is contained in data.row_info,
+ // now fill the displayResultForm with row values
+ var key;
+ for (key in data.row_info) {
+ var $field = $('#edit_fieldID_' + fieldId);
+ var $fieldNull = $('#edit_fields_null_id_' + fieldId);
+ if (data.row_info[key] === null) {
+ $fieldNull.prop('checked', true);
+ $field.val('');
+ } else {
+ $fieldNull.prop('checked', false);
+ if ($field.attr('multiple')) {
+ // when the column is of type SET
+ $field.val(data.row_info[key].split(','));
+ } else {
+ $field.val(data.row_info[key]);
+ }
+ }
+ fieldId++;
+ }
+ selectedRow = data.row_info;
+ });
+ $('#dataPointModal').modal('show');
+ });
+ }
+ $('#help_dialog').on('click', function () {
+ displayHelp();
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/image_upload.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/image_upload.js
new file mode 100644
index 000000000..336b2a157
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/image_upload.js
@@ -0,0 +1,27 @@
+/**
+ * Image upload transformations plugin js
+ *
+ * @package PhpMyAdmin
+ */
+
+AJAX.registerOnload('transformations/image_upload.js', function () {
+ // Change thumbnail when image file is selected
+ // through file upload dialog
+ $('input.image-upload').on('change', function () {
+ if (this.files && this.files[0]) {
+ var reader = new FileReader();
+ var $input = $(this);
+ reader.onload = function (e) {
+ $input.prevAll('img').attr('src', e.target.result);
+ };
+ reader.readAsDataURL(this.files[0]);
+ }
+ });
+});
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+AJAX.registerTeardown('transformations/image_upload.js', function () {
+ $('input.image-upload').off('change');
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json.js
new file mode 100644
index 000000000..6acfa454c
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json.js
@@ -0,0 +1,17 @@
+/**
+ * JSON syntax highlighting transformation plugin
+ */
+AJAX.registerOnload('transformations/json.js', function () {
+ var $elm = $('#page_content').find('code.json');
+ $elm.each(function () {
+ var $json = $(this);
+ var $pre = $json.find('pre');
+ /* We only care about visible elements to avoid double processing */
+ if ($pre.is(':visible')) {
+ var $highlight = $('
');
+ $json.append($highlight);
+ CodeMirror.runMode($json.text(), 'application/json', $highlight[0]);
+ $pre.hide();
+ }
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json_editor.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json_editor.js
new file mode 100644
index 000000000..dbf2fb527
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/json_editor.js
@@ -0,0 +1,16 @@
+/**
+ * JSON syntax highlighting transformation plugin
+ *
+ * @package PhpMyAdmin
+ */
+AJAX.registerOnload('transformations/json_editor.js', function () {
+ $('textarea.transform_json_editor').each(function () {
+ CodeMirror.fromTextArea(this, {
+ lineNumbers: true,
+ matchBrackets: true,
+ indentUnit: 4,
+ mode: 'application/json',
+ lineWrapping: true
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/sql_editor.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/sql_editor.js
new file mode 100644
index 000000000..dcb26f831
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/sql_editor.js
@@ -0,0 +1,10 @@
+/**
+ * SQL syntax highlighting transformation plugin js
+ *
+ * @package PhpMyAdmin
+ */
+AJAX.registerOnload('transformations/sql_editor.js', function () {
+ $('textarea.transform_sql_editor').each(function () {
+ Functions.getSqlEditor($(this), {}, 'both');
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml.js
new file mode 100644
index 000000000..c8096e0b8
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml.js
@@ -0,0 +1,17 @@
+/**
+ * XML syntax highlighting transformation plugin
+ */
+AJAX.registerOnload('transformations/xml.js', function () {
+ var $elm = $('#page_content').find('code.xml');
+ $elm.each(function () {
+ var $json = $(this);
+ var $pre = $json.find('pre');
+ /* We only care about visible elements to avoid double processing */
+ if ($pre.is(':visible')) {
+ var $highlight = $('
');
+ $json.append($highlight);
+ CodeMirror.runMode($json.text(), 'application/xml', $highlight[0]);
+ $pre.hide();
+ }
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml_editor.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml_editor.js
new file mode 100644
index 000000000..2ded1e1b1
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/transformations/xml_editor.js
@@ -0,0 +1,15 @@
+/**
+ * XML editor plugin
+ *
+ * @package PhpMyAdmin
+ */
+AJAX.registerOnload('transformations/xml_editor.js', function () {
+ $('textarea.transform_xml_editor').each(function () {
+ CodeMirror.fromTextArea(this, {
+ lineNumbers: true,
+ indentUnit: 4,
+ mode: 'application/xml',
+ lineWrapping: true
+ });
+ });
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/u2f.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/u2f.js
new file mode 100644
index 000000000..684849b95
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/u2f.js
@@ -0,0 +1,77 @@
+/* global u2f */ // js/vendor/u2f-api-polyfill.js
+
+AJAX.registerOnload('u2f.js', function () {
+ var $inputReg = $('#u2f_registration_response');
+ if ($inputReg.length > 0) {
+ var $formReg = $inputReg.parents('form');
+ $formReg.find('input[type=submit]').hide();
+ setTimeout(function () {
+ // A magic JS function that talks to the USB device. This function will keep polling for the USB device until it finds one.
+ var request = JSON.parse($inputReg.attr('data-request'));
+ u2f.register(request.appId, [request], JSON.parse($inputReg.attr('data-signatures')), function (data) {
+ // Handle returning error data
+ if (data.errorCode && data.errorCode !== 0) {
+ switch (data.errorCode) {
+ case 5:
+ Functions.ajaxShowMessage(Messages.strU2FTimeout, false, 'error');
+ break;
+ case 4:
+ Functions.ajaxShowMessage(Messages.strU2FErrorRegister, false, 'error');
+ break;
+ case 3:
+ Functions.ajaxShowMessage(Messages.strU2FInvalidClient, false, 'error');
+ break;
+ case 2:
+ Functions.ajaxShowMessage(Messages.strU2FBadRequest, false, 'error');
+ break;
+ default:
+ Functions.ajaxShowMessage(Messages.strU2FUnknown, false, 'error');
+ break;
+ }
+ return;
+ }
+
+ // Fill and submit form.
+ $inputReg.val(JSON.stringify(data));
+ $formReg.trigger('submit');
+ });
+ }, 1000);
+ }
+ var $inputAuth = $('#u2f_authentication_response');
+ if ($inputAuth.length > 0) {
+ var $formAuth = $inputAuth.parents('form');
+ $formAuth.find('input[type=submit]').hide();
+ setTimeout(function () {
+ // Magic JavaScript talking to your HID
+ // appid, challenge, authenticateRequests
+ var request = JSON.parse($inputAuth.attr('data-request'));
+ u2f.sign(request[0].appId, request[0].challenge, request, function (data) {
+ // Handle returning error data
+ if (data.errorCode && data.errorCode !== 0) {
+ switch (data.errorCode) {
+ case 5:
+ Functions.ajaxShowMessage(Messages.strU2FTimeout, false, 'error');
+ break;
+ case 4:
+ Functions.ajaxShowMessage(Messages.strU2FErrorAuthenticate, false, 'error');
+ break;
+ case 3:
+ Functions.ajaxShowMessage(Messages.strU2FInvalidClient, false, 'error');
+ break;
+ case 2:
+ Functions.ajaxShowMessage(Messages.strU2FBadRequest, false, 'error');
+ break;
+ default:
+ Functions.ajaxShowMessage(Messages.strU2FUnknown, false, 'error');
+ break;
+ }
+ return;
+ }
+
+ // Fill and submit form.
+ $inputAuth.val(JSON.stringify(data));
+ $formAuth.trigger('submit');
+ });
+ }, 1000);
+ }
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/webauthn.js b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/webauthn.js
new file mode 100644
index 000000000..74cc11abe
--- /dev/null
+++ b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/js/dist/webauthn.js
@@ -0,0 +1,119 @@
+/**
+ * @param {ArrayBuffer} buffer
+ *
+ * @return {string}
+ */
+const arrayBufferToBase64 = buffer => {
+ const bytes = new Uint8Array(buffer);
+ let string = '';
+ for (const byte of bytes) {
+ string += String.fromCharCode(byte);
+ }
+ return window.btoa(string);
+};
+
+/**
+ * @param {string} string
+ *
+ * @return {Uint8Array}
+ */
+const base64ToUint8Array = string => {
+ return Uint8Array.from(window.atob(string), char => char.charCodeAt(0));
+};
+
+/**
+ * @param {JQuery
} $input
+ *
+ * @return {void}
+ */
+const handleCreation = $input => {
+ const $form = $input.parents('form');
+ $form.find('input[type=submit]').hide();
+ const creationOptionsJson = $input.attr('data-creation-options');
+ const creationOptions = JSON.parse(creationOptionsJson);
+ const publicKey = creationOptions;
+ publicKey.challenge = base64ToUint8Array(creationOptions.challenge);
+ publicKey.user.id = base64ToUint8Array(creationOptions.user.id);
+ if (creationOptions.excludeCredentials) {
+ const excludedCredentials = [];
+ for (let value of creationOptions.excludeCredentials) {
+ let excludedCredential = value;
+ excludedCredential.id = base64ToUint8Array(value.id);
+ excludedCredentials.push(excludedCredential);
+ }
+ publicKey.excludeCredentials = excludedCredentials;
+ }
+
+ // eslint-disable-next-line compat/compat
+ navigator.credentials.create({
+ publicKey: publicKey
+ }).then(credential => {
+ const credentialJson = JSON.stringify({
+ id: credential.id,
+ rawId: arrayBufferToBase64(credential.rawId),
+ type: credential.type,
+ response: {
+ clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON),
+ attestationObject: arrayBufferToBase64(credential.response.attestationObject)
+ }
+ });
+ $input.val(credentialJson);
+ $form.trigger('submit');
+ }).catch(error => Functions.ajaxShowMessage(error, false, 'error'));
+};
+
+/**
+ * @param {JQuery} $input
+ *
+ * @return {void}
+ */
+const handleRequest = $input => {
+ const $form = $input.parents('form');
+ $form.find('input[type=submit]').hide();
+ const requestOptionsJson = $input.attr('data-request-options');
+ const requestOptions = JSON.parse(requestOptionsJson);
+ const publicKey = requestOptions;
+ publicKey.challenge = base64ToUint8Array(requestOptions.challenge);
+ if (requestOptions.allowCredentials) {
+ const allowedCredentials = [];
+ for (let value of requestOptions.allowCredentials) {
+ let allowedCredential = value;
+ allowedCredential.id = base64ToUint8Array(value.id);
+ allowedCredentials.push(allowedCredential);
+ }
+ publicKey.allowCredentials = allowedCredentials;
+ }
+
+ // eslint-disable-next-line compat/compat
+ navigator.credentials.get({
+ publicKey: publicKey
+ }).then(credential => {
+ const credentialJson = JSON.stringify({
+ id: credential.id,
+ rawId: arrayBufferToBase64(credential.rawId),
+ type: credential.type,
+ response: {
+ authenticatorData: arrayBufferToBase64(credential.response.authenticatorData),
+ clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON),
+ signature: arrayBufferToBase64(credential.response.signature),
+ userHandle: arrayBufferToBase64(credential.response.userHandle)
+ }
+ });
+ $input.val(credentialJson);
+ $form.trigger('submit');
+ }).catch(error => Functions.ajaxShowMessage(error, false, 'error'));
+};
+AJAX.registerOnload('webauthn.js', function () {
+ if (!navigator.credentials || !navigator.credentials.create || !navigator.credentials.get || !window.PublicKeyCredential) {
+ Functions.ajaxShowMessage(Messages.webAuthnNotSupported, false, 'error');
+ return;
+ }
+ const $creationInput = $('#webauthn_creation_response');
+ if ($creationInput.length > 0) {
+ handleCreation($creationInput);
+ }
+ const $requestInput = $('#webauthn_request_response');
+ if ($requestInput.length > 0) {
+ handleRequest($requestInput);
+ }
+});
\ No newline at end of file
diff --git a/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/locale/ar/LC_MESSAGES/phpmyadmin.mo b/.devilbox/www/htdocs/vendor/phpmyadmin-5.2.1/locale/ar/LC_MESSAGES/phpmyadmin.mo
new file mode 100644
index 0000000000000000000000000000000000000000..aa3400cca658baaff54e55cc4fe4a2c338f079c5
GIT binary patch
literal 164858
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