1 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 * general function, usally for data manipulation pages
8 * @var sql_box_locked lock for the sqlbox textarea in the querybox/querywindow
10 var sql_box_locked = false;
13 * @var array holds elements which content should only selected once
15 var only_once_elements = new Array();
18 * @var ajax_message_init boolean boolean that stores status of
19 * notification for PMA_ajaxShowNotification
21 var ajax_message_init = false;
24 * selects the content of a given object, f.e. a textarea
26 * @param object element element of which the content will be selected
27 * @param var lock variable which holds the lock for this element
28 * or true, if no lock exists
29 * @param boolean only_once if true this is only done once
30 * f.e. only on first focus
32 function selectContent( element, lock, only_once ) {
33 if ( only_once && only_once_elements[element.name] ) {
37 only_once_elements[element.name] = true;
47 * Displays an confirmation box before to submit a "DROP DATABASE" query.
48 * This function is called while clicking links
50 * @param object the link
51 * @param object the sql query to submit
53 * @return boolean whether to run the query or not
55 function confirmLinkDropDB(theLink, theSqlQuery)
57 // Confirmation is not required in the configuration file
58 // or browser is Opera (crappy js implementation)
59 if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
63 var is_confirmed = confirm(PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
65 theLink.href += '&is_js_confirmed=1';
69 } // end of the 'confirmLinkDropDB()' function
72 * Displays an confirmation box before to submit a "DROP/DELETE/ALTER" query.
73 * This function is called while clicking links
75 * @param object the link
76 * @param object the sql query to submit
78 * @return boolean whether to run the query or not
80 function confirmLink(theLink, theSqlQuery)
82 // Confirmation is not required in the configuration file
83 // or browser is Opera (crappy js implementation)
84 if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
88 var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
90 if ( typeof(theLink.href) != 'undefined' ) {
91 theLink.href += '&is_js_confirmed=1';
92 } else if ( typeof(theLink.form) != 'undefined' ) {
93 theLink.form.action += '?is_js_confirmed=1';
98 } // end of the 'confirmLink()' function
102 * Displays an confirmation box before doing some action
104 * @param object the message to display
106 * @return boolean whether to run the query or not
108 * @todo used only by libraries/display_tbl.lib.php. figure out how it is used
109 * and replace with a jQuery equivalent
111 function confirmAction(theMessage)
113 // TODO: Confirmation is not required in the configuration file
114 // or browser is Opera (crappy js implementation)
115 if (typeof(window.opera) != 'undefined') {
119 var is_confirmed = confirm(theMessage);
122 } // end of the 'confirmAction()' function
126 * Displays an error message if a "DROP DATABASE" statement is submitted
127 * while it isn't allowed, else confirms a "DROP/DELETE/ALTER" query before
128 * sumitting it if required.
129 * This function is called by the 'checkSqlQuery()' js function.
131 * @param object the form
132 * @param object the sql query textarea
134 * @return boolean whether to run the query or not
136 * @see checkSqlQuery()
138 function confirmQuery(theForm1, sqlQuery1)
140 // Confirmation is not required in the configuration file
141 if (PMA_messages['strDoYouReally'] == '') {
145 // The replace function (js1.2) isn't supported
146 else if (typeof(sqlQuery1.value.replace) == 'undefined') {
150 // js1.2+ -> validation with regular expressions
152 // "DROP DATABASE" statement isn't allowed
153 if (PMA_messages['strNoDropDatabases'] != '') {
154 var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
155 if (drop_re.test(sqlQuery1.value)) {
156 alert(PMA_messages['strNoDropDatabases']);
163 // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
165 // TODO: find a way (if possible) to use the parser-analyser
166 // for this kind of verification
167 // For now, I just added a ^ to check for the statement at
168 // beginning of expression
170 var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
171 var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
172 var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
173 var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
175 if (do_confirm_re_0.test(sqlQuery1.value)
176 || do_confirm_re_1.test(sqlQuery1.value)
177 || do_confirm_re_2.test(sqlQuery1.value)
178 || do_confirm_re_3.test(sqlQuery1.value)) {
179 var message = (sqlQuery1.value.length > 100)
180 ? sqlQuery1.value.substr(0, 100) + '\n ...'
182 var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
183 // statement is confirmed -> update the
184 // "is_js_confirmed" form field so the confirm test won't be
185 // run on the server side and allows to submit the form
187 theForm1.elements['is_js_confirmed'].value = 1;
190 // statement is rejected -> do not submit the form
195 } // end if (handle confirm box result)
196 } // end if (display confirm box)
197 } // end confirmation stuff
200 } // end of the 'confirmQuery()' function
204 * Displays a confirmation box before disabling the BLOB repository for a given database.
205 * This function is called while clicking links
207 * @param object the database
209 * @return boolean whether to disable the repository or not
211 function confirmDisableRepository(theDB)
213 // Confirmation is not required in the configuration file
214 // or browser is Opera (crappy js implementation)
215 if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') {
219 var is_confirmed = confirm(PMA_messages['strBLOBRepositoryDisableStrongWarning'] + '\n' + PMA_messages['strBLOBRepositoryDisableAreYouSure']);
222 } // end of the 'confirmDisableBLOBRepository()' function
226 * Displays an error message if the user submitted the sql query form with no
227 * sql query, else checks for "DROP/DELETE/ALTER" statements
229 * @param object the form
231 * @return boolean always false
233 * @see confirmQuery()
235 function checkSqlQuery(theForm)
237 var sqlQuery = theForm.elements['sql_query'];
240 // The replace function (js1.2) isn't supported -> basic tests
241 if (typeof(sqlQuery.value.replace) == 'undefined') {
242 isEmpty = (sqlQuery.value == '') ? 1 : 0;
243 if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') {
244 isEmpty = (theForm.elements['sql_file'].value == '') ? 1 : 0;
246 if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') {
247 isEmpty = (theForm.elements['sql_localfile'].value == '') ? 1 : 0;
249 if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') {
250 isEmpty = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == '');
253 // js1.2+ -> validation with regular expressions
255 var space_re = new RegExp('\\s+');
256 if (typeof(theForm.elements['sql_file']) != 'undefined' &&
257 theForm.elements['sql_file'].value.replace(space_re, '') != '') {
260 if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
261 theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
264 if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
265 (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
266 theForm.elements['id_bookmark'].selectedIndex != 0
270 // Checks for "DROP/DELETE/ALTER" statements
271 if (sqlQuery.value.replace(space_re, '') != '') {
272 if (confirmQuery(theForm, sqlQuery)) {
284 alert(PMA_messages['strFormEmpty']);
290 } // end of the 'checkSqlQuery()' function
292 // Global variable row_class is set to even
293 var row_class = 'even';
296 * Generates a row dynamically in the differences table displaying
297 * the complete statistics of difference in table like number of
298 * rows to be updated, number of rows to be inserted, number of
299 * columns to be added, number of columns to be removed, etc.
301 * @param index index of matching table
302 * @param update_size number of rows/column to be updated
303 * @param insert_size number of rows/coulmns to be inserted
304 * @param remove_size number of columns to be removed
305 * @param insert_index number of indexes to be inserted
306 * @param remove_index number of indexes to be removed
307 * @param img_obj image object
308 * @param table_name name of the table
311 function showDetails(i, update_size, insert_size, remove_size, insert_index, remove_index, img_obj, table_name)
313 // The path of the image is split to facilitate comparison
314 var relative_path = (img_obj.src).split("themes/");
316 // The image source is changed when the showDetails function is called.
317 if (relative_path[1] == 'original/img/new_data_hovered.jpg') {
318 img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg";
319 img_obj.alt = PMA_messages['strClickToUnselect']; //only for IE browser
320 } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') {
321 img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg";
322 img_obj.alt = PMA_messages['strClickToUnselect'];
323 } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') {
324 img_obj.src = "./themes/original/img/new_struct_hovered.jpg";
325 img_obj.alt = PMA_messages['strClickToSelect'];
326 } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') {
327 img_obj.src = "./themes/original/img/new_data_hovered.jpg";
328 img_obj.alt = PMA_messages['strClickToSelect'];
331 var div = document.getElementById("list");
332 var table = div.getElementsByTagName("table")[0];
333 var table_body = table.getElementsByTagName("tbody")[0];
335 //Global variable row_class is being used
336 if (row_class == 'even') {
341 // 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.
342 if ((relative_path[1] != 'original/img/new_struct_selected_hovered.jpg') && (relative_path[1] != 'original/img/new_data_selected_hovered.jpg')) {
344 var newRow = document.createElement("tr");
345 newRow.setAttribute("class", row_class);
346 newRow.className = row_class;
347 // Id assigned to this row element is same as the index of this table name in the matching_tables/source_tables_uncommon array
348 newRow.setAttribute("id" , i);
350 var table_name_cell = document.createElement("td");
351 table_name_cell.align = "center";
352 table_name_cell.innerHTML = table_name ;
354 newRow.appendChild(table_name_cell);
356 var create_table = document.createElement("td");
357 create_table.align = "center";
359 var add_cols = document.createElement("td");
360 add_cols.align = "center";
362 var remove_cols = document.createElement("td");
363 remove_cols.align = "center";
365 var alter_cols = document.createElement("td");
366 alter_cols.align = "center";
368 var add_index = document.createElement("td");
369 add_index.align = "center";
371 var delete_index = document.createElement("td");
372 delete_index.align = "center";
374 var update_rows = document.createElement("td");
375 update_rows.align = "center";
377 var insert_rows = document.createElement("td");
378 insert_rows.align = "center";
380 var tick_image = document.createElement("img");
381 tick_image.src = "./themes/original/img/s_success.png";
383 if (update_size == '' && insert_size == '' && remove_size == '') {
385 This is the case when the table needs to be created in target database.
387 create_table.appendChild(tick_image);
388 add_cols.innerHTML = "--";
389 remove_cols.innerHTML = "--";
390 alter_cols.innerHTML = "--";
391 delete_index.innerHTML = "--";
392 add_index.innerHTML = "--";
393 update_rows.innerHTML = "--";
394 insert_rows.innerHTML = "--";
396 newRow.appendChild(create_table);
397 newRow.appendChild(add_cols);
398 newRow.appendChild(remove_cols);
399 newRow.appendChild(alter_cols);
400 newRow.appendChild(delete_index);
401 newRow.appendChild(add_index);
402 newRow.appendChild(update_rows);
403 newRow.appendChild(insert_rows);
405 } else if (update_size == '' && remove_size == '') {
407 This is the case when data difference is displayed in the
408 table which is present in source but absent from target database
410 create_table.innerHTML = "--";
411 add_cols.innerHTML = "--";
412 remove_cols.innerHTML = "--";
413 alter_cols.innerHTML = "--";
414 add_index.innerHTML = "--";
415 delete_index.innerHTML = "--";
416 update_rows.innerHTML = "--";
417 insert_rows.innerHTML = insert_size;
419 newRow.appendChild(create_table);
420 newRow.appendChild(add_cols);
421 newRow.appendChild(remove_cols);
422 newRow.appendChild(alter_cols);
423 newRow.appendChild(delete_index);
424 newRow.appendChild(add_index);
425 newRow.appendChild(update_rows);
426 newRow.appendChild(insert_rows);
428 } else if (remove_size == '') {
430 This is the case when data difference between matching_tables is displayed.
432 create_table.innerHTML = "--";
433 add_cols.innerHTML = "--";
434 remove_cols.innerHTML = "--";
435 alter_cols.innerHTML = "--";
436 add_index.innerHTML = "--";
437 delete_index.innerHTML = "--";
438 update_rows.innerHTML = update_size;
439 insert_rows.innerHTML = insert_size;
441 newRow.appendChild(create_table);
442 newRow.appendChild(add_cols);
443 newRow.appendChild(remove_cols);
444 newRow.appendChild(alter_cols);
445 newRow.appendChild(delete_index);
446 newRow.appendChild(add_index);
447 newRow.appendChild(update_rows);
448 newRow.appendChild(insert_rows);
452 This is the case when structure difference between matching_tables id displayed
454 create_table.innerHTML = "--";
455 add_cols.innerHTML = insert_size;
456 remove_cols.innerHTML = remove_size;
457 alter_cols.innerHTML = update_size;
458 delete_index.innerHTML = remove_index;
459 add_index.innerHTML = insert_index;
460 update_rows.innerHTML = "--";
461 insert_rows.innerHTML = "--";
463 newRow.appendChild(create_table);
464 newRow.appendChild(add_cols);
465 newRow.appendChild(remove_cols);
466 newRow.appendChild(alter_cols);
467 newRow.appendChild(delete_index);
468 newRow.appendChild(add_index);
469 newRow.appendChild(update_rows);
470 newRow.appendChild(insert_rows);
472 table_body.appendChild(newRow);
474 } else if ((relative_path[1] != 'original/img/new_struct_hovered.jpg') && (relative_path[1] != 'original/img/new_data_hovered.jpg')) {
475 //The case when the row showing the details need to be removed from the table i.e. the difference button is deselected now.
476 var table_rows = table_body.getElementsByTagName("tr");
479 for (j=0; j < table_rows.length; j++)
481 if (table_rows[j].id == i) {
483 table_rows[j].parentNode.removeChild(table_rows[j]);
486 //The table row css is being adjusted. Class "odd" for odd rows and "even" for even rows should be maintained.
487 for(index; index < table_rows.length; index++)
489 row_class_element = table_rows[index].getAttribute('class');
490 if (row_class_element == "even") {
491 table_rows[index].setAttribute("class","odd"); // for Mozilla firefox
492 table_rows[index].className = "odd"; // for IE browser
494 table_rows[index].setAttribute("class","even"); // for Mozilla firefox
495 table_rows[index].className = "even"; // for IE browser
502 * Changes the image on hover effects
504 * @param img_obj the image object whose source needs to be changed
508 function change_Image(img_obj)
510 var relative_path = (img_obj.src).split("themes/");
512 if (relative_path[1] == 'original/img/new_data.jpg') {
513 img_obj.src = "./themes/original/img/new_data_hovered.jpg";
514 } else if (relative_path[1] == 'original/img/new_struct.jpg') {
515 img_obj.src = "./themes/original/img/new_struct_hovered.jpg";
516 } else if (relative_path[1] == 'original/img/new_struct_hovered.jpg') {
517 img_obj.src = "./themes/original/img/new_struct.jpg";
518 } else if (relative_path[1] == 'original/img/new_data_hovered.jpg') {
519 img_obj.src = "./themes/original/img/new_data.jpg";
520 } else if (relative_path[1] == 'original/img/new_data_selected.jpg') {
521 img_obj.src = "./themes/original/img/new_data_selected_hovered.jpg";
522 } else if(relative_path[1] == 'original/img/new_struct_selected.jpg') {
523 img_obj.src = "./themes/original/img/new_struct_selected_hovered.jpg";
524 } else if (relative_path[1] == 'original/img/new_struct_selected_hovered.jpg') {
525 img_obj.src = "./themes/original/img/new_struct_selected.jpg";
526 } else if (relative_path[1] == 'original/img/new_data_selected_hovered.jpg') {
527 img_obj.src = "./themes/original/img/new_data_selected.jpg";
532 * Generates the URL containing the list of selected table ids for synchronization and
533 * a variable checked for confirmation of deleting previous rows from target tables
535 * @param token the token generated for each PMA form
539 function ApplySelectedChanges(token)
541 var div = document.getElementById("list");
542 var table = div.getElementsByTagName('table')[0];
543 var table_body = table.getElementsByTagName('tbody')[0];
544 // Get all the rows from the details table
545 var table_rows = table_body.getElementsByTagName('tr');
546 var x = table_rows.length;
549 Append the token at the beginning of the query string followed by
550 Table_ids that shows that "Apply Selected Changes" button is pressed
552 var append_string = "?token="+token+"&Table_ids="+1;
554 append_string += "&";
555 append_string += i+"="+table_rows[i].id;
558 // Getting the value of checkbox delete_rows
559 var checkbox = document.getElementById("delete_rows");
560 if (checkbox.checked){
561 append_string += "&checked=true";
563 append_string += "&checked=false";
565 //Appending the token and list of table ids in the URL
566 location.href += token;
567 location.href += append_string;
571 * Displays error message if any text field
572 * is left empty other than port field.
574 * @param string the form name
575 * @param object the form
577 * @return boolean whether the form field is empty or not
579 function validateConnection(form_name, form_obj)
582 var src_hostfilled = true;
583 var trg_hostfilled = true;
585 for (var i=1; i<form_name.elements.length; i++)
587 // All the text fields are checked excluding the port field because the default port can be used.
588 if ((form_name.elements[i].type == 'text') && (form_name.elements[i].name != 'src_port') && (form_name.elements[i].name != 'trg_port')) {
589 check = emptyFormElements(form_obj, form_name.elements[i].name);
591 element = form_name.elements[i].name;
592 if (form_name.elements[i].name == 'src_host') {
593 src_hostfilled = false;
596 if (form_name.elements[i].name == 'trg_host') {
597 trg_hostfilled = false;
600 if ((form_name.elements[i].name == 'src_socket' && src_hostfilled==false) || (form_name.elements[i].name == 'trg_socket' && trg_hostfilled==false))
610 alert(PMA_messages['strFormEmpty']);
617 * Check if a form's element is empty
620 * @param object the form
621 * @param string the name of the form field to put the focus on
623 * @return boolean whether the form field is empty or not
625 function emptyCheckTheField(theForm, theFieldName)
628 var theField = theForm.elements[theFieldName];
629 // Whether the replace function (js1.2) is supported or not
630 var isRegExp = (typeof(theField.value.replace) != 'undefined');
633 isEmpty = (theField.value == '') ? 1 : 0;
635 var space_re = new RegExp('\\s+');
636 isEmpty = (theField.value.replace(space_re, '') == '') ? 1 : 0;
640 } // end of the 'emptyCheckTheField()' function
645 * @param object the form
646 * @param string the name of the form field to put the focus on
648 * @return boolean whether the form field is empty or not
650 function emptyFormElements(theForm, theFieldName)
652 var theField = theForm.elements[theFieldName];
653 var isEmpty = emptyCheckTheField(theForm, theFieldName);
657 } // end of the 'emptyFormElements()' function
661 * Ensures a value submitted in a form is numeric and is in a range
663 * @param object the form
664 * @param string the name of the form field to check
665 * @param integer the minimum authorized value
666 * @param integer the maximum authorized value
668 * @return boolean whether a valid number has been submitted or not
670 function checkFormElementInRange(theForm, theFieldName, message, min, max)
672 var theField = theForm.elements[theFieldName];
673 var val = parseInt(theField.value);
675 if (typeof(min) == 'undefined') {
678 if (typeof(max) == 'undefined') {
679 max = Number.MAX_VALUE;
685 alert(PMA_messages['strNotNumber']);
689 // It's a number but it is not between min and max
690 else if (val < min || val > max) {
692 alert(message.replace('%d', val));
696 // It's a valid number
698 theField.value = val;
702 } // end of the 'checkFormElementInRange()' function
705 function checkTableEditForm(theForm, fieldsCnt)
707 // TODO: avoid sending a message if user just wants to add a line
708 // on the form but has not completed at least one field name
710 var atLeastOneField = 0;
711 var i, elm, elm2, elm3, val, id;
713 for (i=0; i<fieldsCnt; i++)
715 id = "#field_" + i + "_2";
718 if (val == 'VARCHAR' || val == 'CHAR' || val == 'BIT' || val == 'VARBINARY' || val == 'BINARY') {
719 elm2 = $("#field_" + i + "_3");
720 val = parseInt(elm2.val());
721 elm3 = $("#field_" + i + "_1");
722 if (isNaN(val) && elm3.val() != "") {
724 alert(PMA_messages['strNotNumber']);
730 if (atLeastOneField == 0) {
731 id = "field_" + i + "_1";
732 if (!emptyCheckTheField(theForm, id)) {
737 if (atLeastOneField == 0) {
738 var theField = theForm.elements["field_0_1"];
739 alert(PMA_messages['strFormEmpty']);
745 } // enf of the 'checkTableEditForm()' function
749 * Ensures the choice between 'transmit', 'zipped', 'gzipped' and 'bzipped'
750 * checkboxes is consistant
752 * @param object the form
753 * @param string a code for the action that causes this function to be run
755 * @return boolean always true
757 function checkTransmitDump(theForm, theAction)
759 var formElts = theForm.elements;
761 // 'zipped' option has been checked
762 if (theAction == 'zip' && formElts['zip'].checked) {
763 if (!formElts['asfile'].checked) {
764 theForm.elements['asfile'].checked = true;
766 if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
767 theForm.elements['gzip'].checked = false;
769 if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
770 theForm.elements['bzip'].checked = false;
773 // 'gzipped' option has been checked
774 else if (theAction == 'gzip' && formElts['gzip'].checked) {
775 if (!formElts['asfile'].checked) {
776 theForm.elements['asfile'].checked = true;
778 if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
779 theForm.elements['zip'].checked = false;
781 if (typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked) {
782 theForm.elements['bzip'].checked = false;
785 // 'bzipped' option has been checked
786 else if (theAction == 'bzip' && formElts['bzip'].checked) {
787 if (!formElts['asfile'].checked) {
788 theForm.elements['asfile'].checked = true;
790 if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
791 theForm.elements['zip'].checked = false;
793 if (typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked) {
794 theForm.elements['gzip'].checked = false;
797 // 'transmit' option has been unchecked
798 else if (theAction == 'transmit' && !formElts['asfile'].checked) {
799 if (typeof(formElts['zip']) != 'undefined' && formElts['zip'].checked) {
800 theForm.elements['zip'].checked = false;
802 if ((typeof(formElts['gzip']) != 'undefined' && formElts['gzip'].checked)) {
803 theForm.elements['gzip'].checked = false;
805 if ((typeof(formElts['bzip']) != 'undefined' && formElts['bzip'].checked)) {
806 theForm.elements['bzip'].checked = false;
811 } // end of the 'checkTransmitDump()' function
815 * This array is used to remember mark status of rows in browse mode
817 var marked_row = new Array;
820 * enables highlight and marking of rows in data tables
823 function PMA_markRowsInit() {
824 // for every table row ...
825 var rows = document.getElementsByTagName('tr');
826 for ( var i = 0; i < rows.length; i++ ) {
827 // ... with the class 'odd' or 'even' ...
828 if ( 'odd' != rows[i].className.substr(0,3) && 'even' != rows[i].className.substr(0,4) ) {
831 // ... add event listeners ...
832 // ... to highlight the row on mouseover ...
833 if ( navigator.appName == 'Microsoft Internet Explorer' ) {
834 // but only for IE, other browsers are handled by :hover in css
835 rows[i].onmouseover = function() {
836 this.className += ' hover';
838 rows[i].onmouseout = function() {
839 this.className = this.className.replace( ' hover', '' );
842 // Do not set click events if not wanted
843 if (rows[i].className.search(/noclick/) != -1) {
846 // ... and to mark the row on click ...
847 $(rows[i]).bind('mousedown', function(event) {
852 // Somehow IE8 has this not set
853 if (!event) var event = window.event
855 checkbox = this.getElementsByTagName( 'input' )[0];
856 if ( checkbox && checkbox.type == 'checkbox' ) {
857 unique_id = checkbox.name + checkbox.value;
858 } else if ( this.id.length > 0 ) {
864 if ( typeof(marked_row[unique_id]) == 'undefined' || !marked_row[unique_id] ) {
865 marked_row[unique_id] = true;
867 marked_row[unique_id] = false;
870 if ( marked_row[unique_id] ) {
871 this.className += ' marked';
873 this.className = this.className.replace(' marked', '');
876 if ( checkbox && checkbox.disabled == false ) {
877 checkbox.checked = marked_row[unique_id];
878 if (typeof(event) == 'object') {
879 table = this.parentNode;
880 parentTableLimit = 0;
881 while (table.tagName.toLowerCase() != 'table' && parentTableLimit < 20) {
883 table = table.parentNode;
886 if (event.shiftKey == true && table.lastClicked != undefined) {
887 if (event.preventDefault) {event.preventDefault();} else {event.returnValue = false;}
888 i = table.lastClicked;
890 if (i < this.rowIndex) {
896 while (i != this.rowIndex) {
897 $(table.rows[i]).mousedown();
898 if (i < this.rowIndex) {
906 table.lastClicked = this.rowIndex;
911 // ... and disable label ...
912 var labeltag = rows[i].getElementsByTagName('label')[0];
914 labeltag.onclick = function() {
918 // .. and checkbox clicks
919 var checkbox = rows[i].getElementsByTagName('input')[0];
921 checkbox.onclick = function() {
922 // opera does not recognize return false;
923 this.checked = ! this.checked;
928 $(document).ready(PMA_markRowsInit);
931 * marks all rows and selects its first checkbox inside the given element
932 * the given element is usaly a table or a div containing the table or tables
934 * @param container DOM element
936 function markAllRows( container_id ) {
938 $("#"+container_id).find("input:checkbox:enabled").attr('checked', 'checked')
939 .parents("tr").addClass("marked");
944 * marks all rows and selects its first checkbox inside the given element
945 * the given element is usaly a table or a div containing the table or tables
947 * @param container DOM element
949 function unMarkAllRows( container_id ) {
951 $("#"+container_id).find("input:checkbox:enabled").removeAttr('checked')
952 .parents("tr").removeClass("marked");
957 * Sets/unsets the pointer and marker in browse mode
959 * @param object the table row
960 * @param integer the row number
961 * @param string the action calling this script (over, out or click)
962 * @param string the default background color
963 * @param string the color to use for mouseover
964 * @param string the color to use for marking a row
966 * @return boolean whether pointer is set or not
968 function setPointer(theRow, theRowNum, theAction, theDefaultColor, thePointerColor, theMarkColor)
972 // 1. Pointer and mark feature are disabled or the browser can't get the
974 if ((thePointerColor == '' && theMarkColor == '')
975 || typeof(theRow.style) == 'undefined') {
979 // 1.1 Sets the mouse pointer to pointer on mouseover and back to normal otherwise.
980 if (theAction == "over" || theAction == "click") {
981 theRow.style.cursor='pointer';
983 theRow.style.cursor='default';
986 // 2. Gets the current row and exits if the browser can't get it
987 if (typeof(document.getElementsByTagName) != 'undefined') {
988 theCells = theRow.getElementsByTagName('td');
990 else if (typeof(theRow.cells) != 'undefined') {
991 theCells = theRow.cells;
997 // 3. Gets the current color...
998 var rowCellsCnt = theCells.length;
999 var domDetect = null;
1000 var currentColor = null;
1001 var newColor = null;
1002 // 3.1 ... with DOM compatible browsers except Opera that does not return
1003 // valid values with "getAttribute"
1004 if (typeof(window.opera) == 'undefined'
1005 && typeof(theCells[0].getAttribute) != 'undefined') {
1006 currentColor = theCells[0].getAttribute('bgcolor');
1009 // 3.2 ... with other browsers
1011 currentColor = theCells[0].style.backgroundColor;
1015 // 3.3 ... Opera changes colors set via HTML to rgb(r,g,b) format so fix it
1016 if (currentColor.indexOf("rgb") >= 0)
1018 var rgbStr = currentColor.slice(currentColor.indexOf('(') + 1,
1019 currentColor.indexOf(')'));
1020 var rgbValues = rgbStr.split(",");
1022 var hexChars = "0123456789ABCDEF";
1023 for (var i = 0; i < 3; i++)
1025 var v = rgbValues[i].valueOf();
1026 currentColor += hexChars.charAt(v/16) + hexChars.charAt(v%16);
1030 // 4. Defines the new color
1031 // 4.1 Current color is the default one
1032 if (currentColor == ''
1033 || currentColor.toLowerCase() == theDefaultColor.toLowerCase()) {
1034 if (theAction == 'over' && thePointerColor != '') {
1035 newColor = thePointerColor;
1037 else if (theAction == 'click' && theMarkColor != '') {
1038 newColor = theMarkColor;
1039 marked_row[theRowNum] = true;
1040 // Garvin: deactivated onclick marking of the checkbox because it's also executed
1041 // when an action (like edit/delete) on a single item is performed. Then the checkbox
1042 // would get deactived, even though we need it activated. Maybe there is a way
1043 // to detect if the row was clicked, and not an item therein...
1044 // document.getElementById('id_rows_to_delete' + theRowNum).checked = true;
1047 // 4.1.2 Current color is the pointer one
1048 else if (currentColor.toLowerCase() == thePointerColor.toLowerCase()
1049 && (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum])) {
1050 if (theAction == 'out') {
1051 newColor = theDefaultColor;
1053 else if (theAction == 'click' && theMarkColor != '') {
1054 newColor = theMarkColor;
1055 marked_row[theRowNum] = true;
1056 // document.getElementById('id_rows_to_delete' + theRowNum).checked = true;
1059 // 4.1.3 Current color is the marker one
1060 else if (currentColor.toLowerCase() == theMarkColor.toLowerCase()) {
1061 if (theAction == 'click') {
1062 newColor = (thePointerColor != '')
1065 marked_row[theRowNum] = (typeof(marked_row[theRowNum]) == 'undefined' || !marked_row[theRowNum])
1068 // document.getElementById('id_rows_to_delete' + theRowNum).checked = false;
1072 // 5. Sets the new color...
1075 // 5.1 ... with DOM compatible browsers except Opera
1077 for (c = 0; c < rowCellsCnt; c++) {
1078 theCells[c].setAttribute('bgcolor', newColor, 0);
1081 // 5.2 ... with other browsers
1083 for (c = 0; c < rowCellsCnt; c++) {
1084 theCells[c].style.backgroundColor = newColor;
1090 } // end of the 'setPointer()' function
1093 * Sets/unsets the pointer and marker in vertical browse mode
1095 * @param object the table row
1096 * @param integer the column number
1097 * @param string the action calling this script (over, out or click)
1098 * @param string the default background Class
1099 * @param string the Class to use for mouseover
1100 * @param string the Class to use for marking a row
1102 * @return boolean whether pointer is set or not
1105 function setVerticalPointer(theRow, theColNum, theAction, theDefaultClass1, theDefaultClass2, thePointerClass, theMarkClass) {
1106 // 1. Pointer and mark feature are disabled or the browser can't get the
1108 if ((thePointerClass == '' && theMarkClass == '')
1109 || typeof(theRow.style) == 'undefined') {
1113 var tagSwitch = null;
1115 // 2. Gets the current row and exits if the browser can't get it
1116 if (typeof(document.getElementsByTagName) != 'undefined') {
1118 } else if (typeof(document.getElementById('table_results')) != 'undefined') {
1119 tagSwitch = 'cells';
1124 var theCells = null;
1126 if (tagSwitch == 'tag') {
1127 theRows = document.getElementById('table_results').getElementsByTagName('tr');
1128 theCells = theRows[1].getElementsByTagName('td');
1129 } else if (tagSwitch == 'cells') {
1130 theRows = document.getElementById('table_results').rows;
1131 theCells = theRows[1].cells;
1134 // 3. Gets the current Class...
1135 var currentClass = null;
1136 var newClass = null;
1138 // 3.1 ... with DOM compatible browsers except Opera that does not return
1139 // valid values with "getAttribute"
1140 if (typeof(window.opera) == 'undefined'
1141 && typeof(theCells[theColNum].getAttribute) != 'undefined') {
1142 currentClass = theCells[theColNum].className;
1145 // 4. Defines the new Class
1146 // 4.1 Current Class is the default one
1147 if (currentClass == ''
1148 || currentClass.toLowerCase() == theDefaultClass1.toLowerCase()
1149 || currentClass.toLowerCase() == theDefaultClass2.toLowerCase()) {
1150 if (theAction == 'over' && thePointerClass != '') {
1151 newClass = thePointerClass;
1152 } else if (theAction == 'click' && theMarkClass != '') {
1153 newClass = theMarkClass;
1154 marked_row[theColNum] = true;
1157 // 4.1.2 Current Class is the pointer one
1158 else if (currentClass.toLowerCase() == thePointerClass.toLowerCase() &&
1159 (typeof(marked_row[theColNum]) == 'undefined' || !marked_row[theColNum]) || marked_row[theColNum] == false) {
1160 if (theAction == 'out') {
1161 if (theColNum % 2) {
1162 newClass = theDefaultClass1;
1164 newClass = theDefaultClass2;
1167 else if (theAction == 'click' && theMarkClass != '') {
1168 newClass = theMarkClass;
1169 marked_row[theColNum] = true;
1172 // 4.1.3 Current Class is the marker one
1173 else if (currentClass.toLowerCase() == theMarkClass.toLowerCase()) {
1174 if (theAction == 'click') {
1175 newClass = (thePointerClass != '')
1177 : ((theColNum % 2) ? theDefaultClass2 : theDefaultClass1);
1178 marked_row[theColNum] = false;
1182 // 5 ... with DOM compatible browsers except Opera
1186 var rowCnt = theRows.length;
1187 for (c = 0; c < rowCnt; c++) {
1188 if (tagSwitch == 'tag') {
1189 Cells = theRows[c].getElementsByTagName('td');
1190 } else if (tagSwitch == 'cells') {
1191 Cells = theRows[c].cells;
1194 Cell = Cells[theColNum];
1196 // 5.1 Sets the new Class...
1197 Cell.className = Cell.className.replace(currentClass, newClass);
1202 } // end of the 'setVerticalPointer()' function
1205 * Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div)
1207 * @param string container_id the container id
1208 * @param boolean state new value for checkbox (true or false)
1209 * @return boolean always true
1211 function setCheckboxes( container_id, state ) {
1214 $("#"+container_id).find("input:checkbox").attr('checked', 'checked');
1217 $("#"+container_id).find("input:checkbox").removeAttr('checked');
1221 } // end of the 'setCheckboxes()' function
1224 // added 2004-05-08 by Michael Keck <mail_at_michaelkeck_dot_de>
1225 // copy the checked from left to right or from right to left
1226 // so it's easier for users to see, if $cfg['ModifyAtRight']=true, what they've checked ;)
1227 function copyCheckboxesRange(the_form, the_name, the_clicked)
1229 if (typeof(document.forms[the_form].elements[the_name]) != 'undefined' && typeof(document.forms[the_form].elements[the_name + 'r']) != 'undefined') {
1230 if (the_clicked !== 'r') {
1231 if (document.forms[the_form].elements[the_name].checked == true) {
1232 document.forms[the_form].elements[the_name + 'r'].checked = true;
1234 document.forms[the_form].elements[the_name + 'r'].checked = false;
1236 } else if (the_clicked == 'r') {
1237 if (document.forms[the_form].elements[the_name + 'r'].checked == true) {
1238 document.forms[the_form].elements[the_name].checked = true;
1240 document.forms[the_form].elements[the_name].checked = false;
1247 // added 2004-05-08 by Michael Keck <mail_at_michaelkeck_dot_de>
1248 // - this was directly written to each td, so why not a function ;)
1249 // setCheckboxColumn(\'id_rows_to_delete' . $row_no . ''\');
1250 function setCheckboxColumn(theCheckbox){
1251 if (document.getElementById(theCheckbox)) {
1252 document.getElementById(theCheckbox).checked = (document.getElementById(theCheckbox).checked ? false : true);
1253 if (document.getElementById(theCheckbox + 'r')) {
1254 document.getElementById(theCheckbox + 'r').checked = document.getElementById(theCheckbox).checked;
1257 if (document.getElementById(theCheckbox + 'r')) {
1258 document.getElementById(theCheckbox + 'r').checked = (document.getElementById(theCheckbox +'r').checked ? false : true);
1259 if (document.getElementById(theCheckbox)) {
1260 document.getElementById(theCheckbox).checked = document.getElementById(theCheckbox + 'r').checked;
1268 * Checks/unchecks all options of a <select> element
1270 * @param string the form name
1271 * @param string the element name
1272 * @param boolean whether to check or to uncheck the element
1274 * @return boolean always true
1276 function setSelectOptions(the_form, the_select, do_check)
1280 $("form[name='"+ the_form +"']").find("select[name='"+the_select+"']").find("option").attr('selected', 'selected');
1283 $("form[name='"+ the_form +"']").find("select[name="+the_select+"]").find("option").removeAttr('selected');
1286 } // end of the 'setSelectOptions()' function
1290 * Create quick sql statements.
1293 function insertQuery(queryType) {
1294 var myQuery = document.sqlform.sql_query;
1295 var myListBox = document.sqlform.dummy;
1297 var table = document.sqlform.table.value;
1299 if (myListBox.options.length > 0) {
1300 sql_box_locked = true;
1305 for (var i=0; i < myListBox.options.length; i++) {
1312 chaineAj += myListBox.options[i].value;
1313 valDis += "[value-" + NbSelect + "]";
1314 editDis += myListBox.options[i].value + "=[value-" + NbSelect + "]";
1316 if (queryType == "selectall") {
1317 query = "SELECT * FROM `" + table + "` WHERE 1";
1318 } else if (queryType == "select") {
1319 query = "SELECT " + chaineAj + " FROM `" + table + "` WHERE 1";
1320 } else if (queryType == "insert") {
1321 query = "INSERT INTO `" + table + "`(" + chaineAj + ") VALUES (" + valDis + ")";
1322 } else if (queryType == "update") {
1323 query = "UPDATE `" + table + "` SET " + editDis + " WHERE 1";
1324 } else if(queryType == "delete") {
1325 query = "DELETE FROM `" + table + "` WHERE 1";
1327 document.sqlform.sql_query.value = query;
1328 sql_box_locked = false;
1334 * Inserts multiple fields.
1337 function insertValueQuery() {
1338 var myQuery = document.sqlform.sql_query;
1339 var myListBox = document.sqlform.dummy;
1341 if(myListBox.options.length > 0) {
1342 sql_box_locked = true;
1345 for(var i=0; i<myListBox.options.length; i++) {
1346 if (myListBox.options[i].selected){
1350 chaineAj += myListBox.options[i].value;
1355 if (document.selection) {
1357 sel = document.selection.createRange();
1358 sel.text = chaineAj;
1359 document.sqlform.insert.focus();
1361 //MOZILLA/NETSCAPE support
1362 else if (document.sqlform.sql_query.selectionStart || document.sqlform.sql_query.selectionStart == "0") {
1363 var startPos = document.sqlform.sql_query.selectionStart;
1364 var endPos = document.sqlform.sql_query.selectionEnd;
1365 var chaineSql = document.sqlform.sql_query.value;
1367 myQuery.value = chaineSql.substring(0, startPos) + chaineAj + chaineSql.substring(endPos, chaineSql.length);
1369 myQuery.value += chaineAj;
1371 sql_box_locked = false;
1376 * listbox redirection
1378 function goToUrl(selObj, goToLocation) {
1379 eval("document.location.href = '" + goToLocation + "pos=" + selObj.options[selObj.selectedIndex].value + "'");
1385 function getElement(e,f){
1386 if(document.layers){
1388 if(f.document.layers[e]) {
1389 return f.document.layers[e];
1391 for(W=0;W<f.document.layers.length;W++) {
1392 return(getElement(e,f.document.layers[W]));
1396 return document.all[e];
1398 return document.getElementById(e);
1402 * Refresh the WYSIWYG scratchboard after changes have been made
1404 function refreshDragOption(e) {
1405 var elm = $('#' + e);
1406 if (elm.css('visibility') == 'visible') {
1413 * Refresh/resize the WYSIWYG scratchboard
1415 function refreshLayout() {
1416 var elm = $('#pdflayout')
1417 var orientation = $('#orientation_opt').val();
1418 if($('#paper_opt').length==1){
1419 var paper = $('#paper_opt').val();
1423 if (orientation == 'P') {
1430 elm.css('width', pdfPaperSize(paper, posa) + 'px');
1431 elm.css('height', pdfPaperSize(paper, posb) + 'px');
1435 * Show/hide the WYSIWYG scratchboard
1437 function ToggleDragDrop(e) {
1438 var elm = $('#' + e);
1439 if (elm.css('visibility') == 'hidden') {
1440 PDFinit(); /* Defined in pdf_pages.php */
1441 elm.css('visibility', 'visible');
1442 elm.css('display', 'block');
1443 $('#showwysiwyg').val('1')
1445 elm.css('visibility', 'hidden');
1446 elm.css('display', 'none');
1447 $('#showwysiwyg').val('0')
1452 * PDF scratchboard: When a position is entered manually, update
1453 * the fields inside the scratchboard.
1455 function dragPlace(no, axis, value) {
1456 var elm = $('#table_' + no);
1458 elm.css('left', value + 'px');
1460 elm.css('top', value + 'px');
1465 * Returns paper sizes for a given format
1467 function pdfPaperSize(format, axis) {
1468 switch (format.toUpperCase()) {
1470 if (axis == 'x') return 4767.87; else return 6740.79;
1473 if (axis == 'x') return 3370.39; else return 4767.87;
1476 if (axis == 'x') return 2383.94; else return 3370.39;
1479 if (axis == 'x') return 1683.78; else return 2383.94;
1482 if (axis == 'x') return 1190.55; else return 1683.78;
1485 if (axis == 'x') return 841.89; else return 1190.55;
1488 if (axis == 'x') return 595.28; else return 841.89;
1491 if (axis == 'x') return 419.53; else return 595.28;
1494 if (axis == 'x') return 297.64; else return 419.53;
1497 if (axis == 'x') return 209.76; else return 297.64;
1500 if (axis == 'x') return 147.40; else return 209.76;
1503 if (axis == 'x') return 104.88; else return 147.40;
1506 if (axis == 'x') return 73.70; else return 104.88;
1509 if (axis == 'x') return 2834.65; else return 4008.19;
1512 if (axis == 'x') return 2004.09; else return 2834.65;
1515 if (axis == 'x') return 1417.32; else return 2004.09;
1518 if (axis == 'x') return 1000.63; else return 1417.32;
1521 if (axis == 'x') return 708.66; else return 1000.63;
1524 if (axis == 'x') return 498.90; else return 708.66;
1527 if (axis == 'x') return 354.33; else return 498.90;
1530 if (axis == 'x') return 249.45; else return 354.33;
1533 if (axis == 'x') return 175.75; else return 249.45;
1536 if (axis == 'x') return 124.72; else return 175.75;
1539 if (axis == 'x') return 87.87; else return 124.72;
1542 if (axis == 'x') return 2599.37; else return 3676.54;
1545 if (axis == 'x') return 1836.85; else return 2599.37;
1548 if (axis == 'x') return 1298.27; else return 1836.85;
1551 if (axis == 'x') return 918.43; else return 1298.27;
1554 if (axis == 'x') return 649.13; else return 918.43;
1557 if (axis == 'x') return 459.21; else return 649.13;
1560 if (axis == 'x') return 323.15; else return 459.21;
1563 if (axis == 'x') return 229.61; else return 323.15;
1566 if (axis == 'x') return 161.57; else return 229.61;
1569 if (axis == 'x') return 113.39; else return 161.57;
1572 if (axis == 'x') return 79.37; else return 113.39;
1575 if (axis == 'x') return 2437.80; else return 3458.27;
1578 if (axis == 'x') return 1729.13; else return 2437.80;
1581 if (axis == 'x') return 1218.90; else return 1729.13;
1584 if (axis == 'x') return 864.57; else return 1218.90;
1587 if (axis == 'x') return 609.45; else return 864.57;
1590 if (axis == 'x') return 2551.18; else return 3628.35;
1593 if (axis == 'x') return 1814.17; else return 2551.18;
1596 if (axis == 'x') return 1275.59; else return 1814.17;
1599 if (axis == 'x') return 907.09; else return 1275.59;
1602 if (axis == 'x') return 637.80; else return 907.09;
1605 if (axis == 'x') return 612.00; else return 792.00;
1608 if (axis == 'x') return 612.00; else return 1008.00;
1611 if (axis == 'x') return 521.86; else return 756.00;
1614 if (axis == 'x') return 612.00; else return 936.00;
1622 * for playing media from the BLOB repository
1625 * @param var url_params main purpose is to pass the token
1626 * @param var bs_ref BLOB repository reference
1627 * @param var m_type type of BLOB repository media
1628 * @param var w_width width of popup window
1629 * @param var w_height height of popup window
1631 function popupBSMedia(url_params, bs_ref, m_type, is_cust_type, w_width, w_height)
1633 // if width not specified, use default
1634 if (w_width == undefined)
1637 // if height not specified, use default
1638 if (w_height == undefined)
1641 // open popup window (for displaying video/playing audio)
1642 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');
1646 * popups a request for changing MIME types for files in the BLOB repository
1648 * @param var db database name
1649 * @param var table table name
1650 * @param var reference BLOB repository reference
1651 * @param var current_mime_type current MIME type associated with BLOB repository reference
1653 function requestMIMETypeChange(db, table, reference, current_mime_type)
1655 // no mime type specified, set to default (nothing)
1656 if (undefined == current_mime_type)
1657 current_mime_type = "";
1659 // prompt user for new mime type
1660 var new_mime_type = prompt("Enter custom MIME type", current_mime_type);
1662 // if new mime_type is specified and is not the same as the previous type, request for mime type change
1663 if (new_mime_type && new_mime_type != current_mime_type)
1664 changeMIMEType(db, table, reference, new_mime_type);
1668 * changes MIME types for files in the BLOB repository
1670 * @param var db database name
1671 * @param var table table name
1672 * @param var reference BLOB repository reference
1673 * @param var mime_type new MIME type to be associated with BLOB repository reference
1675 function changeMIMEType(db, table, reference, mime_type)
1677 // specify url and parameters for jQuery POST
1678 var mime_chg_url = 'bs_change_mime_type.php';
1679 var params = {bs_db: db, bs_table: table, bs_reference: reference, bs_new_mime_type: mime_type};
1682 jQuery.post(mime_chg_url, params);
1686 * Jquery Coding for inline editing SQL_QUERY
1688 $(document).ready(function(){
1689 var $oldText,$db,$table,$token,$sql_query;
1690 $oldText=$(".inner_sql").html();
1691 $("#inline_edit").click(function(){
1692 $db=$("input[name='db']").val();
1693 $table=$("input[name='table']").val();
1694 $token=$("input[name='token']").val();
1695 $sql_query=$("input[name='sql_query']").val();
1696 $(".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'] + "\">");
1700 $("#btnSave").live("click",function(){
1701 window.location.replace("import.php?db="+$db+"&table="+$table+"&sql_query="+$("#sql_query_edit").val()+"&show_query=1&token="+$token+"");
1704 $("#btnDiscard").live("click",function(){
1705 $(".sql").html("<span class=\"syntax\"><span class=\"inner_sql\">"+$oldText+"</span></span>");
1708 $('.sqlbutton').click(function(evt){
1709 insertQuery(evt.target.id);
1713 $("#export_type").change(function(){
1714 if($("#export_type").val()=='svg'){
1715 $("#show_grid_opt").attr("disabled","disabled");
1716 $("#orientation_opt").attr("disabled","disabled");
1717 $("#with_doc").attr("disabled","disabled");
1718 $("#show_table_dim_opt").removeAttr("disabled");
1719 $("#all_table_same_wide").removeAttr("disabled");
1720 $("#paper_opt").removeAttr("disabled","disabled");
1721 $("#show_color_opt").removeAttr("disabled","disabled");
1722 //$(this).css("background-color","yellow");
1723 }else if($("#export_type").val()=='dia'){
1724 $("#show_grid_opt").attr("disabled","disabled");
1725 $("#with_doc").attr("disabled","disabled");
1726 $("#show_table_dim_opt").attr("disabled","disabled");
1727 $("#all_table_same_wide").attr("disabled","disabled");
1728 $("#paper_opt").removeAttr("disabled","disabled");
1729 $("#show_color_opt").removeAttr("disabled","disabled");
1730 $("#orientation_opt").removeAttr("disabled","disabled");
1731 }else if($("#export_type").val()=='eps'){
1732 $("#show_grid_opt").attr("disabled","disabled");
1733 $("#orientation_opt").removeAttr("disabled");
1734 $("#with_doc").attr("disabled","disabled");
1735 $("#show_table_dim_opt").attr("disabled","disabled");
1736 $("#all_table_same_wide").attr("disabled","disabled");
1737 $("#paper_opt").attr("disabled","disabled");
1738 $("#show_color_opt").attr("disabled","disabled");
1740 }else if($("#export_type").val()=='pdf'){
1741 $("#show_grid_opt").removeAttr("disabled");
1742 $("#orientation_opt").removeAttr("disabled");
1743 $("#with_doc").removeAttr("disabled","disabled");
1744 $("#show_table_dim_opt").removeAttr("disabled","disabled");
1745 $("#all_table_same_wide").removeAttr("disabled","disabled");
1746 $("#paper_opt").removeAttr("disabled","disabled");
1747 $("#show_color_opt").removeAttr("disabled","disabled");
1753 $('#sqlquery').focus();
1754 if ($('#input_username')) {
1755 if ($('#input_username').val() == '') {
1756 $('#input_username').focus();
1758 $('#input_password').focus();
1764 * Function to process the plain HTML response from an Ajax request. Inserts
1765 * the various HTML divisions from the response at the proper locations. The
1766 * array relates the divisions to be inserted to their placeholders.
1768 * @param var divisions_map an associative array of id names
1771 * PMA_ajaxInsertResponse({'resultsTable':'resultsTable_response',
1772 * 'profilingData':'profilingData_response'});
1777 function PMA_ajaxInsertResponse(divisions_map) {
1778 $.each(divisions_map, function(key, value) {
1779 var content_div = '#'+value;
1780 var target_div = '#'+key;
1781 var content = $(content_div).html();
1783 //replace content of target_div with that from the response
1784 $(target_div).html(content);
1789 * Show a message on the top of the page for an Ajax request
1791 * @param var message string containing the message to be shown.
1792 * optional, defaults to 'Loading...'
1793 * @param var timeout number of milliseconds for the message to be visible
1794 * optional, defaults to 5000
1797 function PMA_ajaxShowMessage(message, timeout) {
1799 //Handle the case when a empty data.message is passed. We don't want the empty message
1805 * @var msg String containing the message that has to be displayed
1806 * @default PMA_messages['strLoading']
1809 var msg = PMA_messages['strLoading'];
1816 * @var timeout Number of milliseconds for which {@link msg} will be visible
1826 if( !ajax_message_init) {
1827 //For the first time this function is called, append a new div
1829 $('<div id="loading_parent"></div>')
1830 .insertBefore("#serverinfo");
1832 $('<span id="loading" class="ajax_notification"></span>')
1833 .appendTo("#loading_parent")
1835 .slideDown('medium')
1837 .slideUp('medium', function(){
1839 .html("") //Clear the message
1842 }, 'top.frame_content');
1843 ajax_message_init = true;
1846 //Otherwise, just show the div again after inserting the message
1850 .slideDown('medium')
1852 .slideUp('medium', function() {
1861 * Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected
1863 function toggle_enum_notice(selectElement) {
1864 var enum_notice_id = selectElement.attr("id").split("_")[1];
1865 enum_notice_id += "_" + (parseInt(selectElement.attr("id").split("_")[2]) + 1);
1866 var selectedType = selectElement.attr("value");
1867 if(selectedType == "ENUM" || selectedType == "SET") {
1868 $("p[id='enum_notice_" + enum_notice_id + "']").show();
1870 $("p[id='enum_notice_" + enum_notice_id + "']").hide();
1875 * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
1876 * return a jQuery object yet and hence cannot be chained
1878 * @param string question
1879 * @param string url URL to be passed to the callbackFn to make
1881 * @param function callbackFn callback to execute after user clicks on OK
1884 jQuery.fn.PMA_confirm = function(question, url, callbackFn) {
1885 if (PMA_messages['strDoYouReally'] == '') {
1890 * @var button_options Object that stores the options passed to jQueryUI
1893 var button_options = {};
1894 button_options[PMA_messages['strOK']] = function(){
1895 $(this).dialog("close").remove();
1897 if($.isFunction(callbackFn)) {
1898 callbackFn.call(this, url);
1901 button_options[PMA_messages['strCancel']] = function() {$(this).dialog("close").remove();}
1903 $('<div id="confirm_dialog"></div>')
1905 .dialog({buttons: button_options});
1909 * jQuery function to sort a table's body after a new row has been appended to it.
1910 * Also fixes the even/odd classes of the table rows at the end.
1912 * @param string text_selector string to select the sortKey's text
1914 * @return jQuery Object for chaining purposes
1916 jQuery.fn.PMA_sort_table = function(text_selector) {
1917 return this.each(function() {
1920 * @var table_body Object referring to the table's <tbody> element
1922 var table_body = $(this);
1924 * @var rows Object referring to the collection of rows in {@link table_body}
1926 var rows = $(this).find('tr').get();
1928 //get the text of the field that we will sort by
1929 $.each(rows, function(index, row) {
1930 row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase());
1933 //get the sorted order
1934 rows.sort(function(a,b) {
1935 if(a.sortKey < b.sortKey) {
1938 if(a.sortKey > b.sortKey) {
1944 //pull out each row from the table and then append it according to it's order
1945 $.each(rows, function(index, row) {
1946 $(table_body).append(row);
1950 //Re-check the classes of each row
1951 $(this).find('tr:odd')
1952 .removeClass('even').addClass('odd')
1955 .removeClass('odd').addClass('even');
1960 * jQuery coding for 'Create Table'. Used on db_operations.php,
1961 * db_structure.php and db_tracking.php (i.e., wherever
1962 * libraries/display_create_table.lib.php is used)
1964 * Attach Ajax Event handlers for Create Table
1966 $(document).ready(function() {
1969 * Attach event handler to the submit action of the create table minimal form
1970 * and retrieve the full table form and display it in a dialog
1972 * @uses PMA_ajaxShowMessage()
1974 $("#create_table_form_minimal").live('submit', function(event) {
1975 event.preventDefault();
1977 /* @todo Validate this form! */
1980 * @var button_options Object that stores the options passed to jQueryUI
1983 var button_options = {};
1984 button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
1986 PMA_ajaxShowMessage();
1987 $(this).append('<input type="hidden" name="ajax_request" value="true" />');
1989 $.get($(this).attr('action'), $(this).serialize(), function(data) {
1990 $('<div id="create_table_dialog"></div>')
1993 title: top.frame_content.PMA_messages['strCreateTable'],
1995 buttons : button_options
1996 }); // end dialog options
2002 * Attach event handler for submission of create table form
2004 * @uses PMA_ajaxShowMessage()
2005 * @uses $.PMA_sort_table()
2006 * @uses window.parent.refreshNavigation()
2008 $("#create_table_form").find("input[name=submit_num_fields], input[name=do_save_data]").live('click', function(event) {
2009 event.preventDefault();
2012 * @var the_form object referring to the create table form
2014 var the_form = $("#create_table_form");
2016 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2017 $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
2019 if($(this).attr('name') == 'submit_num_fields') {
2020 //User wants to add more fields to the table
2021 $.post($(the_form).attr('action'), $(the_form).serialize() + "&submit_num_fields=" + $(this).val(), function(data) {
2022 $("#create_table_dialog").html(data);
2025 else if($(this).attr('name') == 'do_save_data') {
2026 //User wants to submit the form
2027 $.post($(the_form).attr('action'), $(the_form).serialize() + "&do_save_data=" + $(this).val(), function(data) {
2028 if(data.success == true) {
2029 PMA_ajaxShowMessage(data.message);
2030 $("#create_table_dialog").dialog("close").remove();
2033 * @var tables_table Object referring to the <tbody> element that holds the list of tables
2035 var tables_table = $("#tablesForm").find("tbody").not("#tbl_summary_row");
2038 * @var curr_last_row Object referring to the last <tr> element in {@link tables_table}
2040 var curr_last_row = $(tables_table).find('tr:last');
2042 * @var curr_last_row_index_string String containing the index of {@link curr_last_row}
2044 var curr_last_row_index_string = $(curr_last_row).find('input:checkbox').attr('id').match(/\d+/)[0];
2046 * @var curr_last_row_index Index of {@link curr_last_row}
2048 var curr_last_row_index = parseFloat(curr_last_row_index_string);
2050 * @var new_last_row_index Index of the new row to be appended to {@link tables_table}
2052 var new_last_row_index = curr_last_row_index + 1;
2054 * @var new_last_row_id String containing the id of the row to be appended to {@link tables_table}
2056 var new_last_row_id = 'checkbox_tbl_' + new_last_row_index;
2059 $(data.new_table_string)
2060 .find('input:checkbox')
2061 .val(new_last_row_id)
2063 .appendTo(tables_table);
2066 $(tables_table).PMA_sort_table('th');
2068 //Refresh navigation frame as a new table has been added
2069 window.parent.refreshNavigation();
2072 PMA_ajaxShowMessage(data.error);
2076 }) // end create table form submit button actions
2078 }, 'top.frame_content'); //end $(document).ready for 'Create Table'
2081 * Attach event handlers for Empty Table and Drop Table. Used wherever libraries/
2082 * tbl_links.inc.php is used.
2084 $(document).ready(function() {
2087 * Attach Ajax event handlers for Empty Table
2089 * @uses PMA_ajaxShowMessage()
2090 * @uses $.PMA_confirm()
2092 $("#empty_table_anchor").live('click', function(event) {
2093 event.preventDefault();
2096 * @var question String containing the question to be asked for confirmation
2098 var question = 'TRUNCATE TABLE ' + window.parent.table;
2100 $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
2102 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2103 $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
2104 if(data.success == true) {
2105 PMA_ajaxShowMessage(data.message);
2106 $("#topmenucontainer")
2110 .after(data.sql_query);
2113 PMA_ajaxShowMessage(data.error);
2116 }) // end $.PMA_confirm()
2117 }) // end Empty Table
2120 * Attach Ajax event handler for Drop Table
2122 * @uses PMA_ajaxShowMessage()
2123 * @uses $.PMA_confirm()
2124 * @uses window.parent.refreshNavigation()
2126 $("#drop_table_anchor").live('click', function(event) {
2127 event.preventDefault();
2130 * @var question String containing the question to be asked for confirmation
2132 var question = 'DROP TABLE/VIEW ' + window.parent.table;
2133 $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
2135 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2136 $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
2137 if(data.success == true) {
2138 PMA_ajaxShowMessage(data.message);
2139 $("#topmenucontainer")
2143 .after(data.sql_query);
2144 window.parent.table = '';
2145 window.parent.refreshNavigation();
2148 PMA_ajaxShowMessage(data.error);
2151 }) // end $.PMA_confirm()
2152 }) // end $().live()
2153 }, 'top.frame_content'); //end $(document).ready() for libraries/tbl_links.inc.php
2156 * Attach Ajax event handlers for Drop Trigger. Used on tbl_structure.php
2158 $(document).ready(function() {
2160 $(".drop_trigger_anchor").live('click', function(event) {
2161 event.preventDefault();
2164 * @var curr_row Object reference to the current trigger's <tr>
2166 var curr_row = $(this).parents('tr');
2168 * @var question String containing the question to be asked for confirmation
2170 var question = 'DROP TRIGGER IF EXISTS `' + $(curr_row).children('td:first').text() + '`';
2172 $(this).PMA_confirm(question, $(this).attr('href'), function(url) {
2174 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2175 $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) {
2176 if(data.success == true) {
2177 PMA_ajaxShowMessage(data.message);
2178 $("#topmenucontainer")
2182 .after(data.sql_query);
2183 $(curr_row).hide("medium").remove();
2186 PMA_ajaxShowMessage(data.error);
2189 }) // end $.PMA_confirm()
2190 }) // end $().live()
2191 }, 'top.frame_content'); //end $(document).ready() for Drop Trigger
2194 * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js
2195 * as it was also required on db_create.php
2197 * @uses $.PMA_confirm()
2198 * @uses PMA_ajaxShowMessage()
2199 * @uses window.parent.refreshNavigation()
2200 * @uses window.parent.refreshMain()
2202 $(document).ready(function() {
2203 $("#drop_db_anchor").live('click', function(event) {
2204 event.preventDefault();
2206 //context is top.frame_content, so we need to use window.parent.db to access the db var
2208 * @var question String containing the question to be asked for confirmation
2210 var question = PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP DATABASE ' + window.parent.db;
2212 $(this).PMA_confirm(question, $(this).attr('href') ,function(url) {
2214 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2215 $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) {
2216 //Database deleted successfully, refresh both the frames
2217 window.parent.refreshNavigation();
2218 window.parent.refreshMain();
2220 }); // end $.PMA_confirm()
2221 }); //end of Drop Database Ajax action
2222 }) // end of $(document).ready() for Drop Database
2225 * Attach Ajax event handlers for 'Create Database'. Used wherever libraries/
2226 * display_create_database.lib.php is used, ie main.php and server_databases.php
2228 * @uses PMA_ajaxShowMessage()
2230 $(document).ready(function() {
2232 $('#create_database_form').live('submit', function(event) {
2233 event.preventDefault();
2235 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2236 $(this).append('<input type="hidden" name="ajax_request" value="true" />');
2238 $.post($(this).attr('action'), $(this).serialize(), function(data) {
2239 if(data.success == true) {
2240 PMA_ajaxShowMessage(data.message);
2242 //Append database's row to table
2243 $("#tabledatabases")
2245 .append(data.new_db_string)
2246 .PMA_sort_table('.name')
2247 .find('#db_summary_row')
2248 .appendTo('#tabledatabases tbody')
2249 .removeClass('odd even');
2252 PMA_ajaxShowMessage(data.error);
2255 }) // end $().live()
2256 }) // end $(document).ready() for Create Database
2259 * Attach Ajax event handlers for 'Change Password' on main.php
2261 $(document).ready(function() {
2264 * Attach Ajax event handler on the change password anchor
2266 $('#change_password_anchor').live('click', function(event) {
2267 event.preventDefault();
2270 * @var button_options Object containing options to be passed to jQueryUI's dialog
2272 var button_options = {};
2274 button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();}
2276 $.get($(this).attr('href'), {'ajax_request': true}, function(data) {
2277 $('<div id="change_password_dialog></div>')
2279 title: top.frame_content.PMA_messages['strChangePassword'],
2281 buttons : button_options
2285 }) // end handler for change password anchor
2288 * Attach Ajax event handler for Change Password form submission
2290 * @uses PMA_ajaxShowMessage()
2292 $("#change_password_form").find('input[name=change_pw]').live('click', function(event) {
2293 event.preventDefault();
2296 * @var the_form Object referring to the change password form
2298 var the_form = $("#change_password_form");
2301 * @var this_value String containing the value of the submit button.
2302 * Need to append this for the change password form on Server Privileges
2305 var this_value = $(this).val();
2307 PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']);
2308 $(the_form).append('<input type="hidden" name="ajax_request" value="true" />');
2310 $.post($(the_form).attr('action'), $(the_form).serialize() + '&change_pw='+ this_value, function(data) {
2311 if(data.success == true) {
2313 PMA_ajaxShowMessage(data.message);
2315 $("#topmenucontainer").after(data.sql_query);
2317 $("#change_password_dialog").hide().remove();
2318 $("#edit_user_dialog").dialog("close").remove();
2321 PMA_ajaxShowMessage(data.error);
2324 }) // end handler for Change Password form submission
2325 }) // end $(document).ready() for Change Password
2328 * Toggle the hiding/showing of the "Open in ENUM/SET editor" message when
2329 * the page loads and when the selected data type changes
2331 $(document).ready(function() {
2332 $.each($("select[class='column_type']"), function() {
2333 toggle_enum_notice($(this));
2335 $("select[class='column_type']").change(function() {
2336 toggle_enum_notice($(this));
2341 * Closes the ENUM/SET editor and removes the data in it
2343 function disable_popup() {
2344 $("#popup_background").fadeOut("fast");
2345 $("#enum_editor").fadeOut("fast");
2346 // clear the data from the text boxes
2347 $("#enum_editor #values input").remove();
2348 $("#enum_editor input[type='hidden']").remove();
2352 * Opens the ENUM/SET editor and controls its functions
2354 $(document).ready(function() {
2355 $("a[class='open_enum_editor']").click(function() {
2357 var windowWidth = document.documentElement.clientWidth;
2358 var windowHeight = document.documentElement.clientHeight;
2359 var popupWidth = windowWidth/2;
2360 var popupHeight = windowHeight*0.8;
2361 var popupOffsetTop = windowHeight/2 - popupHeight/2;
2362 var popupOffsetLeft = windowWidth/2 - popupWidth/2;
2363 $("#enum_editor").css({"position":"absolute", "top": popupOffsetTop, "left": popupOffsetLeft, "width": popupWidth, "height": popupHeight});
2366 $("#popup_background").css({"opacity":"0.7"});
2367 $("#popup_background").fadeIn("fast");
2368 $("#enum_editor").fadeIn("fast");
2371 var values = $(this).parent().prev("input").attr("value").split(",");
2372 $.each(values, function(index, val) {
2373 if(jQuery.trim(val) != "") {
2374 // enclose the string in single quotes if it's not already
2375 if(val.substr(0, 1) != "'") {
2378 if(val.substr(val.length-1, val.length) != "'") {
2381 // escape the single quotes, except the mandatory ones enclosing the entire string
2382 val = val.substr(1, val.length-2).replace(/''/g, "'").replace(/\\\\/g, '\\').replace(/\\'/g, "'").replace(/'/g, "'");
2383 // escape the greater-than symbol
2384 val = val.replace(/>/g, ">");
2385 $("#enum_editor #values").append("<input type='text' value=" + val + " />");
2388 // So we know which column's data is being edited
2389 $("#enum_editor").append("<input type='hidden' value='" + $(this).parent().prev("input").attr("id") + "' />");
2393 // If the "close" link is clicked, close the enum editor
2394 $("a[class='close_enum_editor']").click(function() {
2398 // If the "cancel" link is clicked, close the enum editor
2399 $("a[class='cancel_enum_editor']").click(function() {
2403 // When "add a new value" is clicked, append an empty text field
2404 $("a[class='add_value']").click(function() {
2405 $("#enum_editor #values").append("<input type='text' />");
2408 // When the submit button is clicked, put the data back into the original form
2409 $("#enum_editor input[type='submit']").click(function() {
2410 var value_array = new Array();
2411 $.each($("#enum_editor #values input"), function(index, input_element) {
2412 val = jQuery.trim(input_element.value);
2414 value_array.push("'" + val.replace(/\\/g, '\\\\').replace(/'/g, "''") + "'");
2417 // get the Length/Values text field where this value belongs
2418 var values_id = $("#enum_editor input[type='hidden']").attr("value");
2419 $("input[id='" + values_id + "']").attr("value", value_array.join(","));
2424 * Hides certain table structure actions, replacing them with the word "More". They are displayed
2425 * in a dropdown menu when the user hovers over the word "More."
2427 // Remove the actions from the table cells (they are available by default for JavaScript-disabled browsers)
2428 // if the table is not a view or information_schema (otherwise there is only one action to hide and there's no point)
2429 if($("input[type='hidden'][name='table_type']").attr("value") == "table") {
2430 $("table[id='tablestructure'] td[class='browse']").remove();
2431 $("table[id='tablestructure'] td[class='primary']").remove();
2432 $("table[id='tablestructure'] td[class='unique']").remove();
2433 $("table[id='tablestructure'] td[class='index']").remove();
2434 $("table[id='tablestructure'] td[class='fulltext']").remove();
2435 $("table[id='tablestructure'] th[class='action']").attr("colspan", 3);
2437 // Display the "more" text
2438 $("table[id='tablestructure'] td[class='more_opts']").show()
2440 // Position the dropdown
2441 $.each($(".structure_actions_dropdown"), function() {
2442 // The top offset must be set for IE even if it didn't change
2443 var cell_right_edge_offset = $(this).parent().offset().left + $(this).parent().innerWidth();
2444 var left_offset = cell_right_edge_offset - $(this).innerWidth();
2445 var top_offset = $(this).parent().offset().top + $(this).parent().innerHeight();
2446 $(this).offset({ top: top_offset, left: left_offset });
2449 // A hack for IE6 to prevent the after_field select element from being displayed on top of the dropdown by
2450 // positioning an iframe directly on top of it
2451 $("iframe[class='IE_hack']").width($("select[name='after_field']").width());
2452 $("iframe[class='IE_hack']").height($("select[name='after_field']").height());
2453 $("iframe[class='IE_hack']").offset({ top: $("select[name='after_field']").offset().top, left: $("select[name='after_field']").offset().left });
2455 // When "more" is hovered over, show the hidden actions
2456 $("table[id='tablestructure'] td[class='more_opts']").mouseenter(
2458 if($.browser.msie && $.browser.version == "6.0") {
2459 $("iframe[class='IE_hack']").show();
2460 $("iframe[class='IE_hack']").width($("select[name='after_field']").width()+4);
2461 $("iframe[class='IE_hack']").height($("select[name='after_field']").height()+4);
2462 $("iframe[class='IE_hack']").offset({ top: $("select[name='after_field']").offset().top, left: $("select[name='after_field']").offset().left});
2464 $(".structure_actions_dropdown").hide(); // Hide all the other ones that may be open
2465 $(this).children(".structure_actions_dropdown").show();
2466 // Need to do this again for IE otherwise the offset is wrong
2467 if($.browser.msie) {
2468 var left_offset_IE = $(this).offset().left + $(this).innerWidth() - $(this).children(".structure_actions_dropdown").innerWidth();
2469 var top_offset_IE = $(this).offset().top + $(this).innerHeight();
2470 $(this).children(".structure_actions_dropdown").offset({ top: top_offset_IE, left: left_offset_IE });
2473 $(".structure_actions_dropdown").mouseleave(function() {
2475 if($.browser.msie && $.browser.version == "6.0") {
2476 $("iframe[class='IE_hack']").hide();
2482 /* Displays tooltips */
2483 $(document).ready(function() {
2484 // Hide the footnotes from the footer (which are displayed for
2485 // JavaScript-disabled browsers) since the tooltip is sufficient
2486 $(".footnotes").hide();
2487 $(".footnotes span").each(function() {
2488 $(this).children("sup").remove();
2490 // The border and padding must be removed otherwise a thin yellow box remains visible
2491 $(".footnotes").css("border", "none");
2492 $(".footnotes").css("padding", "0px");
2494 // Replace the superscripts with the help icon
2495 $("sup[class='footnotemarker']").hide();
2496 $("img[class='footnotemarker']").show();
2498 $("img[class='footnotemarker']").each(function() {
2499 var span_id = $(this).attr("id");
2500 span_id = span_id.split("_")[1];
2501 var tooltip_text = $(".footnotes span[id='footnote_" + span_id + "']").html();
2503 content: tooltip_text,
2505 hide: { when: 'unfocus', delay: 0 },
2506 style: { background: '#ffffcc' }
2511 function menuResize()
2513 var cnt = $('#topmenu');
2514 var wmax = cnt.width() - 5; // 5 px margin for jumping menu in Chrome
2515 var submenu = cnt.find('.submenu');
2516 var submenu_w = submenu.outerWidth(true);
2517 var submenu_ul = submenu.find('ul');
2518 var li = cnt.find('> li');
2519 var li2 = submenu_ul.find('li');
2520 var more_shown = li2.length > 0;
2521 var w = more_shown ? submenu_w : 0;
2525 for (var i = 0; i < li.length-1; i++) { // li.length-1: skip .submenu element
2527 var el_width = el.outerWidth(true);
2528 el.data('width', el_width);
2532 if (w + submenu_w < wmax) {
2536 w -= $(li[i-1]).data('width');
2542 if (hide_start > 0) {
2543 for (var i = hide_start; i < li.length-1; i++) {
2544 $(li[i])[more_shown ? 'prependTo' : 'appendTo'](submenu_ul);
2547 } else if (more_shown) {
2549 // nothing hidden, maybe something can be restored
2550 for (var i = 0; i < li2.length; i++) {
2551 //console.log(li2[i], submenu_w);
2552 w += $(li2[i]).data('width');
2553 // item fits or (it is the last item and it would fit if More got removed)
2554 if (w+submenu_w < wmax || (i == li2.length-1 && w < wmax)) {
2555 $(li2[i]).insertBefore(submenu);
2556 if (i == li2.length-1) {
2564 if (submenu.find('.tabactive').length) {
2565 submenu.addClass('active').find('> a').removeClass('tab').addClass('tabactive');
2567 submenu.removeClass('active').find('> a').addClass('tab').removeClass('tabactive');
2572 var topmenu = $('#topmenu');
2573 if (topmenu.length == 0) {
2576 // create submenu container
2577 var link = $('<a />', {href: '#', 'class': 'tab'})
2578 .text(PMA_messages['strMore'])
2579 .click(function(e) {
2582 var img = topmenu.find('li:first-child img');
2584 img.clone().attr('src', img.attr('src').replace(/\/[^\/]+$/, '/b_more.png')).prependTo(link);
2586 var submenu = $('<li />', {'class': 'submenu'})
2588 .append($('<ul />'))
2589 .mouseenter(function() {
2590 if ($(this).find('ul .tabactive').length == 0) {
2591 $(this).addClass('submenuhover').find('> a').addClass('tabactive');
2594 .mouseleave(function() {
2595 if ($(this).find('ul .tabactive').length == 0) {
2596 $(this).removeClass('submenuhover').find('> a').removeClass('tabactive');
2600 topmenu.append(submenu);
2602 // populate submenu and register resize event
2603 $(window).resize(menuResize);