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