UPDATE 4.4.0.0
[phpmyadmin.git] / js / tbl_structure.js
blob73ba55e7b16bc42b8673b3f97722752cb65a220d
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * @fileoverview    functions used on the table structure page
4  * @name            Table Structure
5  *
6  * @requires    jQuery
7  * @requires    jQueryUI
8  * @required    js/functions.js
9  */
11 /**
12  * AJAX scripts for tbl_structure.php
13  *
14  * Actions ajaxified here:
15  * Drop Column
16  * Add Primary Key
17  * Drop Primary Key/Index
18  *
19  */
21 /**
22  * This function returns the horizontal space available for the menu in pixels.
23  * To calculate this value we start we the width of the main panel, then we
24  * substract the margin of the page content, then we substract any cellspacing
25  * that the table may have (original theme only) and finally we substract the
26  * width of all columns of the table except for the last one (which is where
27  * the menu will go). What we should end up with is the distance between the
28  * start of the last column on the table and the edge of the page, again this
29  * is the space available for the menu.
30  *
31  * In the case where the table cell where the menu will be displayed is already
32  * off-screen (the table is wider than the page), a negative value will be returned,
33  * but this will be treated as a zero by the menuResizer plugin.
34  *
35  * @return int
36  */
37 function PMA_tbl_structure_menu_resizer_callback() {
38     var pagewidth = $('body').width();
39     var $page = $('#page_content');
40     pagewidth -= $page.outerWidth(true) - $page.outerWidth();
41     var columnsWidth = 0;
42     var $columns = $('#tablestructure').find('tr:eq(1)').find('td,th');
43     $columns.not(':last').each(function () {
44         columnsWidth += $(this).outerWidth(true);
45     });
46     var totalCellSpacing = $('#tablestructure').width();
47     $columns.each(function () {
48         totalCellSpacing -= $(this).outerWidth(true);
49     });
50     return pagewidth - columnsWidth - totalCellSpacing - 15; // 15px extra margin
53 /**
54  * Reload fields table
55  */
56 function reloadFieldForm() {
57     $.post($("#fieldsForm").attr('action'), $("#fieldsForm").serialize() + "&ajax_request=true", function (form_data) {
58         var $temp_div = $("<div id='temp_div'><div>").append(form_data.message);
59         $("#fieldsForm").replaceWith($temp_div.find("#fieldsForm"));
60         $("#addColumns").replaceWith($temp_div.find("#addColumns"));
61         $('#move_columns_dialog ul').replaceWith($temp_div.find("#move_columns_dialog ul"));
62         $("#moveColumns").removeClass("move-active");
63         /* reinitialise the more options in table */
64         $('#fieldsForm ul.table-structure-actions').menuResizer(PMA_tbl_structure_menu_resizer_callback);
65     });
66     $('#page_content').show();
69 function checkFirst() {
70     if ($("select[name=after_field] option:selected").data('pos') === 'first') {
71         $("input[name=field_where]").val('first');
72     } else {
73         $("input[name=field_where]").val('after');
74     }
76 /**
77  * Unbind all event handlers before tearing down a page
78  */
79 AJAX.registerTeardown('tbl_structure.js', function () {
80     $(document).off('click', "a.drop_column_anchor.ajax");
81     $(document).off('click', "a.add_key.ajax");
82     $(document).off('click', "#move_columns_anchor");
83     $(document).off('submit', ".append_fields_form.ajax");
84     $('body').off('click', '#fieldsForm.ajax button[name="submit_mult"], #fieldsForm.ajax input[name="submit_mult"]');
85 });
87 AJAX.registerOnload('tbl_structure.js', function () {
89     // Re-initialize variables.
90     primary_indexes = [];
91     unique_indexes = [];
92     indexes = [];
93     fulltext_indexes = [];
95     //by default select the last option to add new column (adds at end of the table)
96     $("select[name=after_field] option:last").attr("selected","selected");
98     /**
99      *Ajax action for submitting the "Column Change" and "Add Column" form
100      */
101     $(".append_fields_form.ajax").off();
102     $(document).on('submit', ".append_fields_form.ajax", function (event) {
103         event.preventDefault();
104         /**
105          * @var    the_form    object referring to the export form
106          */
107         var $form = $(this);
109         /*
110          * First validate the form; if there is a problem, avoid submitting it
111          *
112          * checkTableEditForm() needs a pure element and not a jQuery object,
113          * this is why we pass $form[0] as a parameter (the jQuery object
114          * is actually an array of DOM elements)
115          */
116         if (checkTableEditForm($form[0], $form.find('input[name=orig_num_fields]').val())) {
117             // OK, form passed validation step
118             PMA_prepareForAjaxRequest($form);
119             if (PMA_checkReservedWordColumns($form)) {
120                 //User wants to submit the form
121                 $msg = PMA_ajaxShowMessage();
122                 $.post($form.attr('action'), $form.serialize() + '&do_save_data=1', function (data) {
123                     if ($(".sqlqueryresults").length !== 0) {
124                         $(".sqlqueryresults").remove();
125                     } else if ($(".error:not(.tab)").length !== 0) {
126                         $(".error:not(.tab)").remove();
127                     }
128                     if (typeof data.success != 'undefined' && data.success === true) {
129                         $("#page_content")
130                             .empty()
131                             .append(data.message)
132                             .show();
133                         PMA_highlightSQL($('#page_content'));
134                         $(".result_query .notice").remove();
135                         reloadFieldForm();
136                         $form.remove();
137                         PMA_ajaxRemoveMessage($msg);
138                         PMA_init_slider();
139                         PMA_reloadNavigation();
140                     } else {
141                         PMA_ajaxShowMessage(data.error, false);
142                     }
143                 }); // end $.post()
144             }
145         }
146     }); // end change table button "do_save_data"
148     /**
149      * Attach Event Handler for 'Drop Column'
150      */
151     $(document).on('click', "a.drop_column_anchor.ajax", function (event) {
152         event.preventDefault();
153         /**
154          * @var curr_table_name String containing the name of the current table
155          */
156         var curr_table_name = $(this).closest('form').find('input[name=table]').val();
157         /**
158          * @var curr_row    Object reference to the currently selected row (i.e. field in the table)
159          */
160         var $curr_row = $(this).parents('tr');
161         /**
162          * @var curr_column_name    String containing name of the field referred to by {@link curr_row}
163          */
164         var curr_column_name = $curr_row.children('th').children('label').text();
165         curr_column_name = escapeHtml(curr_column_name);
166         /**
167          * @var $after_field_item    Corresponding entry in the 'After' field.
168          */
169         var $after_field_item = $("select[name='after_field'] option[value='" + curr_column_name + "']");
170         /**
171          * @var question    String containing the question to be asked for confirmation
172          */
173         var question = PMA_sprintf(PMA_messages.strDoYouReally, 'ALTER TABLE `' + escapeHtml(curr_table_name) + '` DROP `' + escapeHtml(curr_column_name) + '`;');
174         $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
175             var $msg = PMA_ajaxShowMessage(PMA_messages.strDroppingColumn, false);
176             $.get(url, {'is_js_confirmed' : 1, 'ajax_request' : true, 'ajax_page_request' : true}, function (data) {
177                 if (typeof data !== 'undefined' && data.success === true) {
178                     PMA_ajaxRemoveMessage($msg);
179                     if ($('.result_query').length) {
180                         $('.result_query').remove();
181                     }
182                     if (data.sql_query) {
183                         $('<div class="result_query"></div>')
184                             .html(data.sql_query)
185                             .prependTo('#structure_content');
186                         PMA_highlightSQL($('#page_content'));
187                     }
188                     toggleRowColors($curr_row.next());
189                     // Adjust the row numbers
190                     for (var $row = $curr_row.next(); $row.length > 0; $row = $row.next()) {
191                         var new_val = parseInt($row.find('td:nth-child(2)').text(), 10) - 1;
192                         $row.find('td:nth-child(2)').text(new_val);
193                     }
194                     $after_field_item.remove();
195                     $curr_row.hide("medium").remove();
196                     //refresh table stats
197                     if (data.tableStat) {
198                         $('#tablestatistics').html(data.tableStat);
199                     }
200                     // refresh the list of indexes (comes from sql.php)
201                     $('.index_info').replaceWith(data.indexes_list);
202                     PMA_reloadNavigation();
203                 } else {
204                     PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest + " : " + data.error, false);
205                 }
206             }); // end $.get()
207         }); // end $.PMA_confirm()
208     }); //end of Drop Column Anchor action
210     /**
211      * Ajax Event handler for adding keys
212      */
213     $(document).on('click', "a.add_key.ajax", function (event) {
214         event.preventDefault();
216         $this = $(this);
217         var curr_table_name = $this.closest('form').find('input[name=table]').val();
218         var curr_column_name = $this.parents('tr').children('th').children('label').text();
220         var add_clause = '';
221         if ($this.is('.add_primary_key_anchor')) {
222             add_clause = 'ADD PRIMARY KEY';
223         } else if ($this.is('.add_index_anchor')) {
224             add_clause = 'ADD INDEX';
225         } else if ($this.is('.add_unique_anchor')) {
226             add_clause = 'ADD UNIQUE';
227         } else if ($this.is('.add_spatial_anchor')) {
228             add_clause = 'ADD SPATIAL';
229         } else if ($this.is('.add_fulltext_anchor')) {
230             add_clause = 'ADD FULLTEXT';
231         }
232         var question = PMA_sprintf(PMA_messages.strDoYouReally, 'ALTER TABLE `' +
233                 escapeHtml(curr_table_name) + '` ' + add_clause + '(`' + escapeHtml(curr_column_name) + '`);');
235         $(this).PMA_confirm(question, $(this).attr('href'), function (url) {
236             PMA_ajaxShowMessage();
237             $.get(url, {'ajax_request' : true, 'ajax_page_request' : true}, AJAX.responseHandler);
238         }); // end $.PMA_confirm()
239     }); //end Add key
241     /**
242      * Inline move columns
243     **/
244     $(document).on('click', "#move_columns_anchor", function (e) {
245         e.preventDefault();
247         if ($(this).hasClass("move-active")) {
248             return;
249         }
251         /**
252          * @var    button_options  Object that stores the options passed to jQueryUI
253          *                          dialog
254          */
255         var button_options = {};
257         button_options[PMA_messages.strGo] = function (event) {
258             event.preventDefault();
259             var $msgbox = PMA_ajaxShowMessage();
260             var $this = $(this);
261             var $form = $this.find("form");
262             var serialized = $form.serialize();
264             // check if any columns were moved at all
265             if (serialized == $form.data("serialized-unmoved")) {
266                 PMA_ajaxRemoveMessage($msgbox);
267                 $this.dialog('close');
268                 return;
269             }
271             $.post($form.prop("action"), serialized + "&ajax_request=true", function (data) {
272                 if (data.success === false) {
273                     PMA_ajaxRemoveMessage($msgbox);
274                     $this
275                     .clone()
276                     .html(data.error)
277                     .dialog({
278                         title: $(this).prop("title"),
279                         height: 230,
280                         width: 900,
281                         modal: true,
282                         buttons: button_options_error
283                     }); // end dialog options
284                 } else {
285                     $('#fieldsForm ul.table-structure-actions').menuResizer('destroy');
286                     // sort the fields table
287                     var $fields_table = $("table#tablestructure tbody");
288                     // remove all existing rows and remember them
289                     var $rows = $fields_table.find("tr").remove();
290                     // loop through the correct order
291                     for (var i in data.columns) {
292                         var the_column = data.columns[i];
293                         var $the_row = $rows
294                             .find("input:checkbox[value=" + the_column + "]")
295                             .closest("tr");
296                         // append the row for this column to the table
297                         $fields_table.append($the_row);
298                     }
299                     var $firstrow = $fields_table.find("tr").eq(0);
300                     // Adjust the row numbers and colors
301                     for (var $row = $firstrow; $row.length > 0; $row = $row.next()) {
302                         $row
303                         .find('td:nth-child(2)')
304                         .text($row.index() + 1)
305                         .end()
306                         .removeClass("odd even")
307                         .addClass($row.index() % 2 === 0 ? "odd" : "even");
308                     }
309                     PMA_ajaxShowMessage(data.message);
310                     $this.dialog('close');
311                     $('#fieldsForm ul.table-structure-actions').menuResizer(PMA_tbl_structure_menu_resizer_callback);
312                 }
313             });
314         };
315         button_options[PMA_messages.strCancel] = function () {
316             $(this).dialog('close');
317         };
319         var button_options_error = {};
320         button_options_error[PMA_messages.strOK] = function () {
321             $(this).dialog('close').remove();
322         };
324         var columns = [];
326         $("#tablestructure tbody tr").each(function () {
327             var col_name = $(this).find("input:checkbox").eq(0).val();
328             var hidden_input = $("<input/>")
329                 .prop({
330                     name: "move_columns[]",
331                     type: "hidden"
332                 })
333                 .val(col_name);
334             columns[columns.length] = $("<li/>")
335                 .addClass("placeholderDrag")
336                 .text(col_name)
337                 .append(hidden_input);
338         });
340         var col_list = $("#move_columns_dialog ul")
341             .find("li").remove().end();
342         for (var i in columns) {
343             col_list.append(columns[i]);
344         }
345         col_list.sortable({
346             axis: 'y',
347             containment: $("#move_columns_dialog div"),
348             tolerance: 'pointer'
349         }).disableSelection();
350         var $form = $("#move_columns_dialog form");
351         $form.data("serialized-unmoved", $form.serialize());
353         $("#move_columns_dialog").dialog({
354             modal: true,
355             buttons: button_options,
356             open: function () {
357                 if ($('#move_columns_dialog').parents('.ui-dialog').height() > $(window).height()) {
358                     $('#move_columns_dialog').dialog("option", "height", $(window).height());
359                 }
360             },
361             beforeClose: function () {
362                 $("#move_columns_anchor").removeClass("move-active");
363             }
364         });
365     });
367     /**
368      * Handles multi submits in table structure page such as change, browse, drop, primary etc.
369      */
370     $('body').on('click', '#fieldsForm.ajax button[name="submit_mult"], #fieldsForm.ajax input[name="submit_mult"]', function (e) {
371         e.preventDefault();
372         var $button = $(this);
373         var $form = $button.parent('form');
374         var submitData = $form.serialize() + '&ajax_request=true&ajax_page_request=true&submit_mult=' + $button.val();
375         PMA_ajaxShowMessage();
376         $.get($form.attr('action'), submitData, AJAX.responseHandler);
377     });
380 /** Handler for "More" dropdown in structure table rows */
381 AJAX.registerOnload('tbl_structure.js', function () {
382     if ($('#fieldsForm').hasClass('HideStructureActions')) {
383         $('#fieldsForm ul.table-structure-actions').menuResizer(PMA_tbl_structure_menu_resizer_callback);
384     }
386 AJAX.registerTeardown('tbl_structure.js', function () {
387     $('#fieldsForm ul.table-structure-actions').menuResizer('destroy');
389 $(function () {
390     $(window).resize($.throttle(function () {
391         var $list = $('#fieldsForm ul.table-structure-actions');
392         if ($list.length) {
393             $list.menuResizer('resize');
394         }
395     }));