Translation update done using Pootle.
[phpmyadmin/ammaryasirr.git] / js / sql.js
blobe762bb53c0cbfb433abfb9c31a3aa18454f84d88
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * @fileoverview    functions used wherever an sql query form is used
4  *
5  * @requires    jQuery
6  * @requires    js/functions.js
7  *
8  */
10 var $data_a;
12 /**
13  * decode a string URL_encoded
14  *
15  * @param string str
16  * @return string the URL-decoded string
17  */
18 function PMA_urldecode(str) {
19     return decodeURIComponent(str.replace(/\+/g, '%20'));
22 function PMA_urlencode(str) {
23     return encodeURIComponent(str.replace(/\%20/g, '+'));
26 /**
27  * Get the field name for the current field.  Required to construct the query
28  * for inline editing
29  *
30  * @param   $this_field  jQuery object that points to the current field's tr
31  */
32 function getFieldName($this_field) {
34     var this_field_index = $this_field.index();
35     // ltr or rtl direction does not impact how the DOM was generated
36     // check if the action column in the left exist
37     var leftActionExist = !$('#table_results').find('th:first').hasClass('draggable');
38     // 5 columns to account for the checkbox, edit, appended inline edit, copy and delete anchors but index is zero-based so substract 4
39     var field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index - (leftActionExist ? 4 : 0)) + ') a').text();
40     // happens when just one row (headings contain no a)
41     if ("" == field_name) {
42         field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index - (leftActionExist ? 4 : 0)) + ')').text();
43     }
45     field_name = $.trim(field_name);
47     return field_name;
50 /**
51  * The function that iterates over each row in the table_results and appends a
52  * new inline edit anchor to each table row.
53  *
54  */
55 function appendInlineAnchor() {
56     // TODO: remove two lines below if vertical display mode has been completely removed
57     var disp_mode = $("#top_direction_dropdown").val();
59     if (disp_mode != 'vertical') {
60         $('.edit_row_anchor').each(function() {
62             var $this_td = $(this);
63             $this_td.removeClass('edit_row_anchor');
65             var $cloned_anchor = $this_td.clone();
67             var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
68             if ($img_object.length != 0) {
69                 $img_object.removeClass('ic_b_edit');
70                 $img_object.addClass('ic_b_inline_edit');
72                 $cloned_anchor.find('a').attr('href', '#');
73                 var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
74                 var $span = $cloned_anchor.find('a').find('span');
75                 if ($edit_span.length > 0) {
76                     $span.text(' ' + PMA_messages['strInlineEdit']);
77                     $span.prepend($img_object);
78                 } else {
79                     $span.text('');
80                     $span.append($img_object);
81                 }
82             } else {
83                 // Only text is displayed. See $cfg['PropertiesIconic']
84                 $cloned_anchor.find('a').attr('href', '#');
85                 $cloned_anchor.find('a span').text(PMA_messages['strInlineEdit']);
87                 // the link was too big so <input type="image"> is there
88                 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
89                 if ($img_object.length > 0) {
90                     $img_object.removeClass('ic_b_edit');
91                     $img_object.addClass('ic_b_inline_edit');
92                 }
93                 $cloned_anchor
94                  .find('.clickprevimage')
95                  .text(' ' + PMA_messages['strInlineEdit']);
96             }
98             $cloned_anchor
99              .addClass('inline_edit_anchor');
101             $this_td.after($cloned_anchor);
102         });
104         $('#resultsForm').find('thead, tbody').find('th').each(function() {
105             var $this_th = $(this);
106             if ($this_th.attr('colspan') == 4) {
107                 $this_th.attr('colspan', '5');
108             }
109         });
110     }
113 /**#@+
114  * @namespace   jQuery
115  */
118  * @description <p>Ajax scripts for sql and browse pages</p>
120  * Actions ajaxified here:
121  * <ul>
122  * <li>Retrieve results of an SQL query</li>
123  * <li>Paginate the results table</li>
124  * <li>Sort the results table</li>
125  * <li>Change table according to display options</li>
126  * <li>Inline editing of data</li>
127  * </ul>
129  * @name        document.ready
130  * @memberOf    jQuery
131  */
132 $(document).ready(function() {
134     /**
135      * Set a parameter for all Ajax queries made on this page.  Don't let the
136      * web server serve cached pages
137      */
138     $.ajaxSetup({
139         cache: 'false'
140     });
142     /* Hides the bookmarkoptions checkboxes when the bookmark label is empty */
143     $('input#bkm_label').keyup(function() {
144         $('input#id_bkm_all_users, input#id_bkm_replace')
145             .parent()
146             .toggle($(this).attr('value').length > 0);
147     }).trigger('keyup');
149     /**
150      * Attach the {@link appendInlineAnchor} function to a custom event, which
151      * will be triggered manually everytime the table of results is reloaded
152      * @memberOf    jQuery
153      */
154     $("#sqlqueryresults").live('appendAnchor',function() {
155         appendInlineAnchor();
156     })
158     /**
159      * Attach the {@link makegrid} function to a custom event, which will be
160      * triggered manually everytime the table of results is reloaded
161      * @memberOf    jQuery
162      */
163     $("#sqlqueryresults").live('makegrid', function() {
164         $('#table_results').makegrid();
165     })
167     /**
168      * Attach the {@link refreshgrid} function to a custom event, which will be
169      * triggered manually everytime the table of results is manipulated (e.g., by inline edit)
170      * @memberOf    jQuery
171      */
172     $("#sqlqueryresults").live('refreshgrid', function() {
173         $('#table_results').refreshgrid();
174     })
176     /**
177      * Trigger the appendAnchor event to prepare the first table for inline edit
178      * (see $GLOBALS['cfg']['AjaxEnable'])
179      * @memberOf    jQuery
180      * @name        sqlqueryresults_trigger
181      */
182     $("#sqlqueryresults.ajax").trigger('appendAnchor');
184     /**
185      * Append the "Show/Hide query box" message to the query input form
186      *
187      * @memberOf jQuery
188      * @name    appendToggleSpan
189      */
190     // do not add this link more than once
191     if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
192         $('<a id="togglequerybox"></a>')
193         .html(PMA_messages['strHideQueryBox'])
194         .appendTo("#sqlqueryform")
195         // initially hidden because at this point, nothing else
196         // appears under the link
197         .hide();
199         // Attach the toggling of the query box visibility to a click
200         $("#togglequerybox").bind('click', function() {
201             var $link = $(this)
202             $link.siblings().slideToggle("fast");
203             if ($link.text() == PMA_messages['strHideQueryBox']) {
204                 $link.text(PMA_messages['strShowQueryBox']);
205                 // cheap trick to add a spacer between the menu tabs
206                 // and "Show query box"; feel free to improve!
207                 $('#togglequerybox_spacer').remove();
208                 $link.before('<br id="togglequerybox_spacer" />');
209             } else {
210                 $link.text(PMA_messages['strHideQueryBox']);
211             }
212             // avoid default click action
213             return false;
214         })
215     }
217     /**
218      * Ajax Event handler for 'SQL Query Submit'
219      *
220      * @see         PMA_ajaxShowMessage()
221      * @see         $cfg['AjaxEnable']
222      * @memberOf    jQuery
223      * @name        sqlqueryform_submit
224      */
225     $("#sqlqueryform.ajax").live('submit', function(event) {
226         event.preventDefault();
228         var $form = $(this);
229         if (! checkSqlQuery($form[0])) {
230             return false;
231         }
233         // remove any div containing a previous error message
234         $('.error').remove();
236         var $msgbox = PMA_ajaxShowMessage();
237         var $sqlqueryresults = $('#sqlqueryresults');
239         PMA_prepareForAjaxRequest($form);
241         $.post($form.attr('action'), $form.serialize() , function(data) {
242             if (data.success == true) {
243                 // fade out previous messages, if any
244                 $('.success').fadeOut();
245                 $('.sqlquery_message').fadeOut();
246                 // show a message that stays on screen
247                 if (typeof data.sql_query != 'undefined') {
248                     $('<div class="sqlquery_message"></div>')
249                      .html(data.sql_query)
250                      .insertBefore('#sqlqueryform');
251                     // unnecessary div that came from data.sql_query
252                     $('.notice').remove();
253                 } else {
254                     $('#sqlqueryform').before(data.message);
255                 }
256                 $sqlqueryresults.show();
257                 // this happens if a USE command was typed
258                 if (typeof data.reload != 'undefined') {
259                     // Unbind the submit event before reloading. See bug #3295529
260                     $("#sqlqueryform.ajax").die('submit');
261                     $form.find('input[name=db]').val(data.db);
262                     // need to regenerate the whole upper part
263                     $form.find('input[name=ajax_request]').remove();
264                     $form.append('<input type="hidden" name="reload" value="true" />');
265                     $.post('db_sql.php', $form.serialize(), function(data) {
266                         $('body').html(data);
267                     }); // end inner post
268                 }
269             }
270             else if (data.success == false ) {
271                 // show an error message that stays on screen
272                 $('#sqlqueryform').before(data.error);
273                 $sqlqueryresults.hide();
274             }
275             else {
276                 // real results are returned
277                 // fade out previous messages, if any
278                 $('.success').fadeOut();
279                 $('.sqlquery_message').fadeOut();
280                 var $received_data = $(data);
281                 var $zero_row_results = $received_data.find('textarea[name="sql_query"]');
282                 // if zero rows are returned from the query execution
283                 if ($zero_row_results.length > 0) {
284                     $('#sqlquery').val($zero_row_results.val());
285                 } else {
286                     $sqlqueryresults
287                      .show()
288                      .html(data)
289                      .trigger('appendAnchor')
290                      .trigger('makegrid');
291                     $('#togglequerybox').show();
292                     if ($("#togglequerybox").siblings(":visible").length > 0) {
293                         $("#togglequerybox").trigger('click');
294                     }
295                     PMA_init_slider();
296                 }
297             }
298             PMA_ajaxRemoveMessage($msgbox);
300         }) // end $.post()
301     }) // end SQL Query submit
303     /**
304      * Ajax Event handlers for Paginating the results table
305      */
307     /**
308      * Paginate when we click any of the navigation buttons
309      * (only if the element has the ajax class, see $cfg['AjaxEnable'])
310      * @memberOf    jQuery
311      * @name        paginate_nav_button_click
312      * @uses        PMA_ajaxShowMessage()
313      * @see         $cfg['AjaxEnable']
314      */
315     $("input[name=navig].ajax").live('click', function(event) {
316         /** @lends jQuery */
317         event.preventDefault();
319         var $msgbox = PMA_ajaxShowMessage();
321         /**
322          * @var $form    Object referring to the form element that paginates the results table
323          */
324         var $form = $(this).parent("form");
326         PMA_prepareForAjaxRequest($form);
328         $.post($form.attr('action'), $form.serialize(), function(data) {
329             $("#sqlqueryresults")
330              .html(data)
331              .trigger('appendAnchor')
332              .trigger('makegrid');
333             PMA_init_slider();
335             PMA_ajaxRemoveMessage($msgbox);
336         }) // end $.post()
337     })// end Paginate results table
339     /**
340      * Paginate results with Page Selector dropdown
341      * @memberOf    jQuery
342      * @name        paginate_dropdown_change
343      * @see         $cfg['AjaxEnable']
344      */
345     $("#pageselector").live('change', function(event) {
346         var $form = $(this).parent("form");
348         if ($(this).hasClass('ajax')) {
349             event.preventDefault();
351             var $msgbox = PMA_ajaxShowMessage();
353             $.post($form.attr('action'), $form.serialize() + '&ajax_request=true', function(data) {
354                 $("#sqlqueryresults")
355                  .html(data)
356                  .trigger('appendAnchor')
357                  .trigger('makegrid');
358                 PMA_init_slider();
359                 PMA_ajaxRemoveMessage($msgbox);
360             }) // end $.post()
361         } else {
362             $form.submit();
363         }
365     })// end Paginate results with Page Selector
367     /**
368      * Ajax Event handler for sorting the results table
369      * @memberOf    jQuery
370      * @name        table_results_sort_click
371      * @see         $cfg['AjaxEnable']
372      */
373     $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
374         event.preventDefault();
376         var $msgbox = PMA_ajaxShowMessage();
378         $anchor = $(this);
380         $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
381             $("#sqlqueryresults")
382              .html(data)
383              .trigger('appendAnchor')
384              .trigger('makegrid');
385             PMA_ajaxRemoveMessage($msgbox);
386         }) // end $.get()
387     })//end Sort results table
389     /**
390      * Ajax Event handler for the display options
391      * @memberOf    jQuery
392      * @name        displayOptionsForm_submit
393      * @see         $cfg['AjaxEnable']
394      */
395     $("#displayOptionsForm.ajax").live('submit', function(event) {
396         event.preventDefault();
398         $form = $(this);
400         $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
401             $("#sqlqueryresults")
402              .html(data)
403              .trigger('appendAnchor')
404              .trigger('makegrid');
405             PMA_init_slider();
406         }) // end $.post()
407     })
408     //end displayOptionsForm handler
410     /**
411      * Ajax Event handlers for Inline Editing
412      */
414     /**
415      * On click, replace the fields of current row with an input/textarea
416      * @memberOf    jQuery
417      * @name        inline_edit_start
418      * @see         PMA_ajaxShowMessage()
419      * @see         getFieldName()
420      */
421     $(".inline_edit_anchor span a").live('click', function(event) {
422         /** @lends jQuery */
423         event.preventDefault();
425         var $edit_td = $(this).parents('td');
426         $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');
428         // Adding submit and hide buttons to inline edit <td>.
429         // For "hide" button the original data to be restored is
430         //  kept in the jQuery data element 'original_data' inside the <td>.
431         // Looping through all columns or rows, to find the required data and then storing it in an array.
433         var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
434         // Keep the original data preserved.
435         $data_a = $edit_td.children('span.nowrap').children('a').clone();
437         // Change the inline edit to save.
438         var $img_object = $this_children.find('img');
440         // If texts are displayed. See $cfg['PropertiesIconic']
441         if ($this_children.parent('a').find('span:contains("' + PMA_messages['strInlineEdit'] + '")').length > 0) {
442             $this_children.text(' ' + PMA_messages['strSave']);
443         } else {
444             $this_children.empty();
445         }
447         // If icons are displayed. See $cfg['PropertiesIconic']
448         if ($img_object.length > 0) {
449             $img_object.attr('title', PMA_messages['strSave']);
450             $img_object.removeClass('ic_b_inline_edit');
451             $img_object.addClass('ic_b_save');
452             $this_children.prepend($img_object);
453         }
455         // Clone the save link and change it to create the hide link.
456         var $hide_a = $edit_td.children('span.nowrap').children('a').clone().attr('id', 'hide');
457         var $hide_span = $hide_a.find('span');
458         var $img_object = $hide_a.find('span img');
460         // If texts are displayed. See $cfg['PropertiesIconic']
461         if ($hide_a.find('span:contains("' + PMA_messages['strSave'] + '")').length > 0) {
462             $hide_span.text(' ' + PMA_messages['strHide']);
463         } else {
464             $hide_span.empty();
465         }
467         // If icons are displayed. See $cfg['PropertiesIconic']
468         if ($img_object.length > 0) {
469             $img_object.attr('title', PMA_messages['strHide']);
470             $img_object.removeClass('ic_b_save');
471             $img_object.addClass('ic_b_close');
472             $hide_span.prepend($img_object);
473         }
475         // Add hide icon and/or text.
476         $edit_td.children('span.nowrap').append($('<br /><br />')).append($hide_a);
478         $('#table_results tbody tr td span a#hide').click(function() {
479             var $this_hide = $(this).parents('td');
481             var $this_span = $this_hide.find('span');
482             $this_span.find('a, br').remove();
483             $this_span.append($data_a.clone());
485             $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
486             $this_hide.parent().removeClass("hover noclick");
487             $this_hide.siblings().removeClass("hover");
489             var $input_siblings = $this_hide.parent('tr').find('.inline_edit');
490             var txt = '';
491             $input_siblings.each(function() {
492                 var $this_hide_siblings = $(this);
493                 txt = $this_hide_siblings.data('original_data');
494                 if($this_hide_siblings.children('span').children().length != 0) {
495                     $this_hide_siblings.children('span').empty();
496                     $this_hide_siblings.children('span').append(txt);
497                 }
498             });
499             $(this).prev().prev().remove();
500             $(this).prev().remove();
501             $(this).remove();
503             // refresh the grid
504             $("#sqlqueryresults").trigger('refreshgrid');
505         });
507         // Initialize some variables
508         var this_row_index = $edit_td.parent().index();
509         var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
510         var where_clause = $edit_td.parent('tr').find('.where_clause').val();
512         $input_siblings.each(function() {
513             /** @lends jQuery */
514             /**
515              * @var data_value  Current value of this field
516              */
517             var data_value = $(this).children('span').html();
519             // We need to retrieve the value from the server for truncated/relation fields
520             // Find the field name
522             /**
523              * @var this_field  Object referring to this field (<td>)
524              */
525             var $this_field = $(this);
526             /**
527              * @var this_field_span Object referring to this field's child (<span>)
528              */
529             var $this_field_span = $(this).children('span');
530             /**
531              * @var field_name  String containing the name of this field.
532              * @see getFieldName()
533              */
534             var field_name = getFieldName($this_field);
535             /**
536              * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
537              */
538             var relation_curr_value = $this_field.find('a').text();
539             /**
540              * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
541              * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
542              */
543             var relation_key_or_display_column = $this_field.find('a').attr('title');
544             /**
545              * @var curr_value String current value of the field (for fields that are of type enum or set).
546              */
547             var curr_value = $this_field_span.text();
549             if($this_field.is(':not(.not_null)')){
550                 // add a checkbox to mark null for all the field that are nullable.
551                 $this_field_span.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
552                 // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
553                 if($this_field.is('.null')) {
554                     $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
555                 }
557                 // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
558                 if ($this_field.is('.enum, .set')) {
559                     $this_field.find('select').live('change', function(e) {
560                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
561                     })
562                 } else if ($this_field.is('.relation')) {
563                     $this_field.find('select').live('change', function(e) {
564                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
565                     })
566                     $this_field.find('.browse_foreign').live('click', function(e) {
567                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
568                     })
569                 } else {
570                     $this_field.find('textarea').live('keypress', function(e) {
571                         // FF errorneously triggers for modifier keys such as tab (bug #3357837)
572                         if (e.which != 0) {
573                             $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
574                         }
575                     })
576                 }
578                 // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
579                 $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
580                     if ($this_field.is('.enum')) {
581                         $this_field.find('select').attr('value', '');
582                     } else if ($this_field.is('.set')) {
583                         $this_field.find('select').find('option').each(function() {
584                             var $option = $(this);
585                             $option.attr('selected', false);
586                         })
587                     } else if ($this_field.is('.relation')) {
588                         // if the dropdown is there to select the foreign value
589                         if ($this_field.find('select').length > 0) {
590                             $this_field.find('select').attr('value', '');
591                         // if foriegn value is selected by browsing foreing values
592                         } else {
593                             $this_field.find('span.curr_value').empty();
594                         }
595                     } else {
596                         $this_field.find('textarea').val('');
597                     }
598                 })
600             } else {
601                 $this_field_span.html('<div class="null_div"></div>');
602             }
604             // In each input sibling, wrap the current value in a textarea
605             // and store the current value in a hidden span
606             if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
607                 // handle non-truncated, non-transformed, non-relation values
609                 value = data_value.replace("<br>", "\n");
610                 // We don't need to get any more data, just wrap the value
611                 $this_field_span.append('<textarea>' + value + '</textarea>');
612                 $this_field.data('original_data', data_value);
613             }
614             else if($this_field.is('.truncated, .transformed')) {
615                 /** @lends jQuery */
616                 //handle truncated/transformed values values
618                 /**
619                  * @var sql_query   String containing the SQL query used to retrieve value of truncated/transformed data
620                  */
621                 var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);
623                 // Make the Ajax call and get the data, wrap it and insert it
624                 $.post('sql.php', {
625                     'token' : window.parent.token,
626                     'db' : window.parent.db,
627                     'ajax_request' : true,
628                     'sql_query' : sql_query,
629                     'inline_edit' : true
630                 }, function(data) {
631                     if(data.success == true) {
632                         $this_field_span.append('<textarea>'+data.value+'</textarea>');
633                         $this_field.data('original_data', data_value);
634                         $("#sqlqueryresults").trigger('refreshgrid');
635                     }
636                     else {
637                         PMA_ajaxShowMessage(data.error);
638                     }
639                 }) // end $.post()
640             }
641             else if($this_field.is('.relation')) {
642                 /** @lends jQuery */
643                 //handle relations
645                 /**
646                  * @var post_params Object containing parameters for the POST request
647                  */
648                 var post_params = {
649                         'ajax_request' : true,
650                         'get_relational_values' : true,
651                         'db' : window.parent.db,
652                         'table' : window.parent.table,
653                         'column' : field_name,
654                         'token' : window.parent.token,
655                         'curr_value' : relation_curr_value,
656                         'relation_key_or_display_column' : relation_key_or_display_column
657                 }
659                 $.post('sql.php', post_params, function(data) {
660                     $this_field_span.append(data.dropdown);
661                     $this_field.data('original_data', data_value);
662                     $("#sqlqueryresults").trigger('refreshgrid');
663                 }) // end $.post()
664             }
665             else if($this_field.is('.enum')) {
666                 /** @lends jQuery */
667                 //handle enum fields
669                 /**
670                  * @var post_params Object containing parameters for the POST request
671                  */
672                 var post_params = {
673                         'ajax_request' : true,
674                         'get_enum_values' : true,
675                         'db' : window.parent.db,
676                         'table' : window.parent.table,
677                         'column' : field_name,
678                         'token' : window.parent.token,
679                         'curr_value' : curr_value
680                 }
681                 $.post('sql.php', post_params, function(data) {
682                     $this_field_span.append(data.dropdown);
683                     $this_field.data('original_data', data_value);
684                     $("#sqlqueryresults").trigger('refreshgrid');
685                 }) // end $.post()
686             }
687             else if($this_field.is('.set')) {
688                 /** @lends jQuery */
689                 //handle set fields
691                 /**
692                  * @var post_params Object containing parameters for the POST request
693                  */
694                 var post_params = {
695                         'ajax_request' : true,
696                         'get_set_values' : true,
697                         'db' : window.parent.db,
698                         'table' : window.parent.table,
699                         'column' : field_name,
700                         'token' : window.parent.token,
701                         'curr_value' : curr_value
702                 }
704                 $.post('sql.php', post_params, function(data) {
705                     $this_field_span.append(data.select);
706                     $this_field.data('original_data', data_value);
707                     $("#sqlqueryresults").trigger('refreshgrid');
708                 }) // end $.post()
709             }
710             else if($this_field.is('.null')) {
711                 //handle null fields
712                 $this_field_span.append('<textarea></textarea>');
713                 $this_field.data('original_data', 'NULL');
714             }
715         });
717         // refresh the grid
718         $("#sqlqueryresults").trigger('refreshgrid');
720     }) // End On click, replace the current field with an input/textarea
722     /**
723      * After editing, clicking again should post data
724      *
725      * @memberOf    jQuery
726      * @name        inline_edit_save
727      * @see         PMA_ajaxShowMessage()
728      * @see         getFieldName()
729      */
730     $(".inline_edit_active span a").live('click', function(event) {
731         /** @lends jQuery */
733         event.preventDefault();
735         /**
736          * @var $this_td    Object referring to the td containing the
737          * "Inline Edit" link that was clicked to save the row that is
738          * being edited
739          *
740          */
741         var $this_td = $(this).parents('td');
742         var $test_element = ''; // to test the presence of a element
744         // Initialize variables
745         var $input_siblings = $this_td.parent('tr').find('.inline_edit');
746         var where_clause = $this_td.parent('tr').find('.where_clause').val();
748         /**
749          * @var nonunique   Boolean, whether this row is unique or not
750          */
751         if($this_td.is('.nonunique')) {
752             var nonunique = 0;
753         }
754         else {
755             var nonunique = 1;
756         }
758         // Collect values of all fields to submit, we don't know which changed
759         /**
760          * @var relation_fields Array containing the name/value pairs of relational fields
761          */
762         var relation_fields = {};
763         /**
764          * @var relational_display string 'K' if relational key, 'D' if relational display column
765          */
766         var relational_display = $("#relational_display_K").attr('checked') ? 'K' : 'D';
767         /**
768          * @var transform_fields    Array containing the name/value pairs for transformed fields
769          */
770         var transform_fields = {};
771         /**
772          * @var transformation_fields   Boolean, if there are any transformed fields in this row
773          */
774         var transformation_fields = false;
776         /**
777          * @var sql_query String containing the SQL query to update this row
778          */
779         var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
781         var need_to_post = false;
783         var new_clause = '';
784         var prev_index = -1;
786         $input_siblings.each(function() {
787             /** @lends jQuery */
788             /**
789              * @var this_field  Object referring to this field (<td>)
790              */
791             var $this_field = $(this);
793             /**
794              * @var field_name  String containing the name of this field.
795              * @see getFieldName()
796              */
797             var field_name = getFieldName($this_field);
799             /**
800              * @var this_field_params   Array temporary storage for the name/value of current field
801              */
802             var this_field_params = {};
804             if($this_field.is('.transformed')) {
805                 transformation_fields =  true;
806             }
807             /**
808              * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
809              */
810             var is_null = $this_field.find('input:checkbox').is(':checked');
811             var value;
812             var addQuotes = true;
814             if (is_null) {
815                 sql_query += ' `' + field_name + "`=NULL , ";
816                 need_to_post = true;
817             } else {
818                 if($this_field.is(":not(.relation, .enum, .set, .bit)")) {
819                     this_field_params[field_name] = $this_field.find('textarea').val();
820                     if($this_field.is('.transformed')) {
821                         $.extend(transform_fields, this_field_params);
822                     }
823                 } else if ($this_field.is('.bit')) {
824                     this_field_params[field_name] = '0b' + $this_field.find('textarea').val();
825                     addQuotes = false;
826                 } else if ($this_field.is('.set')) {
827                     $test_element = $this_field.find('select');
828                     this_field_params[field_name] = $test_element.map(function(){
829                         return $(this).val();
830                     }).get().join(",");
831                 } else {
832                     // results from a drop-down
833                     $test_element = $this_field.find('select');
834                     if ($test_element.length != 0) {
835                         this_field_params[field_name] = $test_element.val();
836                     }
838                     // results from Browse foreign value
839                     $test_element = $this_field.find('span.curr_value');
840                     if ($test_element.length != 0) {
841                         this_field_params[field_name] = $test_element.text();
842                     }
844                     if($this_field.is('.relation')) {
845                         $.extend(relation_fields, this_field_params);
846                     }
847                 }
848                     if(where_clause.indexOf(field_name) > prev_index){
849                         new_clause += '`' + window.parent.table + '`.' + '`' + field_name + "` = '" + this_field_params[field_name].replace(/'/g,"''") + "'" + ' AND ';
850                     }
851                 if (this_field_params[field_name] != $this_field.data('original_data')) {
852                     if (addQuotes == true) {
853                         sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "', ";
854                     } else {
855                         sql_query += ' `' + field_name + "`=" + this_field_params[field_name].replace(/'/g, "''") + ", ";
856                     }
857                     need_to_post = true;
858                 }
859             }
860         })
862         /*
863          * update the where_clause, remove the last appended ' AND '
864          * */
866         //Remove the last ',' appended in the above loop
867         sql_query = sql_query.replace(/,\s$/, '');
868         //Fix non-escaped backslashes
869         sql_query = sql_query.replace(/\\/g, '\\\\');
870         new_clause = new_clause.substring(0, new_clause.length-5);
871         new_clause = PMA_urlencode(new_clause);
872         sql_query += ' WHERE ' + PMA_urldecode(where_clause);
873         // Avoid updating more than one row in case there is no primary key
874         // (happened only for duplicate rows)
875         sql_query += ' LIMIT 1';
876         /**
877          * @var rel_fields_list  String, url encoded representation of {@link relations_fields}
878          */
879         var rel_fields_list = $.param(relation_fields);
881         /**
882          * @var transform_fields_list  String, url encoded representation of {@link transform_fields}
883          */
884         var transform_fields_list = $.param(transform_fields);
886         // if inline_edit is successful, we need to go back to default view
887         var $del_hide = $(this).parent();
888         var $chg_submit = $(this);
890         if (need_to_post) {
891             // Make the Ajax post after setting all parameters
892             /**
893              * @var post_params Object containing parameters for the POST request
894              */
895             var post_params = {'ajax_request' : true,
896                             'sql_query' : sql_query,
897                             'token' : window.parent.token,
898                             'db' : window.parent.db,
899                             'table' : window.parent.table,
900                             'clause_is_unique' : nonunique,
901                             'where_clause' : where_clause,
902                             'rel_fields_list' : rel_fields_list,
903                             'do_transformations' : transformation_fields,
904                             'transform_fields_list' : transform_fields_list,
905                             'relational_display' : relational_display,
906                             'goto' : 'sql.php',
907                             'submit_type' : 'save'
908                           };
910             $.post('tbl_replace.php', post_params, function(data) {
911                 if(data.success == true) {
912                     PMA_ajaxShowMessage(data.message);
913                     $this_td.parent('tr').find('.where_clause').attr('value', new_clause);
914                     // remove possible previous feedback message
915                     $('#result_query').remove();
916                     if (typeof data.sql_query != 'undefined') {
917                         // display feedback
918                         $('#sqlqueryresults').prepend(data.sql_query);
919                     }
920                     PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data);
921                 } else {
922                     PMA_ajaxShowMessage(data.error);
923                 };
924             }) // end $.post()
925         } else {
926             // no posting was done but still need to display the row
927             // in its previous format
928             PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '');
929         }
930     }) // End After editing, clicking again should post data
933  * Ajax Event for table row change
934  * */
935     $("#resultsForm.ajax .mult_submit[value=edit]").live('click', function(event){
936         event.preventDefault();
938         /*Check whether atleast one row is selected for change*/
939         if ($("#table_results tbody tr, #table_results tbody tr td").hasClass("marked")) {
940             var div = $('<div id="change_row_dialog"></div>');
942             /**
943              *  @var    button_options  Object that stores the options passed to jQueryUI
944              *                          dialog
945              */
946             var button_options = {};
947             // in the following function we need to use $(this)
948             button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
950             var button_options_error = {};
951             button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
952             var $form = $("#resultsForm");
953             var $msgbox = PMA_ajaxShowMessage();
955             $.get( $form.attr('action'), $form.serialize()+"&ajax_request=true&submit_mult=row_edit", function(data) {
956                 //in the case of an error, show the error message returned.
957                 if (data.success != undefined && data.success == false) {
958                     div
959                     .append(data.error)
960                     .dialog({
961                         title: PMA_messages['strChangeTbl'],
962                         height: 230,
963                         width: 900,
964                         open: PMA_verifyTypeOfAllColumns,
965                         buttons : button_options_error
966                     })// end dialog options
967                 } else {
968                     div
969                     .append(data)
970                     .dialog({
971                         title: PMA_messages['strChangeTbl'],
972                         height: 600,
973                         width: 900,
974                         open: PMA_verifyTypeOfAllColumns,
975                         buttons : button_options
976                     })
977                     //Remove the top menu container from the dialog
978                     .find("#topmenucontainer").hide()
979                     ; // end dialog options
980                     $(".insertRowTable").addClass("ajax");
981                     $("#buttonYes").addClass("ajax");
982                 }
983                 PMA_ajaxRemoveMessage($msgbox);
984             }) // end $.get()
985         } else {
986             PMA_ajaxShowMessage(PMA_messages['strNoRowSelected']);
987         }
988     });
991  * Click action for "Go" button in ajax dialog insertForm -> insertRowTable
992  */
993     $("#insertForm .insertRowTable.ajax input[value=Go]").live('click', function(event) {
994         event.preventDefault();
995         /**
996          *  @var    the_form    object referring to the insert form
997          */
998         var $form = $("#insertForm");
999         PMA_prepareForAjaxRequest($form);
1000         //User wants to submit the form
1001         $.post($form.attr('action'), $form.serialize(), function(data) {
1002             if (data.success == true) {
1003                 PMA_ajaxShowMessage(data.message);
1004                 if ($("#pageselector").length != 0) {
1005                     $("#pageselector").trigger('change');
1006                 } else {
1007                     $("input[name=navig].ajax").trigger('click');
1008                 }
1010             } else {
1011                 PMA_ajaxShowMessage(data.error);
1012                 $("#table_results tbody tr.marked .multi_checkbox " +
1013                         ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1014                 $("#table_results tbody tr.marked .multi_checkbox " +
1015                         ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1016                 $("#table_results tbody tr" +
1017                         ", #table_results tbody tr td").removeClass("marked");
1018             }
1019             if ($("#change_row_dialog").length > 0) {
1020                 $("#change_row_dialog").dialog("close").remove();
1021             }
1022             /**Update the row count at the tableForm*/
1023             $("#result_query").remove();
1024             $("#sqlqueryresults").prepend(data.sql_query);
1025             $("#result_query .notice").remove();
1026             $("#result_query").prepend((data.message));
1027         }) // end $.post()
1028     }) // end insert table button "Go"
1030 /**$("#buttonYes.ajax").live('click'
1031  * Click action for #buttonYes button in ajax dialog insertForm
1032  */
1033     $("#buttonYes.ajax").live('click', function(event){
1034         event.preventDefault();
1035         /**
1036          *  @var    the_form    object referring to the insert form
1037          */
1038         var $form = $("#insertForm");
1039         /**Get the submit type and the after insert type in the form*/
1040         var selected_submit_type = $("#insertForm").find("#actions_panel .control_at_footer option:selected").attr('value');
1041         var selected_after_insert = $("#insertForm").find("#actions_panel select[name=after_insert] option:selected").attr('value');
1042         $("#result_query").remove();
1043         PMA_prepareForAjaxRequest($form);
1044         //User wants to submit the form
1045         $.post($form.attr('action'), $form.serialize() , function(data) {
1046             if (data.success == true) {
1047                 PMA_ajaxShowMessage(data.message);
1048                 if (selected_submit_type == "showinsert") {
1049                     $("#sqlqueryresults").prepend(data.sql_query);
1050                     $("#result_query .notice").remove();
1051                     $("#result_query").prepend(data.message);
1052                     $("#table_results tbody tr.marked .multi_checkbox " +
1053                         ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1054                     $("#table_results tbody tr.marked .multi_checkbox " +
1055                         ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1056                     $("#table_results tbody tr" +
1057                         ", #table_results tbody tr td").removeClass("marked");
1058                 } else {
1059                     if ($("#pageselector").length != 0) {
1060                         $("#pageselector").trigger('change');
1061                     } else {
1062                         $("input[name=navig].ajax").trigger('click');
1063                     }
1064                     $("#result_query").remove();
1065                     $("#sqlqueryresults").prepend(data.sql_query);
1066                     $("#result_query .notice").remove();
1067                     $("#result_query").prepend((data.message));
1068                 }
1069             } else {
1070                 PMA_ajaxShowMessage(data.error);
1071                 $("#table_results tbody tr.marked .multi_checkbox " +
1072                     ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1073                 $("#table_results tbody tr.marked .multi_checkbox " +
1074                     ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1075                 $("#table_results tbody tr" +
1076                     ", #table_results tbody tr td").removeClass("marked");
1077             }
1078             if ($("#change_row_dialog").length > 0) {
1079                 $("#change_row_dialog").dialog("close").remove();
1080             }
1081         }) // end $.post()
1082     });
1084 }, 'top.frame_content') // end $(document).ready()
1088  * Visually put back the row in the state it was before entering Inline edit
1090  * (when called in the situation where no posting was done, the data
1091  * parameter is empty)
1092  */
1093 function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data) {
1095     // deleting the hide button. remove <br><br><a> tags
1096     $del_hide.find('a, br').remove();
1097     // append inline edit button.
1098     $del_hide.append($data_a.clone());
1100     // changing inline_edit_active to inline_edit_anchor
1101     $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
1103     // removing hover, marked and noclick classes
1104     $this_td.parent('tr').removeClass('noclick');
1105     $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
1107     $input_siblings.each(function() {
1108         // Inline edit post has been successful.
1109         $this_sibling = $(this);
1110         $this_sibling_span = $(this).children('span');
1112         var is_null = $this_sibling.find('input:checkbox').is(':checked');
1113         if (is_null) {
1114             $this_sibling_span.html('NULL');
1115             $this_sibling.addClass('null');
1116         } else {
1117             $this_sibling.removeClass('null');
1118             if($this_sibling.is(':not(.relation, .enum, .set)')) {
1119                 /**
1120                  * @var new_html    String containing value of the data field after edit
1121                  */
1122                 var new_html = $this_sibling.find('textarea').val();
1124                 if($this_sibling.is('.transformed')) {
1125                     var field_name = getFieldName($this_sibling);
1126                     if (typeof data.transformations != 'undefined') {
1127                         $.each(data.transformations, function(key, value) {
1128                             if(key == field_name) {
1129                                 if($this_sibling.is('.text_plain, .application_octetstream')) {
1130                                     new_html = value;
1131                                     return false;
1132                                 } else {
1133                                     var new_value = $this_sibling.find('textarea').val();
1134                                     new_html = $(value).append(new_value);
1135                                     return false;
1136                                 }
1137                             }
1138                         })
1139                     }
1140                 }
1141             } else {
1142                 var new_html = '';
1143                 var new_value = '';
1144                 $test_element = $this_sibling.find('select');
1145                 if ($test_element.length != 0) {
1146                     new_value = $test_element.val();
1147                 }
1148                 $test_element = $this_sibling.find('span.curr_value');
1149                 if ($test_element.length != 0) {
1150                     new_value = $test_element.text();
1151                 }
1153                 if($this_sibling.is('.relation')) {
1154                     var field_name = getFieldName($this_sibling);
1155                     if (typeof data.relations != 'undefined') {
1156                         $.each(data.relations, function(key, value) {
1157                             if(key == field_name) {
1158                                 new_html = $(value);
1159                                 return false;
1160                             }
1161                         })
1162                     }
1163                 } else if ($this_sibling.is('.enum')) {
1164                     new_html = new_value;
1165                 } else if ($this_sibling.is('.set')) {
1166                     if (new_value != null) {
1167                         $.each(new_value, function(key, value) {
1168                             new_html = new_html + value + ',';
1169                         })
1170                         new_html = new_html.substring(0, new_html.length-1);
1171                     }
1172                 }
1173             }
1174             $this_sibling_span.html(new_html);
1175         }
1176     })
1178     // refresh the grid
1179     $("#sqlqueryresults").trigger('refreshgrid');
1183  * Starting from some th, change the class of all td under it.
1184  * If isAddClass is specified, it will be used to determine whether to add or remove the class.
1185  */
1186 function PMA_changeClassForColumn($this_th, newclass, isAddClass) {
1187     // index 0 is the th containing the big T
1188     var th_index = $this_th.index();
1189     var has_big_t = !$this_th.closest('tr').children(':first').hasClass('column_heading');
1190     // .eq() is zero-based
1191     if (has_big_t) {
1192         th_index--;
1193     }
1194     var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
1195     if (isAddClass == undefined) {
1196         $tds.toggleClass(newclass);
1197     } else {
1198         $tds.toggleClass(newclass, isAddClass);
1199     }
1202 $(document).ready(function() {
1204     $('.browse_foreign').live('click', function(e) {
1205         e.preventDefault();
1206         window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
1207         $anchor = $(this);
1208         $anchor.addClass('browse_foreign_clicked');
1209         return false;
1210     });
1212     /**
1213      * vertical column highlighting in horizontal mode when hovering over the column header
1214      */
1215     $('.column_heading.pointer').live('hover', function(e) {
1216         PMA_changeClassForColumn($(this), 'hover', e.type == 'mouseenter');
1217         });
1219     /**
1220      * vertical column marking in horizontal mode when clicking the column header
1221      */
1222     $('.column_heading.marker').live('click', function() {
1223         PMA_changeClassForColumn($(this), 'marked');
1224         });
1226     /**
1227      * create resizable table
1228      */
1229     $("#sqlqueryresults").trigger('makegrid');
1233  * Profiling Chart
1234  */
1235 function makeProfilingChart() {
1236     if ($('#profilingchart').length == 0) {
1237         return;
1238     }
1240     var data = new Array();
1241     $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) {
1242         data.push([key,parseFloat(value)]);
1243     });
1245     // Prevent the user from seeing the JSON code
1246     $('div#profilingchart').html('').show();
1248     PMA_createProfilingChart(data);
1252 /**#@- */