/* 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; /** * Add a hidden field to the form to indicate that this will be an * Ajax request (only if this hidden field does not exist) * * @param object the form */ function PMA_prepareForAjaxRequest($form) { if (! $form.find('input:hidden').is('#ajax_request_hidden')) { $form.append(''); } } /** * 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(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 = 'error'; } 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 submitting 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 /** * Check if a form's element is empty. * An element containing only spaces is also considered empty * * @param object the form * @param string the name of the form field to put the focus on * * @return boolean whether the form field is empty or not */ function emptyCheckTheField(theForm, theFieldName) { var isEmpty = 1; var theField = theForm.elements[theFieldName]; // Whether the replace function (js1.2) is supported or not var isRegExp = (typeof(theField.value.replace) != 'undefined'); if (!isRegExp) { isEmpty = (theField.value == '') ? 1 : 0; } else { var space_re = new RegExp('\\s+'); isEmpty = (theField.value.replace(space_re, '') == '') ? 1 : 0; } return isEmpty; } // end of the 'emptyCheckTheField()' function /** * Check whether a form field is empty or not * * @param object the form * @param string the name of the form field to put the focus on * * @return boolean whether the form field is empty or not */ function emptyFormElements(theForm, theFieldName) { var theField = theForm.elements[theFieldName]; var isEmpty = emptyCheckTheField(theForm, theFieldName); return isEmpty; } // end of the 'emptyFormElements()' function /** * Ensures a value submitted in a form is numeric and is in a range * * @param object the form * @param string the name of the form field to check * @param integer the minimum authorized value * @param integer the maximum authorized value * * @return boolean whether a valid number has been submitted or not */ function checkFormElementInRange(theForm, theFieldName, message, min, max) { var theField = theForm.elements[theFieldName]; var val = parseInt(theField.value); if (typeof(min) == 'undefined') { min = 0; } if (typeof(max) == 'undefined') { max = Number.MAX_VALUE; } // It's not a number if (isNaN(val)) { theField.select(); alert(PMA_messages['strNotNumber']); theField.focus(); return false; } // It's a number but it is not between min and max else if (val < min || val > 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 (label and checkbox), so we need to handle this differently var $tr = $(this); var $checkbox = $tr.find(':checkbox'); if ($checkbox.length) { // checkbox in a row, add or remove class depending on checkbox state var checked = $checkbox.attr('checked'); if (!$(e.target).is(':checkbox, label')) { checked = !checked; $checkbox.attr('checked', checked); } if (checked) { $tr.addClass('marked'); } else { $tr.removeClass('marked'); } } else { // normaln data table, just toggle class $tr.toggleClass('marked'); } }); /** * Add a date/time picker to each element that needs it */ $('.datefield, .datetimefield').each(function() { PMA_addDatepicker($(this)); }); }) /** * Row highlighting in horizontal mode (use "live" * so that it works also for pages reached via AJAX) */ $(document).ready(function() { $('tr.odd, tr.even').live('hover',function() { var $tr = $(this); $tr.toggleClass('hover'); $tr.children().toggleClass('hover'); }); }) /** * This array is used to remember mark status of rows in browse mode */ var marked_row = new Array; /** * marks all rows and selects its first checkbox inside the given element * the given element is usaly a table or a div containing the table or tables * * @param container DOM element */ function markAllRows( container_id ) { $("#"+container_id).find("input:checkbox:enabled").attr('checked', 'checked') .parents("tr").addClass("marked"); return true; } /** * marks all rows and selects its first checkbox inside the given element * the given element is usaly a table or a div containing the table or tables * * @param container DOM element */ function unMarkAllRows( container_id ) { $("#"+container_id).find("input:checkbox:enabled").removeAttr('checked') .parents("tr").removeClass("marked"); return true; } /** * Checks/unchecks all checkbox in given conainer (f.e. a form, fieldset or div) * * @param string container_id the container id * @param boolean state new value for checkbox (true or false) * @return boolean always true */ function setCheckboxes( container_id, state ) { if(state) { $("#"+container_id).find("input:checkbox").attr('checked', 'checked'); } else { $("#"+container_id).find("input:checkbox").removeAttr('checked'); } return true; } // end of the 'setCheckboxes()' function /** * Checks/unchecks all options of a \n"; new_content += "\n"; $inner_sql.replaceWith(new_content); $(".btnSave").each(function(){ $(this).click(function(){ sql_query = $(this).prev().val(); window.location.replace("import.php" + "?server=" + encodeURIComponent(server) + "&db=" + encodeURIComponent(db) + "&table=" + encodeURIComponent(table) + "&sql_query=" + encodeURIComponent(sql_query) + "&show_query=1" + "&token=" + token); }); }); $(".btnDiscard").each(function(){ $(this).click(function(){ $(this).closest(".sql").html("" + old_text + ""); }); }); return false; }); $('.sqlbutton').click(function(evt){ if (evt.target.id == 'clear') { $('#sqlquery').val(''); } else { 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) .fadeIn('medium') .delay(to) .fadeOut('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") .stop(true, true) .html(msg) .fadeIn('medium') .delay(to) .fadeOut('medium', function() { $(this) .html("") .hide(); }) } return $("#loading"); } /** * Removes the message shown for an Ajax operation when it's completed */ function PMA_ajaxRemoveMessage($this_msgbox) { $this_msgbox .stop(true, true) .fadeOut('medium', function() { $this_msgbox.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();} var $msgbox = PMA_ajaxShowMessage(); PMA_prepareForAjaxRequest($form); $.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 } PMA_ajaxRemoveMessage($msgbox); }) // 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']); PMA_prepareForAjaxRequest($form); //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"); var $msgbox = PMA_ajaxShowMessage(PMA_messages['strProcessingRequest']); PMA_prepareForAjaxRequest($form); //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(); PMA_ajaxRemoveMessage($msgbox); }) //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 ' + escapeHtml(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']); PMA_prepareForAjaxRequest($form); $.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(); var $msgbox = 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'); PMA_ajaxRemoveMessage($msgbox); } 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 as a string var inputstring = $(this) .parent() .prev("input") .val(); // Escape html entities inputstring = $('
') .text(inputstring) .html(); // Parse the values, escaping quotes and // slashes on the fly, into an array var values = []; var in_string = false; var curr, next, buffer = ''; for (var i=0; i 0) { values.push(buffer); } // Add the parsed values to the editor for (var i=0; i" ); } // 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(); }); }); /* 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: { delay: 1000 }, 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($('