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