Removed global variables with array counts in sqlparser.lib.php
[phpmyadmin.git] / js / functions.js
blobfdae296e8c76b7ccbb388df12ca9290b7f8ef8bb
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 ajax_message_init   boolean boolean that stores status of
19  *      notification for PMA_ajaxShowNotification
20  */
21 var ajax_message_init = false;
23 /**
24  * @var codemirror_editor object containing CodeMirror editor
25  */
26 var codemirror_editor = false;
28 /**
29  * Add a hidden field to the form to indicate that this will be an
30  * Ajax request (only if this hidden field does not exist)
31  *
32  * @param   object   the form
33  */
34 function PMA_prepareForAjaxRequest($form) {
35     if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
36         $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
37     }
40 /**
41  * Generate a new password and copy it to the password input areas
42  *
43  * @param   object   the form that holds the password fields
44  *
45  * @return  boolean  always true
46  */
47 function suggestPassword(passwd_form) {
48     // restrict the password to just letters and numbers to avoid problems:
49     // "editors and viewers regard the password as multiple words and
50     // things like double click no longer work"
51     var pwchars = "abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ";
52     var passwordlength = 16;    // do we want that to be dynamic?  no, keep it simple :)
53     var passwd = passwd_form.generated_pw;
54     passwd.value = '';
56     for ( i = 0; i < passwordlength; i++ ) {
57         passwd.value += pwchars.charAt( Math.floor( Math.random() * pwchars.length ) )
58     }
59     passwd_form.text_pma_pw.value = passwd.value;
60     passwd_form.text_pma_pw2.value = passwd.value;
61     return true;
64 /**
65  * Version string to integer conversion.
66  */
67 function parseVersionString (str) {
68     if (typeof(str) != 'string') { return false; }
69     var add = 0;
70     // Parse possible alpha/beta/rc/
71     var state = str.split('-');
72     if (state.length >= 2) {
73         if (state[1].substr(0, 2) == 'rc') {
74             add = - 20 - parseInt(state[1].substr(2));
75         } else if (state[1].substr(0, 4) == 'beta') {
76             add =  - 40 - parseInt(state[1].substr(4));
77         } else if (state[1].substr(0, 5) == 'alpha') {
78             add =  - 60 - parseInt(state[1].substr(5));
79         } else if (state[1].substr(0, 3) == 'dev') {
80             /* We don't handle dev, it's git snapshot */
81             add = 0;
82         }
83     }
84     // Parse version
85     var x = str.split('.');
86     // Use 0 for non existing parts
87     var maj = parseInt(x[0]) || 0;
88     var min = parseInt(x[1]) || 0;
89     var pat = parseInt(x[2]) || 0;
90     var hotfix = parseInt(x[3]) || 0;
91     return  maj * 100000000 + min * 1000000 + pat * 10000 + hotfix * 100 + add;
94 /**
95  * Indicates current available version on main page.
96  */
97 function PMA_current_version() {
98     var current = parseVersionString(pmaversion);
99     var latest = parseVersionString(PMA_latest_version);
100     var version_information_message = PMA_messages['strLatestAvailable'] + ' ' + PMA_latest_version;
101     if (latest > current) {
102         var message = $.sprintf(PMA_messages['strNewerVersion'], PMA_latest_version, PMA_latest_date);
103         if (Math.floor(latest / 10000) == Math.floor(current / 10000)) {
104             /* Security update */
105             klass = 'error';
106         } else {
107             klass = 'notice';
108         }
109         $('#maincontainer').after('<div class="' + klass + '">' + message + '</div>');
110     }
111     if (latest == current) {
112         version_information_message = ' (' + PMA_messages['strUpToDate'] + ')';
113     }
114     $('#li_pma_version').append(version_information_message);
118  * for libraries/display_change_password.lib.php
119  *     libraries/user_password.php
121  */
123 function displayPasswordGenerateButton() {
124     $('#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>');
125     $('#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>');
129  * Adds a date/time picker to an element
131  * @param   object  $this_element   a jQuery object pointing to the element
132  */
133 function PMA_addDatepicker($this_element) {
134     var showTimeOption = false;
135     if ($this_element.is('.datetimefield')) {
136         showTimeOption = true;
137     }
139     $this_element
140         .datepicker({
141         showOn: 'button',
142         buttonImage: themeCalendarImage, // defined in js/messages.php
143         buttonImageOnly: true,
144         duration: '',
145         time24h: true,
146         stepMinutes: 1,
147         stepHours: 1,
148         showTime: showTimeOption,
149         dateFormat: 'yy-mm-dd', // yy means year with four digits
150         altTimeField: '',
151         beforeShow: function(input, inst) {
152             // Remember that we came from the datepicker; this is used
153             // in tbl_change.js by verificationsAfterFieldChange()
154             $this_element.data('comes_from', 'datepicker');
155         },
156         constrainInput: false
157      });
161  * selects the content of a given object, f.e. a textarea
163  * @param   object  element     element of which the content will be selected
164  * @param   var     lock        variable which holds the lock for this element
165  *                              or true, if no lock exists
166  * @param   boolean only_once   if true this is only done once
167  *                              f.e. only on first focus
168  */
169 function selectContent( element, lock, only_once ) {
170     if ( only_once && only_once_elements[element.name] ) {
171         return;
172     }
174     only_once_elements[element.name] = true;
176     if ( lock  ) {
177         return;
178     }
180     element.select();
184  * Displays a confirmation box before to submit a "DROP/DELETE/ALTER" query.
185  * This function is called while clicking links
187  * @param   object   the link
188  * @param   object   the sql query to submit
190  * @return  boolean  whether to run the query or not
191  */
192 function confirmLink(theLink, theSqlQuery)
194     // Confirmation is not required in the configuration file
195     // or browser is Opera (crappy js implementation)
196     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
197         return true;
198     }
200     var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
201     if (is_confirmed) {
202         if ( typeof(theLink.href) != 'undefined' ) {
203             theLink.href += '&is_js_confirmed=1';
204         } else if ( typeof(theLink.form) != 'undefined' ) {
205             theLink.form.action += '?is_js_confirmed=1';
206         }
207     }
209     return is_confirmed;
210 } // end of the 'confirmLink()' function
214  * Displays a confirmation box before doing some action
216  * @param   object   the message to display
218  * @return  boolean  whether to run the query or not
220  * @todo used only by libraries/display_tbl.lib.php. figure out how it is used
221  *       and replace with a jQuery equivalent
222  */
223 function confirmAction(theMessage)
225     // TODO: Confirmation is not required in the configuration file
226     // or browser is Opera (crappy js implementation)
227     if (typeof(window.opera) != 'undefined') {
228         return true;
229     }
231     var is_confirmed = confirm(theMessage);
233     return is_confirmed;
234 } // end of the 'confirmAction()' function
238  * Displays an error message if a "DROP DATABASE" statement is submitted
239  * while it isn't allowed, else confirms a "DROP/DELETE/ALTER" query before
240  * sumitting it if required.
241  * This function is called by the 'checkSqlQuery()' js function.
243  * @param   object   the form
244  * @param   object   the sql query textarea
246  * @return  boolean  whether to run the query or not
248  * @see     checkSqlQuery()
249  */
250 function confirmQuery(theForm1, sqlQuery1)
252     // Confirmation is not required in the configuration file
253     if (PMA_messages['strDoYouReally'] == '') {
254         return true;
255     }
257     // The replace function (js1.2) isn't supported
258     else if (typeof(sqlQuery1.value.replace) == 'undefined') {
259         return true;
260     }
262     // js1.2+ -> validation with regular expressions
263     else {
264         // "DROP DATABASE" statement isn't allowed
265         if (PMA_messages['strNoDropDatabases'] != '') {
266             var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
267             if (drop_re.test(sqlQuery1.value)) {
268                 alert(PMA_messages['strNoDropDatabases']);
269                 theForm1.reset();
270                 sqlQuery1.focus();
271                 return false;
272             } // end if
273         } // end if
275         // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
276         //
277         // TODO: find a way (if possible) to use the parser-analyser
278         // for this kind of verification
279         // For now, I just added a ^ to check for the statement at
280         // beginning of expression
282         var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
283         var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
284         var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
285         var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
287         if (do_confirm_re_0.test(sqlQuery1.value)
288             || do_confirm_re_1.test(sqlQuery1.value)
289             || do_confirm_re_2.test(sqlQuery1.value)
290             || do_confirm_re_3.test(sqlQuery1.value)) {
291             var message      = (sqlQuery1.value.length > 100)
292                              ? sqlQuery1.value.substr(0, 100) + '\n    ...'
293                              : sqlQuery1.value;
294             var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
295             // statement is confirmed -> update the
296             // "is_js_confirmed" form field so the confirm test won't be
297             // run on the server side and allows to submit the form
298             if (is_confirmed) {
299                 theForm1.elements['is_js_confirmed'].value = 1;
300                 return true;
301             }
302             // statement is rejected -> do not submit the form
303             else {
304                 window.focus();
305                 sqlQuery1.focus();
306                 return false;
307             } // end if (handle confirm box result)
308         } // end if (display confirm box)
309     } // end confirmation stuff
311     return true;
312 } // end of the 'confirmQuery()' function
316  * Displays a confirmation box before disabling the BLOB repository for a given database.
317  * This function is called while clicking links
319  * @param   object   the database
321  * @return  boolean  whether to disable the repository or not
322  */
323 function confirmDisableRepository(theDB)
325     // Confirmation is not required in the configuration file
326     // or browser is Opera (crappy js implementation)
327     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
328         return true;
329     }
331     var is_confirmed = confirm(PMA_messages['strBLOBRepositoryDisableStrongWarning'] + '\n' + PMA_messages['strBLOBRepositoryDisableAreYouSure']);
333     return is_confirmed;
334 } // end of the 'confirmDisableBLOBRepository()' function
338  * Displays an error message if the user submitted the sql query form with no
339  * sql query, else checks for "DROP/DELETE/ALTER" statements
341  * @param   object   the form
343  * @return  boolean  always false
345  * @see     confirmQuery()
346  */
347 function checkSqlQuery(theForm)
349     var sqlQuery = theForm.elements['sql_query'];
350     var isEmpty  = 1;
352     // The replace function (js1.2) isn't supported -> basic tests
353     if (typeof(sqlQuery.value.replace) == 'undefined') {
354         isEmpty      = (sqlQuery.value == '') ? 1 : 0;
355         if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') {
356             isEmpty  = (theForm.elements['sql_file'].value == '') ? 1 : 0;
357         }
358         if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') {
359             isEmpty  = (theForm.elements['sql_localfile'].value == '') ? 1 : 0;
360         }
361         if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') {
362             isEmpty  = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == '');
363         }
364     }
365     // js1.2+ -> validation with regular expressions
366     else {
367         var space_re = new RegExp('\\s+');
368         if (typeof(theForm.elements['sql_file']) != 'undefined' &&
369                 theForm.elements['sql_file'].value.replace(space_re, '') != '') {
370             return true;
371         }
372         if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
373                 theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
374             return true;
375         }
376         if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
377                 (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
378                 theForm.elements['id_bookmark'].selectedIndex != 0
379                 ) {
380             return true;
381         }
382         // Checks for "DROP/DELETE/ALTER" statements
383         if (sqlQuery.value.replace(space_re, '') != '') {
384             if (confirmQuery(theForm, sqlQuery)) {
385                 return true;
386             } else {
387                 return false;
388             }
389         }
390         theForm.reset();
391         isEmpty = 1;
392     }
394     if (isEmpty) {
395         sqlQuery.select();
396         alert(PMA_messages['strFormEmpty']);
397         sqlQuery.focus();
398         return false;
399     }
401     return true;
402 } // end of the 'checkSqlQuery()' function
405  * Check if a form's element is empty.
406  * An element containing only spaces is also considered empty
408  * @param   object   the form
409  * @param   string   the name of the form field to put the focus on
411  * @return  boolean  whether the form field is empty or not
412  */
413 function emptyCheckTheField(theForm, theFieldName)
415     var isEmpty  = 1;
416     var theField = theForm.elements[theFieldName];
417     // Whether the replace function (js1.2) is supported or not
418     var isRegExp = (typeof(theField.value.replace) != 'undefined');
420     if (!isRegExp) {
421         isEmpty      = (theField.value == '') ? 1 : 0;
422     } else {
423         var space_re = new RegExp('\\s+');
424         isEmpty      = (theField.value.replace(space_re, '') == '') ? 1 : 0;
425     }
427     return isEmpty;
428 } // end of the 'emptyCheckTheField()' function
432  * Check whether a form field is empty or not
434  * @param   object   the form
435  * @param   string   the name of the form field to put the focus on
437  * @return  boolean  whether the form field is empty or not
438  */
439 function emptyFormElements(theForm, theFieldName)
441     var theField = theForm.elements[theFieldName];
442     var isEmpty = emptyCheckTheField(theForm, theFieldName);
445     return isEmpty;
446 } // end of the 'emptyFormElements()' function
450  * Ensures a value submitted in a form is numeric and is in a range
452  * @param   object   the form
453  * @param   string   the name of the form field to check
454  * @param   integer  the minimum authorized value
455  * @param   integer  the maximum authorized value
457  * @return  boolean  whether a valid number has been submitted or not
458  */
459 function checkFormElementInRange(theForm, theFieldName, message, min, max)
461     var theField         = theForm.elements[theFieldName];
462     var val              = parseInt(theField.value);
464     if (typeof(min) == 'undefined') {
465         min = 0;
466     }
467     if (typeof(max) == 'undefined') {
468         max = Number.MAX_VALUE;
469     }
471     // It's not a number
472     if (isNaN(val)) {
473         theField.select();
474         alert(PMA_messages['strNotNumber']);
475         theField.focus();
476         return false;
477     }
478     // It's a number but it is not between min and max
479     else if (val < min || val > max) {
480         theField.select();
481         alert(message.replace('%d', val));
482         theField.focus();
483         return false;
484     }
485     // It's a valid number
486     else {
487         theField.value = val;
488     }
489     return true;
491 } // end of the 'checkFormElementInRange()' function
494 function checkTableEditForm(theForm, fieldsCnt)
496     // TODO: avoid sending a message if user just wants to add a line
497     // on the form but has not completed at least one field name
499     var atLeastOneField = 0;
500     var i, elm, elm2, elm3, val, id;
502     for (i=0; i<fieldsCnt; i++)
503     {
504         id = "#field_" + i + "_2";
505         elm = $(id);
506         val = elm.val()
507         if (val == 'VARCHAR' || val == 'CHAR' || val == 'BIT' || val == 'VARBINARY' || val == 'BINARY') {
508             elm2 = $("#field_" + i + "_3");
509             val = parseInt(elm2.val());
510             elm3 = $("#field_" + i + "_1");
511             if (isNaN(val) && elm3.val() != "") {
512                 elm2.select();
513                 alert(PMA_messages['strNotNumber']);
514                 elm2.focus();
515                 return false;
516             }
517         }
519         if (atLeastOneField == 0) {
520             id = "field_" + i + "_1";
521             if (!emptyCheckTheField(theForm, id)) {
522                 atLeastOneField = 1;
523             }
524         }
525     }
526     if (atLeastOneField == 0) {
527         var theField = theForm.elements["field_0_1"];
528         alert(PMA_messages['strFormEmpty']);
529         theField.focus();
530         return false;
531     }
533     // at least this section is under jQuery
534     if ($("input.textfield[name='table']").val() == "") {
535         alert(PMA_messages['strFormEmpty']);
536         $("input.textfield[name='table']").focus();
537         return false;
538     }
541     return true;
542 } // enf of the 'checkTableEditForm()' function
546  * Ensures the choice between 'transmit', 'zipped', 'gzipped' and 'bzipped'
547  * checkboxes is consistant
549  * @param   object   the form
550  * @param   string   a code for the action that causes this function to be run
552  * @return  boolean  always true
553  */
554 function checkTransmitDump(theForm, theAction)
556     var formElts = theForm.elements;
558     // 'zipped' option has been checked
559     if (theAction == 'zip' && formElts['zip'].checked) {
560         if (!formElts['asfile'].checked) {
561             theForm.elements['asfile'].checked = true;
562         }
563         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
564             theForm.elements['gzip'].checked = false;
565         }
566         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
567             theForm.elements['bzip'].checked = false;
568         }
569     }
570     // 'gzipped' option has been checked
571     else if (theAction == 'gzip' && formElts['gzip'].checked) {
572         if (!formElts['asfile'].checked) {
573             theForm.elements['asfile'].checked = true;
574         }
575         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
576             theForm.elements['zip'].checked = false;
577         }
578         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
579             theForm.elements['bzip'].checked = false;
580         }
581     }
582     // 'bzipped' option has been checked
583     else if (theAction == 'bzip' && formElts['bzip'].checked) {
584         if (!formElts['asfile'].checked) {
585             theForm.elements['asfile'].checked = true;
586         }
587         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
588             theForm.elements['zip'].checked = false;
589         }
590         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
591             theForm.elements['gzip'].checked = false;
592         }
593     }
594     // 'transmit' option has been unchecked
595     else if (theAction == 'transmit' && !formElts['asfile'].checked) {
596         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
597             theForm.elements['zip'].checked = false;
598         }
599         if ((typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked)) {
600             theForm.elements['gzip'].checked = false;
601         }
602         if ((typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked)) {
603             theForm.elements['bzip'].checked = false;
604         }
605     }
607     return true;
608 } // end of the 'checkTransmitDump()' function
610 $(document).ready(function() {
611     /**
612      * Row marking in horizontal mode (use "live" so that it works also for
613      * next pages reached via AJAX); a tr may have the class noclick to remove
614      * this behavior.
615      */
616     $('tr.odd:not(.noclick), tr.even:not(.noclick)').live('click',function(e) {
617         // do not trigger when clicked on anchor
618         if ($(e.target).is('a, img, a *')) {
619             return;
620         }
621         // XXX: FF fires two click events for <label> (label and checkbox), so we need to handle this differently
622         var $tr = $(this);
623         var $checkbox = $tr.find(':checkbox');
624         if ($checkbox.length) {
625             // checkbox in a row, add or remove class depending on checkbox state
626             var checked = $checkbox.attr('checked');
627             if (!$(e.target).is(':checkbox, label')) {
628                 checked = !checked;
629                 $checkbox.attr('checked', checked);
630             }
631             if (checked) {
632                 $tr.addClass('marked');
633             } else {
634                 $tr.removeClass('marked');
635             }
636         } else {
637             // normaln data table, just toggle class
638             $tr.toggleClass('marked');
639         }
640     });
642     /**
643      * Add a date/time picker to each element that needs it
644      */
645     $('.datefield, .datetimefield').each(function() {
646         PMA_addDatepicker($(this));
647         });
651  * Row highlighting in horizontal mode (use "live"
652  * so that it works also for pages reached via AJAX)
653  */
654 $(document).ready(function() {
655     $('tr.odd, tr.even').live('hover',function() {
656         var $tr = $(this);
657         $tr.toggleClass('hover');
658         $tr.children().toggleClass('hover');
659     });
663  * This array is used to remember mark status of rows in browse mode
664  */
665 var marked_row = new Array;
668  * marks all rows and selects its first checkbox inside the given element
669  * the given element is usaly a table or a div containing the table or tables
671  * @param    container    DOM element
672  */
673 function markAllRows( container_id ) {
675     $("#"+container_id).find("input:checkbox:enabled").attr('checked', 'checked')
676     .parents("tr").addClass("marked");
677     return true;
681  * marks all rows and selects its first checkbox inside the given element
682  * the given element is usaly a table or a div containing the table or tables
684  * @param    container    DOM element
685  */
686 function unMarkAllRows( container_id ) {
688     $("#"+container_id).find("input:checkbox:enabled").removeAttr('checked')
689     .parents("tr").removeClass("marked");
690     return true;
694  * Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div)
696  * @param   string   container_id  the container id
697  * @param   boolean  state         new value for checkbox (true or false)
698  * @return  boolean  always true
699  */
700 function setCheckboxes( container_id, state ) {
702     if(state) {
703         $("#"+container_id).find("input:checkbox").attr('checked', 'checked');
704     }
705     else {
706         $("#"+container_id).find("input:checkbox").removeAttr('checked');
707     }
709     return true;
710 } // end of the 'setCheckboxes()' function
713   * Checks/unchecks all options of a <select> element
714   *
715   * @param   string   the form name
716   * @param   string   the element name
717   * @param   boolean  whether to check or to uncheck options
718   *
719   * @return  boolean  always true
720   */
721 function setSelectOptions(the_form, the_select, do_check)
723     $("form[name='"+ the_form +"'] select[name='"+the_select+"']").find("option").attr('selected', do_check);
724     return true;
725 } // end of the 'setSelectOptions()' function
728  * Sets current value for query box.
729  */
730 function setQuery(query) {
731     if (codemirror_editor) {
732         codemirror_editor.setValue(query);
733     } else {
734         document.sqlform.sql_query.value = query;
735     }
740   * Create quick sql statements.
741   *
742   */
743 function insertQuery(queryType) {
744     if (queryType == "clear") {
745         setQuery('');
746         return;
747     }
749     var myQuery = document.sqlform.sql_query;
750     var query = "";
751     var myListBox = document.sqlform.dummy;
752     var table = document.sqlform.table.value;
754     if (myListBox.options.length > 0) {
755         sql_box_locked = true;
756         var chaineAj = "";
757         var valDis = "";
758         var editDis = "";
759         var NbSelect = 0;
760         for (var i=0; i < myListBox.options.length; i++) {
761             NbSelect++;
762             if (NbSelect > 1) {
763                 chaineAj += ", ";
764                 valDis += ",";
765                 editDis += ",";
766             }
767             chaineAj += myListBox.options[i].value;
768             valDis += "[value-" + NbSelect + "]";
769             editDis += myListBox.options[i].value + "=[value-" + NbSelect + "]";
770         }
771         if (queryType == "selectall") {
772             query = "SELECT * FROM `" + table + "` WHERE 1";
773         } else if (queryType == "select") {
774             query = "SELECT " + chaineAj + " FROM `" + table + "` WHERE 1";
775         } else if (queryType == "insert") {
776                query = "INSERT INTO `" + table + "`(" + chaineAj + ") VALUES (" + valDis + ")";
777         } else if (queryType == "update") {
778             query = "UPDATE `" + table + "` SET " + editDis + " WHERE 1";
779         } else if(queryType == "delete") {
780             query = "DELETE FROM `" + table + "` WHERE 1";
781         }
782         setQuery(query);
783         sql_box_locked = false;
784     }
789   * Inserts multiple fields.
790   *
791   */
792 function insertValueQuery() {
793     var myQuery = document.sqlform.sql_query;
794     var myListBox = document.sqlform.dummy;
796     if(myListBox.options.length > 0) {
797         sql_box_locked = true;
798         var chaineAj = "";
799         var NbSelect = 0;
800         for(var i=0; i<myListBox.options.length; i++) {
801             if (myListBox.options[i].selected){
802                 NbSelect++;
803                 if (NbSelect > 1)
804                     chaineAj += ", ";
805                 chaineAj += myListBox.options[i].value;
806             }
807         }
809         /* CodeMirror support */
810         if (codemirror_editor) {
811             codemirror_editor.replaceSelection(chaineAj);
812         //IE support
813         } else if (document.selection) {
814             myQuery.focus();
815             sel = document.selection.createRange();
816             sel.text = chaineAj;
817             document.sqlform.insert.focus();
818         }
819         //MOZILLA/NETSCAPE support
820         else if (document.sqlform.sql_query.selectionStart || document.sqlform.sql_query.selectionStart == "0") {
821             var startPos = document.sqlform.sql_query.selectionStart;
822             var endPos = document.sqlform.sql_query.selectionEnd;
823             var chaineSql = document.sqlform.sql_query.value;
825             myQuery.value = chaineSql.substring(0, startPos) + chaineAj + chaineSql.substring(endPos, chaineSql.length);
826         } else {
827             myQuery.value += chaineAj;
828         }
829         sql_box_locked = false;
830     }
834   * listbox redirection
835   */
836 function goToUrl(selObj, goToLocation) {
837     eval("document.location.href = '" + goToLocation + "pos=" + selObj.options[selObj.selectedIndex].value + "'");
841  * getElement
842  */
843 function getElement(e,f){
844     if(document.layers){
845         f=(f)?f:self;
846         if(f.document.layers[e]) {
847             return f.document.layers[e];
848         }
849         for(W=0;W<f.document.layers.length;W++) {
850             return(getElement(e,f.document.layers[W]));
851         }
852     }
853     if(document.all) {
854         return document.all[e];
855     }
856     return document.getElementById(e);
860   * Refresh the WYSIWYG scratchboard after changes have been made
861   */
862 function refreshDragOption(e) {
863     var elm = $('#' + e);
864     if (elm.css('visibility') == 'visible') {
865         refreshLayout();
866         TableDragInit();
867     }
871   * Refresh/resize the WYSIWYG scratchboard
872   */
873 function refreshLayout() {
874     var elm = $('#pdflayout')
875     var orientation = $('#orientation_opt').val();
876     if($('#paper_opt').length==1){
877         var paper = $('#paper_opt').val();
878     }else{
879         var paper = 'A4';
880     }
881     if (orientation == 'P') {
882         posa = 'x';
883         posb = 'y';
884     } else {
885         posa = 'y';
886         posb = 'x';
887     }
888     elm.css('width', pdfPaperSize(paper, posa) + 'px');
889     elm.css('height', pdfPaperSize(paper, posb) + 'px');
893   * Show/hide the WYSIWYG scratchboard
894   */
895 function ToggleDragDrop(e) {
896     var elm = $('#' + e);
897     if (elm.css('visibility') == 'hidden') {
898         PDFinit(); /* Defined in pdf_pages.php */
899         elm.css('visibility', 'visible');
900         elm.css('display', 'block');
901         $('#showwysiwyg').val('1')
902     } else {
903         elm.css('visibility', 'hidden');
904         elm.css('display', 'none');
905         $('#showwysiwyg').val('0')
906     }
910   * PDF scratchboard: When a position is entered manually, update
911   * the fields inside the scratchboard.
912   */
913 function dragPlace(no, axis, value) {
914     var elm = $('#table_' + no);
915     if (axis == 'x') {
916         elm.css('left', value + 'px');
917     } else {
918         elm.css('top', value + 'px');
919     }
923  * Returns paper sizes for a given format
924  */
925 function pdfPaperSize(format, axis) {
926     switch (format.toUpperCase()) {
927         case '4A0':
928             if (axis == 'x') return 4767.87; else return 6740.79;
929             break;
930         case '2A0':
931             if (axis == 'x') return 3370.39; else return 4767.87;
932             break;
933         case 'A0':
934             if (axis == 'x') return 2383.94; else return 3370.39;
935             break;
936         case 'A1':
937             if (axis == 'x') return 1683.78; else return 2383.94;
938             break;
939         case 'A2':
940             if (axis == 'x') return 1190.55; else return 1683.78;
941             break;
942         case 'A3':
943             if (axis == 'x') return 841.89; else return 1190.55;
944             break;
945         case 'A4':
946             if (axis == 'x') return 595.28; else return 841.89;
947             break;
948         case 'A5':
949             if (axis == 'x') return 419.53; else return 595.28;
950             break;
951         case 'A6':
952             if (axis == 'x') return 297.64; else return 419.53;
953             break;
954         case 'A7':
955             if (axis == 'x') return 209.76; else return 297.64;
956             break;
957         case 'A8':
958             if (axis == 'x') return 147.40; else return 209.76;
959             break;
960         case 'A9':
961             if (axis == 'x') return 104.88; else return 147.40;
962             break;
963         case 'A10':
964             if (axis == 'x') return 73.70; else return 104.88;
965             break;
966         case 'B0':
967             if (axis == 'x') return 2834.65; else return 4008.19;
968             break;
969         case 'B1':
970             if (axis == 'x') return 2004.09; else return 2834.65;
971             break;
972         case 'B2':
973             if (axis == 'x') return 1417.32; else return 2004.09;
974             break;
975         case 'B3':
976             if (axis == 'x') return 1000.63; else return 1417.32;
977             break;
978         case 'B4':
979             if (axis == 'x') return 708.66; else return 1000.63;
980             break;
981         case 'B5':
982             if (axis == 'x') return 498.90; else return 708.66;
983             break;
984         case 'B6':
985             if (axis == 'x') return 354.33; else return 498.90;
986             break;
987         case 'B7':
988             if (axis == 'x') return 249.45; else return 354.33;
989             break;
990         case 'B8':
991             if (axis == 'x') return 175.75; else return 249.45;
992             break;
993         case 'B9':
994             if (axis == 'x') return 124.72; else return 175.75;
995             break;
996         case 'B10':
997             if (axis == 'x') return 87.87; else return 124.72;
998             break;
999         case 'C0':
1000             if (axis == 'x') return 2599.37; else return 3676.54;
1001             break;
1002         case 'C1':
1003             if (axis == 'x') return 1836.85; else return 2599.37;
1004             break;
1005         case 'C2':
1006             if (axis == 'x') return 1298.27; else return 1836.85;
1007             break;
1008         case 'C3':
1009             if (axis == 'x') return 918.43; else return 1298.27;
1010             break;
1011         case 'C4':
1012             if (axis == 'x') return 649.13; else return 918.43;
1013             break;
1014         case 'C5':
1015             if (axis == 'x') return 459.21; else return 649.13;
1016             break;
1017         case 'C6':
1018             if (axis == 'x') return 323.15; else return 459.21;
1019             break;
1020         case 'C7':
1021             if (axis == 'x') return 229.61; else return 323.15;
1022             break;
1023         case 'C8':
1024             if (axis == 'x') return 161.57; else return 229.61;
1025             break;
1026         case 'C9':
1027             if (axis == 'x') return 113.39; else return 161.57;
1028             break;
1029         case 'C10':
1030             if (axis == 'x') return 79.37; else return 113.39;
1031             break;
1032         case 'RA0':
1033             if (axis == 'x') return 2437.80; else return 3458.27;
1034             break;
1035         case 'RA1':
1036             if (axis == 'x') return 1729.13; else return 2437.80;
1037             break;
1038         case 'RA2':
1039             if (axis == 'x') return 1218.90; else return 1729.13;
1040             break;
1041         case 'RA3':
1042             if (axis == 'x') return 864.57; else return 1218.90;
1043             break;
1044         case 'RA4':
1045             if (axis == 'x') return 609.45; else return 864.57;
1046             break;
1047         case 'SRA0':
1048             if (axis == 'x') return 2551.18; else return 3628.35;
1049             break;
1050         case 'SRA1':
1051             if (axis == 'x') return 1814.17; else return 2551.18;
1052             break;
1053         case 'SRA2':
1054             if (axis == 'x') return 1275.59; else return 1814.17;
1055             break;
1056         case 'SRA3':
1057             if (axis == 'x') return 907.09; else return 1275.59;
1058             break;
1059         case 'SRA4':
1060             if (axis == 'x') return 637.80; else return 907.09;
1061             break;
1062         case 'LETTER':
1063             if (axis == 'x') return 612.00; else return 792.00;
1064             break;
1065         case 'LEGAL':
1066             if (axis == 'x') return 612.00; else return 1008.00;
1067             break;
1068         case 'EXECUTIVE':
1069             if (axis == 'x') return 521.86; else return 756.00;
1070             break;
1071         case 'FOLIO':
1072             if (axis == 'x') return 612.00; else return 936.00;
1073             break;
1074     } // end switch
1076     return 0;
1080  * for playing media from the BLOB repository
1082  * @param   var
1083  * @param   var     url_params  main purpose is to pass the token
1084  * @param   var     bs_ref      BLOB repository reference
1085  * @param   var     m_type      type of BLOB repository media
1086  * @param   var     w_width     width of popup window
1087  * @param   var     w_height    height of popup window
1088  */
1089 function popupBSMedia(url_params, bs_ref, m_type, is_cust_type, w_width, w_height)
1091     // if width not specified, use default
1092     if (w_width == undefined)
1093         w_width = 640;
1095     // if height not specified, use default
1096     if (w_height == undefined)
1097         w_height = 480;
1099     // open popup window (for displaying video/playing audio)
1100     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');
1104  * popups a request for changing MIME types for files in the BLOB repository
1106  * @param   var     db                      database name
1107  * @param   var     table                   table name
1108  * @param   var     reference               BLOB repository reference
1109  * @param   var     current_mime_type       current MIME type associated with BLOB repository reference
1110  */
1111 function requestMIMETypeChange(db, table, reference, current_mime_type)
1113     // no mime type specified, set to default (nothing)
1114     if (undefined == current_mime_type)
1115         current_mime_type = "";
1117     // prompt user for new mime type
1118     var new_mime_type = prompt("Enter custom MIME type", current_mime_type);
1120     // if new mime_type is specified and is not the same as the previous type, request for mime type change
1121     if (new_mime_type && new_mime_type != current_mime_type)
1122         changeMIMEType(db, table, reference, new_mime_type);
1126  * changes MIME types for files in the BLOB repository
1128  * @param   var     db              database name
1129  * @param   var     table           table name
1130  * @param   var     reference       BLOB repository reference
1131  * @param   var     mime_type       new MIME type to be associated with BLOB repository reference
1132  */
1133 function changeMIMEType(db, table, reference, mime_type)
1135     // specify url and parameters for jQuery POST
1136     var mime_chg_url = 'bs_change_mime_type.php';
1137     var params = {bs_db: db, bs_table: table, bs_reference: reference, bs_new_mime_type: mime_type};
1139     // jQuery POST
1140     jQuery.post(mime_chg_url, params);
1144  * Jquery Coding for inline editing SQL_QUERY
1145  */
1146 $(document).ready(function(){
1147     $(".inline_edit_sql").click( function(){
1148         var db         = $(this).prev().find("input[name='db']").val();
1149         var table      = $(this).prev().find("input[name='table']").val();
1150         var token      = $(this).prev().find("input[name='token']").val();
1151         var sql_query  = $(this).prev().find("input[name='sql_query']").val();
1152         var $inner_sql = $(this).parent().prev().find('.inner_sql');
1153         var old_text   = $inner_sql.html();
1155         var new_content = "<textarea name=\"sql_query_edit\" id=\"sql_query_edit\">" + sql_query + "</textarea>\n";
1156         new_content    += "<input type=\"button\" class=\"btnSave\" value=\"" + PMA_messages['strGo'] + "\">\n";
1157         new_content    += "<input type=\"button\" class=\"btnDiscard\" value=\"" + PMA_messages['strCancel'] + "\">\n";
1158         $inner_sql.replaceWith(new_content);
1159         $(".btnSave").each(function(){
1160             $(this).click(function(){
1161                 sql_query = $(this).prev().val();
1162                 window.location.replace("import.php?db=" + db +"&table=" + table + "&sql_query=" + sql_query + "&show_query=1&token=" + token);
1163             });
1164         });
1165         $(".btnDiscard").each(function(){
1166             $(this).click(function(){
1167                 $(this).closest(".sql").html("<span class=\"syntax\"><span class=\"inner_sql\">" + old_text + "</span></span>");
1168             });
1169         });
1170         return false;
1171     });
1173     $('.sqlbutton').click(function(evt){
1174         insertQuery(evt.target.id);
1175         return false;
1176     });
1178     $("#export_type").change(function(){
1179         if($("#export_type").val()=='svg'){
1180             $("#show_grid_opt").attr("disabled","disabled");
1181             $("#orientation_opt").attr("disabled","disabled");
1182             $("#with_doc").attr("disabled","disabled");
1183             $("#show_table_dim_opt").removeAttr("disabled");
1184             $("#all_table_same_wide").removeAttr("disabled");
1185             $("#paper_opt").removeAttr("disabled","disabled");
1186             $("#show_color_opt").removeAttr("disabled","disabled");
1187             //$(this).css("background-color","yellow");
1188         }else if($("#export_type").val()=='dia'){
1189             $("#show_grid_opt").attr("disabled","disabled");
1190             $("#with_doc").attr("disabled","disabled");
1191             $("#show_table_dim_opt").attr("disabled","disabled");
1192             $("#all_table_same_wide").attr("disabled","disabled");
1193             $("#paper_opt").removeAttr("disabled","disabled");
1194             $("#show_color_opt").removeAttr("disabled","disabled");
1195             $("#orientation_opt").removeAttr("disabled","disabled");
1196         }else if($("#export_type").val()=='eps'){
1197             $("#show_grid_opt").attr("disabled","disabled");
1198             $("#orientation_opt").removeAttr("disabled");
1199             $("#with_doc").attr("disabled","disabled");
1200             $("#show_table_dim_opt").attr("disabled","disabled");
1201             $("#all_table_same_wide").attr("disabled","disabled");
1202             $("#paper_opt").attr("disabled","disabled");
1203             $("#show_color_opt").attr("disabled","disabled");
1205         }else if($("#export_type").val()=='pdf'){
1206             $("#show_grid_opt").removeAttr("disabled");
1207             $("#orientation_opt").removeAttr("disabled");
1208             $("#with_doc").removeAttr("disabled","disabled");
1209             $("#show_table_dim_opt").removeAttr("disabled","disabled");
1210             $("#all_table_same_wide").removeAttr("disabled","disabled");
1211             $("#paper_opt").removeAttr("disabled","disabled");
1212             $("#show_color_opt").removeAttr("disabled","disabled");
1213         }else{
1214             // nothing
1215         }
1216     });
1218     $('#sqlquery').focus().keydown(function (e) {
1219         if (e.ctrlKey && e.keyCode == 13) {
1220             $("#sqlqueryform").submit();
1221         }
1222     });
1224     if ($('#input_username')) {
1225         if ($('#input_username').val() == '') {
1226             $('#input_username').focus();
1227         } else {
1228             $('#input_password').focus();
1229         }
1230     }
1234  * Show a message on the top of the page for an Ajax request
1236  * @param   var     message     string containing the message to be shown.
1237  *                              optional, defaults to 'Loading...'
1238  * @param   var     timeout     number of milliseconds for the message to be visible
1239  *                              optional, defaults to 5000
1240  */
1242 function PMA_ajaxShowMessage(message, timeout) {
1244     //Handle the case when a empty data.message is passed.  We don't want the empty message
1245     if(message == '') {
1246         return true;
1247     }
1249     /**
1250      * @var msg String containing the message that has to be displayed
1251      * @default PMA_messages['strLoading']
1252      */
1253     if(!message) {
1254         var msg = PMA_messages['strLoading'];
1255     }
1256     else {
1257         var msg = message;
1258     }
1260     /**
1261      * @var timeout Number of milliseconds for which {@link msg} will be visible
1262      * @default 5000 ms
1263      */
1264     if(!timeout) {
1265         var to = 5000;
1266     }
1267     else {
1268         var to = timeout;
1269     }
1271     if( !ajax_message_init) {
1272         //For the first time this function is called, append a new div
1273         $(function(){
1274             $('<div id="loading_parent"></div>')
1275             .insertBefore("#serverinfo");
1277             $('<span id="loading" class="ajax_notification"></span>')
1278             .appendTo("#loading_parent")
1279             .html(msg)
1280             .fadeIn('medium')
1281             .delay(to)
1282             .fadeOut('medium', function(){
1283                 $(this)
1284                 .html("") //Clear the message
1285                 .hide();
1286             });
1287         }, 'top.frame_content');
1288         ajax_message_init = true;
1289     }
1290     else {
1291         //Otherwise, just show the div again after inserting the message
1292         $("#loading")
1293         .stop(true, true)
1294         .html(msg)
1295         .fadeIn('medium')
1296         .delay(to)
1297         .fadeOut('medium', function() {
1298             $(this)
1299             .html("")
1300             .hide();
1301         })
1302     }
1304         return $("#loading");
1308  * Removes the message shown for an Ajax operation when it's completed
1309  */
1310 function PMA_ajaxRemoveMessage($this_msgbox) {
1311     $this_msgbox
1312      .stop(true, true)
1313      .fadeOut('medium', function() {
1314         $this_msgbox.hide();
1315      });
1319  * Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected
1320  */
1321 function PMA_showNoticeForEnum(selectElement) {
1322     var enum_notice_id = selectElement.attr("id").split("_")[1];
1323     enum_notice_id += "_" + (parseInt(selectElement.attr("id").split("_")[2]) + 1);
1324     var selectedType = selectElement.attr("value");
1325     if (selectedType == "ENUM" || selectedType == "SET") {
1326         $("p[id='enum_notice_" + enum_notice_id + "']").show();
1327     } else {
1328         $("p[id='enum_notice_" + enum_notice_id + "']").hide();
1329     }
1333  * Generates a dialog box to pop up the create_table form
1334  */
1335 function PMA_createTableDialog( div, url , target){
1336      /**
1337      *  @var    button_options  Object that stores the options passed to jQueryUI
1338      *                          dialog
1339      */
1340      var button_options = {};
1341      // in the following function we need to use $(this)
1342      button_options[PMA_messages['strCancel']] = function() {$(this).parent().dialog('close').remove();}
1344      var button_options_error = {};
1345      button_options_error[PMA_messages['strOK']] = function() {$(this).parent().dialog('close').remove();}
1347      var $msgbox = PMA_ajaxShowMessage();
1349      $.get( target , url ,  function(data) {
1350          //in the case of an error, show the error message returned.
1351          if (data.success != undefined && data.success == false) {
1352              div
1353              .append(data.error)
1354              .dialog({
1355                  title: PMA_messages['strCreateTable'],
1356                  height: 230,
1357                  width: 900,
1358                  open: PMA_verifyTypeOfAllColumns,
1359                  buttons : button_options_error
1360              })// end dialog options
1361              //remove the redundant [Back] link in the error message.
1362              .find('fieldset').remove();
1363          } else {
1364              div
1365              .append(data)
1366              .dialog({
1367                  title: PMA_messages['strCreateTable'],
1368                  height: 600,
1369                  width: 900,
1370                  open: PMA_verifyTypeOfAllColumns,
1371                  buttons : button_options
1372              }); // end dialog options
1373          }
1374          PMA_ajaxRemoveMessage($msgbox);
1375      }) // end $.get()
1380  * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
1381  *  return a jQuery object yet and hence cannot be chained
1383  * @param   string      question
1384  * @param   string      url         URL to be passed to the callbackFn to make
1385  *                                  an Ajax call to
1386  * @param   function    callbackFn  callback to execute after user clicks on OK
1387  */
1389 jQuery.fn.PMA_confirm = function(question, url, callbackFn) {
1390     if (PMA_messages['strDoYouReally'] == '') {
1391         return true;
1392     }
1394     /**
1395      *  @var    button_options  Object that stores the options passed to jQueryUI
1396      *                          dialog
1397      */
1398     var button_options = {};
1399     button_options[PMA_messages['strOK']] = function(){
1400                                                 $(this).dialog("close").remove();
1402                                                 if($.isFunction(callbackFn)) {
1403                                                     callbackFn.call(this, url);
1404                                                 }
1405                                             };
1406     button_options[PMA_messages['strCancel']] = function() {$(this).dialog("close").remove();}
1408     $('<div id="confirm_dialog"></div>')
1409     .prepend(question)
1410     .dialog({buttons: button_options});
1414  * jQuery function to sort a table's body after a new row has been appended to it.
1415  * Also fixes the even/odd classes of the table rows at the end.
1417  * @param   string      text_selector   string to select the sortKey's text
1419  * @return  jQuery Object for chaining purposes
1420  */
1421 jQuery.fn.PMA_sort_table = function(text_selector) {
1422     return this.each(function() {
1424         /**
1425          * @var table_body  Object referring to the table's <tbody> element
1426          */
1427         var table_body = $(this);
1428         /**
1429          * @var rows    Object referring to the collection of rows in {@link table_body}
1430          */
1431         var rows = $(this).find('tr').get();
1433         //get the text of the field that we will sort by
1434         $.each(rows, function(index, row) {
1435             row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase());
1436         })
1438         //get the sorted order
1439         rows.sort(function(a,b) {
1440             if(a.sortKey < b.sortKey) {
1441                 return -1;
1442             }
1443             if(a.sortKey > b.sortKey) {
1444                 return 1;
1445             }
1446             return 0;
1447         })
1449         //pull out each row from the table and then append it according to it's order
1450         $.each(rows, function(index, row) {
1451             $(table_body).append(row);
1452             row.sortKey = null;
1453         })
1455         //Re-check the classes of each row
1456         $(this).find('tr:odd')
1457         .removeClass('even').addClass('odd')
1458         .end()
1459         .find('tr:even')
1460         .removeClass('odd').addClass('even');
1461     })
1465  * jQuery coding for 'Create Table'.  Used on db_operations.php,
1466  * db_structure.php and db_tracking.php (i.e., wherever
1467  * libraries/display_create_table.lib.php is used)
1469  * Attach Ajax Event handlers for Create Table
1470  */
1471 $(document).ready(function() {
1473      /**
1474      * Attach event handler to the submit action of the create table minimal form
1475      * and retrieve the full table form and display it in a dialog
1476      *
1477      * @uses    PMA_ajaxShowMessage()
1478      */
1479     $("#create_table_form_minimal.ajax").live('submit', function(event) {
1480         event.preventDefault();
1481         $form = $(this);
1482         PMA_prepareForAjaxRequest($form);
1484         /*variables which stores the common attributes*/
1485         var url = $form.serialize();
1486         var action = $form.attr('action');
1487         var div =  $('<div id="create_table_dialog"></div>');
1489         /*Calling to the createTableDialog function*/
1490         PMA_createTableDialog(div, url, action);
1492         // empty table name and number of columns from the minimal form
1493         $form.find('input[name=table],input[name=num_fields]').val('');
1494     });
1496     /**
1497      * Attach event handler for submission of create table form (save)
1498      *
1499      * @uses    PMA_ajaxShowMessage()
1500      * @uses    $.PMA_sort_table()
1501      *
1502      */
1503     // .live() must be called after a selector, see http://api.jquery.com/live
1504     $("#create_table_form input[name=do_save_data]").live('click', function(event) {
1505         event.preventDefault();
1507         /**
1508          *  @var    the_form    object referring to the create table form
1509          */
1510         var $form = $("#create_table_form");
1512         /*
1513          * First validate the form; if there is a problem, avoid submitting it
1514          *
1515          * checkTableEditForm() needs a pure element and not a jQuery object,
1516          * this is why we pass $form[0] as a parameter (the jQuery object
1517          * is actually an array of DOM elements)
1518          */
1520         if (checkTableEditForm($form[0], $form.find('input[name=orig_num_fields]').val())) {
1521             // OK, form passed validation step
1522             if ($form.hasClass('ajax')) {
1523                 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1524                 PMA_prepareForAjaxRequest($form);
1525                 //User wants to submit the form
1526                 $.post($form.attr('action'), $form.serialize() + "&do_save_data=" + $(this).val(), function(data) {
1527                     if(data.success == true) {
1528                         $('#properties_message')
1529                          .removeClass('error')
1530                          .html('');
1531                         PMA_ajaxShowMessage(data.message);
1532                         // Only if the create table dialog (distinct panel) exists
1533                         if ($("#create_table_dialog").length > 0) {
1534                             $("#create_table_dialog").dialog("close").remove();
1535                         }
1537                         /**
1538                          * @var tables_table    Object referring to the <tbody> element that holds the list of tables
1539                          */
1540                         var tables_table = $("#tablesForm").find("tbody").not("#tbl_summary_row");
1541                         // this is the first table created in this db
1542                         if (tables_table.length == 0) {
1543                             if (window.parent && window.parent.frame_content) {
1544                                 window.parent.frame_content.location.reload();
1545                             }
1546                         } else {
1547                             /**
1548                              * @var curr_last_row   Object referring to the last <tr> element in {@link tables_table}
1549                              */
1550                             var curr_last_row = $(tables_table).find('tr:last');
1551                             /**
1552                              * @var curr_last_row_index_string   String containing the index of {@link curr_last_row}
1553                              */
1554                             var curr_last_row_index_string = $(curr_last_row).find('input:checkbox').attr('id').match(/\d+/)[0];
1555                             /**
1556                              * @var curr_last_row_index Index of {@link curr_last_row}
1557                              */
1558                             var curr_last_row_index = parseFloat(curr_last_row_index_string);
1559                             /**
1560                              * @var new_last_row_index   Index of the new row to be appended to {@link tables_table}
1561                              */
1562                             var new_last_row_index = curr_last_row_index + 1;
1563                             /**
1564                              * @var new_last_row_id String containing the id of the row to be appended to {@link tables_table}
1565                              */
1566                             var new_last_row_id = 'checkbox_tbl_' + new_last_row_index;
1568                             data.new_table_string = data.new_table_string.replace(/checkbox_tbl_/, new_last_row_id);
1569                             //append to table
1570                             $(data.new_table_string)
1571                              .appendTo(tables_table);
1573                             //Sort the table
1574                             $(tables_table).PMA_sort_table('th');
1575                         }
1577                         //Refresh navigation frame as a new table has been added
1578                         if (window.parent && window.parent.frame_navigation) {
1579                             window.parent.frame_navigation.location.reload();
1580                         }
1581                     } else {
1582                         $('#properties_message')
1583                          .addClass('error')
1584                          .html(data.error);
1585                         // scroll to the div containing the error message
1586                         $('#properties_message')[0].scrollIntoView();
1587                     }
1588                 }) // end $.post()
1589             } // end if ($form.hasClass('ajax')
1590             else {
1591                 // non-Ajax submit
1592                 $form.append('<input type="hidden" name="do_save_data" value="save" />');
1593                 $form.submit();
1594             }
1595         } // end if (checkTableEditForm() )
1596     }) // end create table form (save)
1598     /**
1599      * Attach event handler for create table form (add fields)
1600      *
1601      * @uses    PMA_ajaxShowMessage()
1602      * @uses    $.PMA_sort_table()
1603      * @uses    window.parent.refreshNavigation()
1604      *
1605      */
1606     // .live() must be called after a selector, see http://api.jquery.com/live
1607     $("#create_table_form.ajax input[name=submit_num_fields]").live('click', function(event) {
1608         event.preventDefault();
1610         /**
1611          *  @var    the_form    object referring to the create table form
1612          */
1613         var $form = $("#create_table_form");
1615         var $msgbox = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1616         PMA_prepareForAjaxRequest($form);
1618         //User wants to add more fields to the table
1619         $.post($form.attr('action'), $form.serialize() + "&submit_num_fields=" + $(this).val(), function(data) {
1620             // if 'create_table_dialog' exists
1621             if ($("#create_table_dialog").length > 0) {
1622                 $("#create_table_dialog").html(data);
1623             }
1624             // if 'create_table_div' exists
1625             if ($("#create_table_div").length > 0) {
1626                 $("#create_table_div").html(data);
1627             }
1628             PMA_verifyTypeOfAllColumns();
1629             PMA_ajaxRemoveMessage($msgbox);
1630         }) //end $.post()
1632     }) // end create table form (add fields)
1634 }, 'top.frame_content'); //end $(document).ready for 'Create Table'
1637  * Attach Ajax event handlers for Drop Trigger.  Used on tbl_structure.php
1638  * @see $cfg['AjaxEnable']
1639  */
1640 $(document).ready(function() {
1642     $(".drop_trigger_anchor").live('click', function(event) {
1643         event.preventDefault();
1645         $anchor = $(this);
1646         /**
1647          * @var curr_row    Object reference to the current trigger's <tr>
1648          */
1649         var $curr_row = $anchor.parents('tr');
1650         /**
1651          * @var question    String containing the question to be asked for confirmation
1652          */
1653         var question = 'DROP TRIGGER IF EXISTS `' + $curr_row.children('td:first').text() + '`';
1655         $anchor.PMA_confirm(question, $anchor.attr('href'), function(url) {
1657             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1658             $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
1659                 if(data.success == true) {
1660                     PMA_ajaxShowMessage(data.message);
1661                     $("#topmenucontainer")
1662                     .next('div')
1663                     .remove()
1664                     .end()
1665                     .after(data.sql_query);
1666                     $curr_row.hide("medium").remove();
1667                 }
1668                 else {
1669                     PMA_ajaxShowMessage(data.error);
1670                 }
1671             }) // end $.get()
1672         }) // end $.PMA_confirm()
1673     }) // end $().live()
1674 }, 'top.frame_content'); //end $(document).ready() for Drop Trigger
1677  * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js
1678  * as it was also required on db_create.php
1680  * @uses    $.PMA_confirm()
1681  * @uses    PMA_ajaxShowMessage()
1682  * @uses    window.parent.refreshNavigation()
1683  * @uses    window.parent.refreshMain()
1684  * @see $cfg['AjaxEnable']
1685  */
1686 $(document).ready(function() {
1687     $("#drop_db_anchor").live('click', function(event) {
1688         event.preventDefault();
1690         //context is top.frame_content, so we need to use window.parent.db to access the db var
1691         /**
1692          * @var question    String containing the question to be asked for confirmation
1693          */
1694         var question = PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP DATABASE ' + window.parent.db;
1696         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
1698             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1699             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
1700                 //Database deleted successfully, refresh both the frames
1701                 window.parent.refreshNavigation();
1702                 window.parent.refreshMain();
1703             }) // end $.get()
1704         }); // end $.PMA_confirm()
1705     }); //end of Drop Database Ajax action
1706 }) // end of $(document).ready() for Drop Database
1709  * Attach Ajax event handlers for 'Create Database'.  Used wherever libraries/
1710  * display_create_database.lib.php is used, ie main.php and server_databases.php
1712  * @uses    PMA_ajaxShowMessage()
1713  * @see $cfg['AjaxEnable']
1714  */
1715 $(document).ready(function() {
1717     $('#create_database_form.ajax').live('submit', function(event) {
1718         event.preventDefault();
1720         $form = $(this);
1722         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1723         PMA_prepareForAjaxRequest($form);
1725         $.post($form.attr('action'), $form.serialize(), function(data) {
1726             if(data.success == true) {
1727                 PMA_ajaxShowMessage(data.message);
1729                 //Append database's row to table
1730                 $("#tabledatabases")
1731                 .find('tbody')
1732                 .append(data.new_db_string)
1733                 .PMA_sort_table('.name')
1734                 .find('#db_summary_row')
1735                 .appendTo('#tabledatabases tbody')
1736                 .removeClass('odd even');
1738                 var $databases_count_object = $('#databases_count');
1739                 var databases_count = parseInt($databases_count_object.text());
1740                 $databases_count_object.text(++databases_count);
1741                 //Refresh navigation frame as a new database has been added
1742                 if (window.parent && window.parent.frame_navigation) {
1743                     window.parent.frame_navigation.location.reload();
1744                 }
1745             }
1746             else {
1747                 PMA_ajaxShowMessage(data.error);
1748             }
1749         }) // end $.post()
1750     }) // end $().live()
1751 })  // end $(document).ready() for Create Database
1754  * Attach Ajax event handlers for 'Change Password' on main.php
1755  */
1756 $(document).ready(function() {
1758     /**
1759      * Attach Ajax event handler on the change password anchor
1760      * @see $cfg['AjaxEnable']
1761      */
1762     $('#change_password_anchor.dialog_active').live('click',function(event) {
1763         event.preventDefault();
1764         return false;
1765         });
1766     $('#change_password_anchor.ajax').live('click', function(event) {
1767         event.preventDefault();
1768         $(this).removeClass('ajax').addClass('dialog_active');
1769         /**
1770          * @var button_options  Object containing options to be passed to jQueryUI's dialog
1771          */
1772         var button_options = {};
1773         button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
1774         $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
1775             $('<div id="change_password_dialog"></div>')
1776             .dialog({
1777                 title: PMA_messages['strChangePassword'],
1778                 width: 600,
1779                 close: function(ev,ui) {$(this).remove();},
1780                 buttons : button_options,
1781                 beforeClose: function(ev,ui){ $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax')}
1782             })
1783             .append(data);
1784             displayPasswordGenerateButton();
1785         }) // end $.get()
1786     }) // end handler for change password anchor
1788     /**
1789      * Attach Ajax event handler for Change Password form submission
1790      *
1791      * @uses    PMA_ajaxShowMessage()
1792      * @see $cfg['AjaxEnable']
1793      */
1794     $("#change_password_form.ajax").find('input[name=change_pw]').live('click', function(event) {
1795         event.preventDefault();
1797         /**
1798          * @var the_form    Object referring to the change password form
1799          */
1800         var the_form = $("#change_password_form");
1802         /**
1803          * @var this_value  String containing the value of the submit button.
1804          * Need to append this for the change password form on Server Privileges
1805          * page to work
1806          */
1807         var this_value = $(this).val();
1809         var $msgbox = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1810         $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
1812         $.post($(the_form).attr('action'), $(the_form).serialize() + '&change_pw='+ this_value, function(data) {
1813             if(data.success == true) {
1814                 $("#topmenucontainer").after(data.sql_query);
1815                 $("#change_password_dialog").hide().remove();
1816                 $("#edit_user_dialog").dialog("close").remove();
1817                 $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax');
1818                 PMA_ajaxRemoveMessage($msgbox);
1819             }
1820             else {
1821                 PMA_ajaxShowMessage(data.error);
1822             }
1823         }) // end $.post()
1824     }) // end handler for Change Password form submission
1825 }) // end $(document).ready() for Change Password
1828  * Toggle the hiding/showing of the "Open in ENUM/SET editor" message when
1829  * the page loads and when the selected data type changes
1830  */
1831 $(document).ready(function() {
1832     // is called here for normal page loads and also when opening
1833     // the Create table dialog
1834     PMA_verifyTypeOfAllColumns();
1835     //
1836     // needs live() to work also in the Create Table dialog
1837     $("select[class='column_type']").live('change', function() {
1838         PMA_showNoticeForEnum($(this));
1839     });
1842 function PMA_verifyTypeOfAllColumns() {
1843     $("select[class='column_type']").each(function() {
1844         PMA_showNoticeForEnum($(this));
1845     });
1849  * Closes the ENUM/SET editor and removes the data in it
1850  */
1851 function disable_popup() {
1852     $("#popup_background").fadeOut("fast");
1853     $("#enum_editor").fadeOut("fast");
1854     // clear the data from the text boxes
1855     $("#enum_editor #values input").remove();
1856     $("#enum_editor input[type='hidden']").remove();
1860  * Opens the ENUM/SET editor and controls its functions
1861  */
1862 $(document).ready(function() {
1863     // Needs live() to work also in the Create table dialog
1864     $("a[class='open_enum_editor']").live('click', function() {
1865         // Center the popup
1866         var windowWidth = document.documentElement.clientWidth;
1867         var windowHeight = document.documentElement.clientHeight;
1868         var popupWidth = windowWidth/2;
1869         var popupHeight = windowHeight*0.8;
1870         var popupOffsetTop = windowHeight/2 - popupHeight/2;
1871         var popupOffsetLeft = windowWidth/2 - popupWidth/2;
1872         $("#enum_editor").css({"position":"absolute", "top": popupOffsetTop, "left": popupOffsetLeft, "width": popupWidth, "height": popupHeight});
1874         // Make it appear
1875         $("#popup_background").css({"opacity":"0.7"});
1876         $("#popup_background").fadeIn("fast");
1877         $("#enum_editor").fadeIn("fast");
1879         // Get the values
1880         var values = $(this).parent().prev("input").attr("value").split(",");
1881         $.each(values, function(index, val) {
1882             if(jQuery.trim(val) != "") {
1883                  // enclose the string in single quotes if it's not already
1884                  if(val.substr(0, 1) != "'") {
1885                       val = "'" + val;
1886                  }
1887                  if(val.substr(val.length-1, val.length) != "'") {
1888                       val = val + "'";
1889                  }
1890                 // escape the single quotes, except the mandatory ones enclosing the entire string
1891                 val = val.substr(1, val.length-2).replace(/''/g, "'").replace(/\\\\/g, '\\').replace(/\\'/g, "'").replace(/'/g, "&#039;");
1892                 // escape the greater-than symbol
1893                 val = val.replace(/>/g, "&gt;");
1894                 $("#enum_editor #values").append("<input type='text' value=" + val + " />");
1895             }
1896         });
1897         // So we know which column's data is being edited
1898         $("#enum_editor").append("<input type='hidden' value='" + $(this).parent().prev("input").attr("id") + "' />");
1899         return false;
1900     });
1902     // If the "close" link is clicked, close the enum editor
1903     // Needs live() to work also in the Create table dialog
1904     $("a[class='close_enum_editor']").live('click', function() {
1905         disable_popup();
1906     });
1908     // If the "cancel" link is clicked, close the enum editor
1909     // Needs live() to work also in the Create table dialog
1910     $("a[class='cancel_enum_editor']").live('click', function() {
1911         disable_popup();
1912     });
1914     // When "add a new value" is clicked, append an empty text field
1915     // Needs live() to work also in the Create table dialog
1916     $("a[class='add_value']").live('click', function() {
1917         $("#enum_editor #values").append("<input type='text' />");
1918     });
1920     // When the submit button is clicked, put the data back into the original form
1921     // Needs live() to work also in the Create table dialog
1922     $("#enum_editor input[type='submit']").live('click', function() {
1923         var value_array = new Array();
1924         $.each($("#enum_editor #values input"), function(index, input_element) {
1925             val = jQuery.trim(input_element.value);
1926             if(val != "") {
1927                 value_array.push("'" + val.replace(/\\/g, '\\\\').replace(/'/g, "''") + "'");
1928             }
1929         });
1930         // get the Length/Values text field where this value belongs
1931         var values_id = $("#enum_editor input[type='hidden']").attr("value");
1932         $("input[id='" + values_id + "']").attr("value", value_array.join(","));
1933         disable_popup();
1934      });
1936     /**
1937      * Hides certain table structure actions, replacing them with the word "More". They are displayed
1938      * in a dropdown menu when the user hovers over the word "More."
1939      */
1940     // Remove the actions from the table cells (they are available by default for JavaScript-disabled browsers)
1941     // if the table is not a view or information_schema (otherwise there is only one action to hide and there's no point)
1942     if($("input[type='hidden'][name='table_type']").val() == "table") {
1943         var $table = $("table[id='tablestructure']");
1944         $table.find("td[class='browse']").remove();
1945         $table.find("td[class='primary']").remove();
1946         $table.find("td[class='unique']").remove();
1947         $table.find("td[class='index']").remove();
1948         $table.find("td[class='fulltext']").remove();
1949         $table.find("th[class='action']").attr("colspan", 3);
1951         // Display the "more" text
1952         $table.find("td[class='more_opts']").show();
1954         // Position the dropdown
1955         $(".structure_actions_dropdown").each(function() {
1956             // Optimize DOM querying
1957             var $this_dropdown = $(this);
1958              // The top offset must be set for IE even if it didn't change
1959             var cell_right_edge_offset = $this_dropdown.parent().offset().left + $this_dropdown.parent().innerWidth();
1960             var left_offset = cell_right_edge_offset - $this_dropdown.innerWidth();
1961             var top_offset = $this_dropdown.parent().offset().top + $this_dropdown.parent().innerHeight();
1962             $this_dropdown.offset({ top: top_offset, left: left_offset });
1963         });
1965         // A hack for IE6 to prevent the after_field select element from being displayed on top of the dropdown by
1966         // positioning an iframe directly on top of it
1967         var $after_field = $("select[name='after_field']");
1968         $("iframe[class='IE_hack']")
1969             .width($after_field.width())
1970             .height($after_field.height())
1971             .offset({
1972                 top: $after_field.offset().top,
1973                 left: $after_field.offset().left
1974             });
1976         // When "more" is hovered over, show the hidden actions
1977         $table.find("td[class='more_opts']")
1978             .mouseenter(function() {
1979                 if($.browser.msie && $.browser.version == "6.0") {
1980                     $("iframe[class='IE_hack']")
1981                         .show()
1982                         .width($after_field.width()+4)
1983                         .height($after_field.height()+4)
1984                         .offset({
1985                             top: $after_field.offset().top,
1986                             left: $after_field.offset().left
1987                         });
1988                 }
1989                 $(".structure_actions_dropdown").hide(); // Hide all the other ones that may be open
1990                 $(this).children(".structure_actions_dropdown").show();
1991                 // Need to do this again for IE otherwise the offset is wrong
1992                 if($.browser.msie) {
1993                     var left_offset_IE = $(this).offset().left + $(this).innerWidth() - $(this).children(".structure_actions_dropdown").innerWidth();
1994                     var top_offset_IE = $(this).offset().top + $(this).innerHeight();
1995                     $(this).children(".structure_actions_dropdown").offset({
1996                         top: top_offset_IE,
1997                         left: left_offset_IE });
1998                 }
1999             })
2000             .mouseleave(function() {
2001                 $(this).children(".structure_actions_dropdown").hide();
2002                 if($.browser.msie && $.browser.version == "6.0") {
2003                     $("iframe[class='IE_hack']").hide();
2004                 }
2005             });
2006     }
2009 /* Displays tooltips */
2010 $(document).ready(function() {
2011     // Hide the footnotes from the footer (which are displayed for
2012     // JavaScript-disabled browsers) since the tooltip is sufficient
2013     $(".footnotes").hide();
2014     $(".footnotes span").each(function() {
2015         $(this).children("sup").remove();
2016     });
2017     // The border and padding must be removed otherwise a thin yellow box remains visible
2018     $(".footnotes").css("border", "none");
2019     $(".footnotes").css("padding", "0px");
2021     // Replace the superscripts with the help icon
2022     $("sup[class='footnotemarker']").hide();
2023     $("img[class='footnotemarker']").show();
2025     $("img[class='footnotemarker']").each(function() {
2026         var span_id = $(this).attr("id");
2027         span_id = span_id.split("_")[1];
2028         var tooltip_text = $(".footnotes span[id='footnote_" + span_id + "']").html();
2029         $(this).qtip({
2030             content: tooltip_text,
2031             show: { delay: 0 },
2032             hide: { when: 'unfocus', delay: 0 },
2033             style: { background: '#ffffcc' }
2034         });
2035     });
2038 function menuResize()
2040     var cnt = $('#topmenu');
2041     var wmax = cnt.innerWidth() - 5; // 5 px margin for jumping menu in Chrome
2042     var submenu = cnt.find('.submenu');
2043     var submenu_w = submenu.outerWidth(true);
2044     var submenu_ul = submenu.find('ul');
2045     var li = cnt.find('> li');
2046     var li2 = submenu_ul.find('li');
2047     var more_shown = li2.length > 0;
2048     var w = more_shown ? submenu_w : 0;
2050     // hide menu items
2051     var hide_start = 0;
2052     for (var i = 0; i < li.length-1; i++) { // li.length-1: skip .submenu element
2053         var el = $(li[i]);
2054         var el_width = el.outerWidth(true);
2055         el.data('width', el_width);
2056         w += el_width;
2057         if (w > wmax) {
2058             w -= el_width;
2059             if (w + submenu_w < wmax) {
2060                 hide_start = i;
2061             } else {
2062                 hide_start = i-1;
2063                 w -= $(li[i-1]).data('width');
2064             }
2065             break;
2066         }
2067     }
2069     if (hide_start > 0) {
2070         for (var i = hide_start; i < li.length-1; i++) {
2071             $(li[i])[more_shown ? 'prependTo' : 'appendTo'](submenu_ul);
2072         }
2073         submenu.addClass('shown');
2074     } else if (more_shown) {
2075         w -= submenu_w;
2076         // nothing hidden, maybe something can be restored
2077         for (var i = 0; i < li2.length; i++) {
2078             //console.log(li2[i], submenu_w);
2079             w += $(li2[i]).data('width');
2080             // item fits or (it is the last item and it would fit if More got removed)
2081             if (w+submenu_w < wmax || (i == li2.length-1 && w < wmax)) {
2082                 $(li2[i]).insertBefore(submenu);
2083                 if (i == li2.length-1) {
2084                     submenu.removeClass('shown');
2085                 }
2086                 continue;
2087             }
2088             break;
2089         }
2090     }
2091     if (submenu.find('.tabactive').length) {
2092         submenu.addClass('active').find('> a').removeClass('tab').addClass('tabactive');
2093     } else {
2094         submenu.removeClass('active').find('> a').addClass('tab').removeClass('tabactive');
2095     }
2098 $(function() {
2099     var topmenu = $('#topmenu');
2100     if (topmenu.length == 0) {
2101         return;
2102     }
2103     // create submenu container
2104     var link = $('<a />', {href: '#', 'class': 'tab'})
2105         .text(PMA_messages['strMore'])
2106         .click(function(e) {
2107             e.preventDefault();
2108         });
2109     var img = topmenu.find('li:first-child img');
2110     if (img.length) {
2111         img.clone().attr('src', img.attr('src').replace(/\/[^\/]+$/, '/b_more.png')).prependTo(link);
2112     }
2113     var submenu = $('<li />', {'class': 'submenu'})
2114         .append(link)
2115         .append($('<ul />'))
2116         .mouseenter(function() {
2117             if ($(this).find('ul .tabactive').length == 0) {
2118                 $(this).addClass('submenuhover').find('> a').addClass('tabactive');
2119             }
2120         })
2121         .mouseleave(function() {
2122             if ($(this).find('ul .tabactive').length == 0) {
2123                 $(this).removeClass('submenuhover').find('> a').removeClass('tabactive');
2124             }
2125         });
2126     topmenu.append(submenu);
2128     // populate submenu and register resize event
2129     $(window).resize(menuResize);
2130     menuResize();
2134  * For the checkboxes in browse mode, handles the shift/click (only works
2135  * in horizontal mode) and propagates the click to the "companion" checkbox
2136  * (in both horizontal and vertical). Works also for pages reached via AJAX.
2137  */
2138 $(document).ready(function() {
2139     $('.multi_checkbox').live('click',function(e) {
2140         var current_checkbox_id = this.id;
2141         var left_checkbox_id = current_checkbox_id.replace('_right', '_left');
2142         var right_checkbox_id = current_checkbox_id.replace('_left', '_right');
2143         var other_checkbox_id = '';
2144         if (current_checkbox_id == left_checkbox_id) {
2145             other_checkbox_id = right_checkbox_id;
2146         } else {
2147             other_checkbox_id = left_checkbox_id;
2148         }
2150         var $current_checkbox = $('#' + current_checkbox_id);
2151         var $other_checkbox = $('#' + other_checkbox_id);
2153         if (e.shiftKey) {
2154             var index_of_current_checkbox = $('.multi_checkbox').index($current_checkbox);
2155             var $last_checkbox = $('.multi_checkbox').filter('.last_clicked');
2156             var index_of_last_click = $('.multi_checkbox').index($last_checkbox);
2157             $('.multi_checkbox')
2158                 .filter(function(index) {
2159                     // the first clicked row can be on a row above or below the
2160                     // shift-clicked row
2161                     return (index_of_current_checkbox > index_of_last_click && index > index_of_last_click && index < index_of_current_checkbox)
2162                      || (index_of_last_click > index_of_current_checkbox && index < index_of_last_click && index > index_of_current_checkbox);
2163                 })
2164                 .each(function(index) {
2165                     var $intermediate_checkbox = $(this);
2166                     if ($current_checkbox.is(':checked')) {
2167                         $intermediate_checkbox.attr('checked', true);
2168                     } else {
2169                         $intermediate_checkbox.attr('checked', false);
2170                     }
2171                 });
2172         }
2174         $('.multi_checkbox').removeClass('last_clicked');
2175         $current_checkbox.addClass('last_clicked');
2177         // When there is a checkbox on both ends of the row, propagate the
2178         // click on one of them to the other one.
2179         // (the default action has not been prevented so if we have
2180         // just clicked, this "if" is true)
2181         if ($current_checkbox.is(':checked')) {
2182             $other_checkbox.attr('checked', true);
2183         } else {
2184             $other_checkbox.attr('checked', false);
2185         }
2186     });
2187 }) // end of $(document).ready() for multi checkbox
2190  * Get the row number from the classlist (for example, row_1)
2191  */
2192 function PMA_getRowNumber(classlist) {
2193     return parseInt(classlist.split(/row_/)[1]);
2197  * Changes status of slider
2198  */
2199 function PMA_set_status_label(id) {
2200     if ($('#' + id).css('display') == 'none') {
2201         $('#anchor_status_' + id).text('+ ');
2202     } else {
2203         $('#anchor_status_' + id).text('- ');
2204     }
2208  * Initializes slider effect.
2209  */
2210 function PMA_init_slider() {
2211     $('.pma_auto_slider').each(function(idx, e) {
2212         if ($(e).hasClass('slider_init_done')) return;
2213         $(e).addClass('slider_init_done');
2214         $('<span id="anchor_status_' + e.id + '"></span>')
2215             .insertBefore(e);
2216         PMA_set_status_label(e.id);
2218         $('<a href="#' + e.id + '" id="anchor_' + e.id + '">' + e.title + '</a>')
2219             .insertBefore(e)
2220             .click(function() {
2221                 $('#' + e.id).toggle('clip', function() {
2222                     PMA_set_status_label(e.id);
2223                 });
2224                 return false;
2225             });
2226     });
2230  * Vertical pointer
2231  */
2232 $(document).ready(function() {
2233     $('.vpointer').live('hover',
2234         //handlerInOut
2235         function(e) {
2236         var $this_td = $(this);
2237         var row_num = PMA_getRowNumber($this_td.attr('class'));
2238         // for all td of the same vertical row, toggle hover
2239         $('.vpointer').filter('.row_' + row_num).toggleClass('hover');
2240         }
2241         );
2242 }) // end of $(document).ready() for vertical pointer
2244 $(document).ready(function() {
2245     /**
2246      * Vertical marker
2247      */
2248     $('.vmarker').live('click', function(e) {
2249         var $this_td = $(this);
2250         var row_num = PMA_getRowNumber($this_td.attr('class'));
2251         // for all td of the same vertical row, toggle the marked class
2252         $('.vmarker').filter('.row_' + row_num).toggleClass('marked');
2253         });
2255     /**
2256      * Reveal visual builder anchor
2257      */
2259     $('#visual_builder_anchor').show();
2261     /**
2262      * Page selector in db Structure (non-AJAX)
2263      */
2264     $('#tableslistcontainer').find('#pageselector').live('change', function() {
2265         $(this).parent("form").submit();
2266     });
2268     /**
2269      * Page selector in navi panel (non-AJAX)
2270      */
2271     $('#navidbpageselector').find('#pageselector').live('change', function() {
2272         $(this).parent("form").submit();
2273     });
2275     /**
2276      * Page selector in browse_foreigners windows (non-AJAX)
2277      */
2278     $('#body_browse_foreigners').find('#pageselector').live('change', function() {
2279         $(this).closest("form").submit();
2280     });
2282     /**
2283      * Load version information asynchronously.
2284      */
2285     if ($('.jsversioncheck').length > 0) {
2286         (function() {
2287             var s = document.createElement('script');
2288             s.type = 'text/javascript';
2289             s.async = true;
2290             s.src = 'http://www.phpmyadmin.net/home_page/version.js';
2291             s.onload = PMA_current_version;
2292             var x = document.getElementsByTagName('script')[0];
2293             x.parentNode.insertBefore(s, x);
2294         })();
2295     }
2297     /**
2298      * Slider effect.
2299      */
2300     PMA_init_slider();
2302     /**
2303      * Enables the text generated by PMA_linkOrButton() to be clickable
2304      */
2305     $('.clickprevimage')
2306         .css('color', function(index) {
2307             return $('a').css('color');
2308         })
2309         .css('cursor', function(index) {
2310             return $('a').css('cursor');
2311         }) //todo: hover effect
2312         .live('click',function(e) {
2313             $this_span = $(this);
2314             if ($this_span.closest('td').is('.inline_edit_anchor')) {
2315             // this would bind a second click event to the inline edit
2316             // anchor and would disturb its behavior
2317             } else {
2318                 $this_span.parent().find('input:image').click();
2319             }
2320         });
2322     $('#update_recent_tables').ready(function() {
2323         if (window.parent.frame_navigation != undefined
2324             && window.parent.frame_navigation.PMA_reloadRecentTable != undefined)
2325         {
2326             window.parent.frame_navigation.PMA_reloadRecentTable();
2327         }
2328     });
2330 }) // end of $(document).ready()
2333  * Attach Ajax event handlers for Drop Table.
2335  * @uses    $.PMA_confirm()
2336  * @uses    PMA_ajaxShowMessage()
2337  * @uses    window.parent.refreshNavigation()
2338  * @uses    window.parent.refreshMain()
2339  * @see $cfg['AjaxEnable']
2340  */
2341 $(document).ready(function() {
2342     $("#drop_tbl_anchor").live('click', function(event) {
2343         event.preventDefault();
2345         //context is top.frame_content, so we need to use window.parent.db to access the db var
2346         /**
2347          * @var question    String containing the question to be asked for confirmation
2348          */
2349         var question = PMA_messages['strDropTableStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP TABLE ' + window.parent.table;
2351         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2353             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2354             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2355                 //Database deleted successfully, refresh both the frames
2356                 window.parent.refreshNavigation();
2357                 window.parent.refreshMain();
2358             }) // end $.get()
2359         }); // end $.PMA_confirm()
2360     }); //end of Drop Table Ajax action
2361 }) // end of $(document).ready() for Drop Table
2364  * Attach Ajax event handlers for Truncate Table.
2366  * @uses    $.PMA_confirm()
2367  * @uses    PMA_ajaxShowMessage()
2368  * @uses    window.parent.refreshNavigation()
2369  * @uses    window.parent.refreshMain()
2370  * @see $cfg['AjaxEnable']
2371  */
2372 $(document).ready(function() {
2373     $("#truncate_tbl_anchor").live('click', function(event) {
2374         event.preventDefault();
2376         //context is top.frame_content, so we need to use window.parent.db to access the db var
2377         /**
2378          * @var question    String containing the question to be asked for confirmation
2379          */
2380         var question = PMA_messages['strTruncateTableStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'TRUNCATE TABLE ' + window.parent.table;
2382         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2384             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2385             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2386                 //Database deleted successfully, refresh both the frames
2387                 window.parent.refreshNavigation();
2388                 window.parent.refreshMain();
2389             }) // end $.get()
2390         }); // end $.PMA_confirm()
2391     }); //end of Drop Table Ajax action
2392 }) // end of $(document).ready() for Drop Table
2395  * Attach CodeMirror2 editor to SQL edit area.
2396  */
2397 $(document).ready(function() {
2398     var elm = $('#sqlquery');
2399     if (elm.length > 0) {
2400         codemirror_editor = CodeMirror.fromTextArea(elm[0], {lineNumbers: true, matchBrackets: true, indentUnit: 4, mode: "text/x-mysql"});
2401     }