1 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 * @fileoverview functions used wherever an sql query form is used
6 * @requires js/functions.js
13 * decode a string URL_encoded
16 * @return string the URL-decoded string
18 function PMA_urldecode(str) {
19 return decodeURIComponent(str.replace(/\+/g, '%20'));
22 function PMA_urlencode(str) {
23 return encodeURIComponent(str.replace(/\%20/g, '+'));
27 * Get the field name for the current field. Required to construct the query
30 * @param $this_field jQuery object that points to the current field's tr
31 * @param disp_mode string
33 function getFieldName($this_field, disp_mode) {
35 if(disp_mode == 'vertical') {
36 var field_name = $this_field.siblings('th').find('a').text();
37 // happens when just one row (headings contain no a)
38 if ("" == field_name) {
39 field_name = $this_field.siblings('th').text();
43 var this_field_index = $this_field.index();
44 // ltr or rtl direction does not impact how the DOM was generated
46 // 5 columns to account for the checkbox, edit, appended inline edit, copy and delete anchors but index is zero-based so substract 4
47 var field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+') a').text();
48 // happens when just one row (headings contain no a)
49 if ("" == field_name) {
50 field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+')').text();
54 field_name = $.trim(field_name);
60 * The function that iterates over each row in the table_results and appends a
61 * new inline edit anchor to each table row.
64 function appendInlineAnchor() {
65 var disp_mode = $("#top_direction_dropdown").val();
67 if (disp_mode == 'vertical') {
68 // there can be one or two tr containing this class, depending
69 // on the ModifyDeleteAtLeft and ModifyDeleteAtRight cfg parameters
70 $('#table_results tr')
71 .find('.edit_row_anchor')
72 .removeClass('edit_row_anchor')
73 .parent().each(function() {
74 var $this_tr = $(this);
75 var $cloned_tr = $this_tr.clone();
77 var $img_object = $cloned_tr.find('img:first').attr('title', PMA_messages['strInlineEdit']);
78 if ($img_object.length != 0) {
79 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
80 $img_object.attr('src', img_src);
84 .addClass('inline_edit_anchor')
85 .find('a').attr('href', '#');
86 var $edit_span = $cloned_tr.find('span:contains("' + PMA_messages['strEdit'] + '")');
87 var $span = $cloned_tr.find('a').find('span');
88 if ($edit_span.length > 0) {
89 $span.text(' ' + PMA_messages['strInlineEdit']);
90 $span.prepend($img_object);
93 $span.append($img_object);
96 $cloned_tr.insertAfter($this_tr);
99 $('#rowsDeleteForm').find('tbody').find('th').each(function() {
100 var $this_th = $(this);
101 if ($this_th.attr('rowspan') == 4) {
102 $this_th.attr('rowspan', '5');
108 $('.edit_row_anchor').each(function() {
110 var $this_td = $(this);
111 $this_td.removeClass('edit_row_anchor');
113 var $cloned_anchor = $this_td.clone();
115 var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
116 if ($img_object.length != 0) {
117 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
118 $img_object.attr('src', img_src);
119 $cloned_anchor.find('a').attr('href', '#');
120 var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
121 var $span = $cloned_anchor.find('a').find('span');
122 if ($edit_span.length > 0) {
123 $span.text(' ' + PMA_messages['strInlineEdit']);
124 $span.prepend($img_object);
127 $span.append($img_object);
130 // Only text is displayed. See $cfg['PropertiesIconic']
131 $cloned_anchor.find('a').attr('href', '#');
132 $cloned_anchor.find('a span').text(PMA_messages['strInlineEdit']);
134 // the link was too big so <input type="image"> is there
135 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
136 if ($img_object.length > 0) {
137 var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
138 $img_object.attr('src', img_src);
141 .find('.clickprevimage')
142 .text(' ' + PMA_messages['strInlineEdit']);
146 .addClass('inline_edit_anchor');
148 $this_td.after($cloned_anchor);
151 $('#rowsDeleteForm').find('thead, tbody').find('th').each(function() {
152 var $this_th = $(this);
153 if ($this_th.attr('colspan') == 4) {
154 $this_th.attr('colspan', '5');
165 * @description <p>Ajax scripts for sql and browse pages</p>
167 * Actions ajaxified here:
169 * <li>Retrieve results of an SQL query</li>
170 * <li>Paginate the results table</li>
171 * <li>Sort the results table</li>
172 * <li>Change table according to display options</li>
173 * <li>Inline editing of data</li>
176 * @name document.ready
179 $(document).ready(function() {
182 * Set a parameter for all Ajax queries made on this page. Don't let the
183 * web server serve cached pages
190 * current value of the direction in which the table is displayed
195 var disp_mode = $("#top_direction_dropdown").val();
198 * Update value of {@link jQuery.disp_mode} everytime the direction dropdown changes value
200 * @name direction_dropdown_change
202 $("#top_direction_dropdown, #bottom_direction_dropdown").live('change', function(event) {
203 disp_mode = $(this).val();
207 * Attach the {@link appendInlineAnchor} function to a custom event, which
208 * will be triggered manually everytime the table of results is reloaded
211 $("#sqlqueryresults").live('appendAnchor',function() {
212 appendInlineAnchor();
216 * Trigger the appendAnchor event to prepare the first table for inline edit
217 * (see $GLOBALS['cfg']['AjaxEnable'])
219 * @name sqlqueryresults_trigger
221 $("#sqlqueryresults.ajax").trigger('appendAnchor');
224 * Append the "Show/Hide query box" message to the query input form
227 * @name appendToggleSpan
229 // do not add this link more than once
230 if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
231 $('<a id="togglequerybox"></a>')
232 .html(PMA_messages['strHideQueryBox'])
233 .appendTo("#sqlqueryform")
234 // initially hidden because at this point, nothing else
235 // appears under the link
238 // Attach the toggling of the query box visibility to a click
239 $("#togglequerybox").bind('click', function() {
241 $link.siblings().slideToggle("fast");
242 if ($link.text() == PMA_messages['strHideQueryBox']) {
243 $link.text(PMA_messages['strShowQueryBox']);
244 // cheap trick to add a spacer between the menu tabs
245 // and "Show query box"; feel free to improve!
246 $('#togglequerybox_spacer').remove();
247 $link.before('<br id="togglequerybox_spacer" />');
249 $link.text(PMA_messages['strHideQueryBox']);
251 // avoid default click action
257 * Ajax Event handler for 'SQL Query Submit'
259 * @see PMA_ajaxShowMessage()
260 * @see $cfg['AjaxEnable']
262 * @name sqlqueryform_submit
264 $("#sqlqueryform.ajax").live('submit', function(event) {
265 event.preventDefault();
268 if (! checkSqlQuery($form[0])) {
272 // remove any div containing a previous error message
273 $('.error').remove();
275 var $msgbox = PMA_ajaxShowMessage();
277 PMA_prepareForAjaxRequest($form);
279 $.post($(this).attr('action'), $(this).serialize() , function(data) {
280 if(data.success == true) {
281 // fade out previous messages, if any
282 $('.success').fadeOut();
283 $('.sqlquery_message').fadeOut();
284 // show a message that stays on screen
285 if (typeof data.sql_query != 'undefined') {
286 $('<div class="sqlquery_message"></div>')
287 .html(data.sql_query)
288 .insertBefore('#sqlqueryform');
289 // unnecessary div that came from data.sql_query
290 $('.notice').remove();
292 $('#sqlqueryform').before(data.message);
294 $('#sqlqueryresults').show();
295 // this happens if a USE command was typed
296 if (typeof data.reload != 'undefined') {
297 // Unbind the submit event before reloading. See bug #3295529
298 $("#sqlqueryform.ajax").die('submit');
299 $form.find('input[name=db]').val(data.db);
300 // need to regenerate the whole upper part
301 $form.find('input[name=ajax_request]').remove();
302 $form.append('<input type="hidden" name="reload" value="true" />');
303 $.post('db_sql.php', $form.serialize(), function(data) {
304 $('body').html(data);
305 }); // end inner post
308 else if (data.success == false ) {
309 // show an error message that stays on screen
310 $('#sqlqueryform').before(data.error);
311 $('#sqlqueryresults').hide();
314 // real results are returned
315 // fade out previous messages, if any
316 $('.success').fadeOut();
317 $('.sqlquery_message').fadeOut();
318 $received_data = $(data);
319 $zero_row_results = $received_data.find('textarea[name="sql_query"]');
320 // if zero rows are returned from the query execution
321 if ($zero_row_results.length > 0) {
322 $('#sqlquery').val($zero_row_results.val());
324 $('#sqlqueryresults').show();
325 $("#sqlqueryresults").html(data);
326 $("#sqlqueryresults").trigger('appendAnchor');
327 $('#togglequerybox').show();
328 if($("#togglequerybox").siblings(":visible").length > 0) {
329 $("#togglequerybox").trigger('click');
334 PMA_ajaxRemoveMessage($msgbox);
337 }) // end SQL Query submit
340 * Ajax Event handlers for Paginating the results table
344 * Paginate when we click any of the navigation buttons
345 * (only if the element has the ajax class, see $cfg['AjaxEnable'])
347 * @name paginate_nav_button_click
348 * @uses PMA_ajaxShowMessage()
349 * @see $cfg['AjaxEnable']
351 $("input[name=navig].ajax").live('click', function(event) {
353 event.preventDefault();
355 var $msgbox = PMA_ajaxShowMessage();
358 * @var $the_form Object referring to the form element that paginates the results table
360 var $the_form = $(this).parent("form");
362 $the_form.append('<input type="hidden" name="ajax_request" value="true" />');
364 $.post($the_form.attr('action'), $the_form.serialize(), function(data) {
365 $("#sqlqueryresults").html(data);
366 $("#sqlqueryresults").trigger('appendAnchor');
369 PMA_ajaxRemoveMessage($msgbox);
371 })// end Paginate results table
374 * Paginate results with Page Selector dropdown
376 * @name paginate_dropdown_change
377 * @see $cfg['AjaxEnable']
379 $("#pageselector").live('change', function(event) {
380 var $the_form = $(this).parent("form");
382 if ($(this).hasClass('ajax')) {
383 event.preventDefault();
385 var $msgbox = PMA_ajaxShowMessage();
387 $.post($the_form.attr('action'), $the_form.serialize() + '&ajax_request=true', function(data) {
388 $("#sqlqueryresults").html(data);
389 $("#sqlqueryresults").trigger('appendAnchor');
391 PMA_ajaxRemoveMessage($msgbox);
397 })// end Paginate results with Page Selector
400 * Ajax Event handler for sorting the results table
402 * @name table_results_sort_click
403 * @see $cfg['AjaxEnable']
405 $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
406 event.preventDefault();
408 var $msgbox = PMA_ajaxShowMessage();
412 $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
413 $("#sqlqueryresults")
415 .trigger('appendAnchor');
416 PMA_ajaxRemoveMessage($msgbox);
418 })//end Sort results table
421 * Ajax Event handler for the display options
423 * @name displayOptionsForm_submit
424 * @see $cfg['AjaxEnable']
426 $("#displayOptionsForm.ajax").live('submit', function(event) {
427 event.preventDefault();
431 $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
432 $("#sqlqueryresults")
434 .trigger('appendAnchor');
438 //end displayOptionsForm handler
441 * Ajax Event handlers for Inline Editing
445 * On click, replace the fields of current row with an input/textarea
447 * @name inline_edit_start
448 * @see PMA_ajaxShowMessage()
449 * @see getFieldName()
451 $(".inline_edit_anchor span a").live('click', function(event) {
453 event.preventDefault();
455 var $edit_td = $(this).parents('td');
456 $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');
458 // Adding submit and hide buttons to inline edit <td>.
459 // For "hide" button the original data to be restored is
460 // kept in the jQuery data element 'original_data' inside the <td>.
461 // Looping through all columns or rows, to find the required data and then storing it in an array.
463 var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
464 // Keep the original data preserved.
465 $data_a = $edit_td.children('span.nowrap').children('a').clone();
467 // Change the inline edit to save.
468 var $img_object = $this_children.find('img');
470 // If texts are displayed. See $cfg['PropertiesIconic']
471 if ($this_children.parent('a').find('span:contains("' + PMA_messages['strInlineEdit'] + '")').length > 0) {
472 $this_children.text(' ' + PMA_messages['strSave']);
474 $this_children.empty();
477 // If icons are displayed. See $cfg['PropertiesIconic']
478 if ($img_object.length > 0) {
479 $img_object.attr('title', PMA_messages['strSave']);
480 var img_src = $img_object.attr('src').replace(/b_inline_edit/,'b_save');
481 $img_object.attr('src', img_src);
482 $this_children.prepend($img_object);
485 // Clone the save link and change it to create the hide link.
486 var $hide_a = $edit_td.children('span.nowrap').children('a').clone().attr('id', 'hide');
487 var $hide_span = $hide_a.find('span');
488 var $img_object = $hide_a.find('span img');
490 // If texts are displayed. See $cfg['PropertiesIconic']
491 if ($hide_a.find('span:contains("' + PMA_messages['strSave'] + '")').length > 0) {
492 $hide_span.text(' ' + PMA_messages['strHide']);
497 // If icons are displayed. See $cfg['PropertiesIconic']
498 if ($img_object.length > 0) {
499 $img_object.attr('title', PMA_messages['strHide']);
500 var img_src = $img_object.attr('src').replace(/b_save/,'b_close');
501 $img_object.attr('src', img_src);
502 $hide_span.prepend($img_object);
505 // Add hide icon and/or text.
506 $edit_td.children('span.nowrap').append($('<br /><br />')).append($hide_a);
508 if (disp_mode != 'vertical') {
509 $('#table_results tbody tr td span a#hide').click(function() {
510 var $this_hide = $(this).parents('td');
512 var $this_span = $this_hide.find('span');
513 $this_span.find('a, br').remove();
514 $this_span.append($data_a.clone());
516 $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
517 $this_hide.parent().removeClass("hover noclick");
518 $this_hide.siblings().removeClass("hover");
520 var last_column = $this_hide.siblings().length;
522 for(var i = 4; i < last_column; i++) {
523 if($this_hide.siblings("td:eq(" + i + ")").hasClass("inline_edit") == false) {
526 txt = $this_hide.siblings("td:eq(" + i + ")").data('original_data');
527 if($this_hide.siblings("td:eq(" + i + ")").children().length != 0) {
528 $this_hide.siblings("td:eq(" + i + ")").empty();
529 $this_hide.siblings("td:eq(" + i + ")").append(txt);
532 $(this).prev().prev().remove();
533 $(this).prev().remove();
538 var rows = $edit_td.parent().siblings().length;
540 $('#table_results tbody tr td span a#hide').click(function() {
541 var $hide_a = $(this);
542 var pos = $hide_a.parents('td').index();
544 var $this_span = $hide_a.parent();
545 $this_span.find('a, br').remove();
546 $this_span.append($data_a.clone());
548 var $this_row = $this_span.parents('tr');
549 // changing inline_edit_active to inline_edit_anchor
550 $this_row.siblings("tr:eq(3) td:eq(" + pos + ")").removeClass("inline_edit_active").addClass("inline_edit_anchor");
552 // removing marked and hover classes.
553 $this_row.parent('tbody').find('tr').find("td:eq(" + pos + ")").removeClass("marked hover");
555 for( var i = 6; i <= rows + 2; i++){
556 if( $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").hasClass("inline_edit") == false) {
559 txt = $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").data('original_data');
560 $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").empty();
561 $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").append(txt);
563 $(this).prev().remove();
564 $(this).prev().remove();
569 // Initialize some variables
570 if(disp_mode == 'vertical') {
572 * @var this_row_index Index of the current <td> in the parent <tr>
573 * Current <td> is the inline edit anchor.
575 var this_row_index = $edit_td.index();
577 * @var $input_siblings Object referring to all inline editable events from same row
579 var $input_siblings = $edit_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_row_index+')');
581 * @var where_clause String containing the WHERE clause to select this row
583 var where_clause = $edit_td.parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
587 var this_row_index = $edit_td.parent().index();
588 var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
589 var where_clause = $edit_td.parent('tr').find('.where_clause').val();
592 $input_siblings.each(function() {
595 * @var data_value Current value of this field
597 var data_value = $(this).html();
599 // We need to retrieve the value from the server for truncated/relation fields
600 // Find the field name
603 * @var this_field Object referring to this field (<td>)
605 var $this_field = $(this);
607 * @var field_name String containing the name of this field.
608 * @see getFieldName()
610 var field_name = getFieldName($this_field, disp_mode);
612 * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
614 var relation_curr_value = $this_field.find('a').text();
616 * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
617 * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
619 var relation_key_or_display_column = $this_field.find('a').attr('title');
621 * @var curr_value String current value of the field (for fields that are of type enum or set).
623 var curr_value = $this_field.text();
625 if($this_field.is(':not(.not_null)')){
626 // add a checkbox to mark null for all the field that are nullable.
627 $this_field.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
628 // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
629 if($this_field.is('.null')) {
630 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
633 // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
634 if ($this_field.is('.enum, .set')) {
635 $this_field.find('select').live('change', function(e) {
636 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
638 } else if ($this_field.is('.relation')) {
639 $this_field.find('select').live('change', function(e) {
640 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
642 $this_field.find('.browse_foreign').live('click', function(e) {
643 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
646 $this_field.find('textarea').live('keypress', function(e) {
647 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
651 // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
652 $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
653 if ($this_field.is('.enum')) {
654 $this_field.find('select').attr('value', '');
655 } else if ($this_field.is('.set')) {
656 $this_field.find('select').find('option').each(function() {
657 var $option = $(this);
658 $option.attr('selected', false);
660 } else if ($this_field.is('.relation')) {
661 // if the dropdown is there to select the foreign value
662 if ($this_field.find('select').length > 0) {
663 $this_field.find('select').attr('value', '');
664 // if foriegn value is selected by browsing foreing values
666 $this_field.find('span.curr_value').empty();
669 $this_field.find('textarea').val('');
674 $this_field.html('<div class="null_div"></div>');
677 // In each input sibling, wrap the current value in a textarea
678 // and store the current value in a hidden span
679 if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
680 // handle non-truncated, non-transformed, non-relation values
681 // We don't need to get any more data, just wrap the value
682 $this_field.append('<textarea>'+data_value+'</textarea>');
683 $this_field.data('original_data', data_value);
685 else if($this_field.is('.truncated, .transformed')) {
687 //handle truncated/transformed values values
690 * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data
692 var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);
694 // Make the Ajax call and get the data, wrap it and insert it
696 'token' : window.parent.token,
697 'db' : window.parent.db,
698 'ajax_request' : true,
699 'sql_query' : sql_query,
702 if(data.success == true) {
703 $this_field.append('<textarea>'+data.value+'</textarea>');
704 $this_field.data('original_data', data_value);
707 PMA_ajaxShowMessage(data.error);
711 else if($this_field.is('.relation')) {
716 * @var post_params Object containing parameters for the POST request
719 'ajax_request' : true,
720 'get_relational_values' : true,
721 'db' : window.parent.db,
722 'table' : window.parent.table,
723 'column' : field_name,
724 'token' : window.parent.token,
725 'curr_value' : relation_curr_value,
726 'relation_key_or_display_column' : relation_key_or_display_column
729 $.post('sql.php', post_params, function(data) {
730 $this_field.append(data.dropdown);
731 $this_field.data('original_data', data_value);
734 else if($this_field.is('.enum')) {
739 * @var post_params Object containing parameters for the POST request
742 'ajax_request' : true,
743 'get_enum_values' : true,
744 'db' : window.parent.db,
745 'table' : window.parent.table,
746 'column' : field_name,
747 'token' : window.parent.token,
748 'curr_value' : curr_value
750 $.post('sql.php', post_params, function(data) {
751 $this_field.append(data.dropdown);
752 $this_field.data('original_data', data_value);
755 else if($this_field.is('.set')) {
760 * @var post_params Object containing parameters for the POST request
763 'ajax_request' : true,
764 'get_set_values' : true,
765 'db' : window.parent.db,
766 'table' : window.parent.table,
767 'column' : field_name,
768 'token' : window.parent.token,
769 'curr_value' : curr_value
772 $.post('sql.php', post_params, function(data) {
773 $this_field.append(data.select);
774 $this_field.data('original_data', data_value);
777 else if($this_field.is('.null')) {
779 $this_field.append('<textarea></textarea>');
780 $this_field.data('original_data', 'NULL');
783 }) // End On click, replace the current field with an input/textarea
786 * After editing, clicking again should post data
789 * @name inline_edit_save
790 * @see PMA_ajaxShowMessage()
791 * @see getFieldName()
793 $(".inline_edit_active span a").live('click', function(event) {
796 event.preventDefault();
799 * @var $this_td Object referring to the td containing the
800 * "Inline Edit" link that was clicked to save the row that is
804 var $this_td = $(this).parent().parent();
805 var $test_element = ''; // to test the presence of a element
807 // Initialize variables
808 if(disp_mode == 'vertical') {
810 * @var this_td_index Index of the current <td> in the parent <tr>
811 * Current <td> is the inline edit anchor.
813 var this_td_index = $this_td.index();
815 * @var $input_siblings Object referring to all inline editable events from same row
817 var $input_siblings = $this_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_td_index+')');
819 * @var where_clause String containing the WHERE clause to select this row
821 var where_clause = $this_td.parents('tbody').find('tr').find('.where_clause:nth('+this_td_index+')').val();
823 var $input_siblings = $this_td.parent('tr').find('.inline_edit');
824 var where_clause = $this_td.parent('tr').find('.where_clause').val();
828 * @var nonunique Boolean, whether this row is unique or not
830 if($this_td.is('.nonunique')) {
837 // Collect values of all fields to submit, we don't know which changed
839 * @var relation_fields Array containing the name/value pairs of relational fields
841 var relation_fields = {};
843 * @var relational_display string 'K' if relational key, 'D' if relational display column
845 var relational_display = $("#relational_display_K").attr('checked') ? 'K' : 'D';
847 * @var transform_fields Array containing the name/value pairs for transformed fields
849 var transform_fields = {};
851 * @var transformation_fields Boolean, if there are any transformed fields in this row
853 var transformation_fields = false;
856 * @var sql_query String containing the SQL query to update this row
858 var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
860 var need_to_post = false;
865 $input_siblings.each(function() {
868 * @var this_field Object referring to this field (<td>)
870 var $this_field = $(this);
873 * @var field_name String containing the name of this field.
874 * @see getFieldName()
876 var field_name = getFieldName($this_field, disp_mode);
879 * @var this_field_params Array temporary storage for the name/value of current field
881 var this_field_params = {};
883 if($this_field.is('.transformed')) {
884 transformation_fields = true;
887 * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
889 var is_null = $this_field.find('input:checkbox').is(':checked');
891 var addQuotes = true;
894 sql_query += ' `' + field_name + "`=NULL , ";
897 if($this_field.is(":not(.relation, .enum, .set, .bit)")) {
898 this_field_params[field_name] = $this_field.find('textarea').val();
899 if($this_field.is('.transformed')) {
900 $.extend(transform_fields, this_field_params);
902 } else if ($this_field.is('.bit')) {
903 this_field_params[field_name] = '0b' + $this_field.find('textarea').val();
905 } else if ($this_field.is('.set')) {
906 $test_element = $this_field.find('select');
907 this_field_params[field_name] = $test_element.map(function(){
908 return $(this).val();
911 // results from a drop-down
912 $test_element = $this_field.find('select');
913 if ($test_element.length != 0) {
914 this_field_params[field_name] = $test_element.val();
917 // results from Browse foreign value
918 $test_element = $this_field.find('span.curr_value');
919 if ($test_element.length != 0) {
920 this_field_params[field_name] = $test_element.text();
923 if($this_field.is('.relation')) {
924 $.extend(relation_fields, this_field_params);
927 if(where_clause.indexOf(field_name) > prev_index){
928 new_clause += '`' + window.parent.table + '`.' + '`' + field_name + "` = '" + this_field_params[field_name].replace(/'/g,"''") + "'" + ' AND ';
930 if (this_field_params[field_name] != $this_field.data('original_data')) {
931 if (addQuotes == true) {
932 sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "', ";
934 sql_query += ' `' + field_name + "`=" + this_field_params[field_name].replace(/'/g, "''") + ", ";
942 * update the where_clause, remove the last appended ' AND '
945 //Remove the last ',' appended in the above loop
946 sql_query = sql_query.replace(/,\s$/, '');
947 //Fix non-escaped backslashes
948 sql_query = sql_query.replace(/\\/g, '\\\\');
949 new_clause = new_clause.substring(0, new_clause.length-5);
950 new_clause = PMA_urlencode(new_clause);
951 sql_query += ' WHERE ' + PMA_urldecode(where_clause);
952 // Avoid updating more than one row in case there is no primary key
953 // (happened only for duplicate rows)
954 sql_query += ' LIMIT 1';
956 * @var rel_fields_list String, url encoded representation of {@link relations_fields}
958 var rel_fields_list = $.param(relation_fields);
961 * @var transform_fields_list String, url encoded representation of {@link transform_fields}
963 var transform_fields_list = $.param(transform_fields);
965 // if inline_edit is successful, we need to go back to default view
966 var $del_hide = $(this).parent();
967 var $chg_submit = $(this);
970 // Make the Ajax post after setting all parameters
972 * @var post_params Object containing parameters for the POST request
974 var post_params = {'ajax_request' : true,
975 'sql_query' : sql_query,
976 'disp_direction' : disp_mode,
977 'token' : window.parent.token,
978 'db' : window.parent.db,
979 'table' : window.parent.table,
980 'clause_is_unique' : nonunique,
981 'where_clause' : where_clause,
982 'rel_fields_list' : rel_fields_list,
983 'do_transformations' : transformation_fields,
984 'transform_fields_list' : transform_fields_list,
985 'relational_display' : relational_display,
987 'submit_type' : 'save'
990 $.post('tbl_replace.php', post_params, function(data) {
991 if(data.success == true) {
992 PMA_ajaxShowMessage(data.message);
993 if(disp_mode == 'vertical') {
994 $this_td.parents('tbody').find('tr').find('.where_clause:nth(' + this_td_index + ')').attr('value', new_clause);
997 $this_td.parent('tr').find('.where_clause').attr('value', new_clause);
999 // remove possible previous feedback message
1000 $('#result_query').remove();
1001 if (typeof data.sql_query != 'undefined') {
1003 $('#sqlqueryresults').prepend(data.sql_query);
1005 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode);
1007 PMA_ajaxShowMessage(data.error);
1011 // no posting was done but still need to display the row
1012 // in its previous format
1013 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '', disp_mode);
1015 }) // End After editing, clicking again should post data
1016 }, 'top.frame_content') // end $(document).ready()
1020 * Visually put back the row in the state it was before entering Inline edit
1022 * (when called in the situation where no posting was done, the data
1023 * parameter is empty)
1025 function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode) {
1027 // deleting the hide button. remove <br><br><a> tags
1028 $del_hide.find('a, br').remove();
1029 // append inline edit button.
1030 $del_hide.append($data_a.clone());
1032 // changing inline_edit_active to inline_edit_anchor
1033 $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
1035 // removing hover, marked and noclick classes
1036 $this_td.parent('tr').removeClass('noclick');
1037 if(disp_mode != 'vertical') {
1038 $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
1040 $this_td.parents('tbody').find('tr').find('td:eq(' + $this_td.index() + ')').removeClass('marked hover');
1043 $input_siblings.each(function() {
1044 // Inline edit post has been successful.
1045 $this_sibling = $(this);
1047 var is_null = $this_sibling.find('input:checkbox').is(':checked');
1049 $this_sibling.html('NULL');
1050 $this_sibling.addClass('null');
1052 $this_sibling.removeClass('null');
1053 if($this_sibling.is(':not(.relation, .enum, .set)')) {
1055 * @var new_html String containing value of the data field after edit
1057 var new_html = $this_sibling.find('textarea').val();
1059 if($this_sibling.is('.transformed')) {
1060 var field_name = getFieldName($this_sibling, disp_mode);
1061 if (typeof data.transformations != 'undefined') {
1062 $.each(data.transformations, function(key, value) {
1063 if(key == field_name) {
1064 if($this_sibling.is('.text_plain, .application_octetstream')) {
1068 var new_value = $this_sibling.find('textarea').val();
1069 new_html = $(value).append(new_value);
1079 $test_element = $this_sibling.find('select');
1080 if ($test_element.length != 0) {
1081 new_value = $test_element.val();
1083 $test_element = $this_sibling.find('span.curr_value');
1084 if ($test_element.length != 0) {
1085 new_value = $test_element.text();
1088 if($this_sibling.is('.relation')) {
1089 var field_name = getFieldName($this_sibling, disp_mode);
1090 if (typeof data.relations != 'undefined') {
1091 $.each(data.relations, function(key, value) {
1092 if(key == field_name) {
1093 new_html = $(value);
1098 } else if ($this_sibling.is('.enum')) {
1099 new_html = new_value;
1100 } else if ($this_sibling.is('.set')) {
1101 if (new_value != null) {
1102 $.each(new_value, function(key, value) {
1103 new_html = new_html + value + ',';
1105 new_html = new_html.substring(0, new_html.length-1);
1109 $this_sibling.html(new_html);
1115 * Starting from some th, change the class of all td under it
1117 function PMA_changeClassForColumn($this_th, newclass) {
1118 // index 0 is the th containing the big T
1119 var th_index = $this_th.index();
1120 var has_big_t = !$this_th.closest('tr').children(':first').hasClass('column_heading');
1121 // .eq() is zero-based
1125 var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
1126 if ($this_th.data('has_class_'+newclass)) {
1127 $tds.removeClass(newclass);
1128 $this_th.data('has_class_'+newclass, false);
1130 $tds.addClass(newclass);
1131 $this_th.data('has_class_'+newclass, true);
1135 $(document).ready(function() {
1137 $('.browse_foreign').live('click', function(e) {
1139 window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
1141 $anchor.addClass('browse_foreign_clicked');
1146 * vertical column highlighting in horizontal mode when hovering over the column header
1148 $('.column_heading.pointer').live('hover', function() {
1149 PMA_changeClassForColumn($(this), 'hover');
1153 * vertical column marking in horizontal mode when clicking the column header
1155 $('.column_heading.marker').live('click', function() {
1156 PMA_changeClassForColumn($(this), 'marked');