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();
59 if (disp_mode != 'vertical') {
60 $('.edit_row_anchor').each(function() {
62 var $this_td = $(this);
63 $this_td.removeClass('edit_row_anchor');
65 var $cloned_anchor = $this_td.clone();
67 var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
68 if ($img_object.length != 0) {
69 $img_object.removeClass('ic_b_edit');
70 $img_object.addClass('ic_b_inline_edit');
72 $cloned_anchor.find('a').attr('href', '#');
73 var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
74 var $span = $cloned_anchor.find('a').find('span');
75 if ($edit_span.length > 0) {
76 $span.text(' ' + PMA_messages['strInlineEdit']);
77 $span.prepend($img_object);
80 $span.append($img_object);
83 // Only text is displayed. See $cfg['PropertiesIconic']
84 $cloned_anchor.find('a').attr('href', '#');
85 $cloned_anchor.find('a span').text(PMA_messages['strInlineEdit']);
87 // the link was too big so <input type="image"> is there
88 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
89 if ($img_object.length > 0) {
90 $img_object.removeClass('ic_b_edit');
91 $img_object.addClass('ic_b_inline_edit');
94 .find('.clickprevimage')
95 .text(' ' + PMA_messages['strInlineEdit']);
99 .addClass('inline_edit_anchor');
101 $this_td.after($cloned_anchor);
104 $('#resultsForm').find('thead, tbody').find('th').each(function() {
105 var $this_th = $(this);
106 if ($this_th.attr('colspan') == 4) {
107 $this_th.attr('colspan', '5');
118 * @description <p>Ajax scripts for sql and browse pages</p>
120 * Actions ajaxified here:
122 * <li>Retrieve results of an SQL query</li>
123 * <li>Paginate the results table</li>
124 * <li>Sort the results table</li>
125 * <li>Change table according to display options</li>
126 * <li>Inline editing of data</li>
129 * @name document.ready
132 $(document).ready(function() {
135 * Set a parameter for all Ajax queries made on this page. Don't let the
136 * web server serve cached pages
142 /* Hides the bookmarkoptions checkboxes when the bookmark label is empty */
143 $('input#bkm_label').keyup(function() {
144 $('input#id_bkm_all_users, input#id_bkm_replace')
146 .toggle($(this).attr('value').length > 0);
150 * Attach the {@link appendInlineAnchor} function to a custom event, which
151 * will be triggered manually everytime the table of results is reloaded
154 $("#sqlqueryresults").live('appendAnchor',function() {
155 appendInlineAnchor();
159 * Attach the {@link makegrid} function to a custom event, which will be
160 * triggered manually everytime the table of results is reloaded
163 $("#sqlqueryresults").live('makegrid', function() {
164 $('#table_results').makegrid();
168 * Attach the {@link refreshgrid} function to a custom event, which will be
169 * triggered manually everytime the table of results is manipulated (e.g., by inline edit)
172 $("#sqlqueryresults").live('refreshgrid', function() {
173 $('#table_results').refreshgrid();
177 * Trigger the appendAnchor event to prepare the first table for inline edit
178 * (see $GLOBALS['cfg']['AjaxEnable'])
180 * @name sqlqueryresults_trigger
182 $("#sqlqueryresults.ajax").trigger('appendAnchor');
185 * Append the "Show/Hide query box" message to the query input form
188 * @name appendToggleSpan
190 // do not add this link more than once
191 if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
192 $('<a id="togglequerybox"></a>')
193 .html(PMA_messages['strHideQueryBox'])
194 .appendTo("#sqlqueryform")
195 // initially hidden because at this point, nothing else
196 // appears under the link
199 // Attach the toggling of the query box visibility to a click
200 $("#togglequerybox").bind('click', function() {
202 $link.siblings().slideToggle("fast");
203 if ($link.text() == PMA_messages['strHideQueryBox']) {
204 $link.text(PMA_messages['strShowQueryBox']);
205 // cheap trick to add a spacer between the menu tabs
206 // and "Show query box"; feel free to improve!
207 $('#togglequerybox_spacer').remove();
208 $link.before('<br id="togglequerybox_spacer" />');
210 $link.text(PMA_messages['strHideQueryBox']);
212 // avoid default click action
218 * Ajax Event handler for 'SQL Query Submit'
220 * @see PMA_ajaxShowMessage()
221 * @see $cfg['AjaxEnable']
223 * @name sqlqueryform_submit
225 $("#sqlqueryform.ajax").live('submit', function(event) {
226 event.preventDefault();
229 if (! checkSqlQuery($form[0])) {
233 // remove any div containing a previous error message
234 $('.error').remove();
236 var $msgbox = PMA_ajaxShowMessage();
237 var $sqlqueryresults = $('#sqlqueryresults');
239 PMA_prepareForAjaxRequest($form);
241 $.post($form.attr('action'), $form.serialize() , function(data) {
242 if (data.success == true) {
243 // fade out previous messages, if any
244 $('.success').fadeOut();
245 $('.sqlquery_message').fadeOut();
246 // show a message that stays on screen
247 if (typeof data.sql_query != 'undefined') {
248 $('<div class="sqlquery_message"></div>')
249 .html(data.sql_query)
250 .insertBefore('#sqlqueryform');
251 // unnecessary div that came from data.sql_query
252 $('.notice').remove();
254 $('#sqlqueryform').before(data.message);
256 $sqlqueryresults.show();
257 // this happens if a USE command was typed
258 if (typeof data.reload != 'undefined') {
259 // Unbind the submit event before reloading. See bug #3295529
260 $("#sqlqueryform.ajax").die('submit');
261 $form.find('input[name=db]').val(data.db);
262 // need to regenerate the whole upper part
263 $form.find('input[name=ajax_request]').remove();
264 $form.append('<input type="hidden" name="reload" value="true" />');
265 $.post('db_sql.php', $form.serialize(), function(data) {
266 $('body').html(data);
267 }); // end inner post
270 else if (data.success == false ) {
271 // show an error message that stays on screen
272 $('#sqlqueryform').before(data.error);
273 $sqlqueryresults.hide();
276 // real results are returned
277 // fade out previous messages, if any
278 $('.success').fadeOut();
279 $('.sqlquery_message').fadeOut();
280 var $received_data = $(data);
281 var $zero_row_results = $received_data.find('textarea[name="sql_query"]');
282 // if zero rows are returned from the query execution
283 if ($zero_row_results.length > 0) {
284 $('#sqlquery').val($zero_row_results.val());
289 .trigger('appendAnchor')
290 .trigger('makegrid');
291 $('#togglequerybox').show();
292 if ($("#togglequerybox").siblings(":visible").length > 0) {
293 $("#togglequerybox").trigger('click');
298 PMA_ajaxRemoveMessage($msgbox);
301 }) // end SQL Query submit
304 * Ajax Event handlers for Paginating the results table
308 * Paginate when we click any of the navigation buttons
309 * (only if the element has the ajax class, see $cfg['AjaxEnable'])
311 * @name paginate_nav_button_click
312 * @uses PMA_ajaxShowMessage()
313 * @see $cfg['AjaxEnable']
315 $("input[name=navig].ajax").live('click', function(event) {
317 event.preventDefault();
319 var $msgbox = PMA_ajaxShowMessage();
322 * @var $form Object referring to the form element that paginates the results table
324 var $form = $(this).parent("form");
326 PMA_prepareForAjaxRequest($form);
328 $.post($form.attr('action'), $form.serialize(), function(data) {
329 $("#sqlqueryresults")
331 .trigger('appendAnchor')
332 .trigger('makegrid');
335 PMA_ajaxRemoveMessage($msgbox);
337 })// end Paginate results table
340 * Paginate results with Page Selector dropdown
342 * @name paginate_dropdown_change
343 * @see $cfg['AjaxEnable']
345 $("#pageselector").live('change', function(event) {
346 var $form = $(this).parent("form");
348 if ($(this).hasClass('ajax')) {
349 event.preventDefault();
351 var $msgbox = PMA_ajaxShowMessage();
353 $.post($form.attr('action'), $form.serialize() + '&ajax_request=true', function(data) {
354 $("#sqlqueryresults")
356 .trigger('appendAnchor')
357 .trigger('makegrid');
359 PMA_ajaxRemoveMessage($msgbox);
365 })// end Paginate results with Page Selector
368 * Ajax Event handler for sorting the results table
370 * @name table_results_sort_click
371 * @see $cfg['AjaxEnable']
373 $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
374 event.preventDefault();
376 var $msgbox = PMA_ajaxShowMessage();
380 $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
381 $("#sqlqueryresults")
383 .trigger('appendAnchor')
384 .trigger('makegrid');
385 PMA_ajaxRemoveMessage($msgbox);
387 })//end Sort results table
390 * Ajax Event handler for the display options
392 * @name displayOptionsForm_submit
393 * @see $cfg['AjaxEnable']
395 $("#displayOptionsForm.ajax").live('submit', function(event) {
396 event.preventDefault();
400 $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
401 $("#sqlqueryresults")
403 .trigger('appendAnchor')
404 .trigger('makegrid');
408 //end displayOptionsForm handler
411 * Ajax Event handlers for Inline Editing
415 * On click, replace the fields of current row with an input/textarea
417 * @name inline_edit_start
418 * @see PMA_ajaxShowMessage()
419 * @see getFieldName()
421 $(".inline_edit_anchor span a").live('click', function(event) {
423 event.preventDefault();
425 var $edit_td = $(this).parents('td');
426 $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');
428 // Adding submit and hide buttons to inline edit <td>.
429 // For "hide" button the original data to be restored is
430 // kept in the jQuery data element 'original_data' inside the <td>.
431 // Looping through all columns or rows, to find the required data and then storing it in an array.
433 var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
434 // Keep the original data preserved.
435 $data_a = $edit_td.children('span.nowrap').children('a').clone();
437 // Change the inline edit to save.
438 var $img_object = $this_children.find('img');
440 // If texts are displayed. See $cfg['PropertiesIconic']
441 if ($this_children.parent('a').find('span:contains("' + PMA_messages['strInlineEdit'] + '")').length > 0) {
442 $this_children.text(' ' + PMA_messages['strSave']);
444 $this_children.empty();
447 // If icons are displayed. See $cfg['PropertiesIconic']
448 if ($img_object.length > 0) {
449 $img_object.attr('title', PMA_messages['strSave']);
450 $img_object.removeClass('ic_b_inline_edit');
451 $img_object.addClass('ic_b_save');
452 $this_children.prepend($img_object);
455 // Clone the save link and change it to create the hide link.
456 var $hide_a = $edit_td.children('span.nowrap').children('a').clone().attr('id', 'hide');
457 var $hide_span = $hide_a.find('span');
458 var $img_object = $hide_a.find('span img');
460 // If texts are displayed. See $cfg['PropertiesIconic']
461 if ($hide_a.find('span:contains("' + PMA_messages['strSave'] + '")').length > 0) {
462 $hide_span.text(' ' + PMA_messages['strHide']);
467 // If icons are displayed. See $cfg['PropertiesIconic']
468 if ($img_object.length > 0) {
469 $img_object.attr('title', PMA_messages['strHide']);
470 $img_object.removeClass('ic_b_save');
471 $img_object.addClass('ic_b_close');
472 $hide_span.prepend($img_object);
475 // Add hide icon and/or text.
476 $edit_td.children('span.nowrap').append($('<br /><br />')).append($hide_a);
478 $('#table_results tbody tr td span a#hide').click(function() {
479 var $this_hide = $(this).parents('td');
481 var $this_span = $this_hide.find('span');
482 $this_span.find('a, br').remove();
483 $this_span.append($data_a.clone());
485 $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
486 $this_hide.parent().removeClass("hover noclick");
487 $this_hide.siblings().removeClass("hover");
489 var $input_siblings = $this_hide.parent('tr').find('.inline_edit');
491 $input_siblings.each(function() {
492 var $this_hide_siblings = $(this);
493 txt = $this_hide_siblings.data('original_data');
494 if($this_hide_siblings.children('span').children().length != 0) {
495 $this_hide_siblings.children('span').empty();
496 $this_hide_siblings.children('span').append(txt);
499 $(this).prev().prev().remove();
500 $(this).prev().remove();
504 $("#sqlqueryresults").trigger('refreshgrid');
507 // Initialize some variables
508 var this_row_index = $edit_td.parent().index();
509 var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
510 var where_clause = $edit_td.parent('tr').find('.where_clause').val();
512 $input_siblings.each(function() {
515 * @var data_value Current value of this field
517 var data_value = $(this).children('span').html();
519 // We need to retrieve the value from the server for truncated/relation fields
520 // Find the field name
523 * @var this_field Object referring to this field (<td>)
525 var $this_field = $(this);
527 * @var this_field_span Object referring to this field's child (<span>)
529 var $this_field_span = $(this).children('span');
531 * @var field_name String containing the name of this field.
532 * @see getFieldName()
534 var field_name = getFieldName($this_field);
536 * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
538 var relation_curr_value = $this_field.find('a').text();
540 * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
541 * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
543 var relation_key_or_display_column = $this_field.find('a').attr('title');
545 * @var curr_value String current value of the field (for fields that are of type enum or set).
547 var curr_value = $this_field_span.text();
549 if($this_field.is(':not(.not_null)')){
550 // add a checkbox to mark null for all the field that are nullable.
551 $this_field_span.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
552 // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
553 if($this_field.is('.null')) {
554 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
557 // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
558 if ($this_field.is('.enum, .set')) {
559 $this_field.find('select').live('change', function(e) {
560 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
562 } else if ($this_field.is('.relation')) {
563 $this_field.find('select').live('change', function(e) {
564 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
566 $this_field.find('.browse_foreign').live('click', function(e) {
567 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
570 $this_field.find('textarea').live('keypress', function(e) {
571 // FF errorneously triggers for modifier keys such as tab (bug #3357837)
573 $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
578 // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
579 $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
580 if ($this_field.is('.enum')) {
581 $this_field.find('select').attr('value', '');
582 } else if ($this_field.is('.set')) {
583 $this_field.find('select').find('option').each(function() {
584 var $option = $(this);
585 $option.attr('selected', false);
587 } else if ($this_field.is('.relation')) {
588 // if the dropdown is there to select the foreign value
589 if ($this_field.find('select').length > 0) {
590 $this_field.find('select').attr('value', '');
591 // if foriegn value is selected by browsing foreing values
593 $this_field.find('span.curr_value').empty();
596 $this_field.find('textarea').val('');
601 $this_field_span.html('<div class="null_div"></div>');
604 // In each input sibling, wrap the current value in a textarea
605 // and store the current value in a hidden span
606 if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
607 // handle non-truncated, non-transformed, non-relation values
609 value = data_value.replace("<br>", "\n");
610 // We don't need to get any more data, just wrap the value
611 $this_field_span.append('<textarea>' + value + '</textarea>');
612 $this_field.data('original_data', data_value);
614 else if($this_field.is('.truncated, .transformed')) {
616 //handle truncated/transformed values values
619 * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data
621 var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);
623 // Make the Ajax call and get the data, wrap it and insert it
625 'token' : window.parent.token,
626 'db' : window.parent.db,
627 'ajax_request' : true,
628 'sql_query' : sql_query,
631 if(data.success == true) {
632 $this_field_span.append('<textarea>'+data.value+'</textarea>');
633 $this_field.data('original_data', data_value);
634 $("#sqlqueryresults").trigger('refreshgrid');
637 PMA_ajaxShowMessage(data.error);
641 else if($this_field.is('.relation')) {
646 * @var post_params Object containing parameters for the POST request
649 'ajax_request' : true,
650 'get_relational_values' : true,
651 'db' : window.parent.db,
652 'table' : window.parent.table,
653 'column' : field_name,
654 'token' : window.parent.token,
655 'curr_value' : relation_curr_value,
656 'relation_key_or_display_column' : relation_key_or_display_column
659 $.post('sql.php', post_params, function(data) {
660 $this_field_span.append(data.dropdown);
661 $this_field.data('original_data', data_value);
662 $("#sqlqueryresults").trigger('refreshgrid');
665 else if($this_field.is('.enum')) {
670 * @var post_params Object containing parameters for the POST request
673 'ajax_request' : true,
674 'get_enum_values' : true,
675 'db' : window.parent.db,
676 'table' : window.parent.table,
677 'column' : field_name,
678 'token' : window.parent.token,
679 'curr_value' : curr_value
681 $.post('sql.php', post_params, function(data) {
682 $this_field_span.append(data.dropdown);
683 $this_field.data('original_data', data_value);
684 $("#sqlqueryresults").trigger('refreshgrid');
687 else if($this_field.is('.set')) {
692 * @var post_params Object containing parameters for the POST request
695 'ajax_request' : true,
696 'get_set_values' : true,
697 'db' : window.parent.db,
698 'table' : window.parent.table,
699 'column' : field_name,
700 'token' : window.parent.token,
701 'curr_value' : curr_value
704 $.post('sql.php', post_params, function(data) {
705 $this_field_span.append(data.select);
706 $this_field.data('original_data', data_value);
707 $("#sqlqueryresults").trigger('refreshgrid');
710 else if($this_field.is('.null')) {
712 $this_field_span.append('<textarea></textarea>');
713 $this_field.data('original_data', 'NULL');
718 $("#sqlqueryresults").trigger('refreshgrid');
720 }) // End On click, replace the current field with an input/textarea
723 * After editing, clicking again should post data
726 * @name inline_edit_save
727 * @see PMA_ajaxShowMessage()
728 * @see getFieldName()
730 $(".inline_edit_active span a").live('click', function(event) {
733 event.preventDefault();
736 * @var $this_td Object referring to the td containing the
737 * "Inline Edit" link that was clicked to save the row that is
741 var $this_td = $(this).parents('td');
742 var $test_element = ''; // to test the presence of a element
744 // Initialize variables
745 var $input_siblings = $this_td.parent('tr').find('.inline_edit');
746 var where_clause = $this_td.parent('tr').find('.where_clause').val();
749 * @var nonunique Boolean, whether this row is unique or not
751 if($this_td.is('.nonunique')) {
758 // Collect values of all fields to submit, we don't know which changed
760 * @var relation_fields Array containing the name/value pairs of relational fields
762 var relation_fields = {};
764 * @var relational_display string 'K' if relational key, 'D' if relational display column
766 var relational_display = $("#relational_display_K").attr('checked') ? 'K' : 'D';
768 * @var transform_fields Array containing the name/value pairs for transformed fields
770 var transform_fields = {};
772 * @var transformation_fields Boolean, if there are any transformed fields in this row
774 var transformation_fields = false;
777 * @var sql_query String containing the SQL query to update this row
779 var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
781 var need_to_post = false;
786 $input_siblings.each(function() {
789 * @var this_field Object referring to this field (<td>)
791 var $this_field = $(this);
794 * @var field_name String containing the name of this field.
795 * @see getFieldName()
797 var field_name = getFieldName($this_field);
800 * @var this_field_params Array temporary storage for the name/value of current field
802 var this_field_params = {};
804 if($this_field.is('.transformed')) {
805 transformation_fields = true;
808 * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
810 var is_null = $this_field.find('input:checkbox').is(':checked');
812 var addQuotes = true;
815 sql_query += ' `' + field_name + "`=NULL , ";
818 if($this_field.is(":not(.relation, .enum, .set, .bit)")) {
819 this_field_params[field_name] = $this_field.find('textarea').val();
820 if($this_field.is('.transformed')) {
821 $.extend(transform_fields, this_field_params);
823 } else if ($this_field.is('.bit')) {
824 this_field_params[field_name] = '0b' + $this_field.find('textarea').val();
826 } else if ($this_field.is('.set')) {
827 $test_element = $this_field.find('select');
828 this_field_params[field_name] = $test_element.map(function(){
829 return $(this).val();
832 // results from a drop-down
833 $test_element = $this_field.find('select');
834 if ($test_element.length != 0) {
835 this_field_params[field_name] = $test_element.val();
838 // results from Browse foreign value
839 $test_element = $this_field.find('span.curr_value');
840 if ($test_element.length != 0) {
841 this_field_params[field_name] = $test_element.text();
844 if($this_field.is('.relation')) {
845 $.extend(relation_fields, this_field_params);
848 if(where_clause.indexOf(field_name) > prev_index){
849 new_clause += '`' + window.parent.table + '`.' + '`' + field_name + "` = '" + this_field_params[field_name].replace(/'/g,"''") + "'" + ' AND ';
851 if (this_field_params[field_name] != $this_field.data('original_data')) {
852 if (addQuotes == true) {
853 sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "', ";
855 sql_query += ' `' + field_name + "`=" + this_field_params[field_name].replace(/'/g, "''") + ", ";
863 * update the where_clause, remove the last appended ' AND '
866 //Remove the last ',' appended in the above loop
867 sql_query = sql_query.replace(/,\s$/, '');
868 //Fix non-escaped backslashes
869 sql_query = sql_query.replace(/\\/g, '\\\\');
870 new_clause = new_clause.substring(0, new_clause.length-5);
871 new_clause = PMA_urlencode(new_clause);
872 sql_query += ' WHERE ' + PMA_urldecode(where_clause);
873 // Avoid updating more than one row in case there is no primary key
874 // (happened only for duplicate rows)
875 sql_query += ' LIMIT 1';
877 * @var rel_fields_list String, url encoded representation of {@link relations_fields}
879 var rel_fields_list = $.param(relation_fields);
882 * @var transform_fields_list String, url encoded representation of {@link transform_fields}
884 var transform_fields_list = $.param(transform_fields);
886 // if inline_edit is successful, we need to go back to default view
887 var $del_hide = $(this).parent();
888 var $chg_submit = $(this);
891 // Make the Ajax post after setting all parameters
893 * @var post_params Object containing parameters for the POST request
895 var post_params = {'ajax_request' : true,
896 'sql_query' : sql_query,
897 'token' : window.parent.token,
898 'db' : window.parent.db,
899 'table' : window.parent.table,
900 'clause_is_unique' : nonunique,
901 'where_clause' : where_clause,
902 'rel_fields_list' : rel_fields_list,
903 'do_transformations' : transformation_fields,
904 'transform_fields_list' : transform_fields_list,
905 'relational_display' : relational_display,
907 'submit_type' : 'save'
910 $.post('tbl_replace.php', post_params, function(data) {
911 if(data.success == true) {
912 PMA_ajaxShowMessage(data.message);
913 $this_td.parent('tr').find('.where_clause').attr('value', new_clause);
914 // remove possible previous feedback message
915 $('#result_query').remove();
916 if (typeof data.sql_query != 'undefined') {
918 $('#sqlqueryresults').prepend(data.sql_query);
920 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data);
922 PMA_ajaxShowMessage(data.error);
926 // no posting was done but still need to display the row
927 // in its previous format
928 PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '');
930 }) // End After editing, clicking again should post data
933 * Ajax Event for table row change
935 $("#resultsForm.ajax .mult_submit[value=edit]").live('click', function(event){
936 event.preventDefault();
938 /*Check whether atleast one row is selected for change*/
939 if ($("#table_results tbody tr, #table_results tbody tr td").hasClass("marked")) {
940 var div = $('<div id="change_row_dialog"></div>');
943 * @var button_options Object that stores the options passed to jQueryUI
946 var button_options = {};
947 // in the following function we need to use $(this)
948 button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
950 var button_options_error = {};
951 button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
952 var $form = $("#resultsForm");
953 var $msgbox = PMA_ajaxShowMessage();
955 $.get( $form.attr('action'), $form.serialize()+"&ajax_request=true&submit_mult=row_edit", function(data) {
956 //in the case of an error, show the error message returned.
957 if (data.success != undefined && data.success == false) {
961 title: PMA_messages['strChangeTbl'],
964 open: PMA_verifyTypeOfAllColumns,
965 buttons : button_options_error
966 })// end dialog options
971 title: PMA_messages['strChangeTbl'],
974 open: PMA_verifyTypeOfAllColumns,
975 buttons : button_options
977 //Remove the top menu container from the dialog
978 .find("#topmenucontainer").hide()
979 ; // end dialog options
980 $(".insertRowTable").addClass("ajax");
981 $("#buttonYes").addClass("ajax");
983 PMA_ajaxRemoveMessage($msgbox);
986 PMA_ajaxShowMessage(PMA_messages['strNoRowSelected']);
991 * Click action for "Go" button in ajax dialog insertForm -> insertRowTable
993 $("#insertForm .insertRowTable.ajax input[value=Go]").live('click', function(event) {
994 event.preventDefault();
996 * @var the_form object referring to the insert form
998 var $form = $("#insertForm");
999 PMA_prepareForAjaxRequest($form);
1000 //User wants to submit the form
1001 $.post($form.attr('action'), $form.serialize(), function(data) {
1002 if (data.success == true) {
1003 PMA_ajaxShowMessage(data.message);
1004 if ($("#pageselector").length != 0) {
1005 $("#pageselector").trigger('change');
1007 $("input[name=navig].ajax").trigger('click');
1011 PMA_ajaxShowMessage(data.error);
1012 $("#table_results tbody tr.marked .multi_checkbox " +
1013 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1014 $("#table_results tbody tr.marked .multi_checkbox " +
1015 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1016 $("#table_results tbody tr" +
1017 ", #table_results tbody tr td").removeClass("marked");
1019 if ($("#change_row_dialog").length > 0) {
1020 $("#change_row_dialog").dialog("close").remove();
1022 /**Update the row count at the tableForm*/
1023 $("#result_query").remove();
1024 $("#sqlqueryresults").prepend(data.sql_query);
1025 $("#result_query .notice").remove();
1026 $("#result_query").prepend((data.message));
1028 }) // end insert table button "Go"
1030 /**$("#buttonYes.ajax").live('click'
1031 * Click action for #buttonYes button in ajax dialog insertForm
1033 $("#buttonYes.ajax").live('click', function(event){
1034 event.preventDefault();
1036 * @var the_form object referring to the insert form
1038 var $form = $("#insertForm");
1039 /**Get the submit type and the after insert type in the form*/
1040 var selected_submit_type = $("#insertForm").find("#actions_panel .control_at_footer option:selected").attr('value');
1041 var selected_after_insert = $("#insertForm").find("#actions_panel select[name=after_insert] option:selected").attr('value');
1042 $("#result_query").remove();
1043 PMA_prepareForAjaxRequest($form);
1044 //User wants to submit the form
1045 $.post($form.attr('action'), $form.serialize() , function(data) {
1046 if (data.success == true) {
1047 PMA_ajaxShowMessage(data.message);
1048 if (selected_submit_type == "showinsert") {
1049 $("#sqlqueryresults").prepend(data.sql_query);
1050 $("#result_query .notice").remove();
1051 $("#result_query").prepend(data.message);
1052 $("#table_results tbody tr.marked .multi_checkbox " +
1053 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1054 $("#table_results tbody tr.marked .multi_checkbox " +
1055 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1056 $("#table_results tbody tr" +
1057 ", #table_results tbody tr td").removeClass("marked");
1059 if ($("#pageselector").length != 0) {
1060 $("#pageselector").trigger('change');
1062 $("input[name=navig].ajax").trigger('click');
1064 $("#result_query").remove();
1065 $("#sqlqueryresults").prepend(data.sql_query);
1066 $("#result_query .notice").remove();
1067 $("#result_query").prepend((data.message));
1070 PMA_ajaxShowMessage(data.error);
1071 $("#table_results tbody tr.marked .multi_checkbox " +
1072 ", #table_results tbody tr td.marked .multi_checkbox").prop("checked", false);
1073 $("#table_results tbody tr.marked .multi_checkbox " +
1074 ", #table_results tbody tr td.marked .multi_checkbox").removeClass("last_clicked");
1075 $("#table_results tbody tr" +
1076 ", #table_results tbody tr td").removeClass("marked");
1078 if ($("#change_row_dialog").length > 0) {
1079 $("#change_row_dialog").dialog("close").remove();
1084 }, 'top.frame_content') // end $(document).ready()
1088 * Visually put back the row in the state it was before entering Inline edit
1090 * (when called in the situation where no posting was done, the data
1091 * parameter is empty)
1093 function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data) {
1095 // deleting the hide button. remove <br><br><a> tags
1096 $del_hide.find('a, br').remove();
1097 // append inline edit button.
1098 $del_hide.append($data_a.clone());
1100 // changing inline_edit_active to inline_edit_anchor
1101 $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
1103 // removing hover, marked and noclick classes
1104 $this_td.parent('tr').removeClass('noclick');
1105 $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
1107 $input_siblings.each(function() {
1108 // Inline edit post has been successful.
1109 $this_sibling = $(this);
1110 $this_sibling_span = $(this).children('span');
1112 var is_null = $this_sibling.find('input:checkbox').is(':checked');
1114 $this_sibling_span.html('NULL');
1115 $this_sibling.addClass('null');
1117 $this_sibling.removeClass('null');
1118 if($this_sibling.is(':not(.relation, .enum, .set)')) {
1120 * @var new_html String containing value of the data field after edit
1122 var new_html = $this_sibling.find('textarea').val();
1124 if($this_sibling.is('.transformed')) {
1125 var field_name = getFieldName($this_sibling);
1126 if (typeof data.transformations != 'undefined') {
1127 $.each(data.transformations, function(key, value) {
1128 if(key == field_name) {
1129 if($this_sibling.is('.text_plain, .application_octetstream')) {
1133 var new_value = $this_sibling.find('textarea').val();
1134 new_html = $(value).append(new_value);
1144 $test_element = $this_sibling.find('select');
1145 if ($test_element.length != 0) {
1146 new_value = $test_element.val();
1148 $test_element = $this_sibling.find('span.curr_value');
1149 if ($test_element.length != 0) {
1150 new_value = $test_element.text();
1153 if($this_sibling.is('.relation')) {
1154 var field_name = getFieldName($this_sibling);
1155 if (typeof data.relations != 'undefined') {
1156 $.each(data.relations, function(key, value) {
1157 if(key == field_name) {
1158 new_html = $(value);
1163 } else if ($this_sibling.is('.enum')) {
1164 new_html = new_value;
1165 } else if ($this_sibling.is('.set')) {
1166 if (new_value != null) {
1167 $.each(new_value, function(key, value) {
1168 new_html = new_html + value + ',';
1170 new_html = new_html.substring(0, new_html.length-1);
1174 $this_sibling_span.html(new_html);
1179 $("#sqlqueryresults").trigger('refreshgrid');
1183 * Starting from some th, change the class of all td under it.
1184 * If isAddClass is specified, it will be used to determine whether to add or remove the class.
1186 function PMA_changeClassForColumn($this_th, newclass, isAddClass) {
1187 // index 0 is the th containing the big T
1188 var th_index = $this_th.index();
1189 var has_big_t = !$this_th.closest('tr').children(':first').hasClass('column_heading');
1190 // .eq() is zero-based
1194 var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
1195 if (isAddClass == undefined) {
1196 $tds.toggleClass(newclass);
1198 $tds.toggleClass(newclass, isAddClass);
1202 $(document).ready(function() {
1204 $('.browse_foreign').live('click', function(e) {
1206 window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
1208 $anchor.addClass('browse_foreign_clicked');
1213 * vertical column highlighting in horizontal mode when hovering over the column header
1215 $('.column_heading.pointer').live('hover', function(e) {
1216 PMA_changeClassForColumn($(this), 'hover', e.type == 'mouseenter');
1220 * vertical column marking in horizontal mode when clicking the column header
1222 $('.column_heading.marker').live('click', function() {
1223 PMA_changeClassForColumn($(this), 'marked');
1227 * create resizable table
1229 $("#sqlqueryresults").trigger('makegrid');
1235 function makeProfilingChart() {
1236 if ($('#profilingchart').length == 0) {
1240 var data = new Array();
1241 $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) {
1242 data.push([key,parseFloat(value)]);
1245 // Prevent the user from seeing the JSON code
1246 $('div#profilingchart').html('').show();
1248 PMA_createProfilingChart(data);