Vertical column highlighing did not work in all cases
[phpmyadmin-themes.git] / js / functions.js
blobcba0853a1cf76e2edfffaa283f1396b532638b94
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
2 /**
3  * general function, usally for data manipulation pages
4  *
5  */
7 /**
8  * @var sql_box_locked lock for the sqlbox textarea in the querybox/querywindow
9  */
10 var sql_box_locked = false;
12 /**
13  * @var array holds elements which content should only selected once
14  */
15 var only_once_elements = new Array();
17 /**
18  * @var ajax_message_init   boolean boolean that stores status of
19  *      notification for PMA_ajaxShowNotification
20  */
21 var ajax_message_init = false;
23 /**
24  * Generate a new password and copy it to the password input areas
25  *
26  * @param   object   the form that holds the password fields
27  *
28  * @return  boolean  always true
29  */
30 function suggestPassword(passwd_form) {
31     // restrict the password to just letters and numbers to avoid problems:
32     // "editors and viewers regard the password as multiple words and
33     // things like double click no longer work"
34     var pwchars = "abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ";
35     var passwordlength = 16;    // do we want that to be dynamic?  no, keep it simple :)
36     var passwd = passwd_form.generated_pw;
37     passwd.value = '';
39     for ( i = 0; i < passwordlength; i++ ) {
40         passwd.value += pwchars.charAt( Math.floor( Math.random() * pwchars.length ) )
41     }
42     passwd_form.text_pma_pw.value = passwd.value;
43     passwd_form.text_pma_pw2.value = passwd.value;
44     return true;
47 /**
48  * for libraries/display_change_password.lib.php 
49  *     libraries/user_password.php
50  *
51  */
53 function displayPasswordGenerateButton() {
54     $('#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>');
55     $('#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>');
59 /**
60  * selects the content of a given object, f.e. a textarea
61  *
62  * @param   object  element     element of which the content will be selected
63  * @param   var     lock        variable which holds the lock for this element
64  *                              or true, if no lock exists
65  * @param   boolean only_once   if true this is only done once
66  *                              f.e. only on first focus
67  */
68 function selectContent( element, lock, only_once ) {
69     if ( only_once && only_once_elements[element.name] ) {
70         return;
71     }
73     only_once_elements[element.name] = true;
75     if ( lock  ) {
76         return;
77     }
79     element.select();
82 /**
83  * Displays a confirmation box before submitting a "DROP DATABASE" query.
84  * This function is called while clicking links
85  *
86  * @param   object   the link
87  * @param   object   the sql query to submit
88  *
89  * @return  boolean  whether to run the query or not
90  */
91 function confirmLinkDropDB(theLink, theSqlQuery)
93     // Confirmation is not required in the configuration file
94     // or browser is Opera (crappy js implementation)
95     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
96         return true;
97     }
99     var is_confirmed = confirm(PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
100     if (is_confirmed) {
101         theLink.href += '&is_js_confirmed=1';
102     }
104     return is_confirmed;
105 } // end of the 'confirmLinkDropDB()' function
108  * Displays a confirmation box before to submit a "DROP/DELETE/ALTER" query.
109  * This function is called while clicking links
111  * @param   object   the link
112  * @param   object   the sql query to submit
114  * @return  boolean  whether to run the query or not
115  */
116 function confirmLink(theLink, theSqlQuery)
118     // Confirmation is not required in the configuration file
119     // or browser is Opera (crappy js implementation)
120     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
121         return true;
122     }
124     var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
125     if (is_confirmed) {
126         if ( typeof(theLink.href) != 'undefined' ) {
127             theLink.href += '&is_js_confirmed=1';
128         } else if ( typeof(theLink.form) != 'undefined' ) {
129             theLink.form.action += '?is_js_confirmed=1';
130         }
131     }
133     return is_confirmed;
134 } // end of the 'confirmLink()' function
138  * Displays a confirmation box before doing some action
140  * @param   object   the message to display
142  * @return  boolean  whether to run the query or not
144  * @todo used only by libraries/display_tbl.lib.php. figure out how it is used
145  *       and replace with a jQuery equivalent
146  */
147 function confirmAction(theMessage)
149     // TODO: Confirmation is not required in the configuration file
150     // or browser is Opera (crappy js implementation)
151     if (typeof(window.opera) != 'undefined') {
152         return true;
153     }
155     var is_confirmed = confirm(theMessage);
157     return is_confirmed;
158 } // end of the 'confirmAction()' function
162  * Displays an error message if a "DROP DATABASE" statement is submitted
163  * while it isn't allowed, else confirms a "DROP/DELETE/ALTER" query before
164  * sumitting it if required.
165  * This function is called by the 'checkSqlQuery()' js function.
167  * @param   object   the form
168  * @param   object   the sql query textarea
170  * @return  boolean  whether to run the query or not
172  * @see     checkSqlQuery()
173  */
174 function confirmQuery(theForm1, sqlQuery1)
176     // Confirmation is not required in the configuration file
177     if (PMA_messages['strDoYouReally'] == '') {
178         return true;
179     }
181     // The replace function (js1.2) isn't supported
182     else if (typeof(sqlQuery1.value.replace) == 'undefined') {
183         return true;
184     }
186     // js1.2+ -> validation with regular expressions
187     else {
188         // "DROP DATABASE" statement isn't allowed
189         if (PMA_messages['strNoDropDatabases'] != '') {
190             var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
191             if (drop_re.test(sqlQuery1.value)) {
192                 alert(PMA_messages['strNoDropDatabases']);
193                 theForm1.reset();
194                 sqlQuery1.focus();
195                 return false;
196             } // end if
197         } // end if
199         // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
200         //
201         // TODO: find a way (if possible) to use the parser-analyser
202         // for this kind of verification
203         // For now, I just added a ^ to check for the statement at
204         // beginning of expression
206         var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
207         var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
208         var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
209         var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
211         if (do_confirm_re_0.test(sqlQuery1.value)
212             || do_confirm_re_1.test(sqlQuery1.value)
213             || do_confirm_re_2.test(sqlQuery1.value)
214             || do_confirm_re_3.test(sqlQuery1.value)) {
215             var message      = (sqlQuery1.value.length > 100)
216                              ? sqlQuery1.value.substr(0, 100) + '\n    ...'
217                              : sqlQuery1.value;
218             var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
219             // statement is confirmed -> update the
220             // "is_js_confirmed" form field so the confirm test won't be
221             // run on the server side and allows to submit the form
222             if (is_confirmed) {
223                 theForm1.elements['is_js_confirmed'].value = 1;
224                 return true;
225             }
226             // statement is rejected -> do not submit the form
227             else {
228                 window.focus();
229                 sqlQuery1.focus();
230                 return false;
231             } // end if (handle confirm box result)
232         } // end if (display confirm box)
233     } // end confirmation stuff
235     return true;
236 } // end of the 'confirmQuery()' function
240  * Displays a confirmation box before disabling the BLOB repository for a given database.
241  * This function is called while clicking links
243  * @param   object   the database
245  * @return  boolean  whether to disable the repository or not
246  */
247 function confirmDisableRepository(theDB)
249     // Confirmation is not required in the configuration file
250     // or browser is Opera (crappy js implementation)
251     if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
252         return true;
253     }
255     var is_confirmed = confirm(PMA_messages['strBLOBRepositoryDisableStrongWarning'] + '\n' + PMA_messages['strBLOBRepositoryDisableAreYouSure']);
257     return is_confirmed;
258 } // end of the 'confirmDisableBLOBRepository()' function
262  * Displays an error message if the user submitted the sql query form with no
263  * sql query, else checks for "DROP/DELETE/ALTER" statements
265  * @param   object   the form
267  * @return  boolean  always false
269  * @see     confirmQuery()
270  */
271 function checkSqlQuery(theForm)
273     var sqlQuery = theForm.elements['sql_query'];
274     var isEmpty  = 1;
276     // The replace function (js1.2) isn't supported -> basic tests
277     if (typeof(sqlQuery.value.replace) == 'undefined') {
278         isEmpty      = (sqlQuery.value == '') ? 1 : 0;
279         if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') {
280             isEmpty  = (theForm.elements['sql_file'].value == '') ? 1 : 0;
281         }
282         if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') {
283             isEmpty  = (theForm.elements['sql_localfile'].value == '') ? 1 : 0;
284         }
285         if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') {
286             isEmpty  = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == '');
287         }
288     }
289     // js1.2+ -> validation with regular expressions
290     else {
291         var space_re = new RegExp('\\s+');
292         if (typeof(theForm.elements['sql_file']) != 'undefined' &&
293                 theForm.elements['sql_file'].value.replace(space_re, '') != '') {
294             return true;
295         }
296         if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
297                 theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
298             return true;
299         }
300         if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
301                 (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
302                 theForm.elements['id_bookmark'].selectedIndex != 0
303                 ) {
304             return true;
305         }
306         // Checks for "DROP/DELETE/ALTER" statements
307         if (sqlQuery.value.replace(space_re, '') != '') {
308             if (confirmQuery(theForm, sqlQuery)) {
309                 return true;
310             } else {
311                 return false;
312             }
313         }
314         theForm.reset();
315         isEmpty = 1;
316     }
318     if (isEmpty) {
319         sqlQuery.select();
320         alert(PMA_messages['strFormEmpty']);
321         sqlQuery.focus();
322         return false;
323     }
325     return true;
326 } // end of the 'checkSqlQuery()' function
328 // Global variable row_class is set to even
329 var row_class = 'even';
332 * Generates a row dynamically in the differences table displaying
333 * the complete statistics of difference in  table like number of
334 * rows to be updated, number of rows to be inserted, number of
335 * columns to be added, number of columns to be removed, etc.
337 * @param  index         index of matching table
338 * @param  update_size   number of rows/column to be updated
339 * @param  insert_size   number of rows/coulmns to be inserted
340 * @param  remove_size   number of columns to be removed
341 * @param  insert_index  number of indexes to be inserted
342 * @param  remove_index  number of indexes to be removed
343 * @param  img_obj       image object
344 * @param  table_name    name of the table
347 function showDetails(i, update_size, insert_size, remove_size, insert_index, remove_index, img_obj, table_name)
349     // The path of the image is split to facilitate comparison
350     var relative_path = (img_obj.src).split("themes/");
352     // The image source is changed when the showDetails function is called.
353     if (relative_path[1] == 'original/img/new_data_hovered.jpg') {
354         img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg";
355         img_obj.alt = PMA_messages['strClickToUnselect'];  //only for IE browser
356     } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') {
357         img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg";
358         img_obj.alt = PMA_messages['strClickToUnselect'];
359     } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') {
360         img_obj.src = "./themes/original/img/new_struct_hovered.jpg";
361         img_obj.alt = PMA_messages['strClickToSelect'];
362     } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') {
363         img_obj.src = "./themes/original/img/new_data_hovered.jpg";
364         img_obj.alt = PMA_messages['strClickToSelect'];
365     }
367     var div = document.getElementById("list");
368     var table = div.getElementsByTagName("table")[0];
369     var table_body = table.getElementsByTagName("tbody")[0];
371     //Global variable row_class is being used
372     if (row_class == 'even') {
373         row_class = 'odd';
374     } else {
375         row_class = 'even';
376     }
377     // If the red or green button against a table name is pressed then append a new row to show the details of differences of this table.
378     if ((relative_path[1] != 'original/img/new_struct_selected_hovered.jpg') && (relative_path[1] != 'original/img/new_data_selected_hovered.jpg')) {
380         var newRow = document.createElement("tr");
381         newRow.setAttribute("class", row_class);
382         newRow.className = row_class;
383         // Id assigned to this row element is same as the index of this table name in the  matching_tables/source_tables_uncommon array
384         newRow.setAttribute("id" , i);
386         var table_name_cell = document.createElement("td");
387         table_name_cell.align = "center";
388         table_name_cell.innerHTML = table_name ;
390         newRow.appendChild(table_name_cell);
392         var create_table = document.createElement("td");
393         create_table.align = "center";
395         var add_cols = document.createElement("td");
396         add_cols.align = "center";
398         var remove_cols = document.createElement("td");
399         remove_cols.align = "center";
401         var alter_cols = document.createElement("td");
402         alter_cols.align = "center";
404         var add_index = document.createElement("td");
405         add_index.align = "center";
407         var delete_index = document.createElement("td");
408         delete_index.align = "center";
410         var update_rows = document.createElement("td");
411         update_rows.align = "center";
413         var insert_rows = document.createElement("td");
414         insert_rows.align = "center";
416         var tick_image = document.createElement("img");
417         tick_image.src = "./themes/original/img/s_success.png";
419         if (update_size == '' && insert_size == '' && remove_size == '') {
420           /**
421           This is the case when the table needs to be created in target database.
422           */
423             create_table.appendChild(tick_image);
424             add_cols.innerHTML = "--";
425             remove_cols.innerHTML = "--";
426             alter_cols.innerHTML = "--";
427             delete_index.innerHTML = "--";
428             add_index.innerHTML = "--";
429             update_rows.innerHTML = "--";
430             insert_rows.innerHTML = "--";
432             newRow.appendChild(create_table);
433             newRow.appendChild(add_cols);
434             newRow.appendChild(remove_cols);
435             newRow.appendChild(alter_cols);
436             newRow.appendChild(delete_index);
437             newRow.appendChild(add_index);
438             newRow.appendChild(update_rows);
439             newRow.appendChild(insert_rows);
441         } else if (update_size == '' && remove_size == '') {
442            /**
443            This is the case when data difference is displayed in the
444            table which is present in source but absent from target database
445           */
446             create_table.innerHTML = "--";
447             add_cols.innerHTML = "--";
448             remove_cols.innerHTML = "--";
449             alter_cols.innerHTML = "--";
450             add_index.innerHTML = "--";
451             delete_index.innerHTML = "--";
452             update_rows.innerHTML = "--";
453             insert_rows.innerHTML = insert_size;
455             newRow.appendChild(create_table);
456             newRow.appendChild(add_cols);
457             newRow.appendChild(remove_cols);
458             newRow.appendChild(alter_cols);
459             newRow.appendChild(delete_index);
460             newRow.appendChild(add_index);
461             newRow.appendChild(update_rows);
462             newRow.appendChild(insert_rows);
464         } else if (remove_size == '') {
465             /**
466              This is the case when data difference between matching_tables is displayed.
467             */
468             create_table.innerHTML = "--";
469             add_cols.innerHTML = "--";
470             remove_cols.innerHTML = "--";
471             alter_cols.innerHTML = "--";
472             add_index.innerHTML = "--";
473             delete_index.innerHTML = "--";
474             update_rows.innerHTML = update_size;
475             insert_rows.innerHTML = insert_size;
477             newRow.appendChild(create_table);
478             newRow.appendChild(add_cols);
479             newRow.appendChild(remove_cols);
480             newRow.appendChild(alter_cols);
481             newRow.appendChild(delete_index);
482             newRow.appendChild(add_index);
483             newRow.appendChild(update_rows);
484             newRow.appendChild(insert_rows);
486         } else {
487             /**
488             This is the case when structure difference between matching_tables id displayed
489             */
490             create_table.innerHTML = "--";
491             add_cols.innerHTML = insert_size;
492             remove_cols.innerHTML = remove_size;
493             alter_cols.innerHTML = update_size;
494             delete_index.innerHTML = remove_index;
495             add_index.innerHTML = insert_index;
496             update_rows.innerHTML = "--";
497             insert_rows.innerHTML = "--";
499             newRow.appendChild(create_table);
500             newRow.appendChild(add_cols);
501             newRow.appendChild(remove_cols);
502             newRow.appendChild(alter_cols);
503             newRow.appendChild(delete_index);
504             newRow.appendChild(add_index);
505             newRow.appendChild(update_rows);
506             newRow.appendChild(insert_rows);
507         }
508         table_body.appendChild(newRow);
510     } else if ((relative_path[1] != 'original/img/new_struct_hovered.jpg') && (relative_path[1] != 'original/img/new_data_hovered.jpg')) {
511       //The case when the row showing the details need to be removed from the table i.e. the difference button is deselected now.
512         var table_rows = table_body.getElementsByTagName("tr");
513         var j;
514         var index = 0;
515         for (j=0; j < table_rows.length; j++)
516         {
517             if (table_rows[j].id == i) {
518                 index = j;
519                 table_rows[j].parentNode.removeChild(table_rows[j]);
520             }
521         }
522         //The table row css is being adjusted. Class "odd" for odd rows and "even" for even rows should be maintained.
523         for(index = 0; index < table_rows.length; index++)
524         {
525             row_class_element = table_rows[index].getAttribute('class');
526             if (row_class_element == "even") {
527                 table_rows[index].setAttribute("class","odd");  // for Mozilla firefox
528                 table_rows[index].className = "odd";            // for IE browser
529             } else {
530                 table_rows[index].setAttribute("class","even"); // for Mozilla firefox
531                 table_rows[index].className = "even";           // for IE browser
532             }
533         }
534     }
538  * Changes the image on hover effects
540  * @param   img_obj   the image object whose source needs to be changed
542  */
543 function change_Image(img_obj)
545      var relative_path = (img_obj.src).split("themes/");
547     if (relative_path[1] == 'original/img/new_data.jpg') {
548         img_obj.src = "./themes/original/img/new_data_hovered.jpg";
549     } else if (relative_path[1] == 'original/img/new_struct.jpg') {
550         img_obj.src = "./themes/original/img/new_struct_hovered.jpg";
551     } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') {
552         img_obj.src = "./themes/original/img/new_struct.jpg";
553     } else if (relative_path[1] == 'original/img/new_data_hovered.jpg') {
554         img_obj.src = "./themes/original/img/new_data.jpg";
555     } else if (relative_path[1] == 'original/img/new_data_selected.jpg') {
556         img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg";
557     } else if(relative_path[1] == 'original/img/new_struct_selected.jpg') {
558         img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg";
559     } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') {
560         img_obj.src = "./themes/original/img/new_struct_selected.jpg";
561     } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') {
562         img_obj.src = "./themes/original/img/new_data_selected.jpg";
563     }
567  * Generates the URL containing the list of selected table ids for synchronization and
568  * a variable checked for confirmation of deleting previous rows from target tables
570  * @param   token   the token generated for each PMA form
572  */
573 function ApplySelectedChanges(token)
575     var div =  document.getElementById("list");
576     var table = div.getElementsByTagName('table')[0];
577     var table_body = table.getElementsByTagName('tbody')[0];
578     // Get all the rows from the details table
579     var table_rows = table_body.getElementsByTagName('tr');
580     var x = table_rows.length;
581     var i;
582     /**
583      Append the token at the beginning of the query string followed by
584     Table_ids that shows that "Apply Selected Changes" button is pressed
585     */
586     var append_string = "?token="+token+"&Table_ids="+1;
587     for(i=0; i<x; i++){
588            append_string += "&";
589            append_string += i+"="+table_rows[i].id;
590     }
592     // Getting the value of checkbox delete_rows
593     var checkbox = document.getElementById("delete_rows");
594     if (checkbox.checked){
595         append_string += "&checked=true";
596     } else {
597          append_string += "&checked=false";
598     }
599     //Appending the token and list of table ids in the URL
600     location.href += token;
601     location.href += append_string;
605 * Displays an error message if any text field
606 * is left empty other than the port field.
608 * @param  string   the form name
609 * @param  object   the form
611 * @return  boolean  whether the form field is empty or not
613 function validateConnection(form_name, form_obj)
615     var check = true;
616     var src_hostfilled = true;
617     var trg_hostfilled = true;
619     for (var i=1; i<form_name.elements.length; i++)
620     {
621         // All the text fields are checked excluding the port field because the default port can be used.
622         if ((form_name.elements[i].type == 'text') && (form_name.elements[i].name != 'src_port') && (form_name.elements[i].name != 'trg_port')) {
623             check = emptyFormElements(form_obj, form_name.elements[i].name);
624             if (check==false) {
625                 element = form_name.elements[i].name;
626                 if (form_name.elements[i].name == 'src_host') {
627                     src_hostfilled = false;
628                     continue;
629                 }
630                 if (form_name.elements[i].name == 'trg_host') {
631                     trg_hostfilled = false;
632                     continue;
633                 }
634                 if ((form_name.elements[i].name == 'src_socket' && src_hostfilled==false) || (form_name.elements[i].name == 'trg_socket' && trg_hostfilled==false))
635                     break;
636                 else
637                     continue;
638             }
639         }
640     }
641     if (!check) {
642         form_obj.reset();
643         element.select();
644         alert(PMA_messages['strFormEmpty']);
645         element.focus();
646     }
647     return check;
651  * Check if a form's element is empty.
652  * An element containing only spaces is also considered empty
654  * @param   object   the form
655  * @param   string   the name of the form field to put the focus on
657  * @return  boolean  whether the form field is empty or not
658  */
659 function emptyCheckTheField(theForm, theFieldName)
661     var isEmpty  = 1;
662     var theField = theForm.elements[theFieldName];
663     // Whether the replace function (js1.2) is supported or not
664     var isRegExp = (typeof(theField.value.replace) != 'undefined');
666     if (!isRegExp) {
667         isEmpty      = (theField.value == '') ? 1 : 0;
668     } else {
669         var space_re = new RegExp('\\s+');
670         isEmpty      = (theField.value.replace(space_re, '') == '') ? 1 : 0;
671     }
673     return isEmpty;
674 } // end of the 'emptyCheckTheField()' function
678  * Check whether a form field is empty or not
680  * @param   object   the form
681  * @param   string   the name of the form field to put the focus on
683  * @return  boolean  whether the form field is empty or not
684  */
685 function emptyFormElements(theForm, theFieldName)
687     var theField = theForm.elements[theFieldName];
688     var isEmpty = emptyCheckTheField(theForm, theFieldName);
691     return isEmpty;
692 } // end of the 'emptyFormElements()' function
696  * Ensures a value submitted in a form is numeric and is in a range
698  * @param   object   the form
699  * @param   string   the name of the form field to check
700  * @param   integer  the minimum authorized value
701  * @param   integer  the maximum authorized value
703  * @return  boolean  whether a valid number has been submitted or not
704  */
705 function checkFormElementInRange(theForm, theFieldName, message, min, max)
707     var theField         = theForm.elements[theFieldName];
708     var val              = parseInt(theField.value);
710     if (typeof(min) == 'undefined') {
711         min = 0;
712     }
713     if (typeof(max) == 'undefined') {
714         max = Number.MAX_VALUE;
715     }
717     // It's not a number
718     if (isNaN(val)) {
719         theField.select();
720         alert(PMA_messages['strNotNumber']);
721         theField.focus();
722         return false;
723     }
724     // It's a number but it is not between min and max
725     else if (val < min || val > max) {
726         theField.select();
727         alert(message.replace('%d', val));
728         theField.focus();
729         return false;
730     }
731     // It's a valid number
732     else {
733         theField.value = val;
734     }
735     return true;
737 } // end of the 'checkFormElementInRange()' function
740 function checkTableEditForm(theForm, fieldsCnt)
742     // TODO: avoid sending a message if user just wants to add a line
743     // on the form but has not completed at least one field name
745     var atLeastOneField = 0;
746     var i, elm, elm2, elm3, val, id;
748     for (i=0; i<fieldsCnt; i++)
749     {
750         id = "#field_" + i + "_2";
751         elm = $(id);
752         val = elm.val()
753         if (val == 'VARCHAR' || val == 'CHAR' || val == 'BIT' || val == 'VARBINARY' || val == 'BINARY') {
754             elm2 = $("#field_" + i + "_3");
755             val = parseInt(elm2.val());
756             elm3 = $("#field_" + i + "_1");
757             if (isNaN(val) && elm3.val() != "") {
758                 elm2.select();
759                 alert(PMA_messages['strNotNumber']);
760                 elm2.focus();
761                 return false;
762             }
763         }
765         if (atLeastOneField == 0) {
766             id = "field_" + i + "_1";
767             if (!emptyCheckTheField(theForm, id)) {
768                 atLeastOneField = 1;
769             }
770         }
771     }
772     if (atLeastOneField == 0) {
773         var theField = theForm.elements["field_0_1"];
774         alert(PMA_messages['strFormEmpty']);
775         theField.focus();
776         return false;
777     }
779     return true;
780 } // enf of the 'checkTableEditForm()' function
784  * Ensures the choice between 'transmit', 'zipped', 'gzipped' and 'bzipped'
785  * checkboxes is consistant
787  * @param   object   the form
788  * @param   string   a code for the action that causes this function to be run
790  * @return  boolean  always true
791  */
792 function checkTransmitDump(theForm, theAction)
794     var formElts = theForm.elements;
796     // 'zipped' option has been checked
797     if (theAction == 'zip' && formElts['zip'].checked) {
798         if (!formElts['asfile'].checked) {
799             theForm.elements['asfile'].checked = true;
800         }
801         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
802             theForm.elements['gzip'].checked = false;
803         }
804         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
805             theForm.elements['bzip'].checked = false;
806         }
807     }
808     // 'gzipped' option has been checked
809     else if (theAction == 'gzip' && formElts['gzip'].checked) {
810         if (!formElts['asfile'].checked) {
811             theForm.elements['asfile'].checked = true;
812         }
813         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
814             theForm.elements['zip'].checked = false;
815         }
816         if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
817             theForm.elements['bzip'].checked = false;
818         }
819     }
820     // 'bzipped' option has been checked
821     else if (theAction == 'bzip' && formElts['bzip'].checked) {
822         if (!formElts['asfile'].checked) {
823             theForm.elements['asfile'].checked = true;
824         }
825         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
826             theForm.elements['zip'].checked = false;
827         }
828         if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
829             theForm.elements['gzip'].checked = false;
830         }
831     }
832     // 'transmit' option has been unchecked
833     else if (theAction == 'transmit' && !formElts['asfile'].checked) {
834         if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
835             theForm.elements['zip'].checked = false;
836         }
837         if ((typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked)) {
838             theForm.elements['gzip'].checked = false;
839         }
840         if ((typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked)) {
841             theForm.elements['bzip'].checked = false;
842         }
843     }
845     return true;
846 } // end of the 'checkTransmitDump()' function
849  * Row marking in horizontal mode (use "live" so that it works also for 
850  * next pages reached via AJAX); a tr may have the class noclick to remove
851  * this behavior.
852  */
853 $(document).ready(function() {
854     $('tr.odd:not(.noclick), tr.even:not(.noclick)').live('click',function() {
855         var $tr = $(this);
856         $tr.toggleClass('marked');
857         $tr.children().toggleClass('marked');
858     });
862  * Row highlighting in horizontal mode (use "live"
863  * so that it works also for pages reached via AJAX)
864  */
865 $(document).ready(function() {
866     $('tr.odd, tr.even').live('hover',function() {
867         var $tr = $(this);
868         $tr.toggleClass('hover');
869         $tr.children().toggleClass('hover');
870     });
874  * This array is used to remember mark status of rows in browse mode
875  */
876 var marked_row = new Array;
879  * marks all rows and selects its first checkbox inside the given element
880  * the given element is usaly a table or a div containing the table or tables
882  * @param    container    DOM element
883  */
884 function markAllRows( container_id ) {
886     $("#"+container_id).find("input:checkbox:enabled").attr('checked', 'checked')
887     .parents("tr").addClass("marked");
888     return true;
892  * marks all rows and selects its first checkbox inside the given element
893  * the given element is usaly a table or a div containing the table or tables
895  * @param    container    DOM element
896  */
897 function unMarkAllRows( container_id ) {
899     $("#"+container_id).find("input:checkbox:enabled").removeAttr('checked')
900     .parents("tr").removeClass("marked");
901     return true;
905  * Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div)
907  * @param   string   container_id  the container id
908  * @param   boolean  state         new value for checkbox (true or false)
909  * @return  boolean  always true
910  */
911 function setCheckboxes( container_id, state ) {
913     if(state) {
914         $("#"+container_id).find("input:checkbox").attr('checked', 'checked');
915     }
916     else {
917         $("#"+container_id).find("input:checkbox").removeAttr('checked');
918     }
920     return true;
921 } // end of the 'setCheckboxes()' function
924   * Checks/unchecks all options of a <select> element
925   *
926   * @param   string   the form name
927   * @param   string   the element name
928   * @param   boolean  whether to check or to uncheck the element
929   *
930   * @return  boolean  always true
931   */
932 function setSelectOptions(the_form, the_select, do_check)
935     if( do_check ) {
936         $("form[name='"+ the_form +"']").find("select[name='"+the_select+"']").find("option").attr('selected', 'selected');
937     }
938     else {
939         $("form[name='"+ the_form +"']").find("select[name="+the_select+"]").find("option").removeAttr('selected');
940     }
941     return true;
942 } // end of the 'setSelectOptions()' function
946   * Create quick sql statements.
947   *
948   */
949 function insertQuery(queryType) {
950     var myQuery = document.sqlform.sql_query;
951     var myListBox = document.sqlform.dummy;
952     var query = "";
953     var table = document.sqlform.table.value;
955     if (myListBox.options.length > 0) {
956         sql_box_locked = true;
957         var chaineAj = "";
958         var valDis = "";
959         var editDis = "";
960         var NbSelect = 0;
961         for (var i=0; i < myListBox.options.length; i++) {
962             NbSelect++;
963             if (NbSelect > 1) {
964                 chaineAj += ", ";
965                 valDis += ",";
966                 editDis += ",";
967             }
968             chaineAj += myListBox.options[i].value;
969             valDis += "[value-" + NbSelect + "]";
970             editDis += myListBox.options[i].value + "=[value-" + NbSelect + "]";
971         }
972     if (queryType == "selectall") {
973         query = "SELECT * FROM `" + table + "` WHERE 1";
974     } else if (queryType == "select") {
975         query = "SELECT " + chaineAj + " FROM `" + table + "` WHERE 1";
976     } else if (queryType == "insert") {
977            query = "INSERT INTO `" + table + "`(" + chaineAj + ") VALUES (" + valDis + ")";
978     } else if (queryType == "update") {
979         query = "UPDATE `" + table + "` SET " + editDis + " WHERE 1";
980     } else if(queryType == "delete") {
981         query = "DELETE FROM `" + table + "` WHERE 1";
982     }
983     document.sqlform.sql_query.value = query;
984     sql_box_locked = false;
985     }
990   * Inserts multiple fields.
991   *
992   */
993 function insertValueQuery() {
994     var myQuery = document.sqlform.sql_query;
995     var myListBox = document.sqlform.dummy;
997     if(myListBox.options.length > 0) {
998         sql_box_locked = true;
999         var chaineAj = "";
1000         var NbSelect = 0;
1001         for(var i=0; i<myListBox.options.length; i++) {
1002             if (myListBox.options[i].selected){
1003                 NbSelect++;
1004                 if (NbSelect > 1)
1005                     chaineAj += ", ";
1006                 chaineAj += myListBox.options[i].value;
1007             }
1008         }
1010         //IE support
1011         if (document.selection) {
1012             myQuery.focus();
1013             sel = document.selection.createRange();
1014             sel.text = chaineAj;
1015             document.sqlform.insert.focus();
1016         }
1017         //MOZILLA/NETSCAPE support
1018         else if (document.sqlform.sql_query.selectionStart || document.sqlform.sql_query.selectionStart == "0") {
1019             var startPos = document.sqlform.sql_query.selectionStart;
1020             var endPos = document.sqlform.sql_query.selectionEnd;
1021             var chaineSql = document.sqlform.sql_query.value;
1023             myQuery.value = chaineSql.substring(0, startPos) + chaineAj + chaineSql.substring(endPos, chaineSql.length);
1024         } else {
1025             myQuery.value += chaineAj;
1026         }
1027         sql_box_locked = false;
1028     }
1032   * listbox redirection
1033   */
1034 function goToUrl(selObj, goToLocation) {
1035     eval("document.location.href = '" + goToLocation + "pos=" + selObj.options[selObj.selectedIndex].value + "'");
1039  * getElement
1040  */
1041 function getElement(e,f){
1042     if(document.layers){
1043         f=(f)?f:self;
1044         if(f.document.layers[e]) {
1045             return f.document.layers[e];
1046         }
1047         for(W=0;W<f.document.layers.length;W++) {
1048             return(getElement(e,f.document.layers[W]));
1049         }
1050     }
1051     if(document.all) {
1052         return document.all[e];
1053     }
1054     return document.getElementById(e);
1058   * Refresh the WYSIWYG scratchboard after changes have been made
1059   */
1060 function refreshDragOption(e) {
1061     var elm = $('#' + e);
1062     if (elm.css('visibility') == 'visible') {
1063         refreshLayout();
1064         TableDragInit();
1065     }
1069   * Refresh/resize the WYSIWYG scratchboard
1070   */
1071 function refreshLayout() {
1072     var elm = $('#pdflayout')
1073     var orientation = $('#orientation_opt').val();
1074     if($('#paper_opt').length==1){
1075         var paper = $('#paper_opt').val();
1076     }else{
1077         var paper = 'A4';
1078     }
1079     if (orientation == 'P') {
1080         posa = 'x';
1081         posb = 'y';
1082     } else {
1083         posa = 'y';
1084         posb = 'x';
1085     }
1086     elm.css('width', pdfPaperSize(paper, posa) + 'px');
1087     elm.css('height', pdfPaperSize(paper, posb) + 'px');
1091   * Show/hide the WYSIWYG scratchboard
1092   */
1093 function ToggleDragDrop(e) {
1094     var elm = $('#' + e);
1095     if (elm.css('visibility') == 'hidden') {
1096         PDFinit(); /* Defined in pdf_pages.php */
1097         elm.css('visibility', 'visible');
1098         elm.css('display', 'block');
1099         $('#showwysiwyg').val('1')
1100     } else {
1101         elm.css('visibility', 'hidden');
1102         elm.css('display', 'none');
1103         $('#showwysiwyg').val('0')
1104     }
1108   * PDF scratchboard: When a position is entered manually, update
1109   * the fields inside the scratchboard.
1110   */
1111 function dragPlace(no, axis, value) {
1112     var elm = $('#table_' + no);
1113     if (axis == 'x') {
1114         elm.css('left', value + 'px');
1115     } else {
1116         elm.css('top', value + 'px');
1117     }
1121  * Returns paper sizes for a given format
1122  */
1123 function pdfPaperSize(format, axis) {
1124     switch (format.toUpperCase()) {
1125         case '4A0':
1126             if (axis == 'x') return 4767.87; else return 6740.79;
1127             break;
1128         case '2A0':
1129             if (axis == 'x') return 3370.39; else return 4767.87;
1130             break;
1131         case 'A0':
1132             if (axis == 'x') return 2383.94; else return 3370.39;
1133             break;
1134         case 'A1':
1135             if (axis == 'x') return 1683.78; else return 2383.94;
1136             break;
1137         case 'A2':
1138             if (axis == 'x') return 1190.55; else return 1683.78;
1139             break;
1140         case 'A3':
1141             if (axis == 'x') return 841.89; else return 1190.55;
1142             break;
1143         case 'A4':
1144             if (axis == 'x') return 595.28; else return 841.89;
1145             break;
1146         case 'A5':
1147             if (axis == 'x') return 419.53; else return 595.28;
1148             break;
1149         case 'A6':
1150             if (axis == 'x') return 297.64; else return 419.53;
1151             break;
1152         case 'A7':
1153             if (axis == 'x') return 209.76; else return 297.64;
1154             break;
1155         case 'A8':
1156             if (axis == 'x') return 147.40; else return 209.76;
1157             break;
1158         case 'A9':
1159             if (axis == 'x') return 104.88; else return 147.40;
1160             break;
1161         case 'A10':
1162             if (axis == 'x') return 73.70; else return 104.88;
1163             break;
1164         case 'B0':
1165             if (axis == 'x') return 2834.65; else return 4008.19;
1166             break;
1167         case 'B1':
1168             if (axis == 'x') return 2004.09; else return 2834.65;
1169             break;
1170         case 'B2':
1171             if (axis == 'x') return 1417.32; else return 2004.09;
1172             break;
1173         case 'B3':
1174             if (axis == 'x') return 1000.63; else return 1417.32;
1175             break;
1176         case 'B4':
1177             if (axis == 'x') return 708.66; else return 1000.63;
1178             break;
1179         case 'B5':
1180             if (axis == 'x') return 498.90; else return 708.66;
1181             break;
1182         case 'B6':
1183             if (axis == 'x') return 354.33; else return 498.90;
1184             break;
1185         case 'B7':
1186             if (axis == 'x') return 249.45; else return 354.33;
1187             break;
1188         case 'B8':
1189             if (axis == 'x') return 175.75; else return 249.45;
1190             break;
1191         case 'B9':
1192             if (axis == 'x') return 124.72; else return 175.75;
1193             break;
1194         case 'B10':
1195             if (axis == 'x') return 87.87; else return 124.72;
1196             break;
1197         case 'C0':
1198             if (axis == 'x') return 2599.37; else return 3676.54;
1199             break;
1200         case 'C1':
1201             if (axis == 'x') return 1836.85; else return 2599.37;
1202             break;
1203         case 'C2':
1204             if (axis == 'x') return 1298.27; else return 1836.85;
1205             break;
1206         case 'C3':
1207             if (axis == 'x') return 918.43; else return 1298.27;
1208             break;
1209         case 'C4':
1210             if (axis == 'x') return 649.13; else return 918.43;
1211             break;
1212         case 'C5':
1213             if (axis == 'x') return 459.21; else return 649.13;
1214             break;
1215         case 'C6':
1216             if (axis == 'x') return 323.15; else return 459.21;
1217             break;
1218         case 'C7':
1219             if (axis == 'x') return 229.61; else return 323.15;
1220             break;
1221         case 'C8':
1222             if (axis == 'x') return 161.57; else return 229.61;
1223             break;
1224         case 'C9':
1225             if (axis == 'x') return 113.39; else return 161.57;
1226             break;
1227         case 'C10':
1228             if (axis == 'x') return 79.37; else return 113.39;
1229             break;
1230         case 'RA0':
1231             if (axis == 'x') return 2437.80; else return 3458.27;
1232             break;
1233         case 'RA1':
1234             if (axis == 'x') return 1729.13; else return 2437.80;
1235             break;
1236         case 'RA2':
1237             if (axis == 'x') return 1218.90; else return 1729.13;
1238             break;
1239         case 'RA3':
1240             if (axis == 'x') return 864.57; else return 1218.90;
1241             break;
1242         case 'RA4':
1243             if (axis == 'x') return 609.45; else return 864.57;
1244             break;
1245         case 'SRA0':
1246             if (axis == 'x') return 2551.18; else return 3628.35;
1247             break;
1248         case 'SRA1':
1249             if (axis == 'x') return 1814.17; else return 2551.18;
1250             break;
1251         case 'SRA2':
1252             if (axis == 'x') return 1275.59; else return 1814.17;
1253             break;
1254         case 'SRA3':
1255             if (axis == 'x') return 907.09; else return 1275.59;
1256             break;
1257         case 'SRA4':
1258             if (axis == 'x') return 637.80; else return 907.09;
1259             break;
1260         case 'LETTER':
1261             if (axis == 'x') return 612.00; else return 792.00;
1262             break;
1263         case 'LEGAL':
1264             if (axis == 'x') return 612.00; else return 1008.00;
1265             break;
1266         case 'EXECUTIVE':
1267             if (axis == 'x') return 521.86; else return 756.00;
1268             break;
1269         case 'FOLIO':
1270             if (axis == 'x') return 612.00; else return 936.00;
1271             break;
1272     } // end switch
1274     return 0;
1278  * for playing media from the BLOB repository
1280  * @param   var
1281  * @param   var     url_params  main purpose is to pass the token
1282  * @param   var     bs_ref      BLOB repository reference
1283  * @param   var     m_type      type of BLOB repository media
1284  * @param   var     w_width     width of popup window
1285  * @param   var     w_height    height of popup window
1286  */
1287 function popupBSMedia(url_params, bs_ref, m_type, is_cust_type, w_width, w_height)
1289     // if width not specified, use default
1290     if (w_width == undefined)
1291         w_width = 640;
1293     // if height not specified, use default
1294     if (w_height == undefined)
1295         w_height = 480;
1297     // open popup window (for displaying video/playing audio)
1298     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');
1302  * popups a request for changing MIME types for files in the BLOB repository
1304  * @param   var     db                      database name
1305  * @param   var     table                   table name
1306  * @param   var     reference               BLOB repository reference
1307  * @param   var     current_mime_type       current MIME type associated with BLOB repository reference
1308  */
1309 function requestMIMETypeChange(db, table, reference, current_mime_type)
1311     // no mime type specified, set to default (nothing)
1312     if (undefined == current_mime_type)
1313         current_mime_type = "";
1315     // prompt user for new mime type
1316     var new_mime_type = prompt("Enter custom MIME type", current_mime_type);
1318     // if new mime_type is specified and is not the same as the previous type, request for mime type change
1319     if (new_mime_type && new_mime_type != current_mime_type)
1320         changeMIMEType(db, table, reference, new_mime_type);
1324  * changes MIME types for files in the BLOB repository
1326  * @param   var     db              database name
1327  * @param   var     table           table name
1328  * @param   var     reference       BLOB repository reference
1329  * @param   var     mime_type       new MIME type to be associated with BLOB repository reference
1330  */
1331 function changeMIMEType(db, table, reference, mime_type)
1333     // specify url and parameters for jQuery POST
1334     var mime_chg_url = 'bs_change_mime_type.php';
1335     var params = {bs_db: db, bs_table: table, bs_reference: reference, bs_new_mime_type: mime_type};
1337     // jQuery POST
1338     jQuery.post(mime_chg_url, params);
1342  * Jquery Coding for inline editing SQL_QUERY
1343  */
1344 $(document).ready(function(){
1345     var oldText,db,table,token,sql_query;
1346     oldText=$(".inner_sql").html();
1347     $("#inline_edit").click(function(){
1348         db=$("input[name='db']").val();
1349         table=$("input[name='table']").val();
1350         token=$("input[name='token']").val();
1351         sql_query=$("input[name='sql_query']").val();
1352         $(".inner_sql").replaceWith("<textarea name=\"sql_query_edit\" id=\"sql_query_edit\">"+ sql_query +"</textarea><input type=\"button\" id=\"btnSave\" value=\"" + PMA_messages['strGo'] + "\"><input type=\"button\" id=\"btnDiscard\" value=\"" + PMA_messages['strCancel'] + "\">");
1353         return false;
1354     });
1356     $("#btnSave").live("click",function(){
1357         window.location.replace("import.php?db=" + db +"&table=" + table + "&sql_query=" + $("#sql_query_edit").val()+"&show_query=1&token=" + token + "");
1358     });
1360     $("#btnDiscard").live("click",function(){
1361         $(".sql").html("<span class=\"syntax\"><span class=\"inner_sql\">" + oldText + "</span></span>");
1362     });
1364     $('.sqlbutton').click(function(evt){
1365         insertQuery(evt.target.id);
1366         return false;
1367     });
1369     $("#export_type").change(function(){
1370         if($("#export_type").val()=='svg'){
1371             $("#show_grid_opt").attr("disabled","disabled");
1372             $("#orientation_opt").attr("disabled","disabled");
1373             $("#with_doc").attr("disabled","disabled");
1374             $("#show_table_dim_opt").removeAttr("disabled");
1375             $("#all_table_same_wide").removeAttr("disabled");
1376             $("#paper_opt").removeAttr("disabled","disabled");
1377             $("#show_color_opt").removeAttr("disabled","disabled");
1378             //$(this).css("background-color","yellow");
1379         }else if($("#export_type").val()=='dia'){
1380             $("#show_grid_opt").attr("disabled","disabled");
1381             $("#with_doc").attr("disabled","disabled");
1382             $("#show_table_dim_opt").attr("disabled","disabled");
1383             $("#all_table_same_wide").attr("disabled","disabled");
1384             $("#paper_opt").removeAttr("disabled","disabled");
1385             $("#show_color_opt").removeAttr("disabled","disabled");
1386             $("#orientation_opt").removeAttr("disabled","disabled");
1387         }else if($("#export_type").val()=='eps'){
1388             $("#show_grid_opt").attr("disabled","disabled");
1389             $("#orientation_opt").removeAttr("disabled");
1390             $("#with_doc").attr("disabled","disabled");
1391             $("#show_table_dim_opt").attr("disabled","disabled");
1392             $("#all_table_same_wide").attr("disabled","disabled");
1393             $("#paper_opt").attr("disabled","disabled");
1394             $("#show_color_opt").attr("disabled","disabled");
1396         }else if($("#export_type").val()=='pdf'){
1397             $("#show_grid_opt").removeAttr("disabled");
1398             $("#orientation_opt").removeAttr("disabled");
1399             $("#with_doc").removeAttr("disabled","disabled");
1400             $("#show_table_dim_opt").removeAttr("disabled","disabled");
1401             $("#all_table_same_wide").removeAttr("disabled","disabled");
1402             $("#paper_opt").removeAttr("disabled","disabled");
1403             $("#show_color_opt").removeAttr("disabled","disabled");
1404         }else{
1405             // nothing
1406         }
1407     });
1409     $('#sqlquery').focus();
1410     if ($('#input_username')) {
1411         if ($('#input_username').val() == '') {
1412             $('#input_username').focus();
1413         } else {
1414             $('#input_password').focus();
1415         }
1416     }
1420  * Function to process the plain HTML response from an Ajax request.  Inserts
1421  * the various HTML divisions from the response at the proper locations.  The
1422  * array relates the divisions to be inserted to their placeholders.
1424  * @param   var divisions_map   an associative array of id names
1426  * <code>
1427  * PMA_ajaxInsertResponse({'resultsTable':'resultsTable_response',
1428  *                         'profilingData':'profilingData_response'});
1429  * </code>
1431  */
1433 function PMA_ajaxInsertResponse(divisions_map) {
1434     $.each(divisions_map, function(key, value) {
1435         var content_div = '#'+value;
1436         var target_div = '#'+key;
1437         var content = $(content_div).html();
1439         //replace content of target_div with that from the response
1440         $(target_div).html(content);
1441     });
1445  * Show a message on the top of the page for an Ajax request
1447  * @param   var     message     string containing the message to be shown.
1448  *                              optional, defaults to 'Loading...'
1449  * @param   var     timeout     number of milliseconds for the message to be visible
1450  *                              optional, defaults to 5000
1451  */
1453 function PMA_ajaxShowMessage(message, timeout) {
1455     //Handle the case when a empty data.message is passed.  We don't want the empty message
1456     if(message == '') {
1457         return true;
1458     }
1460     /**
1461      * @var msg String containing the message that has to be displayed
1462      * @default PMA_messages['strLoading']
1463      */
1464     if(!message) {
1465         var msg = PMA_messages['strLoading'];
1466     }
1467     else {
1468         var msg = message;
1469     }
1471     /**
1472      * @var timeout Number of milliseconds for which {@link msg} will be visible
1473      * @default 5000 ms
1474      */
1475     if(!timeout) {
1476         var to = 5000;
1477     }
1478     else {
1479         var to = timeout;
1480     }
1482     if( !ajax_message_init) {
1483         //For the first time this function is called, append a new div
1484         $(function(){
1485             $('<div id="loading_parent"></div>')
1486             .insertBefore("#serverinfo");
1488             $('<span id="loading" class="ajax_notification"></span>')
1489             .appendTo("#loading_parent")
1490             .html(msg)
1491             .slideDown('medium')
1492             .delay(to)
1493             .slideUp('medium', function(){
1494                 $(this)
1495                 .html("") //Clear the message
1496                 .hide();
1497             });
1498         }, 'top.frame_content');
1499         ajax_message_init = true;
1500     }
1501     else {
1502         //Otherwise, just show the div again after inserting the message
1503         $("#loading")
1504         .clearQueue()
1505         .html(msg)
1506         .slideDown('medium')
1507         .delay(to)
1508         .slideUp('medium', function() {
1509             $(this)
1510             .html("")
1511             .hide();
1512         })
1513     }
1517  * Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected
1518  */
1519 function toggle_enum_notice(selectElement) {
1520     var enum_notice_id = selectElement.attr("id").split("_")[1];
1521     enum_notice_id += "_" + (parseInt(selectElement.attr("id").split("_")[2]) + 1);
1522     var selectedType = selectElement.attr("value");
1523     if(selectedType == "ENUM" || selectedType == "SET") {
1524         $("p[id='enum_notice_" + enum_notice_id + "']").show();
1525     } else {
1526           $("p[id='enum_notice_" + enum_notice_id + "']").hide();
1527     }
1531  * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
1532  *  return a jQuery object yet and hence cannot be chained
1534  * @param   string      question
1535  * @param   string      url         URL to be passed to the callbackFn to make
1536  *                                  an Ajax call to
1537  * @param   function    callbackFn  callback to execute after user clicks on OK
1538  */
1540 jQuery.fn.PMA_confirm = function(question, url, callbackFn) {
1541     if (PMA_messages['strDoYouReally'] == '') {
1542         return true;
1543     }
1545     /**
1546      *  @var    button_options  Object that stores the options passed to jQueryUI
1547      *                          dialog
1548      */
1549     var button_options = {};
1550     button_options[PMA_messages['strOK']] = function(){
1551                                                 $(this).dialog("close").remove();
1553                                                 if($.isFunction(callbackFn)) {
1554                                                     callbackFn.call(this, url);
1555                                                 }
1556                                             };
1557     button_options[PMA_messages['strCancel']] = function() {$(this).dialog("close").remove();}
1559     $('<div id="confirm_dialog"></div>')
1560     .prepend(question)
1561     .dialog({buttons: button_options});
1565  * jQuery function to sort a table's body after a new row has been appended to it.
1566  * Also fixes the even/odd classes of the table rows at the end.
1568  * @param   string      text_selector   string to select the sortKey's text
1570  * @return  jQuery Object for chaining purposes
1571  */
1572 jQuery.fn.PMA_sort_table = function(text_selector) {
1573     return this.each(function() {
1575         /**
1576          * @var table_body  Object referring to the table's <tbody> element
1577          */
1578         var table_body = $(this);
1579         /**
1580          * @var rows    Object referring to the collection of rows in {@link table_body}
1581          */
1582         var rows = $(this).find('tr').get();
1584         //get the text of the field that we will sort by
1585         $.each(rows, function(index, row) {
1586             row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase());
1587         })
1589         //get the sorted order
1590         rows.sort(function(a,b) {
1591             if(a.sortKey < b.sortKey) {
1592                 return -1;
1593             }
1594             if(a.sortKey > b.sortKey) {
1595                 return 1;
1596             }
1597             return 0;
1598         })
1600         //pull out each row from the table and then append it according to it's order
1601         $.each(rows, function(index, row) {
1602             $(table_body).append(row);
1603             row.sortKey = null;
1604         })
1606         //Re-check the classes of each row
1607         $(this).find('tr:odd')
1608         .removeClass('even').addClass('odd')
1609         .end()
1610         .find('tr:even')
1611         .removeClass('odd').addClass('even');
1612     })
1616  * jQuery coding for 'Create Table'.  Used on db_operations.php,
1617  * db_structure.php and db_tracking.php (i.e., wherever
1618  * libraries/display_create_table.lib.php is used)
1620  * Attach Ajax Event handlers for Create Table
1621  */
1622 $(document).ready(function() {
1624     /**
1625      * Attach event handler to the submit action of the create table minimal form
1626      * and retrieve the full table form and display it in a dialog
1627      *
1628      * @uses    PMA_ajaxShowMessage()
1629      */
1630     $("#create_table_form_minimal").live('submit', function(event) {
1631         event.preventDefault();
1632         $form = $(this);
1634         /* @todo Validate this form! */
1636         /**
1637          *  @var    button_options  Object that stores the options passed to jQueryUI
1638          *                          dialog
1639          */
1640         var button_options = {};
1641         // in the following function we need to use $(this)
1642         button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
1644         PMA_ajaxShowMessage();
1645         if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
1646             $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
1647         }
1649         $.get($form.attr('action'), $form.serialize(), function(data) {
1650             $('<div id="create_table_dialog"></div>')
1651             .append(data)
1652             .dialog({
1653                 title: PMA_messages['strCreateTable'],
1654                 width: 900,
1655                 buttons : button_options
1656             }); // end dialog options
1657         }) // end $.get()
1659         // empty table name and number of columns from the minimal form 
1660         $form.find('input[name=table],input[name=num_fields]').val('');
1661     });
1663     /**
1664      * Attach event handler for submission of create table form (save)
1665      *
1666      * @uses    PMA_ajaxShowMessage()
1667      * @uses    $.PMA_sort_table()
1668      *
1669      */
1670     // .live() must be called after a selector, see http://api.jquery.com/live
1671     $("#create_table_form input[name=do_save_data]").live('click', function(event) {
1672         event.preventDefault();
1674         /**
1675          *  @var    the_form    object referring to the create table form
1676          */
1677         var $form = $("#create_table_form");
1679         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1680         if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
1681             $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
1682         }
1683         //User wants to submit the form
1684         $.post($form.attr('action'), $form.serialize() + "&do_save_data=" + $(this).val(), function(data) {
1685             if(data.success == true) {
1686                 PMA_ajaxShowMessage(data.message);
1687                 $("#create_table_dialog").dialog("close").remove();
1689                 /**
1690                  * @var tables_table    Object referring to the <tbody> element that holds the list of tables
1691                  */
1692                 var tables_table = $("#tablesForm").find("tbody").not("#tbl_summary_row");
1693                 // this is the first table created in this db
1694                 if (tables_table.length == 0) {
1695                     if (window.parent && window.parent.frame_content) {
1696                         window.parent.frame_content.location.reload();
1697                     }
1698                 } else {
1699                     /**
1700                      * @var curr_last_row   Object referring to the last <tr> element in {@link tables_table}
1701                      */
1702                     var curr_last_row = $(tables_table).find('tr:last');
1703                     /**
1704                      * @var curr_last_row_index_string   String containing the index of {@link curr_last_row}
1705                      */
1706                     var curr_last_row_index_string = $(curr_last_row).find('input:checkbox').attr('id').match(/\d+/)[0];
1707                     /**
1708                      * @var curr_last_row_index Index of {@link curr_last_row}
1709                      */
1710                     var curr_last_row_index = parseFloat(curr_last_row_index_string);
1711                     /**
1712                      * @var new_last_row_index   Index of the new row to be appended to {@link tables_table}
1713                      */
1714                     var new_last_row_index = curr_last_row_index + 1;
1715                     /**
1716                      * @var new_last_row_id String containing the id of the row to be appended to {@link tables_table}
1717                      */
1718                     var new_last_row_id = 'checkbox_tbl_' + new_last_row_index;
1720                     //append to table
1721                     $(data.new_table_string)
1722                      .find('input:checkbox')
1723                      .val(new_last_row_id)
1724                      .end()
1725                      .appendTo(tables_table);
1727                     //Sort the table
1728                     $(tables_table).PMA_sort_table('th');
1729                 }
1731                 //Refresh navigation frame as a new table has been added
1732                 if (window.parent && window.parent.frame_navigation) {
1733                     window.parent.frame_navigation.location.reload();
1734                 }
1735             }
1736             else {
1737                 PMA_ajaxShowMessage(data.error);
1738             }
1739         }) // end $.post()
1740     }) // end create table form (save) 
1742     /**
1743      * Attach event handler for create table form (add fields)
1744      *
1745      * @uses    PMA_ajaxShowMessage()
1746      * @uses    $.PMA_sort_table()
1747      * @uses    window.parent.refreshNavigation()
1748      *
1749      */
1750     // .live() must be called after a selector, see http://api.jquery.com/live
1751     $("#create_table_form input[name=submit_num_fields]").live('click', function(event) {
1752         event.preventDefault();
1754         /**
1755          *  @var    the_form    object referring to the create table form
1756          */
1757         var $form = $("#create_table_form");
1759         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1760         if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
1761             $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
1762         }
1764         //User wants to add more fields to the table
1765         $.post($form.attr('action'), $form.serialize() + "&submit_num_fields=" + $(this).val(), function(data) {
1766             $("#create_table_dialog").html(data);
1767         }) //end $.post()
1769     }) // end create table form (add fields) 
1771 }, 'top.frame_content'); //end $(document).ready for 'Create Table'
1774  * Attach event handlers for Empty Table and Drop Table.  Used wherever libraries/
1775  * tbl_links.inc.php is used.
1776  */
1777 $(document).ready(function() {
1779     /**
1780      * Attach Ajax event handlers for Empty Table
1781      *
1782      * @uses    PMA_ajaxShowMessage()
1783      * @uses    $.PMA_confirm()
1784      */
1785     $("#empty_table_anchor").live('click', function(event) {
1786         event.preventDefault();
1788         /**
1789          * @var question    String containing the question to be asked for confirmation
1790          */
1791         var question = 'TRUNCATE TABLE ' + window.parent.table;
1793         $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
1795             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1796             $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
1797                 if(data.success == true) {
1798                     PMA_ajaxShowMessage(data.message);
1799                     $("#topmenucontainer")
1800                     .next('div')
1801                     .remove()
1802                     .end()
1803                     .after(data.sql_query);
1804                 }
1805                 else {
1806                     PMA_ajaxShowMessage(data.error);
1807                 }
1808             }) // end $.get
1809         }) // end $.PMA_confirm()
1810     }) // end Empty Table
1812     /**
1813      * Attach Ajax event handler for Drop Table
1814      *
1815      * @uses    PMA_ajaxShowMessage()
1816      * @uses    $.PMA_confirm()
1817      * @uses    window.parent.refreshNavigation()
1818      */
1819     $("#drop_table_anchor").live('click', function(event) {
1820         event.preventDefault();
1822         /**
1823          * @var question    String containing the question to be asked for confirmation
1824          */
1825         var question = 'DROP TABLE/VIEW ' + window.parent.table;
1826         $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
1828             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1829             $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
1830                 if(data.success == true) {
1831                     PMA_ajaxShowMessage(data.message);
1832                     $("#topmenucontainer")
1833                     .next('div')
1834                     .remove()
1835                     .end()
1836                     .after(data.sql_query);
1837                     window.parent.table = '';
1838                     if (window.parent && window.parent.frame_navigation) {
1839                         window.parent.frame_navigation.location.reload();
1840                     }
1841                 }
1842                 else {
1843                     PMA_ajaxShowMessage(data.error);
1844                 }
1845             }) // end $.get
1846         }) // end $.PMA_confirm()
1847     }) // end $().live()
1848 }, 'top.frame_content'); //end $(document).ready() for libraries/tbl_links.inc.php
1851  * Attach Ajax event handlers for Drop Trigger.  Used on tbl_structure.php
1852  */
1853 $(document).ready(function() {
1855     $(".drop_trigger_anchor").live('click', function(event) {
1856         event.preventDefault();
1858         /**
1859          * @var curr_row    Object reference to the current trigger's <tr>
1860          */
1861         var curr_row = $(this).parents('tr');
1862         /**
1863          * @var question    String containing the question to be asked for confirmation
1864          */
1865         var question = 'DROP TRIGGER IF EXISTS `' + $(curr_row).children('td:first').text() + '`';
1867         $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
1869             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1870             $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
1871                 if(data.success == true) {
1872                     PMA_ajaxShowMessage(data.message);
1873                     $("#topmenucontainer")
1874                     .next('div')
1875                     .remove()
1876                     .end()
1877                     .after(data.sql_query);
1878                     $(curr_row).hide("medium").remove();
1879                 }
1880                 else {
1881                     PMA_ajaxShowMessage(data.error);
1882                 }
1883             }) // end $.get()
1884         }) // end $.PMA_confirm()
1885     }) // end $().live()
1886 }, 'top.frame_content'); //end $(document).ready() for Drop Trigger
1889  * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js
1890  * as it was also required on db_create.php
1892  * @uses    $.PMA_confirm()
1893  * @uses    PMA_ajaxShowMessage()
1894  * @uses    window.parent.refreshNavigation()
1895  * @uses    window.parent.refreshMain()
1896  */
1897 $(document).ready(function() {
1898     $("#drop_db_anchor").live('click', function(event) {
1899         event.preventDefault();
1901         //context is top.frame_content, so we need to use window.parent.db to access the db var
1902         /**
1903          * @var question    String containing the question to be asked for confirmation
1904          */
1905         var question = PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP DATABASE ' + window.parent.db;
1907         $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
1909             PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1910             $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
1911                 //Database deleted successfully, refresh both the frames
1912                 window.parent.refreshNavigation();
1913                 window.parent.refreshMain();
1914             }) // end $.get()
1915         }); // end $.PMA_confirm()
1916     }); //end of Drop Database Ajax action
1917 }) // end of $(document).ready() for Drop Database
1920  * Attach Ajax event handlers for 'Create Database'.  Used wherever libraries/
1921  * display_create_database.lib.php is used, ie main.php and server_databases.php
1923  * @uses    PMA_ajaxShowMessage()
1924  */
1925 $(document).ready(function() {
1927     $('#create_database_form').live('submit', function(event) {
1928         event.preventDefault();
1930         $form = $(this);
1932         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
1934         if (! $form.find('input:hidden').is('#ajax_request_hidden')) {
1935             $form.append('<input type="hidden" id="ajax_request_hidden" name="ajax_request" value="true" />');
1936         }
1938         $.post($form.attr('action'), $form.serialize(), function(data) {
1939             if(data.success == true) {
1940                 PMA_ajaxShowMessage(data.message);
1942                 //Append database's row to table
1943                 $("#tabledatabases")
1944                 .find('tbody')
1945                 .append(data.new_db_string)
1946                 .PMA_sort_table('.name')
1947                 .find('#db_summary_row')
1948                 .appendTo('#tabledatabases tbody')
1949                 .removeClass('odd even');
1951                 var $databases_count_object = $('#databases_count');
1952                 var databases_count = parseInt($databases_count_object.text()); 
1953                 $databases_count_object.text(++databases_count);
1954                 //Refresh navigation frame as a new database has been added
1955                 if (window.parent && window.parent.frame_navigation) {
1956                     window.parent.frame_navigation.location.reload();
1957                 }
1958             }
1959             else {
1960                 PMA_ajaxShowMessage(data.error);
1961             }
1962         }) // end $.post()
1963     }) // end $().live()
1964 })  // end $(document).ready() for Create Database
1967  * Attach Ajax event handlers for 'Change Password' on main.php
1968  */
1969 $(document).ready(function() {
1971     /**
1972      * Attach Ajax event handler on the change password anchor
1973      */
1974     $('#change_password_anchor').live('click', function(event) {
1975         event.preventDefault();
1977         /**
1978          * @var button_options  Object containing options to be passed to jQueryUI's dialog
1979          */
1980         var button_options = {};
1982         button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
1984         $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
1985             $('<div id="change_password_dialog></div>')
1986             .dialog({
1987                 title: PMA_messages['strChangePassword'],
1988                 width: 600,
1989                 buttons : button_options
1990             })
1991             .append(data);
1992             displayPasswordGenerateButton();
1993         }) // end $.get()
1994     }) // end handler for change password anchor
1996     /**
1997      * Attach Ajax event handler for Change Password form submission
1998      *
1999      * @uses    PMA_ajaxShowMessage()
2000      */
2001     $("#change_password_form").find('input[name=change_pw]').live('click', function(event) {
2002         event.preventDefault();
2004         /**
2005          * @var the_form    Object referring to the change password form
2006          */
2007         var the_form = $("#change_password_form");
2009         /**
2010          * @var this_value  String containing the value of the submit button.
2011          * Need to append this for the change password form on Server Privileges
2012          * page to work
2013          */
2014         var this_value = $(this).val();
2016         PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2017         $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
2019         $.post($(the_form).attr('action'), $(the_form).serialize() + '&change_pw='+ this_value, function(data) {
2020             if(data.success == true) {
2022                 PMA_ajaxShowMessage(data.message);
2024                 $("#topmenucontainer").after(data.sql_query);
2026                 $("#change_password_dialog").hide().remove();
2027                 $("#edit_user_dialog").dialog("close").remove();
2028             }
2029             else {
2030                 PMA_ajaxShowMessage(data.error);
2031             }
2032         }) // end $.post()
2033     }) // end handler for Change Password form submission
2034 }) // end $(document).ready() for Change Password
2037  * Toggle the hiding/showing of the "Open in ENUM/SET editor" message when
2038  * the page loads and when the selected data type changes
2039  */
2040 $(document).ready(function() {
2041     $.each($("select[class='column_type']"), function() {
2042         toggle_enum_notice($(this));
2043     });
2044     $("select[class='column_type']").change(function() {
2045         toggle_enum_notice($(this));
2046     });
2050  * Closes the ENUM/SET editor and removes the data in it
2051  */
2052 function disable_popup() {
2053     $("#popup_background").fadeOut("fast");
2054     $("#enum_editor").fadeOut("fast");
2055     // clear the data from the text boxes
2056     $("#enum_editor #values input").remove();
2057     $("#enum_editor input[type='hidden']").remove();
2061  * Opens the ENUM/SET editor and controls its functions
2062  */
2063 $(document).ready(function() {
2064     $("a[class='open_enum_editor']").click(function() {
2065         // Center the popup
2066         var windowWidth = document.documentElement.clientWidth;
2067         var windowHeight = document.documentElement.clientHeight;
2068         var popupWidth = windowWidth/2;
2069         var popupHeight = windowHeight*0.8;
2070         var popupOffsetTop = windowHeight/2 - popupHeight/2;
2071         var popupOffsetLeft = windowWidth/2 - popupWidth/2;
2072         $("#enum_editor").css({"position":"absolute", "top": popupOffsetTop, "left": popupOffsetLeft, "width": popupWidth, "height": popupHeight});
2074         // Make it appear
2075         $("#popup_background").css({"opacity":"0.7"});
2076         $("#popup_background").fadeIn("fast");
2077         $("#enum_editor").fadeIn("fast");
2079         // Get the values
2080         var values = $(this).parent().prev("input").attr("value").split(",");
2081         $.each(values, function(index, val) {
2082             if(jQuery.trim(val) != "") {
2083                  // enclose the string in single quotes if it's not already
2084                  if(val.substr(0, 1) != "'") {
2085                       val = "'" + val;
2086                  }
2087                  if(val.substr(val.length-1, val.length) != "'") {
2088                       val = val + "'";
2089                  }
2090                 // escape the single quotes, except the mandatory ones enclosing the entire string
2091                 val = val.substr(1, val.length-2).replace(/''/g, "'").replace(/\\\\/g, '\\').replace(/\\'/g, "'").replace(/'/g, "&#039;");
2092                 // escape the greater-than symbol
2093                 val = val.replace(/>/g, "&gt;");
2094                 $("#enum_editor #values").append("<input type='text' value=" + val + " />");
2095             }
2096         });
2097         // So we know which column's data is being edited
2098         $("#enum_editor").append("<input type='hidden' value='" + $(this).parent().prev("input").attr("id") + "' />");
2099         return false;
2100     });
2102     // If the "close" link is clicked, close the enum editor
2103     $("a[class='close_enum_editor']").click(function() {
2104         disable_popup();
2105     });
2107     // If the "cancel" link is clicked, close the enum editor
2108     $("a[class='cancel_enum_editor']").click(function() {
2109         disable_popup();
2110     });
2112     // When "add a new value" is clicked, append an empty text field
2113     $("a[class='add_value']").click(function() {
2114         $("#enum_editor #values").append("<input type='text' />");
2115     });
2117     // When the submit button is clicked, put the data back into the original form
2118     $("#enum_editor input[type='submit']").click(function() {
2119         var value_array = new Array();
2120         $.each($("#enum_editor #values input"), function(index, input_element) {
2121             val = jQuery.trim(input_element.value);
2122             if(val != "") {
2123                 value_array.push("'" + val.replace(/\\/g, '\\\\').replace(/'/g, "''") + "'");
2124             }
2125         });
2126         // get the Length/Values text field where this value belongs
2127         var values_id = $("#enum_editor input[type='hidden']").attr("value");
2128         $("input[id='" + values_id + "']").attr("value", value_array.join(","));
2129         disable_popup();
2130      });
2132     /**
2133      * Hides certain table structure actions, replacing them with the word "More". They are displayed
2134      * in a dropdown menu when the user hovers over the word "More."
2135      */
2136     // Remove the actions from the table cells (they are available by default for JavaScript-disabled browsers)
2137     // if the table is not a view or information_schema (otherwise there is only one action to hide and there's no point)
2138     if($("input[type='hidden'][name='table_type']").attr("value") == "table") {
2139          $("table[id='tablestructure'] td[class='browse']").remove();
2140          $("table[id='tablestructure'] td[class='primary']").remove();
2141          $("table[id='tablestructure'] td[class='unique']").remove();
2142          $("table[id='tablestructure'] td[class='index']").remove();
2143          $("table[id='tablestructure'] td[class='fulltext']").remove();
2144          $("table[id='tablestructure'] th[class='action']").attr("colspan", 3);
2146          // Display the "more" text
2147          $("table[id='tablestructure'] td[class='more_opts']").show()
2149          // Position the dropdown
2150          $.each($(".structure_actions_dropdown"), function() {
2151               // The top offset must be set for IE even if it didn't change
2152              var cell_right_edge_offset = $(this).parent().offset().left + $(this).parent().innerWidth();
2153              var left_offset = cell_right_edge_offset - $(this).innerWidth();
2154              var top_offset = $(this).parent().offset().top + $(this).parent().innerHeight();
2155              $(this).offset({ top: top_offset, left: left_offset });
2156          });
2158          // A hack for IE6 to prevent the after_field select element from being displayed on top of the dropdown by
2159          // positioning an iframe directly on top of it
2160          $("iframe[class='IE_hack']").width($("select[name='after_field']").width());
2161          $("iframe[class='IE_hack']").height($("select[name='after_field']").height());
2162          $("iframe[class='IE_hack']").offset({ top: $("select[name='after_field']").offset().top, left: $("select[name='after_field']").offset().left });
2164          // When "more" is hovered over, show the hidden actions
2165          $("table[id='tablestructure'] td[class='more_opts']").mouseenter(
2166              function() {
2167                 if($.browser.msie && $.browser.version == "6.0") {
2168                     $("iframe[class='IE_hack']").show();
2169                     $("iframe[class='IE_hack']").width($("select[name='after_field']").width()+4);
2170                     $("iframe[class='IE_hack']").height($("select[name='after_field']").height()+4);
2171                     $("iframe[class='IE_hack']").offset({ top: $("select[name='after_field']").offset().top, left: $("select[name='after_field']").offset().left});
2172                 }
2173                 $(".structure_actions_dropdown").hide(); // Hide all the other ones that may be open
2174                 $(this).children(".structure_actions_dropdown").show();
2175                 // Need to do this again for IE otherwise the offset is wrong
2176                 if($.browser.msie) {
2177                     var left_offset_IE = $(this).offset().left + $(this).innerWidth() - $(this).children(".structure_actions_dropdown").innerWidth();
2178                     var top_offset_IE = $(this).offset().top + $(this).innerHeight();
2179                     $(this).children(".structure_actions_dropdown").offset({ top: top_offset_IE, left: left_offset_IE });
2180                 }
2181          });
2182          $(".structure_actions_dropdown").mouseleave(function() {
2183               $(this).hide();
2184               if($.browser.msie && $.browser.version == "6.0") {
2185                   $("iframe[class='IE_hack']").hide();
2186               }
2187          });
2188     }
2191 /* Displays tooltips */
2192 $(document).ready(function() {
2193     // Hide the footnotes from the footer (which are displayed for
2194     // JavaScript-disabled browsers) since the tooltip is sufficient
2195     $(".footnotes").hide();
2196     $(".footnotes span").each(function() {
2197         $(this).children("sup").remove();
2198     });
2199     // The border and padding must be removed otherwise a thin yellow box remains visible
2200     $(".footnotes").css("border", "none");
2201     $(".footnotes").css("padding", "0px");
2203     // Replace the superscripts with the help icon
2204     $("sup[class='footnotemarker']").hide();
2205     $("img[class='footnotemarker']").show();
2207     $("img[class='footnotemarker']").each(function() {
2208         var span_id = $(this).attr("id");
2209         span_id = span_id.split("_")[1];
2210         var tooltip_text = $(".footnotes span[id='footnote_" + span_id + "']").html();
2211         $(this).qtip({
2212             content: tooltip_text,
2213             show: { delay: 0 },
2214             hide: { when: 'unfocus', delay: 0 },
2215             style: { background: '#ffffcc' }
2216         });
2217     });
2220 function menuResize()
2222     var cnt = $('#topmenu');
2223     var wmax = cnt.width() - 5; // 5 px margin for jumping menu in Chrome
2224     var submenu = cnt.find('.submenu');
2225     var submenu_w = submenu.outerWidth(true);
2226     var submenu_ul = submenu.find('ul');
2227     var li = cnt.find('> li');
2228     var li2 = submenu_ul.find('li');
2229     var more_shown = li2.length > 0;
2230     var w = more_shown ? submenu_w : 0;
2232     // hide menu items
2233     var hide_start = 0;
2234     for (var i = 0; i < li.length-1; i++) { // li.length-1: skip .submenu element
2235         var el = $(li[i]);
2236         var el_width = el.outerWidth(true);
2237         el.data('width', el_width);
2238         w += el_width;
2239         if (w > wmax) {
2240             w -= el_width;
2241             if (w + submenu_w < wmax) {
2242                 hide_start = i;
2243             } else {
2244                 hide_start = i-1;
2245                 w -= $(li[i-1]).data('width');
2246             }
2247             break;
2248         }
2249     }
2251     if (hide_start > 0) {
2252         for (var i = hide_start; i < li.length-1; i++) {
2253             $(li[i])[more_shown ? 'prependTo' : 'appendTo'](submenu_ul);
2254         }
2255         submenu.show();
2256     } else if (more_shown) {
2257         w -= submenu_w;
2258         // nothing hidden, maybe something can be restored
2259         for (var i = 0; i < li2.length; i++) {
2260             //console.log(li2[i], submenu_w);
2261             w += $(li2[i]).data('width');
2262             // item fits or (it is the last item and it would fit if More got removed)
2263             if (w+submenu_w < wmax || (i == li2.length-1 && w < wmax)) {
2264                 $(li2[i]).insertBefore(submenu);
2265                 if (i == li2.length-1) {
2266                     submenu.hide();
2267                 }
2268                 continue;
2269             }
2270             break;
2271         }
2272     }
2273     if (submenu.find('.tabactive').length) {
2274         submenu.addClass('active').find('> a').removeClass('tab').addClass('tabactive');
2275     } else {
2276         submenu.removeClass('active').find('> a').addClass('tab').removeClass('tabactive');
2277     }
2280 $(function() {
2281     var topmenu = $('#topmenu');
2282     if (topmenu.length == 0) {
2283         return;
2284     }
2285     // create submenu container
2286     var link = $('<a />', {href: '#', 'class': 'tab'})
2287         .text(PMA_messages['strMore'])
2288         .click(function(e) {
2289             e.preventDefault();
2290         });
2291     var img = topmenu.find('li:first-child img');
2292     if (img.length) {
2293         img.clone().attr('src', img.attr('src').replace(/\/[^\/]+$/, '/b_more.png')).prependTo(link);
2294     }
2295     var submenu = $('<li />', {'class': 'submenu'})
2296         .append(link)
2297         .append($('<ul />'))
2298         .mouseenter(function() {
2299             if ($(this).find('ul .tabactive').length == 0) {
2300                 $(this).addClass('submenuhover').find('> a').addClass('tabactive');
2301             }
2302         })
2303         .mouseleave(function() {
2304             if ($(this).find('ul .tabactive').length == 0) {
2305                 $(this).removeClass('submenuhover').find('> a').removeClass('tabactive');
2306             }
2307         })
2308         .hide();
2309     topmenu.append(submenu);
2311     // populate submenu and register resize event
2312     $(window).resize(menuResize);
2313     menuResize();
2317  * For the checkboxes in browse mode, handles the shift/click (only works
2318  * in horizontal mode) and propagates the click to the "companion" checkbox
2319  * (in both horizontal and vertical). Works also for pages reached via AJAX.
2320  */
2321 $(document).ready(function() {
2322     $('.multi_checkbox').live('click',function(e) {
2323         var current_checkbox_id = this.id;
2324         var left_checkbox_id = current_checkbox_id.replace('_right', '_left');
2325         var right_checkbox_id = current_checkbox_id.replace('_left', '_right');
2326         var other_checkbox_id = '';
2327         if (current_checkbox_id == left_checkbox_id) {
2328             other_checkbox_id = right_checkbox_id; 
2329         } else {
2330             other_checkbox_id = left_checkbox_id;
2331         }
2333         var $current_checkbox = $('#' + current_checkbox_id);
2334         var $other_checkbox = $('#' + other_checkbox_id);
2336         if (e.shiftKey) {
2337             var index_of_current_checkbox = $('.multi_checkbox').index($current_checkbox);
2338             var $last_checkbox = $('.multi_checkbox').filter('.last_clicked');
2339             var index_of_last_click = $('.multi_checkbox').index($last_checkbox);
2340             $('.multi_checkbox')
2341                 .filter(function(index) {
2342                     // the first clicked row can be on a row above or below the
2343                     // shift-clicked row
2344                     return (index_of_current_checkbox > index_of_last_click && index > index_of_last_click && index < index_of_current_checkbox) 
2345                      || (index_of_last_click > index_of_current_checkbox && index < index_of_last_click && index > index_of_current_checkbox);
2346                 })
2347                 .each(function(index) {
2348                     var $intermediate_checkbox = $(this);
2349                     if ($current_checkbox.is(':checked')) {
2350                         $intermediate_checkbox.attr('checked', true);
2351                     } else {
2352                         $intermediate_checkbox.attr('checked', false);
2353                     }
2354                 });
2355         }
2357         $('.multi_checkbox').removeClass('last_clicked');
2358         $current_checkbox.addClass('last_clicked');
2359         
2360         // When there is a checkbox on both ends of the row, propagate the 
2361         // click on one of them to the other one.
2362         // (the default action has not been prevented so if we have
2363         // just clicked, this "if" is true)
2364         if ($current_checkbox.is(':checked')) {
2365             $other_checkbox.attr('checked', true);
2366         } else {
2367             $other_checkbox.attr('checked', false);
2368         }
2369     });
2370 }) // end of $(document).ready() for multi checkbox
2373  * Get the row number from the classlist (for example, row_1)
2374  */
2375 function PMA_getRowNumber(classlist) {
2376     return parseInt(classlist.split(/row_/)[1]);
2380  * Vertical pointer
2381  */
2382 $(document).ready(function() {
2383     $('.vpointer').live('hover',
2384         //handlerInOut
2385         function(e) {
2386         var $this_td = $(this);
2387         var row_num = PMA_getRowNumber($this_td.attr('class'));
2388         // for all td of the same vertical row, toggle hover
2389         $('.vpointer').filter('.row_' + row_num).toggleClass('hover'); 
2390         }
2391         );
2392 }) // end of $(document).ready() for vertical pointer
2394 $(document).ready(function() {
2395     /**
2396      * Vertical marker 
2397      */
2398     $('.vmarker').live('click', function(e) {
2399         var $this_td = $(this);
2400         var row_num = PMA_getRowNumber($this_td.attr('class'));
2401         // for all td of the same vertical row, toggle the marked class 
2402         $('.vmarker').filter('.row_' + row_num).toggleClass('marked'); 
2403         });
2405     /**
2406      * Reveal visual builder anchor
2407      */
2409     $('#visual_builder_anchor').show();
2410 }) // end of $(document).ready()