Translation update done using Pootle.
[phpmyadmin/adnan.git] / js / sql.js
blob57cb76123678353f056feb693a92cb69eb51a214
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3 * @fileoverview functions used wherever an sql query form is used
5 * @requires jQuery
6 * @requires js/functions.js
8 */
10 /**
11 * decode a string URL_encoded
13 * @param string str
14 * @return string the URL-decoded string
16 function PMA_urldecode(str) {
17 return decodeURIComponent(str.replace(/\+/g, '%20'));
20 /**
21 * Get the field name for the current field. Required to construct the query
22 * for inline editing
24 * @param $this_field jQuery object that points to the current field's tr
25 * @param disp_mode string
27 function getFieldName($this_field, disp_mode) {
29 if(disp_mode == 'vertical') {
30 var field_name = $this_field.siblings('th').find('a').text();
32 else {
33 var this_field_index = $this_field.index();
34 if(window.parent.text_dir == 'ltr') {
35 // 4 columns to account for the checkbox, edit, delete and appended inline edit anchors but index is zero-based so substract 3
36 var field_name = $this_field.parents('table').find('thead').find('th:nth('+ (this_field_index-3 )+') a').text();
38 else {
39 var field_name = $this_field.parents('table').find('thead').find('th:nth('+ this_field_index+') a').text();
43 field_name = $.trim(field_name);
45 return field_name;
48 /**
49 * The function that iterates over each row in the table_results and appends a
50 * new inline edit anchor to each table row.
52 * @param disp_mode string
54 function appendInlineAnchor(disp_mode) {
55 if(disp_mode == 'vertical') {
56 // there can be one or two tr containing this class, depending
57 // on the ModifyDeleteAtLeft and ModifyDeleteAtRight cfg parameters
58 $('#table_results tr')
59 .find('.edit_row_anchor')
60 .removeClass('.edit_row_anchor')
61 .parent().each(function() {
62 var $this_tr = $(this);
63 var $cloned_tr = $this_tr.clone();
65 var $img_object = $cloned_tr.find('img:first').attr('title', PMA_messages['strInlineEdit']);
67 $cloned_tr.find('td')
68 .addClass('inline_edit_anchor')
69 .find('a').attr('href', '#')
70 .find('span')
71 .text(PMA_messages['strInlineEdit'])
72 .prepend($img_object);
74 $cloned_tr.insertAfter($this_tr);
75 });
77 $("#table_results").find('tr').find(':checkbox').closest('tr').find('th')
78 .attr('rowspan', '4');
80 else {
81 $('.edit_row_anchor').each(function() {
83 $this_td = $(this)
84 $this_td.removeClass('edit_row_anchor');
86 var $cloned_anchor = $this_td.clone();
88 var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
90 $cloned_anchor.addClass('inline_edit_anchor')
91 .find('a').attr('href', '#')
92 .find('span')
93 .text(PMA_messages['strInlineEdit'])
94 .prepend($img_object);
96 $this_td.after($cloned_anchor);
97 });
99 $('#rowsDeleteForm').find('thead').find('th').each(function() {
100 if($(this).attr('colspan') == 3) {
101 $(this).attr('colspan', '4')
107 /**#@+
108 * @namespace jQuery
112 * @description <p>Ajax scripts for sql and browse pages</p>
114 * Actions ajaxified here:
115 * <ul>
116 * <li>Retrieve results of an SQL query</li>
117 * <li>Paginate the results table</li>
118 * <li>Sort the results table</li>
119 * <li>Change table according to display options</li>
120 * <li>Inline editing of data</li>
121 * </ul>
123 * @name document.ready
124 * @memberOf jQuery
126 $(document).ready(function() {
129 * Set a parameter for all Ajax queries made on this page. Don't let the
130 * web server serve cached pages
132 $.ajaxSetup({
133 cache: 'false'
137 * current value of the direction in which the table is displayed
138 * @type String
139 * @fieldOf jQuery
140 * @name disp_mode
142 var disp_mode = $("#top_direction_dropdown").val();
145 * Update value of {@link jQuery.disp_mode} everytime the direction dropdown changes value
146 * @memberOf jQuery
147 * @name direction_dropdown_change
149 $("#top_direction_dropdown, #bottom_direction_dropdown").live('change', function(event) {
150 disp_mode = $(this).val();
154 * Attach the {@link appendInlineAnchor} function to a custom event, which
155 * will be triggered manually everytime the table of results is reloaded
156 * @memberOf jQuery
157 * @name sqlqueryresults_live
159 $("#sqlqueryresults").live('appendAnchor',function() {
160 appendInlineAnchor(disp_mode);
164 * Trigger the appendAnchor event to prepare the first table for inline edit
166 * @memberOf jQuery
167 * @name sqlqueryresults_trigger
169 $("#sqlqueryresults").trigger('appendAnchor');
172 * Append the "Show/Hide query box" message to the query input form
174 * @memberOf jQuery
175 * @name appendToggleSpan
177 // do not add this link more than once
178 if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
179 $('<a id="togglequerybox"></a>')
180 .html(PMA_messages['strHideQueryBox'])
181 .appendTo("#sqlqueryform");
183 // Attach the toggling of the query box visibility to a click
184 $("#togglequerybox").bind('click', function() {
185 var $link = $(this)
186 $link.siblings().slideToggle("medium");
187 if ($link.text() == PMA_messages['strHideQueryBox']) {
188 $link.text(PMA_messages['strShowQueryBox']);
189 } else {
190 $link.text(PMA_messages['strHideQueryBox']);
192 // avoid default click action
193 return false;
198 * Ajax Event handler for 'SQL Query Submit'
200 * @see PMA_ajaxShowMessage()
201 * @memberOf jQuery
202 * @name sqlqueryform_submit
204 $("#sqlqueryform").live('submit', function(event) {
205 event.preventDefault();
206 // remove any div containing a previous error message
207 $('.error').remove();
209 $form = $(this);
210 PMA_ajaxShowMessage();
212 if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
213 $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
216 $.post($(this).attr('action'), $(this).serialize() , function(data) {
217 if(data.success == true) {
218 PMA_ajaxShowMessage(data.message);
219 $('#sqlqueryresults').show();
220 // this happens if a USE command was typed
221 if (typeof data.reload != 'undefined') {
222 $form.find('input[name=db]').val(data.db);
223 // need to regenerate the whole upper part
224 $form.find('input[name=ajax_request]').remove();
225 $form.append('<input type="hidden" name="reload" value="true" />');
226 $.post('db_sql.php', $form.serialize(), function(data) {
227 $('body').html(data);
228 }); // end inner post
231 else if (data.success == false ) {
232 // show an error message that stays on screen
233 $('#sqlqueryform').before(data.error);
234 $('#sqlqueryresults').hide();
236 else {
237 $('#sqlqueryresults').show();
238 $("#sqlqueryresults").html(data);
239 $("#sqlqueryresults").trigger('appendAnchor');
240 if($("#togglequerybox").siblings(":visible").length > 0) {
241 $("#togglequerybox").trigger('click');
244 }) // end $.post()
245 }) // end SQL Query submit
248 * Ajax Event handlers for Paginating the results table
252 * Paginate when we click any of the navigation buttons
253 * @memberOf jQuery
254 * @name paginate_nav_button_click
255 * @uses PMA_ajaxShowMessage()
257 $("input[name=navig]").live('click', function(event) {
258 /** @lends jQuery */
259 event.preventDefault();
261 PMA_ajaxShowMessage();
264 * @var the_form Object referring to the form element that paginates the results table
266 var the_form = $(this).parent("form");
268 $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
270 $.post($(the_form).attr('action'), $(the_form).serialize(), function(data) {
271 $("#sqlqueryresults").html(data);
272 $("#sqlqueryresults").trigger('appendAnchor');
273 }) // end $.post()
274 })// end Paginate results table
277 * Paginate results with Page Selector dropdown
278 * @memberOf jQuery
279 * @name paginate_dropdown_change
281 $("#pageselector").live('change', function(event) {
282 event.preventDefault();
284 PMA_ajaxShowMessage();
286 $.get($(this).attr('href'), $(this).serialize() + '&ajax_request=true', function(data) {
287 $("#sqlqueryresults").html(data);
288 $("#sqlqueryresults").trigger('appendAnchor');
289 }) // end $.get()
290 })// end Paginate results with Page Selector
293 * Ajax Event handler for sorting the results table
294 * @memberOf jQuery
295 * @name table_results_sort_click
297 $("#table_results").find("a[title=Sort]").live('click', function(event) {
298 event.preventDefault();
300 PMA_ajaxShowMessage();
302 $.get($(this).attr('href'), $(this).serialize() + '&ajax_request=true', function(data) {
303 $("#sqlqueryresults").html(data);
304 $("#sqlqueryresults").trigger('appendAnchor');
305 }) // end $.get()
306 })//end Sort results table
309 * Ajax Event handler for the display options
310 * @memberOf jQuery
311 * @name displayOptionsForm_submit
313 $("#displayOptionsForm").live('submit', function(event) {
314 event.preventDefault();
316 $.post($(this).attr('action'), $(this).serialize() + '&ajax_request=true' , function(data) {
317 $("#sqlqueryresults").html(data);
318 $("#sqlqueryresults").trigger('appendAnchor');
319 }) // end $.post()
321 //end displayOptionsForm handler
324 * Ajax Event handlers for Inline Editing
328 * On click, replace the fields of current row with an input/textarea
329 * @memberOf jQuery
330 * @name inline_edit_start
331 * @see PMA_ajaxShowMessage()
332 * @see getFieldName()
334 $(".inline_edit_anchor").live('click', function(event) {
335 /** @lends jQuery */
336 event.preventDefault();
338 $(this).removeClass('inline_edit_anchor').addClass('inline_edit_active');
340 // Initialize some variables
341 if(disp_mode == 'vertical') {
343 * @var this_row_index Index of the current <td> in the parent <tr>
344 * Current <td> is the inline edit anchor.
346 var this_row_index = $(this).index();
348 * @var $input_siblings Object referring to all inline editable events from same row
350 var $input_siblings = $(this).parents('tbody').find('tr').find('.data_inline_edit:nth('+this_row_index+')');
352 * @var where_clause String containing the WHERE clause to select this row
354 var where_clause = $(this).parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
356 else {
357 var $input_siblings = $(this).parent('tr').find('.data_inline_edit');
358 var where_clause = $(this).parent('tr').find('.where_clause').val();
361 $input_siblings.each(function() {
362 /** @lends jQuery */
364 * @var data_value Current value of this field
366 var data_value = $(this).html();
368 // We need to retrieve the value from the server for truncated/relation fields
369 // Find the field name
372 * @var this_field Object referring to this field (<td>)
374 var $this_field = $(this);
376 * @var field_name String containing the name of this field.
377 * @see getFieldName()
379 var field_name = getFieldName($this_field, disp_mode);
381 // In each input sibling, wrap the current value in a textarea
382 // and store the current value in a hidden span
383 if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .null)')) {
384 // handle non-truncated, non-transformed, non-relation values
385 // We don't need to get any more data, just wrap the value
386 $this_field.html('<textarea>'+data_value+'</textarea>')
387 .append('<span class="original_data">'+data_value+'</span>');
388 $(".original_data").hide();
390 else if($this_field.is('.truncated, .transformed')) {
391 /** @lends jQuery */
392 //handle truncated/transformed values values
395 * @var sql_query String containing the SQL query used to retrieve value of truncated/transformed data
397 var sql_query = 'SELECT ' + field_name + ' FROM ' + window.parent.table + ' WHERE ' + where_clause;
399 // Make the Ajax call and get the data, wrap it and insert it
400 $.post('sql.php', {
401 'token' : window.parent.token,
402 'db' : window.parent.db,
403 'ajax_request' : true,
404 'sql_query' : sql_query,
405 'inline_edit' : true
406 }, function(data) {
407 if(data.success == true) {
408 $this_field.html('<textarea>'+data.value+'</textarea>')
409 .append('<span class="original_data">'+data_value+'</span>');
410 $(".original_data").hide();
412 else {
413 PMA_ajaxShowMessage(data.error);
415 }) // end $.post()
417 else if($this_field.is('.relation')) {
418 /** @lends jQuery */
419 //handle relations
422 * @var curr_value String containing the current value of this relational field
424 var curr_value = $this_field.find('a').text();
427 * @var post_params Object containing parameters for the POST request
429 var post_params = {
430 'ajax_request' : true,
431 'get_relational_values' : true,
432 'db' : window.parent.db,
433 'table' : window.parent.table,
434 'column' : field_name,
435 'token' : window.parent.token,
436 'curr_value' : curr_value
439 $.post('sql.php', post_params, function(data) {
440 $this_field.html(data.dropdown)
441 .append('<span class="original_data">'+data_value+'</span>');
442 $(".original_data").hide();
443 }) // end $.post()
445 else if($this_field.is('.enum')) {
446 /** @lends jQuery */
447 //handle enum fields
449 * @var curr_value String containing the current value of this relational field
451 var curr_value = $this_field.text();
454 * @var post_params Object containing parameters for the POST request
456 var post_params = {
457 'ajax_request' : true,
458 'get_enum_values' : true,
459 'db' : window.parent.db,
460 'table' : window.parent.table,
461 'column' : field_name,
462 'token' : window.parent.token,
463 'curr_value' : curr_value
466 $.post('sql.php', post_params, function(data) {
467 $this_field.html(data.dropdown)
468 .append('<span class="original_data">'+data_value+'</span>');
469 $(".original_data").hide();
470 }) // end $.post()
472 else if($this_field.is('.null')) {
473 //handle null fields
474 $this_field.html('<textarea></textarea>')
475 .append('<span class="original_data">NULL</span>');
476 $(".original_data").hide();
479 }) // End On click, replace the current field with an input/textarea
482 * After editing, clicking again should post data
484 * @memberOf jQuery
485 * @name inline_edit_save
486 * @see PMA_ajaxShowMessage()
487 * @see getFieldName()
489 $(".inline_edit_active").live('click', function(event) {
490 /** @lends jQuery */
491 event.preventDefault();
494 * @var $this_td Object referring to the td containing the
495 * "Inline Edit" link that was clicked to save the row that is
496 * being edited
499 var $this_td = $(this);
501 // Initialize variables
502 if(disp_mode == 'vertical') {
504 * @var this_td_index Index of the current <td> in the parent <tr>
505 * Current <td> is the inline edit anchor.
507 var this_td_index = $this_td.index();
509 * @var $input_siblings Object referring to all inline editable events from same row
511 var $input_siblings = $this_td.parents('tbody').find('tr').find('.data_inline_edit:nth('+this_td_index+')');
513 * @var where_clause String containing the WHERE clause to select this row
515 var where_clause = $this_td.parents('tbody').find('tr').find('.where_clause:nth('+this_td_index+')').val();
517 else {
518 var $input_siblings = $this_td.parent('tr').find('.data_inline_edit');
519 var where_clause = $this_td.parent('tr').find('.where_clause').val();
523 * @var nonunique Boolean, whether this row is unique or not
525 if($this_td.is('.nonunique')) {
526 var nonunique = 0;
528 else {
529 var nonunique = 1;
532 // Collect values of all fields to submit, we don't know which changed
534 * @var params_to_submit Array containing the name/value pairs of all fields
536 var params_to_submit = {};
538 * @var relation_fields Array containing the name/value pairs of relational fields
540 var relation_fields = {};
542 * @var transform_fields Array containing the name/value pairs for transformed fields
544 var transform_fields = {};
546 * @var transformation_fields Boolean, if there are any transformed fields in this row
548 var transformation_fields = false;
550 $input_siblings.each(function() {
551 /** @lends jQuery */
553 * @var this_field Object referring to this field (<td>)
555 var $this_field = $(this);
557 * @var field_name String containing the name of this field.
558 * @see getFieldName()
560 var field_name = getFieldName($this_field, disp_mode);
563 * @var this_field_params Array temporary storage for the name/value of current field
565 var this_field_params = {};
567 if($this_field.is('.transformed')) {
568 transformation_fields = true;
571 if($this_field.is(":not(.relation, .enum)")) {
572 this_field_params[field_name] = $this_field.find('textarea').val();
573 if($this_field.is('.transformed')) {
574 $.extend(transform_fields, this_field_params);
577 else {
578 this_field_params[field_name] = $this_field.find('select').val();
580 if($this_field.is('.relation')) {
581 $.extend(relation_fields, this_field_params);
585 $.extend(params_to_submit, this_field_params);
589 * @var sql_query String containing the SQL query to update this row
591 var sql_query = 'UPDATE ' + window.parent.table + ' SET ';
593 $.each(params_to_submit, function(key, value) {
594 if(value.length == 0) {
595 value = 'NULL'
597 sql_query += ' ' + key + "='" + value + "' , ";
599 //Remove the last ',' appended in the above loop
600 sql_query = sql_query.replace(/,\s$/, '');
601 sql_query += ' WHERE ' + PMA_urldecode(where_clause);
604 * @var rel_fields_list String, url encoded representation of {@link relations_fields}
606 var rel_fields_list = $.param(relation_fields);
609 * @var transform_fields_list String, url encoded representation of {@link transform_fields}
611 var transform_fields_list = $.param(transform_fields);
613 // Make the Ajax post after setting all parameters
615 * @var post_params Object containing parameters for the POST request
617 var post_params = {'ajax_request' : true,
618 'sql_query' : sql_query,
619 'disp_direction' : disp_mode,
620 'token' : window.parent.token,
621 'db' : window.parent.db,
622 'table' : window.parent.table,
623 'clause_is_unique' : nonunique,
624 'where_clause' : where_clause,
625 'rel_fields_list' : rel_fields_list,
626 'do_transformations' : transformation_fields,
627 'transform_fields_list' : transform_fields_list,
628 'goto' : 'sql.php',
629 'submit_type' : 'save'
632 $.post('tbl_replace.php', post_params, function(data) {
633 if(data.success == true) {
634 PMA_ajaxShowMessage(data.message);
635 $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');
637 $input_siblings.each(function() {
638 // Inline edit post has been successful.
639 if($(this).is(':not(.relation, .enum)')) {
641 * @var new_html String containing value of the data field after edit
643 var new_html = $(this).find('textarea').val();
645 if($(this).is('.transformed')) {
646 var field_name = getFieldName($(this), disp_mode);
647 var this_field = $(this);
649 $.each(data.transformations, function(key, value) {
650 if(key == field_name) {
651 if($(this_field).is('.text_plain, .application_octetstream')) {
652 new_html = value;
653 return false;
655 else {
656 var new_value = $(this_field).find('textarea').val();
657 new_html = $(value).append(new_value);
658 return false;
664 else {
665 var new_html = $(this).find('select').val();
666 if($(this).is('.relation')) {
667 var field_name = getFieldName($(this), disp_mode);
668 var this_field = $(this);
670 $.each(data.relations, function(key, value) {
671 if(key == field_name) {
672 var new_value = $(this_field).find('select').val();
673 new_html = $(value).append(new_value);
674 return false;
679 $(this).html(new_html);
682 else {
683 PMA_ajaxShowMessage(data.error);
685 }) // end $.post()
686 }) // End After editing, clicking again should post data
687 }, 'top.frame_content') // end $(document).ready()
690 * Starting from some th, change the class of all td under it
692 function PMA_changeClassForColumn($this_th, klass) {
693 // index 0 is the th containing the big T
694 var th_index = $this_th.index();
695 // .eq() is zero-based
696 th_index--;
697 var $tr_with_data = $this_th.closest('table').find('tbody tr ').has('td.data_inline_edit');
698 $tr_with_data.each(function() {
699 $(this).find('td.data_inline_edit:eq('+th_index+')').toggleClass(klass);
703 $(document).ready(function() {
705 * column highlighting in horizontal mode when hovering over the column header
707 $('.column_heading').live('hover', function() {
708 PMA_changeClassForColumn($(this), 'hover');
712 * column marking in horizontal mode when clicking the column header
714 $('.column_heading').live('click', function() {
715 PMA_changeClassForColumn($(this), 'marked');
719 /**#@- */