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
32 function getFieldName($this_field) {
34 var this_field_index = $this_field.index();
35 // ltr or rtl direction does not impact how the DOM was generated
36 // check if the action column in the left exist
37 var leftActionExist = !$('#table_results').find('th:first').hasClass('draggable');
38 // 5 columns to account for the checkbox, edit, appended inline edit, copy and delete anchors but index is zero-based so substract 4
39 var field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index - (leftActionExist ? 4 : 0)) + ') a').text();
40 // happens when just one row (headings contain no a)
41 if ("" == field_name) {
42 field_name = $('#table_results').find('thead').find('th:nth('+ (this_field_index - (leftActionExist ? 4 : 0)) + ')').text();
45 field_name = $.trim(field_name);
51 * The function that iterates over each row in the table_results and appends a
52 * new inline edit anchor to each table row.
55 function appendInlineAnchor() {
56 // TODO: remove two lines below if vertical display mode has been completely removed
57 var disp_mode = $("#top_direction_dropdown").val();
58 if (disp_mode != 'vertical') {
59 $('.edit_row_anchor').each(function() {
61 var $this_td = $(this);
62 $this_td.removeClass('edit_row_anchor');
64 var $cloned_anchor = $this_td.clone();
66 var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
67 if ($img_object.length != 0) {
68 var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
69 $img_object.attr('class', img_class);
70 $cloned_anchor.find('a').attr('href', '#');
71 var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
72 var $span = $cloned_anchor.find('a').find('span');
73 if ($edit_span.length > 0) {
74 $span.text(' ' + PMA_messages['strInlineEdit']);
75 $span.prepend($img_object);
78 $span.append($img_object);
81 // Only text is displayed. See $cfg['PropertiesIconic']
82 $cloned_anchor.find('a').attr('href', '#');
83 $cloned_anchor.find('a span').text(PMA_messages['strInlineEdit']);
85 // the link was too big so <input type="image"> is there
86 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
87 if ($img_object.length > 0) {
88 var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
89 $img_object.attr('class', img_class);
92 .find('.clickprevimage')
93 .text(' ' + PMA_messages['strInlineEdit']);
97 .addClass('inline_edit_anchor');
99 $this_td.after($cloned_anchor);
102 $('#resultsForm').find('thead, tbody').find('th').each(function() {
103 var $this_th = $(this);
104 if ($this_th.attr('colspan') == 4) {
105 $this_th.attr('colspan', '5');
116 * @description <p>Ajax scripts for sql and browse pages</p>
118 * Actions ajaxified here:
120 * <li>Retrieve results of an SQL query</li>
121 * <li>Paginate the results table</li>
122 * <li>Sort the results table</li>
123 * <li>Change table according to display options</li>
124 * <li>Inline editing of data</li>
127 * @name document.ready
130 $(document).ready(function() {
133 * Set a parameter for all Ajax queries made on this page. Don't let the
134 * web server serve cached pages
140 /* Hides the bookmarkoptions checkboxes when the bookmark label is empty */
141 $('input#bkm_label').keyup(function() {
142 $('input#id_bkm_all_users, input#id_bkm_replace')
144 .toggle($(this).attr('value').length > 0);
148 * Attach the {@link appendInlineAnchor} function to a custom event, which
149 * will be triggered manually everytime the table of results is reloaded
152 $("#sqlqueryresults").live('appendAnchor',function() {
153 appendInlineAnchor();
157 * Attach the {@link makegrid} function to a custom event, which will be
158 * triggered manually everytime the table of results is reloaded
161 $("#sqlqueryresults").live('makegrid', function() {
162 $('#table_results').makegrid();
166 * Attach the {@link refreshgrid} function to a custom event, which will be
167 * triggered manually everytime the table of results is manipulated (e.g., by inline edit)
170 $("#sqlqueryresults").live('refreshgrid', function() {
171 $('#table_results').refreshgrid();
175 * Trigger the appendAnchor event to prepare the first table for inline edit
176 * (see $GLOBALS['cfg']['AjaxEnable'])
178 * @name sqlqueryresults_trigger
180 $("#sqlqueryresults.ajax").trigger('appendAnchor');
183 * Append the "Show/Hide query box" message to the query input form
186 * @name appendToggleSpan
188 // do not add this link more than once
189 if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
190 $('<a id="togglequerybox"></a>')
191 .html(PMA_messages['strHideQueryBox'])
192 .appendTo("#sqlqueryform")
193 // initially hidden because at this point, nothing else
194 // appears under the link
197 // Attach the toggling of the query box visibility to a click
198 $("#togglequerybox").bind('click', function() {
200 $link.siblings().slideToggle("fast");
201 if ($link.text() == PMA_messages['strHideQueryBox']) {
202 $link.text(PMA_messages['strShowQueryBox']);
203 // cheap trick to add a spacer between the menu tabs
204 // and "Show query box"; feel free to improve!
205 $('#togglequerybox_spacer').remove();
206 $link.before('<br id="togglequerybox_spacer" />');
208 $link.text(PMA_messages['strHideQueryBox']);
210 // avoid default click action
216 * Ajax Event handler for 'SQL Query Submit'
218 * @see PMA_ajaxShowMessage()
219 * @see $cfg['AjaxEnable']
221 * @name sqlqueryform_submit
223 $("#sqlqueryform.ajax").live('submit', function(event) {
224 event.preventDefault();
227 if (! checkSqlQuery($form[0])) {
231 // remove any div containing a previous error message
232 $('.error').remove();
234 var $msgbox = PMA_ajaxShowMessage();
235 var $sqlqueryresults = $('#sqlqueryresults');
237 PMA_prepareForAjaxRequest($form);
239 $.post($form.attr('action'), $form.serialize() , function(data) {
240 if (data.success == true) {
241 // fade out previous messages, if any
242 $('.success').fadeOut();
243 $('.sqlquery_message').fadeOut();
244 // show a message that stays on screen
245 if (typeof data.sql_query != 'undefined') {
246 $('<div class="sqlquery_message"></div>')
247 .html(data.sql_query)
248 .insertBefore('#sqlqueryform');
249 // unnecessary div that came from data.sql_query
250 $('.notice').remove();
252 $('#sqlqueryform').before(data.message);
254 $sqlqueryresults.show();
255 // this happens if a USE command was typed
256 if (typeof data.reload != 'undefined') {
257 // Unbind the submit event before reloading. See bug #3295529
258 $("#sqlqueryform.ajax").die('submit');
259 $form.find('input[name=db]').val(data.db);
260 // need to regenerate the whole upper part
261 $form.find('input[name=ajax_request]').remove();
262 $form.append('<input type="hidden" name="reload" value="true" />');
263 $.post('db_sql.php', $form.serialize(), function(data) {
264 $('body').html(data);
265 }); // end inner post
268 else if (data.success == false ) {
269 // show an error message that stays on screen
270 $('#sqlqueryform').before(data.error);
271 $sqlqueryresults.hide();
274 // real results are returned
275 // fade out previous messages, if any
276 $('.success').fadeOut();
277 $('.sqlquery_message').fadeOut();
278 var $received_data = $(data);
279 var $zero_row_results = $received_data.find('textarea[name="sql_query"]');
280 // if zero rows are returned from the query execution
281 if ($zero_row_results.length > 0) {
282 $('#sqlquery').val($zero_row_results.val());
287 .trigger('appendAnchor')
288 .trigger('makegrid');
289 $('#togglequerybox').show();
290 if ($("#togglequerybox").siblings(":visible").length > 0) {
291 $("#togglequerybox").trigger('click');
296 PMA_ajaxRemoveMessage($msgbox);
299 }) // end SQL Query submit
302 * Ajax Event handlers for Paginating the results table
306 * Paginate when we click any of the navigation buttons
307 * (only if the element has the ajax class, see $cfg['AjaxEnable'])
309 * @name paginate_nav_button_click
310 * @uses PMA_ajaxShowMessage()
311 * @see $cfg['AjaxEnable']
313 $("input[name=navig].ajax").live('click', function(event) {
315 event.preventDefault();
317 var $msgbox = PMA_ajaxShowMessage();
320 * @var $form Object referring to the form element that paginates the results table
322 var $form = $(this).parent("form");
324 PMA_prepareForAjaxRequest($form);
326 $.post($form.attr('action'), $form.serialize(), function(data) {
327 $("#sqlqueryresults")
329 .trigger('appendAnchor')
330 .trigger('makegrid');
333 PMA_ajaxRemoveMessage($msgbox);
335 })// end Paginate results table
338 * Paginate results with Page Selector dropdown
340 * @name paginate_dropdown_change
341 * @see $cfg['AjaxEnable']
343 $("#pageselector").live('change', function(event) {
344 var $form = $(this).parent("form");
346 if ($(this).hasClass('ajax')) {
347 event.preventDefault();
349 var $msgbox = PMA_ajaxShowMessage();
351 $.post($form.attr('action'), $form.serialize() + '&ajax_request=true', function(data) {
352 $("#sqlqueryresults")
354 .trigger('appendAnchor')
355 .trigger('makegrid');
357 PMA_ajaxRemoveMessage($msgbox);
363 })// end Paginate results with Page Selector
366 * Ajax Event handler for sorting the results table
368 * @name table_results_sort_click
369 * @see $cfg['AjaxEnable']
371 $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
372 event.preventDefault();
374 var $msgbox = PMA_ajaxShowMessage();
378 $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
379 $("#sqlqueryresults")
381 .trigger('appendAnchor')
382 .trigger('makegrid');
383 PMA_ajaxRemoveMessage($msgbox);
385 })//end Sort results table
388 * Ajax Event handler for the display options
390 * @name displayOptionsForm_submit
391 * @see $cfg['AjaxEnable']
393 $("#displayOptionsForm.ajax").live('submit', function(event) {
394 event.preventDefault();
398 $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
399 $("#sqlqueryresults")
401 .trigger('appendAnchor')
402 .trigger('makegrid');
406 //end displayOptionsForm handler
409 * Ajax Event handlers for Inline Editing
413 * On click, replace the fields of current row with an input/textarea
415 * @name inline_edit_start
416 * @see PMA_ajaxShowMessage()
417 * @see getFieldName()
419 $(".inline_edit_anchor span a").live('click', function(event) {
421 event.preventDefault();
423 var $edit_td = $(this).parents('td');
424 $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');
426 // Adding submit and hide buttons to inline edit <td>.
427 // For "hide" button the original data to be restored is
428 // kept in the jQuery data element 'original_data' inside the <td>.
429 // Looping through all columns or rows, to find the required data and then storing it in an array.
431 var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
432 // Keep the original data preserved.
433 $data_a = $edit_td.children('span.nowrap').children('a').clone();
435 // Change the inline edit to save.
436 var $img_object = $this_children.find('img');
438 // If texts are displayed. See $cfg['PropertiesIconic']
439 if ($this_children.parent('a').find('span:contains("' + PMA_messages['strInlineEdit'] + '")').length > 0) {
440 $this_children.text(' ' + PMA_messages['strSave']);
442 $this_children.empty();
445 // If icons are displayed. See $cfg['PropertiesIconic']
446 if ($img_object.length > 0) {
447 $img_object.attr('title', PMA_messages['strSave']);
448 var img_class = $img_object.attr('class').replace(/b_inline_edit/,'b_save');
449 $img_object.attr('class', img_class);
450 $this_children.prepend($img_object);
453 // Clone the save link and change it to create the hide link.
454 var $hide_a = $edit_td.children('span.nowrap').children('a').clone().attr('id', 'hide');
455 var $hide_span = $hide_a.find('span');
456 var $img_object = $hide_a.find('span img');
458 // If texts are displayed. See $cfg['PropertiesIconic']
459 if ($hide_a.find('span:contains("' + PMA_messages['strSave'] + '")').length > 0) {
460 $hide_span.text(' ' + PMA_messages['strHide']);
465 // If icons are displayed. See $cfg['PropertiesIconic']
466 if ($img_object.length > 0) {
467 $img_object.attr('title', PMA_messages['strHide']);
468 var img_class = $img_object.attr('class').replace(/b_save/,'b_close');
469 $img_object.attr('class', img_class);
470 $hide_span.prepend($img_object);
473 // Add hide icon and/or text.
474 $edit_td.children('span.nowrap').append($('<br /><br />')).append($hide_a);
476 $('#table_results tbody tr td span a#hide').click(function() {
477 var $this_hide = $(this).parents('td');
479 var $this_span = $this_hide.find('span');
480 $this_span.find('a, br').remove();
481 $this_span.append($data_a.clone());
483 $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
484 $this_hide.parent().removeClass("hover noclick");
485 $this_hide.siblings().removeClass("hover");
487 var $input_siblings = $this_hide.parent('tr').find('.inline_edit');
489 $input_siblings.each(function() {
490 var $this_hide_siblings = $(this);
491 txt = $this_hide_siblings.data('original_data');
492 if($this_hide_siblings.children('span').children().length != 0) {
493 $this_hide_siblings.children('span').empty();
494 $this_hide_siblings.children('span').append(txt);
497 $(this).prev().prev().remove();
498 $(this).prev().remove();
502 $("#sqlqueryresults").trigger('refreshgrid');
505 // Initialize some variables
506 var this_row_index = $edit_td.parent().index();
507 var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
508 var where_clause = $edit_td.parent('tr').find('.where_clause').val();
510 $input_siblings.each(function() {
513 * @var data_value Current value of this field
515 var data_value = $(this).children('span').html();
517 // We need to retrieve the value from the server for truncated/relation fields
518 // Find the field name
521 * @var this_field Object referring to this field (<td>)
523 var $this_field = $(this);
525 * @var this_field_span Object referring to this field's child (<span>)
527 var $this_field_span = $(this).children('span');
529 * @var field_name String containing the name of this field.
530 * @see getFieldName()
532 var field_name = getFieldName($this_field);
534 * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
536 var relation_curr_value = $this_field.find('a').text();
538 * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
539 * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
541 var relation_key_or_display_column = $this_field.find('a').attr('title');
543 * @var curr_value String current value of the field (for fields that are of type enum or set).
545 var curr_value = $this_field_span.text();
547 if($this_field.is(':not(.not_null)')){
548 // add a checkbox to mark null for all the field that are nullable.
549 $this_field_span.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
550 // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
551 if($this_field.is('.null')) {
552 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
555 // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
556 if ($this_field.is('.enum, .set')) {
557 $this_field.find('select').live('change', function(e) {
558 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
560 } else if ($this_field.is('.relation')) {
561 $this_field.find('select').live('change', function(e) {
562 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
564 $this_field.find('.browse_foreign').live('click', function(e) {
565 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
568 $this_field.find('textarea').live('keypress', function(e) {
569 // FF errorneously triggers for modifier keys such as tab (bug #3357837)
571 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
576 // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
577 $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
578 if ($this_field.is('.enum')) {
579 $this_field.find('select').attr('value', '');
580 } else if ($this_field.is('.set')) {
581 $this_field.find('select').find('option').each(function() {
582 var $option = $(this);
583 $option.attr('selected', false);
585 } else if ($this_field.is('.relation')) {
586 // if the dropdown is there to select the foreign value
587 if ($this_field.find('select').length > 0) {
588 $this_field.find('select').attr('value', '');
589 // if foriegn value is selected by browsing foreing values
591 $this_field.find('span.curr_value').empty();
594 $this_field.find('textarea').val('');
599 $this_field_span.html('<div class="null_div"></div>');
602 // In each input sibling, wrap the current value in a textarea
603 // and store the current value in a hidden span
604 if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
605 // handle non-truncated, non-transformed, non-relation values
607 value = data_value.replace("<br>", "\n");
608 // We don't need to get any more data, just wrap the value
609 $this_field_span.append('<textarea>' + value + '</textarea>');
610 $this_field.data('original_data', data_value);
612 else if($this_field.is('.truncated, .transformed')) {
614 //handle truncated/transformed values values
617 * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data
619 var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);
621 // Make the Ajax call and get the data, wrap it and insert it
623 'token' : window.parent.token,
624 'db' : window.parent.db,
625 'ajax_request' : true,
626 'sql_query' : sql_query,
629 if(data.success == true) {
630 $this_field_span.append('<textarea>'+data.value+'</textarea>');
631 $this_field.data('original_data', data_value);
632 $("#sqlqueryresults").trigger('refreshgrid');
635 PMA_ajaxShowMessage(data.error);
639 else if($this_field.is('.relation')) {
644 * @var post_params Object containing parameters for the POST request
647 'ajax_request' : true,
648 'get_relational_values' : true,
649 'db' : window.parent.db,
650 'table' : window.parent.table,
651 'column' : field_name,
652 'token' : window.parent.token,
653 'curr_value' : relation_curr_value,
654 'relation_key_or_display_column' : relation_key_or_display_column
657 $.post('sql.php', post_params, function(data) {
658 $this_field_span.append(data.dropdown);
659 $this_field.data('original_data', data_value);
660 $("#sqlqueryresults").trigger('refreshgrid');
663 else if($this_field.is('.enum')) {
668 * @var post_params Object containing parameters for the POST request
671 'ajax_request' : true,
672 'get_enum_values' : true,
673 'db' : window.parent.db,
674 'table' : window.parent.table,
675 'column' : field_name,
676 'token' : window.parent.token,
677 'curr_value' : curr_value
679 $.post('sql.php', post_params, function(data) {
680 $this_field_span.append(data.dropdown);
681 $this_field.data('original_data', data_value);
682 $("#sqlqueryresults").trigger('refreshgrid');
685 else if($this_field.is('.set')) {
690 * @var post_params Object containing parameters for the POST request
693 'ajax_request' : true,
694 'get_set_values' : true,
695 'db' : window.parent.db,
696 'table' : window.parent.table,
697 'column' : field_name,
698 'token' : window.parent.token,
699 'curr_value' : curr_value
702 $.post('sql.php', post_params, function(data) {
703 $this_field_span.append(data.select);
704 $this_field.data('original_data', data_value);
705 $("#sqlqueryresults").trigger('refreshgrid');
708 else if($this_field.is('.null')) {
710 $this_field_span.append('<textarea></textarea>');
711 $this_field.data('original_data', 'NULL');
716 $("#sqlqueryresults").trigger('refreshgrid');
718 }) // End On click, replace the current field with an input/textarea
721 * After editing, clicking again should post data
724 * @name inline_edit_save
725 * @see PMA_ajaxShowMessage()
726 * @see getFieldName()
728 $(".inline_edit_active span a").live('click', function(event) {
731 event.preventDefault();
734 * @var $this_td Object referring to the td containing the
735 * "Inline Edit" link that was clicked to save the row that is
739 var $this_td = $(this).parents('td');
740 var $test_element = ''; // to test the presence of a element
742 // Initialize variables
743 var $input_siblings = $this_td.parent('tr').find('.inline_edit');
744 var where_clause = $this_td.parent('tr').find('.where_clause').val();
747 * @var nonunique Boolean, whether this row is unique or not
749 if($this_td.is('.nonunique')) {
756 // Collect values of all fields to submit, we don't know which changed
758 * @var relation_fields Array containing the name/value pairs of relational fields
760 var relation_fields = {};
762 * @var relational_display string 'K' if relational key, 'D' if relational display column
764 var relational_display = $("#relational_display_K").attr('checked') ? 'K' : 'D';
766 * @var transform_fields Array containing the name/value pairs for transformed fields
768 var transform_fields = {};
770 * @var transformation_fields Boolean, if there are any transformed fields in this row
772 var transformation_fields = false;
775 * @var sql_query String containing the SQL query to update this row
777 var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
779 var need_to_post = false;
784 $input_siblings.each(function() {
787 * @var this_field Object referring to this field (<td>)
789 var $this_field = $(this);
792 * @var field_name String containing the name of this field.
793 * @see getFieldName()
795 var field_name = getFieldName($this_field);
798 * @var this_field_params Array temporary storage for the name/value of current field
800 var this_field_params = {};
802 if($this_field.is('.transformed')) {
803 transformation_fields = true;
806 * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
808 var is_null = $this_field.find('input:checkbox').is(':checked');
810 var addQuotes = true;
813 sql_query += ' `' + field_name + "`=NULL , ";
816 if($this_field.is(":not(.relation, .enum, .set, .bit)")) {
817 this_field_params[field_name] = $this_field.find('textarea').val();
818 if($this_field.is('.transformed')) {
819 $.extend(transform_fields, this_field_params);
821 } else if ($this_field.is('.bit')) {
822 this_field_params[field_name] = '0b' + $this_field.find('textarea').val();
824 } else if ($this_field.is('.set')) {
825 $test_element = $this_field.find('select');
826 this_field_params[field_name] = $test_element.map(function(){
827 return $(this).val();
830 // results from a drop-down
831 $test_element = $this_field.find('select');
832 if ($test_element.length != 0) {
833 this_field_params[field_name] = $test_element.val();
836 // results from Browse foreign value
837 $test_element = $this_field.find('span.curr_value');
838 if ($test_element.length != 0) {
839 this_field_params[field_name] = $test_element.text();
842 if($this_field.is('.relation')) {
843 $.extend(relation_fields, this_field_params);
846 if(where_clause.indexOf(field_name) > prev_index){
847 new_clause += '`' + window.parent.table + '`.' + '`' + field_name + "` = '" + this_field_params[field_name].replace(/'/g,"''") + "'" + ' AND ';
849 if (this_field_params[field_name] != $this_field.data('original_data')) {
850 if (addQuotes == true) {
851 sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "', ";
853 sql_query += ' `' + field_name + "`=" + this_field_params[field_name].replace(/'/g, "''") + ", ";
861 * update the where_clause, remove the last appended ' AND '
864 //Remove the last ',' appended in the above loop
865 sql_query = sql_query.replace(/,\s$/, '');
866 //Fix non-escaped backslashes
867 sql_query = sql_query.replace(/\\/g, '\\\\');
868 new_clause = new_clause.substring(0, new_clause.length-5);
869 new_clause = PMA_urlencode(new_clause);
870 sql_query += ' WHERE ' + PMA_urldecode(where_clause);
871 // Avoid updating more than one row in case there is no primary key
872 // (happened only for duplicate rows)
873 sql_query += ' LIMIT 1';
875 * @var rel_fields_list String, url encoded representation of {@link relations_fields}
877 var rel_fields_list = $.param(relation_fields);
880 * @var transform_fields_list String, url encoded representation of {@link transform_fields}
882 var transform_fields_list = $.param(transform_fields);
884 // if inline_edit is successful, we need to go back to default view
885 var $del_hide = $(this).parent();
886 var $chg_submit = $(this);
889 // Make the Ajax post after setting all parameters
891 * @var post_params Object containing parameters for the POST request
893 var post_params = {'ajax_request' : true,
894 'sql_query' : sql_query,
895 'token' : window.parent.token,
896 'db' : window.parent.db,
897 'table' : window.parent.table,
898 'clause_is_unique' : nonunique,
899 'where_clause' : where_clause,
900 'rel_fields_list' : rel_fields_list,
901 'do_transformations' : transformation_fields,
902 'transform_fields_list' : transform_fields_list,
903 'relational_display' : relational_display,
905 'submit_type' : 'save'
908 $.post('tbl_replace.php', post_params, function(data) {
909 if(data.success == true) {
910 PMA_ajaxShowMessage(data.message);
911 $this_td.parent('tr').find('.where_clause').attr('value', new_clause);
912 // remove possible previous feedback message
913 $('#result_query').remove();
914 if (typeof data.sql_query != 'undefined') {
916 $('#sqlqueryresults').prepend(data.sql_query);
918 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data);
920 PMA_ajaxShowMessage(data.error);
924 // no posting was done but still need to display the row
925 // in its previous format
926 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '');
928 }) // End After editing, clicking again should post data
931 * Ajax Event for table row change
933 $("#resultsForm.ajax .mult_submit[value=edit]").live('click', function(event){
934 event.preventDefault();
936 /*Check whether atleast one row is selected for change*/
937 if ($("#table_results tbody tr, #table_results tbody tr td").hasClass("marked")) {
938 var div = $('<div id="change_row_dialog"></div>');
941 * @var button_options Object that stores the options passed to jQueryUI
944 var button_options = {};
945 // in the following function we need to use $(this)
946 button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
948 var button_options_error = {};
949 button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
950 var $form = $("#resultsForm");
951 var $msgbox = PMA_ajaxShowMessage();
953 $.get( $form.attr('action'), $form.serialize()+"&ajax_request=true&submit_mult=row_edit", function(data) {
954 //in the case of an error, show the error message returned.
955 if (data.success != undefined && data.success == false) {
959 title: PMA_messages['strChangeTbl'],
962 open: PMA_verifyTypeOfAllColumns,
963 buttons : button_options_error
964 })// end dialog options
969 title: PMA_messages['strChangeTbl'],
972 open: PMA_verifyTypeOfAllColumns,
973 buttons : button_options
975 //Remove the top menu container from the dialog
976 .find("#topmenucontainer").hide()
977 ; // end dialog options
978 $(".insertRowTable").addClass("ajax");
979 $("#buttonYes").addClass("ajax");
981 PMA_ajaxRemoveMessage($msgbox);
984 PMA_ajaxShowMessage(PMA_messages['strNoRowSelected']);
989 * Click action for "Go" button in ajax dialog insertForm -> insertRowTable
991 $("#insertForm .insertRowTable.ajax input[value=Go]").live('click', function(event) {
992 event.preventDefault();
994 * @var the_form object referring to the insert form
996 var $form = $("#insertForm");
997 PMA_prepareForAjaxRequest($form);
998 //User wants to submit the form
999 $.post($form.attr('action'), $form.serialize(), function(data) {
1000 if (data.success == true) {
1001 PMA_ajaxShowMessage(data.message);
1002 if ($("#pageselector").length != 0) {
1003 $("#pageselector").trigger('change');
1005 $("input[name=navig].ajax").trigger('click');
1009 PMA_ajaxShowMessage(data.error);
1010 $("#table_results tbody tr.marked .multi_checkbox " +
1011 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1012 $("#table_results tbody tr.marked .multi_checkbox " +
1013 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1014 $("#table_results tbody tr" +
1015 ", #table_results tbody tr td").removeClass("marked");
1017 if ($("#change_row_dialog").length > 0) {
1018 $("#change_row_dialog").dialog("close").remove();
1020 /**Update the row count at the tableForm*/
1021 $("#result_query").remove();
1022 $("#sqlqueryresults").prepend(data.sql_query);
1023 $("#result_query .notice").remove();
1024 $("#result_query").prepend((data.message));
1026 }) // end insert table button "Go"
1028 /**$("#buttonYes.ajax").live('click'
1029 * Click action for #buttonYes button in ajax dialog insertForm
1031 $("#buttonYes.ajax").live('click', function(event){
1032 event.preventDefault();
1034 * @var the_form object referring to the insert form
1036 var $form = $("#insertForm");
1037 /**Get the submit type and the after insert type in the form*/
1038 var selected_submit_type = $("#insertForm").find("#actions_panel .control_at_footer option:selected").attr('value');
1039 var selected_after_insert = $("#insertForm").find("#actions_panel select[name=after_insert] option:selected").attr('value');
1040 $("#result_query").remove();
1041 PMA_prepareForAjaxRequest($form);
1042 //User wants to submit the form
1043 $.post($form.attr('action'), $form.serialize() , function(data) {
1044 if (data.success == true) {
1045 PMA_ajaxShowMessage(data.message);
1046 if (selected_submit_type == "showinsert") {
1047 $("#sqlqueryresults").prepend(data.sql_query);
1048 $("#result_query .notice").remove();
1049 $("#result_query").prepend(data.message);
1050 $("#table_results tbody tr.marked .multi_checkbox " +
1051 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1052 $("#table_results tbody tr.marked .multi_checkbox " +
1053 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1054 $("#table_results tbody tr" +
1055 ", #table_results tbody tr td").removeClass("marked");
1057 if ($("#pageselector").length != 0) {
1058 $("#pageselector").trigger('change');
1060 $("input[name=navig].ajax").trigger('click');
1062 $("#result_query").remove();
1063 $("#sqlqueryresults").prepend(data.sql_query);
1064 $("#result_query .notice").remove();
1065 $("#result_query").prepend((data.message));
1068 PMA_ajaxShowMessage(data.error);
1069 $("#table_results tbody tr.marked .multi_checkbox " +
1070 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1071 $("#table_results tbody tr.marked .multi_checkbox " +
1072 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1073 $("#table_results tbody tr" +
1074 ", #table_results tbody tr td").removeClass("marked");
1076 if ($("#change_row_dialog").length > 0) {
1077 $("#change_row_dialog").dialog("close").remove();
1082 }, 'top.frame_content') // end $(document).ready()
1086 * Visually put back the row in the state it was before entering Inline edit
1088 * (when called in the situation where no posting was done, the data
1089 * parameter is empty)
1091 function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data) {
1093 // deleting the hide button. remove <br><br><a> tags
1094 $del_hide.find('a, br').remove();
1095 // append inline edit button.
1096 $del_hide.append($data_a.clone());
1098 // changing inline_edit_active to inline_edit_anchor
1099 $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
1101 // removing hover, marked and noclick classes
1102 $this_td.parent('tr').removeClass('noclick');
1103 $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
1105 $input_siblings.each(function() {
1106 // Inline edit post has been successful.
1107 $this_sibling = $(this);
1108 $this_sibling_span = $(this).children('span');
1110 var is_null = $this_sibling.find('input:checkbox').is(':checked');
1112 $this_sibling_span.html('NULL');
1113 $this_sibling.addClass('null');
1115 $this_sibling.removeClass('null');
1116 if($this_sibling.is(':not(.relation, .enum, .set)')) {
1118 * @var new_html String containing value of the data field after edit
1120 var new_html = $this_sibling.find('textarea').val();
1122 if($this_sibling.is('.transformed')) {
1123 var field_name = getFieldName($this_sibling);
1124 if (typeof data.transformations != 'undefined') {
1125 $.each(data.transformations, function(key, value) {
1126 if(key == field_name) {
1127 if($this_sibling.is('.text_plain, .application_octetstream')) {
1131 var new_value = $this_sibling.find('textarea').val();
1132 new_html = $(value).append(new_value);
1142 $test_element = $this_sibling.find('select');
1143 if ($test_element.length != 0) {
1144 new_value = $test_element.val();
1146 $test_element = $this_sibling.find('span.curr_value');
1147 if ($test_element.length != 0) {
1148 new_value = $test_element.text();
1151 if($this_sibling.is('.relation')) {
1152 var field_name = getFieldName($this_sibling);
1153 if (typeof data.relations != 'undefined') {
1154 $.each(data.relations, function(key, value) {
1155 if(key == field_name) {
1156 new_html = $(value);
1161 } else if ($this_sibling.is('.enum')) {
1162 new_html = new_value;
1163 } else if ($this_sibling.is('.set')) {
1164 if (new_value != null) {
1165 $.each(new_value, function(key, value) {
1166 new_html = new_html + value + ',';
1168 new_html = new_html.substring(0, new_html.length-1);
1172 $this_sibling_span.html(new_html);
1177 $("#sqlqueryresults").trigger('refreshgrid');
1181 * Starting from some th, change the class of all td under it.
1182 * If isAddClass is specified, it will be used to determine whether to add or remove the class.
1184 function PMA_changeClassForColumn($this_th, newclass, isAddClass) {
1185 // index 0 is the th containing the big T
1186 var th_index = $this_th.index();
1187 var has_big_t = !$this_th.closest('tr').children(':first').hasClass('column_heading');
1188 // .eq() is zero-based
1192 var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
1193 if (isAddClass == undefined) {
1194 $tds.toggleClass(newclass);
1196 $tds.toggleClass(newclass, isAddClass);
1200 $(document).ready(function() {
1202 $('.browse_foreign').live('click', function(e) {
1204 window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
1206 $anchor.addClass('browse_foreign_clicked');
1211 * vertical column highlighting in horizontal mode when hovering over the column header
1213 $('.column_heading.pointer').live('hover', function(e) {
1214 PMA_changeClassForColumn($(this), 'hover', e.type == 'mouseenter');
1218 * vertical column marking in horizontal mode when clicking the column header
1220 $('.column_heading.marker').live('click', function() {
1221 PMA_changeClassForColumn($(this), 'marked');
1225 * create resizable table
1227 $("#sqlqueryresults").trigger('makegrid');
1233 function createProfilingChart() {
1234 if ($('#profilingchart').length == 0) {
1238 var cdata = new Array();
1239 $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) {
1240 cdata.push([key,parseFloat(value)]);
1243 // Prevent the user from seeing the JSON code
1244 $('div#profilingchart').html('').show();
1248 renderTo: 'profilingchart',
1249 backgroundColor: $('#sqlqueryresults fieldset').css('background-color')
1251 title: { text:'', margin:0 },
1254 name: 'Query execution time',
1259 allowPointSelect: true,
1264 formatter: function() {
1265 return '<b>'+ this.point.name +'</b><br/>'+ Highcharts.numberFormat(this.percentage, 2) +' %';
1271 formatter: function() { return '<b>'+ this.point.name +'</b><br/>'+this.y+'s<br/>('+Highcharts.numberFormat(this.percentage, 2) +' %)'; }