Translation update done using Pootle.
[phpmyadmin/ammaryasirr.git] / js / functions.js
blobb6b76924422e64e9ee8e0d255cb14d53129c6110
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * general function, usally for data manipulation pages
4  *
5  */
7 /**
8  * @var sql_box_locked lock for the sqlbox textarea in the querybox/querywindow
9  */
10 var sql_box_locked = false;
12 /**
13  * @var array holds elements which content should only selected once
14  */
15 var only_once_elements = new Array();
17 /**
18  * @var   int   ajax_message_count   Number of AJAX messages shown since page load
19  */
20 var ajax_message_count = 0;
22 /**
23  * @var codemirror_editor object containing CodeMirror editor
24  */
25 var codemirror_editor = false;
27 /**
28  * @var chart_activeTimeouts object active timeouts that refresh the charts. When disabling a realtime chart, this can be used to stop the continuous ajax requests
29  */
30 var chart_activeTimeouts = new Object();
32 if(window.parent) {
33         $(document).ready(function() {
34                 if(window.parent.currentWidth() == 0)
35                         $('div#frameExpand').show();
36         });
39 /**
40  * Add a hidden field to the form to indicate that this will be an
41  * Ajax request (only if this hidden field does not exist)
42  *
43  * @param   object   the form
44  */
45 function PMA_prepareForAjaxRequest($form) {
46     if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
47         $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
48     }
51 /**
52  * Generate a new password and copy it to the password input areas
53  *
54  * @param   object   the form that holds the password fields
55  *
56  * @return  boolean  always true
57  */
58 function suggestPassword(passwd_form) {
59     // restrict the password to just letters and numbers to avoid problems:
60     // "editors and viewers regard the password as multiple words and
61     // things like double click no longer work"
62     var pwchars = "abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ";
63     var passwordlength = 16;    // do we want that to be dynamic?  no, keep it simple :)
64     var passwd = passwd_form.generated_pw;
65     passwd.value = '';
67     for ( i = 0; i < passwordlength; i++ ) {
68         passwd.value += pwchars.charAt( Math.floor( Math.random() * pwchars.length ) )
69     }
70     passwd_form.text_pma_pw.value = passwd.value;
71     passwd_form.text_pma_pw2.value = passwd.value;
72     return true;
75 /**
76  * Version string to integer conversion.
77  */
78 function parseVersionString (str) {
79     if (typeof(str) != 'string') { return false; }
80     var add = 0;
81     // Parse possible alpha/beta/rc/
82     var state = str.split('-');
83     if (state.length >= 2) {
84         if (state[1].substr(0, 2) == 'rc') {
85             add = - 20 - parseInt(state[1].substr(2));
86         } else if (state[1].substr(0, 4) == 'beta') {
87             add =  - 40 - parseInt(state[1].substr(4));
88         } else if (state[1].substr(0, 5) == 'alpha') {
89             add =  - 60 - parseInt(state[1].substr(5));
90         } else if (state[1].substr(0, 3) == 'dev') {
91             /* We don't handle dev, it's git snapshot */
92             add = 0;
93         }
94     }
95     // Parse version
96     var x = str.split('.');
97     // Use 0 for non existing parts
98     var maj = parseInt(x[0]) || 0;
99     var min = parseInt(x[1]) || 0;
100     var pat = parseInt(x[2]) || 0;
101     var hotfix = parseInt(x[3]) || 0;
102     return  maj * 100000000 + min * 1000000 + pat * 10000 + hotfix * 100 + add;
106  * Indicates current available version on main page.
107  */
108 function PMA_current_version() {
109     var current = parseVersionString(pmaversion);
110     var latest = parseVersionString(PMA_latest_version);
111     var version_information_message = PMA_messages['strLatestAvailable'] + ' ' + PMA_latest_version;
112     if (latest > current) {
113         var message = $.sprintf(PMA_messages['strNewerVersion'], PMA_latest_version, PMA_latest_date);
114         if (Math.floor(latest / 10000) == Math.floor(current / 10000)) {
115             /* Security update */
116             klass = 'error';
117         } else {
118             klass = 'notice';
119         }
120         $('#maincontainer').after('<div class="' + klass + '">' + message + '</div>');
121     }
122     if (latest == current) {
123         version_information_message = ' (' + PMA_messages['strUpToDate'] + ')';
124     }
125     $('#li_pma_version').append(version_information_message);
129  * for libraries/display_change_password.lib.php
130  *     libraries/user_password.php
132  */
134 function displayPasswordGenerateButton() {
135     $('#tr_element_before_generate_password').parent().append('<tr><td>' + PMA_messages['strGeneratePassword'] + '</td><td><input type="button" id="button_generate_password" value="' + PMA_messages['strGenerate'] + '" onclick="suggestPassword(this.form)" /><input type="text" name="generated_pw" id="generated_pw" /></td></tr>');
136     $('#div_element_before_generate_password').parent().append('<div class="item"><label for="button_generate_password">' + PMA_messages['strGeneratePassword'] + ':</label><span class="options"><input type="button" id="button_generate_password" value="' + PMA_messages['strGenerate'] + '" onclick="suggestPassword(this.form)" /></span><input type="text" name="generated_pw" id="generated_pw" /></div>');
140  * Adds a date/time picker to an element
142  * @param   object  $this_element   a jQuery object pointing to the element
143  */
144 function PMA_addDatepicker($this_element, options) {
145     var showTimeOption = false;
146     if ($this_element.is('.datetimefield')) {
147         showTimeOption = true;
148     }
150     var defaultOptions = {
151         showOn: 'button',
152         buttonImage: themeCalendarImage, // defined in js/messages.php
153         buttonImageOnly: true,
154         duration: '',
155         time24h: true,
156         stepMinutes: 1,
157         stepHours: 1,
158         showTime: showTimeOption,
159         dateFormat: 'yy-mm-dd', // yy means year with four digits
160         altTimeField: '',
161         beforeShow: function(input, inst) {
162             // Remember that we came from the datepicker; this is used
163             // in tbl_change.js by verificationsAfterFieldChange()
164             $this_element.data('comes_from', 'datepicker');
166             // Fix wrong timepicker z-index, doesn't work without timeout
167             setTimeout(function() {
168                 $('#ui-timepicker-div').css('z-index',$('#ui-datepicker-div').css('z-index'))
169             },0);
170         },
171         constrainInput: false
172     };
174     $this_element.datepicker($.extend(defaultOptions, options));
178  * selects the content of a given object, f.e. a textarea
180  * @param   object  element     element of which the content will be selected
181  * @param   var     lock        variable which holds the lock for this element
182  *                              or true, if no lock exists
183  * @param   boolean only_once   if true this is only done once
184  *                              f.e. only on first focus
185  */
186 function selectContent( element, lock, only_once ) {
187     if ( only_once && only_once_elements[element.name] ) {
188         return;
189     }
191     only_once_elements[element.name] = true;
193     if ( lock  ) {
194         return;
195     }
197     element.select();
201  * Displays a confirmation box before to submit a "DROP/DELETE/ALTER" query.
202  * This function is called while clicking links
204  * @param   object   the link
205  * @param   object   the sql query to submit
207  * @return  boolean  whether to run the query or not
208  */
209 function confirmLink(theLink, theSqlQuery)
211     // Confirmation is not required in the configuration file
212     // or browser is Opera (crappy js implementation)
213     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
214         return true;
215     }
217     var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
218     if (is_confirmed) {
219         if ( $(theLink).hasClass('formLinkSubmit') ) {
220             var name = 'is_js_confirmed';
221             if ($(theLink).attr('href').indexOf('usesubform') != -1) {
222                 name = 'subform[' + $(theLink).attr('href').substr('#').match(/usesubform\[(\d+)\]/i)[1] + '][is_js_confirmed]';
223             }
225             $(theLink).parents('form').append('<input type="hidden" name="' + name + '" value="1" />');
226         } else if ( typeof(theLink.href) != 'undefined' ) {
227             theLink.href += '&is_js_confirmed=1';
228         } else if ( typeof(theLink.form) != 'undefined' ) {
229             theLink.form.action += '?is_js_confirmed=1';
230         }
231     }
233     return is_confirmed;
234 } // end of the 'confirmLink()' function
238  * Displays a confirmation box before doing some action
240  * @param   object   the message to display
242  * @return  boolean  whether to run the query or not
244  * @todo used only by libraries/display_tbl.lib.php. figure out how it is used
245  *       and replace with a jQuery equivalent
246  */
247 function confirmAction(theMessage)
249     // TODO: Confirmation is not required in the configuration file
250     // or browser is Opera (crappy js implementation)
251     if (typeof(window.opera) != 'undefined') {
252         return true;
253     }
255     var is_confirmed = confirm(theMessage);
257     return is_confirmed;
258 } // end of the 'confirmAction()' function
262  * Displays an error message if a "DROP DATABASE" statement is submitted
263  * while it isn't allowed, else confirms a "DROP/DELETE/ALTER" query before
264  * sumitting it if required.
265  * This function is called by the 'checkSqlQuery()' js function.
267  * @param   object   the form
268  * @param   object   the sql query textarea
270  * @return  boolean  whether to run the query or not
272  * @see     checkSqlQuery()
273  */
274 function confirmQuery(theForm1, sqlQuery1)
276     // Confirmation is not required in the configuration file
277     if (PMA_messages['strDoYouReally'] == '') {
278         return true;
279     }
281     // "DROP DATABASE" statement isn't allowed
282     if (PMA_messages['strNoDropDatabases'] != '') {
283         var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
284         if (drop_re.test(sqlQuery1.value)) {
285             alert(PMA_messages['strNoDropDatabases']);
286             theForm1.reset();
287             sqlQuery1.focus();
288             return false;
289         } // end if
290     } // end if
292     // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
293     //
294     // TODO: find a way (if possible) to use the parser-analyser
295     // for this kind of verification
296     // For now, I just added a ^ to check for the statement at
297     // beginning of expression
299     var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
300     var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
301     var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
302     var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
304     if (do_confirm_re_0.test(sqlQuery1.value)
305         || do_confirm_re_1.test(sqlQuery1.value)
306         || do_confirm_re_2.test(sqlQuery1.value)
307         || do_confirm_re_3.test(sqlQuery1.value)) {
308         var message      = (sqlQuery1.value.length > 100)
309                          ? sqlQuery1.value.substr(0, 100) + '\n    ...'
310                          : sqlQuery1.value;
311         var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
312         // statement is confirmed -> update the
313         // "is_js_confirmed" form field so the confirm test won't be
314         // run on the server side and allows to submit the form
315         if (is_confirmed) {
316             theForm1.elements['is_js_confirmed'].value = 1;
317             return true;
318         }
319         // statement is rejected -> do not submit the form
320         else {
321             window.focus();
322             sqlQuery1.focus();
323             return false;
324         } // end if (handle confirm box result)
325     } // end if (display confirm box)
327     return true;
328 } // end of the 'confirmQuery()' function
332  * Displays a confirmation box before disabling the BLOB repository for a given database.
333  * This function is called while clicking links
335  * @param   object   the database
337  * @return  boolean  whether to disable the repository or not
338  */
339 function confirmDisableRepository(theDB)
341     // Confirmation is not required in the configuration file
342     // or browser is Opera (crappy js implementation)
343     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
344         return true;
345     }
347     var is_confirmed = confirm(PMA_messages['strBLOBRepositoryDisableStrongWarning'] + '\n' + PMA_messages['strBLOBRepositoryDisableAreYouSure']);
349     return is_confirmed;
350 } // end of the 'confirmDisableBLOBRepository()' function
354  * Displays an error message if the user submitted the sql query form with no
355  * sql query, else checks for "DROP/DELETE/ALTER" statements
357  * @param   object   the form
359  * @return  boolean  always false
361  * @see     confirmQuery()
362  */
363 function checkSqlQuery(theForm)
365     var sqlQuery = theForm.elements['sql_query'];
366     var isEmpty  = 1;
368     var space_re = new RegExp('\\s+');
369     if (typeof(theForm.elements['sql_file']) != 'undefined' &&
370             theForm.elements['sql_file'].value.replace(space_re, '') != '') {
371         return true;
372     }
373     if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
374             theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
375         return true;
376     }
377     if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
378             (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
379             theForm.elements['id_bookmark'].selectedIndex != 0
380             ) {
381         return true;
382     }
383     // Checks for "DROP/DELETE/ALTER" statements
384     if (sqlQuery.value.replace(space_re, '') != '') {
385         if (confirmQuery(theForm, sqlQuery)) {
386             return true;
387         } else {
388             return false;
389         }
390     }
391     theForm.reset();
392     isEmpty = 1;
394     if (isEmpty) {
395         sqlQuery.select();
396         alert(PMA_messages['strFormEmpty']);
397         sqlQuery.focus();
398         return false;
399     }
401     return true;
402 } // end of the 'checkSqlQuery()' function
405  * Check if a form's element is empty.
406  * An element containing only spaces is also considered empty
408  * @param   object   the form
409  * @param   string   the name of the form field to put the focus on
411  * @return  boolean  whether the form field is empty or not
412  */
413 function emptyCheckTheField(theForm, theFieldName)
415     var theField = theForm.elements[theFieldName];
416     var space_re = new RegExp('\\s+');
417     return (theField.value.replace(space_re, '') == '') ? 1 : 0;
418 } // end of the 'emptyCheckTheField()' function
422  * Check whether a form field is empty or not
424  * @param   object   the form
425  * @param   string   the name of the form field to put the focus on
427  * @return  boolean  whether the form field is empty or not
428  */
429 function emptyFormElements(theForm, theFieldName)
431     var theField = theForm.elements[theFieldName];
432     var isEmpty = emptyCheckTheField(theForm, theFieldName);
435     return isEmpty;
436 } // end of the 'emptyFormElements()' function
440  * Ensures a value submitted in a form is numeric and is in a range
442  * @param   object   the form
443  * @param   string   the name of the form field to check
444  * @param   integer  the minimum authorized value
445  * @param   integer  the maximum authorized value
447  * @return  boolean  whether a valid number has been submitted or not
448  */
449 function checkFormElementInRange(theForm, theFieldName, message, min, max)
451     var theField         = theForm.elements[theFieldName];
452     var val              = parseInt(theField.value);
454     if (typeof(min) == 'undefined') {
455         min = 0;
456     }
457     if (typeof(max) == 'undefined') {
458         max = Number.MAX_VALUE;
459     }
461     // It's not a number
462     if (isNaN(val)) {
463         theField.select();
464         alert(PMA_messages['strNotNumber']);
465         theField.focus();
466         return false;
467     }
468     // It's a number but it is not between min and max
469     else if (val < min || val > max) {
470         theField.select();
471         alert(message.replace('%d', val));
472         theField.focus();
473         return false;
474     }
475     // It's a valid number
476     else {
477         theField.value = val;
478     }
479     return true;
481 } // end of the 'checkFormElementInRange()' function
484 function checkTableEditForm(theForm, fieldsCnt)
486     // TODO: avoid sending a message if user just wants to add a line
487     // on the form but has not completed at least one field name
489     var atLeastOneField = 0;
490     var i, elm, elm2, elm3, val, id;
492     for (i=0; i<fieldsCnt; i++)
493     {
494         id = "#field_" + i + "_2";
495         elm = $(id);
496         val = elm.val()
497         if (val == 'VARCHAR' || val == 'CHAR' || val == 'BIT' || val == 'VARBINARY' || val == 'BINARY') {
498             elm2 = $("#field_" + i + "_3");
499             val = parseInt(elm2.val());
500             elm3 = $("#field_" + i + "_1");
501             if (isNaN(val) && elm3.val() != "") {
502                 elm2.select();
503                 alert(PMA_messages['strNotNumber']);
504                 elm2.focus();
505                 return false;
506             }
507         }
509         if (atLeastOneField == 0) {
510             id = "field_" + i + "_1";
511             if (!emptyCheckTheField(theForm, id)) {
512                 atLeastOneField = 1;
513             }
514         }
515     }
516     if (atLeastOneField == 0) {
517         var theField = theForm.elements["field_0_1"];
518         alert(PMA_messages['strFormEmpty']);
519         theField.focus();
520         return false;
521     }
523     // at least this section is under jQuery
524     if ($("input.textfield[name='table']").val() == "") {
525         alert(PMA_messages['strFormEmpty']);
526         $("input.textfield[name='table']").focus();
527         return false;
528     }
531     return true;
532 } // enf of the 'checkTableEditForm()' function
536  * Ensures the choice between 'transmit', 'zipped', 'gzipped' and 'bzipped'
537  * checkboxes is consistant
539  * @param   object   the form
540  * @param   string   a code for the action that causes this function to be run
542  * @return  boolean  always true
543  */
544 function checkTransmitDump(theForm, theAction)
546     var formElts = theForm.elements;
548     // 'zipped' option has been checked
549     if (theAction == 'zip' && formElts['zip'].checked) {
550         if (!formElts['asfile'].checked) {
551             theForm.elements['asfile'].checked = true;
552         }
553         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
554             theForm.elements['gzip'].checked = false;
555         }
556         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
557             theForm.elements['bzip'].checked = false;
558         }
559     }
560     // 'gzipped' option has been checked
561     else if (theAction == 'gzip' && formElts['gzip'].checked) {
562         if (!formElts['asfile'].checked) {
563             theForm.elements['asfile'].checked = true;
564         }
565         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
566             theForm.elements['zip'].checked = false;
567         }
568         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
569             theForm.elements['bzip'].checked = false;
570         }
571     }
572     // 'bzipped' option has been checked
573     else if (theAction == 'bzip' && formElts['bzip'].checked) {
574         if (!formElts['asfile'].checked) {
575             theForm.elements['asfile'].checked = true;
576         }
577         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
578             theForm.elements['zip'].checked = false;
579         }
580         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
581             theForm.elements['gzip'].checked = false;
582         }
583     }
584     // 'transmit' option has been unchecked
585     else if (theAction == 'transmit' && !formElts['asfile'].checked) {
586         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
587             theForm.elements['zip'].checked = false;
588         }
589         if ((typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked)) {
590             theForm.elements['gzip'].checked = false;
591         }
592         if ((typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked)) {
593             theForm.elements['bzip'].checked = false;
594         }
595     }
597     return true;
598 } // end of the 'checkTransmitDump()' function
600 $(document).ready(function() {
601     /**
602      * Row marking in horizontal mode (use "live" so that it works also for
603      * next pages reached via AJAX); a tr may have the class noclick to remove
604      * this behavior.
605      */
606     $('table:not(.noclick) tr.odd:not(.noclick), table:not(.noclick) tr.even:not(.noclick)').live('click',function(e) {
607         // do not trigger when clicked on anchor
608         if ($(e.target).is('a, img, a *')) {
609             return;
610         }
611         var $tr = $(this);
613         // make the table unselectable (to prevent default highlighting when shift+click)
614         $tr.parents('table').noSelect();
616         if (!e.shiftKey || last_clicked_row == -1) {
617             // usual click
619             // XXX: FF fires two click events for <label> (label and checkbox), so we need to handle this differently
620             var $checkbox = $tr.find(':checkbox');
621             if ($checkbox.length) {
622                 // checkbox in a row, add or remove class depending on checkbox state
623                 var checked = $checkbox.attr('checked');
624                 if (!$(e.target).is(':checkbox, label')) {
625                     checked = !checked;
626                     $checkbox.attr('checked', checked);
627                 }
628                 if (checked) {
629                     $tr.addClass('marked');
630                 } else {
631                     $tr.removeClass('marked');
632                 }
633                 last_click_checked = checked;
634             } else {
635                 // normaln data table, just toggle class
636                 $tr.toggleClass('marked');
637                 last_click_checked = false;
638             }
640             // remember the last clicked row
641             last_clicked_row = last_click_checked ? $('tr.odd:not(.noclick), tr.even:not(.noclick)').index(this) : -1;
642             last_shift_clicked_row = -1;
643         } else {
644             // handle the shift click
645             var start, end;
647             // clear last shift click result
648             if (last_shift_clicked_row >= 0) {
649                 if (last_shift_clicked_row >= last_clicked_row) {
650                     start = last_clicked_row;
651                     end = last_shift_clicked_row;
652                 } else {
653                     start = last_shift_clicked_row;
654                     end = last_clicked_row;
655                 }
656                 $tr.parent().find('tr.odd:not(.noclick), tr.even:not(.noclick)')
657                     .slice(start, end + 1)
658                     .removeClass('marked')
659                     .find(':checkbox')
660                     .attr('checked', false);
661             }
663             // handle new shift click
664             var curr_row = $('tr.odd:not(.noclick), tr.even:not(.noclick)').index(this);
665             if (curr_row >= last_clicked_row) {
666                 start = last_clicked_row;
667                 end = curr_row;
668             } else {
669                 start = curr_row;
670                 end = last_clicked_row;
671             }
672             $tr.parent().find('tr.odd:not(.noclick), tr.even:not(.noclick)')
673                 .slice(start, end + 1)
674                 .addClass('marked')
675                 .find(':checkbox')
676                 .attr('checked', true);
678             // remember the last shift clicked row
679             last_shift_clicked_row = curr_row;
680         }
681     });
683     /**
684      * Add a date/time picker to each element that needs it
685      */
686     $('.datefield, .datetimefield').each(function() {
687         PMA_addDatepicker($(this));
688         });
692  * True if last click is to check a row.
693  */
694 var last_click_checked = false;
697  * Zero-based index of last clicked row.
698  * Used to handle the shift + click event in the code above.
699  */
700 var last_clicked_row = -1;
703  * Zero-based index of last shift clicked row.
704  */
705 var last_shift_clicked_row = -1;
708  * Row highlighting in horizontal mode (use "live"
709  * so that it works also for pages reached via AJAX)
710  */
711 /*$(document).ready(function() {
712     $('tr.odd, tr.even').live('hover',function(event) {
713         var $tr = $(this);
714         $tr.toggleClass('hover',event.type=='mouseover');
715         $tr.children().toggleClass('hover',event.type=='mouseover');
716     });
717 })*/
720  * This array is used to remember mark status of rows in browse mode
721  */
722 var marked_row = new Array;
725  * marks all rows and selects its first checkbox inside the given element
726  * the given element is usaly a table or a div containing the table or tables
728  * @param    container    DOM element
729  */
730 function markAllRows( container_id ) {
732     $("#"+container_id).find("input:checkbox:enabled").attr('checked', 'checked')
733     .parents("tr").addClass("marked");
734     return true;
738  * marks all rows and selects its first checkbox inside the given element
739  * the given element is usaly a table or a div containing the table or tables
741  * @param    container    DOM element
742  */
743 function unMarkAllRows( container_id ) {
745     $("#"+container_id).find("input:checkbox:enabled").removeAttr('checked')
746     .parents("tr").removeClass("marked");
747     return true;
751  * Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div)
753  * @param   string   container_id  the container id
754  * @param   boolean  state         new value for checkbox (true or false)
755  * @return  boolean  always true
756  */
757 function setCheckboxes( container_id, state ) {
759     if(state) {
760         $("#"+container_id).find("input:checkbox").attr('checked', 'checked');
761     }
762     else {
763         $("#"+container_id).find("input:checkbox").removeAttr('checked');
764     }
766     return true;
767 } // end of the 'setCheckboxes()' function
770   * Checks/unchecks all options of a <select> element
771   *
772   * @param   string   the form name
773   * @param   string   the element name
774   * @param   boolean  whether to check or to uncheck options
775   *
776   * @return  boolean  always true
777   */
778 function setSelectOptions(the_form, the_select, do_check)
780     $("form[name='"+ the_form +"'] select[name='"+the_select+"']").find("option").attr('selected', do_check);
781     return true;
782 } // end of the 'setSelectOptions()' function
785  * Sets current value for query box.
786  */
787 function setQuery(query) {
788     if (codemirror_editor) {
789         codemirror_editor.setValue(query);
790     } else {
791         document.sqlform.sql_query.value = query;
792     }
797   * Create quick sql statements.
798   *
799   */
800 function insertQuery(queryType) {
801     if (queryType == "clear") {
802         setQuery('');
803         return;
804     }
806     var myQuery = document.sqlform.sql_query;
807     var query = "";
808     var myListBox = document.sqlform.dummy;
809     var table = document.sqlform.table.value;
811     if (myListBox.options.length > 0) {
812         sql_box_locked = true;
813         var chaineAj = "";
814         var valDis = "";
815         var editDis = "";
816         var NbSelect = 0;
817         for (var i=0; i < myListBox.options.length; i++) {
818             NbSelect++;
819             if (NbSelect > 1) {
820                 chaineAj += ", ";
821                 valDis += ",";
822                 editDis += ",";
823             }
824             chaineAj += myListBox.options[i].value;
825             valDis += "[value-" + NbSelect + "]";
826             editDis += myListBox.options[i].value + "=[value-" + NbSelect + "]";
827         }
828         if (queryType == "selectall") {
829             query = "SELECT * FROM `" + table + "` WHERE 1";
830         } else if (queryType == "select") {
831             query = "SELECT " + chaineAj + " FROM `" + table + "` WHERE 1";
832         } else if (queryType == "insert") {
833                query = "INSERT INTO `" + table + "`(" + chaineAj + ") VALUES (" + valDis + ")";
834         } else if (queryType == "update") {
835             query = "UPDATE `" + table + "` SET " + editDis + " WHERE 1";
836         } else if(queryType == "delete") {
837             query = "DELETE FROM `" + table + "` WHERE 1";
838         }
839         setQuery(query);
840         sql_box_locked = false;
841     }
846   * Inserts multiple fields.
847   *
848   */
849 function insertValueQuery() {
850     var myQuery = document.sqlform.sql_query;
851     var myListBox = document.sqlform.dummy;
853     if(myListBox.options.length > 0) {
854         sql_box_locked = true;
855         var chaineAj = "";
856         var NbSelect = 0;
857         for(var i=0; i<myListBox.options.length; i++) {
858             if (myListBox.options[i].selected) {
859                 NbSelect++;
860                 if (NbSelect > 1) {
861                     chaineAj += ", ";
862                 }
863                 chaineAj += myListBox.options[i].value;
864             }
865         }
867         /* CodeMirror support */
868         if (codemirror_editor) {
869             codemirror_editor.replaceSelection(chaineAj);
870         //IE support
871         } else if (document.selection) {
872             myQuery.focus();
873             sel = document.selection.createRange();
874             sel.text = chaineAj;
875             document.sqlform.insert.focus();
876         }
877         //MOZILLA/NETSCAPE support
878         else if (document.sqlform.sql_query.selectionStart || document.sqlform.sql_query.selectionStart == "0") {
879             var startPos = document.sqlform.sql_query.selectionStart;
880             var endPos = document.sqlform.sql_query.selectionEnd;
881             var chaineSql = document.sqlform.sql_query.value;
883             myQuery.value = chaineSql.substring(0, startPos) + chaineAj + chaineSql.substring(endPos, chaineSql.length);
884         } else {
885             myQuery.value += chaineAj;
886         }
887         sql_box_locked = false;
888     }
892   * listbox redirection
893   */
894 function goToUrl(selObj, goToLocation) {
895     eval("document.location.href = '" + goToLocation + "pos=" + selObj.options[selObj.selectedIndex].value + "'");
899  * getElement
900  */
901 function getElement(e,f){
902     if(document.layers){
903         f=(f)?f:self;
904         if(f.document.layers[e]) {
905             return f.document.layers[e];
906         }
907         for(W=0;W<f.document.layers.length;W++) {
908             return(getElement(e,f.document.layers[W]));
909         }
910     }
911     if(document.all) {
912         return document.all[e];
913     }
914     return document.getElementById(e);
918   * Refresh the WYSIWYG scratchboard after changes have been made
919   */
920 function refreshDragOption(e) {
921     var elm = $('#' + e);
922     if (elm.css('visibility') == 'visible') {
923         refreshLayout();
924         TableDragInit();
925     }
929   * Refresh/resize the WYSIWYG scratchboard
930   */
931 function refreshLayout() {
932     var elm = $('#pdflayout')
933     var orientation = $('#orientation_opt').val();
934     if($('#paper_opt').length==1){
935         var paper = $('#paper_opt').val();
936     }else{
937         var paper = 'A4';
938     }
939     if (orientation == 'P') {
940         posa = 'x';
941         posb = 'y';
942     } else {
943         posa = 'y';
944         posb = 'x';
945     }
946     elm.css('width', pdfPaperSize(paper, posa) + 'px');
947     elm.css('height', pdfPaperSize(paper, posb) + 'px');
951   * Show/hide the WYSIWYG scratchboard
952   */
953 function ToggleDragDrop(e) {
954     var elm = $('#' + e);
955     if (elm.css('visibility') == 'hidden') {
956         PDFinit(); /* Defined in pdf_pages.php */
957         elm.css('visibility', 'visible');
958         elm.css('display', 'block');
959         $('#showwysiwyg').val('1')
960     } else {
961         elm.css('visibility', 'hidden');
962         elm.css('display', 'none');
963         $('#showwysiwyg').val('0')
964     }
968   * PDF scratchboard: When a position is entered manually, update
969   * the fields inside the scratchboard.
970   */
971 function dragPlace(no, axis, value) {
972     var elm = $('#table_' + no);
973     if (axis == 'x') {
974         elm.css('left', value + 'px');
975     } else {
976         elm.css('top', value + 'px');
977     }
981  * Returns paper sizes for a given format
982  */
983 function pdfPaperSize(format, axis) {
984     switch (format.toUpperCase()) {
985         case '4A0':
986             if (axis == 'x') return 4767.87; else return 6740.79;
987             break;
988         case '2A0':
989             if (axis == 'x') return 3370.39; else return 4767.87;
990             break;
991         case 'A0':
992             if (axis == 'x') return 2383.94; else return 3370.39;
993             break;
994         case 'A1':
995             if (axis == 'x') return 1683.78; else return 2383.94;
996             break;
997         case 'A2':
998             if (axis == 'x') return 1190.55; else return 1683.78;
999             break;
1000         case 'A3':
1001             if (axis == 'x') return 841.89; else return 1190.55;
1002             break;
1003         case 'A4':
1004             if (axis == 'x') return 595.28; else return 841.89;
1005             break;
1006         case 'A5':
1007             if (axis == 'x') return 419.53; else return 595.28;
1008             break;
1009         case 'A6':
1010             if (axis == 'x') return 297.64; else return 419.53;
1011             break;
1012         case 'A7':
1013             if (axis == 'x') return 209.76; else return 297.64;
1014             break;
1015         case 'A8':
1016             if (axis == 'x') return 147.40; else return 209.76;
1017             break;
1018         case 'A9':
1019             if (axis == 'x') return 104.88; else return 147.40;
1020             break;
1021         case 'A10':
1022             if (axis == 'x') return 73.70; else return 104.88;
1023             break;
1024         case 'B0':
1025             if (axis == 'x') return 2834.65; else return 4008.19;
1026             break;
1027         case 'B1':
1028             if (axis == 'x') return 2004.09; else return 2834.65;
1029             break;
1030         case 'B2':
1031             if (axis == 'x') return 1417.32; else return 2004.09;
1032             break;
1033         case 'B3':
1034             if (axis == 'x') return 1000.63; else return 1417.32;
1035             break;
1036         case 'B4':
1037             if (axis == 'x') return 708.66; else return 1000.63;
1038             break;
1039         case 'B5':
1040             if (axis == 'x') return 498.90; else return 708.66;
1041             break;
1042         case 'B6':
1043             if (axis == 'x') return 354.33; else return 498.90;
1044             break;
1045         case 'B7':
1046             if (axis == 'x') return 249.45; else return 354.33;
1047             break;
1048         case 'B8':
1049             if (axis == 'x') return 175.75; else return 249.45;
1050             break;
1051         case 'B9':
1052             if (axis == 'x') return 124.72; else return 175.75;
1053             break;
1054         case 'B10':
1055             if (axis == 'x') return 87.87; else return 124.72;
1056             break;
1057         case 'C0':
1058             if (axis == 'x') return 2599.37; else return 3676.54;
1059             break;
1060         case 'C1':
1061             if (axis == 'x') return 1836.85; else return 2599.37;
1062             break;
1063         case 'C2':
1064             if (axis == 'x') return 1298.27; else return 1836.85;
1065             break;
1066         case 'C3':
1067             if (axis == 'x') return 918.43; else return 1298.27;
1068             break;
1069         case 'C4':
1070             if (axis == 'x') return 649.13; else return 918.43;
1071             break;
1072         case 'C5':
1073             if (axis == 'x') return 459.21; else return 649.13;
1074             break;
1075         case 'C6':
1076             if (axis == 'x') return 323.15; else return 459.21;
1077             break;
1078         case 'C7':
1079             if (axis == 'x') return 229.61; else return 323.15;
1080             break;
1081         case 'C8':
1082             if (axis == 'x') return 161.57; else return 229.61;
1083             break;
1084         case 'C9':
1085             if (axis == 'x') return 113.39; else return 161.57;
1086             break;
1087         case 'C10':
1088             if (axis == 'x') return 79.37; else return 113.39;
1089             break;
1090         case 'RA0':
1091             if (axis == 'x') return 2437.80; else return 3458.27;
1092             break;
1093         case 'RA1':
1094             if (axis == 'x') return 1729.13; else return 2437.80;
1095             break;
1096         case 'RA2':
1097             if (axis == 'x') return 1218.90; else return 1729.13;
1098             break;
1099         case 'RA3':
1100             if (axis == 'x') return 864.57; else return 1218.90;
1101             break;
1102         case 'RA4':
1103             if (axis == 'x') return 609.45; else return 864.57;
1104             break;
1105         case 'SRA0':
1106             if (axis == 'x') return 2551.18; else return 3628.35;
1107             break;
1108         case 'SRA1':
1109             if (axis == 'x') return 1814.17; else return 2551.18;
1110             break;
1111         case 'SRA2':
1112             if (axis == 'x') return 1275.59; else return 1814.17;
1113             break;
1114         case 'SRA3':
1115             if (axis == 'x') return 907.09; else return 1275.59;
1116             break;
1117         case 'SRA4':
1118             if (axis == 'x') return 637.80; else return 907.09;
1119             break;
1120         case 'LETTER':
1121             if (axis == 'x') return 612.00; else return 792.00;
1122             break;
1123         case 'LEGAL':
1124             if (axis == 'x') return 612.00; else return 1008.00;
1125             break;
1126         case 'EXECUTIVE':
1127             if (axis == 'x') return 521.86; else return 756.00;
1128             break;
1129         case 'FOLIO':
1130             if (axis == 'x') return 612.00; else return 936.00;
1131             break;
1132     } // end switch
1134     return 0;
1138  * for playing media from the BLOB repository
1140  * @param   var
1141  * @param   var     url_params  main purpose is to pass the token
1142  * @param   var     bs_ref      BLOB repository reference
1143  * @param   var     m_type      type of BLOB repository media
1144  * @param   var     w_width     width of popup window
1145  * @param   var     w_height    height of popup window
1146  */
1147 function popupBSMedia(url_params, bs_ref, m_type, is_cust_type, w_width, w_height)
1149     // if width not specified, use default
1150     if (w_width == undefined) {
1151         w_width = 640;
1152     }
1154     // if height not specified, use default
1155     if (w_height == undefined) {
1156         w_height = 480;
1157     }
1159     // open popup window (for displaying video/playing audio)
1160     var mediaWin = window.open('bs_play_media.php?' + url_params + '&bs_reference=' + bs_ref + '&media_type=' + m_type + '&custom_type=' + is_cust_type, 'viewBSMedia', 'width=' + w_width + ', height=' + w_height + ', resizable=1, scrollbars=1, status=0');
1164  * popups a request for changing MIME types for files in the BLOB repository
1166  * @param   var     db                      database name
1167  * @param   var     table                   table name
1168  * @param   var     reference               BLOB repository reference
1169  * @param   var     current_mime_type       current MIME type associated with BLOB repository reference
1170  */
1171 function requestMIMETypeChange(db, table, reference, current_mime_type)
1173     // no mime type specified, set to default (nothing)
1174     if (undefined == current_mime_type) {
1175         current_mime_type = "";
1176     }
1178     // prompt user for new mime type
1179     var new_mime_type = prompt("Enter custom MIME type", current_mime_type);
1181     // if new mime_type is specified and is not the same as the previous type, request for mime type change
1182     if (new_mime_type && new_mime_type != current_mime_type) {
1183         changeMIMEType(db, table, reference, new_mime_type);
1184     }
1188  * changes MIME types for files in the BLOB repository
1190  * @param   var     db              database name
1191  * @param   var     table           table name
1192  * @param   var     reference       BLOB repository reference
1193  * @param   var     mime_type       new MIME type to be associated with BLOB repository reference
1194  */
1195 function changeMIMEType(db, table, reference, mime_type)
1197     // specify url and parameters for jQuery POST
1198     var mime_chg_url = 'bs_change_mime_type.php';
1199     var params = {bs_db: db, bs_table: table, bs_reference: reference, bs_new_mime_type: mime_type};
1201     // jQuery POST
1202     jQuery.post(mime_chg_url, params);
1206  * Jquery Coding for inline editing SQL_QUERY
1207  */
1208 $(document).ready(function(){
1209     $(".inline_edit_sql").live('click', function(){
1210         var server     = $(this).prev().find("input[name='server']").val();
1211         var db         = $(this).prev().find("input[name='db']").val();
1212         var table      = $(this).prev().find("input[name='table']").val();
1213         var token      = $(this).prev().find("input[name='token']").val();
1214         var sql_query  = $(this).prev().find("input[name='sql_query']").val();
1215         var $inner_sql = $(this).parent().prev().find('.inner_sql');
1216         var old_text   = $inner_sql.html();
1218         var new_content = "<textarea name=\"sql_query_edit\" id=\"sql_query_edit\">" + sql_query + "</textarea>\n";
1219         new_content    += "<input type=\"button\" class=\"btnSave\" value=\"" + PMA_messages['strGo'] + "\">\n";
1220         new_content    += "<input type=\"button\" class=\"btnDiscard\" value=\"" + PMA_messages['strCancel'] + "\">\n";
1221         $inner_sql.replaceWith(new_content);
1222         $(".btnSave").each(function(){
1223             $(this).click(function(){
1224                 sql_query = $(this).prev().val();
1225                 window.location.replace("import.php"
1226                                       + "?server=" + encodeURIComponent(server)
1227                                       + "&db=" + encodeURIComponent(db)
1228                                       + "&table=" + encodeURIComponent(table)
1229                                       + "&sql_query=" + encodeURIComponent(sql_query)
1230                                       + "&show_query=1"
1231                                       + "&token=" + token);
1232             });
1233         });
1234         $(".btnDiscard").each(function(){
1235             $(this).click(function(){
1236                 $(this).closest(".sql").html("<span class=\"syntax\"><span class=\"inner_sql\">" + old_text + "</span></span>");
1237             });
1238         });
1239         return false;
1240     });
1242     $('.sqlbutton').click(function(evt){
1243         insertQuery(evt.target.id);
1244         return false;
1245     });
1247     $("#export_type").change(function(){
1248         if($("#export_type").val()=='svg'){
1249             $("#show_grid_opt").attr("disabled","disabled");
1250             $("#orientation_opt").attr("disabled","disabled");
1251             $("#with_doc").attr("disabled","disabled");
1252             $("#show_table_dim_opt").removeAttr("disabled");
1253             $("#all_table_same_wide").removeAttr("disabled");
1254             $("#paper_opt").removeAttr("disabled","disabled");
1255             $("#show_color_opt").removeAttr("disabled","disabled");
1256             //$(this).css("background-color","yellow");
1257         }else if($("#export_type").val()=='dia'){
1258             $("#show_grid_opt").attr("disabled","disabled");
1259             $("#with_doc").attr("disabled","disabled");
1260             $("#show_table_dim_opt").attr("disabled","disabled");
1261             $("#all_table_same_wide").attr("disabled","disabled");
1262             $("#paper_opt").removeAttr("disabled","disabled");
1263             $("#show_color_opt").removeAttr("disabled","disabled");
1264             $("#orientation_opt").removeAttr("disabled","disabled");
1265         }else if($("#export_type").val()=='eps'){
1266             $("#show_grid_opt").attr("disabled","disabled");
1267             $("#orientation_opt").removeAttr("disabled");
1268             $("#with_doc").attr("disabled","disabled");
1269             $("#show_table_dim_opt").attr("disabled","disabled");
1270             $("#all_table_same_wide").attr("disabled","disabled");
1271             $("#paper_opt").attr("disabled","disabled");
1272             $("#show_color_opt").attr("disabled","disabled");
1274         }else if($("#export_type").val()=='pdf'){
1275             $("#show_grid_opt").removeAttr("disabled");
1276             $("#orientation_opt").removeAttr("disabled");
1277             $("#with_doc").removeAttr("disabled","disabled");
1278             $("#show_table_dim_opt").removeAttr("disabled","disabled");
1279             $("#all_table_same_wide").removeAttr("disabled","disabled");
1280             $("#paper_opt").removeAttr("disabled","disabled");
1281             $("#show_color_opt").removeAttr("disabled","disabled");
1282         }else{
1283             // nothing
1284         }
1285     });
1287     $('#sqlquery').focus().keydown(function (e) {
1288         if (e.ctrlKey && e.keyCode == 13) {
1289             $("#sqlqueryform").submit();
1290         }
1291     });
1293     if ($('#input_username')) {
1294         if ($('#input_username').val() == '') {
1295             $('#input_username').focus();
1296         } else {
1297             $('#input_password').focus();
1298         }
1299     }
1303  * Show a message on the top of the page for an Ajax request
1305  * @param   var     message     string containing the message to be shown.
1306  *                              optional, defaults to 'Loading...'
1307  * @param   var     timeout     number of milliseconds for the message to be visible
1308  *                              optional, defaults to 5000
1309  * @return  jQuery object       jQuery Element that holds the message div
1310  */
1311 function PMA_ajaxShowMessage(message, timeout) {
1313     //Handle the case when a empty data.message is passed. We don't want the empty message
1314     if (message == '') {
1315         return true;
1316     } else if (! message) {
1317         // If the message is undefined, show the default
1318         message = PMA_messages['strLoading'];
1319     }
1321     /**
1322      * @var timeout Number of milliseconds for which the message will be visible
1323      * @default 5000 ms
1324      */
1325     if (! timeout) {
1326         timeout = 5000;
1327     }
1329     // Create a parent element for the AJAX messages, if necessary
1330     if ($('#loading_parent').length == 0) {
1331         $('<div id="loading_parent"></div>')
1332         .insertBefore("#serverinfo");
1333     }
1335     // Update message count to create distinct message elements every time
1336     ajax_message_count++;
1338     // Remove all old messages, if any
1339     $(".ajax_notification[id^=ajax_message_num]").remove();
1341     /**
1342      * @var    $retval    a jQuery object containing the reference
1343      *                    to the created AJAX message
1344      */
1345     var $retval = $('<span class="ajax_notification" id="ajax_message_num_' + ajax_message_count + '"></span>')
1346         .hide()
1347         .appendTo("#loading_parent")
1348         .html(message)
1349         .fadeIn('medium')
1350         .delay(timeout)
1351         .fadeOut('medium', function() {
1352             $(this).remove();
1353         });
1355     return $retval;
1359  * Removes the message shown for an Ajax operation when it's completed
1360  */
1361 function PMA_ajaxRemoveMessage($this_msgbox) {
1362     if ($this_msgbox != undefined && $this_msgbox instanceof jQuery) {
1363         $this_msgbox
1364         .stop(true, true)
1365         .fadeOut('medium');
1366     }
1370  * Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected
1371  */
1372 function PMA_showNoticeForEnum(selectElement) {
1373     var enum_notice_id = selectElement.attr("id").split("_")[1];
1374     enum_notice_id += "_" + (parseInt(selectElement.attr("id").split("_")[2]) + 1);
1375     var selectedType = selectElement.attr("value");
1376     if (selectedType == "ENUM" || selectedType == "SET") {
1377         $("p[id='enum_notice_" + enum_notice_id + "']").show();
1378     } else {
1379         $("p[id='enum_notice_" + enum_notice_id + "']").hide();
1380     }
1384  * Generates a dialog box to pop up the create_table form
1385  */
1386 function PMA_createTableDialog( div, url , target) {
1387      /**
1388      *  @var    button_options  Object that stores the options passed to jQueryUI
1389      *                          dialog
1390      */
1391      var button_options = {};
1392      // in the following function we need to use $(this)
1393      button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
1395      var button_options_error = {};
1396      button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
1398      var $msgbox = PMA_ajaxShowMessage();
1400      $.get( target , url ,  function(data) {
1401          //in the case of an error, show the error message returned.
1402          if (data.success != undefined && data.success == false) {
1403              div
1404              .append(data.error)
1405              .dialog({
1406                  title: PMA_messages['strCreateTable'],
1407                  height: 230,
1408                  width: 900,
1409                  open: PMA_verifyTypeOfAllColumns,
1410                  buttons : button_options_error
1411              })// end dialog options
1412              //remove the redundant [Back] link in the error message.
1413              .find('fieldset').remove();
1414          } else {
1415              div
1416              .append(data)
1417              .dialog({
1418                  title: PMA_messages['strCreateTable'],
1419                  height: 600,
1420                  width: 900,
1421                  open: PMA_verifyTypeOfAllColumns,
1422                  buttons : button_options
1423              }); // end dialog options
1424          }
1425          PMA_ajaxRemoveMessage($msgbox);
1426      }) // end $.get()
1431  * Creates a highcharts chart in the given container
1433  * @param   var     settings    object with highcharts properties that should be applied. (See also http://www.highcharts.com/ref/)
1434  *                              requires at least settings.chart.renderTo and settings.series to be set.
1435  *                              In addition there may be an additional property object 'realtime' that allows for realtime charting:
1436  *                              realtime: {
1437  *                                  url: adress to get the data from (will always add token, ajax_request=1 and chart_data=1 to the GET request)
1438  *                                  type: the GET request will also add type=[value of the type property] to the request
1439  *                                  callback: Callback function that should draw the point, it's called with 4 parameters in this order:
1440  *                                      - the chart object
1441  *                                      - the current response value of the GET request, JSON parsed
1442  *                                      - the previous response value of the GET request, JSON parsed
1443  *                                      - the number of added points
1444  *                                  error: Callback function when the get request fails. TODO: Apply callback on timeouts aswell
1445  *                              }
1447  * @return  object   The created highcharts instance
1448  */
1449 function PMA_createChart(passedSettings) {
1450     var container = passedSettings.chart.renderTo;
1452     var settings = {
1453         chart: {
1454             type: 'spline',
1455             marginRight: 10,
1456             backgroundColor: 'none',
1457             events: {
1458                 /* Live charting support */
1459                 load: function() {
1460                     var thisChart = this;
1461                     var lastValue = null, curValue = null;
1462                     var numLoadedPoints = 0, otherSum = 0;
1463                     var diff;
1465                     // No realtime updates for graphs that are being exported, and disabled when realtime is not set
1466                     // Also don't do live charting if we don't have the server time
1467                     if(thisChart.options.chart.forExport == true ||
1468                         ! thisChart.options.realtime ||
1469                         ! thisChart.options.realtime.callback ||
1470                         ! server_time_diff) return;
1472                     thisChart.options.realtime.timeoutCallBack = function() {
1473                         thisChart.options.realtime.postRequest = $.post(
1474                             thisChart.options.realtime.url,
1475                             thisChart.options.realtime.postData,
1476                             function(data) {
1477                                 try {
1478                                     curValue = jQuery.parseJSON(data);
1479                                 } catch (err) {
1480                                     if(thisChart.options.realtime.error)
1481                                         thisChart.options.realtime.error(err);
1482                                     return;
1483                                 }
1485                                 if (lastValue==null) {
1486                                     diff = curValue.x - thisChart.xAxis[0].getExtremes().max;
1487                                 } else {
1488                                     diff = parseInt(curValue.x - lastValue.x);
1489                                 }
1491                                 thisChart.xAxis[0].setExtremes(
1492                                     thisChart.xAxis[0].getExtremes().min+diff,
1493                                     thisChart.xAxis[0].getExtremes().max+diff,
1494                                     false
1495                                 );
1497                                 thisChart.options.realtime.callback(thisChart,curValue,lastValue,numLoadedPoints);
1499                                 lastValue = curValue;
1500                                 numLoadedPoints++;
1502                                 // Timeout has been cleared => don't start a new timeout
1503                                 if (chart_activeTimeouts[container] == null) {
1504                                     return;
1505                                 }
1507                                 chart_activeTimeouts[container] = setTimeout(
1508                                     thisChart.options.realtime.timeoutCallBack,
1509                                     thisChart.options.realtime.refreshRate
1510                                 );
1511                         });
1512                     }
1514                     chart_activeTimeouts[container] = setTimeout(thisChart.options.realtime.timeoutCallBack, 5);
1515                 }
1516             }
1517         },
1518         plotOptions: {
1519             series: {
1520                 marker: {
1521                     radius: 3
1522                 }
1523             }
1524         },
1525         credits: {
1526             enabled:false
1527         },
1528         xAxis: {
1529             type: 'datetime'
1530         },
1531         yAxis: {
1532             min: 0,
1533             title: {
1534                 text: PMA_messages['strTotalCount']
1535             },
1536             plotLines: [{
1537                 value: 0,
1538                 width: 1,
1539                 color: '#808080'
1540             }]
1541         },
1542         tooltip: {
1543             formatter: function() {
1544                     return '<b>' + this.series.name +'</b><br/>' +
1545                     Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
1546                     Highcharts.numberFormat(this.y, 2);
1547             }
1548         },
1549         exporting: {
1550             enabled: true
1551         },
1552         series: []
1553     }
1555     /* Set/Get realtime chart default values */
1556     if(passedSettings.realtime) {
1557         if(!passedSettings.realtime.refreshRate) {
1558             passedSettings.realtime.refreshRate = 5000;
1559         }
1561         if(!passedSettings.realtime.numMaxPoints) {
1562             passedSettings.realtime.numMaxPoints = 30;
1563         }
1565         // Allow custom POST vars to be added
1566         passedSettings.realtime.postData = $.extend(false,{ ajax_request: true, chart_data: 1, type: passedSettings.realtime.type },passedSettings.realtime.postData);
1568         if(server_time_diff) {
1569             settings.xAxis.min = new Date().getTime() - server_time_diff - passedSettings.realtime.numMaxPoints * passedSettings.realtime.refreshRate;
1570             settings.xAxis.max = new Date().getTime() - server_time_diff + passedSettings.realtime.refreshRate;
1571         }
1572     }
1574     // Overwrite/Merge default settings with passedsettings
1575     $.extend(true,settings,passedSettings);
1577     return new Highcharts.Chart(settings);
1582  * Creates a Profiling Chart. Used in sql.php and server_status.js
1583  */
1584 function PMA_createProfilingChart(data, options) {
1585     return PMA_createChart($.extend(true, {
1586         chart: {
1587             renderTo: 'profilingchart',
1588             type: 'pie'
1589         },
1590         title: { text:'', margin:0 },
1591         series: [{
1592             type: 'pie',
1593             name: PMA_messages['strQueryExecutionTime'],
1594             data: data
1595         }],
1596         plotOptions: {
1597             pie: {
1598                 allowPointSelect: true,
1599                 cursor: 'pointer',
1600                 dataLabels: {
1601                     enabled: true,
1602                     distance: 35,
1603                     formatter: function() {
1604                         return '<b>'+ this.point.name +'</b><br/>'+ Highcharts.numberFormat(this.percentage, 2) +' %';
1605                    }
1606                 }
1607             }
1608         },
1609         tooltip: {
1610             formatter: function() {
1611                 return '<b>'+ this.point.name +'</b><br/>'+PMA_prettyProfilingNum(this.y)+'<br/>('+Highcharts.numberFormat(this.percentage, 2) +' %)';
1612             }
1613         }
1614     },options));
1617 // Formats a profiling duration nicely. Used in PMA_createProfilingChart() and server_status.js
1618 function PMA_prettyProfilingNum(num, acc) {
1619     if (!acc) {
1620         acc = 2;
1621     }
1622     acc = Math.pow(10,acc);
1623     if (num * 1000 < 0.1) {
1624         num = Math.round(acc * (num * 1000 * 1000)) / acc + 'µ';
1625     } else if (num < 0.1) {
1626         num = Math.round(acc * (num * 1000)) / acc + 'm';
1627     } else {
1628         num = Math.round(acc * num) / acc;
1629     }
1631     return num + 's';
1635  * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
1636  *  return a jQuery object yet and hence cannot be chained
1638  * @param   string      question
1639  * @param   string      url         URL to be passed to the callbackFn to make
1640  *                                  an Ajax call to
1641  * @param   function    callbackFn  callback to execute after user clicks on OK
1642  */
1644 jQuery.fn.PMA_confirm = function(question, url, callbackFn) {
1645     if (PMA_messages['strDoYouReally'] == '') {
1646         return true;
1647     }
1649     /**
1650      *  @var    button_options  Object that stores the options passed to jQueryUI
1651      *                          dialog
1652      */
1653     var button_options = {};
1654     button_options[PMA_messages['strOK']] = function(){
1655                                                 $(this).dialog("close").remove();
1657                                                 if($.isFunction(callbackFn)) {
1658                                                     callbackFn.call(this, url);
1659                                                 }
1660                                             };
1661     button_options[PMA_messages['strCancel']] = function() {$(this).dialog("close").remove();}
1663     $('<div id="confirm_dialog"></div>')
1664     .prepend(question)
1665     .dialog({buttons: button_options});
1669  * jQuery function to sort a table's body after a new row has been appended to it.
1670  * Also fixes the even/odd classes of the table rows at the end.
1672  * @param   string      text_selector   string to select the sortKey's text
1674  * @return  jQuery Object for chaining purposes
1675  */
1676 jQuery.fn.PMA_sort_table = function(text_selector) {
1677     return this.each(function() {
1679         /**
1680          * @var table_body  Object referring to the table's <tbody> element
1681          */
1682         var table_body = $(this);
1683         /**
1684          * @var rows    Object referring to the collection of rows in {@link table_body}
1685          */
1686         var rows = $(this).find('tr').get();
1688         //get the text of the field that we will sort by
1689         $.each(rows, function(index, row) {
1690             row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase());
1691         })
1693         //get the sorted order
1694         rows.sort(function(a,b) {
1695             if(a.sortKey < b.sortKey) {
1696                 return -1;
1697             }
1698             if(a.sortKey > b.sortKey) {
1699                 return 1;
1700             }
1701             return 0;
1702         })
1704         //pull out each row from the table and then append it according to it's order
1705         $.each(rows, function(index, row) {
1706             $(table_body).append(row);
1707             row.sortKey = null;
1708         })
1710         //Re-check the classes of each row
1711         $(this).find('tr:odd')
1712         .removeClass('even').addClass('odd')
1713         .end()
1714         .find('tr:even')
1715         .removeClass('odd').addClass('even');
1716     })
1720  * jQuery coding for 'Create Table'.  Used on db_operations.php,
1721  * db_structure.php and db_tracking.php (i.e., wherever
1722  * libraries/display_create_table.lib.php is used)
1724  * Attach Ajax Event handlers for Create Table
1725  */
1726 $(document).ready(function() {
1728      /**
1729      * Attach event handler to the submit action of the create table minimal form
1730      * and retrieve the full table form and display it in a dialog
1731      *
1732      * @uses    PMA_ajaxShowMessage()
1733      */
1734     $("#create_table_form_minimal.ajax").live('submit', function(event) {
1735         event.preventDefault();
1736         $form = $(this);
1737         PMA_prepareForAjaxRequest($form);
1739         /*variables which stores the common attributes*/
1740         var url = $form.serialize();
1741         var action = $form.attr('action');
1742         var div =  $('<div id="create_table_dialog"></div>');
1744         /*Calling to the createTableDialog function*/
1745         PMA_createTableDialog(div, url, action);
1747         // empty table name and number of columns from the minimal form
1748         $form.find('input[name=table],input[name=num_fields]').val('');
1749     });
1751     /**
1752      * Attach event handler for submission of create table form (save)
1753      *
1754      * @uses    PMA_ajaxShowMessage()
1755      * @uses    $.PMA_sort_table()
1756      *
1757      */
1758     // .live() must be called after a selector, see http://api.jquery.com/live
1759     $("#create_table_form input[name=do_save_data]").live('click', function(event) {
1760         event.preventDefault();
1762         /**
1763          *  @var    the_form    object referring to the create table form
1764          */
1765         var $form = $("#create_table_form");
1767         /*
1768          * First validate the form; if there is a problem, avoid submitting it
1769          *
1770          * checkTableEditForm() needs a pure element and not a jQuery object,
1771          * this is why we pass $form[0] as a parameter (the jQuery object
1772          * is actually an array of DOM elements)
1773          */
1775         if (checkTableEditForm($form[0], $form.find('input[name=orig_num_fields]').val())) {
1776             // OK, form passed validation step
1777             if ($form.hasClass('ajax')) {
1778                 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1779                 PMA_prepareForAjaxRequest($form);
1780                 //User wants to submit the form
1781                 $.post($form.attr('action'), $form.serialize() + "&do_save_data=" + $(this).val(), function(data) {
1782                     if(data.success == true) {
1783                         $('#properties_message')
1784                          .removeClass('error')
1785                          .html('');
1786                         PMA_ajaxShowMessage(data.message);
1787                         // Only if the create table dialog (distinct panel) exists
1788                         if ($("#create_table_dialog").length > 0) {
1789                             $("#create_table_dialog").dialog("close").remove();
1790                         }
1792                         /**
1793                          * @var tables_table    Object referring to the <tbody> element that holds the list of tables
1794                          */
1795                         var tables_table = $("#tablesForm").find("tbody").not("#tbl_summary_row");
1796                         // this is the first table created in this db
1797                         if (tables_table.length == 0) {
1798                             if (window.parent && window.parent.frame_content) {
1799                                 window.parent.frame_content.location.reload();
1800                             }
1801                         } else {
1802                             /**
1803                              * @var curr_last_row   Object referring to the last <tr> element in {@link tables_table}
1804                              */
1805                             var curr_last_row = $(tables_table).find('tr:last');
1806                             /**
1807                              * @var curr_last_row_index_string   String containing the index of {@link curr_last_row}
1808                              */
1809                             var curr_last_row_index_string = $(curr_last_row).find('input:checkbox').attr('id').match(/\d+/)[0];
1810                             /**
1811                              * @var curr_last_row_index Index of {@link curr_last_row}
1812                              */
1813                             var curr_last_row_index = parseFloat(curr_last_row_index_string);
1814                             /**
1815                              * @var new_last_row_index   Index of the new row to be appended to {@link tables_table}
1816                              */
1817                             var new_last_row_index = curr_last_row_index + 1;
1818                             /**
1819                              * @var new_last_row_id String containing the id of the row to be appended to {@link tables_table}
1820                              */
1821                             var new_last_row_id = 'checkbox_tbl_' + new_last_row_index;
1823                             data.new_table_string = data.new_table_string.replace(/checkbox_tbl_/, new_last_row_id);
1824                             //append to table
1825                             $(data.new_table_string)
1826                              .appendTo(tables_table);
1828                             //Sort the table
1829                             $(tables_table).PMA_sort_table('th');
1830                         }
1832                         //Refresh navigation frame as a new table has been added
1833                         if (window.parent && window.parent.frame_navigation) {
1834                             window.parent.frame_navigation.location.reload();
1835                         }
1836                     } else {
1837                         $('#properties_message')
1838                          .addClass('error')
1839                          .html(data.error);
1840                         // scroll to the div containing the error message
1841                         $('#properties_message')[0].scrollIntoView();
1842                     }
1843                 }) // end $.post()
1844             } // end if ($form.hasClass('ajax')
1845             else {
1846                 // non-Ajax submit
1847                 $form.append('<input type="hidden" name="do_save_data" value="save" />');
1848                 $form.submit();
1849             }
1850         } // end if (checkTableEditForm() )
1851     }) // end create table form (save)
1853     /**
1854      * Attach event handler for create table form (add fields)
1855      *
1856      * @uses    PMA_ajaxShowMessage()
1857      * @uses    $.PMA_sort_table()
1858      * @uses    window.parent.refreshNavigation()
1859      *
1860      */
1861     // .live() must be called after a selector, see http://api.jquery.com/live
1862     $("#create_table_form.ajax input[name=submit_num_fields]").live('click', function(event) {
1863         event.preventDefault();
1865         /**
1866          *  @var    the_form    object referring to the create table form
1867          */
1868         var $form = $("#create_table_form");
1870         var $msgbox = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1871         PMA_prepareForAjaxRequest($form);
1873         //User wants to add more fields to the table
1874         $.post($form.attr('action'), $form.serialize() + "&submit_num_fields=" + $(this).val(), function(data) {
1875             // if 'create_table_dialog' exists
1876             if ($("#create_table_dialog").length > 0) {
1877                 $("#create_table_dialog").html(data);
1878             }
1879             // if 'create_table_div' exists
1880             if ($("#create_table_div").length > 0) {
1881                 $("#create_table_div").html(data);
1882             }
1883             PMA_verifyTypeOfAllColumns();
1884             PMA_ajaxRemoveMessage($msgbox);
1885         }) //end $.post()
1887     }) // end create table form (add fields)
1889 }, 'top.frame_content'); //end $(document).ready for 'Create Table'
1892  * jQuery coding for 'Change Table' and 'Add Column'.  Used on tbl_structure.php *
1893  * Attach Ajax Event handlers for Change Table
1894  */
1895 $(document).ready(function() {
1896     /**
1897      *Ajax action for submitting the "Column Change" and "Add Column" form
1898     **/
1899     $("#append_fields_form input[name=do_save_data]").live('click', function(event) {
1900         event.preventDefault();
1901         /**
1902          *  @var    the_form    object referring to the export form
1903          */
1904         var $form = $("#append_fields_form");
1906         /*
1907          * First validate the form; if there is a problem, avoid submitting it
1908          *
1909          * checkTableEditForm() needs a pure element and not a jQuery object,
1910          * this is why we pass $form[0] as a parameter (the jQuery object
1911          * is actually an array of DOM elements)
1912          */
1913         if (checkTableEditForm($form[0], $form.find('input[name=orig_num_fields]').val())) {
1914             // OK, form passed validation step
1915             if ($form.hasClass('ajax')) {
1916                 PMA_prepareForAjaxRequest($form);
1917                 //User wants to submit the form
1918                 $.post($form.attr('action'), $form.serialize()+"&do_save_data=Save", function(data) {
1919                     if ($("#sqlqueryresults").length != 0) {
1920                         $("#sqlqueryresults").remove();
1921                     } else if ($(".error").length != 0) {
1922                         $(".error").remove();
1923                     }
1924                     if (data.success == true) {
1925                         PMA_ajaxShowMessage(data.message);
1926                         $("<div id='sqlqueryresults'></div>").insertAfter("#topmenucontainer");
1927                         $("#sqlqueryresults").html(data.sql_query);
1928                         $("#result_query .notice").remove();
1929                         $("#result_query").prepend((data.message));
1930                         if ($("#change_column_dialog").length > 0) {
1931                             $("#change_column_dialog").dialog("close").remove();
1932                         } else if ($("#add_columns").length > 0) {
1933                             $("#add_columns").dialog("close").remove();
1934                         }
1935                         /*Reload the field form*/
1936                         $.post($("#fieldsForm").attr('action'), $("#fieldsForm").serialize()+"&ajax_request=true", function(form_data) {
1937                             $("#fieldsForm").remove();
1938                             $("#addColumns").remove();
1939                             var $temp_div = $("<div id='temp_div'><div>").append(form_data);
1940                             if ($("#sqlqueryresults").length != 0) {
1941                                 $temp_div.find("#fieldsForm").insertAfter("#sqlqueryresults");
1942                             } else {
1943                                 $temp_div.find("#fieldsForm").insertAfter(".error");
1944                             }
1945                             $temp_div.find("#addColumns").insertBefore("iframe.IE_hack");
1946                             /*Call the function to display the more options in table*/
1947                             displayMoreTableOpts();
1948                         });
1949                     } else {
1950                         var $temp_div = $("<div id='temp_div'><div>").append(data);
1951                         var $error = $temp_div.find(".error code").addClass("error");
1952                         PMA_ajaxShowMessage($error);
1953                     }
1954                 }) // end $.post()
1955             } else {
1956                 // non-Ajax submit
1957                 $form.append('<input type="hidden" name="do_save_data" value="Save" />');
1958                 $form.submit();
1959             }
1960         }
1961     }) // end change table button "do_save_data"
1963 }, 'top.frame_content'); //end $(document).ready for 'Change Table'
1966  * jQuery coding for 'Table operations'.  Used on tbl_operations.php
1967  * Attach Ajax Event handlers for Table operations
1968  */
1969 $(document).ready(function() {
1970     /**
1971      *Ajax action for submitting the "Alter table order by"
1972     **/
1973     $("#alterTableOrderby.ajax").live('submit', function(event) {
1974         event.preventDefault();
1975         $form = $(this);
1977         PMA_prepareForAjaxRequest($form);
1978         /*variables which stores the common attributes*/
1979         $.post($form.attr('action'), $form.serialize()+"&submitorderby=Go", function(data) {
1980             if ($("#sqlqueryresults").length != 0) {
1981                 $("#sqlqueryresults").remove();
1982             }
1983             if ($("#result_query").length != 0) {
1984                 $("#result_query").remove();
1985             }
1986             if (data.success == true) {
1987                 PMA_ajaxShowMessage(data.message);
1988                 $("<div id='sqlqueryresults'></div>").insertAfter("#topmenucontainer");
1989                 $("#sqlqueryresults").html(data.sql_query);
1990                 $("#result_query .notice").remove();
1991                 $("#result_query").prepend((data.message));
1992             } else {
1993                 $temp_div = $("<div id='temp_div'></div>")
1994                 $temp_div.html(data.error);
1995                 $error = $temp_div.find("code").addClass("error");
1996                 PMA_ajaxShowMessage($error);
1997             }
1998         }) // end $.post()
1999     });//end of alterTableOrderby ajax submit
2001     /**
2002      *Ajax action for submitting the "Copy table"
2003     **/
2004     $("#copyTable.ajax input[name='submit_copy']").live('click', function(event) {
2005         event.preventDefault();
2006         $form = $("#copyTable");
2007         if($form.find("input[name='switch_to_new']").attr('checked')) {
2008             $form.append('<input type="hidden" name="submit_copy" value="Go" />');
2009             $form.removeClass('ajax');
2010             $form.find("#ajax_request_hidden").remove();
2011             $form.submit();
2012         } else {
2013             PMA_prepareForAjaxRequest($form);
2014             /*variables which stores the common attributes*/
2015             $.post($form.attr('action'), $form.serialize()+"&submit_copy=Go", function(data) {
2016                 if ($("#sqlqueryresults").length != 0) {
2017                     $("#sqlqueryresults").remove();
2018                 }
2019                 if ($("#result_query").length != 0) {
2020                     $("#result_query").remove();
2021                 }
2022                 if (data.success == true) {
2023                     PMA_ajaxShowMessage(data.message);
2024                     $("<div id='sqlqueryresults'></div>").insertAfter("#topmenucontainer");
2025                     $("#sqlqueryresults").html(data.sql_query);
2026                     $("#result_query .notice").remove();
2027                     $("#result_query").prepend((data.message));
2028                     $("#copyTable").find("select[name='target_db'] option[value="+data.db+"]").attr('selected', 'selected');
2030                     //Refresh navigation frame when the table is coppied
2031                     if (window.parent && window.parent.frame_navigation) {
2032                         window.parent.frame_navigation.location.reload();
2033                     }
2034                 } else {
2035                     $temp_div = $("<div id='temp_div'></div>")
2036                     $temp_div.html(data.error);
2037                     $error = $temp_div.find("code").addClass("error");
2038                     PMA_ajaxShowMessage($error);
2039                 }
2040             }) // end $.post()
2041         }
2042     });//end of copyTable ajax submit
2044 }, 'top.frame_content'); //end $(document).ready for 'Table operations'
2048  * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js
2049  * as it was also required on db_create.php
2051  * @uses    $.PMA_confirm()
2052  * @uses    PMA_ajaxShowMessage()
2053  * @uses    window.parent.refreshNavigation()
2054  * @uses    window.parent.refreshMain()
2055  * @see $cfg['AjaxEnable']
2056  */
2057 $(document).ready(function() {
2058     $("#drop_db_anchor").live('click', function(event) {
2059         event.preventDefault();
2061         //context is top.frame_content, so we need to use window.parent.db to access the db var
2062         /**
2063          * @var question    String containing the question to be asked for confirmation
2064          */
2065         var question = PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP DATABASE ' + window.parent.db;
2067         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2069             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2070             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2071                 //Database deleted successfully, refresh both the frames
2072                 window.parent.refreshNavigation();
2073                 window.parent.refreshMain();
2074             }) // end $.get()
2075         }); // end $.PMA_confirm()
2076     }); //end of Drop Database Ajax action
2077 }) // end of $(document).ready() for Drop Database
2080  * Attach Ajax event handlers for 'Create Database'.  Used wherever libraries/
2081  * display_create_database.lib.php is used, ie main.php and server_databases.php
2083  * @uses    PMA_ajaxShowMessage()
2084  * @see $cfg['AjaxEnable']
2085  */
2086 $(document).ready(function() {
2088     $('#create_database_form.ajax').live('submit', function(event) {
2089         event.preventDefault();
2091         $form = $(this);
2093         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2094         PMA_prepareForAjaxRequest($form);
2096         $.post($form.attr('action'), $form.serialize(), function(data) {
2097             if(data.success == true) {
2098                 PMA_ajaxShowMessage(data.message);
2100                 //Append database's row to table
2101                 $("#tabledatabases")
2102                 .find('tbody')
2103                 .append(data.new_db_string)
2104                 .PMA_sort_table('.name')
2105                 .find('#db_summary_row')
2106                 .appendTo('#tabledatabases tbody')
2107                 .removeClass('odd even');
2109                 var $databases_count_object = $('#databases_count');
2110                 var databases_count = parseInt($databases_count_object.text());
2111                 $databases_count_object.text(++databases_count);
2112                 //Refresh navigation frame as a new database has been added
2113                 if (window.parent && window.parent.frame_navigation) {
2114                     window.parent.frame_navigation.location.reload();
2115                 }
2116             }
2117             else {
2118                 PMA_ajaxShowMessage(data.error);
2119             }
2120         }) // end $.post()
2121     }) // end $().live()
2122 })  // end $(document).ready() for Create Database
2125  * Attach Ajax event handlers for 'Change Password' on main.php
2126  */
2127 $(document).ready(function() {
2129     /**
2130      * Attach Ajax event handler on the change password anchor
2131      * @see $cfg['AjaxEnable']
2132      */
2133     $('#change_password_anchor.dialog_active').live('click',function(event) {
2134         event.preventDefault();
2135         return false;
2136         });
2137     $('#change_password_anchor.ajax').live('click', function(event) {
2138         event.preventDefault();
2139         $(this).removeClass('ajax').addClass('dialog_active');
2140         /**
2141          * @var button_options  Object containing options to be passed to jQueryUI's dialog
2142          */
2143         var button_options = {};
2144         button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
2145         $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
2146             $('<div id="change_password_dialog"></div>')
2147             .dialog({
2148                 title: PMA_messages['strChangePassword'],
2149                 width: 600,
2150                 close: function(ev,ui) {$(this).remove();},
2151                 buttons : button_options,
2152                 beforeClose: function(ev,ui){ $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax')}
2153             })
2154             .append(data);
2155             displayPasswordGenerateButton();
2156         }) // end $.get()
2157     }) // end handler for change password anchor
2159     /**
2160      * Attach Ajax event handler for Change Password form submission
2161      *
2162      * @uses    PMA_ajaxShowMessage()
2163      * @see $cfg['AjaxEnable']
2164      */
2165     $("#change_password_form.ajax").find('input[name=change_pw]').live('click', function(event) {
2166         event.preventDefault();
2168         /**
2169          * @var the_form    Object referring to the change password form
2170          */
2171         var the_form = $("#change_password_form");
2173         /**
2174          * @var this_value  String containing the value of the submit button.
2175          * Need to append this for the change password form on Server Privileges
2176          * page to work
2177          */
2178         var this_value = $(this).val();
2180         var $msgbox = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2181         $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
2183         $.post($(the_form).attr('action'), $(the_form).serialize() + '&change_pw='+ this_value, function(data) {
2184             if(data.success == true) {
2185                 $("#topmenucontainer").after(data.sql_query);
2186                 $("#change_password_dialog").hide().remove();
2187                 $("#edit_user_dialog").dialog("close").remove();
2188                 $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax');
2189                 PMA_ajaxRemoveMessage($msgbox);
2190             }
2191             else {
2192                 PMA_ajaxShowMessage(data.error);
2193             }
2194         }) // end $.post()
2195     }) // end handler for Change Password form submission
2196 }) // end $(document).ready() for Change Password
2199  * Toggle the hiding/showing of the "Open in ENUM/SET editor" message when
2200  * the page loads and when the selected data type changes
2201  */
2202 $(document).ready(function() {
2203     // is called here for normal page loads and also when opening
2204     // the Create table dialog
2205     PMA_verifyTypeOfAllColumns();
2206     //
2207     // needs live() to work also in the Create Table dialog
2208     $("select[class='column_type']").live('change', function() {
2209         PMA_showNoticeForEnum($(this));
2210     });
2213 function PMA_verifyTypeOfAllColumns() {
2214     $("select[class='column_type']").each(function() {
2215         PMA_showNoticeForEnum($(this));
2216     });
2220  * Closes the ENUM/SET editor and removes the data in it
2221  */
2222 function disable_popup() {
2223     $("#popup_background").fadeOut("fast");
2224     $("#enum_editor").fadeOut("fast");
2225     // clear the data from the text boxes
2226     $("#enum_editor #values input").remove();
2227     $("#enum_editor input[type='hidden']").remove();
2231  * Opens the ENUM/SET editor and controls its functions
2232  */
2233 $(document).ready(function() {
2234     // Needs live() to work also in the Create table dialog
2235     $("a[class='open_enum_editor']").live('click', function() {
2236         // Center the popup
2237         var windowWidth = document.documentElement.clientWidth;
2238         var windowHeight = document.documentElement.clientHeight;
2239         var popupWidth = windowWidth/2;
2240         var popupHeight = windowHeight*0.8;
2241         var popupOffsetTop = windowHeight/2 - popupHeight/2;
2242         var popupOffsetLeft = windowWidth/2 - popupWidth/2;
2243         $("#enum_editor").css({"position":"absolute", "top": popupOffsetTop, "left": popupOffsetLeft, "width": popupWidth, "height": popupHeight});
2245         // Make it appear
2246         $("#popup_background").css({"opacity":"0.7"});
2247         $("#popup_background").fadeIn("fast");
2248         $("#enum_editor").fadeIn("fast");
2249         /**Replacing the column name in the enum editor header*/
2250         var column_name = $("#append_fields_form").find("input[id=field_0_1]").attr("value");
2251         var h3_text = $("#enum_editor h3").html();
2252         $("#enum_editor h3").html(h3_text.split('"')[0]+'"'+column_name+'"');
2254         // Get the values
2255         var values = $(this).parent().prev("input").attr("value").split(",");
2256         $.each(values, function(index, val) {
2257             if(jQuery.trim(val) != "") {
2258                  // enclose the string in single quotes if it's not already
2259                  if(val.substr(0, 1) != "'") {
2260                       val = "'" + val;
2261                  }
2262                  if(val.substr(val.length-1, val.length) != "'") {
2263                       val = val + "'";
2264                  }
2265                 // escape the single quotes, except the mandatory ones enclosing the entire string
2266                 val = val.substr(1, val.length-2).replace(/''/g, "'").replace(/\\\\/g, '\\').replace(/\\'/g, "'").replace(/'/g, "&#039;");
2267                 // escape the greater-than symbol
2268                 val = val.replace(/>/g, "&gt;");
2269                 $("#enum_editor #values").append("<input type='text' value=" + val + " />");
2270             }
2271         });
2272         // So we know which column's data is being edited
2273         $("#enum_editor").append("<input type='hidden' value='" + $(this).parent().prev("input").attr("id") + "' />");
2274         return false;
2275     });
2277     // If the "close" link is clicked, close the enum editor
2278     // Needs live() to work also in the Create table dialog
2279     $("a[class='close_enum_editor']").live('click', function() {
2280         disable_popup();
2281     });
2283     // If the "cancel" link is clicked, close the enum editor
2284     // Needs live() to work also in the Create table dialog
2285     $("a[class='cancel_enum_editor']").live('click', function() {
2286         disable_popup();
2287     });
2289     // When "add a new value" is clicked, append an empty text field
2290     // Needs live() to work also in the Create table dialog
2291     $("a[class='add_value']").live('click', function() {
2292         $("#enum_editor #values").append("<input type='text' />");
2293     });
2295     // When the submit button is clicked, put the data back into the original form
2296     // Needs live() to work also in the Create table dialog
2297     $("#enum_editor input[type='submit']").live('click', function() {
2298         var value_array = new Array();
2299         $.each($("#enum_editor #values input"), function(index, input_element) {
2300             val = jQuery.trim(input_element.value);
2301             if(val != "") {
2302                 value_array.push("'" + val.replace(/\\/g, '\\\\').replace(/'/g, "''") + "'");
2303             }
2304         });
2305         // get the Length/Values text field where this value belongs
2306         var values_id = $("#enum_editor input[type='hidden']").attr("value");
2307         $("input[id='" + values_id + "']").attr("value", value_array.join(","));
2308         disable_popup();
2309      });
2311     /**
2312      * Hides certain table structure actions, replacing them with the word "More". They are displayed
2313      * in a dropdown menu when the user hovers over the word "More."
2314      */
2315     displayMoreTableOpts();
2318 function displayMoreTableOpts() {
2319     // Remove the actions from the table cells (they are available by default for JavaScript-disabled browsers)
2320     // if the table is not a view or information_schema (otherwise there is only one action to hide and there's no point)
2321     if($("input[type='hidden'][name='table_type']").val() == "table") {
2322         var $table = $("table[id='tablestructure']");
2323         $table.find("td[class='browse']").remove();
2324         $table.find("td[class='primary']").remove();
2325         $table.find("td[class='unique']").remove();
2326         $table.find("td[class='index']").remove();
2327         $table.find("td[class='fulltext']").remove();
2328         $table.find("td[class='spatial']").remove();
2329         $table.find("th[class='action']").attr("colspan", 3);
2331         // Display the "more" text
2332         $table.find("td[class='more_opts']").show();
2334         // Position the dropdown
2335         $(".structure_actions_dropdown").each(function() {
2336             // Optimize DOM querying
2337             var $this_dropdown = $(this);
2338              // The top offset must be set for IE even if it didn't change
2339             var cell_right_edge_offset = $this_dropdown.parent().position().left + $this_dropdown.parent().innerWidth();
2340             var left_offset = cell_right_edge_offset - $this_dropdown.innerWidth();
2341             var top_offset = $this_dropdown.parent().position().top + $this_dropdown.parent().innerHeight();
2342             $this_dropdown.offset({ top: top_offset, left: left_offset });
2343         });
2345         // A hack for IE6 to prevent the after_field select element from being displayed on top of the dropdown by
2346         // positioning an iframe directly on top of it
2347         var $after_field = $("select[name='after_field']");
2348         $("iframe[class='IE_hack']")
2349             .width($after_field.width())
2350             .height($after_field.height())
2351             .offset({
2352                 top: $after_field.offset().top,
2353                 left: $after_field.offset().left
2354             });
2356         // When "more" is hovered over, show the hidden actions
2357         $table.find("td[class='more_opts']")
2358             .mouseenter(function() {
2359                 if($.browser.msie && $.browser.version == "6.0") {
2360                     $("iframe[class='IE_hack']")
2361                         .show()
2362                         .width($after_field.width()+4)
2363                         .height($after_field.height()+4)
2364                         .offset({
2365                             top: $after_field.offset().top,
2366                             left: $after_field.offset().left
2367                         });
2368                 }
2369                 $(".structure_actions_dropdown").hide(); // Hide all the other ones that may be open
2370                 $(this).children(".structure_actions_dropdown").show();
2371                 // Need to do this again for IE otherwise the offset is wrong
2372                 if($.browser.msie) {
2373                     var left_offset_IE = $(this).offset().left + $(this).innerWidth() - $(this).children(".structure_actions_dropdown").innerWidth();
2374                     var top_offset_IE = $(this).offset().top + $(this).innerHeight();
2375                     $(this).children(".structure_actions_dropdown").offset({
2376                         top: top_offset_IE,
2377                         left: left_offset_IE });
2378                 }
2379             })
2380             .mouseleave(function() {
2381                 $(this).children(".structure_actions_dropdown").hide();
2382                 if($.browser.msie && $.browser.version == "6.0") {
2383                     $("iframe[class='IE_hack']").hide();
2384                 }
2385             });
2386     }
2389 $(document).ready(function(){
2390     PMA_convertFootnotesToTooltips();
2394  * Ensures indexes names are valid according to their type and, for a primary
2395  * key, lock index name to 'PRIMARY'
2396  * @param   string   form_id  Variable which parses the form name as
2397  *                            the input
2398  * @return  boolean  false    if there is no index form, true else
2399  */
2400 function checkIndexName(form_id)
2402     if ($("#"+form_id).length == 0) {
2403         return false;
2404     }
2406     // Gets the elements pointers
2407     var $the_idx_name = $("#input_index_name");
2408     var $the_idx_type = $("#select_index_type");
2410     // Index is a primary key
2411     if ($the_idx_type.find("option:selected").attr("value") == 'PRIMARY') {
2412         $the_idx_name.attr("value", 'PRIMARY');
2413         $the_idx_name.attr("disabled", true);
2414     }
2416     // Other cases
2417     else {
2418         if ($the_idx_name.attr("value") == 'PRIMARY') {
2419             $the_idx_name.attr("value",  '');
2420         }
2421         $the_idx_name.attr("disabled", false);
2422     }
2424     return true;
2425 } // end of the 'checkIndexName()' function
2428  * function to convert the footnotes to tooltips
2430  * @param   jquery-Object   $div    a div jquery object which specifies the
2431  *                                  domain for searching footnootes. If we
2432  *                                  ommit this parameter the function searches
2433  *                                  the footnotes in the whole body
2434  **/
2435 function PMA_convertFootnotesToTooltips($div) {
2436     // Hide the footnotes from the footer (which are displayed for
2437     // JavaScript-disabled browsers) since the tooltip is sufficient
2439     if ($div == undefined || ! $div instanceof jQuery || $div.length == 0) {
2440         $div = $("#serverinfo").parent();
2441     }
2443     $footnotes = $div.find(".footnotes");
2445     $footnotes.hide();
2446     $footnotes.find('span').each(function() {
2447         $(this).children("sup").remove();
2448     });
2449     // The border and padding must be removed otherwise a thin yellow box remains visible
2450     $footnotes.css("border", "none");
2451     $footnotes.css("padding", "0px");
2453     // Replace the superscripts with the help icon
2454     $div.find("sup.footnotemarker").hide();
2455     $div.find("img.footnotemarker").show();
2457     $div.find("img.footnotemarker").each(function() {
2458         var img_class = $(this).attr("class");
2459         /** img contains two classes, as example "footnotemarker footnote_1".
2460          *  We split it by second class and take it for the id of span
2461         */
2462         img_class = img_class.split(" ");
2463         for (i = 0; i < img_class.length; i++) {
2464             if (img_class[i].split("_")[0] == "footnote") {
2465                 var span_id = img_class[i].split("_")[1];
2466             }
2467         }
2468         /**
2469          * Now we get the #id of the span with span_id variable. As an example if we
2470          * initially get the img class as "footnotemarker footnote_2", now we get
2471          * #2 as the span_id. Using that we can find footnote_2 in footnotes.
2472          * */
2473         var tooltip_text = $footnotes.find("span[id='footnote_" + span_id + "']").html();
2474         $(this).qtip({
2475             content: tooltip_text,
2476             show: { delay: 0 },
2477             hide: { delay: 1000 },
2478             style: { background: '#ffffcc' }
2479         });
2480     });
2483 function menuResize()
2485     var cnt = $('#topmenu');
2486     var wmax = cnt.innerWidth() - 5; // 5 px margin for jumping menu in Chrome
2487     var submenu = cnt.find('.submenu');
2488     var submenu_w = submenu.outerWidth(true);
2489     var submenu_ul = submenu.find('ul');
2490     var li = cnt.find('> li');
2491     var li2 = submenu_ul.find('li');
2492     var more_shown = li2.length > 0;
2493     var w = more_shown ? submenu_w : 0;
2495     // hide menu items
2496     var hide_start = 0;
2497     for (var i = 0; i < li.length-1; i++) { // li.length-1: skip .submenu element
2498         var el = $(li[i]);
2499         var el_width = el.outerWidth(true);
2500         el.data('width', el_width);
2501         w += el_width;
2502         if (w > wmax) {
2503             w -= el_width;
2504             if (w + submenu_w < wmax) {
2505                 hide_start = i;
2506             } else {
2507                 hide_start = i-1;
2508                 w -= $(li[i-1]).data('width');
2509             }
2510             break;
2511         }
2512     }
2514     if (hide_start > 0) {
2515         for (var i = hide_start; i < li.length-1; i++) {
2516             $(li[i])[more_shown ? 'prependTo' : 'appendTo'](submenu_ul);
2517         }
2518         submenu.addClass('shown');
2519     } else if (more_shown) {
2520         w -= submenu_w;
2521         // nothing hidden, maybe something can be restored
2522         for (var i = 0; i < li2.length; i++) {
2523             //console.log(li2[i], submenu_w);
2524             w += $(li2[i]).data('width');
2525             // item fits or (it is the last item and it would fit if More got removed)
2526             if (w+submenu_w < wmax || (i == li2.length-1 && w < wmax)) {
2527                 $(li2[i]).insertBefore(submenu);
2528                 if (i == li2.length-1) {
2529                     submenu.removeClass('shown');
2530                 }
2531                 continue;
2532             }
2533             break;
2534         }
2535     }
2536     if (submenu.find('.tabactive').length) {
2537         submenu.addClass('active').find('> a').removeClass('tab').addClass('tabactive');
2538     } else {
2539         submenu.removeClass('active').find('> a').addClass('tab').removeClass('tabactive');
2540     }
2543 $(function() {
2544     var topmenu = $('#topmenu');
2545     if (topmenu.length == 0) {
2546         return;
2547     }
2548     // create submenu container
2549     var link = $('<a />', {href: '#', 'class': 'tab'})
2550         .text(PMA_messages['strMore'])
2551         .click(function(e) {
2552             e.preventDefault();
2553         });
2554     var img = topmenu.find('li:first-child img');
2555     if (img.length) {
2556         img.clone().attr('class', 'icon ic_b_more').prependTo(link);
2557     }
2558     var submenu = $('<li />', {'class': 'submenu'})
2559         .append(link)
2560         .append($('<ul />'))
2561         .mouseenter(function() {
2562             if ($(this).find('ul .tabactive').length == 0) {
2563                 $(this).addClass('submenuhover').find('> a').addClass('tabactive');
2564             }
2565         })
2566         .mouseleave(function() {
2567             if ($(this).find('ul .tabactive').length == 0) {
2568                 $(this).removeClass('submenuhover').find('> a').removeClass('tabactive');
2569             }
2570         });
2571     topmenu.append(submenu);
2573     // populate submenu and register resize event
2574     $(window).resize(menuResize);
2575     menuResize();
2579  * Get the row number from the classlist (for example, row_1)
2580  */
2581 function PMA_getRowNumber(classlist) {
2582     return parseInt(classlist.split(/\s+row_/)[1]);
2586  * Changes status of slider
2587  */
2588 function PMA_set_status_label(id) {
2589     if ($('#' + id).css('display') == 'none') {
2590         $('#anchor_status_' + id).text('+ ');
2591     } else {
2592         $('#anchor_status_' + id).text('- ');
2593     }
2597  * Initializes slider effect.
2598  */
2599 function PMA_init_slider() {
2600     $('.pma_auto_slider').each(function(idx, e) {
2601         if ($(e).hasClass('slider_init_done')) return;
2602         $(e).addClass('slider_init_done');
2603         $('<span id="anchor_status_' + e.id + '"></span>')
2604             .insertBefore(e);
2605         PMA_set_status_label(e.id);
2607         $('<a href="#' + e.id + '" id="anchor_' + e.id + '">' + e.title + '</a>')
2608             .insertBefore(e)
2609             .click(function() {
2610                 $('#' + e.id).toggle('clip', function() {
2611                     PMA_set_status_label(e.id);
2612                 });
2613                 return false;
2614             });
2615     });
2619  * var  toggleButton  This is a function that creates a toggle
2620  *                    sliding button given a jQuery reference
2621  *                    to the correct DOM element
2622  */
2623 var toggleButton = function ($obj) {
2624     // In rtl mode the toggle switch is flipped horizontally
2625     // so we need to take that into account
2626     if ($('.text_direction', $obj).text() == 'ltr') {
2627         var right = 'right';
2628     } else {
2629         var right = 'left';
2630     }
2631     /**
2632      *  var  h  Height of the button, used to scale the
2633      *          background image and position the layers
2634      */
2635     var h = $obj.height();
2636     $('img', $obj).height(h);
2637     $('table', $obj).css('bottom', h-1);
2638     /**
2639      *  var  on   Width of the "ON" part of the toggle switch
2640      *  var  off  Width of the "OFF" part of the toggle switch
2641      */
2642     var on  = $('.toggleOn', $obj).width();
2643     var off = $('.toggleOff', $obj).width();
2644     // Make the "ON" and "OFF" parts of the switch the same size
2645     $('.toggleOn > div', $obj).width(Math.max(on, off));
2646     $('.toggleOff > div', $obj).width(Math.max(on, off));
2647     /**
2648      *  var  w  Width of the central part of the switch
2649      */
2650     var w = parseInt(($('img', $obj).height() / 16) * 22, 10);
2651     // Resize the central part of the switch on the top
2652     // layer to match the background
2653     $('table td:nth-child(2) > div', $obj).width(w);
2654     /**
2655      *  var  imgw    Width of the background image
2656      *  var  tblw    Width of the foreground layer
2657      *  var  offset  By how many pixels to move the background
2658      *               image, so that it matches the top layer
2659      */
2660     var imgw = $('img', $obj).width();
2661     var tblw = $('table', $obj).width();
2662     var offset = parseInt(((imgw - tblw) / 2), 10);
2663     // Move the background to match the layout of the top layer
2664     $obj.find('img').css(right, offset);
2665     /**
2666      *  var  offw    Outer width of the "ON" part of the toggle switch
2667      *  var  btnw    Outer width of the central part of the switch
2668      */
2669     var offw = $('.toggleOff', $obj).outerWidth();
2670     var btnw = $('table td:nth-child(2)', $obj).outerWidth();
2671     // Resize the main div so that exactly one side of
2672     // the switch plus the central part fit into it.
2673     $obj.width(offw + btnw + 2);
2674     /**
2675      *  var  move  How many pixels to move the
2676      *             switch by when toggling
2677      */
2678     var move = $('.toggleOff', $obj).outerWidth();
2679     // If the switch is initialized to the
2680     // OFF state we need to move it now.
2681     if ($('.container', $obj).hasClass('off')) {
2682         if (right == 'right') {
2683             $('table, img', $obj).animate({'left': '-=' + move + 'px'}, 0);
2684         } else {
2685             $('table, img', $obj).animate({'left': '+=' + move + 'px'}, 0);
2686         }
2687     }
2688     // Attach an 'onclick' event to the switch
2689     $('.container', $obj).click(function () {
2690         if ($(this).hasClass('isActive')) {
2691             return false;
2692         } else {
2693             $(this).addClass('isActive');
2694         }
2695         var $msg = PMA_ajaxShowMessage(PMA_messages['strLoading']);
2696         var $container = $(this);
2697         var callback = $('.callback', this).text();
2698         // Perform the actual toggle
2699         if ($(this).hasClass('on')) {
2700             if (right == 'right') {
2701                 var operator = '-=';
2702             } else {
2703                 var operator = '+=';
2704             }
2705             var url = $(this).find('.toggleOff > span').text();
2706             var removeClass = 'on';
2707             var addClass = 'off';
2708         } else {
2709             if (right == 'right') {
2710                 var operator = '+=';
2711             } else {
2712                 var operator = '-=';
2713             }
2714             var url = $(this).find('.toggleOn > span').text();
2715             var removeClass = 'off';
2716             var addClass = 'on';
2717         }
2718         $.post(url, {'ajax_request': true}, function(data) {
2719             if(data.success == true) {
2720                 PMA_ajaxRemoveMessage($msg);
2721                 $container
2722                 .removeClass(removeClass)
2723                 .addClass(addClass)
2724                 .animate({'left': operator + move + 'px'}, function () {
2725                     $container.removeClass('isActive');
2726                 });
2727                 eval(callback);
2728             } else {
2729                 PMA_ajaxShowMessage(data.error);
2730                 $container.removeClass('isActive');
2731             }
2732         });
2733     });
2737  * Initialise all toggle buttons
2738  */
2739 $(window).load(function () {
2740     $('.toggleAjax').each(function () {
2741         $(this)
2742         .show()
2743         .find('.toggleButton')
2744         toggleButton($(this));
2745     });
2749  * Vertical pointer
2750  */
2751 $(document).ready(function() {
2752     $('.vpointer').live('hover',
2753         //handlerInOut
2754         function(e) {
2755             var $this_td = $(this);
2756             var row_num = PMA_getRowNumber($this_td.attr('class'));
2757             // for all td of the same vertical row, toggle hover
2758             $('.vpointer').filter('.row_' + row_num).toggleClass('hover');
2759         }
2760         );
2761 }) // end of $(document).ready() for vertical pointer
2763 $(document).ready(function() {
2764     /**
2765      * Vertical marker
2766      */
2767     $('.vmarker').live('click', function(e) {
2768         // do not trigger when clicked on anchor
2769         if ($(e.target).is('a, img, a *')) {
2770             return;
2771         }
2773         var $this_td = $(this);
2774         var row_num = PMA_getRowNumber($this_td.attr('class'));
2776         // XXX: FF fires two click events for <label> (label and checkbox), so we need to handle this differently
2777         var $tr = $(this);
2778         var $checkbox = $('.vmarker').filter('.row_' + row_num + ':first').find(':checkbox');
2779         if ($checkbox.length) {
2780             // checkbox in a row, add or remove class depending on checkbox state
2781             var checked = $checkbox.attr('checked');
2782             if (!$(e.target).is(':checkbox, label')) {
2783                 checked = !checked;
2784                 $checkbox.attr('checked', checked);
2785             }
2786             // for all td of the same vertical row, toggle the marked class
2787             if (checked) {
2788                 $('.vmarker').filter('.row_' + row_num).addClass('marked');
2789             } else {
2790                 $('.vmarker').filter('.row_' + row_num).removeClass('marked');
2791             }
2792         } else {
2793             // normaln data table, just toggle class
2794             $('.vmarker').filter('.row_' + row_num).toggleClass('marked');
2795         }
2796     });
2798     /**
2799      * Reveal visual builder anchor
2800      */
2802     $('#visual_builder_anchor').show();
2804     /**
2805      * Page selector in db Structure (non-AJAX)
2806      */
2807     $('#tableslistcontainer').find('#pageselector').live('change', function() {
2808         $(this).parent("form").submit();
2809     });
2811     /**
2812      * Page selector in navi panel (non-AJAX)
2813      */
2814     $('#navidbpageselector').find('#pageselector').live('change', function() {
2815         $(this).parent("form").submit();
2816     });
2818     /**
2819      * Page selector in browse_foreigners windows (non-AJAX)
2820      */
2821     $('#body_browse_foreigners').find('#pageselector').live('change', function() {
2822         $(this).closest("form").submit();
2823     });
2825     /**
2826      * Load version information asynchronously.
2827      */
2828     if ($('.jsversioncheck').length > 0) {
2829         (function() {
2830             var s = document.createElement('script');
2831             s.type = 'text/javascript';
2832             s.async = true;
2833             s.src = 'http://www.phpmyadmin.net/home_page/version.js';
2834             s.onload = PMA_current_version;
2835             var x = document.getElementsByTagName('script')[0];
2836             x.parentNode.insertBefore(s, x);
2837         })();
2838     }
2840     /**
2841      * Slider effect.
2842      */
2843     PMA_init_slider();
2845     /**
2846      * Enables the text generated by PMA_linkOrButton() to be clickable
2847      */
2848     $('a[class~="formLinkSubmit"]').live('click',function(e) {
2850         if($(this).attr('href').indexOf('=') != -1) {
2851             var data = $(this).attr('href').substr($(this).attr('href').indexOf('#')+1).split('=',2);
2852             $(this).parents('form').append('<input type="hidden" name="' + data[0] + '" value="' + data[1] + '"/>');
2853         }
2854         $(this).parents('form').submit();
2855         return false;
2856     });
2858     $('#update_recent_tables').ready(function() {
2859         if (window.parent.frame_navigation != undefined
2860             && window.parent.frame_navigation.PMA_reloadRecentTable != undefined)
2861         {
2862             window.parent.frame_navigation.PMA_reloadRecentTable();
2863         }
2864     });
2866 }) // end of $(document).ready()
2869  * Creates a message inside an object with a sliding effect
2871  * @param   msg    A string containing the text to display
2872  * @param   $obj   a jQuery object containing the reference
2873  *                 to the element where to put the message
2874  *                 This is optional, if no element is
2875  *                 provided, one will be created below the
2876  *                 navigation links at the top of the page
2878  * @return  bool   True on success, false on failure
2879  */
2880 function PMA_slidingMessage(msg, $obj) {
2881     if (msg == undefined || msg.length == 0) {
2882         // Don't show an empty message
2883         return false;
2884     }
2885     if ($obj == undefined || ! $obj instanceof jQuery || $obj.length == 0) {
2886         // If the second argument was not supplied,
2887         // we might have to create a new DOM node.
2888         if ($('#PMA_slidingMessage').length == 0) {
2889             $('#topmenucontainer')
2890             .after('<span id="PMA_slidingMessage" '
2891                  + 'style="display: inline-block;"></span>');
2892         }
2893         $obj = $('#PMA_slidingMessage');
2894     }
2895     if ($obj.has('div').length > 0) {
2896         // If there already is a message inside the
2897         // target object, we must get rid of it
2898         $obj
2899         .find('div')
2900         .first()
2901         .fadeOut(function () {
2902             $obj
2903             .children()
2904             .remove();
2905             $obj
2906             .append('<div style="display: none;">' + msg + '</div>')
2907             .animate({
2908                 height: $obj.find('div').first().height()
2909             })
2910             .find('div')
2911             .first()
2912             .fadeIn();
2913         });
2914     } else {
2915         // Object does not already have a message
2916         // inside it, so we simply slide it down
2917         var h = $obj
2918                 .width('100%')
2919                 .html('<div style="display: none;">' + msg + '</div>')
2920                 .find('div')
2921                 .first()
2922                 .height();
2923         $obj
2924         .find('div')
2925         .first()
2926         .css('height', 0)
2927         .show()
2928         .animate({
2929                 height: h
2930             }, function() {
2931             // Set the height of the parent
2932             // to the height of the child
2933             $obj
2934             .height(
2935                 $obj
2936                 .find('div')
2937                 .first()
2938                 .height()
2939             );
2940         });
2941     }
2942     return true;
2943 } // end PMA_slidingMessage()
2946  * Attach Ajax event handlers for Drop Table.
2948  * @uses    $.PMA_confirm()
2949  * @uses    PMA_ajaxShowMessage()
2950  * @uses    window.parent.refreshNavigation()
2951  * @uses    window.parent.refreshMain()
2952  * @see $cfg['AjaxEnable']
2953  */
2954 $(document).ready(function() {
2955     $("#drop_tbl_anchor").live('click', function(event) {
2956         event.preventDefault();
2958         //context is top.frame_content, so we need to use window.parent.db to access the db var
2959         /**
2960          * @var question    String containing the question to be asked for confirmation
2961          */
2962         var question = PMA_messages['strDropTableStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP TABLE ' + window.parent.table;
2964         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2966             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2967             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2968                 //Database deleted successfully, refresh both the frames
2969                 window.parent.refreshNavigation();
2970                 window.parent.refreshMain();
2971             }) // end $.get()
2972         }); // end $.PMA_confirm()
2973     }); //end of Drop Table Ajax action
2974 }) // end of $(document).ready() for Drop Table
2977  * Attach Ajax event handlers for Truncate Table.
2979  * @uses    $.PMA_confirm()
2980  * @uses    PMA_ajaxShowMessage()
2981  * @uses    window.parent.refreshNavigation()
2982  * @uses    window.parent.refreshMain()
2983  * @see $cfg['AjaxEnable']
2984  */
2985 $(document).ready(function() {
2986     $("#truncate_tbl_anchor").live('click', function(event) {
2987         event.preventDefault();
2989         //context is top.frame_content, so we need to use window.parent.db to access the db var
2990         /**
2991          * @var question    String containing the question to be asked for confirmation
2992          */
2993         var question = PMA_messages['strTruncateTableStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'TRUNCATE TABLE ' + window.parent.table;
2995         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2997             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2998             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2999                 //Database deleted successfully, refresh both the frames
3000                 window.parent.refreshNavigation();
3001                 window.parent.refreshMain();
3002             }) // end $.get()
3003         }); // end $.PMA_confirm()
3004     }); //end of Drop Table Ajax action
3005 }) // end of $(document).ready() for Drop Table
3008  * Attach CodeMirror2 editor to SQL edit area.
3009  */
3010 $(document).ready(function() {
3011     var elm = $('#sqlquery');
3012     if (elm.length > 0) {
3013         codemirror_editor = CodeMirror.fromTextArea(elm[0], {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"});
3014     }
3018  * jQuery plugin to cancel selection in HTML code.
3019  */
3020 (function ($) {
3021     $.fn.noSelect = function (p) { //no select plugin by Paulo P.Marinas
3022         var prevent = (p == null) ? true : p;
3023         if (prevent) {
3024             return this.each(function () {
3025                 if ($.browser.msie || $.browser.safari) $(this).bind('selectstart', function () {
3026                     return false;
3027                 });
3028                 else if ($.browser.mozilla) {
3029                     $(this).css('MozUserSelect', 'none');
3030                     $('body').trigger('focus');
3031                 } else if ($.browser.opera) $(this).bind('mousedown', function () {
3032                     return false;
3033                 });
3034                 else $(this).attr('unselectable', 'on');
3035             });
3036         } else {
3037             return this.each(function () {
3038                 if ($.browser.msie || $.browser.safari) $(this).unbind('selectstart');
3039                 else if ($.browser.mozilla) $(this).css('MozUserSelect', 'inherit');
3040                 else if ($.browser.opera) $(this).unbind('mousedown');
3041                 else $(this).removeAttr('unselectable', 'on');
3042             });
3043         }
3044     }; //end noSelect
3045 })(jQuery);
3048  * Create default PMA tooltip for the element specified. The default appearance
3049  * can be overriden by specifying optional "options" parameter (see qTip options).
3050  */
3051 function PMA_createqTip($elements, content, options) {
3052     var o = {
3053         content: content,
3054         style: {
3055             background: '#333',
3056             border: {
3057                 radius: 5
3058             },
3059             fontSize: '0.8em',
3060             padding: '0 0.5em',
3061             name: 'dark'
3062         },
3063         position: {
3064             target: 'mouse',
3065             corner: { target: 'rightMiddle', tooltip: 'leftMiddle' },
3066             adjust: { x: 20 }
3067         },
3068         show: {
3069             delay: 0,
3070             effect: {
3071                 type: 'grow',
3072                 length: 100
3073             }
3074         },
3075         hide: {
3076             effect: {
3077                 type: 'grow',
3078                 length: 150
3079             }
3080         }
3081     }
3083     $elements.qtip($.extend(true, o, options));