1 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 * @fileoverview function used for index manipulation pages
4 * @name Table Structure
8 * @required js/functions.js
12 * Returns the array of indexes based on the index choice
14 * @param index_choice index choice
16 function PMA_getIndexArray(index_choice)
18 var source_array = null;
20 switch (index_choice.toLowerCase()) {
22 source_array = primary_indexes;
25 source_array = unique_indexes;
28 source_array = indexes;
31 source_array = fulltext_indexes;
34 source_array = spatial_indexes;
43 * Hides/shows the inputs and submits appropriately depending
44 * on whether the index type chosen is 'SPATIAL' or not.
46 function checkIndexType()
49 * @var Object Dropdown to select the index choice.
51 var $select_index_choice = $('#select_index_choice');
53 * @var Object Dropdown to select the index type.
55 var $select_index_type = $('#select_index_type');
57 * @var Object Table header for the size column.
59 var $size_header = $('#index_columns').find('thead tr th:nth-child(2)');
61 * @var Object Inputs to specify the columns for the index.
63 var $column_inputs = $('select[name="index[columns][names][]"]');
65 * @var Object Inputs to specify sizes for columns of the index.
67 var $size_inputs = $('input[name="index[columns][sub_parts][]"]');
69 * @var Object Footer containg the controllers to add more columns
71 var $add_more = $('#index_frm').find('.add_more');
73 if ($select_index_choice.val() == 'SPATIAL') {
74 // Disable and hide the size column
76 $size_inputs.each(function () {
78 .prop('disabled', true)
82 // Disable and hide the columns of the index other than the first one
84 $column_inputs.each(function () {
85 $column_input = $(this);
88 .prop('disabled', true)
95 // Hide controllers to add more columns
98 // Enable and show the size column
100 $size_inputs.each(function () {
102 .prop('disabled', false)
103 .parent('td').show();
106 // Enable and show the columns of the index
107 $column_inputs.each(function () {
109 .prop('disabled', false)
110 .parent('td').show();
113 // Show controllers to add more columns
117 if ($select_index_choice.val() == 'SPATIAL' ||
118 $select_index_choice.val() == 'FULLTEXT') {
119 $select_index_type.val('').prop('disabled', true);
121 $select_index_type.prop('disabled', false)
126 * Sets current index information into form parameters.
128 * @param array source_array Array containing index columns
129 * @param string index_choice Choice of index
133 function PMA_setIndexFormParameters(source_array, index_choice)
135 if (index_choice == 'index') {
136 $('input[name="indexes"]').val(JSON.stringify(source_array));
138 $('input[name="' + index_choice + '_indexes"]').val(JSON.stringify(source_array));
143 * Removes a column from an Index.
145 * @param string col_index Index of column in form
149 function PMA_removeColumnFromIndex(col_index)
151 // Get previous index details.
152 var previous_index = $('select[name="field_key[' + col_index + ']"]')
154 if (previous_index.length) {
155 previous_index = previous_index.split(',');
156 var source_array = PMA_getIndexArray(previous_index[0]);
157 if (source_array == null) {
161 // Remove column from index array.
162 var source_length = source_array[previous_index[1]].columns.length;
163 for (var i=0; i<source_length; i++) {
164 if (source_array[previous_index[1]].columns[i].col_index == col_index) {
165 source_array[previous_index[1]].columns.splice(i, 1);
169 // Remove index completely if no columns left.
170 if (source_array[previous_index[1]].columns.length === 0) {
171 source_array.splice(previous_index[1], 1);
174 // Update current index details.
175 $('select[name="field_key[' + col_index + ']"]').attr('data-index', '');
176 // Update form index parameters.
177 PMA_setIndexFormParameters(source_array, previous_index[0].toLowerCase());
182 * Adds a column to an Index.
184 * @param array source_array Array holding corresponding indexes
185 * @param string array_index Index of an INDEX in array
186 * @param string index_choice Choice of Index
187 * @param string col_index Index of column on form
191 function PMA_addColumnToIndex(source_array, array_index, index_choice, col_index)
193 if (col_index >= 0) {
194 // Remove column from other indexes (if any).
195 PMA_removeColumnFromIndex(col_index);
197 var index_name = $('input[name="index[Key_name]"]').val();
198 var index_comment = $('input[name="index[Index_comment]"]').val();
199 var key_block_size = $('input[name="index[Key_block_size]"]').val();
200 var parser = $('input[name="index[Parser]"]').val();
201 var index_type = $('select[name="index[Index_type]"]').val();
203 $('#index_columns').find('tbody').find('tr').each(function () {
204 // Get columns in particular order.
205 var col_index = $(this).find('select[name="index[columns][names][]"]').val();
206 var size = $(this).find('input[name="index[columns][sub_parts][]"]').val();
208 'col_index': col_index,
213 // Update or create an index.
214 source_array[array_index] = {
215 'Key_name': index_name,
216 'Index_comment': index_comment,
217 'Index_choice': index_choice.toUpperCase(),
218 'Key_block_size': key_block_size,
220 'Index_type': index_type,
224 // Display index name (or column list)
225 var displayName = index_name;
226 if (displayName == '') {
227 var columnNames = [];
228 $.each(columns, function () {
229 columnNames.push($('input[name="field_name[' + this.col_index + ']"]').val());
231 displayName = '[' + columnNames.join(', ') + ']';
233 $.each(columns, function () {
234 var id = 'index_name_' + this.col_index + '_8';
235 var $name = $('#' + id);
236 if ($name.length == 0) {
237 $name = $('<a id="' + id + '" href="#" class="ajax show_index_dialog"></a>');
238 $name.insertAfter($('select[name="field_key[' + this.col_index + ']"]'));
240 var $text = $('<small>').text(displayName);
244 if (col_index >= 0) {
245 // Update index details on form.
246 $('select[name="field_key[' + col_index + ']"]')
247 .attr('data-index', index_choice + ',' + array_index);
249 PMA_setIndexFormParameters(source_array, index_choice.toLowerCase());
253 * Get choices list for a column to create a composite index with.
255 * @param string index_choice Choice of index
256 * @param array source_array Array hodling columns for particular index
258 * @return jQuery Object
260 function PMA_getCompositeIndexList(source_array, col_index)
262 // Remove any previous list.
263 if ($('#composite_index_list').length) {
264 $('#composite_index_list').remove();
268 var $composite_index_list = $(
269 '<ul id="composite_index_list">' +
270 '<div>' + PMA_messages.strCompositeWith + '</div>' +
274 // Add each column to list available for composite index.
275 var source_length = source_array.length;
276 var already_present = false;
277 for (var i=0; i<source_length; i++) {
278 var sub_array_len = source_array[i].columns.length;
279 var column_names = [];
280 for (var j=0; j<sub_array_len; j++) {
282 $('input[name="field_name[' + source_array[i].columns[j].col_index + ']"]').val()
285 if (col_index == source_array[i].columns[j].col_index) {
286 already_present = true;
290 $composite_index_list.append(
292 '<input type="radio" name="composite_with" ' +
293 (already_present ? 'checked="checked"' : '') +
294 ' id="composite_index_' + i + '" value="' + i + '">' +
295 '<label for="composite_index_' + i + '">' + column_names.join(', ') +
301 return $composite_index_list;
305 * Shows 'Add Index' dialog.
307 * @param array source_array Array holding particluar index
308 * @param string array_index Index of an INDEX in array
309 * @param array target_columns Columns for an INDEX
310 * @param string col_index Index of column on form
311 * @param object index Index detail object
315 function PMA_showAddIndexDialog(source_array, array_index, target_columns, col_index, index)
317 // Prepare post-data.
318 var $table = $('input[name="table"]');
319 var table = $table.length > 0 ? $table.val() : '';
321 server: PMA_commonParams.get('server'),
322 token: PMA_commonParams.get('token'),
323 db: $('input[name="db"]').val(),
326 create_edit_table: 1,
331 for (var i=0; i<target_columns.length; i++) {
332 var column_name = $('input[name="field_name[' + target_columns[i] + ']"]').val();
333 var column_type = $('select[name="field_type[' + target_columns[i] + ']"]').val().toLowerCase();
334 columns[column_name] = [column_type, target_columns[i]];
336 post_data.columns = JSON.stringify(columns);
338 var button_options = {};
339 button_options[PMA_messages.strGo] = function () {
340 var is_missing_value = false;
341 $('select[name="index[columns][names][]"]').each(function () {
342 if ($(this).val() === '') {
343 is_missing_value = true;
347 if (! is_missing_value) {
348 PMA_addColumnToIndex(
356 '<div class="error"><img src="themes/dot.gif" title="" alt=""' +
357 ' class="icon ic_s_error" /> ' + PMA_messages.strMissingColumn +
364 $(this).dialog('close');
366 button_options[PMA_messages.strCancel] = function () {
367 if (col_index >= 0) {
368 // Handle state on 'Cancel'.
369 var $select_list = $('select[name="field_key[' + col_index + ']"]');
370 if (! $select_list.attr('data-index').length) {
371 $select_list.find('option[value*="none"]').attr('selected', 'selected');
373 var previous_index = $select_list.attr('data-index').split(',');
374 $select_list.find('option[value*="' + previous_index[0].toLowerCase() + '"]')
375 .attr('selected', 'selected');
378 $(this).dialog('close');
380 var $msgbox = PMA_ajaxShowMessage();
381 $.post("tbl_indexes.php", post_data, function (data) {
382 if (data.success === false) {
383 //in the case of an error, show the error message returned.
384 PMA_ajaxShowMessage(data.error, false);
386 PMA_ajaxRemoveMessage($msgbox);
387 // Show dialog if the request was successful
388 var $div = $('<div/>');
390 .append(data.message)
392 title: PMA_messages.strAddIndex,
396 checkIndexName("index_frm");
399 $('#index_columns').find('td').each(function () {
400 $(this).css("width", $(this).width() + 'px');
402 $('#index_columns').find('tbody').sortable({
404 containment: $("#index_columns").find("tbody"),
407 // We dont need the slider at this moment.
408 $(this).find('fieldset.tblFooters').remove();
411 buttons: button_options,
421 * Creates a advanced index type selection dialog.
423 * @param array source_array Array holding a particular type of indexes
424 * @param string index_choice Choice of index
425 * @param string col_index Index of new column on form
429 function PMA_indexTypeSelectionDialog(source_array, index_choice, col_index)
431 var $single_column_radio = $('<input type="radio" id="single_column" name="index_choice"' +
432 ' checked="checked">' +
433 '<label for="single_column">' + PMA_messages.strCreateSingleColumnIndex + '</label>');
434 var $composite_index_radio = $('<input type="radio" id="composite_index"' +
435 ' name="index_choice">' +
436 '<label for="composite_index">' + PMA_messages.strCreateCompositeIndex + '</label>');
437 var $dialog_content = $('<fieldset id="advance_index_creator"></fieldset>');
438 $dialog_content.append('<legend>' + index_choice.toUpperCase() + '</legend>');
441 // For UNIQUE/INDEX type, show choice for single-column and composite index.
442 $dialog_content.append($single_column_radio);
443 $dialog_content.append($composite_index_radio);
445 var button_options = {};
447 button_options[PMA_messages.strGo] = function () {
448 if ($('#single_column').is(':checked')) {
450 'Key_name': (index_choice == 'primary' ? 'PRIMARY' : ''),
451 'Index_choice': index_choice.toUpperCase()
453 PMA_showAddIndexDialog(source_array, (source_array.length), [col_index], col_index, index);
456 if ($('#composite_index').is(':checked')) {
457 if ($('input[name="composite_with"]').length !== 0 && $('input[name="composite_with"]:checked').length === 0
460 '<div class="error"><img src="themes/dot.gif" title=""' +
461 ' alt="" class="icon ic_s_error" /> ' +
462 PMA_messages.strFormEmpty +
469 var array_index = $('input[name="composite_with"]:checked').val();
470 var source_length = source_array[array_index].columns.length;
471 var target_columns = [];
472 for (var i=0; i<source_length; i++) {
473 target_columns.push(source_array[array_index].columns[i].col_index);
475 target_columns.push(col_index);
477 PMA_showAddIndexDialog(source_array, array_index, target_columns, col_index,
478 source_array[array_index]);
483 button_options[PMA_messages.strCancel] = function () {
484 // Handle state on 'Cancel'.
485 var $select_list = $('select[name="field_key[' + col_index + ']"]');
486 if (! $select_list.attr('data-index').length) {
487 $select_list.find('option[value*="none"]').attr('selected', 'selected');
489 var previous_index = $select_list.attr('data-index').split(',');
490 $select_list.find('option[value*="' + previous_index[0].toLowerCase() + '"]')
491 .attr('selected', 'selected');
495 var $dialog = $('<div/>').append($dialog_content).dialog({
499 title: PMA_messages.strAddIndex,
501 buttons: button_options,
503 $('#composite_index').on('change', function () {
504 if ($(this).is(':checked')) {
505 $dialog_content.append(PMA_getCompositeIndexList(source_array, col_index));
508 $('#single_column').on('change', function () {
509 if ($(this).is(':checked')) {
510 if ($('#composite_index_list').length) {
511 $('#composite_index_list').remove();
517 $('#composite_index').off('change');
518 $('#single_column').off('change');
525 * Unbind all event handlers before tearing down a page
527 AJAX.registerTeardown('indexes.js', function () {
528 $(document).off('click', '#save_index_frm');
529 $(document).off('click', '#preview_index_frm');
530 $(document).off('change', '#select_index_choice');
531 $(document).off('click', 'a.drop_primary_key_index_anchor.ajax');
532 $(document).off('click', "#table_index tbody tr td.edit_index.ajax, #indexes .add_index.ajax");
533 $(document).off('click', '#index_frm input[type=submit]');
534 $('body').off('change', 'select[name*="field_key"]');
535 $(document).off('click', '.show_index_dialog');
539 * @description <p>Ajax scripts for table index page</p>
541 * Actions ajaxified here:
543 * <li>Showing/hiding inputs depending on the index type chosen</li>
544 * <li>create/edit/drop indexes</li>
547 AJAX.registerOnload('indexes.js', function () {
548 // Re-initialize variables.
549 primary_indexes = [];
552 fulltext_indexes = [];
553 spatial_indexes = [];
555 // for table creation form
556 var $engine_selector = $('.create_table_form select[name=tbl_storage_engine]');
557 if ($engine_selector.length) {
558 PMA_hideShowConnection($engine_selector);
561 var $form = $("#index_frm");
562 if ($form.length > 0) {
563 showIndexEditDialog($form);
566 $(document).on('click', '#save_index_frm', function (event) {
567 event.preventDefault();
568 var $form = $("#index_frm");
569 var submitData = $form.serialize() + '&do_save_data=1&ajax_request=true&ajax_page_request=true';
570 var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
572 $.post($form.attr('action'), submitData, AJAX.responseHandler);
575 $(document).on('click', '#preview_index_frm', function (event) {
576 event.preventDefault();
577 PMA_previewSQL($('#index_frm'));
580 $(document).on('change', '#select_index_choice', function (event) {
581 event.preventDefault();
583 checkIndexName("index_frm");
587 * Ajax Event handler for 'Drop Index'
589 $(document).on('click', 'a.drop_primary_key_index_anchor.ajax', function (event) {
590 event.preventDefault();
591 var $anchor = $(this);
593 * @var $curr_row Object containing reference to the current field's row
595 var $curr_row = $anchor.parents('tr');
596 /** @var Number of columns in the key */
597 var rows = $anchor.parents('td').attr('rowspan') || 1;
598 /** @var Rows that should be hidden */
599 var $rows_to_hide = $curr_row;
600 for (var i = 1, $last_row = $curr_row.next(); i < rows; i++, $last_row = $last_row.next()) {
601 $rows_to_hide = $rows_to_hide.add($last_row);
604 var question = escapeHtml(
605 $curr_row.children('td')
606 .children('.drop_primary_key_index_msg')
610 $anchor.PMA_confirm(question, $anchor.attr('href'), function (url) {
611 var $msg = PMA_ajaxShowMessage(PMA_messages.strDroppingPrimaryKeyIndex, false);
613 'is_js_confirmed': 1,
614 'ajax_request': true,
615 'token' : PMA_commonParams.get('token')
617 $.post(url, params, function (data) {
618 if (typeof data !== 'undefined' && data.success === true) {
619 PMA_ajaxRemoveMessage($msg);
620 var $table_ref = $rows_to_hide.closest('table');
621 if ($rows_to_hide.length == $table_ref.find('tbody > tr').length) {
622 // We are about to remove all rows from the table
623 $table_ref.hide('medium', function () {
624 $('div.no_indexes_defined').show('medium');
625 $rows_to_hide.remove();
627 $table_ref.siblings('div.notice').hide('medium');
629 // We are removing some of the rows only
630 $rows_to_hide.hide("medium", function () {
634 if ($('.result_query').length) {
635 $('.result_query').remove();
637 if (data.sql_query) {
638 $('<div class="result_query"></div>')
639 .html(data.sql_query)
640 .prependTo('#structure_content');
641 PMA_highlightSQL($('#page_content'));
643 PMA_commonActions.refreshMain(false, function () {
644 $("a.ajax[href^=#indexes]").click();
646 PMA_reloadNavigation();
648 PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false);
651 }); // end $.PMA_confirm()
652 }); //end Drop Primary Key/Index
655 *Ajax event handler for index edit
657 $(document).on('click', "#table_index tbody tr td.edit_index.ajax, #indexes .add_index.ajax", function (event) {
658 event.preventDefault();
660 if ($(this).find("a").length === 0) {
662 var valid = checkFormElementInRange(
663 $(this).closest('form')[0],
665 'Column count has to be larger than zero.'
670 url = $(this).closest('form').serialize();
671 title = PMA_messages.strAddIndex;
674 url = $(this).find("a").attr("href");
675 if (url.substring(0, 16) == "tbl_indexes.php?") {
676 url = url.substring(16, url.length);
678 title = PMA_messages.strEditIndex;
680 url += "&ajax_request=true";
681 indexEditorDialog(url, title, function () {
682 // refresh the page using ajax
683 PMA_commonActions.refreshMain(false, function () {
684 $("a.ajax[href^=#indexes]").click();
690 * Ajax event handler for advanced index creation during table creation
691 * and column addition.
693 $('body').on('change', 'select[name*="field_key"]', function () {
694 // Index of column on Table edit and create page.
695 var col_index = /\d+/.exec($(this).attr('name'));
696 col_index = col_index[0];
697 // Choice of selected index.
698 var index_choice = /[a-z]+/.exec($(this).val());
699 index_choice = index_choice[0];
700 // Array containing corresponding indexes.
701 var source_array = null;
703 if (index_choice == 'none') {
704 PMA_removeColumnFromIndex(col_index);
708 // Select a source array.
709 source_array = PMA_getIndexArray(index_choice);
710 if (source_array == null) {
714 if (source_array.length === 0) {
716 'Key_name': (index_choice == 'primary' ? 'PRIMARY' : ''),
717 'Index_choice': index_choice.toUpperCase()
719 PMA_showAddIndexDialog(source_array, 0, [col_index], col_index, index);
721 if (index_choice == 'primary') {
723 var source_length = source_array[array_index].columns.length;
724 var target_columns = [];
725 for (var i=0; i<source_length; i++) {
726 target_columns.push(source_array[array_index].columns[i].col_index);
728 target_columns.push(col_index);
730 PMA_showAddIndexDialog(source_array, array_index, target_columns, col_index,
731 source_array[array_index]);
733 // If there are multiple columns selected for an index, show advanced dialog.
734 PMA_indexTypeSelectionDialog(source_array, index_choice, col_index);
739 $(document).on('click', '.show_index_dialog', function (e) {
742 // Get index details.
743 var previous_index = $(this).prev('select')
747 var index_choice = previous_index[0];
748 var array_index = previous_index[1];
750 var source_array = PMA_getIndexArray(index_choice);
751 var source_length = source_array[array_index].columns.length;
753 var target_columns = [];
754 for (var i = 0; i < source_length; i++) {
755 target_columns.push(source_array[array_index].columns[i].col_index);
758 PMA_showAddIndexDialog(source_array, array_index, target_columns, -1, source_array[array_index]);