diff options
author | Deven Bansod <devenbansod@users.noreply.github.com> | 2018-08-19 13:54:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-19 13:54:09 +0300 |
commit | d031dec87a1e3f9cc1fceee1195d11acdba80383 (patch) | |
tree | d5faa27b7f9917477e450452b3cc30f036ff878e | |
parent | 0c3411587ab9bbe0a2efb260c3a0acf9cb5a5418 (diff) | |
parent | 5f4db91d71502b8f4971e12cb69baeb686b45ff1 (diff) |
Merge pull request #14564 from Piyush3079/Mod_Js_Tbl_Structure
Modular code for table structure and table related files
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) { @@ -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'; |