Translation update done using Pootle.
[phpmyadmin/mlewandow.git] / js / sql.js
blob078f3a2807e2062b5da7f770c54bfce498631d8e
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 /**
11  * decode a string URL_encoded
12  *
13  * @param string str
14  * @return string the URL-decoded string
15  */
16 var data_vt;
17 function PMA_urldecode(str) {
18     return decodeURIComponent(str.replace(/\+/g, '%20'));
21 /**
22  * Get the field name for the current field.  Required to construct the query
23  * for inline editing
24  *
25  * @param   $this_field  jQuery object that points to the current field's tr
26  * @param   disp_mode    string
27  */
28 function getFieldName($this_field, disp_mode) {
30     if(disp_mode == 'vertical') {
31         var field_name = $this_field.siblings('th').find('a').text();
32         // happens when just one row (headings contain no a)
33         if ("" == field_name) {
34             field_name = $this_field.siblings('th').text();
35         }
36     }
37     else {
38         var this_field_index = $this_field.index();
39         // ltr or rtl direction does not impact how the DOM was generated
40         //
41         // 5 columns to account for the checkbox, edit, appended inline edit, copy and delete anchors but index is zero-based so substract 4
42         var field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+') a').text();
43         // happens when just one row (headings contain no a)
44         if ("" == field_name) {
45             field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+')').text();
46         }
47     }
49     field_name = $.trim(field_name);
51     return field_name;
54 /**
55  * The function that iterates over each row in the table_results and appends a
56  * new inline edit anchor to each table row.
57  *
58  */
59 function appendInlineAnchor() {
60     var disp_mode = $("#top_direction_dropdown").val();
62     if (disp_mode == 'vertical') {
63         // there can be one or two tr containing this class, depending
64         // on the ModifyDeleteAtLeft and ModifyDeleteAtRight cfg parameters
65         $('#table_results tr')
66             .find('.edit_row_anchor')
67             .removeClass('edit_row_anchor')
68             .parent().each(function() {
69             var $this_tr = $(this);
70             var $cloned_tr = $this_tr.clone();
72             var $img_object = $cloned_tr.find('img:first').attr('title', PMA_messages['strInlineEdit']);
73             if ($img_object.length != 0) {
74                 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
75                 $img_object.attr('src', img_src);
76             }
78             $cloned_tr.find('td')
79              .addClass('inline_edit_anchor')
80              .find('a').attr('href', '#')
81              .find('span')
82              .text(' ' + PMA_messages['strInlineEdit'])
83              .prepend($img_object);
85             $cloned_tr.insertAfter($this_tr);
86         });
88         $('#rowsDeleteForm').find('tbody').find('th').each(function() {
89             var $this_th = $(this);
90             if ($this_th.attr('rowspan') == 4) {
91                 $this_th.attr('rowspan', '5');
92             }
93         });
94     }
95     else {
96         // horizontal mode
97         $('.edit_row_anchor').each(function() {
99             var $this_td = $(this);
100             $this_td.removeClass('edit_row_anchor');
102             var $cloned_anchor = $this_td.clone();
104             var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
105             if ($img_object.length != 0) {
106                 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
107                 $img_object.attr('src', img_src);
108                 $cloned_anchor
109                  .find('a').attr('href', '#')
110                  .find('span')
111                  .text(' ' + PMA_messages['strInlineEdit']);
112                 $cloned_anchor
113                  .find('span')
114                  .first()
115                  .prepend($img_object);
116             } else {
117                 // the link was too big so <input type="image"> is there
118                 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
119                 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
120                 $img_object.attr('src', img_src);
121                 $cloned_anchor
122                  .find('.clickprevimage')
123                  .text(' ' + PMA_messages['strInlineEdit']);
124             }
126             $cloned_anchor
127              .addClass('inline_edit_anchor');
129             $this_td.after($cloned_anchor);
130         });
132         $('#rowsDeleteForm').find('thead, tbody').find('th').each(function() {
133             var $this_th = $(this);
134             if ($this_th.attr('colspan') == 4) {
135                 $this_th.attr('colspan', '5');
136             }
137         });
138     }
141 /**#@+
142  * @namespace   jQuery
143  */
146  * @description <p>Ajax scripts for sql and browse pages</p>
148  * Actions ajaxified here:
149  * <ul>
150  * <li>Retrieve results of an SQL query</li>
151  * <li>Paginate the results table</li>
152  * <li>Sort the results table</li>
153  * <li>Change table according to display options</li>
154  * <li>Inline editing of data</li>
155  * </ul>
157  * @name        document.ready
158  * @memberOf    jQuery
159  */
160 $(document).ready(function() {
162     /**
163      * Set a parameter for all Ajax queries made on this page.  Don't let the
164      * web server serve cached pages
165      */
166     $.ajaxSetup({
167         cache: 'false'
168     });
170     /**
171      * current value of the direction in which the table is displayed
172      * @type    String
173      * @fieldOf jQuery
174      * @name    disp_mode
175      */
176     var disp_mode = $("#top_direction_dropdown").val();
178     /**
179      * Update value of {@link jQuery.disp_mode} everytime the direction dropdown changes value
180      * @memberOf    jQuery
181      * @name        direction_dropdown_change
182      */
183     $("#top_direction_dropdown, #bottom_direction_dropdown").live('change', function(event) {
184         disp_mode = $(this).val();
185     })
187     /**
188      * Attach the {@link appendInlineAnchor} function to a custom event, which
189      * will be triggered manually everytime the table of results is reloaded
190      * @memberOf    jQuery
191      */
192     $("#sqlqueryresults").live('appendAnchor',function() {
193         appendInlineAnchor();
194     })
196     /**
197      * Trigger the appendAnchor event to prepare the first table for inline edit
198      * (see $GLOBALS['cfg']['AjaxEnable'])
199      * @memberOf    jQuery
200      * @name        sqlqueryresults_trigger
201      */
202     $("#sqlqueryresults.ajax").trigger('appendAnchor');
204     /**
205      * Append the "Show/Hide query box" message to the query input form
206      *
207      * @memberOf jQuery
208      * @name    appendToggleSpan
209      */
210     // do not add this link more than once
211     if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
212         $('<a id="togglequerybox"></a>')
213         .html(PMA_messages['strHideQueryBox'])
214         .appendTo("#sqlqueryform")
215         // initially hidden because at this point, nothing else
216         // appears under the link
217         .hide();
219         // Attach the toggling of the query box visibility to a click
220         $("#togglequerybox").bind('click', function() {
221             var $link = $(this)
222             $link.siblings().slideToggle("fast");
223             if ($link.text() == PMA_messages['strHideQueryBox']) {
224                 $link.text(PMA_messages['strShowQueryBox']);
225                 // cheap trick to add a spacer between the menu tabs
226                 // and "Show query box"; feel free to improve!
227                 $('#togglequerybox_spacer').remove();
228                 $link.before('<br id="togglequerybox_spacer" />');
229             } else {
230                 $link.text(PMA_messages['strHideQueryBox']);
231             }
232             // avoid default click action
233             return false;
234         })
235     }
237     /**
238      * Ajax Event handler for 'SQL Query Submit'
239      *
240      * @see         PMA_ajaxShowMessage()
241      * @see         $cfg['AjaxEnable']
242      * @memberOf    jQuery
243      * @name        sqlqueryform_submit
244      */
245     $("#sqlqueryform.ajax").live('submit', function(event) {
246         event.preventDefault();
247         // remove any div containing a previous error message
248         $('.error').remove();
250         $form = $(this);
251         var $msgbox = PMA_ajaxShowMessage();
253         if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
254             $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
255         }
257         $.post($(this).attr('action'), $(this).serialize() , function(data) {
258             if(data.success == true) {
259                 // fade out previous messages, if any
260                 $('.success').fadeOut();
261                 $('.sqlquery_message').fadeOut();
262                 // show a message that stays on screen
263                 $('#sqlqueryform').before(data.message);
264                 // and display the query
265                 $('<div class="sqlquery_message"></div>')
266                  .html(data.sql_query)
267                  .insertBefore('#sqlqueryform');
268                 // unnecessary div that came from data.sql_query
269                 $('.notice').remove();
270                 $('#sqlqueryresults').show();
271                 // this happens if a USE command was typed
272                 if (typeof data.reload != 'undefined') {
273                     $form.find('input[name=db]').val(data.db);
274                     // need to regenerate the whole upper part
275                     $form.find('input[name=ajax_request]').remove();
276                     $form.append('<input type="hidden" name="reload" value="true" />');
277                     $.post('db_sql.php', $form.serialize(), function(data) {
278                         $('body').html(data);
279                     }); // end inner post
280                 }
281             }
282             else if (data.success == false ) {
283                 // show an error message that stays on screen
284                 $('#sqlqueryform').before(data.error);
285                 $('#sqlqueryresults').hide();
286             }
287             else {
288                 // real results are returned
289                 $received_data = $(data);
290                 $zero_row_results = $received_data.find('textarea[name="sql_query"]');
291                 // if zero rows are returned from the query execution
292                 if ($zero_row_results.length > 0) {
293                     $('#sqlquery').val($zero_row_results.val());
294                 } else {
295                     $('#sqlqueryresults').show();
296                     $("#sqlqueryresults").html(data);
297                     $("#sqlqueryresults").trigger('appendAnchor');
298                     $('#togglequerybox').show();
299                     if($("#togglequerybox").siblings(":visible").length > 0) {
300                         $("#togglequerybox").trigger('click');
301                     }
302                     PMA_init_slider();
303                 }
304             }
305             PMA_ajaxRemoveMessage($msgbox);
307         }) // end $.post()
308     }) // end SQL Query submit
310     /**
311      * Ajax Event handlers for Paginating the results table
312      */
314     /**
315      * Paginate when we click any of the navigation buttons
316      * (only if the element has the ajax class, see $cfg['AjaxEnable'])
317      * @memberOf    jQuery
318      * @name        paginate_nav_button_click
319      * @uses        PMA_ajaxShowMessage()
320      * @see         $cfg['AjaxEnable']
321      */
322     $("input[name=navig].ajax").live('click', function(event) {
323         /** @lends jQuery */
324         event.preventDefault();
326         var $msgbox = PMA_ajaxShowMessage();
328         /**
329          * @var $the_form    Object referring to the form element that paginates the results table
330          */
331         var $the_form = $(this).parent("form");
333         $the_form.append('<input type="hidden" name="ajax_request" value="true" />');
335         $.post($the_form.attr('action'), $the_form.serialize(), function(data) {
336             $("#sqlqueryresults").html(data);
337             $("#sqlqueryresults").trigger('appendAnchor');
338             PMA_init_slider();
339             
340             PMA_ajaxRemoveMessage($msgbox);
341         }) // end $.post()
342     })// end Paginate results table
344     /**
345      * Paginate results with Page Selector dropdown
346      * @memberOf    jQuery
347      * @name        paginate_dropdown_change
348      * @see         $cfg['AjaxEnable']
349      */
350     $("#pageselector").live('change', function(event) {
351         var $the_form = $(this).parent("form");
353         if ($(this).hasClass('ajax')) {
354             event.preventDefault();
356             var $msgbox = PMA_ajaxShowMessage();
358             $.post($the_form.attr('action'), $the_form.serialize() + '&ajax_request=true', function(data) {
359                 $("#sqlqueryresults").html(data);
360                 $("#sqlqueryresults").trigger('appendAnchor');
361                 PMA_init_slider();
362                 PMA_ajaxRemoveMessage($msgbox); 
363             }) // end $.post()
364         } else {
365             $the_form.submit();
366         }
368     })// end Paginate results with Page Selector
370     /**
371      * Ajax Event handler for sorting the results table
372      * @memberOf    jQuery
373      * @name        table_results_sort_click
374      * @see         $cfg['AjaxEnable']
375      */
376     $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
377         event.preventDefault();
379         var $msgbox = PMA_ajaxShowMessage();
381         $anchor = $(this);
383         $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
384             $("#sqlqueryresults")
385              .html(data)
386              .trigger('appendAnchor');
387             PMA_ajaxRemoveMessage($msgbox);
388         }) // end $.get()
389     })//end Sort results table
391     /**
392      * Ajax Event handler for the display options
393      * @memberOf    jQuery
394      * @name        displayOptionsForm_submit
395      * @see         $cfg['AjaxEnable']
396      */
397     $("#displayOptionsForm.ajax").live('submit', function(event) {
398         event.preventDefault();
400         $form = $(this);
402         $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
403             $("#sqlqueryresults")
404              .html(data)
405              .trigger('appendAnchor');
406             PMA_init_slider();
407         }) // end $.post()
408     })
409     //end displayOptionsForm handler
411     /**
412      * Ajax Event handlers for Inline Editing
413      */
415     /**
416      * On click, replace the fields of current row with an input/textarea
417      * @memberOf    jQuery
418      * @name        inline_edit_start
419      * @see         PMA_ajaxShowMessage()
420      * @see         getFieldName()
421      */
422     $(".inline_edit_anchor span a").live('click', function(event) {
423         /** @lends jQuery */
424         event.preventDefault();
426         var $edit_td = $(this).parents('td');
427         $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');
429         // Adding submit and hide buttons to inline edit <td>.
430         // For "hide" button the original data to be restored is 
431         //  kept in the jQuery data element 'original_data' inside the <td>.
432         // Looping through all columns or rows, to find the required data and then storing it in an array.
434         var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
435         if (disp_mode != 'vertical') {
436             $this_children.empty();
437             $this_children.text(PMA_messages['strSave']);
438         } else {
439             // vertical
440             data_vt = $this_children.html();
441             $this_children.text(PMA_messages['strSave']);
442         }
444         var hide_link = '<br /><br /><a id="hide">' + PMA_messages['strHide'] + '</a>';
445         if (disp_mode != 'vertical') {
446             $edit_td.append(hide_link);
447             $('#table_results tbody tr td a#hide').click(function() {
448                 $this_children = $(this).siblings('span.nowrap').children('a').children('span.nowrap');
449                 $this_children.empty();
450                 $this_children.text(PMA_messages['strInlineEdit']);
452                 var $this_hide = $(this).parent();
453                 $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
454                 $this_hide.parent().removeClass("hover noclick");
455                 $this_hide.siblings().removeClass("hover");
457                 var last_column = $this_hide.siblings().length;
458                 var txt = '';
459                 for(var i = 4; i < last_column; i++) {
460                     if($this_hide.siblings("td:eq(" + i + ")").hasClass("inline_edit") == false) {
461                         continue;
462                     }
463                     txt = $this_hide.siblings("td:eq(" + i + ")").data('original_data');
464                     if($this_hide.siblings("td:eq(" + i + ")").children().length != 0) {
465                         $this_hide.siblings("td:eq(" + i + ")").empty();
466                         $this_hide.siblings("td:eq(" + i + ")").append(txt);
467                     }
468                 }
469                 $(this).prev().prev().remove();
470                 $(this).prev().remove();
471                 $(this).remove();
472             });
473         } else {
474             var txt = '';
475             var rows = $edit_td.parent().siblings().length;
477             $edit_td.append(hide_link);
478             $('#table_results tbody tr td a#hide').click(function() {
479                 var pos = $(this).parent().index();
480                 var $chg_submit = $(this).parent().children('span.nowrap').children('a').children('span.nowrap');
481                 $chg_submit.empty();
482                 $chg_submit.append(data_vt);
484                 var $this_row = $(this).parents('tr');
485                 // changing inline_edit_active to inline_edit_anchor
486                 $this_row.siblings("tr:eq(3) td:eq(" + pos + ")").removeClass("inline_edit_active").addClass("inline_edit_anchor");
488                 // removing marked and hover classes.
489                 $this_row.parent('tbody').find('tr').find("td:eq(" + pos + ")").removeClass("marked hover");
491                 for( var i = 6; i <= rows + 2; i++){
492                     if( $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").hasClass("inline_edit") == false) {
493                         continue;
494                     }
495                     txt = $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").data('original_data');
496                     $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").empty();
497                     $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").append(txt);
498                 }
499                 $(this).prev().remove();
500                 $(this).prev().remove();
501                 $(this).remove();
502             });
503         }
505         // Initialize some variables
506         if(disp_mode == 'vertical') {
507             /**
508              * @var this_row_index  Index of the current <td> in the parent <tr>
509              *                      Current <td> is the inline edit anchor.
510              */
511             var this_row_index = $edit_td.index();
512             /**
513              * @var $input_siblings  Object referring to all inline editable events from same row
514              */
515             var $input_siblings = $edit_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_row_index+')');
516             /**
517              * @var where_clause    String containing the WHERE clause to select this row
518              */
519             var where_clause = $edit_td.parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
520         }
521         // horizontal mode
522         else {
523             var this_row_index = $edit_td.parent().index();
524             var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
525             var where_clause = $edit_td.parent('tr').find('.where_clause').val();
526         }
528         $input_siblings.each(function() {
529             /** @lends jQuery */
530             /**
531              * @var data_value  Current value of this field
532              */
533             var data_value = $(this).html();
535             // We need to retrieve the value from the server for truncated/relation fields
536             // Find the field name
538             /**
539              * @var this_field  Object referring to this field (<td>)
540              */
541             var $this_field = $(this);
542             /**
543              * @var field_name  String containing the name of this field.
544              * @see getFieldName()
545              */
546             var field_name = getFieldName($this_field, disp_mode);
547             /**
548              * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
549              */
550             var relation_curr_value = $this_field.find('a').text();
551             /**
552              * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
553              * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
554              */
555             var relation_key_or_display_column = $this_field.find('a').attr('title');
556             /**
557              * @var curr_value String current value of the field (for fields that are of type enum or set).
558              */
559             var curr_value = $this_field.text();
561             if($this_field.is(':not(.not_null)')){
562                 // add a checkbox to mark null for all the field that are nullable.
563                 $this_field.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
564                 // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
565                 if($this_field.is('.null')) {
566                     $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
567                 }
569                 // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
570                 if ($this_field.is('.enum, .set')) {
571                     $this_field.find('select').live('change', function(e) {
572                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
573                     })
574                 } else if ($this_field.is('.relation')) {
575                     $this_field.find('select').live('change', function(e) {
576                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
577                     })
578                     $this_field.find('.browse_foreign').live('click', function(e) {
579                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
580                     })
581                 } else {
582                     $this_field.find('textarea').live('keypress', function(e) {
583                         $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
584                     })
585                 }
587                 // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
588                 $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
589                     if ($this_field.is('.enum')) {
590                         $this_field.find('select').attr('value', '');
591                     } else if ($this_field.is('.set')) {
592                         $this_field.find('select').find('option').each(function() {
593                             var $option = $(this);
594                             $option.attr('selected', false);
595                         })
596                     } else if ($this_field.is('.relation')) {
597                         // if the dropdown is there to select the foreign value
598                         if ($this_field.find('select').length > 0) {
599                             $this_field.find('select').attr('value', '');
600                         // if foriegn value is selected by browsing foreing values
601                         } else {
602                             $this_field.find('span.curr_value').empty();
603                         }
604                     } else {
605                         $this_field.find('textarea').val('');
606                     }
607                 })
609             } else {
610                 $this_field.html('<div class="null_div"></div>');
611             }
613             // In each input sibling, wrap the current value in a textarea
614             // and store the current value in a hidden span
615             if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
616                 // handle non-truncated, non-transformed, non-relation values
617                 // We don't need to get any more data, just wrap the value
618                 $this_field.append('<textarea>'+data_value+'</textarea>');
619                 $this_field.data('original_data', data_value);
620             }
621             else if($this_field.is('.truncated, .transformed')) {
622                 /** @lends jQuery */
623                 //handle truncated/transformed values values
625                 /**
626                  * @var sql_query   String containing the SQL query used to retrieve value of truncated/transformed data
627                  */
628                 var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);
630                 // Make the Ajax call and get the data, wrap it and insert it
631                 $.post('sql.php', {
632                     'token' : window.parent.token,
633                     'db' : window.parent.db,
634                     'ajax_request' : true,
635                     'sql_query' : sql_query,
636                     'inline_edit' : true
637                 }, function(data) {
638                     if(data.success == true) {
639                         $this_field.append('<textarea>'+data.value+'</textarea>');
640                         $this_field.data('original_data', data_value);
641                     }
642                     else {
643                         PMA_ajaxShowMessage(data.error);
644                     }
645                 }) // end $.post()
646             }
647             else if($this_field.is('.relation')) {
648                 /** @lends jQuery */
649                 //handle relations
651                 /**
652                  * @var post_params Object containing parameters for the POST request
653                  */
654                 var post_params = {
655                         'ajax_request' : true,
656                         'get_relational_values' : true,
657                         'db' : window.parent.db,
658                         'table' : window.parent.table,
659                         'column' : field_name,
660                         'token' : window.parent.token,
661                         'curr_value' : relation_curr_value,
662                         'relation_key_or_display_column' : relation_key_or_display_column
663                 }
665                 $.post('sql.php', post_params, function(data) {
666                     $this_field.append(data.dropdown);
667                     $this_field.data('original_data', data_value);
668                 }) // end $.post()
669             }
670             else if($this_field.is('.enum')) {
671                 /** @lends jQuery */
672                 //handle enum fields
674                 /**
675                  * @var post_params Object containing parameters for the POST request
676                  */
677                 var post_params = {
678                         'ajax_request' : true,
679                         'get_enum_values' : true,
680                         'db' : window.parent.db,
681                         'table' : window.parent.table,
682                         'column' : field_name,
683                         'token' : window.parent.token,
684                         'curr_value' : curr_value
685                 }
687                 $.post('sql.php', post_params, function(data) {
688                     $this_field.append(data.dropdown);
689                     $this_field.data('original_data', data_value);
690                 }) // end $.post()
691             }
692             else if($this_field.is('.set')) {
693                 /** @lends jQuery */
694                 //handle set fields
696                 /**
697                  * @var post_params Object containing parameters for the POST request
698                  */
699                 var post_params = {
700                         'ajax_request' : true,
701                         'get_set_values' : true,
702                         'db' : window.parent.db,
703                         'table' : window.parent.table,
704                         'column' : field_name,
705                         'token' : window.parent.token,
706                         'curr_value' : curr_value
707                 }
709                 $.post('sql.php', post_params, function(data) {
710                     $this_field.append(data.select);
711                     $this_field.data('original_data', data_value);
712                 }) // end $.post()
713             }
714             else if($this_field.is('.null')) {
715                 //handle null fields
716                 $this_field.append('<textarea></textarea>');
717                 $this_field.data('original_data', 'NULL');
718             }
719         })
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).parent().parent();
742         var $test_element = ''; // to test the presence of a element
744         // Initialize variables
745         if(disp_mode == 'vertical') {
746             /**
747              * @var this_td_index  Index of the current <td> in the parent <tr>
748              *                      Current <td> is the inline edit anchor.
749              */
750             var this_td_index = $this_td.index();
751             /**
752              * @var $input_siblings  Object referring to all inline editable events from same row
753              */
754             var $input_siblings = $this_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_td_index+')');
755             /**
756              * @var where_clause    String containing the WHERE clause to select this row
757              */
758             var where_clause = $this_td.parents('tbody').find('tr').find('.where_clause:nth('+this_td_index+')').val();
759         } else {
760             var $input_siblings = $this_td.parent('tr').find('.inline_edit');
761             var where_clause = $this_td.parent('tr').find('.where_clause').val();
762         }
764         /**
765          * @var nonunique   Boolean, whether this row is unique or not
766          */
767         if($this_td.is('.nonunique')) {
768             var nonunique = 0;
769         }
770         else {
771             var nonunique = 1;
772         }
774         // Collect values of all fields to submit, we don't know which changed
775         /**
776          * @var relation_fields Array containing the name/value pairs of relational fields
777          */
778         var relation_fields = {};
779         /**
780          * @var transform_fields    Array containing the name/value pairs for transformed fields
781          */
782         var transform_fields = {};
783         /**
784          * @var transformation_fields   Boolean, if there are any transformed fields in this row
785          */
786         var transformation_fields = false;
788         /**
789          * @var sql_query String containing the SQL query to update this row
790          */
791         var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
793         var need_to_post = false;
795         $input_siblings.each(function() {
796             /** @lends jQuery */
797             /**
798              * @var this_field  Object referring to this field (<td>)
799              */
800                 var $this_field = $(this);
801             /**
802              * @var field_name  String containing the name of this field.
803              * @see getFieldName()
804              */
805             var field_name = getFieldName($this_field, disp_mode);
807             /**
808              * @var this_field_params   Array temporary storage for the name/value of current field
809              */
810             var this_field_params = {};
812             if($this_field.is('.transformed')) {
813                 transformation_fields =  true;
814             }
815             /**
816              * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
817              */
818             var is_null = $this_field.find('input:checkbox').is(':checked');
819             var value;
821             if (is_null) {
822                 sql_query += ' `' + field_name + "`=NULL , ";
823                 need_to_post = true;
824             } else {
825                 if($this_field.is(":not(.relation, .enum, .set)")) {
826                     this_field_params[field_name] = $this_field.find('textarea').val();
827                     if($this_field.is('.transformed')) {
828                         $.extend(transform_fields, this_field_params);
829                     }
830                 } else if ($this_field.is('.set')) {
831                     $test_element = $this_field.find('select');
832                     this_field_params[field_name] = $test_element.map(function(){
833                         return $(this).val();
834                     }).get().join(",");
835                 } else {
836                     // results from a drop-down
837                     $test_element = $this_field.find('select');
838                     if ($test_element.length != 0) {
839                         this_field_params[field_name] = $test_element.val();
840                     }
842                     // results from Browse foreign value
843                     $test_element = $this_field.find('span.curr_value');
844                     if ($test_element.length != 0) {
845                         this_field_params[field_name] = $test_element.text();
846                     }
848                     if($this_field.is('.relation')) {
849                         $.extend(relation_fields, this_field_params);
850                     }
851                 }
852                 if (this_field_params[field_name] != $this_field.data('original_data')) {
853                     sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "' , ";
854                     need_to_post = true;
855                 }
856             }
857         })
859         //Remove the last ',' appended in the above loop
860         sql_query = sql_query.replace(/,\s$/, '');
861         sql_query += ' WHERE ' + PMA_urldecode(where_clause);
863         /**
864          * @var rel_fields_list  String, url encoded representation of {@link relations_fields}
865          */
866         var rel_fields_list = $.param(relation_fields);
868         /**
869          * @var transform_fields_list  String, url encoded representation of {@link transform_fields}
870          */
871         var transform_fields_list = $.param(transform_fields);
873         // if inline_edit is successful, we need to go back to default view
874         var $del_hide=$(this).parent();
875         var $chg_submit=$(this);
877         if (need_to_post) {
878             // Make the Ajax post after setting all parameters
879             /**
880              * @var post_params Object containing parameters for the POST request
881              */
882             var post_params = {'ajax_request' : true,
883                             'sql_query' : sql_query,
884                             'disp_direction' : disp_mode,
885                             'token' : window.parent.token,
886                             'db' : window.parent.db,
887                             'table' : window.parent.table,
888                             'clause_is_unique' : nonunique,
889                             'where_clause' : where_clause,
890                             'rel_fields_list' : rel_fields_list,
891                             'do_transformations' : transformation_fields,
892                             'transform_fields_list' : transform_fields_list,
893                             'goto' : 'sql.php',
894                             'submit_type' : 'save'
895                           };
897             $.post('tbl_replace.php', post_params, function(data) {
898                 if(data.success == true) {
899                     PMA_ajaxShowMessage(data.message);
900                     // remove possible previous feedback message
901                     $('#result_query').remove();
902                     if (typeof data.result_query != 'undefined') {
903                         // display feedback
904                         $('#sqlqueryresults').prepend('<div id="result_query" align="left"></div>');
905                         $('#result_query').prepend(data.result_query);
906                     }
907                     PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode);
908                 } else {
909                     PMA_ajaxShowMessage(data.error);
910                 };
911             }) // end $.post()
912         } else {
913             // no posting was done but still need to display the row
914             // in its previous format
915             PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '', disp_mode);
916         }
917     }) // End After editing, clicking again should post data
918 }, 'top.frame_content') // end $(document).ready()
922  * Visually put back the row in the state it was before entering Inline edit 
924  * (when called in the situation where no posting was done, the data
925  * parameter is empty) 
926  */
927 function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode) {
929     // deleting the hide button
930     // remove <br><br><a> tags
931     for ( var i = 0; i <= 2; i++) {
932         $del_hide.next().remove();
933     }
934     if(disp_mode != 'vertical'){
935         $chg_submit.empty();
936         $chg_submit.html('<span class="nowrap"></span>');
937         $chg_submit.children('span.nowrap').text(PMA_messages['strInlineEdit']);
938     } else {
939         $chg_submit.children('span.nowrap').empty();
940         $chg_submit.children('span.nowrap').append(data_vt);
941     }
943     // changing inline_edit_active to inline_edit_anchor
944     $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
946     // removing hover, marked and noclick classes
947     $this_td.parent('tr').removeClass('noclick');
948     if(disp_mode != 'vertical') {
949         $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
950     } else {
951         $this_td.parents('tbody').find('tr').find('td:eq(' + $this_td.index() + ')').removeClass('marked');
952     }
954     $input_siblings.each(function() {
955         // Inline edit post has been successful.
956         $this_sibling = $(this);
958         var is_null = $this_sibling.find('input:checkbox').is(':checked');
959         if (is_null) {
960             $this_sibling.html('NULL');
961             $this_sibling.addClass('null');
962         } else {
963             $this_sibling.removeClass('null');
964             if($this_sibling.is(':not(.relation, .enum, .set)')) {
965                 /**
966                  * @var new_html    String containing value of the data field after edit
967                  */
968                 var new_html = $this_sibling.find('textarea').val();
970                 if($this_sibling.is('.transformed')) {
971                     var field_name = getFieldName($this_sibling, disp_mode);
972                     if (typeof data.transformations != 'undefined') {
973                         $.each(data.transformations, function(key, value) {
974                             if(key == field_name) {
975                                 if($this_sibling.is('.text_plain, .application_octetstream')) {
976                                     new_html = value;
977                                     return false;
978                                 } else {
979                                     var new_value = $this_sibling.find('textarea').val();
980                                     new_html = $(value).append(new_value);
981                                     return false;
982                                 }
983                             }
984                         })
985                     }
986                 }
987             } else {
988                 var new_html = '';
989                 var new_value = '';
990                 $test_element = $this_sibling.find('select');
991                 if ($test_element.length != 0) {
992                     new_value = $test_element.val();
993                 }
994                 $test_element = $this_sibling.find('span.curr_value');
995                 if ($test_element.length != 0) {
996                     new_value = $test_element.text();
997                 }
999                 if($this_sibling.is('.relation')) {
1000                     var field_name = getFieldName($this_sibling, disp_mode);
1001                     if (typeof data.relations != 'undefined') {
1002                         $.each(data.relations, function(key, value) {
1003                             if(key == field_name) {
1004                                 new_html = $(value).append(new_value);
1005                                 return false;
1006                             }
1007                         })
1008                     }
1009                 } else if ($this_sibling.is('.enum')) {
1010                     new_html = new_value;
1011                 } else if ($this_sibling.is('.set')) {
1012                     if (new_value != null) {
1013                         $.each(new_value, function(key, value) {
1014                             new_html = new_html + value + ',';
1015                         })
1016                         new_html = new_html.substring(0, new_html.length-1);
1017                     }
1018                 }
1019             }
1020             $this_sibling.html(new_html);
1021         }
1022     })
1026  * Starting from some th, change the class of all td under it
1027  */
1028 function PMA_changeClassForColumn($this_th, newclass) {
1029     // index 0 is the th containing the big T
1030     var th_index = $this_th.index();
1031     // .eq() is zero-based
1032     th_index--;
1033     var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
1034     if ($this_th.data('has_class_'+newclass)) {
1035         $tds.removeClass(newclass);
1036         $this_th.data('has_class_'+newclass, false);
1037     } else {
1038         $tds.addClass(newclass);
1039         $this_th.data('has_class_'+newclass, true);
1040     }
1043 $(document).ready(function() {
1045     $('.browse_foreign').live('click', function(e) {
1046         e.preventDefault();
1047         window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
1048         $anchor = $(this);
1049         $anchor.addClass('browse_foreign_clicked');
1050         return false;
1051     });
1053     /**
1054      * vertical column highlighting in horizontal mode when hovering over the column header
1055      */
1056     $('.column_heading').live('hover', function() {
1057         PMA_changeClassForColumn($(this), 'hover');
1058         });
1060     /**
1061      * vertical column marking in horizontal mode when clicking the column header
1062      */
1063     $('.column_heading').live('click', function() {
1064         PMA_changeClassForColumn($(this), 'marked');
1065         });
1068 /**#@- */