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
11 /* global fulltextIndexes:writable, indexes:writable, primaryIndexes:writable, spatialIndexes:writable, uniqueIndexes:writable */ // js/functions.js
16 * Returns the array of indexes based on the index choice
18 * @param indexChoice index choice
20 Indexes.getIndexArray = function (indexChoice) {
21 var sourceArray = null;
23 switch (indexChoice.toLowerCase()) {
25 sourceArray = primaryIndexes;
28 sourceArray = uniqueIndexes;
31 sourceArray = indexes;
34 sourceArray = fulltextIndexes;
37 sourceArray = spatialIndexes;
46 * Hides/shows the inputs and submits appropriately depending
47 * on whether the index type chosen is 'SPATIAL' or not.
49 Indexes.checkIndexType = function () {
51 * @var Object Dropdown to select the index choice.
53 var $selectIndexChoice = $('#select_index_choice');
55 * @var Object Dropdown to select the index type.
57 var $selectIndexType = $('#select_index_type');
59 * @var Object Table header for the size column.
61 var $sizeHeader = $('#index_columns').find('thead tr th:nth-child(2)');
63 * @var Object Inputs to specify the columns for the index.
65 var $columnInputs = $('select[name="index[columns][names][]"]');
67 * @var Object Inputs to specify sizes for columns of the index.
69 var $sizeInputs = $('input[name="index[columns][sub_parts][]"]');
71 * @var Object Footer containg the controllers to add more columns
73 var $addMore = $('#index_frm').find('.add_more');
75 if ($selectIndexChoice.val() === 'SPATIAL') {
76 // Disable and hide the size column
78 $sizeInputs.each(function () {
80 .prop('disabled', true)
84 // Disable and hide the columns of the index other than the first one
86 $columnInputs.each(function () {
87 var $columnInput = $(this);
90 .prop('disabled', true)
97 // Hide controllers to add more columns
100 // Enable and show the size column
102 $sizeInputs.each(function () {
104 .prop('disabled', false)
105 .parent('td').show();
108 // Enable and show the columns of the index
109 $columnInputs.each(function () {
111 .prop('disabled', false)
112 .parent('td').show();
115 // Show controllers to add more columns
119 if ($selectIndexChoice.val() === 'SPATIAL' ||
120 $selectIndexChoice.val() === 'FULLTEXT') {
121 $selectIndexType.val('').prop('disabled', true);
123 $selectIndexType.prop('disabled', false);
128 * Sets current index information into form parameters.
130 * @param array source_array Array containing index columns
131 * @param string index_choice Choice of index
135 Indexes.setIndexFormParameters = function (sourceArray, indexChoice) {
136 if (indexChoice === 'index') {
137 $('input[name="indexes"]').val(JSON.stringify(sourceArray));
139 $('input[name="' + indexChoice + '_indexes"]').val(JSON.stringify(sourceArray));
144 * Removes a column from an Index.
146 * @param string col_index Index of column in form
150 Indexes.removeColumnFromIndex = function (colIndex) {
151 // Get previous index details.
152 var previousIndex = $('select[name="field_key[' + colIndex + ']"]')
154 if (previousIndex.length) {
155 previousIndex = previousIndex.split(',');
156 var sourceArray = Indexes.getIndexArray(previousIndex[0]);
157 if (sourceArray === null) {
161 // Remove column from index array.
162 var sourceLength = sourceArray[previousIndex[1]].columns.length;
163 for (var i = 0; i < sourceLength; i++) {
164 if (sourceArray[previousIndex[1]].columns[i].col_index === colIndex) {
165 sourceArray[previousIndex[1]].columns.splice(i, 1);
169 // Remove index completely if no columns left.
170 if (sourceArray[previousIndex[1]].columns.length === 0) {
171 sourceArray.splice(previousIndex[1], 1);
174 // Update current index details.
175 $('select[name="field_key[' + colIndex + ']"]').attr('data-index', '');
176 // Update form index parameters.
177 Indexes.setIndexFormParameters(sourceArray, previousIndex[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 Indexes.addColumnToIndex = function (sourceArray, arrayIndex, indexChoice, colIndex) {
193 // Remove column from other indexes (if any).
194 Indexes.removeColumnFromIndex(colIndex);
196 var indexName = $('input[name="index[Key_name]"]').val();
197 var indexComment = $('input[name="index[Index_comment]"]').val();
198 var keyBlockSize = $('input[name="index[Key_block_size]"]').val();
199 var parser = $('input[name="index[Parser]"]').val();
200 var indexType = $('select[name="index[Index_type]"]').val();
202 $('#index_columns').find('tbody').find('tr').each(function () {
203 // Get columns in particular order.
204 var colIndex = $(this).find('select[name="index[columns][names][]"]').val();
205 var size = $(this).find('input[name="index[columns][sub_parts][]"]').val();
207 'col_index': colIndex,
212 // Update or create an index.
213 sourceArray[arrayIndex] = {
214 'Key_name': indexName,
215 'Index_comment': indexComment,
216 'Index_choice': indexChoice.toUpperCase(),
217 'Key_block_size': keyBlockSize,
219 'Index_type': indexType,
223 // Display index name (or column list)
224 var displayName = indexName;
225 if (displayName === '') {
226 var columnNames = [];
227 $.each(columns, function () {
228 columnNames.push($('input[name="field_name[' + this.col_index + ']"]').val());
230 displayName = '[' + columnNames.join(', ') + ']';
232 $.each(columns, function () {
233 var id = 'index_name_' + this.col_index + '_8';
234 var $name = $('#' + id);
235 if ($name.length === 0) {
236 $name = $('<a id="' + id + '" href="#" class="ajax show_index_dialog"></a>');
237 $name.insertAfter($('select[name="field_key[' + this.col_index + ']"]'));
239 var $text = $('<small>').text(displayName);
244 // Update index details on form.
245 $('select[name="field_key[' + colIndex + ']"]')
246 .attr('data-index', indexChoice + ',' + arrayIndex);
248 Indexes.setIndexFormParameters(sourceArray, indexChoice.toLowerCase());
252 * Get choices list for a column to create a composite index with.
254 * @param string index_choice Choice of index
255 * @param array source_array Array hodling columns for particular index
257 * @return jQuery Object
259 Indexes.getCompositeIndexList = function (sourceArray, colIndex) {
260 // Remove any previous list.
261 if ($('#composite_index_list').length) {
262 $('#composite_index_list').remove();
266 var $compositeIndexList = $(
267 '<ul id="composite_index_list">' +
268 '<div>' + Messages.strCompositeWith + '</div>' +
272 // Add each column to list available for composite index.
273 var sourceLength = sourceArray.length;
274 var alreadyPresent = false;
275 for (var i = 0; i < sourceLength; i++) {
276 var subArrayLen = sourceArray[i].columns.length;
277 var columnNames = [];
278 for (var j = 0; j < subArrayLen; j++) {
280 $('input[name="field_name[' + sourceArray[i].columns[j].col_index + ']"]').val()
283 if (colIndex === sourceArray[i].columns[j].col_index) {
284 alreadyPresent = true;
288 $compositeIndexList.append(
290 '<input type="radio" name="composite_with" ' +
291 (alreadyPresent ? 'checked="checked"' : '') +
292 ' id="composite_index_' + i + '" value="' + i + '">' +
293 '<label for="composite_index_' + i + '">' + columnNames.join(', ') +
299 return $compositeIndexList;
303 * Shows 'Add Index' dialog.
305 * @param array source_array Array holding particluar index
306 * @param string array_index Index of an INDEX in array
307 * @param array target_columns Columns for an INDEX
308 * @param string col_index Index of column on form
309 * @param object index Index detail object
310 * @param bool showDialog Whether to show index creation dialog or not
314 Indexes.showAddIndexDialog = function (sourceArray, arrayIndex, targetColumns, colIndex, index, showDialog) {
315 var showDialogLocal = typeof showDialog !== 'undefined' ? showDialog : true;
316 // Prepare post-data.
317 var $table = $('input[name="table"]');
318 var table = $table.length > 0 ? $table.val() : '';
320 'server': CommonParams.get('server'),
321 'db': $('input[name="db"]').val(),
324 'create_edit_table': 1,
329 for (var i = 0; i < targetColumns.length; i++) {
330 var columnName = $('input[name="field_name[' + targetColumns[i] + ']"]').val();
331 var columnType = $('select[name="field_type[' + targetColumns[i] + ']"]').val().toLowerCase();
332 columns[columnName] = [columnType, targetColumns[i]];
334 postData.columns = JSON.stringify(columns);
336 var buttonOptions = {};
337 buttonOptions[Messages.strGo] = function () {
338 var isMissingValue = false;
339 $('select[name="index[columns][names][]"]').each(function () {
340 if ($(this).val() === '') {
341 isMissingValue = true;
345 if (! isMissingValue) {
346 Indexes.addColumnToIndex(
353 Functions.ajaxShowMessage(
354 '<div class="error"><img src="themes/dot.gif" title="" alt=""' +
355 ' class="icon ic_s_error"> ' + Messages.strMissingColumn +
364 buttonOptions[Messages.strCancel] = function () {
366 // Handle state on 'Cancel'.
367 var $selectList = $('select[name="field_key[' + colIndex + ']"]');
368 if (! $selectList.attr('data-index').length) {
369 $selectList.find('option[value*="none"]').attr('selected', 'selected');
371 var previousIndex = $selectList.attr('data-index').split(',');
372 $selectList.find('option[value*="' + previousIndex[0].toLowerCase() + '"]')
373 .attr('selected', 'selected');
376 $(this).dialog('close');
378 var $msgbox = Functions.ajaxShowMessage();
379 $.post('tbl_indexes.php', postData, function (data) {
380 if (data.success === false) {
381 // in the case of an error, show the error message returned.
382 Functions.ajaxShowMessage(data.error, false);
384 Functions.ajaxRemoveMessage($msgbox);
385 var $div = $('<div></div>');
386 if (showDialogLocal) {
387 // Show dialog if the request was successful
388 if ($('#addIndex').length > 0) {
389 $('#addIndex').remove();
392 .append(data.message)
394 title: Messages.strAddIndex,
397 create: function () {
398 $(this).keypress(function (e) {
399 if (e.which === 13 || e.keyCode === 13 || window.event.keyCode === 13) {
401 buttonOptions[Messages.strGo]();
407 Functions.checkIndexName('index_frm');
408 Functions.showHints($div);
409 Functions.initSlider();
410 $('#index_columns').find('td').each(function () {
411 $(this).css('width', $(this).width() + 'px');
413 $('#index_columns').find('tbody').sortable({
415 containment: $('#index_columns').find('tbody'),
418 // We dont need the slider at this moment.
419 $(this).find('fieldset.tblFooters').remove();
422 buttons: buttonOptions,
429 .append(data.message);
430 $div.css({ 'display' : 'none' });
431 $div.appendTo($('body'));
432 $div.attr({ 'id' : 'addIndex' });
433 var isMissingValue = false;
434 $('select[name="index[columns][names][]"]').each(function () {
435 if ($(this).val() === '') {
436 isMissingValue = true;
440 if (! isMissingValue) {
441 Indexes.addColumnToIndex(
448 Functions.ajaxShowMessage(
449 '<div class="error"><img src="themes/dot.gif" title="" alt=""' +
450 ' class="icon ic_s_error"> ' + Messages.strMissingColumn +
462 * Creates a advanced index type selection dialog.
464 * @param array source_array Array holding a particular type of indexes
465 * @param string index_choice Choice of index
466 * @param string col_index Index of new column on form
470 Indexes.indexTypeSelectionDialog = function (sourceArray, indexChoice, colIndex) {
471 var $singleColumnRadio = $('<input type="radio" id="single_column" name="index_choice"' +
472 ' checked="checked">' +
473 '<label for="single_column">' + Messages.strCreateSingleColumnIndex + '</label>');
474 var $compositeIndexRadio = $('<input type="radio" id="composite_index"' +
475 ' name="index_choice">' +
476 '<label for="composite_index">' + Messages.strCreateCompositeIndex + '</label>');
477 var $dialogContent = $('<fieldset id="advance_index_creator"></fieldset>');
478 $dialogContent.append('<legend>' + indexChoice.toUpperCase() + '</legend>');
481 // For UNIQUE/INDEX type, show choice for single-column and composite index.
482 $dialogContent.append($singleColumnRadio);
483 $dialogContent.append($compositeIndexRadio);
485 var buttonOptions = {};
487 buttonOptions[Messages.strGo] = function () {
488 if ($('#single_column').is(':checked')) {
490 'Key_name': (indexChoice === 'primary' ? 'PRIMARY' : ''),
491 'Index_choice': indexChoice.toUpperCase()
493 Indexes.showAddIndexDialog(sourceArray, (sourceArray.length), [colIndex], colIndex, index);
496 if ($('#composite_index').is(':checked')) {
497 if ($('input[name="composite_with"]').length !== 0 && $('input[name="composite_with"]:checked').length === 0
499 Functions.ajaxShowMessage(
500 '<div class="error"><img src="themes/dot.gif" title=""' +
501 ' alt="" class="icon ic_s_error"> ' +
502 Messages.strFormEmpty +
509 var arrayIndex = $('input[name="composite_with"]:checked').val();
510 var sourceLength = sourceArray[arrayIndex].columns.length;
511 var targetColumns = [];
512 for (var i = 0; i < sourceLength; i++) {
513 targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
515 targetColumns.push(colIndex);
517 Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, colIndex,
518 sourceArray[arrayIndex]);
523 buttonOptions[Messages.strCancel] = function () {
524 // Handle state on 'Cancel'.
525 var $selectList = $('select[name="field_key[' + colIndex + ']"]');
526 if (! $selectList.attr('data-index').length) {
527 $selectList.find('option[value*="none"]').attr('selected', 'selected');
529 var previousIndex = $selectList.attr('data-index').split(',');
530 $selectList.find('option[value*="' + previousIndex[0].toLowerCase() + '"]')
531 .attr('selected', 'selected');
535 $('<div></div>').append($dialogContent).dialog({
539 title: Messages.strAddIndex,
541 buttons: buttonOptions,
543 $('#composite_index').on('change', function () {
544 if ($(this).is(':checked')) {
545 $dialogContent.append(Indexes.getCompositeIndexList(sourceArray, colIndex));
548 $('#single_column').on('change', function () {
549 if ($(this).is(':checked')) {
550 if ($('#composite_index_list').length) {
551 $('#composite_index_list').remove();
557 $('#composite_index').off('change');
558 $('#single_column').off('change');
565 * Unbind all event handlers before tearing down a page
567 AJAX.registerTeardown('indexes.js', function () {
568 $(document).off('click', '#save_index_frm');
569 $(document).off('click', '#preview_index_frm');
570 $(document).off('change', '#select_index_choice');
571 $(document).off('click', 'a.drop_primary_key_index_anchor.ajax');
572 $(document).off('click', '#table_index tbody tr td.edit_index.ajax, #index_div .add_index.ajax');
573 $(document).off('click', '#index_frm input[type=submit]');
574 $('body').off('change', 'select[name*="field_key"]');
575 $(document).off('click', '.show_index_dialog');
579 * @description <p>Ajax scripts for table index page</p>
581 * Actions ajaxified here:
583 * <li>Showing/hiding inputs depending on the index type chosen</li>
584 * <li>create/edit/drop indexes</li>
587 AJAX.registerOnload('indexes.js', function () {
588 // Re-initialize variables.
592 fulltextIndexes = [];
595 // for table creation form
596 var $engineSelector = $('.create_table_form select[name=tbl_storage_engine]');
597 if ($engineSelector.length) {
598 Functions.hideShowConnection($engineSelector);
601 var $form = $('#index_frm');
602 if ($form.length > 0) {
603 Functions.showIndexEditDialog($form);
606 $(document).on('click', '#save_index_frm', function (event) {
607 event.preventDefault();
608 var $form = $('#index_frm');
609 var argsep = CommonParams.get('arg_separator');
610 var submitData = $form.serialize() + argsep + 'do_save_data=1' + argsep + 'ajax_request=true' + argsep + 'ajax_page_request=true';
611 Functions.ajaxShowMessage(Messages.strProcessingRequest);
613 $.post($form.attr('action'), submitData, AJAX.responseHandler);
616 $(document).on('click', '#preview_index_frm', function (event) {
617 event.preventDefault();
618 Functions.previewSql($('#index_frm'));
621 $(document).on('change', '#select_index_choice', function (event) {
622 event.preventDefault();
623 Indexes.checkIndexType();
624 Functions.checkIndexName('index_frm');
628 * Ajax Event handler for 'Drop Index'
630 $(document).on('click', 'a.drop_primary_key_index_anchor.ajax', function (event) {
631 event.preventDefault();
632 var $anchor = $(this);
634 * @var $currRow Object containing reference to the current field's row
636 var $currRow = $anchor.parents('tr');
637 /** @var Number of columns in the key */
638 var rows = $anchor.parents('td').attr('rowspan') || 1;
639 /** @var Rows that should be hidden */
640 var $rowsToHide = $currRow;
641 for (var i = 1, $lastRow = $currRow.next(); i < rows; i++, $lastRow = $lastRow.next()) {
642 $rowsToHide = $rowsToHide.add($lastRow);
645 var question = Functions.escapeHtml(
646 $currRow.children('td')
647 .children('.drop_primary_key_index_msg')
651 Functions.confirmPreviewSql(question, $anchor.attr('href'), function (url) {
652 var $msg = Functions.ajaxShowMessage(Messages.strDroppingPrimaryKeyIndex, false);
653 var params = Functions.getJsConfirmCommonParam(this, $anchor.getPostData());
654 $.post(url, params, function (data) {
655 if (typeof data !== 'undefined' && data.success === true) {
656 Functions.ajaxRemoveMessage($msg);
657 var $tableRef = $rowsToHide.closest('table');
658 if ($rowsToHide.length === $tableRef.find('tbody > tr').length) {
659 // We are about to remove all rows from the table
660 $tableRef.hide('medium', function () {
661 $('div.no_indexes_defined').show('medium');
662 $rowsToHide.remove();
664 $tableRef.siblings('div.notice').hide('medium');
666 // We are removing some of the rows only
667 $rowsToHide.hide('medium', function () {
671 if ($('.result_query').length) {
672 $('.result_query').remove();
674 if (data.sql_query) {
675 $('<div class="result_query"></div>')
676 .html(data.sql_query)
677 .prependTo('#structure_content');
678 Functions.highlightSql($('#page_content'));
680 CommonActions.refreshMain(false, function () {
681 $('a.ajax[href^=#indexes]').trigger('click');
685 Functions.ajaxShowMessage(Messages.strErrorProcessingRequest + ' : ' + data.error, false);
689 }); // end Drop Primary Key/Index
692 *Ajax event handler for index edit
694 $(document).on('click', '#table_index tbody tr td.edit_index.ajax, #index_div .add_index.ajax', function (event) {
695 event.preventDefault();
698 if ($(this).find('a').length === 0) {
700 var valid = Functions.checkFormElementInRange(
701 $(this).closest('form')[0],
703 'Column count has to be larger than zero.'
708 url = $(this).closest('form').serialize();
709 title = Messages.strAddIndex;
712 url = $(this).find('a').getPostData();
713 title = Messages.strEditIndex;
715 url += CommonParams.get('arg_separator') + 'ajax_request=true';
716 Functions.indexEditorDialog(url, title, function () {
717 // refresh the page using ajax
718 CommonActions.refreshMain(false, function () {
719 $('a.ajax[href^=#indexes]').trigger('click');
725 * Ajax event handler for advanced index creation during table creation
726 * and column addition.
728 $('body').on('change', 'select[name*="field_key"]', function (e, showDialog) {
729 var showDialogLocal = typeof showDialog !== 'undefined' ? showDialog : true;
730 // Index of column on Table edit and create page.
731 var colIndex = /\d+/.exec($(this).attr('name'));
732 colIndex = colIndex[0];
733 // Choice of selected index.
734 var indexChoice = /[a-z]+/.exec($(this).val());
735 indexChoice = indexChoice[0];
736 // Array containing corresponding indexes.
737 var sourceArray = null;
739 if (indexChoice === 'none') {
740 Indexes.removeColumnFromIndex(colIndex);
741 var id = 'index_name_' + '0' + '_8';
742 var $name = $('#' + id);
743 if ($name.length === 0) {
744 $name = $('<a id="' + id + '" href="#" class="ajax show_index_dialog"></a>');
745 $name.insertAfter($('select[name="field_key[' + '0' + ']"]'));
751 // Select a source array.
752 sourceArray = Indexes.getIndexArray(indexChoice);
753 if (sourceArray === null) {
757 if (sourceArray.length === 0) {
759 'Key_name': (indexChoice === 'primary' ? 'PRIMARY' : ''),
760 'Index_choice': indexChoice.toUpperCase()
762 Indexes.showAddIndexDialog(sourceArray, 0, [colIndex], colIndex, index, showDialogLocal);
764 if (indexChoice === 'primary') {
766 var sourceLength = sourceArray[arrayIndex].columns.length;
767 var targetColumns = [];
768 for (var i = 0; i < sourceLength; i++) {
769 targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
771 targetColumns.push(colIndex);
772 Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, colIndex,
773 sourceArray[arrayIndex], showDialogLocal);
775 // If there are multiple columns selected for an index, show advanced dialog.
776 Indexes.indexTypeSelectionDialog(sourceArray, indexChoice, colIndex);
781 $(document).on('click', '.show_index_dialog', function (e) {
784 // Get index details.
785 var previousIndex = $(this).prev('select')
789 var indexChoice = previousIndex[0];
790 var arrayIndex = previousIndex[1];
792 var sourceArray = Indexes.getIndexArray(indexChoice);
793 if (sourceArray !== null) {
794 var sourceLength = sourceArray[arrayIndex].columns.length;
796 var targetColumns = [];
797 for (var i = 0; i < sourceLength; i++) {
798 targetColumns.push(sourceArray[arrayIndex].columns[i].col_index);
801 Indexes.showAddIndexDialog(sourceArray, arrayIndex, targetColumns, -1, sourceArray[arrayIndex]);
805 $('#index_frm').on('submit', function () {
806 if (typeof(this.elements['index[Key_name]'].disabled) !== 'undefined') {
807 this.elements['index[Key_name]'].disabled = false;