remove extra jQuery wrapping and prepend a dollar sign to some jQuery objects
[phpmyadmin/gandalfml.git] / js / sql.js
blob019986a146f0c2192bf8747a5576155a175dbd62
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  * Get the field name for the current field.  Required to construct the query
12  * for inline editing
13  *
14  * @param   this_field_obj  jQuery object that points to the current field's tr
15  * @param   disp_mode       string
16  */
17 function getFieldName(this_field_obj, disp_mode) {
19     if(disp_mode == 'vertical') {
20         var field_name = $(this_field_obj).siblings('th').find('a').text();
21     }
22     else {
23         var this_field_index = $(this_field_obj).index();
24         if(window.parent.text_dir == 'ltr') {
25             // 4 columns to account for the checkbox, edit, delete and appended inline edit anchors
26             var field_name = $(this_field_obj).parents('table').find('thead').find('th:nth('+ (this_field_index-4 )+') a').text();
27         }
28         else {
29             var field_name = $(this_field_obj).parents('table').find('thead').find('th:nth('+ this_field_index+') a').text();
30         }
31     }
33     field_name = $.trim(field_name);
35     return field_name;
38 /**
39  * The function that iterates over each row in the table_results and appends a
40  * new inline edit anchor to each table row.
41  *
42  * @param   disp_mode   string
43  */
44 function appendInlineAnchor(disp_mode) {
45     if(disp_mode == 'vertical') {
46         var $cloned_row = $('.edit_row_anchor').removeClass('edit_row_anchor').parent('tr').clone();
48         var $img_object = $cloned_row.find('img:first').attr('title', PMA_messages['strInlineEdit']);
50         $cloned_row.find('td').addClass('edit_row_anchor')
51         .find('a').attr('href', '#')
52         .find('span')
53         .text(PMA_messages['strInlineEdit'])
54         .prepend($img_object);
56         $cloned_row.insertBefore($('.where_clause').parent('tr'));
58         $("#table_results").find('tr:first').find('th')
59         .attr('rowspan', '4');
60     }
61     else {
62         $('.edit_row_anchor').each(function() {
64             $(this).removeClass('edit_row_anchor');
66             var $cloned_anchor = $(this).clone();
68             var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
70             $cloned_anchor.addClass('edit_row_anchor')
71             .find('a').attr('href', '#')
72             .find('span')
73             .text(PMA_messages['strInlineEdit'])
74             .prepend($img_object);
76             $(this).siblings('.where_clause')
77             .before($cloned_anchor);
78         });
80         $('#rowsDeleteForm').find('thead').find('th').each(function() {
81             if($(this).attr('colspan') == 3) {
82                 $(this).attr('colspan', '4')
83             }
84         })
85     }
88 /**#@+
89  * @namespace   jQuery
90  */
92 /**
93  * @description <p>Ajax scripts for sql and browse pages</p>
94  *
95  * Actions ajaxified here:
96  * <ul>
97  * <li>Retrieve results of an SQL query</li>
98  * <li>Paginate the results table</li>
99  * <li>Sort the results table</li>
100  * <li>Change table according to display options</li>
101  * <li>Inline editing of data</li>
102  * </ul>
104  * @name        document.ready
105  * @memberOf    jQuery
106  */
107 $(document).ready(function() {
109     /**
110      * Set a parameter for all Ajax queries made on this page.  Don't let the
111      * web server serve cached pages
112      */
113     $.ajaxSetup({
114         cache: 'false'
115     });
117     /**
118      * current value of the direction in which the table is displayed
119      * @type    String
120      * @fieldOf jQuery
121      * @name    disp_mode
122      */
123     var disp_mode = $("#top_direction_dropdown").val();
125     /**
126      * Update value of {@link jQuery.disp_mode} everytime the direction dropdown changes value
127      * @memberOf    jQuery
128      * @name        direction_dropdown_change
129      */
130     $("#top_direction_dropdown, #bottom_direction_dropdown").live('change', function(event) {
131         disp_mode = $(this).val();
132     })
134     /**
135      * Attach the {@link appendInlineAnchor} function to a custom event, which
136      * will be triggered manually everytime the table of results is reloaded
137      * @memberOf    jQuery
138      * @name        sqlqueryresults_live
139      */
140     $("#sqlqueryresults").live('appendAnchor',function() {
141         appendInlineAnchor(disp_mode);
142     })
144     /**
145      * Trigger the appendAnchor event to prepare the first table for inline edit
146      *
147      * @memberOf    jQuery
148      * @name        sqlqueryresults_trigger
149      */
150     $("#sqlqueryresults").trigger('appendAnchor');
152     /**
153      * Append the "Show/Hide query box" message to the query input form
154      *
155      * @memberOf jQuery
156      * @name    appendToggleSpan
157      */
158     // do not add this link more than once
159     if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
160         $('<a id="togglequerybox"></a>')
161         .html(PMA_messages['strHideQueryBox'])
162         .appendTo("#sqlqueryform");
164         // Attach the toggling of the query box visibility to a click
165         $("#togglequerybox").bind('click', function() {
166             var $link = $(this)
167             $link.siblings().slideToggle("medium");
168             if ($link.text() == PMA_messages['strHideQueryBox']) {
169                 $link.text(PMA_messages['strShowQueryBox']);
170             } else {
171                 $link.text(PMA_messages['strHideQueryBox']);
172             }
173             // avoid default click action
174             return false;
175         })
176     }
177     
178     /**
179      * Ajax Event handler for 'SQL Query Submit'
180      *
181      * @see         PMA_ajaxShowMessage()
182      * @memberOf    jQuery
183      * @name        sqlqueryform_submit
184      */
185     $("#sqlqueryform").live('submit', function(event) {
186         event.preventDefault();
187         // remove any div containing a previous error message
188         $('.error').remove();
190         $form = $(this);
191         PMA_ajaxShowMessage();
193             if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
194                 $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
195             }
197         $.post($(this).attr('action'), $(this).serialize() , function(data) {
198             if(data.success == true) {
199                 PMA_ajaxShowMessage(data.message);
200                 $('#sqlqueryresults').show();
201                 // this happens if a USE command was typed
202                 if (typeof data.reload != 'undefined') {
203                     $form.find('input[name=db]').val(data.db);
204                     // need to regenerate the whole upper part
205                     $form.find('input[name=ajax_request]').remove();
206                     $form.append('<input type="hidden" name="reload" value="true" />');
207                     $.post('db_sql.php', $form.serialize(), function(data) {
208                         $('body').html(data);
209                     }); // end inner post
210                 }
211             }
212             else if (data.success == false ) {
213                 // show an error message that stays on screen 
214                 $('#sqlqueryform').before(data.error);
215                 $('#sqlqueryresults').hide();
216             }
217             else {
218                 $('#sqlqueryresults').show();
219                 $("#sqlqueryresults").html(data);
220                 $("#sqlqueryresults").trigger('appendAnchor');
221                 if($("#togglequerybox").siblings(":visible").length > 0) {
222                     $("#togglequerybox").trigger('click');
223                 }
224             }
225         }) // end $.post()
226     }) // end SQL Query submit
228     /**
229      * Ajax Event handlers for Paginating the results table
230      */
232     /**
233      * Paginate when we click any of the navigation buttons
234      * @memberOf    jQuery
235      * @name        paginate_nav_button_click
236      * @uses        PMA_ajaxShowMessage()
237      */
238     $("input[name=navig]").live('click', function(event) {
239         /** @lends jQuery */
240         event.preventDefault();
242         PMA_ajaxShowMessage();
243         
244         /**
245          * @var the_form    Object referring to the form element that paginates the results table
246          */
247         var the_form = $(this).parent("form");
249         $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
251         $.post($(the_form).attr('action'), $(the_form).serialize(), function(data) {
252             $("#sqlqueryresults").html(data);
253             $("#sqlqueryresults").trigger('appendAnchor');
254         }) // end $.post()
255     })// end Paginate results table
257     /**
258      * Paginate results with Page Selector dropdown
259      * @memberOf    jQuery
260      * @name        paginate_dropdown_change
261      */
262     $("#pageselector").live('change', function(event) {
263         event.preventDefault();
265         PMA_ajaxShowMessage();
267         $.get($(this).attr('href'), $(this).serialize() + '&ajax_request=true', function(data) {
268             $("#sqlqueryresults").html(data);
269             $("#sqlqueryresults").trigger('appendAnchor');
270         }) // end $.get()
271     })// end Paginate results with Page Selector
273     /**
274      * Ajax Event handler for sorting the results table
275      * @memberOf    jQuery
276      * @name        table_results_sort_click
277      */
278     $("#table_results").find("a[title=Sort]").live('click', function(event) {
279         event.preventDefault();
281         PMA_ajaxShowMessage();
283         $.get($(this).attr('href'), $(this).serialize() + '&ajax_request=true', function(data) {
284             $("#sqlqueryresults").html(data);
285             $("#sqlqueryresults").trigger('appendAnchor');
286         }) // end $.get()
287     })//end Sort results table
289     /**
290      * Ajax Event handler for the display options
291      * @memberOf    jQuery
292      * @name        displayOptionsForm_submit
293      */
294     $("#displayOptionsForm").live('submit', function(event) {
295         event.preventDefault();
297         $.post($(this).attr('action'), $(this).serialize() + '&ajax_request=true' , function(data) {
298             $("#sqlqueryresults").html(data);
299             $("#sqlqueryresults").trigger('appendAnchor');
300         }) // end $.post()
301     })
302     //end displayOptionsForm handler
304     /**
305      * Ajax Event handlers for Inline Editing
306      */
308     /**
309      * On click, replace the current field with an input/textarea
310      * @memberOf    jQuery
311      * @name        inline_edit_start
312      * @see         PMA_ajaxShowMessage()
313      * @see         getFieldName()
314      */
315     $(".edit_row_anchor").live('click', function(event) {
316         /** @lends jQuery */
317         event.preventDefault();
319         $(this).removeClass('edit_row_anchor').addClass('edit_row_anchor_active');
321         // Initialize some variables
322         if(disp_mode == 'vertical') {
323             /**
324              * @var this_row_index  Index of the current <td> in the parent <tr>
325              *                      Current <td> is the inline edit anchor.
326              */
327             var this_row_index = $(this).index();
328             /**
329              * @var input_siblings  Object referring to all inline editable events from same row
330              */
331             var input_siblings = $(this).parents('tbody').find('tr').find('.data_inline_edit:nth('+this_row_index+')');
332             /**
333              * @var where_clause    String containing the WHERE clause to select this row
334              */
335             var where_clause = $(this).parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
336         }
337         else {
338             var input_siblings = $(this).parent('tr').find('.data_inline_edit');
339             var where_clause = $(this).parent('tr').find('.where_clause').val();
340         }
342         $(input_siblings).each(function() {
343             /** @lends jQuery */
344             /**
345              * @var data_value  Current value of this field
346              */
347             var data_value = $(this).html();
349             // We need to retrieve the value from the server for truncated/relation fields
350             // Find the field name
351             
352             /**
353              * @var this_field  Object referring to this field (<td>)
354              */
355             var this_field = $(this);
356             /**
357              * @var field_name  String containing the name of this field.
358              * @see getFieldName()
359              */
360             var field_name = getFieldName($(this), disp_mode);
362             // In each input sibling, wrap the current value in a textarea
363             // and store the current value in a hidden span
364             if($(this).is(':not(.truncated, .transformed, .relation, .enum, .null)')) {
365                 // handle non-truncated, non-transformed, non-relation values
366                 // We don't need to get any more data, just wrap the value
367                 $(this).html('<textarea>'+data_value+'</textarea>')
368                 .append('<span class="original_data">'+data_value+'</span>');
369                 $(".original_data").hide();
370             }
371             else if($(this).is('.truncated, .transformed')) {
372                 /** @lends jQuery */
373                 //handle truncated/transformed values values
375                 /**
376                  * @var sql_query   String containing the SQL query used to retrieve value of truncated/transformed data
377                  */
378                 var sql_query = 'SELECT ' + field_name + ' FROM ' + window.parent.table + ' WHERE ' + where_clause;
380                 // Make the Ajax call and get the data, wrap it and insert it
381                 $.post('sql.php', {
382                     'token' : window.parent.token,
383                     'db' : window.parent.db,
384                     'ajax_request' : true,
385                     'sql_query' : sql_query,
386                     'inline_edit' : true
387                 }, function(data) {
388                     if(data.success == true) {
389                         $(this_field).html('<textarea>'+data.value+'</textarea>')
390                         .append('<span class="original_data">'+data_value+'</span>');
391                         $(".original_data").hide();
392                     }
393                     else {
394                         PMA_ajaxShowMessage(data.error);
395                     }
396                 }) // end $.post()
397             }
398             else if($(this).is('.relation')) {
399                 /** @lends jQuery */
400                 //handle relations
402                 /**
403                  * @var curr_value  String containing the current value of this relational field
404                  */
405                 var curr_value = $(this).find('a').text();
407                 /**
408                  * @var post_params Object containing parameters for the POST request
409                  */
410                 var post_params = {
411                         'ajax_request' : true,
412                         'get_relational_values' : true,
413                         'db' : window.parent.db,
414                         'table' : window.parent.table,
415                         'column' : field_name,
416                         'token' : window.parent.token,
417                         'curr_value' : curr_value
418                 }
420                 $.post('sql.php', post_params, function(data) {
421                     $(this_field).html(data.dropdown)
422                     .append('<span class="original_data">'+data_value+'</span>');
423                     $(".original_data").hide();
424                 }) // end $.post()
425             }
426             else if($(this).is('.enum')) {
427                 /** @lends jQuery */
428                 //handle enum fields
429                 /**
430                  * @var curr_value  String containing the current value of this relational field
431                  */
432                 var curr_value = $(this).text();
434                 /**
435                  * @var post_params Object containing parameters for the POST request
436                  */
437                 var post_params = {
438                         'ajax_request' : true,
439                         'get_enum_values' : true,
440                         'db' : window.parent.db,
441                         'table' : window.parent.table,
442                         'column' : field_name,
443                         'token' : window.parent.token,
444                         'curr_value' : curr_value
445                 }
447                 $.post('sql.php', post_params, function(data) {
448                     $(this_field).html(data.dropdown)
449                     .append('<span class="original_data">'+data_value+'</span>');
450                     $(".original_data").hide();
451                 }) // end $.post()
452             }
453             else if($(this).is('.null')) {
454                 //handle null fields
455                 $(this_field).html('<textarea></textarea>')
456                 .append('<span class="original_data">NULL</span>');
457                 $(".original_data").hide();
458             }
459         })
460     }) // End On click, replace the current field with an input/textarea
462     /**
463      * After editing, clicking again should post data
464      *
465      * @memberOf    jQuery
466      * @name        inline_edit_save
467      * @see         PMA_ajaxShowMessage()
468      * @see         getFieldName()
469      */
470     $(".edit_row_anchor_active").live('click', function(event) {
471         /** @lends jQuery */
472         event.preventDefault();
474         /**
475          * @var this_row    Object referring to current row that is being edited
476          */
477         var this_row = $(this);
479         // Initialize variables
480         if(disp_mode == 'vertical') {
481             /**
482              * @var this_row_index  Index of the current <td> in the parent <tr>
483              *                      Current <td> is the inline edit anchor.
484              */
485             var this_row_index = $(this).index();
486             /**
487              * @var input_siblings  Object referring to all inline editable events from same row
488              */
489             var input_siblings = $(this).parents('tbody').find('tr').find('.data_inline_edit:nth('+this_row_index+')');
490             /**
491              * @var where_clause    String containing the WHERE clause to select this row
492              */
493             var where_clause = $(this).parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
494         }
495         else {
496             var input_siblings = $(this).parent('tr').find('.data_inline_edit');
497             var where_clause = $(this).parent('tr').find('.where_clause').val();
498         }
500         /**
501          * @var nonunique   Boolean, whether this row is unique or not
502          */
503         if($(this).is('.nonunique')) {
504             var nonunique = 0;
505         }
506         else {
507             var nonunique = 1;
508         }
510         // Collect values of all fields to submit, we don't know which changed
511         /**
512          * @var params_to_submit    Array containing the name/value pairs of all fields
513          */
514         var params_to_submit = {};
515         /**
516          * @var relation_fields Array containing the name/value pairs of relational fields
517          */
518         var relation_fields = {};
519         /**
520          * @var transform_fields    Array containing the name/value pairs for transformed fields
521          */
522         var transform_fields = {};
523         /**
524          * @var transformation_fields   Boolean, if there are any transformed fields in this row
525          */
526         var transformation_fields = false;
528         $(input_siblings).each(function() {
529             /** @lends jQuery */
530             /**
531              * @var this_field  Object referring to this field (<td>)
532              */
533             var this_field = $(this);
534             /**
535              * @var field_name  String containing the name of this field.
536              * @see getFieldName()
537              */
538             var field_name = getFieldName($(this), disp_mode);
540             /**
541              * @var this_field_params   Array temporary storage for the name/value of current field
542              */
543             var this_field_params = {};
545             if($(this).is('.transformed')) {
546                 transformation_fields =  true;
547             }
549             if($(this).is(":not(.relation, .enum)")) {
550                 this_field_params[field_name] = $(this).find('textarea').val();
551                 if($(this).is('.transformed')) {
552                     $.extend(transform_fields, this_field_params);
553                 }
554             }
555             else {
556                 this_field_params[field_name] = $(this).find('select').val();
558                 if($(this).is('.relation')) {
559                     $.extend(relation_fields, this_field_params);
560                 }
561             }
563             $.extend(params_to_submit, this_field_params);
564         })
566         /**
567          * @var sql_query   String containing the SQL query to update this row
568          */
569         var sql_query = 'UPDATE ' + window.parent.table + ' SET ';
571         $.each(params_to_submit, function(key, value) {
572             if(value.length == 0) {
573                 value = 'NULL'
574             }
575            sql_query += ' ' + key + "='" + value + "' , ";
576         })
577         //Remove the last ',' appended in the above loop
578         sql_query = sql_query.replace(/,\s$/, '');
579         sql_query += ' WHERE ' + where_clause;
581         /**
582          * @var rel_fields_list  String, url encoded representation of {@link relations_fields}
583          */
584         var rel_fields_list = $.param(relation_fields);
586         /**
587          * @var transform_fields_list  String, url encoded representation of {@link transform_fields}
588          */
589         var transform_fields_list = $.param(transform_fields);
591         // Make the Ajax post after setting all parameters
592         /**
593          * @var post_params Object containing parameters for the POST request
594          */
595         var post_params = {'ajax_request' : true,
596                             'sql_query' : sql_query,
597                             'disp_direction' : disp_mode,
598                             'token' : window.parent.token,
599                             'db' : window.parent.db,
600                             'table' : window.parent.table,
601                             'clause_is_unique' : nonunique,
602                             'where_clause' : where_clause,
603                             'rel_fields_list' : rel_fields_list,
604                             'do_transformations' : transformation_fields,
605                             'transform_fields_list' : transform_fields_list,
606                             'goto' : 'sql.php'
607                           };
609         $.post('tbl_replace.php', post_params, function(data) {
610             if(data.success == true) {
611                 PMA_ajaxShowMessage(data.message);
612                 $(this_row).removeClass('edit_row_anchor_active').addClass('edit_row_anchor');
614                 $(input_siblings).each(function() {
615                     // Inline edit post has been successful.
616                     if($(this).is(':not(.relation, .enum)')) {
617                         /**
618                          * @var new_html    String containing value of the data field after edit
619                          */
620                         var new_html = $(this).find('textarea').val();
622                         if($(this).is('.transformed')) {
623                             var field_name = getFieldName($(this), disp_mode);
624                             var this_field = $(this);
626                             $.each(data.transformations, function(key, value) {
627                                 if(key == field_name) {
628                                     if($(this_field).is('.text_plain, .application_octetstream')) {
629                                         new_html = value;
630                                         return false;
631                                     }
632                                     else {
633                                         var new_value = $(this_field).find('textarea').val();
634                                         new_html = $(value).append(new_value);
635                                         return false;
636                                     }
637                                 }
638                             })
639                         }
640                     }
641                     else {
642                         var new_html = $(this).find('select').val();
643                         if($(this).is('.relation')) {
644                             var field_name = getFieldName($(this), disp_mode);
645                             var this_field = $(this);
647                             $.each(data.relations, function(key, value) {
648                                 if(key == field_name) {
649                                     var new_value = $(this_field).find('select').val();
650                                     new_html = $(value).append(new_value);
651                                     return false;
652                                 }
653                             })
654                         }
655                     }
656                     $(this).html(new_html);
657                 })
658             }
659             else {
660                 PMA_ajaxShowMessage(data.error);
661             };
662         }) // end $.post()
663     }) // End After editing, clicking again should post data
664 }, 'top.frame_content') // end $(document).ready()
666 /**#@- */