/* vim: set expandtab sw=4 ts=4 sts=4: */ /** * general function, usally for data manipulation pages * */ /** * @var sql_box_locked lock for the sqlbox textarea in the querybox/querywindow */ var sql_box_locked = false; /** * @var array holds elements which content should only selected once */ var only_once_elements = new Array(); /** * @var ajax_message_init boolean boolean that stores status of * notification for PMA_ajaxShowNotification */ var ajax_message_init = false; /** * Generate a new password and copy it to the password input areas * * @param object the form that holds the password fields * * @return boolean always true */ function suggestPassword(passwd_form) { // restrict the password to just letters and numbers to avoid problems: // "editors and viewers regard the password as multiple words and // things like double click no longer work" var pwchars = "abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ"; var passwordlength = 16; // do we want that to be dynamic? no, keep it simple :) var passwd = passwd_form.generated_pw; passwd.value = ''; for ( i = 0; i < passwordlength; i++ ) { passwd.value += pwchars.charAt( Math.floor( Math.random() * pwchars.length ) ) } passwd_form.text_pma_pw.value = passwd.value; passwd_form.text_pma_pw2.value = passwd.value; return true; } /** * Version string to integer conversion. */ function parseVersionString (str) { if (typeof(str) != 'string') { return false; } var add = 0; // Parse possible alpha/beta/rc/ var state = str.split('-'); if (state.length >= 2) { if (state[1].substr(0, 2) == 'rc') { add = - 20 - parseInt(state[1].substr(2)); } else if (state[1].substr(0, 4) == 'beta') { add = - 40 - parseInt(state[1].substr(4)); } else if (state[1].substr(0, 5) == 'alpha') { add = - 60 - parseInt(state[1].substr(5)); } else if (state[1].substr(0, 3) == 'dev') { /* We don't handle dev, it's git snapshot */ add = 0; } } // Parse version var x = str.split('.'); // Use 0 for non existing parts var maj = parseInt(x[0]) || 0; var min = parseInt(x[1]) || 0; var pat = parseInt(x[2]) || 0; var hotfix = parseInt(x[3]) || 0; return maj * 100000000 + min * 1000000 + pat * 10000 + hotfix * 100 + add; } /** * Indicates current available version on main page. */ function PMA_current_version() { var current = parseVersionString('3.4.0'/*pmaversion*/); var latest = parseVersionString(PMA_latest_version); $('#li_pma_version').append(PMA_messages['strLatestAvailable'] + ' ' + PMA_latest_version); if (latest > current) { var message = $.sprintf(PMA_messages['strNewerVersion'], PMA_latest_version, PMA_latest_date); if (Math.floor(latest / 10000) == Math.floor(current / 10000)) { /* Security update */ klass = 'warning'; } else { klass = 'notice'; } $('#maincontainer').after('
' + message + '
'); } } /** * for libraries/display_change_password.lib.php * libraries/user_password.php * */ function displayPasswordGenerateButton() { $('#tr_element_before_generate_password').parent().append('' + PMA_messages['strGeneratePassword'] + ''); $('#div_element_before_generate_password').parent().append('
'); } /* * Adds a date/time picker to an element * * @param object $this_element a jQuery object pointing to the element */ function PMA_addDatepicker($this_element) { var showTimeOption = false; if ($this_element.is('.datetimefield')) { showTimeOption = true; } $this_element .datepicker({ showOn: 'button', buttonImage: themeCalendarImage, // defined in js/messages.php buttonImageOnly: true, duration: '', time24h: true, stepMinutes: 1, stepHours: 1, showTime: showTimeOption, dateFormat: 'yy-mm-dd', // yy means year with four digits altTimeField: '', beforeShow: function(input, inst) { // Remember that we came from the datepicker; this is used // in tbl_change.js by verificationsAfterFieldChange() $this_element.data('comes_from', 'datepicker'); }, constrainInput: false }); } /** * selects the content of a given object, f.e. a textarea * * @param object element element of which the content will be selected * @param var lock variable which holds the lock for this element * or true, if no lock exists * @param boolean only_once if true this is only done once * f.e. only on first focus */ function selectContent( element, lock, only_once ) { if ( only_once && only_once_elements[element.name] ) { return; } only_once_elements[element.name] = true; if ( lock ) { return; } element.select(); } /** * Displays a confirmation box before to submit a "DROP/DELETE/ALTER" query. * This function is called while clicking links * * @param object the link * @param object the sql query to submit * * @return boolean whether to run the query or not */ function confirmLink(theLink, theSqlQuery) { // Confirmation is not required in the configuration file // or browser is Opera (crappy js implementation) if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') { return true; } var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery); if (is_confirmed) { if ( typeof(theLink.href) != 'undefined' ) { theLink.href += '&is_js_confirmed=1'; } else if ( typeof(theLink.form) != 'undefined' ) { theLink.form.action += '?is_js_confirmed=1'; } } return is_confirmed; } // end of the 'confirmLink()' function /** * Displays a confirmation box before doing some action * * @param object the message to display * * @return boolean whether to run the query or not * * @todo used only by libraries/display_tbl.lib.php. figure out how it is used * and replace with a jQuery equivalent */ function confirmAction(theMessage) { // TODO: Confirmation is not required in the configuration file // or browser is Opera (crappy js implementation) if (typeof(window.opera) != 'undefined') { return true; } var is_confirmed = confirm(theMessage); return is_confirmed; } // end of the 'confirmAction()' function /** * Displays an error message if a "DROP DATABASE" statement is submitted * while it isn't allowed, else confirms a "DROP/DELETE/ALTER" query before * sumitting it if required. * This function is called by the 'checkSqlQuery()' js function. * * @param object the form * @param object the sql query textarea * * @return boolean whether to run the query or not * * @see checkSqlQuery() */ function confirmQuery(theForm1, sqlQuery1) { // Confirmation is not required in the configuration file if (PMA_messages['strDoYouReally'] == '') { return true; } // The replace function (js1.2) isn't supported else if (typeof(sqlQuery1.value.replace) == 'undefined') { return true; } // js1.2+ -> validation with regular expressions else { // "DROP DATABASE" statement isn't allowed if (PMA_messages['strNoDropDatabases'] != '') { var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i'); if (drop_re.test(sqlQuery1.value)) { alert(PMA_messages['strNoDropDatabases']); theForm1.reset(); sqlQuery1.focus(); return false; } // end if } // end if // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement // // TODO: find a way (if possible) to use the parser-analyser // for this kind of verification // For now, I just added a ^ to check for the statement at // beginning of expression var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i'); var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i'); var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i'); var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i'); if (do_confirm_re_0.test(sqlQuery1.value) || do_confirm_re_1.test(sqlQuery1.value) || do_confirm_re_2.test(sqlQuery1.value) || do_confirm_re_3.test(sqlQuery1.value)) { var message = (sqlQuery1.value.length > 100) ? sqlQuery1.value.substr(0, 100) + '\n ...' : sqlQuery1.value; var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message); // statement is confirmed -> update the // "is_js_confirmed" form field so the confirm test won't be // run on the server side and allows to submit the form if (is_confirmed) { theForm1.elements['is_js_confirmed'].value = 1; return true; } // statement is rejected -> do not submit the form else { window.focus(); sqlQuery1.focus(); return false; } // end if (handle confirm box result) } // end if (display confirm box) } // end confirmation stuff return true; } // end of the 'confirmQuery()' function /** * Displays a confirmation box before disabling the BLOB repository for a given database. * This function is called while clicking links * * @param object the database * * @return boolean whether to disable the repository or not */ function confirmDisableRepository(theDB) { // Confirmation is not required in the configuration file // or browser is Opera (crappy js implementation) if (PMA_messages['strDoYouReally'] == '' || typeof(window.opera) != 'undefined') { return true; } var is_confirmed = confirm(PMA_messages['strBLOBRepositoryDisableStrongWarning'] + '\n' + PMA_messages['strBLOBRepositoryDisableAreYouSure']); return is_confirmed; } // end of the 'confirmDisableBLOBRepository()' function /** * Displays an error message if the user submitted the sql query form with no * sql query, else checks for "DROP/DELETE/ALTER" statements * * @param object the form * * @return boolean always false * * @see confirmQuery() */ function checkSqlQuery(theForm) { var sqlQuery = theForm.elements['sql_query']; var isEmpty = 1; // The replace function (js1.2) isn't supported -> basic tests if (typeof(sqlQuery.value.replace) == 'undefined') { isEmpty = (sqlQuery.value == '') ? 1 : 0; if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') { isEmpty = (theForm.elements['sql_file'].value == '') ? 1 : 0; } if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') { isEmpty = (theForm.elements['sql_localfile'].value == '') ? 1 : 0; } if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') { isEmpty = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == ''); } } // js1.2+ -> validation with regular expressions else { var space_re = new RegExp('\\s+'); if (typeof(theForm.elements['sql_file']) != 'undefined' && theForm.elements['sql_file'].value.replace(space_re, '') != '') { return true; } if (typeof(theForm.elements['sql_localfile']) != 'undefined' && theForm.elements['sql_localfile'].value.replace(space_re, '') != '') { return true; } if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' && (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') && theForm.elements['id_bookmark'].selectedIndex != 0 ) { return true; } // Checks for "DROP/DELETE/ALTER" statements if (sqlQuery.value.replace(space_re, '') != '') { if (confirmQuery(theForm, sqlQuery)) { return true; } else { return false; } } theForm.reset(); isEmpty = 1; } if (isEmpty) { sqlQuery.select(); alert(PMA_messages['strFormEmpty']); sqlQuery.focus(); return false; } return true; } // end of the 'checkSqlQuery()' function // Global variable row_class is set to even var row_class = 'even'; /** * Generates a row dynamically in the differences table displaying * the complete statistics of difference in table like number of * rows to be updated, number of rows to be inserted, number of * columns to be added, number of columns to be removed, etc. * * @param index index of matching table * @param update_size number of rows/column to be updated * @param insert_size number of rows/coulmns to be inserted * @param remove_size number of columns to be removed * @param insert_index number of indexes to be inserted * @param remove_index number of indexes to be removed * @param img_obj image object * @param table_name name of the table */ function showDetails(i, update_size, insert_size, remove_size, insert_index, remove_index, img_obj, table_name) { // a jQuery object var $img = $(img_obj); $img.toggleClass('selected'); // The image source is changed when the showDetails function is called. if ($img.hasClass('selected')) { if ($img.hasClass('struct_img')) { $img.attr('src', pmaThemeImage + 'new_struct_selected.jpg'); } if ($img.hasClass('data_img')) { $img.attr('src', pmaThemeImage + 'new_data_selected.jpg'); } } else { if ($img.hasClass('struct_img')) { $img.attr('src', pmaThemeImage + 'new_struct.jpg'); } if ($img.hasClass('data_img')) { $img.attr('src', pmaThemeImage + 'new_data.jpg'); } } var div = document.getElementById("list"); var table = div.getElementsByTagName("table")[0]; var table_body = table.getElementsByTagName("tbody")[0]; //Global variable row_class is being used if (row_class == 'even') { row_class = 'odd'; } else { row_class = 'even'; } // 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. if ($img.hasClass('selected')) { var newRow = document.createElement("tr"); newRow.setAttribute("class", row_class); newRow.className = row_class; // Id assigned to this row element is same as the index of this table name in the matching_tables/source_tables_uncommon array newRow.setAttribute("id" , i); var table_name_cell = document.createElement("td"); table_name_cell.align = "center"; table_name_cell.innerHTML = table_name ; newRow.appendChild(table_name_cell); var create_table = document.createElement("td"); create_table.align = "center"; var add_cols = document.createElement("td"); add_cols.align = "center"; var remove_cols = document.createElement("td"); remove_cols.align = "center"; var alter_cols = document.createElement("td"); alter_cols.align = "center"; var add_index = document.createElement("td"); add_index.align = "center"; var delete_index = document.createElement("td"); delete_index.align = "center"; var update_rows = document.createElement("td"); update_rows.align = "center"; var insert_rows = document.createElement("td"); insert_rows.align = "center"; var tick_image = document.createElement("img"); tick_image.src = pmaThemeImage + "s_success.png"; if (update_size == '' && insert_size == '' && remove_size == '') { /** This is the case when the table needs to be created in target database. */ create_table.appendChild(tick_image); add_cols.innerHTML = "--"; remove_cols.innerHTML = "--"; alter_cols.innerHTML = "--"; delete_index.innerHTML = "--"; add_index.innerHTML = "--"; update_rows.innerHTML = "--"; insert_rows.innerHTML = "--"; newRow.appendChild(create_table); newRow.appendChild(add_cols); newRow.appendChild(remove_cols); newRow.appendChild(alter_cols); newRow.appendChild(delete_index); newRow.appendChild(add_index); newRow.appendChild(update_rows); newRow.appendChild(insert_rows); } else if (update_size == '' && remove_size == '') { /** This is the case when data difference is displayed in the table which is present in source but absent from target database */ create_table.innerHTML = "--"; add_cols.innerHTML = "--"; remove_cols.innerHTML = "--"; alter_cols.innerHTML = "--"; add_index.innerHTML = "--"; delete_index.innerHTML = "--"; update_rows.innerHTML = "--"; insert_rows.innerHTML = insert_size; newRow.appendChild(create_table); newRow.appendChild(add_cols); newRow.appendChild(remove_cols); newRow.appendChild(alter_cols); newRow.appendChild(delete_index); newRow.appendChild(add_index); newRow.appendChild(update_rows); newRow.appendChild(insert_rows); } else if (remove_size == '') { /** This is the case when data difference between matching_tables is displayed. */ create_table.innerHTML = "--"; add_cols.innerHTML = "--"; remove_cols.innerHTML = "--"; alter_cols.innerHTML = "--"; add_index.innerHTML = "--"; delete_index.innerHTML = "--"; update_rows.innerHTML = update_size; insert_rows.innerHTML = insert_size; newRow.appendChild(create_table); newRow.appendChild(add_cols); newRow.appendChild(remove_cols); newRow.appendChild(alter_cols); newRow.appendChild(delete_index); newRow.appendChild(add_index); newRow.appendChild(update_rows); newRow.appendChild(insert_rows); } else { /** This is the case when structure difference between matching_tables id displayed */ create_table.innerHTML = "--"; add_cols.innerHTML = insert_size; remove_cols.innerHTML = remove_size; alter_cols.innerHTML = update_size; delete_index.innerHTML = remove_index; add_index.innerHTML = insert_index; update_rows.innerHTML = "--"; insert_rows.innerHTML = "--"; newRow.appendChild(create_table); newRow.appendChild(add_cols); newRow.appendChild(remove_cols); newRow.appendChild(alter_cols); newRow.appendChild(delete_index); newRow.appendChild(add_index); newRow.appendChild(update_rows); newRow.appendChild(insert_rows); } table_body.appendChild(newRow); } else { //The case when the row showing the details need to be removed from the table i.e. the difference button is deselected now. var table_rows = table_body.getElementsByTagName("tr"); var j; var index = 0; for (j=0; j < table_rows.length; j++) { if (table_rows[j].id == i) { index = j; table_rows[j].parentNode.removeChild(table_rows[j]); } } //The table row css is being adjusted. Class "odd" for odd rows and "even" for even rows should be maintained. for(index = 0; index < table_rows.length; index++) { row_class_element = table_rows[index].getAttribute('class'); if (row_class_element == "even") { table_rows[index].setAttribute("class","odd"); // for Mozilla firefox table_rows[index].className = "odd"; // for IE browser } else { table_rows[index].setAttribute("class","even"); // for Mozilla firefox table_rows[index].className = "even"; // for IE browser } } } } /** * Generates the URL containing the list of selected table ids for synchronization and * a variable checked for confirmation of deleting previous rows from target tables * * @param token the token generated for each PMA form * */ function ApplySelectedChanges(token) { var div = document.getElementById("list"); var table = div.getElementsByTagName('table')[0]; var table_body = table.getElementsByTagName('tbody')[0]; // Get all the rows from the details table var table_rows = table_body.getElementsByTagName('tr'); var x = table_rows.length; var i; /** Append the token at the beginning of the query string followed by Table_ids that shows that "Apply Selected Changes" button is pressed */ var append_string = "?token="+token+"&Table_ids="+1; for(i=0; i max) { theField.select(); alert(message.replace('%d', val)); theField.focus(); return false; } // It's a valid number else { theField.value = val; } return true; } // end of the 'checkFormElementInRange()' function function checkTableEditForm(theForm, fieldsCnt) { // TODO: avoid sending a message if user just wants to add a line // on the form but has not completed at least one field name var atLeastOneField = 0; var i, elm, elm2, elm3, val, id; for (i=0; i element * * @param string the form name * @param string the element name * @param boolean whether to check or to uncheck the element * * @return boolean always true */ function setSelectOptions(the_form, the_select, do_check) { if( do_check ) { $("form[name='"+ the_form +"']").find("select[name='"+the_select+"']").find("option").attr('selected', 'selected'); } else { $("form[name='"+ the_form +"']").find("select[name="+the_select+"]").find("option").removeAttr('selected'); } return true; } // end of the 'setSelectOptions()' function /** * Create quick sql statements. * */ function insertQuery(queryType) { var myQuery = document.sqlform.sql_query; var myListBox = document.sqlform.dummy; var query = ""; var table = document.sqlform.table.value; if (myListBox.options.length > 0) { sql_box_locked = true; var chaineAj = ""; var valDis = ""; var editDis = ""; var NbSelect = 0; for (var i=0; i < myListBox.options.length; i++) { NbSelect++; if (NbSelect > 1) { chaineAj += ", "; valDis += ","; editDis += ","; } chaineAj += myListBox.options[i].value; valDis += "[value-" + NbSelect + "]"; editDis += myListBox.options[i].value + "=[value-" + NbSelect + "]"; } if (queryType == "selectall") { query = "SELECT * FROM `" + table + "` WHERE 1"; } else if (queryType == "select") { query = "SELECT " + chaineAj + " FROM `" + table + "` WHERE 1"; } else if (queryType == "insert") { query = "INSERT INTO `" + table + "`(" + chaineAj + ") VALUES (" + valDis + ")"; } else if (queryType == "update") { query = "UPDATE `" + table + "` SET " + editDis + " WHERE 1"; } else if(queryType == "delete") { query = "DELETE FROM `" + table + "` WHERE 1"; } else if(queryType == "clear") { query = ''; } document.sqlform.sql_query.value = query; sql_box_locked = false; } } /** * Inserts multiple fields. * */ function insertValueQuery() { var myQuery = document.sqlform.sql_query; var myListBox = document.sqlform.dummy; if(myListBox.options.length > 0) { sql_box_locked = true; var chaineAj = ""; var NbSelect = 0; for(var i=0; i 1) chaineAj += ", "; chaineAj += myListBox.options[i].value; } } //IE support if (document.selection) { myQuery.focus(); sel = document.selection.createRange(); sel.text = chaineAj; document.sqlform.insert.focus(); } //MOZILLA/NETSCAPE support else if (document.sqlform.sql_query.selectionStart || document.sqlform.sql_query.selectionStart == "0") { var startPos = document.sqlform.sql_query.selectionStart; var endPos = document.sqlform.sql_query.selectionEnd; var chaineSql = document.sqlform.sql_query.value; myQuery.value = chaineSql.substring(0, startPos) + chaineAj + chaineSql.substring(endPos, chaineSql.length); } else { myQuery.value += chaineAj; } sql_box_locked = false; } } /** * listbox redirection */ function goToUrl(selObj, goToLocation) { eval("document.location.href = '" + goToLocation + "pos=" + selObj.options[selObj.selectedIndex].value + "'"); } /** * getElement */ function getElement(e,f){ if(document.layers){ f=(f)?f:self; if(f.document.layers[e]) { return f.document.layers[e]; } for(W=0;W"+ sql_query +""); return false; }); $("#btnSave").live("click",function(){ window.location.replace("import.php?db=" + db +"&table=" + table + "&sql_query=" + $("#sql_query_edit").val()+"&show_query=1&token=" + token + ""); }); $("#btnDiscard").live("click",function(){ $(".sql").html("" + oldText + ""); }); $('.sqlbutton').click(function(evt){ insertQuery(evt.target.id); return false; }); $("#export_type").change(function(){ if($("#export_type").val()=='svg'){ $("#show_grid_opt").attr("disabled","disabled"); $("#orientation_opt").attr("disabled","disabled"); $("#with_doc").attr("disabled","disabled"); $("#show_table_dim_opt").removeAttr("disabled"); $("#all_table_same_wide").removeAttr("disabled"); $("#paper_opt").removeAttr("disabled","disabled"); $("#show_color_opt").removeAttr("disabled","disabled"); //$(this).css("background-color","yellow"); }else if($("#export_type").val()=='dia'){ $("#show_grid_opt").attr("disabled","disabled"); $("#with_doc").attr("disabled","disabled"); $("#show_table_dim_opt").attr("disabled","disabled"); $("#all_table_same_wide").attr("disabled","disabled"); $("#paper_opt").removeAttr("disabled","disabled"); $("#show_color_opt").removeAttr("disabled","disabled"); $("#orientation_opt").removeAttr("disabled","disabled"); }else if($("#export_type").val()=='eps'){ $("#show_grid_opt").attr("disabled","disabled"); $("#orientation_opt").removeAttr("disabled"); $("#with_doc").attr("disabled","disabled"); $("#show_table_dim_opt").attr("disabled","disabled"); $("#all_table_same_wide").attr("disabled","disabled"); $("#paper_opt").attr("disabled","disabled"); $("#show_color_opt").attr("disabled","disabled"); }else if($("#export_type").val()=='pdf'){ $("#show_grid_opt").removeAttr("disabled"); $("#orientation_opt").removeAttr("disabled"); $("#with_doc").removeAttr("disabled","disabled"); $("#show_table_dim_opt").removeAttr("disabled","disabled"); $("#all_table_same_wide").removeAttr("disabled","disabled"); $("#paper_opt").removeAttr("disabled","disabled"); $("#show_color_opt").removeAttr("disabled","disabled"); }else{ // nothing } }); $('#sqlquery').focus(); if ($('#input_username')) { if ($('#input_username').val() == '') { $('#input_username').focus(); } else { $('#input_password').focus(); } } }); /** * Show a message on the top of the page for an Ajax request * * @param var message string containing the message to be shown. * optional, defaults to 'Loading...' * @param var timeout number of milliseconds for the message to be visible * optional, defaults to 5000 */ function PMA_ajaxShowMessage(message, timeout) { //Handle the case when a empty data.message is passed. We don't want the empty message if(message == '') { return true; } /** * @var msg String containing the message that has to be displayed * @default PMA_messages['strLoading'] */ if(!message) { var msg = PMA_messages['strLoading']; } else { var msg = message; } /** * @var timeout Number of milliseconds for which {@link msg} will be visible * @default 5000 ms */ if(!timeout) { var to = 5000; } else { var to = timeout; } if( !ajax_message_init) { //For the first time this function is called, append a new div $(function(){ $('
') .insertBefore("#serverinfo"); $('') .appendTo("#loading_parent") .html(msg) .slideDown('medium') .delay(to) .slideUp('medium', function(){ $(this) .html("") //Clear the message .hide(); }); }, 'top.frame_content'); ajax_message_init = true; } else { //Otherwise, just show the div again after inserting the message $("#loading") .clearQueue() .html(msg) .slideDown('medium') .delay(to) .slideUp('medium', function() { $(this) .html("") .hide(); }) } } /** * Hides/shows the "Open in ENUM/SET editor" message, depending on the data type of the column currently selected */ function PMA_showNoticeForEnum(selectElement) { var enum_notice_id = selectElement.attr("id").split("_")[1]; enum_notice_id += "_" + (parseInt(selectElement.attr("id").split("_")[2]) + 1); var selectedType = selectElement.attr("value"); if (selectedType == "ENUM" || selectedType == "SET") { $("p[id='enum_notice_" + enum_notice_id + "']").show(); } else { $("p[id='enum_notice_" + enum_notice_id + "']").hide(); } } /** * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not * return a jQuery object yet and hence cannot be chained * * @param string question * @param string url URL to be passed to the callbackFn to make * an Ajax call to * @param function callbackFn callback to execute after user clicks on OK */ jQuery.fn.PMA_confirm = function(question, url, callbackFn) { if (PMA_messages['strDoYouReally'] == '') { return true; } /** * @var button_options Object that stores the options passed to jQueryUI * dialog */ var button_options = {}; button_options[PMA_messages['strOK']] = function(){ $(this).dialog("close").remove(); if($.isFunction(callbackFn)) { callbackFn.call(this, url); } }; button_options[PMA_messages['strCancel']] = function() {$(this).dialog("close").remove();} $('
') .prepend(question) .dialog({buttons: button_options}); }; /** * jQuery function to sort a table's body after a new row has been appended to it. * Also fixes the even/odd classes of the table rows at the end. * * @param string text_selector string to select the sortKey's text * * @return jQuery Object for chaining purposes */ jQuery.fn.PMA_sort_table = function(text_selector) { return this.each(function() { /** * @var table_body Object referring to the table's element */ var table_body = $(this); /** * @var rows Object referring to the collection of rows in {@link table_body} */ var rows = $(this).find('tr').get(); //get the text of the field that we will sort by $.each(rows, function(index, row) { row.sortKey = $.trim($(row).find(text_selector).text().toLowerCase()); }) //get the sorted order rows.sort(function(a,b) { if(a.sortKey < b.sortKey) { return -1; } if(a.sortKey > b.sortKey) { return 1; } return 0; }) //pull out each row from the table and then append it according to it's order $.each(rows, function(index, row) { $(table_body).append(row); row.sortKey = null; }) //Re-check the classes of each row $(this).find('tr:odd') .removeClass('even').addClass('odd') .end() .find('tr:even') .removeClass('odd').addClass('even'); }) } /** * jQuery coding for 'Create Table'. Used on db_operations.php, * db_structure.php and db_tracking.php (i.e., wherever * libraries/display_create_table.lib.php is used) * * Attach Ajax Event handlers for Create Table */ $(document).ready(function() { /** * Attach event handler to the submit action of the create table minimal form * and retrieve the full table form and display it in a dialog * * @uses PMA_ajaxShowMessage() */ $("#create_table_form_minimal.ajax").live('submit', function(event) { event.preventDefault(); $form = $(this); /* @todo Validate this form! */ /** * @var button_options Object that stores the options passed to jQueryUI * dialog */ var button_options = {}; // in the following function we need to use $(this) button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();} var button_options_error = {}; button_options_error[PMA_messages['strOK']] = function() {$(this).dialog('close').remove();} PMA_ajaxShowMessage(); if (! $form.find('input:hidden').is('#ajax_request_hidden')) { $form.append(''); } $.get($form.attr('action'), $form.serialize(), function(data) { //in the case of an error, show the error message returned. if (data.success != undefined && data.success == false) { $('
') .append(data.error) .dialog({ title: PMA_messages['strCreateTable'], height: 230, width: 900, open: PMA_verifyTypeOfAllColumns, buttons : button_options_error })// end dialog options //remove the redundant [Back] link in the error message. .find('fieldset').remove(); } else { $('
') .append(data) .dialog({ title: PMA_messages['strCreateTable'], height: 600, width: 900, open: PMA_verifyTypeOfAllColumns, buttons : button_options }); // end dialog options } }) // end $.get() // empty table name and number of columns from the minimal form $form.find('input[name=table],input[name=num_fields]').val(''); }); /** * Attach event handler for submission of create table form (save) * * @uses PMA_ajaxShowMessage() * @uses $.PMA_sort_table() * */ // .live() must be called after a selector, see http://api.jquery.com/live $("#create_table_form input[name=do_save_data]").live('click', function(event) { event.preventDefault(); /** * @var the_form object referring to the create table form */ var $form = $("#create_table_form"); /* * First validate the form; if there is a problem, avoid submitting it * * checkTableEditForm() needs a pure element and not a jQuery object, * this is why we pass $form[0] as a parameter (the jQuery object * is actually an array of DOM elements) */ if (checkTableEditForm($form[0], $form.find('input[name=orig_num_fields]').val())) { // OK, form passed validation step if ($form.hasClass('ajax')) { PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); if (! $form.find('input:hidden').is('#ajax_request_hidden')) { $form.append(''); } //User wants to submit the form $.post($form.attr('action'), $form.serialize() + "&do_save_data=" + $(this).val(), function(data) { if(data.success == true) { $('#properties_message') .removeClass('error') .html(''); PMA_ajaxShowMessage(data.message); // Only if the create table dialog (distinct panel) exists if ($("#create_table_dialog").length > 0) { $("#create_table_dialog").dialog("close").remove(); } /** * @var tables_table Object referring to the element that holds the list of tables */ var tables_table = $("#tablesForm").find("tbody").not("#tbl_summary_row"); // this is the first table created in this db if (tables_table.length == 0) { if (window.parent && window.parent.frame_content) { window.parent.frame_content.location.reload(); } } else { /** * @var curr_last_row Object referring to the last element in {@link tables_table} */ var curr_last_row = $(tables_table).find('tr:last'); /** * @var curr_last_row_index_string String containing the index of {@link curr_last_row} */ var curr_last_row_index_string = $(curr_last_row).find('input:checkbox').attr('id').match(/\d+/)[0]; /** * @var curr_last_row_index Index of {@link curr_last_row} */ var curr_last_row_index = parseFloat(curr_last_row_index_string); /** * @var new_last_row_index Index of the new row to be appended to {@link tables_table} */ var new_last_row_index = curr_last_row_index + 1; /** * @var new_last_row_id String containing the id of the row to be appended to {@link tables_table} */ var new_last_row_id = 'checkbox_tbl_' + new_last_row_index; data.new_table_string = data.new_table_string.replace(/checkbox_tbl_/, new_last_row_id); //append to table $(data.new_table_string) .appendTo(tables_table); //Sort the table $(tables_table).PMA_sort_table('th'); } //Refresh navigation frame as a new table has been added if (window.parent && window.parent.frame_navigation) { window.parent.frame_navigation.location.reload(); } } else { $('#properties_message') .addClass('error') .html(data.error); // scroll to the div containing the error message $('#properties_message')[0].scrollIntoView(); } }) // end $.post() } // end if ($form.hasClass('ajax') else { // non-Ajax submit $form.append(''); $form.submit(); } } // end if (checkTableEditForm() ) }) // end create table form (save) /** * Attach event handler for create table form (add fields) * * @uses PMA_ajaxShowMessage() * @uses $.PMA_sort_table() * @uses window.parent.refreshNavigation() * */ // .live() must be called after a selector, see http://api.jquery.com/live $("#create_table_form.ajax input[name=submit_num_fields]").live('click', function(event) { event.preventDefault(); /** * @var the_form object referring to the create table form */ var $form = $("#create_table_form"); PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); if (! $form.find('input:hidden').is('#ajax_request_hidden')) { $form.append(''); } //User wants to add more fields to the table $.post($form.attr('action'), $form.serialize() + "&submit_num_fields=" + $(this).val(), function(data) { // if 'create_table_dialog' exists if ($("#create_table_dialog").length > 0) { $("#create_table_dialog").html(data); } // if 'create_table_div' exists if ($("#create_table_div").length > 0) { $("#create_table_div").html(data); } PMA_verifyTypeOfAllColumns(); }) //end $.post() }) // end create table form (add fields) }, 'top.frame_content'); //end $(document).ready for 'Create Table' /** * Attach Ajax event handlers for Drop Trigger. Used on tbl_structure.php * @see $cfg['AjaxEnable'] */ $(document).ready(function() { $(".drop_trigger_anchor").live('click', function(event) { event.preventDefault(); $anchor = $(this); /** * @var curr_row Object reference to the current trigger's */ var $curr_row = $anchor.parents('tr'); /** * @var question String containing the question to be asked for confirmation */ var question = 'DROP TRIGGER IF EXISTS `' + $curr_row.children('td:first').text() + '`'; $anchor.PMA_confirm(question, $anchor.attr('href'), function(url) { PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); $.get(url, {'is_js_confirmed': 1, 'ajax_request': true}, function(data) { if(data.success == true) { PMA_ajaxShowMessage(data.message); $("#topmenucontainer") .next('div') .remove() .end() .after(data.sql_query); $curr_row.hide("medium").remove(); } else { PMA_ajaxShowMessage(data.error); } }) // end $.get() }) // end $.PMA_confirm() }) // end $().live() }, 'top.frame_content'); //end $(document).ready() for Drop Trigger /** * Attach Ajax event handlers for Drop Database. Moved here from db_structure.js * as it was also required on db_create.php * * @uses $.PMA_confirm() * @uses PMA_ajaxShowMessage() * @uses window.parent.refreshNavigation() * @uses window.parent.refreshMain() * @see $cfg['AjaxEnable'] */ $(document).ready(function() { $("#drop_db_anchor").live('click', function(event) { event.preventDefault(); //context is top.frame_content, so we need to use window.parent.db to access the db var /** * @var question String containing the question to be asked for confirmation */ var question = PMA_messages['strDropDatabaseStrongWarning'] + '\n' + PMA_messages['strDoYouReally'] + ' :\n' + 'DROP DATABASE ' + window.parent.db; $(this).PMA_confirm(question, $(this).attr('href') ,function(url) { PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); $.get(url, {'is_js_confirmed': '1', 'ajax_request': true}, function(data) { //Database deleted successfully, refresh both the frames window.parent.refreshNavigation(); window.parent.refreshMain(); }) // end $.get() }); // end $.PMA_confirm() }); //end of Drop Database Ajax action }) // end of $(document).ready() for Drop Database /** * Attach Ajax event handlers for 'Create Database'. Used wherever libraries/ * display_create_database.lib.php is used, ie main.php and server_databases.php * * @uses PMA_ajaxShowMessage() * @see $cfg['AjaxEnable'] */ $(document).ready(function() { $('#create_database_form.ajax').live('submit', function(event) { event.preventDefault(); $form = $(this); PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); if (! $form.find('input:hidden').is('#ajax_request_hidden')) { $form.append(''); } $.post($form.attr('action'), $form.serialize(), function(data) { if(data.success == true) { PMA_ajaxShowMessage(data.message); //Append database's row to table $("#tabledatabases") .find('tbody') .append(data.new_db_string) .PMA_sort_table('.name') .find('#db_summary_row') .appendTo('#tabledatabases tbody') .removeClass('odd even'); var $databases_count_object = $('#databases_count'); var databases_count = parseInt($databases_count_object.text()); $databases_count_object.text(++databases_count); //Refresh navigation frame as a new database has been added if (window.parent && window.parent.frame_navigation) { window.parent.frame_navigation.location.reload(); } } else { PMA_ajaxShowMessage(data.error); } }) // end $.post() }) // end $().live() }) // end $(document).ready() for Create Database /** * Attach Ajax event handlers for 'Change Password' on main.php */ $(document).ready(function() { /** * Attach Ajax event handler on the change password anchor * @see $cfg['AjaxEnable'] */ $('#change_password_anchor.dialog_active').live('click',function(event) { event.preventDefault(); return false; }); $('#change_password_anchor.ajax').live('click', function(event) { event.preventDefault(); $(this).removeClass('ajax').addClass('dialog_active'); /** * @var button_options Object containing options to be passed to jQueryUI's dialog */ var button_options = {}; button_options[PMA_messages['strCancel']] = function() {$(this).dialog('close').remove();} $.get($(this).attr('href'), {'ajax_request': true}, function(data) { $('
') .dialog({ title: PMA_messages['strChangePassword'], width: 600, close: function(ev,ui) {$(this).remove();}, buttons : button_options, beforeClose: function(ev,ui){ $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax')} }) .append(data); displayPasswordGenerateButton(); }) // end $.get() }) // end handler for change password anchor /** * Attach Ajax event handler for Change Password form submission * * @uses PMA_ajaxShowMessage() * @see $cfg['AjaxEnable'] */ $("#change_password_form.ajax").find('input[name=change_pw]').live('click', function(event) { event.preventDefault(); /** * @var the_form Object referring to the change password form */ var the_form = $("#change_password_form"); /** * @var this_value String containing the value of the submit button. * Need to append this for the change password form on Server Privileges * page to work */ var this_value = $(this).val(); PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); $(the_form).append(''); $.post($(the_form).attr('action'), $(the_form).serialize() + '&change_pw='+ this_value, function(data) { if(data.success == true) { $("#topmenucontainer").after(data.sql_query); $("#change_password_dialog").hide().remove(); $("#edit_user_dialog").dialog("close").remove(); $('#change_password_anchor.dialog_active').removeClass('dialog_active').addClass('ajax'); } else { PMA_ajaxShowMessage(data.error); } }) // end $.post() }) // end handler for Change Password form submission }) // end $(document).ready() for Change Password /** * Toggle the hiding/showing of the "Open in ENUM/SET editor" message when * the page loads and when the selected data type changes */ $(document).ready(function() { // is called here for normal page loads and also when opening // the Create table dialog PMA_verifyTypeOfAllColumns(); // // needs live() to work also in the Create Table dialog $("select[class='column_type']").live('change', function() { PMA_showNoticeForEnum($(this)); }); }); function PMA_verifyTypeOfAllColumns() { $("select[class='column_type']").each(function() { PMA_showNoticeForEnum($(this)); }); } /** * Closes the ENUM/SET editor and removes the data in it */ function disable_popup() { $("#popup_background").fadeOut("fast"); $("#enum_editor").fadeOut("fast"); // clear the data from the text boxes $("#enum_editor #values input").remove(); $("#enum_editor input[type='hidden']").remove(); } /** * Opens the ENUM/SET editor and controls its functions */ $(document).ready(function() { // Needs live() to work also in the Create table dialog $("a[class='open_enum_editor']").live('click', function() { // Center the popup var windowWidth = document.documentElement.clientWidth; var windowHeight = document.documentElement.clientHeight; var popupWidth = windowWidth/2; var popupHeight = windowHeight*0.8; var popupOffsetTop = windowHeight/2 - popupHeight/2; var popupOffsetLeft = windowWidth/2 - popupWidth/2; $("#enum_editor").css({"position":"absolute", "top": popupOffsetTop, "left": popupOffsetLeft, "width": popupWidth, "height": popupHeight}); // Make it appear $("#popup_background").css({"opacity":"0.7"}); $("#popup_background").fadeIn("fast"); $("#enum_editor").fadeIn("fast"); // Get the values var values = $(this).parent().prev("input").attr("value").split(","); $.each(values, function(index, val) { if(jQuery.trim(val) != "") { // enclose the string in single quotes if it's not already if(val.substr(0, 1) != "'") { val = "'" + val; } if(val.substr(val.length-1, val.length) != "'") { val = val + "'"; } // escape the single quotes, except the mandatory ones enclosing the entire string val = val.substr(1, val.length-2).replace(/''/g, "'").replace(/\\\\/g, '\\').replace(/\\'/g, "'").replace(/'/g, "'"); // escape the greater-than symbol val = val.replace(/>/g, ">"); $("#enum_editor #values").append(""); } }); // So we know which column's data is being edited $("#enum_editor").append(""); return false; }); // If the "close" link is clicked, close the enum editor // Needs live() to work also in the Create table dialog $("a[class='close_enum_editor']").live('click', function() { disable_popup(); }); // If the "cancel" link is clicked, close the enum editor // Needs live() to work also in the Create table dialog $("a[class='cancel_enum_editor']").live('click', function() { disable_popup(); }); // When "add a new value" is clicked, append an empty text field // Needs live() to work also in the Create table dialog $("a[class='add_value']").live('click', function() { $("#enum_editor #values").append(""); }); // When the submit button is clicked, put the data back into the original form // Needs live() to work also in the Create table dialog $("#enum_editor input[type='submit']").live('click', function() { var value_array = new Array(); $.each($("#enum_editor #values input"), function(index, input_element) { val = jQuery.trim(input_element.value); if(val != "") { value_array.push("'" + val.replace(/\\/g, '\\\\').replace(/'/g, "''") + "'"); } }); // get the Length/Values text field where this value belongs var values_id = $("#enum_editor input[type='hidden']").attr("value"); $("input[id='" + values_id + "']").attr("value", value_array.join(",")); disable_popup(); }); /** * Hides certain table structure actions, replacing them with the word "More". They are displayed * in a dropdown menu when the user hovers over the word "More." */ // Remove the actions from the table cells (they are available by default for JavaScript-disabled browsers) // if the table is not a view or information_schema (otherwise there is only one action to hide and there's no point) if($("input[type='hidden'][name='table_type']").val() == "table") { var $table = $("table[id='tablestructure']"); $table.find("td[class='browse']").remove(); $table.find("td[class='primary']").remove(); $table.find("td[class='unique']").remove(); $table.find("td[class='index']").remove(); $table.find("td[class='fulltext']").remove(); $table.find("th[class='action']").attr("colspan", 3); // Display the "more" text $table.find("td[class='more_opts']").show(); // Position the dropdown $(".structure_actions_dropdown").each(function() { // Optimize DOM querying var $this_dropdown = $(this); // The top offset must be set for IE even if it didn't change var cell_right_edge_offset = $this_dropdown.parent().offset().left + $this_dropdown.parent().innerWidth(); var left_offset = cell_right_edge_offset - $this_dropdown.innerWidth(); var top_offset = $this_dropdown.parent().offset().top + $this_dropdown.parent().innerHeight(); $this_dropdown.offset({ top: top_offset, left: left_offset }); }); // A hack for IE6 to prevent the after_field select element from being displayed on top of the dropdown by // positioning an iframe directly on top of it var $after_field = $("select[name='after_field']"); $("iframe[class='IE_hack']") .width($after_field.width()) .height($after_field.height()) .offset({ top: $after_field.offset().top, left: $after_field.offset().left }); // When "more" is hovered over, show the hidden actions $table.find("td[class='more_opts']") .mouseenter(function() { if($.browser.msie && $.browser.version == "6.0") { $("iframe[class='IE_hack']") .show() .width($after_field.width()+4) .height($after_field.height()+4) .offset({ top: $after_field.offset().top, left: $after_field.offset().left }); } $(".structure_actions_dropdown").hide(); // Hide all the other ones that may be open $(this).children(".structure_actions_dropdown").show(); // Need to do this again for IE otherwise the offset is wrong if($.browser.msie) { var left_offset_IE = $(this).offset().left + $(this).innerWidth() - $(this).children(".structure_actions_dropdown").innerWidth(); var top_offset_IE = $(this).offset().top + $(this).innerHeight(); $(this).children(".structure_actions_dropdown").offset({ top: top_offset_IE, left: left_offset_IE }); } }) .mouseleave(function() { $(this).children(".structure_actions_dropdown").hide(); if($.browser.msie && $.browser.version == "6.0") { $("iframe[class='IE_hack']").hide(); } }); } }); /* Displays tooltips */ $(document).ready(function() { // Hide the footnotes from the footer (which are displayed for // JavaScript-disabled browsers) since the tooltip is sufficient $(".footnotes").hide(); $(".footnotes span").each(function() { $(this).children("sup").remove(); }); // The border and padding must be removed otherwise a thin yellow box remains visible $(".footnotes").css("border", "none"); $(".footnotes").css("padding", "0px"); // Replace the superscripts with the help icon $("sup[class='footnotemarker']").hide(); $("img[class='footnotemarker']").show(); $("img[class='footnotemarker']").each(function() { var span_id = $(this).attr("id"); span_id = span_id.split("_")[1]; var tooltip_text = $(".footnotes span[id='footnote_" + span_id + "']").html(); $(this).qtip({ content: tooltip_text, show: { delay: 0 }, hide: { when: 'unfocus', delay: 0 }, style: { background: '#ffffcc' } }); }); }); function menuResize() { var cnt = $('#topmenu'); var wmax = cnt.innerWidth() - 5; // 5 px margin for jumping menu in Chrome var submenu = cnt.find('.submenu'); var submenu_w = submenu.outerWidth(true); var submenu_ul = submenu.find('ul'); var li = cnt.find('> li'); var li2 = submenu_ul.find('li'); var more_shown = li2.length > 0; var w = more_shown ? submenu_w : 0; // hide menu items var hide_start = 0; for (var i = 0; i < li.length-1; i++) { // li.length-1: skip .submenu element var el = $(li[i]); var el_width = el.outerWidth(true); el.data('width', el_width); w += el_width; if (w > wmax) { w -= el_width; if (w + submenu_w < wmax) { hide_start = i; } else { hide_start = i-1; w -= $(li[i-1]).data('width'); } break; } } if (hide_start > 0) { for (var i = hide_start; i < li.length-1; i++) { $(li[i])[more_shown ? 'prependTo' : 'appendTo'](submenu_ul); } submenu.addClass('shown'); } else if (more_shown) { w -= submenu_w; // nothing hidden, maybe something can be restored for (var i = 0; i < li2.length; i++) { //console.log(li2[i], submenu_w); w += $(li2[i]).data('width'); // item fits or (it is the last item and it would fit if More got removed) if (w+submenu_w < wmax || (i == li2.length-1 && w < wmax)) { $(li2[i]).insertBefore(submenu); if (i == li2.length-1) { submenu.removeClass('shown'); } continue; } break; } } if (submenu.find('.tabactive').length) { submenu.addClass('active').find('> a').removeClass('tab').addClass('tabactive'); } else { submenu.removeClass('active').find('> a').addClass('tab').removeClass('tabactive'); } } $(function() { var topmenu = $('#topmenu'); if (topmenu.length == 0) { return; } // create submenu container var link = $('', {href: '#', 'class': 'tab'}) .text(PMA_messages['strMore']) .click(function(e) { e.preventDefault(); }); var img = topmenu.find('li:first-child img'); if (img.length) { img.clone().attr('src', img.attr('src').replace(/\/[^\/]+$/, '/b_more.png')).prependTo(link); } var submenu = $('
  • ', {'class': 'submenu'}) .append(link) .append($('