Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpmyadmin/phpmyadmin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeven Bansod <devenbansod@users.noreply.github.com>2018-08-19 13:54:09 +0300
committerGitHub <noreply@github.com>2018-08-19 13:54:09 +0300
commitd031dec87a1e3f9cc1fceee1195d11acdba80383 (patch)
treed5faa27b7f9917477e450452b3cc30f036ff878e
parent0c3411587ab9bbe0a2efb260c3a0acf9cb5a5418 (diff)
parent5f4db91d71502b8f4971e12cb69baeb686b45ff1 (diff)
Merge pull request #14564 from Piyush3079/Mod_Js_Tbl_Structure
Modular code for table structure and table related files
-rw-r--r--js/functions.js209
-rw-r--r--js/src/ajax.js37
-rw-r--r--js/src/classes/Chart.js7
-rw-r--r--js/src/consts/files.js32
-rw-r--r--js/src/functions.js109
-rw-r--r--js/src/functions/Indexes.js692
-rw-r--r--js/src/functions/Table/Relation.js117
-rw-r--r--js/src/functions/Table/TableChange.js296
-rw-r--r--js/src/functions/Table/TableChart.js239
-rw-r--r--js/src/functions/Table/TableColumns.js1
-rw-r--r--js/src/functions/Table/TableSelect.js51
-rw-r--r--js/src/indexes.js264
-rw-r--r--js/src/tbl_change.js409
-rw-r--r--js/src/tbl_chart.js201
-rw-r--r--js/src/tbl_find_replace.js50
-rw-r--r--js/src/tbl_operations.js339
-rw-r--r--js/src/tbl_relation.js135
-rw-r--r--js/src/tbl_select.js394
-rw-r--r--js/src/tbl_structure.js520
-rw-r--r--js/src/tbl_tracking.js115
-rw-r--r--js/src/utils/DateTime.js3
-rw-r--r--js/src/utils/IndexEnum.js28
-rw-r--r--js/src/utils/JqueryExtended.js12
-rw-r--r--js/src/utils/Slider.js47
-rw-r--r--js/src/utils/show_ajax_messages.js22
-rw-r--r--libraries/classes/Controllers/Database/DatabaseStructureController.php2
-rw-r--r--libraries/classes/Controllers/Table/TableChartController.php17
-rw-r--r--libraries/classes/Controllers/Table/TableIndexesController.php2
-rw-r--r--libraries/classes/Controllers/Table/TableRelationController.php4
-rw-r--r--libraries/classes/Controllers/Table/TableSearchController.php14
-rw-r--r--libraries/classes/Controllers/Table/TableStructureController.php4
-rw-r--r--libraries/classes/Header.php2
-rw-r--r--sql.php4
-rw-r--r--tbl_change.php5
-rw-r--r--tbl_export.php2
-rw-r--r--tbl_import.php2
-rw-r--r--tbl_operations.php2
-rw-r--r--tbl_replace.php8
-rw-r--r--tbl_tracking.php3
39 files changed, 4135 insertions, 265 deletions
diff --git a/js/functions.js b/js/functions.js
index 5d39f13830..be524b83b4 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -87,128 +87,6 @@ $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
}
});
-/*
- * Adds a date/time picker to an element
- *
- * @param object $this_element a jQuery object pointing to the element
- */
-function PMA_addDatepicker ($this_element, type, options) {
- var showTimepicker = true;
- if (type === 'date') {
- showTimepicker = false;
- }
-
- var defaultOptions = {
- showOn: 'button',
- buttonImage: themeCalendarImage, // defined in js/messages.php
- buttonImageOnly: true,
- stepMinutes: 1,
- stepHours: 1,
- showSecond: true,
- showMillisec: true,
- showMicrosec: true,
- showTimepicker: showTimepicker,
- showButtonPanel: false,
- dateFormat: 'yy-mm-dd', // yy means year with four digits
- timeFormat: 'HH:mm:ss.lc',
- constrainInput: false,
- altFieldTimeOnly: false,
- showAnim: '',
- beforeShow: function (input, inst) {
- // Remember that we came from the datepicker; this is used
- // in tbl_change.js by verificationsAfterFieldChange()
- $this_element.data('comes_from', 'datepicker');
- if ($(input).closest('.cEdit').length > 0) {
- setTimeout(function () {
- inst.dpDiv.css({
- top: 0,
- left: 0,
- position: 'relative'
- });
- }, 0);
- }
- setTimeout(function () {
- // Fix wrong timepicker z-index, doesn't work without timeout
- $('#ui-timepicker-div').css('z-index', $('#ui-datepicker-div').css('z-index'));
- // Integrate tooltip text into dialog
- var tooltip = $this_element.tooltip('instance');
- if (typeof tooltip !== 'undefined') {
- tooltip.disable();
- var $note = $('<p class="note"></div>');
- $note.text(tooltip.option('content'));
- $('div.ui-datepicker').append($note);
- }
- }, 0);
- },
- onSelect: function () {
- $this_element.data('datepicker').inline = true;
- },
- onClose: function (dateText, dp_inst) {
- // The value is no more from the date picker
- $this_element.data('comes_from', '');
- if (typeof $this_element.data('datepicker') !== 'undefined') {
- $this_element.data('datepicker').inline = false;
- }
- var tooltip = $this_element.tooltip('instance');
- if (typeof tooltip !== 'undefined') {
- tooltip.enable();
- }
- }
- };
- if (type === 'time') {
- $this_element.timepicker($.extend(defaultOptions, options));
- // Add a tip regarding entering MySQL allowed-values for TIME data-type
- PMA_tooltip($this_element, 'input', PMA_messages.strMysqlAllowedValuesTipTime);
- } else {
- $this_element.datetimepicker($.extend(defaultOptions, options));
- }
-}
-
-/**
- * Add a date/time picker to each element that needs it
- * (only when jquery-ui-timepicker-addon.js is loaded)
- */
-function addDateTimePicker () {
- if ($.timepicker !== undefined) {
- $('input.timefield, input.datefield, input.datetimefield').each(function () {
- var decimals = $(this).parent().attr('data-decimals');
- var type = $(this).parent().attr('data-type');
-
- var showMillisec = false;
- var showMicrosec = false;
- var timeFormat = 'HH:mm:ss';
- var hourMax = 23;
- // check for decimal places of seconds
- if (decimals > 0 && type.indexOf('time') !== -1) {
- if (decimals > 3) {
- showMillisec = true;
- showMicrosec = true;
- timeFormat = 'HH:mm:ss.lc';
- } else {
- showMillisec = true;
- timeFormat = 'HH:mm:ss.l';
- }
- }
- if (type === 'time') {
- hourMax = 99;
- }
- PMA_addDatepicker($(this), type, {
- showMillisec: showMillisec,
- showMicrosec: showMicrosec,
- timeFormat: timeFormat,
- hourMax: hourMax
- });
- // Add a tip regarding entering MySQL allowed-values
- // for TIME and DATE data-type
- if ($(this).hasClass('timefield')) {
- PMA_tooltip($(this), 'input', PMA_messages.strMysqlAllowedValuesTipTime);
- } else if ($(this).hasClass('datefield')) {
- PMA_tooltip($(this), 'input', PMA_messages.strMysqlAllowedValuesTipDate);
- }
- });
- }
-}
-
/**
* Handle redirect and reload flags sent as part of AJAX requests
*
@@ -999,93 +877,6 @@ AJAX.registerOnload('functions.js', function () {
updateTimeout = window.setTimeout(UpdateIdleTime, interval);
}
});
-/**
- * Unbind all event handlers before tearing down a page
- */
-AJAX.registerTeardown('functions.js', function () {
- $(document).off('click', 'input:checkbox.checkall');
-});
-AJAX.registerOnload('functions.js', function () {
- /**
- * Row marking in horizontal mode (use "on" so that it works also for
- * next pages reached via AJAX); a tr may have the class noclick to remove
- * this behavior.
- */
-
- $(document).on('click', 'input:checkbox.checkall', function (e) {
- $this = $(this);
- var $tr = $this.closest('tr');
- var $table = $this.closest('table');
-
- if (!e.shiftKey || last_clicked_row === -1) {
- // usual click
-
- var $checkbox = $tr.find(':checkbox.checkall');
- var checked = $this.prop('checked');
- $checkbox.prop('checked', checked).trigger('change');
- if (checked) {
- $tr.addClass('marked');
- } else {
- $tr.removeClass('marked');
- }
- last_click_checked = checked;
-
- // remember the last clicked row
- last_clicked_row = last_click_checked ? $table.find('tr:not(.noclick)').index($tr) : -1;
- last_shift_clicked_row = -1;
- } else {
- // handle the shift click
- PMA_clearSelection();
- var start;
- var end;
-
- // clear last shift click result
- if (last_shift_clicked_row >= 0) {
- if (last_shift_clicked_row >= last_clicked_row) {
- start = last_clicked_row;
- end = last_shift_clicked_row;
- } else {
- start = last_shift_clicked_row;
- end = last_clicked_row;
- }
- $tr.parent().find('tr:not(.noclick)')
- .slice(start, end + 1)
- .removeClass('marked')
- .find(':checkbox')
- .prop('checked', false)
- .trigger('change');
- }
-
- // handle new shift click
- var curr_row = $table.find('tr:not(.noclick)').index($tr);
- if (curr_row >= last_clicked_row) {
- start = last_clicked_row;
- end = curr_row;
- } else {
- start = curr_row;
- end = last_clicked_row;
- }
- $tr.parent().find('tr:not(.noclick)')
- .slice(start, end)
- .addClass('marked')
- .find(':checkbox')
- .prop('checked', true)
- .trigger('change');
-
- // remember the last shift clicked row
- last_shift_clicked_row = curr_row;
- }
- });
-
- addDateTimePicker();
-
- /**
- * Add attribute to text boxes for iOS devices (based on bugID: 3508912)
- */
- if (navigator.userAgent.match(/(iphone|ipod|ipad)/i)) {
- $('input[type=text]').attr('autocapitalize', 'off').attr('autocorrect', 'off');
- }
-});
/**
* Checks/unchecks all options of a <select> element
diff --git a/js/src/ajax.js b/js/src/ajax.js
index 06aac9425d..23f00a8058 100644
--- a/js/src/ajax.js
+++ b/js/src/ajax.js
@@ -772,6 +772,40 @@ export let AJAX = {
$(document).on('click', 'a', AJAX.requestHandler);
$(document).on('submit', 'form', AJAX.requestHandler);
+/**
+ * @todo this is to be removed when complete code is modularised * Gracefully handle fatal server errors
+ * (e.g: 500 - Internal server error)
+ */
+$(document).ajaxError(function (event, request, settings) {
+ if (AJAX._debug) {
+ console.log('AJAX error: status=' + request.status + ', text=' + request.statusText);
+ }
+ // Don't handle aborted requests
+ if (request.status !== 0 || request.statusText !== 'abort') {
+ var details = '';
+ var state = request.state();
+ if (request.status !== 0) {
+ details += '<div>' + escapeHtml(PMA_sprintf(PMA_messages.strErrorCode, request.status)) + '</div>';
+ }
+ details += '<div>' + escapeHtml(PMA_sprintf(PMA_messages.strErrorText, request.statusText + ' (' + state + ')')) + '</div>';
+ if (state === 'rejected' || state === 'timeout') {
+ details += '<div>' + escapeHtml(PMA_messages.strErrorConnection) + '</div>';
+ }
+ PMA_ajaxShowMessage(
+ '<div class="error">' +
+ PMA_messages.strErrorProcessingRequest +
+ details +
+ '</div>',
+ false
+ );
+ AJAX.active = false;
+ AJAX.xhr = null;
+ }
+});
+/**
+ * Gracefully handle fatal server errors
+ * (e.g: 500 - Internal server error)
+ */
$(document).ajaxError(function (event, request, settings) {
if (AJAX._debug) {
console.log('AJAX error: status=' + request.status + ', text=' + request.statusText);
@@ -780,6 +814,7 @@ $(document).ajaxError(function (event, request, settings) {
if (request.status !== 0 || request.statusText !== 'abort') {
var details = '';
var state = request.state();
+
if (request.status !== 0) {
details += '<div>' + escapeHtml(PMA_sprintf(PMA_messages.strErrorCode, request.status)) + '</div>';
}
@@ -798,8 +833,8 @@ $(document).ajaxError(function (event, request, settings) {
AJAX.xhr = null;
}
});
+
/**
- * @todo this is to be removed when complete code is modularised
* Exporsing module to window for use with non modular code
*/
window.AJAX = AJAX;
diff --git a/js/src/classes/Chart.js b/js/src/classes/Chart.js
index c13b8adb53..0f1312c27f 100644
--- a/js/src/classes/Chart.js
+++ b/js/src/classes/Chart.js
@@ -4,6 +4,13 @@ import 'updated-jqplot/dist/plugins/jqplot.pieRenderer';
import 'updated-jqplot/dist/plugins/jqplot.highlighter';
import 'updated-jqplot/dist/plugins/jqplot.enhancedPieLegendRenderer';
+import 'updated-jqplot/dist/plugins/jqplot.barRenderer.js';
+import 'updated-jqplot/dist/plugins/jqplot.canvasAxisLabelRenderer.js';
+import 'updated-jqplot/dist/plugins/jqplot.canvasTextRenderer.js';
+import 'updated-jqplot/dist/plugins/jqplot.categoryAxisRenderer.js';
+import 'updated-jqplot/dist/plugins/jqplot.dateAxisRenderer.js';
+import 'updated-jqplot/dist/plugins/jqplot.pointLabels.js';
+
/**
* Chart type enumerations
*/
diff --git a/js/src/consts/files.js b/js/src/consts/files.js
index 6526284dfc..22072897f9 100644
--- a/js/src/consts/files.js
+++ b/js/src/consts/files.js
@@ -7,7 +7,7 @@
* @type {Object} files
*/
const PhpToJsFileMapping = {
- global: ['error_report', 'config', 'navigation', 'page_settings', 'shortcuts_handler', 'functions'],
+ global: ['error_report', 'config', 'navigation', 'page_settings', 'shortcuts_handler', 'functions', 'indexes'],
server_privileges: ['server_privileges'],
server_databases: ['server_databases'],
server_status_advisor: ['server_status_advisor'],
@@ -24,15 +24,28 @@ const PhpToJsFileMapping = {
server_import: ['import'],
db_search: ['db_search', 'sql'],
server_sql: ['sql', 'multi_column_sort'],
- tbl_sql: ['sql', 'multi_column_sort'],
+ tbl_sql: ['sql', 'multi_column_sort', 'tbl_change'],
db_sql: ['sql', 'multi_column_sort'],
sql: ['sql', 'multi_column_sort'],
- db_structure: ['db_structure'],
+ db_structure: ['db_structure', 'tbl_change'],
db_operations: ['db_operations'],
db_tracking: ['db_tracking'],
db_central_columns: ['db_central_columns'],
db_export: ['export'],
- db_import: ['import']
+ db_import: ['import'],
+ tbl_structure: ['tbl_structure'],
+ tbl_indexes: [],
+ tbl_relation: ['tbl_relation'],
+ tbl_replace: ['tbl_change', 'sql'],
+ tbl_chart: ['tbl_chart'],
+ tbl_operations: ['tbl_operations'],
+ tbl_tracking: ['tbl_tracking'],
+ tbl_change: ['sql', 'tbl_change'],
+ tbl_select: ['sql', 'tbl_change', 'tbl_select'],
+ tbl_zoom_select: ['sql', 'tbl_change'],
+ tbl_find_replace: ['tbl_find_replace'],
+ tbl_import: ['import'],
+ tbl_export: ['export']
};
const JsFileList = [
@@ -62,7 +75,16 @@ const JsFileList = [
'db_structure',
'db_operations',
'db_tracking',
- 'db_central_columns'
+ 'db_central_columns',
+ 'indexes',
+ 'tbl_structure',
+ 'tbl_relation',
+ 'tbl_chart',
+ 'tbl_operations',
+ 'tbl_tracking',
+ 'tbl_change',
+ 'tbl_select',
+ 'tbl_find_replace'
];
export {
diff --git a/js/src/functions.js b/js/src/functions.js
index ad0e2f5418..831662544b 100644
--- a/js/src/functions.js
+++ b/js/src/functions.js
@@ -20,6 +20,8 @@ import { checkTableEditForm, PMA_checkReservedWordColumns } from './functions/Ta
import { PMA_adjustTotals } from './functions/Database/Structure';
import { PMA_verifyColumnsProperties, PMA_hideShowConnection } from './functions/Table/TableColumns';
+import { addDateTimePicker } from './utils/DateTime';
+
/**
* Here we register a function that will remove the onsubmit event from all
* forms that will be handled by the generic page loader. We then save this
@@ -493,3 +495,110 @@ export function onloadCreateTable () {
});
}
/* *************************************** CREATE TABLE STARTS *************************************** */
+
+/* ************************************** HANDLE CHECKALL CLICK ************************************** */
+/**
+ * True if last click is to check a row.
+ */
+var last_click_checked = false;
+
+/**
+ * Zero-based index of last clicked row.
+ * Used to handle the shift + click event in the code above.
+ */
+var last_clicked_row = -1;
+
+/**
+ * Zero-based index of last shift clicked row.
+ */
+var last_shift_clicked_row = -1;
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teadownFunctions () {
+ $(document).off('click', 'input:checkbox.checkall');
+}
+
+export function onloadFunctions () {
+ /**
+ * Row marking in horizontal mode (use "on" so that it works also for
+ * next pages reached via AJAX); a tr may have the class noclick to remove
+ * this behavior.
+ */
+
+ $(document).on('click', 'input:checkbox.checkall', function (e) {
+ var $this = $(this);
+ var $tr = $this.closest('tr');
+ var $table = $this.closest('table');
+
+ if (!e.shiftKey || last_clicked_row === -1) {
+ // usual click
+
+ var $checkbox = $tr.find(':checkbox.checkall');
+ var checked = $this.prop('checked');
+ $checkbox.prop('checked', checked).trigger('change');
+ if (checked) {
+ $tr.addClass('marked');
+ } else {
+ $tr.removeClass('marked');
+ }
+ last_click_checked = checked;
+
+ // remember the last clicked row
+ last_clicked_row = last_click_checked ? $table.find('tr:not(.noclick)').index($tr) : -1;
+ last_shift_clicked_row = -1;
+ } else {
+ // handle the shift click
+ PMA_clearSelection();
+ var start;
+ var end;
+
+ // clear last shift click result
+ if (last_shift_clicked_row >= 0) {
+ if (last_shift_clicked_row >= last_clicked_row) {
+ start = last_clicked_row;
+ end = last_shift_clicked_row;
+ } else {
+ start = last_shift_clicked_row;
+ end = last_clicked_row;
+ }
+ $tr.parent().find('tr:not(.noclick)')
+ .slice(start, end + 1)
+ .removeClass('marked')
+ .find(':checkbox')
+ .prop('checked', false)
+ .trigger('change');
+ }
+
+ // handle new shift click
+ var curr_row = $table.find('tr:not(.noclick)').index($tr);
+ if (curr_row >= last_clicked_row) {
+ start = last_clicked_row;
+ end = curr_row;
+ } else {
+ start = curr_row;
+ end = last_clicked_row;
+ }
+ $tr.parent().find('tr:not(.noclick)')
+ .slice(start, end)
+ .addClass('marked')
+ .find(':checkbox')
+ .prop('checked', true)
+ .trigger('change');
+
+ // remember the last shift clicked row
+ last_shift_clicked_row = curr_row;
+ }
+ });
+
+ addDateTimePicker();
+
+ /**
+ * Add attribute to text boxes for iOS devices (based on bugID: 3508912)
+ */
+ if (navigator.userAgent.match(/(iphone|ipod|ipad)/i)) {
+ $('input[type=text]').attr('autocapitalize', 'off').attr('autocorrect', 'off');
+ }
+}
+/* ************************************** HANDLE CHECKALL CLICK ************************************** */
diff --git a/js/src/functions/Indexes.js b/js/src/functions/Indexes.js
new file mode 100644
index 0000000000..9d854ae959
--- /dev/null
+++ b/js/src/functions/Indexes.js
@@ -0,0 +1,692 @@
+import IndexEnum from '../utils/IndexEnum';
+import { PMA_Messages as PMA_messages } from '../variables/export_variables';
+import PMA_commonParams from '../variables/common_params';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage, PMA_showHints } from '../utils/show_ajax_messages';
+import { PMA_prepareForAjaxRequest } from './AjaxRequest';
+import { PMA_highlightSQL } from '../utils/sql';
+import { PMA_previewSQL } from './Sql/PreviewSql';
+import { PMA_verifyColumnsProperties } from './Table/TableColumns';
+import { PMA_sprintf } from '../utils/sprintf';
+import { PMA_init_slider } from '../utils/Slider';
+import { PMA_reloadNavigation } from './navigation';
+
+/**
+ * Returns the array of indexes based on the index choice
+ *
+ * @param index_choice index choice
+ */
+export function PMA_getIndexArray (index_choice) {
+ var source_array = null;
+
+ switch (index_choice.toLowerCase()) {
+ case 'primary':
+ source_array = IndexEnum.primary_indexes;
+ break;
+ case 'unique':
+ source_array = IndexEnum.unique_indexes;
+ break;
+ case 'index':
+ source_array = IndexEnum.indexes;
+ break;
+ case 'fulltext':
+ source_array = IndexEnum.fulltext_indexes;
+ break;
+ case 'spatial':
+ source_array = IndexEnum.spatial_indexes;
+ break;
+ default:
+ return null;
+ }
+ return source_array;
+}
+
+/**
+ * Hides/shows the inputs and submits appropriately depending
+ * on whether the index type chosen is 'SPATIAL' or not.
+ */
+export function checkIndexType () {
+ /**
+ * @var Object Dropdown to select the index choice.
+ */
+ var $select_index_choice = $('#select_index_choice');
+ /**
+ * @var Object Dropdown to select the index type.
+ */
+ var $select_index_type = $('#select_index_type');
+ /**
+ * @var Object Table header for the size column.
+ */
+ var $size_header = $('#index_columns').find('thead tr th:nth-child(2)');
+ /**
+ * @var Object Inputs to specify the columns for the index.
+ */
+ var $column_inputs = $('select[name="index[columns][names][]"]');
+ /**
+ * @var Object Inputs to specify sizes for columns of the index.
+ */
+ var $size_inputs = $('input[name="index[columns][sub_parts][]"]');
+ /**
+ * @var Object Footer containg the controllers to add more columns
+ */
+ var $add_more = $('#index_frm').find('.add_more');
+
+ if ($select_index_choice.val() === 'SPATIAL') {
+ // Disable and hide the size column
+ $size_header.hide();
+ $size_inputs.each(function () {
+ $(this)
+ .prop('disabled', true)
+ .parent('td').hide();
+ });
+
+ // Disable and hide the columns of the index other than the first one
+ var initial = true;
+ $column_inputs.each(function () {
+ var $column_input = $(this);
+ if (! initial) {
+ $column_input
+ .prop('disabled', true)
+ .parent('td').hide();
+ } else {
+ initial = false;
+ }
+ });
+
+ // Hide controllers to add more columns
+ $add_more.hide();
+ } else {
+ // Enable and show the size column
+ $size_header.show();
+ $size_inputs.each(function () {
+ $(this)
+ .prop('disabled', false)
+ .parent('td').show();
+ });
+
+ // Enable and show the columns of the index
+ $column_inputs.each(function () {
+ $(this)
+ .prop('disabled', false)
+ .parent('td').show();
+ });
+
+ // Show controllers to add more columns
+ $add_more.show();
+ }
+
+ if ($select_index_choice.val() === 'SPATIAL' ||
+ $select_index_choice.val() === 'FULLTEXT') {
+ $select_index_type.val('').prop('disabled', true);
+ } else {
+ $select_index_type.prop('disabled', false);
+ }
+}
+
+/**
+ * Sets current index information into form parameters.
+ *
+ * @param array source_array Array containing index columns
+ * @param string index_choice Choice of index
+ *
+ * @return void
+ */
+function PMA_setIndexFormParameters (source_array, index_choice) {
+ if (index_choice === 'index') {
+ $('input[name="indexes"]').val(JSON.stringify(source_array));
+ } else {
+ $('input[name="' + index_choice + '_indexes"]').val(JSON.stringify(source_array));
+ }
+}
+
+/**
+ * Removes a column from an Index.
+ *
+ * @param string col_index Index of column in form
+ *
+ * @return void
+ */
+export function PMA_removeColumnFromIndex (col_index) {
+ // Get previous index details.
+ var previous_index = $('select[name="field_key[' + col_index + ']"]')
+ .attr('data-index');
+ if (previous_index.length) {
+ previous_index = previous_index.split(',');
+ var source_array = PMA_getIndexArray(previous_index[0]);
+ if (source_array === null) {
+ return;
+ }
+
+ // Remove column from index array.
+ var source_length = source_array[previous_index[1]].columns.length;
+ for (var i = 0; i < source_length; i++) {
+ if (source_array[previous_index[1]].columns[i].col_index === col_index) {
+ source_array[previous_index[1]].columns.splice(i, 1);
+ }
+ }
+
+ // Remove index completely if no columns left.
+ if (source_array[previous_index[1]].columns.length === 0) {
+ source_array.splice(previous_index[1], 1);
+ }
+
+ // Update current index details.
+ $('select[name="field_key[' + col_index + ']"]').attr('data-index', '');
+ // Update form index parameters.
+ PMA_setIndexFormParameters(source_array, previous_index[0].toLowerCase());
+ }
+}
+
+/**
+ * Adds a column to an Index.
+ *
+ * @param array source_array Array holding corresponding indexes
+ * @param string array_index Index of an INDEX in array
+ * @param string index_choice Choice of Index
+ * @param string col_index Index of column on form
+ *
+ * @return void
+ */
+function PMA_addColumnToIndex (source_array, array_index, index_choice, col_index) {
+ if (col_index >= 0) {
+ // Remove column from other indexes (if any).
+ PMA_removeColumnFromIndex(col_index);
+ }
+ var index_name = $('input[name="index[Key_name]"]').val();
+ var index_comment = $('input[name="index[Index_comment]"]').val();
+ var key_block_size = $('input[name="index[Key_block_size]"]').val();
+ var parser = $('input[name="index[Parser]"]').val();
+ var index_type = $('select[name="index[Index_type]"]').val();
+ var columns = [];
+ $('#index_columns').find('tbody').find('tr').each(function () {
+ // Get columns in particular order.
+ var col_index = $(this).find('select[name="index[columns][names][]"]').val();
+ var size = $(this).find('input[name="index[columns][sub_parts][]"]').val();
+ columns.push({
+ 'col_index': col_index,
+ 'size': size
+ });
+ });
+
+ // Update or create an index.
+ source_array[array_index] = {
+ 'Key_name': index_name,
+ 'Index_comment': index_comment,
+ 'Index_choice': index_choice.toUpperCase(),
+ 'Key_block_size': key_block_size,
+ 'Parser': parser,
+ 'Index_type': index_type,
+ 'columns': columns
+ };
+
+ // Display index name (or column list)
+ var displayName = index_name;
+ 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 = $('<a id="' + id + '" href="#" class="ajax show_index_dialog"></a>');
+ $name.insertAfter($('select[name="field_key[' + this.col_index + ']"]'));
+ }
+ var $text = $('<small>').text(displayName);
+ $name.html($text);
+ });
+
+ if (col_index >= 0) {
+ // Update index details on form.
+ $('select[name="field_key[' + col_index + ']"]')
+ .attr('data-index', index_choice + ',' + array_index);
+ }
+ PMA_setIndexFormParameters(source_array, index_choice.toLowerCase());
+}
+
+/**
+ * Get choices list for a column to create a composite index with.
+ *
+ * @param string index_choice Choice of index
+ * @param array source_array Array hodling columns for particular index
+ *
+ * @return jQuery Object
+ */
+function PMA_getCompositeIndexList (source_array, col_index) {
+ // Remove any previous list.
+ if ($('#composite_index_list').length) {
+ $('#composite_index_list').remove();
+ }
+
+ // Html list.
+ var $composite_index_list = $(
+ '<ul id="composite_index_list">' +
+ '<div>' + PMA_messages.strCompositeWith + '</div>' +
+ '</ul>'
+ );
+
+ // Add each column to list available for composite index.
+ var source_length = source_array.length;
+ var already_present = false;
+ for (var i = 0; i < source_length; i++) {
+ var sub_array_len = source_array[i].columns.length;
+ var column_names = [];
+ for (var j = 0; j < sub_array_len; j++) {
+ column_names.push(
+ $('input[name="field_name[' + source_array[i].columns[j].col_index + ']"]').val()
+ );
+
+ if (col_index === source_array[i].columns[j].col_index) {
+ already_present = true;
+ }
+ }
+
+ $composite_index_list.append(
+ '<li>' +
+ '<input type="radio" name="composite_with" ' +
+ (already_present ? 'checked="checked"' : '') +
+ ' id="composite_index_' + i + '" value="' + i + '">' +
+ '<label for="composite_index_' + i + '">' + column_names.join(', ') +
+ '</lablel>' +
+ '</li>'
+ );
+ }
+
+ return $composite_index_list;
+}
+
+/**
+ * Ensures indexes names are valid according to their type and, for a primary
+ * key, lock index name to 'PRIMARY'
+ * @param string form_id Variable which parses the form name as
+ * the input
+ * @return boolean false if there is no index form, true else
+ */
+export function checkIndexName (form_id) {
+ if ($('#' + form_id).length === 0) {
+ return false;
+ }
+
+ // Gets the elements pointers
+ var $the_idx_name = $('#input_index_name');
+ var $the_idx_choice = $('#select_index_choice');
+
+ // Index is a primary key
+ if ($the_idx_choice.find('option:selected').val() === 'PRIMARY') {
+ $the_idx_name.val('PRIMARY');
+ $the_idx_name.prop('disabled', true);
+ } else {
+ if ($the_idx_name.val() === 'PRIMARY') {
+ $the_idx_name.val('');
+ }
+ $the_idx_name.prop('disabled', false);
+ }
+
+ return true;
+} // end of the 'checkIndexName()' function
+
+/**
+ * Shows 'Add Index' dialog.
+ *
+ * @param array source_array Array holding particluar index
+ * @param string array_index Index of an INDEX in array
+ * @param array target_columns Columns for an INDEX
+ * @param string col_index Index of column on form
+ * @param object index Index detail object
+ *
+ * @return void
+ */
+export function PMA_showAddIndexDialog (source_array, array_index, target_columns, col_index, index) {
+ // Prepare post-data.
+ var $table = $('input[name="table"]');
+ var table = $table.length > 0 ? $table.val() : '';
+ var post_data = {
+ server: PMA_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 < target_columns.length; i++) {
+ var column_name = $('input[name="field_name[' + target_columns[i] + ']"]').val();
+ var column_type = $('select[name="field_type[' + target_columns[i] + ']"]').val().toLowerCase();
+ columns[column_name] = [column_type, target_columns[i]];
+ }
+ post_data.columns = JSON.stringify(columns);
+
+ var button_options = {};
+ button_options[PMA_messages.strGo] = function () {
+ var is_missing_value = false;
+ $('select[name="index[columns][names][]"]').each(function () {
+ if ($(this).val() === '') {
+ is_missing_value = true;
+ }
+ });
+
+ if (! is_missing_value) {
+ PMA_addColumnToIndex(
+ source_array,
+ array_index,
+ index.Index_choice,
+ col_index
+ );
+ } else {
+ PMA_ajaxShowMessage(
+ '<div class="error"><img src="themes/dot.gif" title="" alt=""' +
+ ' class="icon ic_s_error" /> ' + PMA_messages.strMissingColumn +
+ ' </div>', false
+ );
+
+ return false;
+ }
+
+ $(this).dialog('close');
+ };
+ button_options[PMA_messages.strCancel] = function () {
+ if (col_index >= 0) {
+ // Handle state on 'Cancel'.
+ var $select_list = $('select[name="field_key[' + col_index + ']"]');
+ if (! $select_list.attr('data-index').length) {
+ $select_list.find('option[value*="none"]').attr('selected', 'selected');
+ } else {
+ var previous_index = $select_list.attr('data-index').split(',');
+ $select_list.find('option[value*="' + previous_index[0].toLowerCase() + '"]')
+ .attr('selected', 'selected');
+ }
+ }
+ $(this).dialog('close');
+ };
+ var $msgbox = PMA_ajaxShowMessage();
+ $.post('tbl_indexes.php', post_data, function (data) {
+ if (data.success === false) {
+ // in the case of an error, show the error message returned.
+ PMA_ajaxShowMessage(data.error, false);
+ } else {
+ PMA_ajaxRemoveMessage($msgbox);
+ // Show dialog if the request was successful
+ var $div = $('<div/>');
+ $div
+ .append(data.message)
+ .dialog({
+ title: PMA_messages.strAddIndex,
+ width: 450,
+ minHeight: 250,
+ open: function () {
+ checkIndexName('index_frm');
+ PMA_showHints($div);
+ PMA_init_slider();
+ $('#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'
+ });
+ // We dont need the slider at this moment.
+ $(this).find('fieldset.tblFooters').remove();
+ },
+ modal: true,
+ buttons: button_options,
+ close: function () {
+ $(this).remove();
+ }
+ });
+ }
+ });
+}
+
+/**
+ * Creates a advanced index type selection dialog.
+ *
+ * @param array source_array Array holding a particular type of indexes
+ * @param string index_choice Choice of index
+ * @param string col_index Index of new column on form
+ *
+ * @return void
+ */
+export function PMA_indexTypeSelectionDialog (source_array, index_choice, col_index) {
+ var $single_column_radio = $('<input type="radio" id="single_column" name="index_choice"' +
+ ' checked="checked">' +
+ '<label for="single_column">' + PMA_messages.strCreateSingleColumnIndex + '</label>');
+ var $composite_index_radio = $('<input type="radio" id="composite_index"' +
+ ' name="index_choice">' +
+ '<label for="composite_index">' + PMA_messages.strCreateCompositeIndex + '</label>');
+ var $dialog_content = $('<fieldset id="advance_index_creator"></fieldset>');
+ $dialog_content.append('<legend>' + index_choice.toUpperCase() + '</legend>');
+
+
+ // For UNIQUE/INDEX type, show choice for single-column and composite index.
+ $dialog_content.append($single_column_radio);
+ $dialog_content.append($composite_index_radio);
+
+ var button_options = {};
+ // 'OK' operation.
+ button_options[PMA_messages.strGo] = function () {
+ if ($('#single_column').is(':checked')) {
+ var index = {
+ 'Key_name': (index_choice === 'primary' ? 'PRIMARY' : ''),
+ 'Index_choice': index_choice.toUpperCase()
+ };
+ PMA_showAddIndexDialog(source_array, (source_array.length), [col_index], col_index, index);
+ }
+
+ if ($('#composite_index').is(':checked')) {
+ if ($('input[name="composite_with"]').length !== 0 && $('input[name="composite_with"]:checked').length === 0
+ ) {
+ PMA_ajaxShowMessage(
+ '<div class="error"><img src="themes/dot.gif" title=""' +
+ ' alt="" class="icon ic_s_error" /> ' +
+ PMA_messages.strFormEmpty +
+ ' </div>',
+ false
+ );
+ return false;
+ }
+
+ var array_index = $('input[name="composite_with"]:checked').val();
+ var source_length = source_array[array_index].columns.length;
+ var target_columns = [];
+ for (var i = 0; i < source_length; i++) {
+ target_columns.push(source_array[array_index].columns[i].col_index);
+ }
+ target_columns.push(col_index);
+
+ PMA_showAddIndexDialog(source_array, array_index, target_columns, col_index,
+ source_array[array_index]);
+ }
+
+ $(this).remove();
+ };
+ button_options[PMA_messages.strCancel] = function () {
+ // Handle state on 'Cancel'.
+ var $select_list = $('select[name="field_key[' + col_index + ']"]');
+ if (! $select_list.attr('data-index').length) {
+ $select_list.find('option[value*="none"]').attr('selected', 'selected');
+ } else {
+ var previous_index = $select_list.attr('data-index').split(',');
+ $select_list.find('option[value*="' + previous_index[0].toLowerCase() + '"]')
+ .attr('selected', 'selected');
+ }
+ $(this).remove();
+ };
+ var $dialog = $('<div/>').append($dialog_content).dialog({
+ minWidth: 525,
+ minHeight: 200,
+ modal: true,
+ title: PMA_messages.strAddIndex,
+ resizable: false,
+ buttons: button_options,
+ open: function () {
+ $('#composite_index').on('change', function () {
+ if ($(this).is(':checked')) {
+ $dialog_content.append(PMA_getCompositeIndexList(source_array, col_index));
+ }
+ });
+ $('#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();
+ }
+ });
+}
+
+export function showIndexEditDialog ($outer) {
+ checkIndexType();
+ checkIndexName('index_frm');
+ var $indexColumns = $('#index_columns');
+ $indexColumns.find('td').each(function () {
+ $(this).css('width', $(this).width() + 'px');
+ });
+ $indexColumns.find('tbody').sortable({
+ axis: 'y',
+ containment: $indexColumns.find('tbody'),
+ tolerance: 'pointer'
+ });
+ PMA_showHints($outer);
+ PMA_init_slider();
+ // Add a slider for selecting how many columns to add to the index
+ $outer.find('.slider').slider({
+ animate: true,
+ value: 1,
+ min: 1,
+ max: 16,
+ slide: function (event, ui) {
+ $(this).closest('fieldset').find('input[type=submit]').val(
+ PMA_sprintf(PMA_messages.strAddToIndex, ui.value)
+ );
+ }
+ });
+ $('div.add_fields').removeClass('hide');
+ // focus index size input on column picked
+ $outer.find('table#index_columns select').on('change', function () {
+ if ($(this).find('option:selected').val() === '') {
+ return true;
+ }
+ $(this).closest('tr').find('input').focus();
+ });
+ // Focus the slider, otherwise it looks nearly transparent
+ $('a.ui-slider-handle').addClass('ui-state-focus');
+ // set focus on index name input, if empty
+ var input = $outer.find('input#input_index_name');
+ if (! input.val()) {
+ input.focus();
+ }
+}
+
+export function indexEditorDialog (url, title, callback_success, callback_failure) {
+ /* Remove the hidden dialogs if there are*/
+ var $editIndexDialog = $('#edit_index_dialog');
+ if ($editIndexDialog.length !== 0) {
+ $editIndexDialog.remove();
+ }
+ var $div = $('<div id="edit_index_dialog"></div>');
+
+ /**
+ * @var button_options Object that stores the options
+ * passed to jQueryUI dialog
+ */
+ var button_options = {};
+ button_options[PMA_messages.strGo] = function () {
+ /**
+ * @var the_form object referring to the export form
+ */
+ var $form = $('#index_frm');
+ var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+ PMA_prepareForAjaxRequest($form);
+ // User wants to submit the form
+ $.post($form.attr('action'), $form.serialize() + PMA_commonParams.get('arg_separator') + 'do_save_data=1', function (data) {
+ var $sqlqueryresults = $('.sqlqueryresults');
+ if ($sqlqueryresults.length !== 0) {
+ $sqlqueryresults.remove();
+ }
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_ajaxShowMessage(data.message);
+ var $resultQuery = $('.result_query');
+ if ($resultQuery.length) {
+ $resultQuery.remove();
+ }
+ if (data.sql_query) {
+ $('<div class="result_query"></div>')
+ .html(data.sql_query)
+ .prependTo('#page_content');
+ PMA_highlightSQL($('#page_content'));
+ }
+ $('.result_query .notice').remove();
+ $resultQuery.prepend(data.message);
+ /* Reload the field form*/
+ $('#table_index').remove();
+ $('<div id=\'temp_div\'><div>')
+ .append(data.index_table)
+ .find('#table_index')
+ .insertAfter('#index_header');
+ var $editIndexDialog = $('#edit_index_dialog');
+ if ($editIndexDialog.length > 0) {
+ $editIndexDialog.dialog('close');
+ }
+ $('div.no_indexes_defined').hide();
+ if (callback_success) {
+ callback_success();
+ }
+ PMA_reloadNavigation();
+ } else {
+ var $temp_div = $('<div id=\'temp_div\'><div>').append(data.error);
+ var $error;
+ if ($temp_div.find('.error code').length !== 0) {
+ $error = $temp_div.find('.error code').addClass('error');
+ } else {
+ $error = $temp_div;
+ }
+ if (callback_failure) {
+ callback_failure();
+ }
+ PMA_ajaxShowMessage($error, false);
+ }
+ }); // end $.post()
+ };
+ button_options[PMA_messages.strPreviewSQL] = function () {
+ // Function for Previewing SQL
+ var $form = $('#index_frm');
+ PMA_previewSQL($form);
+ };
+ button_options[PMA_messages.strCancel] = function () {
+ $(this).dialog('close');
+ };
+ var $msgbox = PMA_ajaxShowMessage();
+ $.get('tbl_indexes.php', url, function (data) {
+ if (typeof data !== 'undefined' && data.success === false) {
+ // in the case of an error, show the error message returned.
+ PMA_ajaxShowMessage(data.error, false);
+ } else {
+ PMA_ajaxRemoveMessage($msgbox);
+ // Show dialog if the request was successful
+ $div
+ .append(data.message)
+ .dialog({
+ title: title,
+ width: 'auto',
+ open: PMA_verifyColumnsProperties,
+ modal: true,
+ buttons: button_options,
+ close: function () {
+ $(this).remove();
+ }
+ });
+ $div.find('.tblFooters').remove();
+ showIndexEditDialog($div);
+ }
+ }); // end $.get()
+}
diff --git a/js/src/functions/Table/Relation.js b/js/src/functions/Table/Relation.js
new file mode 100644
index 0000000000..a987a6867a
--- /dev/null
+++ b/js/src/functions/Table/Relation.js
@@ -0,0 +1,117 @@
+import { $ } from '../../utils/JqueryExtended';
+import { escapeHtml } from '../../utils/Sanitise';
+import PMA_commonParams from '../../variables/common_params';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from '../../utils/show_ajax_messages';
+/**
+ * for tbl_relation.php
+ *
+ */
+function show_hide_clauses ($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
+ */
+function setDropdownValues ($dropdown, values, selectedValue) {
+ $dropdown.empty();
+ var optionsAsString = '';
+ // add an empty string to the beginning for empty selection
+ values.unshift('');
+ $.each(values, function () {
+ optionsAsString += '<option value=\'' + escapeHtml(this) + '\'' + (selectedValue === escapeHtml(this) ? ' selected=\'selected\'' : '') + '>' + escapeHtml(this) + '</option>';
+ });
+ $dropdown.append($(optionsAsString));
+}
+
+/**
+ * Retrieves and populates dropdowns to the left based on the selected value
+ *
+ * @param $dropdown the dropdown whose value got changed
+ */
+export function getDropdownValues ($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 === '') {
+ setDropdownValues($tableDd, []);
+ 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 === '') {
+ setDropdownValues($columnDd, []);
+ return;
+ }
+ }
+ var $msgbox = PMA_ajaxShowMessage();
+ var $form = $dropdown.parents('form');
+ var argsep = PMA_commonParams.get('arg_separator');
+ var url = 'tbl_relation.php?getDropdownValues=true' + argsep + 'ajax_request=true' +
+ argsep + 'db=' + $form.find('input[name="db"]').val() +
+ argsep + 'table=' + $form.find('input[name="table"]').val() +
+ argsep + 'foreign=' + (foreign !== '') +
+ argsep + 'foreignDb=' + encodeURIComponent(foreignDb) +
+ (foreignTable !== null ?
+ argsep + 'foreignTable=' + encodeURIComponent(foreignTable) : ''
+ );
+ var $server = $form.find('input[name="server"]');
+ if ($server.length > 0) {
+ url += argsep + 'server=' + $form.find('input[name="server"]').val();
+ }
+ $.ajax({
+ url: url,
+ datatype: 'json',
+ success: function (data) {
+ PMA_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
+ setDropdownValues($tableDd, data.tables);
+ 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];
+ }
+ setDropdownValues($columnDd.first(), data.columns, primary);
+ setDropdownValues($columnDd.slice(1), data.columns);
+ }
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }
+ });
+}
diff --git a/js/src/functions/Table/TableChange.js b/js/src/functions/Table/TableChange.js
new file mode 100644
index 0000000000..3b9133de61
--- /dev/null
+++ b/js/src/functions/Table/TableChange.js
@@ -0,0 +1,296 @@
+import { $ } from '../../utils/JqueryExtended';
+import { PMA_Messages as PMA_messages } from '../../variables/export_variables';
+
+/**
+ * Modify form controls when the "NULL" checkbox is checked
+ *
+ * @param theType string the MySQL field type
+ * @param urlField string the urlencoded field name - OBSOLETE
+ * @param md5Field string the md5 hashed field name
+ * @param multi_edit string the multi_edit row sequence number
+ *
+ * @return boolean always true
+ */
+export function nullify (theType, urlField, md5Field, multi_edit) {
+ var rowForm = document.forms.insertForm;
+
+ if (typeof(rowForm.elements['funcs' + multi_edit + '[' + md5Field + ']']) !== 'undefined') {
+ rowForm.elements['funcs' + multi_edit + '[' + md5Field + ']'].selectedIndex = -1;
+ }
+
+ // "ENUM" field with more than 20 characters
+ if (theType === 1) {
+ rowForm.elements['fields' + multi_edit + '[' + md5Field + ']'][1].selectedIndex = -1;
+ // Other "ENUM" field
+ } else if (theType === 2) {
+ var elts = rowForm.elements['fields' + multi_edit + '[' + md5Field + ']'];
+ // when there is just one option in ENUM:
+ if (elts.checked) {
+ elts.checked = false;
+ } else {
+ var elts_cnt = elts.length;
+ for (var i = 0; i < elts_cnt; i++) {
+ elts[i].checked = false;
+ } // end for
+ } // end if
+ // "SET" field
+ } else if (theType === 3) {
+ rowForm.elements['fields' + multi_edit + '[' + md5Field + '][]'].selectedIndex = -1;
+ // Foreign key field (drop-down)
+ } else if (theType === 4) {
+ rowForm.elements['fields' + multi_edit + '[' + md5Field + ']'].selectedIndex = -1;
+ // foreign key field (with browsing icon for foreign values)
+ } else if (theType === 6) {
+ rowForm.elements['fields' + multi_edit + '[' + md5Field + ']'].value = '';
+ // Other field types
+ } else /* if (theType === 5)*/ {
+ rowForm.elements['fields' + multi_edit + '[' + 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 (num) {
+ num = parseInt(num, 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
+*/
+export function isDate (val, tmstmp) {
+ val = val.replace(/[.|*|^|+|//|@]/g, '-');
+ var arrayVal = val.split('-');
+ for (var a = 0; a < arrayVal.length; a++) {
+ if (arrayVal[a].length === 1) {
+ arrayVal[a] = fractionReplace(arrayVal[a]);
+ }
+ }
+ val = 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 (val.length === 8) {
+ pos = 0;
+ }
+ if (dtexp.test(val)) {
+ var month = parseInt(val.substring(pos + 3, pos + 5), 10);
+ var day = parseInt(val.substring(pos + 6, pos + 8), 10);
+ var year = parseInt(val.substring(0, pos + 2), 10);
+ if (month === 2 && day > daysInFebruary(year)) {
+ return false;
+ }
+ if (val.substring(0, pos + 2).length === 2) {
+ year = parseInt('20' + val.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
+*/
+export 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]);
+ }
+ }
+ val = 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(val);
+}
+
+/**
+ * To check whether insert section is ignored or not
+ */
+function checkForCheckbox (multi_edit) {
+ if ($('#insert_ignore_' + multi_edit).length) {
+ return $('#insert_ignore_' + multi_edit).is(':unchecked');
+ }
+ return true;
+}
+
+export function verificationsAfterFieldChange (urlField, multi_edit, theType) {
+ var evt = window.event || arguments.callee.caller.arguments[0];
+ var target = evt.target || evt.srcElement;
+ var $this_input = $(':input[name^=\'fields[multi_edit][' + multi_edit + '][' +
+ urlField + ']\']');
+ // the function drop-down that corresponds to this input field
+ var $this_function = $('select[name=\'funcs[multi_edit][' + multi_edit + '][' +
+ urlField + ']\']');
+ var function_selected = false;
+ if (typeof $this_function.val() !== 'undefined' &&
+ $this_function.val() !== null &&
+ $this_function.val().length > 0
+ ) {
+ function_selected = true;
+ }
+
+ // To generate the textbox that can take the salt
+ var new_salt_box = '<br><input type=text name=salt[multi_edit][' + multi_edit + '][' + urlField + ']' +
+ ' id=salt_' + target.id + ' placeholder=\'' + PMA_messages.strEncryptionKey + '\'>';
+
+ // 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)) {
+ $this_input.after(new_salt_box);
+ }
+ } else {
+ // Remove the textbox for salt
+ $('#salt_' + target.id).prev('br').remove();
+ $('#salt_' + target.id).remove();
+ }
+
+ // call validate before adding rules
+ $($this_input[0].form).validate();
+
+ if (target.value === 'AES_DECRYPT'
+ || target.value === 'AES_ENCRYPT'
+ || target.value === 'MD5') {
+ $('#' + target.id).rules('add', {
+ validationFunctionForFuns: {
+ param: $this_input,
+ depends: function () {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ });
+ }
+
+ // Unchecks the corresponding "NULL" control
+ $('input[name=\'fields_null[multi_edit][' + multi_edit + '][' + urlField + ']\']').prop('checked', false);
+
+ // Unchecks the Ignore checkbox for the current row
+ $('input[name=\'insert_ignore_' + multi_edit + '\']').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 (function_selected) {
+ $this_input.removeAttr('min');
+ $this_input.removeAttr('max');
+ // @todo: put back attributes if corresponding function is deselected
+ }
+
+ if ($this_input.data('rulesadded') === null && ! function_selected) {
+ // validate for date time
+ if (theType === 'datetime' || theType === 'time' || theType === 'date' || theType === 'timestamp') {
+ $this_input.rules('add', {
+ validationFunctionForDateTime: {
+ param: theType,
+ depends: function () {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ });
+ }
+ // validation for integer type
+ if ($this_input.data('type') === 'INT') {
+ var mini = parseInt($this_input.attr('min'));
+ var maxi = parseInt($this_input.attr('max'));
+ $this_input.rules('add', {
+ number: {
+ param : true,
+ depends: function () {
+ return checkForCheckbox(multi_edit);
+ }
+ },
+ min: {
+ param: mini,
+ depends: function () {
+ if (isNaN($this_input.val())) {
+ return false;
+ } else {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ },
+ max: {
+ param: maxi,
+ depends: function () {
+ if (isNaN($this_input.val())) {
+ return false;
+ } else {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ }
+ });
+ // validation for CHAR types
+ } else if ($this_input.data('type') === 'CHAR') {
+ var maxlen = $this_input.data('maxlength');
+ if (typeof maxlen !== 'undefined') {
+ if (maxlen <= 4) {
+ maxlen = charExceptionHandling;
+ }
+ $this_input.rules('add', {
+ maxlength: {
+ param: maxlen,
+ depends: function () {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ });
+ }
+ // validate binary & blob types
+ } else if ($this_input.data('type') === 'HEX') {
+ $this_input.rules('add', {
+ validationFunctionForHex: {
+ param: true,
+ depends: function () {
+ return checkForCheckbox(multi_edit);
+ }
+ }
+ });
+ }
+ $this_input.data('rulesadded', true);
+ } else if ($this_input.data('rulesadded') === true && function_selected) {
+ // remove any rules added
+ $this_input.rules('remove');
+ // remove any error messages
+ $this_input
+ .removeClass('error')
+ .removeAttr('aria-invalid')
+ .siblings('.error')
+ .remove();
+ $this_input.data('rulesadded', null);
+ }
+}
+
+window.verificationsAfterFieldChange = verificationsAfterFieldChange;
+/* End of fields validation*/
diff --git a/js/src/functions/Table/TableChart.js b/js/src/functions/Table/TableChart.js
new file mode 100644
index 0000000000..e00a36c6b1
--- /dev/null
+++ b/js/src/functions/Table/TableChart.js
@@ -0,0 +1,239 @@
+import { $ } from '../../utils/JqueryExtended';
+import JQPlotChartFactory, { DataTable, ColumnType } from '../../classes/Chart';
+import { escapeHtml } from '../../utils/Sanitise';
+import { PMA_Messages as PMA_messages } from '../../variables/export_variables';
+import { PMA_ajaxShowMessage } from '../../utils/show_ajax_messages';
+
+export var TableChartEnum = {
+ chart_data: {},
+ temp_chart_title: null,
+
+ currentChart: null,
+ currentSettings: null,
+
+ dateTimeCols: [],
+ 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 PMA_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 : 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;
+ 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 values = [];
+ 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, seriesNumber) {
+ 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]);
+ }
+
+ var values = [];
+ $.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;
+}
+
+export function drawChart () {
+ TableChartEnum.currentSettings.width = $('#resizer').width() - 20;
+ TableChartEnum.currentSettings.height = $('#resizer').height() - 20;
+
+ // TODO: a better way using .redraw() ?
+ if (TableChartEnum.currentChart !== null) {
+ TableChartEnum.currentChart.destroy();
+ }
+
+ var columnNames = [];
+ $('select[name="chartXAxis"] option').each(function () {
+ columnNames.push(escapeHtml($(this).text()));
+ });
+ try {
+ TableChartEnum.currentChart = PMA_queryChart(TableChartEnum.chart_data, columnNames, TableChartEnum.currentSettings);
+ if (TableChartEnum.currentChart !== null) {
+ $('#saveChart').attr('href', TableChartEnum.currentChart.toImageString());
+ }
+ } catch (err) {
+ PMA_ajaxShowMessage(err.message, false);
+ }
+}
+
+export function getSelectedSeries () {
+ var val = $('select[name="chartSeries"]').val() || [];
+ var ret = [];
+ $.each(val, function (i, v) {
+ ret.push(parseInt(v, 10));
+ });
+ return ret;
+}
+
+export function onXAxisChange () {
+ var $xAxisSelect = $('select[name="chartXAxis"]');
+ TableChartEnum.currentSettings.mainAxis = parseInt($xAxisSelect.val(), 10);
+ if (TableChartEnum.dateTimeCols.indexOf(TableChartEnum.currentSettings.mainAxis) !== -1) {
+ $('span.span_timeline').show();
+ } else {
+ $('span.span_timeline').hide();
+ if (TableChartEnum.currentSettings.type === 'timeline') {
+ $('input#radio_line').prop('checked', true);
+ TableChartEnum.currentSettings.type = 'line';
+ }
+ }
+ if (TableChartEnum.numericCols.indexOf(TableChartEnum.currentSettings.mainAxis) !== -1) {
+ $('span.span_scatter').show();
+ } else {
+ $('span.span_scatter').hide();
+ if (TableChartEnum.currentSettings.type === 'scatter') {
+ $('input#radio_line').prop('checked', true);
+ TableChartEnum.currentSettings.type = 'line';
+ }
+ }
+ var xaxis_title = $xAxisSelect.children('option:selected').text();
+ $('input[name="xaxis_label"]').val(xaxis_title);
+ TableChartEnum.currentSettings.xaxisLabel = xaxis_title;
+}
+
+export function onDataSeriesChange () {
+ var $seriesSelect = $('select[name="chartSeries"]');
+ TableChartEnum.currentSettings.selectedSeries = getSelectedSeries();
+ var yaxis_title;
+ if (TableChartEnum.currentSettings.selectedSeries.length === 1) {
+ $('span.span_pie').show();
+ yaxis_title = $seriesSelect.children('option:selected').text();
+ } else {
+ $('span.span_pie').hide();
+ if (TableChartEnum.currentSettings.type === 'pie') {
+ $('input#radio_line').prop('checked', true);
+ TableChartEnum.currentSettings.type = 'line';
+ }
+ yaxis_title = PMA_messages.strYValues;
+ }
+ $('input[name="yaxis_label"]').val(yaxis_title);
+ TableChartEnum.currentSettings.yaxisLabel = yaxis_title;
+}
diff --git a/js/src/functions/Table/TableColumns.js b/js/src/functions/Table/TableColumns.js
index ae672cee64..eef47c540f 100644
--- a/js/src/functions/Table/TableColumns.js
+++ b/js/src/functions/Table/TableColumns.js
@@ -1,3 +1,4 @@
+import { $ } from '../../utils/JqueryExtended';
/**
* Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected
*/
diff --git a/js/src/functions/Table/TableSelect.js b/js/src/functions/Table/TableSelect.js
new file mode 100644
index 0000000000..69302e9cab
--- /dev/null
+++ b/js/src/functions/Table/TableSelect.js
@@ -0,0 +1,51 @@
+import { $ } from '../../utils/JqueryExtended';
+
+export function changeValueFieldType (elem, searchIndex) {
+ var fieldsValue = $('select#fieldID_' + searchIndex);
+ if (0 === fieldsValue.size()) {
+ return;
+ }
+
+ var type = $(elem).val();
+ if ('IN (...)' === type ||
+ 'NOT IN (...)' === type ||
+ 'BETWEEN' === type ||
+ 'NOT BETWEEN' === type
+ ) {
+ $('#fieldID_' + searchIndex).attr('multiple', '');
+ } else {
+ $('#fieldID_' + searchIndex).removeAttr('multiple');
+ }
+}
+
+/**
+ * Checks if given data-type is numeric or date.
+ *
+ * @param string data_type Column data-type
+ *
+ * @return bool|string
+ */
+export function PMA_checkIfDataTypeNumericOrDate (data_type) {
+ // To test for numeric data-types.
+ var numeric_re = new RegExp(
+ 'TINYINT|SMALLINT|MEDIUMINT|INT|BIGINT|DECIMAL|FLOAT|DOUBLE|REAL',
+ 'i'
+ );
+
+ // To test for date data-types.
+ var date_re = new RegExp(
+ 'DATETIME|DATE|TIMESTAMP|TIME|YEAR',
+ 'i'
+ );
+
+ // Return matched data-type
+ if (numeric_re.test(data_type)) {
+ return numeric_re.exec(data_type)[0];
+ }
+
+ if (date_re.test(data_type)) {
+ return date_re.exec(data_type)[0];
+ }
+
+ return false;
+}
diff --git a/js/src/indexes.js b/js/src/indexes.js
new file mode 100644
index 0000000000..2c45bce527
--- /dev/null
+++ b/js/src/indexes.js
@@ -0,0 +1,264 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import IndexEnum from './utils/IndexEnum';
+import * as Indexes from './functions/Indexes';
+import { escapeHtml } from './utils/Sanitise';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
+import { PMA_hideShowConnection } from './functions/Table/TableColumns';
+import { PMA_previewSQL } from './functions/Sql/PreviewSql';
+import PMA_commonParams from './variables/common_params';
+import { AJAX } from './ajax';
+import { getJSConfirmCommonParam } from './functions/Common';
+import { PMA_commonActions } from './classes/CommonActions';
+import { PMA_highlightSQL } from './utils/sql';
+/**
+ * @fileoverview function used for index manipulation pages
+ * @name Table Structure
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @required js/functions.js
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownIndexes () {
+ $(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', '#index_frm input[type=submit]');
+ $('body').off('change', 'select[name*="field_key"]');
+ $(document).off('click', '.show_index_dialog');
+}
+
+/**
+ * @description <p>Ajax scripts for table index page</p>
+ *
+ * Actions ajaxified here:
+ * <ul>
+ * <li>Showing/hiding inputs depending on the index type chosen</li>
+ * <li>create/edit/drop indexes</li>
+ * </ul>
+ */
+export function onloadIndexes () {
+ // Re-initialize variables.
+ IndexEnum.primary_indexes = [];
+ IndexEnum.unique_indexes = [];
+ IndexEnum.indexes = [];
+ IndexEnum.fulltext_indexes = [];
+ IndexEnum.spatial_indexes = [];
+
+ // for table creation form
+ var $engine_selector = $('.create_table_form select[name=tbl_storage_engine]');
+ if ($engine_selector.length) {
+ PMA_hideShowConnection($engine_selector);
+ }
+
+ var $form = $('#index_frm');
+ if ($form.length > 0) {
+ Indexes.showIndexEditDialog($form);
+ }
+
+ $(document).on('click', '#save_index_frm', function (event) {
+ event.preventDefault();
+ var $form = $('#index_frm');
+ var argsep = PMA_commonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'do_save_data=1' + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ });
+
+ $(document).on('click', '#preview_index_frm', function (event) {
+ event.preventDefault();
+ PMA_previewSQL($('#index_frm'));
+ });
+
+ $(document).on('change', '#select_index_choice', function (event) {
+ event.preventDefault();
+ Indexes.checkIndexType();
+ Indexes.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 $curr_row Object containing reference to the current field's row
+ */
+ var $curr_row = $anchor.parents('tr');
+ /** @var Number of columns in the key */
+ var rows = $anchor.parents('td').attr('rowspan') || 1;
+ /** @var Rows that should be hidden */
+ var $rows_to_hide = $curr_row;
+ for (var i = 1, $last_row = $curr_row.next(); i < rows; i++, $last_row = $last_row.next()) {
+ $rows_to_hide = $rows_to_hide.add($last_row);
+ }
+
+ var question = escapeHtml(
+ $curr_row.children('td')
+ .children('.drop_primary_key_index_msg')
+ .val()
+ );
+
+ $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) {
+ var $msg = PMA_ajaxShowMessage(PMA_messages.strDroppingPrimaryKeyIndex, false);
+ var params = getJSConfirmCommonParam(this, $anchor.getPostData());
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_ajaxRemoveMessage($msg);
+ var $table_ref = $rows_to_hide.closest('table');
+ if ($rows_to_hide.length === $table_ref.find('tbody > tr').length) {
+ // We are about to remove all rows from the table
+ $table_ref.hide('medium', function () {
+ $('div.no_indexes_defined').show('medium');
+ $rows_to_hide.remove();
+ });
+ $table_ref.siblings('div.notice').hide('medium');
+ } else {
+ // We are removing some of the rows only
+ $rows_to_hide.hide('medium', function () {
+ $(this).remove();
+ });
+ }
+ if ($('.result_query').length) {
+ $('.result_query').remove();
+ }
+ if (data.sql_query) {
+ $('<div class="result_query"></div>')
+ .html(data.sql_query)
+ .prependTo('#structure_content');
+ PMA_highlightSQL($('#page_content'));
+ }
+ PMA_commonActions.refreshMain(false, function () {
+ $('a.ajax[href^=#indexes]').trigger('click');
+ });
+ PMA_reloadNavigation();
+ } else {
+ PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ }); // end $.PMA_confirm()
+ }); // 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 = checkFormElementInRange(
+ $(this).closest('form')[0],
+ 'added_fields',
+ 'Column count has to be larger than zero.'
+ );
+ if (! valid) {
+ return;
+ }
+ url = $(this).closest('form').serialize();
+ title = PMA_messages.strAddIndex;
+ } else {
+ // Edit index
+ url = $(this).find('a').attr('href');
+ if (url.substring(0, 16) === 'tbl_indexes.php?') {
+ url = url.substring(16, url.length);
+ }
+ title = PMA_messages.strEditIndex;
+ }
+ url += PMA_commonParams.get('arg_separator') + 'ajax_request=true';
+ Indexes.indexEditorDialog(url, title, function () {
+ // refresh the page using ajax
+ PMA_commonActions.refreshMain(false, function () {
+ $('a.ajax[href^=#indexes]').trigger('click');
+ });
+ });
+ });
+
+ /**
+ * Ajax event handler for advanced index creation during table creation
+ * and column addition.
+ */
+ $('body').on('change', 'select[name*="field_key"]', function () {
+ // Index of column on Table edit and create page.
+ var col_index = /\d+/.exec($(this).attr('name'));
+ col_index = col_index[0];
+ // Choice of selected index.
+ var index_choice = /[a-z]+/.exec($(this).val());
+ index_choice = index_choice[0];
+ // Array containing corresponding indexes.
+ var source_array = null;
+
+ if (index_choice === 'none') {
+ Indexes.PMA_removeColumnFromIndex(col_index);
+ return false;
+ }
+
+ // Select a source array.
+ source_array = Indexes.PMA_getIndexArray(index_choice);
+ if (source_array === null) {
+ return;
+ }
+
+ if (source_array.length === 0) {
+ var index = {
+ 'Key_name': (index_choice === 'primary' ? 'PRIMARY' : ''),
+ 'Index_choice': index_choice.toUpperCase()
+ };
+ Indexes.PMA_showAddIndexDialog(source_array, 0, [col_index], col_index, index);
+ } else {
+ if (index_choice === 'primary') {
+ var array_index = 0;
+ var source_length = source_array[array_index].columns.length;
+ var target_columns = [];
+ for (var i = 0; i < source_length; i++) {
+ target_columns.push(source_array[array_index].columns[i].col_index);
+ }
+ target_columns.push(col_index);
+
+ Indexes.PMA_showAddIndexDialog(source_array, array_index, target_columns, col_index,
+ source_array[array_index]);
+ } else {
+ // If there are multiple columns selected for an index, show advanced dialog.
+ Indexes.PMA_indexTypeSelectionDialog(source_array, index_choice, col_index);
+ }
+ }
+ });
+
+ $(document).on('click', '.show_index_dialog', function (e) {
+ e.preventDefault();
+
+ // Get index details.
+ var previous_index = $(this).prev('select')
+ .attr('data-index')
+ .split(',');
+
+ var index_choice = previous_index[0];
+ var array_index = previous_index[1];
+
+ var source_array = Indexes.PMA_getIndexArray(index_choice);
+ var source_length = source_array[array_index].columns.length;
+
+ var target_columns = [];
+ for (var i = 0; i < source_length; i++) {
+ target_columns.push(source_array[array_index].columns[i].col_index);
+ }
+
+ Indexes.PMA_showAddIndexDialog(source_array, array_index, target_columns, -1, source_array[array_index]);
+ });
+
+ $('#index_frm').on('submit', function () {
+ if (typeof(this.elements['index[Key_name]'].disabled) !== 'undefined') {
+ this.elements['index[Key_name]'].disabled = false;
+ }
+ });
+}
diff --git a/js/src/tbl_change.js b/js/src/tbl_change.js
new file mode 100644
index 0000000000..9868c2d425
--- /dev/null
+++ b/js/src/tbl_change.js
@@ -0,0 +1,409 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { $, extendingValidatorMessages } from './utils/JqueryExtended';
+import {
+ isDate,
+ isTime,
+ nullify,
+ verificationsAfterFieldChange
+} from './functions/Table/TableChange';
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import { addDateTimePicker } from './utils/DateTime';
+import { AJAX } from './ajax';
+
+/**
+ * @fileoverview function used in table data manipulation pages
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @requires js/functions.js
+ *
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownTblChange () {
+ $(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.
+ */
+export function onloadTblChange () {
+ if ($('#insertForm').length) {
+ // validate the comment form when it is submitted
+ $('#insertForm').validate();
+ jQuery.validator.addMethod('validationFunctionForHex', function (value, element) {
+ return value.match(/^[a-f0-9]*$/i) !== null;
+ });
+
+ jQuery.validator.addMethod('validationFunctionForFuns', function (value, element, options) {
+ if (value.substring(0, 3) === 'AES' && options.data('type') !== 'HEX') {
+ return false;
+ }
+
+ return !(value.substring(0, 3) === 'MD5' &&
+ typeof options.data('maxlength') !== 'undefined' &&
+ options.data('maxlength') < 32);
+ });
+
+ jQuery.validator.addMethod('validationFunctionForDateTime', function (value, element, options) {
+ var dt_value = value;
+ var theType = options;
+ if (theType === 'date') {
+ return isDate(dt_value);
+ } else if (theType === 'time') {
+ return isTime(dt_value);
+ } else if (theType === 'datetime' || theType === 'timestamp') {
+ var tmstmp = false;
+ dt_value = dt_value.trim();
+ if (dt_value === 'CURRENT_TIMESTAMP' || dt_value === 'current_timestamp()') {
+ return true;
+ }
+ if (theType === 'timestamp') {
+ tmstmp = true;
+ }
+ if (dt_value === '0000-00-00 00:00:00') {
+ return true;
+ }
+ var dv = dt_value.indexOf(' ');
+ if (dv === -1) { // Only the date component, which is valid
+ return isDate(dt_value, tmstmp);
+ }
+
+ return isDate(dt_value.substring(0, dv), tmstmp) &&
+ isTime(dt_value.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 input_name = $span.parent('td').children('input[type=\'text\']').attr('name');
+
+ openGISEditor();
+ if (!gisEditorLoaded) {
+ loadJSAndGISEditor(value, field, type, input_name);
+ } else {
+ loadGISEditor(value, field, type, input_name);
+ }
+ });
+
+ /**
+ * Forced validation check of fields
+ */
+ $(document).on('click','input[name^=\'insert_ignore_\']', function (event) {
+ $('#insertForm').valid();
+ });
+
+ /**
+ * Uncheck the null checkbox as geometry data is placed on the input field
+ */
+ $(document).on('click', 'input[name=\'gis_data[save]\']', function (event) {
+ var input_name = $('form#gis_data_editor_form').find('input[name=\'input_name\']').val();
+ var $null_checkbox = $('input[name=\'' + input_name + '\']').parents('tr').find('.checkbox_null');
+ $null_checkbox.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 tbl_change.php
+ $(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 auto_increment_column = $table.find('input[name^="auto_increment"]');
+ auto_increment_column.each(function () {
+ var $thisElemAIField = $(this);
+ var thisElemName = $thisElemAIField.attr('name');
+
+ var prev_value_field = $table.find('input[name="' + thisElemName.replace('auto_increment', 'fields_prev') + '"]');
+ var value_field = $table.find('input[name="' + thisElemName.replace('auto_increment', 'fields') + '"]');
+ var previous_value = $(prev_value_field).val();
+ if (previous_value !== undefined) {
+ if (thisElemSubmitTypeVal === 'insert'
+ || thisElemSubmitTypeVal === 'insertignore'
+ || thisElemSubmitTypeVal === 'showinsert'
+ ) {
+ $(value_field).val(0);
+ } else {
+ $(value_field).val(previous_value);
+ }
+ }
+ });
+ });
+
+ /**
+ * Continue Insertion form
+ */
+ $(document).on('change', '#insert_rows', function (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 curr_rows = $('table.insertRowTable').length;
+ /**
+ * @var target_rows Number of rows the user wants
+ */
+ var target_rows = $('#insert_rows').val();
+
+ // remove all datepickers
+ $('input.datefield, input.datetimefield').each(function () {
+ $(this).datepicker('destroy');
+ });
+
+ if (curr_rows < target_rows) {
+ var tempIncrementIndex = function () {
+ var $this_element = $(this);
+ /**
+ * Extract the index from the name attribute for all input/select fields and increment it
+ * name is of format funcs[multi_edit][10][<long random string of alphanum chars>]
+ */
+
+ /**
+ * @var this_name String containing name of the input/select elements
+ */
+ var this_name = $this_element.attr('name');
+ /** split {@link this_name} at [10], so we have the parts that can be concatenated later */
+ var name_parts = this_name.split(/\[\d+\]/);
+ /** extract the [10] from {@link name_parts} */
+ var old_row_index_string = this_name.match(/\[\d+\]/)[0];
+ /** extract 10 - had to split into two steps to accomodate double digits */
+ var old_row_index = parseInt(old_row_index_string.match(/\d+/)[0], 10);
+
+ /** calculate next index i.e. 11 */
+ new_row_index = old_row_index + 1;
+ /** generate the new name i.e. funcs[multi_edit][11][foobarbaz] */
+ var new_name = name_parts[0] + '[' + new_row_index + ']' + name_parts[1];
+
+ var hashed_field = name_parts[1].match(/\[(.+)\]/)[1];
+ $this_element.attr('name', new_name);
+
+ /** If element is select[name*='funcs'], update id */
+ if ($this_element.is('select[name*=\'funcs\']')) {
+ var this_id = $this_element.attr('id');
+ var id_parts = this_id.split(/\_/);
+ var old_id_index = id_parts[1];
+ var prevSelectedValue = $('#field_' + old_id_index + '_1').val();
+ var new_id_index = parseInt(old_id_index) + columnCount;
+ var new_id = 'field_' + new_id_index + '_1';
+ $this_element.attr('id', new_id);
+ $this_element.find('option').filter(function () {
+ return $(this).text() === prevSelectedValue;
+ }).attr('selected','selected');
+
+ // If salt field is there then update its id.
+ var nextSaltInput = $this_element.parent().next('td').next('td').find('input[name*=\'salt\']');
+ if (nextSaltInput.length !== 0) {
+ nextSaltInput.attr('id', 'salt_' + new_id);
+ }
+ }
+
+ // handle input text fields and textareas
+ if ($this_element.is('.textfield') || $this_element.is('.char') || $this_element.is('textarea')) {
+ // do not remove the 'value' attribute for ENUM columns
+ // special handling for radio fields after updating ids to unique - see below
+ if ($this_element.closest('tr').find('span.column_type').html() !== 'enum') {
+ $this_element.val($this_element.closest('tr').find('span.default_value').html());
+ }
+ $this_element
+ .off('change')
+ // Remove onchange attribute that was placed
+ // by tbl_change.php; it refers to the wrong row index
+ .attr('onchange', null)
+ // Keep these values to be used when the element
+ // will change
+ .data('hashed_field', hashed_field)
+ .data('new_row_index', new_row_index)
+ .on('change', function () {
+ var $changed_element = $(this);
+ verificationsAfterFieldChange(
+ $changed_element.data('hashed_field'),
+ $changed_element.data('new_row_index'),
+ $changed_element.closest('tr').find('span.column_type').html()
+ );
+ });
+ }
+
+ if ($this_element.is('.checkbox_null')) {
+ $this_element
+ // 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', hashed_field)
+ .data('new_row_index', new_row_index)
+ .on('click', function () {
+ var $changed_element = $(this);
+ nullify(
+ $changed_element.siblings('.nullify_code').val(),
+ $this_element.closest('tr').find('input:hidden').first().val(),
+ $changed_element.data('hashed_field'),
+ '[multi_edit][' + $changed_element.data('new_row_index') + ']'
+ );
+ });
+ }
+ };
+
+ var tempReplaceAnchor = function () {
+ var $anchor = $(this);
+ var new_value = 'rownumber=' + new_row_index;
+ // needs improvement in case something else inside
+ // the href contains this pattern
+ var new_href = $anchor.attr('href').replace(/rownumber=\d+/, new_value);
+ $anchor.attr('href', new_href);
+ };
+
+ while (curr_rows < target_rows) {
+ /**
+ * @var $last_row Object referring to the last row
+ */
+ var $last_row = $('#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 new_row_index = 0;
+
+ // Clone the insert tables
+ $last_row
+ .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);
+
+ // Insert/Clone the ignore checkboxes
+ if (curr_rows === 1) {
+ $('<input id="insert_ignore_1" type="checkbox" name="insert_ignore_1" checked="checked" />')
+ .insertBefore('table.insertRowTable:last')
+ .after('<label for="insert_ignore_1">' + PMA_messages.strIgnore + '</label>');
+ } else {
+ /**
+ * @var $last_checkbox Object reference to the last checkbox in #insertForm
+ */
+ var $last_checkbox = $('#insertForm').children('input:checkbox:last');
+
+ /** name of {@link $last_checkbox} */
+ var last_checkbox_name = $last_checkbox.attr('name');
+ /** index of {@link $last_checkbox} */
+ var last_checkbox_index = parseInt(last_checkbox_name.match(/\d+/), 10);
+ /** name of new {@link $last_checkbox} */
+ var new_name = last_checkbox_name.replace(/\d+/, last_checkbox_index + 1);
+
+ $('<br/><div class="clearfloat"></div>')
+ .insertBefore('table.insertRowTable:last');
+
+ $last_checkbox
+ .clone()
+ .attr({ 'id': new_name, 'name': new_name })
+ .prop('checked', true)
+ .insertBefore('table.insertRowTable:last');
+
+ $('label[for^=insert_ignore]:last')
+ .clone()
+ .attr('for', new_name)
+ .insertBefore('table.insertRowTable:last');
+
+ $('<br/>')
+ .insertBefore('table.insertRowTable:last');
+ }
+ curr_rows++;
+ }
+ // 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');
+
+ // special handling for radio fields after updating ids to unique
+ 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);
+ }
+ }
+ });
+ $('.control_at_footer')
+ .each(function () {
+ tabindex++;
+ $(this).attr('tabindex', tabindex);
+ });
+ } else if (curr_rows > target_rows) {
+ /**
+ * Displays alert if data loss possible on decrease
+ * of rows.
+ */
+ var checkLock = jQuery.isEmptyObject(AJAX.lockedTargets);
+ if (checkLock || confirm(PMA_messages.strConfirmRowChange) === true) {
+ while (curr_rows > target_rows) {
+ $('input[id^=insert_ignore]:last')
+ .nextUntil('fieldset')
+ .addBack()
+ .remove();
+ curr_rows--;
+ }
+ } else {
+ document.getElementById('insert_rows').value = curr_rows;
+ }
+ }
+ // Add all the required datepickers back
+ addDateTimePicker();
+ });
+}
diff --git a/js/src/tbl_chart.js b/js/src/tbl_chart.js
new file mode 100644
index 0000000000..81849e4dd7
--- /dev/null
+++ b/js/src/tbl_chart.js
@@ -0,0 +1,201 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { TableChartEnum,
+ drawChart,
+ onDataSeriesChange,
+ onXAxisChange,
+ getSelectedSeries
+} from './functions/Table/TableChart';
+import { PMA_ajaxRemoveMessage, PMA_ajaxShowMessage } from './utils/show_ajax_messages';
+import { checkSqlQuery } from './functions/Sql/SqlQuery';
+import { PMA_prepareForAjaxRequest } from './functions/AjaxRequest';
+import { sqlQueryOptions } from './utils/sql';
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardown1 () {
+ $('input[name="chartType"]').off('click');
+ $('input[name="barStacked"]').off('click');
+ $('input[name="chkAlternative"]').off('click');
+ $('input[name="chartTitle"]').off('focus').off('keyup').off('blur');
+ $('select[name="chartXAxis"]').off('change');
+ $('select[name="chartSeries"]').off('change');
+ $('select[name="chartSeriesColumn"]').off('change');
+ $('select[name="chartValueColumn"]').off('change');
+ $('input[name="xaxis_label"]').off('keyup');
+ $('input[name="yaxis_label"]').off('keyup');
+ $('#resizer').off('resizestop');
+ $('#tblchartform').off('submit');
+}
+
+export function onload1 () {
+ // handle manual resize
+ $('#resizer').on('resizestop', function (event, ui) {
+ // make room so that the handle will still appear
+ $('#querychart').height($('#resizer').height() * 0.96);
+ $('#querychart').width($('#resizer').width() * 0.96);
+ if (TableChartEnum.currentChart !== null) {
+ TableChartEnum.currentChart.redraw({
+ resetAxes : true
+ });
+ }
+ });
+
+ // handle chart type changes
+ $('input[name="chartType"]').on('click', function () {
+ var type = TableChartEnum.currentSettings.type = $(this).val();
+ if (type === 'bar' || type === 'column' || type === 'area') {
+ $('span.barStacked').show();
+ } else {
+ $('input[name="barStacked"]').prop('checked', false);
+ $.extend(true, TableChartEnum.currentSettings, { stackSeries : false });
+ $('span.barStacked').hide();
+ }
+ drawChart();
+ });
+
+ // handle chosing alternative data format
+ $('input[name="chkAlternative"]').on('click', function () {
+ var $seriesColumn = $('select[name="chartSeriesColumn"]');
+ var $valueColumn = $('select[name="chartValueColumn"]');
+ var $chartSeries = $('select[name="chartSeries"]');
+ if ($(this).is(':checked')) {
+ $seriesColumn.prop('disabled', false);
+ $valueColumn.prop('disabled', false);
+ $chartSeries.prop('disabled', true);
+ TableChartEnum.currentSettings.seriesColumn = parseInt($seriesColumn.val(), 10);
+ TableChartEnum.currentSettings.valueColumn = parseInt($valueColumn.val(), 10);
+ } else {
+ $seriesColumn.prop('disabled', true);
+ $valueColumn.prop('disabled', true);
+ $chartSeries.prop('disabled', false);
+ TableChartEnum.currentSettings.seriesColumn = null;
+ TableChartEnum.currentSettings.valueColumn = null;
+ }
+ drawChart();
+ });
+
+ // handle stacking for bar, column and area charts
+ $('input[name="barStacked"]').on('click', function () {
+ if ($(this).is(':checked')) {
+ $.extend(true, TableChartEnum.currentSettings, { stackSeries : true });
+ } else {
+ $.extend(true, TableChartEnum.currentSettings, { stackSeries : false });
+ }
+ drawChart();
+ });
+
+ // handle changes in chart title
+ $('input[name="chartTitle"]')
+ .focus(function () {
+ TableChartEnum.temp_chart_title = $(this).val();
+ })
+ .on('keyup', function () {
+ TableChartEnum.currentSettings.title = $('input[name="chartTitle"]').val();
+ drawChart();
+ })
+ .blur(function () {
+ if ($(this).val() !== TableChartEnum.temp_chart_title) {
+ drawChart();
+ }
+ });
+
+ // handle changing the x-axis
+ $('select[name="chartXAxis"]').on('change', function () {
+ onXAxisChange();
+ drawChart();
+ });
+
+ // handle changing the selected data series
+ $('select[name="chartSeries"]').on('change', function () {
+ onDataSeriesChange();
+ drawChart();
+ });
+
+ // handle changing the series column
+ $('select[name="chartSeriesColumn"]').on('change', function () {
+ TableChartEnum.currentSettings.seriesColumn = parseInt($(this).val(), 10);
+ drawChart();
+ });
+
+ // handle changing the value column
+ $('select[name="chartValueColumn"]').on('change', function () {
+ TableChartEnum.currentSettings.valueColumn = parseInt($(this).val(), 10);
+ drawChart();
+ });
+
+ // handle manual changes to the chart x-axis labels
+ $('input[name="xaxis_label"]').on('keyup', function () {
+ TableChartEnum.currentSettings.xaxisLabel = $(this).val();
+ drawChart();
+ });
+
+ // handle manual changes to the chart y-axis labels
+ $('input[name="yaxis_label"]').on('keyup', function () {
+ TableChartEnum.currentSettings.yaxisLabel = $(this).val();
+ drawChart();
+ });
+
+ // handler for ajax form submission
+ $('#tblchartform').submit(function (event) {
+ var $form = $(this);
+ if (sqlQueryOptions.codemirror_editor) {
+ $form[0].elements.sql_query.value = sqlQueryOptions.codemirror_editor.getValue();
+ }
+ if (!checkSqlQuery($form[0])) {
+ return false;
+ }
+
+ var $msgbox = PMA_ajaxShowMessage();
+ PMA_prepareForAjaxRequest($form);
+ $.post($form.attr('action'), $form.serialize(), function (data) {
+ if (typeof data !== 'undefined' &&
+ data.success === true &&
+ typeof data.chartData !== 'undefined') {
+ TableChartEnum.chart_data = JSON.parse(data.chartData);
+ drawChart();
+ PMA_ajaxRemoveMessage($msgbox);
+ } else {
+ PMA_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');
+
+ TableChartEnum.currentSettings = {
+ type : 'line',
+ width : $('#resizer').width() - 20,
+ height : $('#resizer').height() - 20,
+ xaxisLabel : $('input[name="xaxis_label"]').val(),
+ yaxisLabel : $('input[name="yaxis_label"]').val(),
+ title : $('input[name="chartTitle"]').val(),
+ stackSeries : false,
+ mainAxis : parseInt($('select[name="chartXAxis"]').val(), 10),
+ selectedSeries : getSelectedSeries(),
+ seriesColumn : null
+ };
+
+ var vals = $('input[name="dateTimeCols"]').val().split(' ');
+ $.each(vals, function (i, v) {
+ TableChartEnum.dateTimeCols.push(parseInt(v, 10));
+ });
+
+ vals = $('input[name="numericCols"]').val().split(' ');
+ $.each(vals, function (i, v) {
+ TableChartEnum.numericCols.push(parseInt(v, 10));
+ });
+
+ onXAxisChange();
+ onDataSeriesChange();
+
+ $('#tblchartform').submit();
+}
diff --git a/js/src/tbl_find_replace.js b/js/src/tbl_find_replace.js
new file mode 100644
index 0000000000..3da67f242d
--- /dev/null
+++ b/js/src/tbl_find_replace.js
@@ -0,0 +1,50 @@
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import { PMA_prepareForAjaxRequest } from './functions/AjaxRequest';
+import { PMA_ajaxRemoveMessage, PMA_ajaxShowMessage } from './utils/show_ajax_messages';
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownTblFindReplace () {
+ $('#find_replace_form').off('submit');
+ $('#toggle_find').off('click');
+}
+
+/**
+ * Bind events
+ */
+export function onloadTblFindReplace () {
+ $('<div id="toggle_find_div"><a id="toggle_find"></a></div>')
+ .insertAfter('#find_replace_form')
+ .hide();
+
+ $('#toggle_find')
+ .html(PMA_messages.strHideFindNReplaceCriteria)
+ .on('click', function () {
+ var $link = $(this);
+ $('#find_replace_form').slideToggle();
+ if ($link.text() === PMA_messages.strHideFindNReplaceCriteria) {
+ $link.text(PMA_messages.strShowFindNReplaceCriteria);
+ } else {
+ $link.text(PMA_messages.strHideFindNReplaceCriteria);
+ }
+ return false;
+ });
+
+ $('#find_replace_form').submit(function (e) {
+ e.preventDefault();
+ var findReplaceForm = $('#find_replace_form');
+ PMA_prepareForAjaxRequest(findReplaceForm);
+ var $msgbox = PMA_ajaxShowMessage();
+ $.post(findReplaceForm.attr('action'), findReplaceForm.serialize(), function (data) {
+ PMA_ajaxRemoveMessage($msgbox);
+ if (data.success === true) {
+ $('#toggle_find_div').show();
+ $('#toggle_find').trigger('click');
+ $('#sqlqueryresultsouter').html(data.preview);
+ } else {
+ $('#sqlqueryresultsouter').html(data.error);
+ }
+ });
+ });
+}
diff --git a/js/src/tbl_operations.js b/js/src/tbl_operations.js
new file mode 100644
index 0000000000..2845bab167
--- /dev/null
+++ b/js/src/tbl_operations.js
@@ -0,0 +1,339 @@
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import PMA_commonParams from './variables/common_params';
+import { PMA_commonActions } from './classes/CommonActions';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
+import { PMA_prepareForAjaxRequest } from './functions/AjaxRequest';
+import { PMA_highlightSQL } from './utils/sql';
+import { PMA_init_slider } from './utils/Slider';
+import { escapeHtml } from './utils/Sanitise';
+import { getJSConfirmCommonParam } from './functions/Common';
+import { getForeignKeyCheckboxLoader, loadForeignKeyCheckbox } from './functions/Sql/ForeignKey';
+import { PMA_sprintf } from './utils/sprintf';
+import { PMA_reloadNavigation } from './functions/navigation';
+import { AJAX } from './ajax';
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownTblOperations () {
+ $(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');
+}
+
+/**
+ * jQuery coding for 'Table operations'. Used on tbl_operations.php
+ * Attach Ajax Event handlers for Table operations
+ */
+export function onloadTblOperations () {
+ /**
+ *Ajax action for submitting the "Copy table"
+ **/
+ $(document).on('submit', '#copyTable.ajax', function (event) {
+ event.preventDefault();
+ var $form = $(this);
+ PMA_prepareForAjaxRequest($form);
+ var argsep = PMA_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')) {
+ PMA_commonParams.set(
+ 'db',
+ $form.find('select[name=\'target_db\']').val()
+ );
+ PMA_commonParams.set(
+ 'table',
+ $form.find('input[name=\'new_name\']').val()
+ );
+ PMA_commonActions.refreshMain(false, function () {
+ PMA_ajaxShowMessage(data.message);
+ });
+ } else {
+ PMA_ajaxShowMessage(data.message);
+ }
+ // Refresh navigation when the table is copied
+ PMA_reloadNavigation();
+ } else {
+ PMA_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);
+ PMA_prepareForAjaxRequest($form);
+ var argsep = PMA_commonParams.get('arg_separator');
+ $.post($form.attr('action'), $form.serialize() + argsep + 'submit_move=1', function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_commonParams.set('db', data._params.db);
+ PMA_commonParams.set('table', data._params.tbl);
+ PMA_commonActions.refreshMain(false, function () {
+ PMA_ajaxShowMessage(data.message);
+ });
+ // Refresh navigation when the table is copied
+ PMA_reloadNavigation();
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ });
+
+ /**
+ * 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 = PMA_messages.strChangeAllColumnCollationsWarning;
+
+ if ($tblNameField.val() !== $tblNameField[0].defaultValue) {
+ // reload page and navigation if the table has been renamed
+ PMA_prepareForAjaxRequest($form);
+
+ if ($tblCollationField.val() !== collationOrigValue && $changeAllColumnCollationsCheckBox.is(':checked')) {
+ $form.PMA_confirm(question, $form.attr('action'), function () {
+ submitOptionsForm();
+ });
+ } else {
+ submitOptionsForm();
+ }
+ } else {
+ if ($tblCollationField.val() !== collationOrigValue && $changeAllColumnCollationsCheckBox.is(':checked')) {
+ $form.PMA_confirm(question, $form.attr('action'), function () {
+ $form.removeClass('ajax').submit().addClass('ajax');
+ });
+ } else {
+ $form.removeClass('ajax').submit().addClass('ajax');
+ }
+ }
+
+ function submitOptionsForm () {
+ $.post($form.attr('action'), $form.serialize(), function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_commonParams.set('table', data._params.table);
+ PMA_commonActions.refreshMain(false, function () {
+ $('#page_content').html(data.message);
+ PMA_highlightSQL($('#page_content'));
+ });
+ // Refresh navigation when the table is renamed
+ PMA_reloadNavigation();
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }
+ });
+
+ /**
+ *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: PMA_commonParams.get('server')
+ });
+ var postData = $link.getPostData();
+ if (postData) {
+ params += PMA_commonParams.get('arg_separator') + postData;
+ }
+
+ $.post($link.attr('href'), params, function (data) {
+ function scrollToTop () {
+ $('html, body').animate({ scrollTop: 0 });
+ }
+ var $temp_div;
+ if (typeof data !== 'undefined' && data.success === true && data.sql_query !== undefined) {
+ PMA_ajaxShowMessage(data.message);
+ $('<div class=\'sqlqueryresults ajax\'></div>').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.sql_query);
+ PMA_highlightSQL($('#page_content'));
+ scrollToTop();
+ } else if (typeof data !== 'undefined' && data.success === true) {
+ $temp_div = $('<div id=\'temp_div\'></div>');
+ $temp_div.html(data.message);
+ var $success = $temp_div.find('.result_query .success');
+ PMA_ajaxShowMessage($success);
+ $('<div class=\'sqlqueryresults ajax\'></div>').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.message);
+ PMA_highlightSQL($('#page_content'));
+ PMA_init_slider();
+ $('.sqlqueryresults').children('fieldset,br').remove();
+ scrollToTop();
+ } else {
+ $temp_div = $('<div id=\'temp_div\'></div>');
+ $temp_div.html(data.error);
+
+ var $error;
+ if ($temp_div.find('.error code').length !== 0) {
+ $error = $temp_div.find('.error code').addClass('error');
+ } else {
+ $error = $temp_div;
+ }
+
+ PMA_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 = PMA_commonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
+ PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ }
+
+ if ($('#partition_operation_DROP').is(':checked')) {
+ let question = PMA_messages.strDropPartitionWarning;
+ $form.PMA_confirm(question, $form.attr('action'), function () {
+ submitPartitionMaintenance();
+ });
+ } else if ($('#partition_operation_TRUNCATE').is(':checked')) {
+ let question = PMA_messages.strTruncatePartitionWarning;
+ $form.PMA_confirm(question, $form.attr('action'), function () {
+ submitPartitionMaintenance();
+ });
+ } else {
+ submitPartitionMaintenance();
+ }
+ });
+
+ $(document).on('click', '#drop_tbl_anchor.ajax', function (event) {
+ event.preventDefault();
+ var $link = $(this);
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = PMA_messages.strDropTableStrongWarning + ' ';
+ question += PMA_sprintf(
+ PMA_messages.strDoYouReally,
+ 'DROP TABLE `' + escapeHtml(PMA_commonParams.get('db')) + '`.`' + escapeHtml(PMA_commonParams.get('table') + '`')
+ ) + getForeignKeyCheckboxLoader();
+
+ $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
+ var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+
+ var params = getJSConfirmCommonParam(this, $link.getPostData());
+
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_ajaxRemoveMessage($msgbox);
+ // Table deleted successfully, refresh both the frames
+ PMA_reloadNavigation();
+ PMA_commonParams.set('table', '');
+ PMA_commonActions.refreshMain(
+ PMA_commonParams.get('opendb_url'),
+ function () {
+ PMA_ajaxShowMessage(data.message);
+ }
+ );
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }, loadForeignKeyCheckbox); // end $.PMA_confirm()
+ }); // end of Drop Table Ajax action
+
+ $(document).on('click', '#drop_view_anchor.ajax', function (event) {
+ event.preventDefault();
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = PMA_messages.strDropTableStrongWarning + ' ';
+ question += PMA_sprintf(
+ PMA_messages.strDoYouReally,
+ 'DROP VIEW `' + escapeHtml(PMA_commonParams.get('table') + '`')
+ );
+
+ $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
+ var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+ var params = {
+ 'is_js_confirmed': '1',
+ 'ajax_request': true
+ };
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_ajaxRemoveMessage($msgbox);
+ // Table deleted successfully, refresh both the frames
+ PMA_reloadNavigation();
+ PMA_commonParams.set('table', '');
+ PMA_commonActions.refreshMain(
+ PMA_commonParams.get('opendb_url'),
+ function () {
+ PMA_ajaxShowMessage(data.message);
+ }
+ );
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }); // end $.PMA_confirm()
+ }); // end of Drop View Ajax action
+
+ $(document).on('click', '#truncate_tbl_anchor.ajax', function (event) {
+ event.preventDefault();
+ var $link = $(this);
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = PMA_messages.strTruncateTableStrongWarning + ' ';
+ question += PMA_sprintf(
+ PMA_messages.strDoYouReally,
+ 'TRUNCATE `' + escapeHtml(PMA_commonParams.get('db')) + '`.`' + escapeHtml(PMA_commonParams.get('table') + '`')
+ ) + getForeignKeyCheckboxLoader();
+ $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
+ PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+
+ var params = getJSConfirmCommonParam(this, $link.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) {
+ PMA_ajaxShowMessage(data.message);
+ $('<div class=\'sqlqueryresults ajax\'></div>').prependTo('#page_content');
+ $('.sqlqueryresults').html(data.sql_query);
+ PMA_highlightSQL($('#page_content'));
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }, loadForeignKeyCheckbox); // end $.PMA_confirm()
+ }); // end of Truncate Table Ajax action
+} // end $(document).ready for 'Table operations'
diff --git a/js/src/tbl_relation.js b/js/src/tbl_relation.js
new file mode 100644
index 0000000000..06afd6c2d6
--- /dev/null
+++ b/js/src/tbl_relation.js
@@ -0,0 +1,135 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
+import { escapeHtml } from './utils/Sanitise';
+import { PMA_commonActions } from './classes/CommonActions';
+import { PMA_sprintf } from './utils/sprintf';
+import { getJSConfirmCommonParam } from './functions/Common';
+import { getDropdownValues } from './functions/Table/Relation';
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownTblRelation () {
+ $('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');
+}
+
+export function onloadTblRelation () {
+ /**
+ * 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 () {
+ 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 $source_elem = $('select[name^="destination_foreign_column[' +
+ $(this).attr('data-index') + ']"]:last').parent();
+ $source_elem
+ .clone(true, true)
+ .insertAfter($source_elem)
+ .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 $prev_row = $(this).closest('tr').prev('tr');
+ var $newRow = $prev_row.clone(true, true);
+
+ // Update serial number.
+ var curr_index = $newRow
+ .find('a.add_foreign_key_field')
+ .attr('data-index');
+ var new_index = parseInt(curr_index) + 1;
+ $newRow.find('a.add_foreign_key_field').attr('data-index', new_index);
+
+ // Update form parameter names.
+ $newRow.find('select[name^="foreign_key_fields_name"]:not(:first), ' +
+ 'select[name^="destination_foreign_column"]:not(:first)'
+ ).each(function () {
+ $(this).parent().remove();
+ });
+ $newRow.find('input, select').each(function () {
+ $(this).attr('name',
+ $(this).attr('name').replace(/\d/, new_index)
+ );
+ });
+ $newRow.find('input[type="text"]').each(function () {
+ $(this).val('');
+ });
+ // Finally add the row.
+ $newRow.insertAfter($prev_row);
+ });
+
+ /**
+ * 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 $curr_row = $anchor.parents('tr');
+
+ var drop_query = escapeHtml(
+ $curr_row.children('td')
+ .children('.drop_foreign_key_msg')
+ .val()
+ );
+
+ var question = PMA_sprintf(PMA_messages.strDoYouReally, drop_query);
+
+ $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) {
+ var $msg = PMA_ajaxShowMessage(PMA_messages.strDroppingForeignKey, false);
+ var params = getJSConfirmCommonParam(this, $anchor.getPostData());
+ $.post(url, params, function (data) {
+ if (data.success === true) {
+ PMA_ajaxRemoveMessage($msg);
+ PMA_commonActions.refreshMain(false, function () {
+ // Do nothing
+ });
+ } else {
+ PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ }); // end $.PMA_confirm()
+ }); // end Drop Foreign key
+
+ var windowwidth = $(window).width();
+ $('.jsresponsive').css('max-width', (windowwidth - 35) + 'px');
+}
diff --git a/js/src/tbl_select.js b/js/src/tbl_select.js
new file mode 100644
index 0000000000..e6082c84ad
--- /dev/null
+++ b/js/src/tbl_select.js
@@ -0,0 +1,394 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { $ } from './utils/JqueryExtended';
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import {
+ changeValueFieldType,
+ PMA_checkIfDataTypeNumericOrDate
+} from './functions/Table/TableSelect';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
+import { PMA_prepareForAjaxRequest } from './functions/AjaxRequest';
+import { PMA_init_slider } from './utils/Slider';
+import { PMA_highlightSQL } from './utils/sql';
+import { PMA_addDatepicker } from './utils/DateTime';
+import { PMA_commonParams } from './variables/common_params';
+
+/**
+ * @fileoverview JavaScript functions used on tbl_select.php
+ *
+ * @requires jQuery
+ * @requires js/functions.js
+ */
+
+/**
+ * Ajax event handlers for this page
+ *
+ * Actions ajaxified here:
+ * Table search
+ */
+
+/**
+ * Unbind all event handlers before tearing down a page
+ */
+export function teardownTblSelect () {
+ $('#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'
+}
+
+export function onloadTblSelect () {
+ /**
+ * Prepare a div containing a link, otherwise it's incorrectly displayed
+ * after a couple of clicks
+ */
+ $('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
+ .insertAfter('#tbl_search_form')
+ // don't show it until we have results on-screen
+ .hide();
+
+ $('#togglesearchformlink')
+ .html(PMA_messages.strShowSearchCriteria)
+ .on('click', function () {
+ var $link = $(this);
+ $('#tbl_search_form').slideToggle();
+ if ($link.text() === PMA_messages.strHideSearchCriteria) {
+ $link.text(PMA_messages.strShowSearchCriteria);
+ } else {
+ $link.text(PMA_messages.strHideSearchCriteria);
+ }
+ // avoid default click action
+ return false;
+ });
+
+ var tableRows = $('#fieldset_table_qbe select');
+ $.each(tableRows, function (index, item) {
+ $(item).on('change', function () {
+ changeValueFieldType(this, index);
+ });
+ });
+
+ /**
+ * 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 $search_form = $(this);
+ event.preventDefault();
+
+ // empty previous search results while we are waiting for new results
+ $('#sqlqueryresultsouter').empty();
+ var $msgbox = PMA_ajaxShowMessage(PMA_messages.strSearching, false);
+
+ PMA_prepareForAjaxRequest($search_form);
+
+ var values = {};
+ $search_form.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 + ']'] &&
+ $.isArray(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($search_form.attr('action'), values, function (data) {
+ PMA_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').trigger('stickycolumns');
+ }
+ $('#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(PMA_messages.strShowSearchCriteria);
+ $('#togglesearchformdiv')
+ // now it's time to show the div containing the link
+ .show();
+ // needed for the display options slider in the results
+ PMA_init_slider();
+ $('html, body').animate({ scrollTop: 0 }, 'fast');
+ } else {
+ $('#sqlqueryresultsouter').html(data.error);
+ }
+ PMA_highlightSQL($('#sqlqueryresultsouter'));
+ }); // end $.post()
+ });
+
+ // Following section is related to the 'function based search' for geometry data types.
+ // Initialy hide all the open_gis_editor spans
+ $('span.open_search_gis_editor').hide();
+
+ $('select.geom_func').bind('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:nth-child(5)').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 geom_func = $span.parents('tr').find('.geom_func').val();
+ var type;
+ if (geom_func === 'Envelope') {
+ type = 'polygon';
+ } else if (geom_func === 'ExteriorRing') {
+ type = 'linestring';
+ } else {
+ type = 'point';
+ }
+ // Names of input field and null checkbox
+ var input_name = $span.parent('td').children('input[type=\'text\']').attr('name');
+ // Token
+
+ openGISEditor();
+ if (!gisEditorLoaded) {
+ loadJSAndGISEditor(value, field, type, input_name);
+ } else {
+ loadGISEditor(value, field, type, input_name);
+ }
+ });
+
+ /**
+ * Ajax event handler for Range-Search.
+ */
+ $('body').on('change', 'select[name*="criteriaColumnOperators"]', function () { // Fix for bug #13778, changed 'click' to 'change'
+ var $source_select = $(this);
+ // Get the column name.
+ var column_name = $(this)
+ .closest('tr')
+ .find('th:first')
+ .text();
+
+ // Get the data-type of column excluding size.
+ var data_type = $(this)
+ .closest('tr')
+ .find('td[data-type]')
+ .attr('data-type');
+ data_type = PMA_checkIfDataTypeNumericOrDate(data_type);
+
+ // Get the operator.
+ var operator = $(this).val();
+
+ if ((operator === 'BETWEEN' || operator === 'NOT BETWEEN')
+ && data_type
+ ) {
+ var $msgbox = PMA_ajaxShowMessage();
+ $.ajax({
+ url: 'tbl_select.php',
+ type: 'POST',
+ data: {
+ server: PMA_commonParams.get('server'),
+ ajax_request: 1,
+ db: $('input[name="db"]').val(),
+ table: $('input[name="table"]').val(),
+ column: column_name,
+ range_search: 1
+ },
+ success: function (response) {
+ PMA_ajaxRemoveMessage($msgbox);
+ if (response.success) {
+ // Get the column min value.
+ var min = response.column_data.min
+ ? '(' + PMA_messages.strColumnMin +
+ ' ' + response.column_data.min + ')'
+ : '';
+ // Get the column max value.
+ var max = response.column_data.max
+ ? '(' + PMA_messages.strColumnMax +
+ ' ' + response.column_data.max + ')'
+ : '';
+ var button_options = {};
+ button_options[PMA_messages.strGo] = function () {
+ var min_value = $('#min_value').val();
+ var max_value = $('#max_value').val();
+ var final_value = '';
+ if (min_value.length && max_value.length) {
+ final_value = min_value + ', ' +
+ max_value;
+ }
+ var $target_field = $source_select.closest('tr')
+ .find('[name*="criteriaValues"]');
+
+ // If target field is a select list.
+ if ($target_field.is('select')) {
+ $target_field.val(final_value);
+ var $options = $target_field.find('option');
+ var $closest_min = null;
+ var $closest_max = null;
+ // Find closest min and max value.
+ $options.each(function () {
+ if (
+ $closest_min === null
+ || Math.abs($(this).val() - min_value) < Math.abs($closest_min.val() - min_value)
+ ) {
+ $closest_min = $(this);
+ }
+
+ if (
+ $closest_max === null
+ || Math.abs($(this).val() - max_value) < Math.abs($closest_max.val() - max_value)
+ ) {
+ $closest_max = $(this);
+ }
+ });
+
+ $closest_min.attr('selected', 'selected');
+ $closest_max.attr('selected', 'selected');
+ } else {
+ $target_field.val(final_value);
+ }
+ $(this).dialog('close');
+ };
+ button_options[PMA_messages.strCancel] = function () {
+ $(this).dialog('close');
+ };
+
+ // Display dialog box.
+ $('<div/>').append(
+ '<fieldset>' +
+ '<legend>' + operator + '</legend>' +
+ '<label for="min_value">' + PMA_messages.strMinValue +
+ '</label>' +
+ '<input type="text" id="min_value" />' + '<br>' +
+ '<span class="small_font">' + min + '</span>' + '<br>' +
+ '<label for="max_value">' + PMA_messages.strMaxValue +
+ '</label>' +
+ '<input type="text" id="max_value" />' + '<br>' +
+ '<span class="small_font">' + max + '</span>' +
+ '</fieldset>'
+ ).dialog({
+ minWidth: 500,
+ maxHeight: 400,
+ modal: true,
+ buttons: button_options,
+ title: PMA_messages.strRangeSearch,
+ open: function () {
+ // Add datepicker wherever required.
+ PMA_addDatepicker($('#min_value'), data_type);
+ PMA_addDatepicker($('#max_value'), data_type);
+ },
+ close: function () {
+ $(this).remove();
+ }
+ });
+ } else {
+ PMA_ajaxShowMessage(response.error);
+ }
+ },
+ error: function (response) {
+ PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest);
+ }
+ });
+ }
+ });
+ var windowwidth = $(window).width();
+ $('.jsresponsive').css('max-width', (windowwidth - 69) + 'px');
+}
diff --git a/js/src/tbl_structure.js b/js/src/tbl_structure.js
new file mode 100644
index 0000000000..f65d3a0be5
--- /dev/null
+++ b/js/src/tbl_structure.js
@@ -0,0 +1,520 @@
+/* vim: set expandtab sw=4 ts=4 sts=4: */
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import Indexes from './utils/IndexEnum';
+import PMA_commonParams from './variables/common_params';
+import { PMA_ajaxShowMessage, PMA_ajaxRemoveMessage } from './utils/show_ajax_messages';
+import { PMA_highlightSQL } from './utils/sql';
+import { PMA_prepareForAjaxRequest } from './functions/AjaxRequest';
+import { PMA_checkReservedWordColumns } from './functions/Table/CreateTable';
+import { PMA_init_slider } from './utils/Slider';
+import { PMA_sprintf } from './utils/sprintf';
+import { getJSConfirmCommonParam } from './functions/Common';
+import { escapeHtml } from './utils/Sanitise';
+import { AJAX } from './ajax';
+import { PMA_previewSQL } from './functions/Sql/PreviewSql';
+import { printPreview } from './functions/Print';
+/**
+ * @fileoverview functions used on the table structure page
+ * @name Table Structure
+ *
+ * @requires jQuery
+ * @requires jQueryUI
+ * @required js/functions.js
+ */
+
+/**
+ * AJAX scripts for tbl_structure.php
+ *
+ * Actions ajaxified here:
+ * Drop Column
+ * Add Primary Key
+ * Drop Primary Key/Index
+ *
+ */
+
+/**
+ * Reload fields table
+ */
+function reloadFieldForm () {
+ $.post($('#fieldsForm').attr('action'), $('#fieldsForm').serialize() + PMA_commonParams.get('arg_separator') + 'ajax_request=true', function (form_data) {
+ var $temp_div = $('<div id=\'temp_div\'><div>').append(form_data.message);
+ $('#fieldsForm').replaceWith($temp_div.find('#fieldsForm'));
+ $('#addColumns').replaceWith($temp_div.find('#addColumns'));
+ $('#move_columns_dialog').find('ul').replaceWith($temp_div.find('#move_columns_dialog ul'));
+ $('#moveColumns').removeClass('move-active');
+ });
+ $('#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
+ */
+export function teardownTblStructure () {
+ $(document).off('click', 'a.drop_column_anchor.ajax');
+ $(document).off('click', 'a.add_key.ajax');
+ $(document).off('click', '#move_columns_anchor');
+ $(document).off('click', '#printView');
+ $(document).off('submit', '.append_fields_form.ajax');
+ $('body').off('click', '#fieldsForm.ajax button[name="submit_mult"], #fieldsForm.ajax input[name="submit_mult"]');
+ $(document).off('click', 'a[name^=partition_action].ajax');
+ $(document).off('click', '#remove_partitioning.ajax');
+}
+
+export function onloadTblStructure () {
+ // Re-initialize variables.
+ Indexes.primary_indexes = [];
+ Indexes.indexes = [];
+ Indexes.fulltext_indexes = [];
+ Indexes.spatial_indexes = [];
+
+ /**
+ *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 the_form object referring to the export form
+ */
+ var $form = $(this);
+ var field_cnt = $form.find('input[name=orig_num_fields]').val();
+
+
+ function submitForm () {
+ var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
+ $.post($form.attr('action'), $form.serialize() + PMA_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();
+ PMA_highlightSQL($('#page_content'));
+ $('.result_query .notice').remove();
+ reloadFieldForm();
+ $form.remove();
+ PMA_ajaxRemoveMessage($msg);
+ PMA_init_slider();
+ PMA_reloadNavigation();
+ } else {
+ PMA_ajaxShowMessage(data.error, false);
+ }
+ }); // end $.post()
+ }
+
+ function checkIfConfirmRequired ($form, $field_cnt) {
+ var i = 0;
+ var id;
+ var elm;
+ var val;
+ var name_orig;
+ var elm_orig;
+ var val_orig;
+ var checkRequired = false;
+ for (i = 0; i < field_cnt; i++) {
+ id = '#field_' + i + '_5';
+ elm = $(id);
+ val = elm.val();
+
+ name_orig = 'input[name=field_collation_orig\\[' + i + '\\]]';
+ elm_orig = $form.find(name_orig);
+ val_orig = elm_orig.val();
+
+ if (val && val_orig && val !== val_orig) {
+ checkRequired = true;
+ break;
+ }
+ }
+ return checkRequired;
+ }
+
+ /*
+ * First validate the form; if there is a problem, avoid submitting it
+ *
+ * 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 (checkTableEditForm($form[0], field_cnt)) {
+ // OK, form passed validation step
+
+ PMA_prepareForAjaxRequest($form);
+ if (PMA_checkReservedWordColumns($form)) {
+ // User wants to submit the form
+
+ // If Collation is changed, Warn and Confirm
+ if (checkIfConfirmRequired($form, field_cnt)) {
+ var question = PMA_sprintf(
+ PMA_messages.strChangeColumnCollation, 'https://wiki.phpmyadmin.net/pma/Garbled_data'
+ );
+ $form.PMA_confirm(question, $form.attr('action'), function (url) {
+ 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 curr_table_name String containing the name of the current table
+ */
+ var curr_table_name = $(this).closest('form').find('input[name=table]').val();
+ /**
+ * @var curr_row Object reference to the currently selected row (i.e. field in the table)
+ */
+ var $curr_row = $(this).parents('tr');
+ /**
+ * @var curr_column_name String containing name of the field referred to by {@link curr_row}
+ */
+ var curr_column_name = $curr_row.children('th').children('label').text().trim();
+ curr_column_name = escapeHtml(curr_column_name);
+ /**
+ * @var $after_field_item Corresponding entry in the 'After' field.
+ */
+ var $after_field_item = $('select[name=\'after_field\'] option[value=\'' + curr_column_name + '\']');
+ /**
+ * @var question String containing the question to be asked for confirmation
+ */
+ var question = PMA_sprintf(PMA_messages.strDoYouReally, 'ALTER TABLE `' + escapeHtml(curr_table_name) + '` DROP `' + escapeHtml(curr_column_name) + '`;');
+ var $this_anchor = $(this);
+ $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) {
+ var $msg = PMA_ajaxShowMessage(PMA_messages.strDroppingColumn, false);
+ var params = getJSConfirmCommonParam(this, $this_anchor.getPostData());
+ params += PMA_commonParams.get('arg_separator') + 'ajax_page_request=1';
+ $.post(url, params, function (data) {
+ if (typeof data !== 'undefined' && data.success === true) {
+ PMA_ajaxRemoveMessage($msg);
+ if ($('.result_query').length) {
+ $('.result_query').remove();
+ }
+ if (data.sql_query) {
+ $('<div class="result_query"></div>')
+ .html(data.sql_query)
+ .prependTo('#structure_content');
+ PMA_highlightSQL($('#page_content'));
+ }
+ // Adjust the row numbers
+ for (var $row = $curr_row.next(); $row.length > 0; $row = $row.next()) {
+ var new_val = parseInt($row.find('td:nth-child(2)').text(), 10) - 1;
+ $row.find('td:nth-child(2)').text(new_val);
+ }
+ $after_field_item.remove();
+ $curr_row.hide('medium').remove();
+
+ // Remove the dropped column from select menu for 'after field'
+ $('select[name=after_field]').find(
+ '[value="' + curr_column_name + '"]'
+ ).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.php)
+ $('.index_info').replaceWith(data.indexes_list);
+ PMA_reloadNavigation();
+ } else {
+ PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + ' : ' + data.error, false);
+ }
+ }); // end $.post()
+ }); // end $.PMA_confirm()
+ }); // end of Drop Column Anchor action
+
+ /**
+ * Attach Event Handler for 'Print' link
+ */
+ $(document).on('click', '#printView', function (event) {
+ event.preventDefault();
+
+ // Take to preview mode
+ printPreview();
+ }); // end of Print View action
+
+ /**
+ * Ajax Event handler for adding keys
+ */
+ $(document).on('click', 'a.add_key.ajax', function (event) {
+ event.preventDefault();
+
+ var $this = $(this);
+ var curr_table_name = $this.closest('form').find('input[name=table]').val();
+ var curr_column_name = $this.parents('tr').children('th').children('label').text().trim();
+
+ var add_clause = '';
+ if ($this.is('.add_primary_key_anchor')) {
+ add_clause = 'ADD PRIMARY KEY';
+ } else if ($this.is('.add_index_anchor')) {
+ add_clause = 'ADD INDEX';
+ } else if ($this.is('.add_unique_anchor')) {
+ add_clause = 'ADD UNIQUE';
+ } else if ($this.is('.add_spatial_anchor')) {
+ add_clause = 'ADD SPATIAL';
+ } else if ($this.is('.add_fulltext_anchor')) {
+ add_clause = 'ADD FULLTEXT';
+ }
+ var question = PMA_sprintf(PMA_messages.strDoYouReally, 'ALTER TABLE `' +
+ escapeHtml(curr_table_name) + '` ' + add_clause + '(`' + escapeHtml(curr_column_name) + '`);');
+
+ var $this_anchor = $(this);
+
+ $this_anchor.PMA_confirm(question, $this_anchor.attr('href'), function (url) {
+ PMA_ajaxShowMessage();
+ AJAX.source = $this;
+
+ var params = getJSConfirmCommonParam(this, $this_anchor.getPostData());
+ params += PMA_commonParams.get('arg_separator') + 'ajax_page_request=1';
+ $.post(url, params, AJAX.responseHandler);
+ }); // end $.PMA_confirm()
+ }); // end Add key
+
+ /**
+ * Inline move columns
+ **/
+ $(document).on('click', '#move_columns_anchor', function (e) {
+ e.preventDefault();
+
+ if ($(this).hasClass('move-active')) {
+ return;
+ }
+
+ /**
+ * @var button_options Object that stores the options passed to jQueryUI
+ * dialog
+ */
+ var button_options = {};
+
+ button_options[PMA_messages.strGo] = function (event) {
+ event.preventDefault();
+ var $msgbox = PMA_ajaxShowMessage();
+ var $this = $(this);
+ var $form = $this.find('form');
+ var serialized = $form.serialize();
+ // check if any columns were moved at all
+ if (serialized === $form.data('serialized-unmoved')) {
+ PMA_ajaxRemoveMessage($msgbox);
+ $this.dialog('close');
+ return;
+ }
+ $.post($form.prop('action'), serialized + PMA_commonParams.get('arg_separator') + 'ajax_request=true', function (data) {
+ if (data.success === false) {
+ PMA_ajaxRemoveMessage($msgbox);
+ $this
+ .clone()
+ .html(data.error)
+ .dialog({
+ title: $(this).prop('title'),
+ height: 230,
+ width: 900,
+ modal: true,
+ buttons: button_options_error
+ }); // end dialog options
+ } else {
+ // sort the fields table
+ var $fields_table = $('table#tablestructure tbody');
+ // remove all existing rows and remember them
+ var $rows = $fields_table.find('tr').remove();
+ // loop through the correct order
+ for (var i in data.columns) {
+ var the_column = data.columns[i];
+ var $the_row = $rows
+ .find('input:checkbox[value=\'' + the_column + '\']')
+ .closest('tr');
+ // append the row for this column to the table
+ $fields_table.append($the_row);
+ }
+ var $firstrow = $fields_table.find('tr').eq(0);
+ // Adjust the row numbers and colors
+ for (var $row = $firstrow; $row.length > 0; $row = $row.next()) {
+ $row
+ .find('td:nth-child(2)')
+ .text($row.index() + 1)
+ .end()
+ .removeClass('odd even')
+ .addClass($row.index() % 2 === 0 ? 'odd' : 'even');
+ }
+ PMA_ajaxShowMessage(data.message);
+ $this.dialog('close');
+ }
+ });
+ };
+ button_options[PMA_messages.strPreviewSQL] = function () {
+ // Function for Previewing SQL
+ var $form = $('#move_column_form');
+ PMA_previewSQL($form);
+ };
+ button_options[PMA_messages.strCancel] = function () {
+ $(this).dialog('close');
+ };
+
+ var button_options_error = {};
+ button_options_error[PMA_messages.strOK] = function () {
+ $(this).dialog('close').remove();
+ };
+
+ var columns = [];
+
+ $('#tablestructure').find('tbody tr').each(function () {
+ var col_name = $(this).find('input:checkbox').eq(0).val();
+ var hidden_input = $('<input/>')
+ .prop({
+ name: 'move_columns[]',
+ type: 'hidden'
+ })
+ .val(col_name);
+ columns[columns.length] = $('<li/>')
+ .addClass('placeholderDrag')
+ .text(col_name)
+ .append(hidden_input);
+ });
+
+ var col_list = $('#move_columns_dialog').find('ul')
+ .find('li').remove().end();
+ for (var i in columns) {
+ col_list.append(columns[i]);
+ }
+ col_list.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());
+
+ $('#move_columns_dialog').dialog({
+ modal: true,
+ buttons: button_options,
+ open: function () {
+ if ($('#move_columns_dialog').parents('.ui-dialog').height() > $(window).height()) {
+ $('#move_columns_dialog').dialog('option', 'height', $(window).height());
+ }
+ },
+ beforeClose: function () {
+ $('#move_columns_anchor').removeClass('move-active');
+ }
+ });
+ });
+
+ /**
+ * Handles multi submits in table structure page such as change, browse, drop, primary etc.
+ */
+ $('body').on('click', '#fieldsForm.ajax button[name="submit_mult"], #fieldsForm.ajax input[name="submit_mult"]', function (e) {
+ e.preventDefault();
+ var $button = $(this);
+ var $form = $button.parents('form');
+ var argsep = PMA_commonParams.get('arg_separator');
+ var submitData = $form.serialize() + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true' + argsep + 'submit_mult=' + $button.val();
+ PMA_ajaxShowMessage();
+ AJAX.source = $form;
+ $.post($form.attr('action'), submitData, AJAX.responseHandler);
+ });
+
+ /**
+ * Handles clicks on Action links in partition table
+ */
+ $(document).on('click', 'a[name^=partition_action].ajax', function (e) {
+ e.preventDefault();
+ var $link = $(this);
+
+ function submitPartitionAction (url) {
+ var params = {
+ 'ajax_request' : true,
+ 'ajax_page_request' : true
+ };
+ PMA_ajaxShowMessage();
+ AJAX.source = $link;
+ $.post(url, params, AJAX.responseHandler);
+ }
+
+ if ($link.is('#partition_action_DROP')) {
+ let question = PMA_messages.strDropPartitionWarning;
+ $link.PMA_confirm(question, $link.attr('href'), function (url) {
+ submitPartitionAction(url);
+ });
+ } else if ($link.is('#partition_action_TRUNCATE')) {
+ let question = PMA_messages.strTruncatePartitionWarning;
+ $link.PMA_confirm(question, $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 = PMA_messages.strRemovePartitioningWarning;
+ $link.PMA_confirm(question, $link.attr('href'), function (url) {
+ var params = {
+ 'ajax_request' : true,
+ 'ajax_page_request' : true
+ };
+ PMA_ajaxShowMessage();
+ AJAX.source = $link;
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+
+ $(document).on('change', 'select[name=after_field]', function () {
+ checkFirst();
+ });
+}
+
+/** Handler for "More" dropdown in structure table rows */
+export function onloadTblStructueDropdown () {
+ var windowwidth = $(window).width();
+ if (windowwidth > 768) {
+ if (! $('#fieldsForm').hasClass('HideStructureActions')) {
+ $('.table-structure-actions').width(function () {
+ var width = 5;
+ $(this).find('li').each(function () {
+ width += $(this).outerWidth(true);
+ });
+ return width;
+ });
+ }
+ }
+
+ $('.jsresponsive').css('max-width', (windowwidth - 35) + 'px');
+ var tableRows = $('.central_columns');
+ $.each(tableRows, function (index, item) {
+ if ($(item).hasClass('add_button')) {
+ $(item).on('click', function () {
+ $('input:checkbox').prop('checked', false);
+ $('#checkbox_row_' + (index + 1)).prop('checked', true);
+ $('button[value=add_to_central_columns]').trigger('click');
+ });
+ } else {
+ $(item).on('click', function () {
+ $('input:checkbox').prop('checked', false);
+ $('#checkbox_row_' + (index + 1)).prop('checked', true);
+ $('button[value=remove_from_central_columns]').trigger('click');
+ });
+ }
+ });
+}
diff --git a/js/src/tbl_tracking.js b/js/src/tbl_tracking.js
new file mode 100644
index 0000000000..da6f8f7bcb
--- /dev/null
+++ b/js/src/tbl_tracking.js
@@ -0,0 +1,115 @@
+import { $ } from './utils/JqueryExtended';
+import './plugins/jquery/jquery.tablesorter';
+import { PMA_Messages as PMA_messages } from './variables/export_variables';
+import PMA_commonParams from './variables/common_params';
+import { PMA_ajaxShowMessage } from './utils/show_ajax_messages';
+import { AJAX } from './ajax';
+
+/**
+ * Unbind all event handlers before tearing down the page
+ */
+export function teardownTblTracking () {
+ $('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
+ */
+export function onloadTblTracking () {
+ $('#versions tr:first th').append($('<div class="sorticon"></div>'));
+ $('#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 th').append($('<div class="sorticon"></div>'));
+ $('#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 th').append($('<div class="sorticon"></div>'));
+ $('#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 = PMA_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 = PMA_messages.strDeleteTrackingVersionMultiple;
+ $button.PMA_confirm(question, $form.attr('action'), function (url) {
+ PMA_ajaxShowMessage();
+ AJAX.source = $form;
+ $.post(url, submitData, AJAX.responseHandler);
+ });
+ } else {
+ PMA_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 = PMA_messages.strDeleteTrackingVersion;
+ $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) {
+ PMA_ajaxShowMessage();
+ AJAX.source = $anchor;
+ var params = {
+ 'ajax_page_request': true,
+ 'ajax_request': true
+ };
+ $.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 = PMA_messages.strDeletingTrackingEntry;
+ $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) {
+ PMA_ajaxShowMessage();
+ AJAX.source = $anchor;
+ var params = {
+ 'ajax_page_request': true,
+ 'ajax_request': true
+ };
+ $.post(url, params, AJAX.responseHandler);
+ });
+ });
+}
diff --git a/js/src/utils/DateTime.js b/js/src/utils/DateTime.js
index ef74c685d6..ff6b24dd12 100644
--- a/js/src/utils/DateTime.js
+++ b/js/src/utils/DateTime.js
@@ -1,3 +1,4 @@
+import { $ } from './JqueryExtended';
import { PMA_Messages as PMA_messages } from '../variables/export_variables';
import { PMA_tooltip } from './show_ajax_messages';
/*
@@ -81,7 +82,7 @@ export function PMA_addDatepicker ($this_element, type, options) {
* Add a date/time picker to each element that needs it
* (only when jquery-ui-timepicker-addon.js is loaded)
*/
-function addDateTimePicker () {
+export function addDateTimePicker () {
if ($.timepicker !== undefined) {
$('input.timefield, input.datefield, input.datetimefield').each(function () {
var decimals = $(this).parent().attr('data-decimals');
diff --git a/js/src/utils/IndexEnum.js b/js/src/utils/IndexEnum.js
new file mode 100644
index 0000000000..c47bd84a21
--- /dev/null
+++ b/js/src/utils/IndexEnum.js
@@ -0,0 +1,28 @@
+var IndexEnum = {
+ /**
+ * @var primary_indexes array to hold 'Primary' index columns.
+ */
+ primary_indexes: [],
+
+ /**
+ * @var unique_indexes array to hold 'Unique' index columns.
+ */
+ unique_indexes: [],
+
+ /**
+ * @var indexes array to hold 'Index' columns.
+ */
+ indexes: [],
+
+ /**
+ * @var fulltext_indexes array to hold 'Fulltext' columns.
+ */
+ fulltext_indexes: [],
+
+ /**
+ * @var spatial_indexes array to hold 'Spatial' columns.
+ */
+ spatial_indexes: []
+};
+
+export default IndexEnum;
diff --git a/js/src/utils/JqueryExtended.js b/js/src/utils/JqueryExtended.js
index 0f5f9374fa..64c0d57355 100644
--- a/js/src/utils/JqueryExtended.js
+++ b/js/src/utils/JqueryExtended.js
@@ -1,10 +1,10 @@
import $ from 'jquery';
import 'jquery-migrate';
import 'jquery-ui-bundle';
-import 'jquery-ui-timepicker-addon';
import 'jquery-mousewheel';
import 'jquery.event.drag';
import 'jquery-validation';
+import 'jquery-ui-timepicker-addon';
import '../plugins/jquery/jquery.uitablefilter';
import { methods } from './menu_resizer';
// TODO: To use this import for replacing variables used in this file for
@@ -231,15 +231,21 @@ if ($.timePicker) {
}
export function extendingValidatorMessages () {
+ var validateMessage;
+ var validateFormat;
// Creating copy of validationMessage strings object
- var validateMessage = Object.assign(window.validationMessage);
+ if (typeof window.validateMessage !== 'undefined') {
+ validateMessage = Object.assign(window.validationMessage);
+ }
// Deleting validationMessage variable from window as it is of no use now
delete window.validationMessage;
// Replacing default validation messages forr localization
$.extend($.validator.messages, validateMessage);
// Creating copy of validationFormat strings object
- var validateFormat = Object.assign(window.validationFormat);
+ if (typeof window.validationFormat !== 'undefined') {
+ validateFormat = Object.assign(window.validationFormat);
+ }
// Deleting validationFormat variable from window as it is of no use now
delete window.validationFormat;
for (let i in validateFormat) {
diff --git a/js/src/utils/Slider.js b/js/src/utils/Slider.js
new file mode 100644
index 0000000000..2e6bd416e0
--- /dev/null
+++ b/js/src/utils/Slider.js
@@ -0,0 +1,47 @@
+/**
+ * Changes status of slider
+ */
+function PMA_set_status_label ($element) {
+ var text;
+ if ($element.css('display') === 'none') {
+ text = '+ ';
+ } else {
+ text = '- ';
+ }
+ $element.closest('.slide-wrapper').prev().find('span').text(text);
+}
+
+/**
+ * Initializes slider effect.
+ */
+export function PMA_init_slider () {
+ $('div.pma_auto_slider').each(function () {
+ var $this = $(this);
+ if ($this.data('slider_init_done')) {
+ return;
+ }
+ var $wrapper = $('<div>', { 'class': 'slide-wrapper' });
+ $wrapper.toggle($this.is(':visible'));
+ $('<a>', { href: '#' + this.id, 'class': 'ajax' })
+ .text($this.attr('title'))
+ .prepend($('<span>'))
+ .insertBefore($this)
+ .on('click', function () {
+ var $wrapper = $this.closest('.slide-wrapper');
+ var visible = $this.is(':visible');
+ if (!visible) {
+ $wrapper.show();
+ }
+ $this[visible ? 'hide' : 'show']('blind', function () {
+ $wrapper.toggle(!visible);
+ $wrapper.parent().toggleClass('print_ignore', visible);
+ PMA_set_status_label($this);
+ });
+ return false;
+ });
+ $this.wrap($wrapper);
+ $this.removeAttr('title');
+ PMA_set_status_label($this);
+ $this.data('slider_init_done', 1);
+ });
+}
diff --git a/js/src/utils/show_ajax_messages.js b/js/src/utils/show_ajax_messages.js
index 6a2defcf94..b8be628bd9 100644
--- a/js/src/utils/show_ajax_messages.js
+++ b/js/src/utils/show_ajax_messages.js
@@ -47,6 +47,28 @@ function PMA_tooltip ($elements, item, myContent, additionalOptions) {
}
/**
+ * Function to display tooltips that were
+ * generated on the PHP side by PhpMyAdmin\Util::showHint()
+ *
+ * @param object $div a div jquery object which specifies the
+ * domain for searching for tooltips. If we
+ * omit this parameter the function searches
+ * in the whole body
+ **/
+export function PMA_showHints ($div) {
+ if ($div === undefined || ! $div instanceof jQuery || $div.length === 0) {
+ $div = $('body');
+ }
+ $div.find('.pma_hint').each(function () {
+ PMA_tooltip(
+ $(this).children('img'),
+ 'img',
+ $(this).children('span').html()
+ );
+ });
+}
+
+/**
* Show a message on the top of the page for an Ajax request
*
* Sample usage:
diff --git a/libraries/classes/Controllers/Database/DatabaseStructureController.php b/libraries/classes/Controllers/Database/DatabaseStructureController.php
index 914850101b..5878803374 100644
--- a/libraries/classes/Controllers/Database/DatabaseStructureController.php
+++ b/libraries/classes/Controllers/Database/DatabaseStructureController.php
@@ -145,7 +145,7 @@ class DatabaseStructureController extends DatabaseController
$this->response->getHeader()->getScripts()->addFiles(
[
'db_structure',
- 'tbl_change.js',
+ 'tbl_change',
]
);
diff --git a/libraries/classes/Controllers/Table/TableChartController.php b/libraries/classes/Controllers/Table/TableChartController.php
index e0fc1a7c9a..e2a98166fe 100644
--- a/libraries/classes/Controllers/Table/TableChartController.php
+++ b/libraries/classes/Controllers/Table/TableChartController.php
@@ -92,22 +92,7 @@ class TableChartController extends TableController
return;
}
- $this->response->getHeader()->getScripts()->addFiles(
- [
- 'chart.js',
- 'tbl_chart.js',
- 'vendor/jqplot/jquery.jqplot.js',
- 'vendor/jqplot/plugins/jqplot.barRenderer.js',
- 'vendor/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js',
- 'vendor/jqplot/plugins/jqplot.canvasTextRenderer.js',
- 'vendor/jqplot/plugins/jqplot.categoryAxisRenderer.js',
- 'vendor/jqplot/plugins/jqplot.dateAxisRenderer.js',
- 'vendor/jqplot/plugins/jqplot.pointLabels.js',
- 'vendor/jqplot/plugins/jqplot.pieRenderer.js',
- 'vendor/jqplot/plugins/jqplot.enhancedPieLegendRenderer.js',
- 'vendor/jqplot/plugins/jqplot.highlighter.js'
- ]
- );
+ $this->response->getHeader()->getScripts()->addFile('tbl_chart');
/**
* Extract values for common work
diff --git a/libraries/classes/Controllers/Table/TableIndexesController.php b/libraries/classes/Controllers/Table/TableIndexesController.php
index a31888697c..6a28531097 100644
--- a/libraries/classes/Controllers/Table/TableIndexesController.php
+++ b/libraries/classes/Controllers/Table/TableIndexesController.php
@@ -113,7 +113,7 @@ class TableIndexesController extends TableController
$form_params['old_index'] = $_REQUEST['index'];
}
- $this->response->getHeader()->getScripts()->addFile('indexes.js');
+ $this->response->getHeader()->getScripts()->addFile('indexes');
$this->response->addHTML(
$this->template->render('table/index_form', [
diff --git a/libraries/classes/Controllers/Table/TableRelationController.php b/libraries/classes/Controllers/Table/TableRelationController.php
index 08c661b728..ef7ad3596e 100644
--- a/libraries/classes/Controllers/Table/TableRelationController.php
+++ b/libraries/classes/Controllers/Table/TableRelationController.php
@@ -120,8 +120,8 @@ class TableRelationController extends TableController
$this->response->getHeader()->getScripts()->addFiles(
[
- 'tbl_relation.js',
- 'indexes.js'
+ 'tbl_relation',
+ 'indexes'
]
);
diff --git a/libraries/classes/Controllers/Table/TableSearchController.php b/libraries/classes/Controllers/Table/TableSearchController.php
index 4416f089e2..43e3845349 100644
--- a/libraries/classes/Controllers/Table/TableSearchController.php
+++ b/libraries/classes/Controllers/Table/TableSearchController.php
@@ -197,7 +197,7 @@ class TableSearchController extends TableController
$this->response
->getHeader()
->getScripts()
- ->addFile('tbl_find_replace.js');
+ ->addFile('tbl_find_replace');
if (isset($_POST['replace'])) {
$this->replaceAction();
@@ -212,10 +212,9 @@ class TableSearchController extends TableController
->getScripts()
->addFiles(
[
- 'makegrid.js',
- 'sql.js',
- 'tbl_select.js',
- 'tbl_change.js',
+ 'sql',
+ 'tbl_select',
+ 'tbl_change',
'vendor/jquery/jquery.uitablefilter.js',
'gis_data_editor.js',
]
@@ -244,8 +243,7 @@ class TableSearchController extends TableController
->getScripts()
->addFiles(
[
- 'makegrid.js',
- 'sql.js',
+ 'sql',
'vendor/jqplot/jquery.jqplot.js',
'vendor/jqplot/plugins/jqplot.canvasTextRenderer.js',
'vendor/jqplot/plugins/jqplot.canvasAxisLabelRenderer.js',
@@ -253,7 +251,7 @@ class TableSearchController extends TableController
'vendor/jqplot/plugins/jqplot.highlighter.js',
'vendor/jqplot/plugins/jqplot.cursor.js',
'tbl_zoom_plot_jqplot.js',
- 'tbl_change.js',
+ 'tbl_change',
]
);
diff --git a/libraries/classes/Controllers/Table/TableStructureController.php b/libraries/classes/Controllers/Table/TableStructureController.php
index 943ac5e37e..06095e9a78 100644
--- a/libraries/classes/Controllers/Table/TableStructureController.php
+++ b/libraries/classes/Controllers/Table/TableStructureController.php
@@ -155,8 +155,8 @@ class TableStructureController extends TableController
$this->response->getHeader()->getScripts()->addFiles(
[
- 'tbl_structure.js',
- 'indexes.js'
+ 'tbl_structure',
+ 'indexes'
]
);
diff --git a/libraries/classes/Header.php b/libraries/classes/Header.php
index 94b5454315..20189e42c6 100644
--- a/libraries/classes/Header.php
+++ b/libraries/classes/Header.php
@@ -209,7 +209,7 @@ class Header
$this->_scripts->addFile('functions');
$this->_scripts->addFile('navigation');
$this->_scripts->addFile('navigation.js');
- $this->_scripts->addFile('indexes.js');
+ $this->_scripts->addFile('indexes');
$this->_scripts->addFile('common.js');
if($GLOBALS['cfg']['enable_drag_drop_import'] === true) {
diff --git a/sql.php b/sql.php
index 92dbb5b1e7..8cd4df3bf8 100644
--- a/sql.php
+++ b/sql.php
@@ -27,8 +27,8 @@ PageSettings::showGroup('Browse');
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('tbl_change.js');
-$scripts->addFile('indexes.js');
+$scripts->addFile('tbl_change');
+$scripts->addFile('indexes');
$scripts->addFile('gis_data_editor.js');
$scripts->addFile('multi_column_sort');
diff --git a/tbl_change.php b/tbl_change.php
index 20804d89bb..65201dd5b5 100644
--- a/tbl_change.php
+++ b/tbl_change.php
@@ -74,9 +74,8 @@ $comments_map = $insertEdit->getCommentsMap($db, $table);
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('sql.js');
-$scripts->addFile('tbl_change.js');
-$scripts->addFile('vendor/jquery/additional-methods.js');
+$scripts->addFile('sql');
+$scripts->addFile('tbl_change');
$scripts->addFile('gis_data_editor.js');
/**
diff --git a/tbl_export.php b/tbl_export.php
index cf346eee17..ec8f3f9389 100644
--- a/tbl_export.php
+++ b/tbl_export.php
@@ -22,7 +22,7 @@ PageSettings::showGroup('Export');
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('export.js');
+$scripts->addFile('export');
// Get the relation settings
$relation = new Relation();
diff --git a/tbl_import.php b/tbl_import.php
index d12ec3425a..6cd48a1378 100644
--- a/tbl_import.php
+++ b/tbl_import.php
@@ -21,7 +21,7 @@ PageSettings::showGroup('Import');
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('import.js');
+$scripts->addFile('import');
$import = new Import();
diff --git a/tbl_operations.php b/tbl_operations.php
index c79c70c068..03acf5b47f 100644
--- a/tbl_operations.php
+++ b/tbl_operations.php
@@ -34,7 +34,7 @@ $pma_table = new Table($GLOBALS['table'], $GLOBALS['db']);
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('tbl_operations.js');
+$scripts->addFile('tbl_operations');
/**
* Runs common work
diff --git a/tbl_replace.php b/tbl_replace.php
index 245479ce49..387b65196f 100644
--- a/tbl_replace.php
+++ b/tbl_replace.php
@@ -42,10 +42,9 @@ $goto_include = false;
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('makegrid.js');
// Needed for generation of Inline Edit anchors
-$scripts->addFile('sql.js');
-$scripts->addFile('indexes.js');
+$scripts->addFile('sql');
+$scripts->addFile('indexes');
$scripts->addFile('gis_data_editor.js');
$relation = new Relation();
@@ -515,8 +514,7 @@ if (! empty($return_to_sql_query)) {
$GLOBALS['sql_query'] = $return_to_sql_query;
}
-$scripts->addFile('vendor/jquery/additional-methods.js');
-$scripts->addFile('tbl_change.js');
+$scripts->addFile('tbl_change');
$active_page = $goto_include;
diff --git a/tbl_tracking.php b/tbl_tracking.php
index d43a43d47d..41440ab4ab 100644
--- a/tbl_tracking.php
+++ b/tbl_tracking.php
@@ -18,8 +18,7 @@ require_once './libraries/common.inc.php';
$response = Response::getInstance();
$header = $response->getHeader();
$scripts = $header->getScripts();
-$scripts->addFile('vendor/jquery/jquery.tablesorter.js');
-$scripts->addFile('tbl_tracking.js');
+$scripts->addFile('tbl_tracking');
define('TABLE_MAY_BE_ABSENT', true);
require './libraries/tbl_common.inc.php';