')
.text(data.columnName)
.appendTo(elem);
$('
')
.text(data.columnHint)
.appendTo(elem);
};
$.ajax({
type: 'POST',
url: href,
data: params,
success: function (data) {
if (data.success) {
var tables = $.parseJSON(data.tables);
sql_autocomplete_default_table = PMA_commonParams.get('table');
sql_autocomplete = [];
for (var table in tables) {
if (tables.hasOwnProperty(table)) {
var columns = tables[table];
table = {
text: table,
columns: []
};
for (var column in columns) {
if (columns.hasOwnProperty(column)) {
var displayText = columns[column].Type;
if (columns[column].Key == 'PRI') {
displayText += ' | Primary';
} else if (columns[column].Key == 'UNI') {
displayText += ' | Unique';
}
table.columns.push({
text: column,
displayText: column + " | " + displayText,
columnName: column,
columnHint: displayText,
render: columnHintRender
});
}
}
}
sql_autocomplete.push(table);
}
instance.options.hintOptions.tables = sql_autocomplete;
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
}
},
complete: function () {
sql_autocomplete_in_progress = false;
}
});
}
else {
instance.options.hintOptions.tables = sql_autocomplete;
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
}
}
if (instance.state.completionActive) {
return;
}
var cur = instance.getCursor();
var token = instance.getTokenAt(cur);
var string = '';
if (token.string.match(/^[.`\w@]\w*$/)) {
string = token.string;
}
if (string.length > 0) {
CodeMirror.commands.autocomplete(instance);
}
}
/**
* Remove autocomplete information before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
sql_autocomplete = false;
sql_autocomplete_default_table = '';
});
/**
* Binds the CodeMirror to the text area used to inline edit a query.
*/
function bindCodeMirrorToInlineEditor() {
var $inline_editor = $('#sql_query_edit');
if ($inline_editor.length > 0) {
if (typeof CodeMirror !== 'undefined') {
var height = $inline_editor.css('height');
codemirror_inline_editor = PMA_getSQLEditor($inline_editor);
codemirror_inline_editor.getWrapperElement().style.height = height;
codemirror_inline_editor.refresh();
codemirror_inline_editor.focus();
$(codemirror_inline_editor.getWrapperElement())
.bind('keydown', catchKeypressesFromSqlInlineEdit);
} else {
$inline_editor
.focus()
.bind('keydown', catchKeypressesFromSqlInlineEdit);
}
}
}
function catchKeypressesFromSqlInlineEdit(event) {
// ctrl-enter is 10 in chrome and ie, but 13 in ff
if (event.ctrlKey && (event.keyCode == 13 || event.keyCode == 10)) {
$("#sql_query_edit_save").trigger('click');
}
}
/**
* Adds doc link to single highlighted SQL element
*/
function PMA_doc_add($elm, params)
{
if (typeof mysql_doc_template == 'undefined') {
return;
}
var url = PMA_sprintf(
decodeURIComponent(mysql_doc_template),
params[0]
);
if (params.length > 1) {
url += '#' + params[1];
}
var content = $elm.text();
$elm.text('');
$elm.append('
' + content + '');
}
/**
* Generates doc links for keywords inside highlighted SQL
*/
function PMA_doc_keyword(idx, elm)
{
var $elm = $(elm);
/* Skip already processed ones */
if ($elm.find('a').length > 0) {
return;
}
var keyword = $elm.text().toUpperCase();
var $next = $elm.next('.cm-keyword');
if ($next) {
var next_keyword = $next.text().toUpperCase();
var full = keyword + ' ' + next_keyword;
var $next2 = $next.next('.cm-keyword');
if ($next2) {
var next2_keyword = $next2.text().toUpperCase();
var full2 = full + ' ' + next2_keyword;
if (full2 in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[full2]);
PMA_doc_add($next, mysql_doc_keyword[full2]);
PMA_doc_add($next2, mysql_doc_keyword[full2]);
return;
}
}
if (full in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[full]);
PMA_doc_add($next, mysql_doc_keyword[full]);
return;
}
}
if (keyword in mysql_doc_keyword) {
PMA_doc_add($elm, mysql_doc_keyword[keyword]);
}
}
/**
* Generates doc links for builtins inside highlighted SQL
*/
function PMA_doc_builtin(idx, elm)
{
var $elm = $(elm);
var builtin = $elm.text().toUpperCase();
if (builtin in mysql_doc_builtin) {
PMA_doc_add($elm, mysql_doc_builtin[builtin]);
}
}
/**
* Higlights SQL using CodeMirror.
*/
function PMA_highlightSQL($base)
{
var $elm = $base.find('code.sql');
$elm.each(function () {
var $sql = $(this);
var $pre = $sql.find('pre');
/* We only care about visible elements to avoid double processing */
if ($pre.is(":visible")) {
var $highlight = $('
');
$sql.append($highlight);
if (typeof CodeMirror != 'undefined') {
CodeMirror.runMode($sql.text(), 'text/x-mysql', $highlight[0]);
$pre.hide();
$highlight.find('.cm-keyword').each(PMA_doc_keyword);
$highlight.find('.cm-builtin').each(PMA_doc_builtin);
}
}
});
}
/**
* Updates an element containing code.
*
* @param jQuery Object $base base element which contains the raw and the
* highlighted code.
*
* @param string htmlValue code in HTML format, displayed if code cannot be
* highlighted
*
* @param string rawValue raw code, used as a parameter for highlighter
*
* @return bool whether content was updated or not
*/
function PMA_updateCode($base, htmlValue, rawValue)
{
var $code = $base.find('code');
if ($code.length === 0) {
return false;
}
// Determines the type of the content and appropriate CodeMirror mode.
var type = '', mode = '';
if ($code.hasClass('json')) {
type = 'json';
mode = 'application/json';
} else if ($code.hasClass('sql')) {
type = 'sql';
mode = 'text/x-mysql';
} else if ($code.hasClass('xml')) {
type = 'xml';
mode = 'application/xml';
} else {
return false;
}
// Element used to display unhighlighted code.
var $notHighlighted = $('
' + htmlValue + '
');
// Tries to highlight code using CodeMirror.
if (typeof CodeMirror != 'undefined') {
var $highlighted = $('
');
CodeMirror.runMode(rawValue, mode, $highlighted[0]);
$notHighlighted.hide();
$code.html('').append($notHighlighted, $highlighted[0]);
} else {
$code.html('').append($notHighlighted);
}
return true;
}
/**
* Show a message on the top of the page for an Ajax request
*
* Sample usage:
*
* 1) var $msg = PMA_ajaxShowMessage();
* This will show a message that reads "Loading...". Such a message will not
* disappear automatically and cannot be dismissed by the user. To remove this
* message either the PMA_ajaxRemoveMessage($msg) function must be called or
* another message must be show with PMA_ajaxShowMessage() function.
*
* 2) var $msg = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
* This is a special case. The behaviour is same as above,
* just with a different message
*
* 3) var $msg = PMA_ajaxShowMessage('The operation was successful');
* This will show a message that will disappear automatically and it can also
* be dismissed by the user.
*
* 4) var $msg = PMA_ajaxShowMessage('Some error', false);
* This will show a message that will not disappear automatically, but it
* can be dismissed by the user after he has finished reading it.
*
* @param string message string containing the message to be shown.
* optional, defaults to 'Loading...'
* @param mixed timeout number of milliseconds for the message to be visible
* optional, defaults to 5000. If set to 'false', the
* notification will never disappear
* @return jQuery object jQuery Element that holds the message div
* this object can be passed to PMA_ajaxRemoveMessage()
* to remove the notification
*/
function PMA_ajaxShowMessage(message, timeout)
{
/**
* @var self_closing Whether the notification will automatically disappear
*/
var self_closing = true;
/**
* @var dismissable Whether the user will be able to remove
* the notification by clicking on it
*/
var dismissable = true;
// Handle the case when a empty data.message is passed.
// We don't want the empty message
if (message === '') {
return true;
} else if (! message) {
// If the message is undefined, show the default
message = PMA_messages.strLoading;
dismissable = false;
self_closing = false;
} else if (message == PMA_messages.strProcessingRequest) {
// This is another case where the message should not disappear
dismissable = false;
self_closing = false;
}
// Figure out whether (or after how long) to remove the notification
if (timeout === undefined) {
timeout = 5000;
} else if (timeout === false) {
self_closing = false;
}
// Create a parent element for the AJAX messages, if necessary
if ($('#loading_parent').length === 0) {
$('
')
.prependTo("#page_content");
}
// Update message count to create distinct message elements every time
ajax_message_count++;
// Remove all old messages, if any
$("span.ajax_notification[id^=ajax_message_num]").remove();
/**
* @var $retval a jQuery object containing the reference
* to the created AJAX message
*/
var $retval = $(
'
'
)
.hide()
.appendTo("#loading_parent")
.html(message)
.show();
// If the notification is self-closing we should create a callback to remove it
if (self_closing) {
$retval
.delay(timeout)
.fadeOut('medium', function () {
if ($(this).is(':data(tooltip)')) {
$(this).tooltip('destroy');
}
// Remove the notification
$(this).remove();
});
}
// If the notification is dismissable we need to add the relevant class to it
// and add a tooltip so that the users know that it can be removed
if (dismissable) {
$retval.addClass('dismissable').css('cursor', 'pointer');
/**
* Add a tooltip to the notification to let the user know that (s)he
* can dismiss the ajax notification by clicking on it.
*/
PMA_tooltip(
$retval,
'span',
PMA_messages.strDismiss
);
}
PMA_highlightSQL($retval);
return $retval;
}
/**
* Removes the message shown for an Ajax operation when it's completed
*
* @param jQuery object jQuery Element that holds the notification
*
* @return nothing
*/
function PMA_ajaxRemoveMessage($this_msgbox)
{
if ($this_msgbox !== undefined && $this_msgbox instanceof jQuery) {
$this_msgbox
.stop(true, true)
.fadeOut('medium');
if ($this_msgbox.is(':data(tooltip)')) {
$this_msgbox.tooltip('destroy');
} else {
$this_msgbox.remove();
}
}
}
/**
* Requests SQL for previewing before executing.
*
* @param jQuery Object $form Form containing query data
*
* @return void
*/
function PMA_previewSQL($form)
{
var form_url = $form.attr('action');
var form_data = $form.serialize() +
'&do_save_data=1' +
'&preview_sql=1' +
'&ajax_request=1';
var $msgbox = PMA_ajaxShowMessage();
$.ajax({
type: 'POST',
url: form_url,
data: form_data,
success: function (response) {
PMA_ajaxRemoveMessage($msgbox);
if (response.success) {
var $dialog_content = $('
')
.append(response.sql_data);
var button_options = {};
button_options[PMA_messages.strClose] = function () {
$(this).dialog('close');
};
var $response_dialog = $dialog_content.dialog({
minWidth: 550,
maxHeight: 400,
modal: true,
buttons: button_options,
title: PMA_messages.strPreviewSQL,
close: function () {
$(this).remove();
},
open: function () {
// Pretty SQL printing.
PMA_highlightSQL($(this));
}
});
} else {
PMA_ajaxShowMessage(response.message);
}
},
error: function () {
PMA_ajaxShowMessage(PMA_messages.strErrorProcessingRequest);
}
});
}
/**
* check for reserved keyword column name
*
* @param jQuery Object $form Form
*
* @returns true|false
*/
function PMA_checkReservedWordColumns($form) {
var is_confirmed = true;
$.ajax({
type: 'POST',
url: "tbl_structure.php",
data: $form.serialize() + '&reserved_word_check=1',
success: function (data) {
if (typeof data.success != 'undefined' && data.success === true) {
is_confirmed = confirm(data.message);
}
},
async:false
});
return is_confirmed;
}
// This event only need to be fired once after the initial page load
$(function () {
/**
* Allows the user to dismiss a notification
* created with PMA_ajaxShowMessage()
*/
$(document).on('click', 'span.ajax_notification.dismissable', function () {
PMA_ajaxRemoveMessage($(this));
});
/**
* The below two functions hide the "Dismiss notification" tooltip when a user
* is hovering a link or button that is inside an ajax message
*/
$(document).on('mouseover', 'span.ajax_notification a, span.ajax_notification button, span.ajax_notification input', function () {
if ($(this).parents('span.ajax_notification').is(':data(tooltip)')) {
$(this).parents('span.ajax_notification').tooltip('disable');
}
});
$(document).on('mouseout', 'span.ajax_notification a, span.ajax_notification button, span.ajax_notification input', function () {
if ($(this).parents('span.ajax_notification').is(':data(tooltip)')) {
$(this).parents('span.ajax_notification').tooltip('enable');
}
});
});
/**
* 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], 10) + 1);
var selectedType = selectElement.val();
if (selectedType == "ENUM" || selectedType == "SET") {
$("p#enum_notice_" + enum_notice_id).show();
} else {
$("p#enum_notice_" + enum_notice_id).hide();
}
}
/**
* Creates a Profiling Chart. Used in sql.js
* and in server_status_monitor.js
*/
function PMA_createProfilingChart(target, data)
{
// create the chart
var factory = new JQPlotChartFactory();
var chart = factory.createChart(ChartType.PIE, target);
// create the data table and add columns
var dataTable = new DataTable();
dataTable.addColumn(ColumnType.STRING, '');
dataTable.addColumn(ColumnType.NUMBER, '');
dataTable.setData(data);
// draw the chart and return the chart object
chart.draw(dataTable, {
seriesDefaults: {
rendererOptions: {
showDataLabels: true
}
},
highlighter: {
tooltipLocation: 'se',
sizeAdjust: 0,
tooltipAxes: 'pieref',
formatString: '%s, %.9Ps'
},
legend: {
show: true,
location: 'e',
rendererOptions: {
numberColumns: 2
}
},
// from http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines#Color_Palette
seriesColors: [
'#fce94f',
'#fcaf3e',
'#e9b96e',
'#8ae234',
'#729fcf',
'#ad7fa8',
'#ef2929',
'#eeeeec',
'#888a85',
'#c4a000',
'#ce5c00',
'#8f5902',
'#4e9a06',
'#204a87',
'#5c3566',
'#a40000',
'#babdb6',
'#2e3436'
]
});
return chart;
}
/**
* Formats a profiling duration nicely (in us and ms time).
* Used in server_status_monitor.js
*
* @param integer Number to be formatted, should be in the range of microsecond to second
* @param integer Accuracy, how many numbers right to the comma should be
* @return string The formatted number
*/
function PMA_prettyProfilingNum(num, acc)
{
if (!acc) {
acc = 2;
}
acc = Math.pow(10, acc);
if (num * 1000 < 0.1) {
num = Math.round(acc * (num * 1000 * 1000)) / acc + 'µ';
} else if (num < 0.1) {
num = Math.round(acc * (num * 1000)) / acc + 'm';
} else {
num = Math.round(acc * num) / acc;
}
return num + 's';
}
/**
* Formats a SQL Query nicely with newlines and indentation. Depends on Codemirror and MySQL Mode!
*
* @param string Query to be formatted
* @return string The formatted query
*/
function PMA_SQLPrettyPrint(string)
{
if (typeof CodeMirror == 'undefined') {
return string;
}
var mode = CodeMirror.getMode({}, "text/x-mysql");
var stream = new CodeMirror.StringStream(string);
var state = mode.startState();
var token, tokens = [];
var output = '';
var tabs = function (cnt) {
var ret = '';
for (var i = 0; i < 4 * cnt; i++) {
ret += " ";
}
return ret;
};
// "root-level" statements
var statements = {
'select': ['select', 'from', 'on', 'where', 'having', 'limit', 'order by', 'group by'],
'update': ['update', 'set', 'where'],
'insert into': ['insert into', 'values']
};
// don't put spaces before these tokens
var spaceExceptionsBefore = {';': true, ',': true, '.': true, '(': true};
// don't put spaces after these tokens
var spaceExceptionsAfter = {'.': true};
// Populate tokens array
var str = '';
while (! stream.eol()) {
stream.start = stream.pos;
token = mode.token(stream, state);
if (token !== null) {
tokens.push([token, stream.current().toLowerCase()]);
}
}
var currentStatement = tokens[0][1];
if (! statements[currentStatement]) {
return string;
}
// Holds all currently opened code blocks (statement, function or generic)
var blockStack = [];
// Holds the type of block from last iteration (the current is in blockStack[0])
var previousBlock;
// If a new code block is found, newBlock contains its type for one iteration and vice versa for endBlock
var newBlock, endBlock;
// How much to indent in the current line
var indentLevel = 0;
// Holds the "root-level" statements
var statementPart, lastStatementPart = statements[currentStatement][0];
blockStack.unshift('statement');
// Iterate through every token and format accordingly
for (var i = 0; i < tokens.length; i++) {
previousBlock = blockStack[0];
// New block => push to stack
if (tokens[i][1] == '(') {
if (i < tokens.length - 1 && tokens[i + 1][0] == 'statement-verb') {
blockStack.unshift(newBlock = 'statement');
} else if (i > 0 && tokens[i - 1][0] == 'builtin') {
blockStack.unshift(newBlock = 'function');
} else {
blockStack.unshift(newBlock = 'generic');
}
} else {
newBlock = null;
}
// Block end => pop from stack
if (tokens[i][1] == ')') {
endBlock = blockStack[0];
blockStack.shift();
} else {
endBlock = null;
}
// A subquery is starting
if (i > 0 && newBlock == 'statement') {
indentLevel++;
output += "\n" + tabs(indentLevel) + tokens[i][1] + ' ' + tokens[i + 1][1].toUpperCase() + "\n" + tabs(indentLevel + 1);
currentStatement = tokens[i + 1][1];
i++;
continue;
}
// A subquery is ending
if (endBlock == 'statement' && indentLevel > 0) {
output += "\n" + tabs(indentLevel);
indentLevel--;
}
// One less indentation for statement parts (from, where, order by, etc.) and a newline
statementPart = statements[currentStatement].indexOf(tokens[i][1]);
if (statementPart != -1) {
if (i > 0) {
output += "\n";
}
output += tabs(indentLevel) + tokens[i][1].toUpperCase();
output += "\n" + tabs(indentLevel + 1);
lastStatementPart = tokens[i][1];
}
// Normal indentation and spaces for everything else
else {
if (! spaceExceptionsBefore[tokens[i][1]] &&
! (i > 0 && spaceExceptionsAfter[tokens[i - 1][1]]) &&
output.charAt(output.length - 1) != ' ') {
output += " ";
}
if (tokens[i][0] == 'keyword') {
output += tokens[i][1].toUpperCase();
} else {
output += tokens[i][1];
}
}
// split columns in select and 'update set' clauses, but only inside statements blocks
if ((lastStatementPart == 'select' || lastStatementPart == 'where' || lastStatementPart == 'set') &&
tokens[i][1] == ',' && blockStack[0] == 'statement') {
output += "\n" + tabs(indentLevel + 1);
}
// split conditions in where clauses, but only inside statements blocks
if (lastStatementPart == 'where' &&
(tokens[i][1] == 'and' || tokens[i][1] == 'or' || tokens[i][1] == 'xor')) {
if (blockStack[0] == 'statement') {
output += "\n" + tabs(indentLevel + 1);
}
// Todo: Also split and or blocks in newlines & indentation++
//if (blockStack[0] == 'generic')
// output += ...
}
}
return output;
}
/**
* 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
* @param function openCallback optional callback to run when dialog is shown
*/
jQuery.fn.PMA_confirm = function (question, url, callbackFn, openCallback) {
var confirmState = PMA_commonParams.get('confirm');
if (! confirmState) {
// user does not want to confirm
if ($.isFunction(callbackFn)) {
callbackFn.call(this, url);
return true;
}
}
if (PMA_messages.strDoYouReally === '') {
return true;
}
/**
* @var button_options Object that stores the options passed to jQueryUI
* dialog
*/
var button_options = [
{
text: PMA_messages.strOK,
'class': 'submitOK',
click: function () {
$(this).dialog("close");
if ($.isFunction(callbackFn)) {
callbackFn.call(this, url);
}
}
},
{
text: PMA_messages.strCancel,
'class': 'submitCancel',
click: function () {
$(this).dialog("close");
}
}
];
$('
', {'id': 'confirm_dialog', 'title': PMA_messages.strConfirm})
.prepend(question)
.dialog({
buttons: button_options,
close: function () {
$(this).remove();
},
open: openCallback,
modal: true
});
};
/**
* 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');
});
};
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('submit', "#create_table_form_minimal.ajax");
$(document).off('submit', "form.create_table_form.ajax");
$(document).off('click', "form.create_table_form.ajax input[name=submit_num_fields]");
$(document).off('keyup', "form.create_table_form.ajax input");
$(document).off('change', "input[name=partition_count],input[name=subpartition_count],select[name=partition_by]");
});
/**
* 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
*/
AJAX.registerOnload('functions.js', function () {
/**
* Attach event handler for submission of create table form (save)
*/
$(document).on('submit', "form.create_table_form.ajax", function (event) {
event.preventDefault();
/**
* @var the_form object referring to the create table form
*/
var $form = $(this);
/*
* 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())) {
PMA_prepareForAjaxRequest($form);
if (PMA_checkReservedWordColumns($form)) {
PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
//User wants to submit the form
$.post($form.attr('action'), $form.serialize() + "&do_save_data=1", function (data) {
if (typeof data !== 'undefined' && data.success === true) {
$('#properties_message')
.removeClass('error')
.html('');
PMA_ajaxShowMessage(data.message);
// Only if the create table dialog (distinct panel) exists
var $createTableDialog = $("#create_table_dialog");
if ($createTableDialog.length > 0) {
$createTableDialog.dialog("close").remove();
}
$('#tableslistcontainer').before(data.formatted_sql);
/**
* @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) {
PMA_commonActions.refreshMain(
PMA_commonParams.get('opendb_url')
);
} 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');
// Adjust summary row
PMA_adjustTotals();
}
//Refresh navigation as a new table has been added
PMA_reloadNavigation();
// Redirect to table structure page on creation of new table
var params_12 = 'ajax_request=true&ajax_page_request=true';
if (! (history && history.pushState)) {
params_12 += PMA_MicroHistory.menus.getRequestParam();
}
tblStruct_url = 'tbl_structure.php?server=' + data._params.server +
'&db='+ data._params.db + '&token=' + data._params.token +
'&goto=db_structure.php&table=' + data._params.table + '';
$.get(tblStruct_url, params_12, AJAX.responseHandler);
} else {
PMA_ajaxShowMessage(
'' + data.error + '
',
false
);
}
}); // end $.post()
}
} // end if (checkTableEditForm() )
}); // end create table form (save)
/**
* Submits the intermediate changes in the table creation form
* to refresh the UI accordingly
*/
function submitChangesInCreateTableForm (actionParam) {
/**
* @var the_form object referring to the create table form
*/
var $form = $('form.create_table_form.ajax');
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() + "&" + actionParam, function (data) {
if (typeof data !== 'undefined' && data.success) {
var $pageContent = $("#page_content");
$pageContent.html(data.message);
PMA_highlightSQL($pageContent);
PMA_verifyColumnsProperties();
PMA_hideShowConnection($('.create_table_form select[name=tbl_storage_engine]'));
PMA_ajaxRemoveMessage($msgbox);
} else {
PMA_ajaxShowMessage(data.error);
}
}); //end $.post()
}
/**
* Attach event handler for create table form (add fields)
*/
$(document).on('click', "form.create_table_form.ajax input[name=submit_num_fields]", function (event) {
event.preventDefault();
if (!checkFormElementInRange(this.form, 'added_fields', PMA_messages.strLeastColumnError, 1)) {
return;
}
submitChangesInCreateTableForm('submit_num_fields=1');
}); // end create table form (add fields)
$(document).on('keydown', "form.create_table_form.ajax input[name=added_fields]", function (event) {
if (event.keyCode == 13) {
event.preventDefault();
event.stopImmediatePropagation();
$(this)
.closest('form')
.find('input[name=submit_num_fields]')
.click();
}
});
/**
* Attach event handler to manage changes in number of partitions and subpartitions
*/
$(document).on('change', "input[name=partition_count],input[name=subpartition_count],select[name=partition_by]", function (event) {
$this = $(this);
$form = $this.parents('form');
if ($form.is(".create_table_form.ajax")) {
submitChangesInCreateTableForm('submit_partition_change=1');
} else {
$form.submit();
}
});
$("input[value=AUTO_INCREMENT]").change(function(){
if (this.checked) {
var col = /\d/.exec($(this).attr('name'));
col = col[0];
var $selectFieldKey = $('select[name="field_key[' + col + ']"]');
if ($selectFieldKey.val() === 'none_'+col) {
$selectFieldKey.val('primary_'+col).change();
}
}
});
$('body')
.off('click', 'input.preview_sql')
.on('click', 'input.preview_sql', function () {
var $form = $(this).closest('form');
PMA_previewSQL($form);
});
});
/**
* Validates the password field in a form
*
* @see PMA_messages.strPasswordEmpty
* @see PMA_messages.strPasswordNotSame
* @param object $the_form The form to be validated
* @return bool
*/
function PMA_checkPassword($the_form)
{
// Did the user select 'no password'?
if ($the_form.find('#nopass_1').is(':checked')) {
return true;
} else {
var $pred = $the_form.find('#select_pred_password');
if ($pred.length && ($pred.val() == 'none' || $pred.val() == 'keep')) {
return true;
}
}
var $password = $the_form.find('input[name=pma_pw]');
var $password_repeat = $the_form.find('input[name=pma_pw2]');
var alert_msg = false;
if ($password.val() === '') {
alert_msg = PMA_messages.strPasswordEmpty;
} else if ($password.val() != $password_repeat.val()) {
alert_msg = PMA_messages.strPasswordNotSame;
}
if (alert_msg) {
alert(alert_msg);
$password.val('');
$password_repeat.val('');
$password.focus();
return false;
}
return true;
}
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', '#change_password_anchor.ajax');
});
/**
* Attach Ajax event handlers for 'Change Password' on index.php
*/
AJAX.registerOnload('functions.js', function () {
/* Handler for hostname type */
$(document).on('change', '#select_pred_hostname', function () {
var hostname = $('#pma_hostname');
if (this.value == 'any') {
hostname.val('%');
} else if (this.value == 'localhost') {
hostname.val('localhost');
} else if (this.value == 'thishost' && $(this).data('thishost')) {
hostname.val($(this).data('thishost'));
} else if (this.value == 'hosttable') {
hostname.val('').prop('required', false);
} else if (this.value == 'userdefined') {
hostname.focus().select().prop('required', true);
}
});
/* Handler for editing hostname */
$(document).on('change', '#pma_hostname', function () {
$('#select_pred_hostname').val('userdefined');
$('#pma_hostname').prop('required', true);
});
/* Handler for username type */
$(document).on('change', '#select_pred_username', function () {
if (this.value == 'any') {
$('#pma_username').val('').prop('required', false);
$('#user_exists_warning').css('display', 'none');
} else if (this.value == 'userdefined') {
$('#pma_username').focus().select().prop('required', true);
}
});
/* Handler for editing username */
$(document).on('change', '#pma_username', function () {
$('#select_pred_username').val('userdefined');
$('#pma_username').prop('required', true);
});
/* Handler for password type */
$(document).on('change', '#select_pred_password', function () {
if (this.value == 'none') {
$('#text_pma_pw2').prop('required', false).val('');
$('#text_pma_pw').prop('required', false).val('');
} else if (this.value == 'userdefined') {
$('#text_pma_pw2').prop('required', true);
$('#text_pma_pw').prop('required', true).focus().select();
} else {
$('#text_pma_pw2').prop('required', false);
$('#text_pma_pw').prop('required', false);
}
});
/* Handler for editing password */
$(document).on('change', '#text_pma_pw,#text_pma_pw2', function () {
$('#select_pred_password').val('userdefined');
$('#text_pma_pw2').prop('required', true);
$('#text_pma_pw').prop('required', true);
});
/**
* Attach Ajax event handler on the change password anchor
*/
$(document).on('click', '#change_password_anchor.ajax', function (event) {
event.preventDefault();
var $msgbox = PMA_ajaxShowMessage();
/**
* @var button_options Object containing options to be passed to jQueryUI's dialog
*/
var button_options = {};
button_options[PMA_messages.strGo] = function () {
event.preventDefault();
/**
* @var $the_form Object referring to the change password form
*/
var $the_form = $("#change_password_form");
if (! PMA_checkPassword($the_form)) {
return false;
}
/**
* @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 (typeof data === 'undefined' || data.success !== true) {
PMA_ajaxShowMessage(data.error, false);
return;
}
var $pageContent = $("#page_content");
$pageContent.prepend(data.message);
PMA_highlightSQL($pageContent);
$("#change_password_dialog").hide().remove();
$("#edit_user_dialog").dialog("close").remove();
PMA_ajaxRemoveMessage($msgbox);
}); // end $.post()
};
button_options[PMA_messages.strCancel] = function () {
$(this).dialog('close');
};
$.get($(this).attr('href'), {'ajax_request': true}, function (data) {
if (typeof data === 'undefined' || !data.success) {
PMA_ajaxShowMessage(data.error, false);
return;
}
$('')
.dialog({
title: PMA_messages.strChangePassword,
width: 600,
close: function (ev, ui) {
$(this).remove();
},
buttons: button_options,
modal: true
})
.append(data.message);
// for this dialog, we remove the fieldset wrapping due to double headings
$("fieldset#fieldset_change_password")
.find("legend").remove().end()
.find("table.noclick").unwrap().addClass("some-margin")
.find("input#text_pma_pw").focus();
displayPasswordGenerateButton();
$('#fieldset_change_password_footer').hide();
PMA_ajaxRemoveMessage($msgbox);
$('#change_password_form').bind('submit', function (e) {
e.preventDefault();
$(this)
.closest('.ui-dialog')
.find('.ui-dialog-buttonpane .ui-button')
.first()
.click();
});
}); // end $.get()
}); // end handler for change password anchor
}); // end $() for Change Password
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('change', "select.column_type");
$(document).off('change', "select.default_type");
$(document).off('change', "select.virtuality");
$(document).off('change', 'input.allow_null');
$(document).off('change', '.create_table_form select[name=tbl_storage_engine]');
});
/**
* Toggle the hiding/showing of the "Open in ENUM/SET editor" message when
* the page loads and when the selected data type changes
*/
AJAX.registerOnload('functions.js', function () {
// is called here for normal page loads and also when opening
// the Create table dialog
PMA_verifyColumnsProperties();
//
// needs on() to work also in the Create Table dialog
$(document).on('change', "select.column_type", function () {
PMA_showNoticeForEnum($(this));
});
$(document).on('change', "select.default_type", function () {
PMA_hideShowDefaultValue($(this));
});
$(document).on('change', "select.virtuality", function () {
PMA_hideShowExpression($(this));
});
$(document).on('change', 'input.allow_null', function () {
PMA_validateDefaultValue($(this));
});
$(document).on('change', '.create_table_form select[name=tbl_storage_engine]', function () {
PMA_hideShowConnection($(this));
});
});
/**
* If the chosen storage engine is FEDERATED show connection field. Hide otherwise
*
* @param $engine_selector storage engine selector
*/
function PMA_hideShowConnection($engine_selector)
{
var $connection = $('.create_table_form input[name=connection]');
var index = $connection.parent('td').index() + 1;
var $labelTh = $connection.parents('tr').prev('tr').children('th:nth-child(' + index + ')');
if ($engine_selector.val() != 'FEDERATED') {
$connection
.prop('disabled', true)
.parent('td').hide();
$labelTh.hide();
} else {
$connection
.prop('disabled', false)
.parent('td').show();
$labelTh.show();
}
}
/**
* If the column does not allow NULL values, makes sure that default is not NULL
*/
function PMA_validateDefaultValue($null_checkbox)
{
if (! $null_checkbox.prop('checked')) {
var $default = $null_checkbox.closest('tr').find('.default_type');
if ($default.val() == 'NULL') {
$default.val('NONE');
}
}
}
/**
* function to populate the input fields on picking a column from central list
*
* @param string input_id input id of the name field for the column to be populated
* @param integer offset of the selected column in central list of columns
*/
function autoPopulate(input_id, offset)
{
var db = PMA_commonParams.get('db');
var table = PMA_commonParams.get('table');
input_id = input_id.substring(0, input_id.length - 1);
$('#' + input_id + '1').val(central_column_list[db + '_' + table][offset].col_name);
var col_type = central_column_list[db + '_' + table][offset].col_type.toUpperCase();
$('#' + input_id + '2').val(col_type);
var $input3 = $('#' + input_id + '3');
$input3.val(central_column_list[db + '_' + table][offset].col_length);
if(col_type === 'ENUM' || col_type === 'SET') {
$input3.next().show();
} else {
$input3.next().hide();
}
var col_default = central_column_list[db + '_' + table][offset].col_default.toUpperCase();
var $input4 = $('#' + input_id + '4');
if (col_default !== '' && col_default !== 'NULL' && col_default !== 'CURRENT_TIMESTAMP') {
$input4.val("USER_DEFINED");
$input4.next().next().show();
$input4.next().next().val(central_column_list[db + '_' + table][offset].col_default);
} else {
$input4.val(central_column_list[db + '_' + table][offset].col_default);
$input4.next().next().hide();
}
$('#' + input_id + '5').val(central_column_list[db + '_' + table][offset].col_collation);
var $input6 = $('#' + input_id + '6');
$input6.val(central_column_list[db + '_' + table][offset].col_attribute);
if(central_column_list[db + '_' + table][offset].col_extra === 'on update CURRENT_TIMESTAMP') {
$input6.val(central_column_list[db + '_' + table][offset].col_extra);
}
if(central_column_list[db + '_' + table][offset].col_extra.toUpperCase() === 'AUTO_INCREMENT') {
$('#' + input_id + '9').prop("checked",true).change();
} else {
$('#' + input_id + '9').prop("checked",false);
}
if(central_column_list[db + '_' + table][offset].col_isNull !== '0') {
$('#' + input_id + '7').prop("checked",true);
} else {
$('#' + input_id + '7').prop("checked",false);
}
}
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', "a.open_enum_editor");
$(document).off('click', "input.add_value");
$(document).off('click', "#enum_editor td.drop");
$(document).off('click', 'a.central_columns_dialog');
});
/**
* @var $enum_editor_dialog An object that points to the jQuery
* dialog of the ENUM/SET editor
*/
var $enum_editor_dialog = null;
/**
* Opens the ENUM/SET editor and controls its functions
*/
AJAX.registerOnload('functions.js', function () {
$(document).on('click', "a.open_enum_editor", function () {
// Get the name of the column that is being edited
var colname = $(this).closest('tr').find('input:first').val();
var title;
var i;
// And use it to make up a title for the page
if (colname.length < 1) {
title = PMA_messages.enum_newColumnVals;
} else {
title = PMA_messages.enum_columnVals.replace(
/%s/,
'"' + escapeHtml(decodeURIComponent(colname)) + '"'
);
}
// Get the values as a string
var inputstring = $(this)
.closest('td')
.find("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 (i = 0; i < inputstring.length; i++) {
curr = inputstring.charAt(i);
next = i == inputstring.length ? '' : inputstring.charAt(i + 1);
if (! in_string && curr == "'") {
in_string = true;
} else if (in_string && curr == "\\" && next == "\\") {
buffer += "\";
i++;
} else if (in_string && next == "'" && (curr == "'" || curr == "\\")) {
buffer += "'";
i++;
} else if (in_string && curr == "'") {
in_string = false;
values.push(buffer);
buffer = '';
} else if (in_string) {
buffer += curr;
}
}
if (buffer.length > 0) {
// The leftovers in the buffer are the last value (if any)
values.push(buffer);
}
var fields = '';
// If there are no values, maybe the user is about to make a
// new list so we add a few for him/her to get started with.
if (values.length === 0) {
values.push('', '', '', '');
}
// Add the parsed values to the editor
var drop_icon = PMA_getImage('b_drop.png');
for (i = 0; i < values.length; i++) {
fields += "
| " +
"" +
" | " +
drop_icon +
" |
";
}
/**
* @var dialog HTML code for the ENUM/SET dialog
*/
var dialog = "" +
"
" +
"
";
/**
* @var Defines functions to be called when the buttons in
* the buttonOptions jQuery dialog bar are pressed
*/
var buttonOptions = {};
buttonOptions[PMA_messages.strGo] = function () {
// When the submit button is clicked,
// put the data back into the original form
var value_array = [];
$(this).find(".values input").each(function (index, elm) {
var val = elm.value.replace(/\\/g, '\\\\').replace(/'/g, "''");
value_array.push("'" + val + "'");
});
// get the Length/Values text field where this value belongs
var values_id = $(this).find("input[type='hidden']").val();
$("input#" + values_id).val(value_array.join(","));
$(this).dialog("close");
};
buttonOptions[PMA_messages.strClose] = function () {
$(this).dialog("close");
};
// Show the dialog
var width = parseInt(
(parseInt($('html').css('font-size'), 10) / 13) * 340,
10
);
if (! width) {
width = 340;
}
$enum_editor_dialog = $(dialog).dialog({
minWidth: width,
maxHeight: 450,
modal: true,
title: PMA_messages.enum_editor,
buttons: buttonOptions,
open: function () {
// Focus the "Go" button after opening the dialog
$(this).closest('.ui-dialog').find('.ui-dialog-buttonpane button:first').focus();
},
close: function () {
$(this).remove();
}
});
// slider for choosing how many fields to add
$enum_editor_dialog.find(".slider").slider({
animate: true,
range: "min",
value: 1,
min: 1,
max: 9,
slide: function (event, ui) {
$(this).closest('table').find('input[type=submit]').val(
PMA_sprintf(PMA_messages.enum_addValue, ui.value)
);
}
});
// Focus the slider, otherwise it looks nearly transparent
$('a.ui-slider-handle').addClass('ui-state-focus');
return false;
});
$(document).on('click', 'a.central_columns_dialog', function (e) {
var href = "db_central_columns.php";
var db = PMA_commonParams.get('db');
var table = PMA_commonParams.get('table');
var maxRows = $(this).data('maxrows');
var pick = $(this).data('pick');
if (pick !== false) {
pick = true;
}
var params = {
'ajax_request' : true,
'token' : PMA_commonParams.get('token'),
'server' : PMA_commonParams.get('server'),
'db' : PMA_commonParams.get('db'),
'cur_table' : PMA_commonParams.get('table'),
'getColumnList':true
};
var colid = $(this).closest('td').find("input").attr("id");
var fields = '';
if (! (db + '_' + table in central_column_list)) {
central_column_list.push(db + '_' + table);
$.ajax({
type: 'POST',
url: href,
data: params,
success: function (data) {
central_column_list[db + '_' + table] = $.parseJSON(data.message);
},
async:false
});
}
var i = 0;
var list_size = central_column_list[db + '_' + table].length;
var min = (list_size <= maxRows) ? list_size : maxRows;
for (i = 0; i < min; i++) {
fields += '' +
escapeHtml(central_column_list[db + '_' + table][i].col_name) +
' ' + central_column_list[db + '_' + table][i].col_type;
if (central_column_list[db + '_' + table][i].col_attribute !== '') {
fields += '(' + escapeHtml(central_column_list[db + '_' + table][i].col_attribute) + ') ';
}
if (central_column_list[db + '_' + table][i].col_length !== '') {
fields += '(' + escapeHtml(central_column_list[db + '_' + table][i].col_length) +') ';
}
fields += escapeHtml(central_column_list[db + '_' + table][i].col_extra) + '' +
' | ';
if (pick) {
fields += ' | ';
}
fields += '
';
}
var result_pointer = i;
var search_in = '';
if (fields === '') {
fields = PMA_sprintf(PMA_messages.strEmptyCentralList, "'" + escapeHtml(db) + "'");
search_in = '';
}
var seeMore = '';
if (list_size > maxRows) {
seeMore = "";
}
var central_columns_dialog = "" +
"
" +
seeMore +
"
";
var width = parseInt(
(parseInt($('html').css('font-size'), 10) / 13) * 500,
10
);
if (! width) {
width = 500;
}
var buttonOptions = {};
var $central_columns_dialog = $(central_columns_dialog).dialog({
minWidth: width,
maxHeight: 450,
modal: true,
title: PMA_messages.pickColumnTitle,
buttons: buttonOptions,
open: function () {
$('#col_list').on("click", ".pick", function (){
$central_columns_dialog.remove();
});
$(".filter_rows").on("keyup", function () {
$.uiTableFilter($("#col_list"), $(this).val());
});
$("#seeMore").click(function() {
fields = '';
min = (list_size <= maxRows + result_pointer) ? list_size : maxRows + result_pointer;
for (i = result_pointer; i < min; i++) {
fields += '' +
central_column_list[db + '_' + table][i].col_name +
' ' +
central_column_list[db + '_' + table][i].col_type;
if (central_column_list[db + '_' + table][i].col_attribute !== '') {
fields += '(' + central_column_list[db + '_' + table][i].col_attribute + ') ';
}
if (central_column_list[db + '_' + table][i].col_length !== '') {
fields += '(' + central_column_list[db + '_' + table][i].col_length + ') ';
}
fields += central_column_list[db + '_' + table][i].col_extra + '' +
' | ';
if (pick) {
fields += ' | ';
}
fields += '
';
}
$("#col_list").append(fields);
result_pointer = i;
if (result_pointer === list_size) {
$('.tblFooters').hide();
}
return false;
});
$(this).closest('.ui-dialog').find('.ui-dialog-buttonpane button:first').focus();
},
close: function () {
$('#col_list').off("click", ".pick");
$(".filter_rows").off("keyup");
$(this).remove();
}
});
return false;
});
// $(document).on('click', 'a.show_central_list',function(e) {
// });
// When "add a new value" is clicked, append an empty text field
$(document).on('click', "input.add_value", function (e) {
e.preventDefault();
var num_new_rows = $enum_editor_dialog.find("div.slider").slider('value');
while (num_new_rows--) {
$enum_editor_dialog.find('.values')
.append(
"| " +
"" +
" | " +
PMA_getImage('b_drop.png') +
" |
"
)
.find('tr:last')
.show('fast');
}
});
// Removes the specified row from the enum editor
$(document).on('click', "#enum_editor td.drop", function () {
$(this).closest('tr').hide('fast', function () {
$(this).remove();
});
});
});
/**
* Ensures indexes names are valid according to their type and, for a primary
* key, lock index name to 'PRIMARY'
* @param string form_id Variable which parses the form name as
* the input
* @return boolean false if there is no index form, true else
*/
function checkIndexName(form_id)
{
if ($("#" + form_id).length === 0) {
return false;
}
// Gets the elements pointers
var $the_idx_name = $("#input_index_name");
var $the_idx_choice = $("#select_index_choice");
// Index is a primary key
if ($the_idx_choice.find("option:selected").val() == 'PRIMARY') {
$the_idx_name.val('PRIMARY');
$the_idx_name.prop("disabled", true);
}
// Other cases
else {
if ($the_idx_name.val() == 'PRIMARY') {
$the_idx_name.val("");
}
$the_idx_name.prop("disabled", false);
}
return true;
} // end of the 'checkIndexName()' function
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', '#index_frm input[type=submit]');
});
AJAX.registerOnload('functions.js', function () {
/**
* Handler for adding more columns to an index in the editor
*/
$(document).on('click', '#index_frm input[type=submit]', function (event) {
event.preventDefault();
var rows_to_add = $(this)
.closest('fieldset')
.find('.slider')
.slider('value');
var tempEmptyVal = function () {
$(this).val('');
};
var tempSetFocus = function () {
if ($(this).find("option:selected").val() === '') {
return true;
}
$(this).closest("tr").find("input").focus();
};
while (rows_to_add--) {
var $indexColumns = $('#index_columns');
var $newrow = $indexColumns
.find('tbody > tr:first')
.clone()
.appendTo(
$indexColumns.find('tbody')
);
$newrow.find(':input').each(tempEmptyVal);
// focus index size input on column picked
$newrow.find('select').change(tempSetFocus);
}
});
});
function indexEditorDialog(url, title, callback_success, callback_failure)
{
/*Remove the hidden dialogs if there are*/
var $editIndexDialog = $('#edit_index_dialog');
if ($editIndexDialog.length !== 0) {
$editIndexDialog.remove();
}
var $div = $('');
/**
* @var button_options Object that stores the options
* passed to jQueryUI dialog
*/
var button_options = {};
button_options[PMA_messages.strGo] = function () {
/**
* @var the_form object referring to the export form
*/
var $form = $("#index_frm");
var $msgbox = PMA_ajaxShowMessage(PMA_messages.strProcessingRequest);
PMA_prepareForAjaxRequest($form);
//User wants to submit the form
$.post($form.attr('action'), $form.serialize() + "&do_save_data=1", function (data) {
var $sqlqueryresults = $(".sqlqueryresults");
if ($sqlqueryresults.length !== 0) {
$sqlqueryresults.remove();
}
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxShowMessage(data.message);
var $resultQuery = $('.result_query');
if ($resultQuery.length) {
$resultQuery.remove();
}
if (data.sql_query) {
$('')
.html(data.sql_query)
.prependTo('#page_content');
PMA_highlightSQL($('#page_content'));
}
$(".result_query .notice").remove();
$resultQuery.prepend(data.message);
/*Reload the field form*/
$("#table_index").remove();
$("")
.append(data.index_table)
.find("#table_index")
.insertAfter("#index_header");
var $editIndexDialog = $("#edit_index_dialog");
if ($editIndexDialog.length > 0) {
$editIndexDialog.dialog("close");
}
$('div.no_indexes_defined').hide();
if (callback_success) {
callback_success();
}
PMA_reloadNavigation();
} else {
var $temp_div = $("
").append(data.error);
var $error;
if ($temp_div.find(".error code").length !== 0) {
$error = $temp_div.find(".error code").addClass("error");
} else {
$error = $temp_div;
}
if (callback_failure) {
callback_failure();
}
PMA_ajaxShowMessage($error, false);
}
}); // end $.post()
};
button_options[PMA_messages.strPreviewSQL] = function () {
// Function for Previewing SQL
var $form = $('#index_frm');
PMA_previewSQL($form);
};
button_options[PMA_messages.strCancel] = function () {
$(this).dialog('close');
};
var $msgbox = PMA_ajaxShowMessage();
$.get("tbl_indexes.php", url, function (data) {
if (typeof data !== 'undefined' && data.success === false) {
//in the case of an error, show the error message returned.
PMA_ajaxShowMessage(data.error, false);
} else {
PMA_ajaxRemoveMessage($msgbox);
// Show dialog if the request was successful
$div
.append(data.message)
.dialog({
title: title,
width: 450,
height: 350,
open: PMA_verifyColumnsProperties,
modal: true,
buttons: button_options,
close: function () {
$(this).remove();
}
});
$div.find('.tblFooters').remove();
showIndexEditDialog($div);
}
}); // end $.get()
}
function showIndexEditDialog($outer)
{
checkIndexType();
checkIndexName("index_frm");
var $indexColumns = $('#index_columns');
$indexColumns.find('td').each(function () {
$(this).css("width", $(this).width() + 'px');
});
$indexColumns.find('tbody').sortable({
axis: 'y',
containment: $indexColumns.find("tbody"),
tolerance: 'pointer'
});
PMA_showHints($outer);
PMA_init_slider();
// Add a slider for selecting how many columns to add to the index
$outer.find('.slider').slider({
animate: true,
value: 1,
min: 1,
max: 16,
slide: function (event, ui) {
$(this).closest('fieldset').find('input[type=submit]').val(
PMA_sprintf(PMA_messages.strAddToIndex, ui.value)
);
}
});
$('div.add_fields').removeClass('hide');
// focus index size input on column picked
$outer.find('table#index_columns select').change(function () {
if ($(this).find("option:selected").val() === '') {
return true;
}
$(this).closest("tr").find("input").focus();
});
// Focus the slider, otherwise it looks nearly transparent
$('a.ui-slider-handle').addClass('ui-state-focus');
// set focus on index name input, if empty
var input = $outer.find('input#input_index_name');
if (! input.val()) {
input.focus();
}
}
/**
* Function to display tooltips that were
* generated on the PHP side by PMA\libraries\Util::showHint()
*
* @param object $div a div jquery object which specifies the
* domain for searching for tooltips. If we
* omit this parameter the function searches
* in the whole body
**/
function PMA_showHints($div)
{
if ($div === undefined || ! $div instanceof jQuery || $div.length === 0) {
$div = $("body");
}
$div.find('.pma_hint').each(function () {
PMA_tooltip(
$(this).children('img'),
'img',
$(this).children('span').html()
);
});
}
AJAX.registerOnload('functions.js', function () {
PMA_showHints();
});
function PMA_mainMenuResizerCallback() {
// 5 px margin for jumping menu in Chrome
return $(document.body).width() - 5;
}
// This must be fired only once after the initial page load
$(function () {
// Initialise the menu resize plugin
$('#topmenu').menuResizer(PMA_mainMenuResizerCallback);
// register resize event
$(window).resize(function () {
$('#topmenu').menuResizer('resize');
});
});
/**
* Get the row number from the classlist (for example, row_1)
*/
function PMA_getRowNumber(classlist)
{
return parseInt(classlist.split(/\s+row_/)[1], 10);
}
/**
* Changes status of slider
*/
function PMA_set_status_label($element)
{
var text;
if ($element.css('display') == 'none') {
text = '+ ';
} else {
text = '- ';
}
$element.closest('.slide-wrapper').prev().find('span').text(text);
}
/**
* var toggleButton This is a function that creates a toggle
* sliding button given a jQuery reference
* to the correct DOM element
*/
var toggleButton = function ($obj) {
// In rtl mode the toggle switch is flipped horizontally
// so we need to take that into account
var right;
if ($('span.text_direction', $obj).text() == 'ltr') {
right = 'right';
} else {
right = 'left';
}
/**
* var h Height of the button, used to scale the
* background image and position the layers
*/
var h = $obj.height();
$('img', $obj).height(h);
$('table', $obj).css('bottom', h - 1);
/**
* var on Width of the "ON" part of the toggle switch
* var off Width of the "OFF" part of the toggle switch
*/
var on = $('td.toggleOn', $obj).width();
var off = $('td.toggleOff', $obj).width();
// Make the "ON" and "OFF" parts of the switch the same size
// + 2 pixels to avoid overflowed
$('td.toggleOn > div', $obj).width(Math.max(on, off) + 2);
$('td.toggleOff > div', $obj).width(Math.max(on, off) + 2);
/**
* var w Width of the central part of the switch
*/
var w = parseInt(($('img', $obj).height() / 16) * 22, 10);
// Resize the central part of the switch on the top
// layer to match the background
$('table td:nth-child(2) > div', $obj).width(w);
/**
* var imgw Width of the background image
* var tblw Width of the foreground layer
* var offset By how many pixels to move the background
* image, so that it matches the top layer
*/
var imgw = $('img', $obj).width();
var tblw = $('table', $obj).width();
var offset = parseInt(((imgw - tblw) / 2), 10);
// Move the background to match the layout of the top layer
$obj.find('img').css(right, offset);
/**
* var offw Outer width of the "ON" part of the toggle switch
* var btnw Outer width of the central part of the switch
*/
var offw = $('td.toggleOff', $obj).outerWidth();
var btnw = $('table td:nth-child(2)', $obj).outerWidth();
// Resize the main div so that exactly one side of
// the switch plus the central part fit into it.
$obj.width(offw + btnw + 2);
/**
* var move How many pixels to move the
* switch by when toggling
*/
var move = $('td.toggleOff', $obj).outerWidth();
// If the switch is initialized to the
// OFF state we need to move it now.
if ($('div.container', $obj).hasClass('off')) {
if (right == 'right') {
$('div.container', $obj).animate({'left': '-=' + move + 'px'}, 0);
} else {
$('div.container', $obj).animate({'left': '+=' + move + 'px'}, 0);
}
}
// Attach an 'onclick' event to the switch
$('div.container', $obj).click(function () {
if ($(this).hasClass('isActive')) {
return false;
} else {
$(this).addClass('isActive');
}
var $msg = PMA_ajaxShowMessage();
var $container = $(this);
var callback = $('span.callback', this).text();
var operator, url, removeClass, addClass;
// Perform the actual toggle
if ($(this).hasClass('on')) {
if (right == 'right') {
operator = '-=';
} else {
operator = '+=';
}
url = $(this).find('td.toggleOff > span').text();
removeClass = 'on';
addClass = 'off';
} else {
if (right == 'right') {
operator = '+=';
} else {
operator = '-=';
}
url = $(this).find('td.toggleOn > span').text();
removeClass = 'off';
addClass = 'on';
}
$.post(url, {'ajax_request': true}, function (data) {
if (typeof data !== 'undefined' && data.success === true) {
PMA_ajaxRemoveMessage($msg);
$container
.removeClass(removeClass)
.addClass(addClass)
.animate({'left': operator + move + 'px'}, function () {
$container.removeClass('isActive');
});
eval(callback);
} else {
PMA_ajaxShowMessage(data.error, false);
$container.removeClass('isActive');
}
});
});
};
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$('div.container').unbind('click');
});
/**
* Initialise all toggle buttons
*/
AJAX.registerOnload('functions.js', function () {
$('div.toggleAjax').each(function () {
var $button = $(this).show();
$button.find('img').each(function () {
if (this.complete) {
toggleButton($button);
} else {
$(this).load(function () {
toggleButton($button);
});
}
});
});
});
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('change', 'select.pageselector');
$(document).off('click', 'a.formLinkSubmit');
$('#update_recent_tables').unbind('ready');
$('#sync_favorite_tables').unbind('ready');
});
AJAX.registerOnload('functions.js', function () {
/**
* Autosubmit page selector
*/
$(document).on('change', 'select.pageselector', function (event) {
event.stopPropagation();
// Check where to load the new content
if ($(this).closest("#pma_navigation").length === 0) {
// For the main page we don't need to do anything,
$(this).closest("form").submit();
} else {
// but for the navigation we need to manually replace the content
PMA_navigationTreePagination($(this));
}
});
/**
* Load version information asynchronously.
*/
if ($('li.jsversioncheck').length > 0) {
$.ajax({
dataType: "json",
url: 'version_check.php',
method: "POST",
data: {
"server": PMA_commonParams.get('server'),
"token": PMA_commonParams.get('token'),
},
success: PMA_current_version
});
}
if ($('#is_git_revision').length > 0) {
setTimeout(PMA_display_git_revision, 10);
}
/**
* Slider effect.
*/
PMA_init_slider();
/**
* Enables the text generated by PMA\libraries\Util::linkOrButton() to be clickable
*/
$(document).on('click', 'a.formLinkSubmit', function (e) {
if (! $(this).hasClass('requireConfirm')) {
submitFormLink($(this));
return false;
}
});
var $updateRecentTables = $('#update_recent_tables');
if ($updateRecentTables.length) {
$.get(
$updateRecentTables.attr('href'),
{no_debug: true},
function (data) {
if (typeof data !== 'undefined' && data.success === true) {
$('#pma_recent_list').html(data.list);
}
}
);
}
// Sync favorite tables from localStorage to pmadb.
if ($('#sync_favorite_tables').length) {
$.ajax({
url: $('#sync_favorite_tables').attr("href"),
cache: false,
type: 'POST',
data: {
favorite_tables: (isStorageSupported('localStorage') && typeof window.localStorage.favorite_tables !== 'undefined')
? window.localStorage.favorite_tables
: '',
no_debug: true
},
success: function (data) {
// Update localStorage.
if (isStorageSupported('localStorage')) {
window.localStorage.favorite_tables = data.favorite_tables;
}
$('#pma_favorite_list').html(data.list);
}
});
}
}); // end of $()
/**
* Submits the form placed in place of a link due to the excessive url length
*
* @param $link anchor
* @returns {Boolean}
*/
function submitFormLink($link)
{
if ($link.attr('href').indexOf('=') != -1) {
var data = $link.attr('href').substr($link.attr('href').indexOf('#') + 1).split('=', 2);
$link.parents('form').append('
');
}
$link.parents('form').submit();
}
/**
* Initializes slider effect.
*/
function PMA_init_slider()
{
$('div.pma_auto_slider').each(function () {
var $this = $(this);
if ($this.data('slider_init_done')) {
return;
}
var $wrapper = $('
', {'class': 'slide-wrapper'});
$wrapper.toggle($this.is(':visible'));
$('
', {href: '#' + this.id, "class": 'ajax'})
.text($this.attr('title'))
.prepend($(''))
.insertBefore($this)
.click(function () {
var $wrapper = $this.closest('.slide-wrapper');
var visible = $this.is(':visible');
if (!visible) {
$wrapper.show();
}
$this[visible ? 'hide' : 'show']('blind', function () {
$wrapper.toggle(!visible);
$wrapper.parent().toggleClass("print_ignore", visible);
PMA_set_status_label($this);
});
return false;
});
$this.wrap($wrapper);
$this.removeAttr('title');
PMA_set_status_label($this);
$this.data('slider_init_done', 1);
});
}
/**
* Initializes slider effect.
*/
AJAX.registerOnload('functions.js', function () {
PMA_init_slider();
});
/**
* Restores sliders to the state they were in before initialisation.
*/
AJAX.registerTeardown('functions.js', function () {
$('div.pma_auto_slider').each(function () {
var $this = $(this);
$this.removeData();
$this.parent().replaceWith($this);
$this.parent().children('a').remove();
});
});
/**
* Creates a message inside an object with a sliding effect
*
* @param msg A string containing the text to display
* @param $obj a jQuery object containing the reference
* to the element where to put the message
* This is optional, if no element is
* provided, one will be created below the
* navigation links at the top of the page
*
* @return bool True on success, false on failure
*/
function PMA_slidingMessage(msg, $obj)
{
if (msg === undefined || msg.length === 0) {
// Don't show an empty message
return false;
}
if ($obj === undefined || ! $obj instanceof jQuery || $obj.length === 0) {
// If the second argument was not supplied,
// we might have to create a new DOM node.
if ($('#PMA_slidingMessage').length === 0) {
$('#page_content').prepend(
''
);
}
$obj = $('#PMA_slidingMessage');
}
if ($obj.has('div').length > 0) {
// If there already is a message inside the
// target object, we must get rid of it
$obj
.find('div')
.first()
.fadeOut(function () {
$obj
.children()
.remove();
$obj
.append('' + msg + '
');
// highlight any sql before taking height;
PMA_highlightSQL($obj);
$obj.find('div')
.first()
.hide();
$obj
.animate({
height: $obj.find('div').first().height()
})
.find('div')
.first()
.fadeIn();
});
} else {
// Object does not already have a message
// inside it, so we simply slide it down
$obj.width('100%')
.html('' + msg + '
');
// highlight any sql before taking height;
PMA_highlightSQL($obj);
var h = $obj
.find('div')
.first()
.hide()
.height();
$obj
.find('div')
.first()
.css('height', 0)
.show()
.animate({
height: h
}, function () {
// Set the height of the parent
// to the height of the child
$obj
.height(
$obj
.find('div')
.first()
.height()
);
});
}
return true;
} // end PMA_slidingMessage()
/**
* Attach CodeMirror2 editor to SQL edit area.
*/
AJAX.registerOnload('functions.js', function () {
var $elm = $('#sqlquery');
if ($elm.length > 0) {
if (typeof CodeMirror != 'undefined') {
codemirror_editor = PMA_getSQLEditor($elm);
codemirror_editor.focus();
codemirror_editor.on("blur", updateQueryParameters);
} else {
// without codemirror
$elm.focus()
.bind('blur', updateQueryParameters);
}
}
PMA_highlightSQL($('body'));
});
AJAX.registerTeardown('functions.js', function () {
if (codemirror_editor) {
$('#sqlquery').text(codemirror_editor.getValue());
codemirror_editor.toTextArea();
codemirror_editor = false;
}
});
AJAX.registerOnload('functions.js', function () {
// initializes all lock-page elements lock-id and
// val-hash data property
$('#page_content form.lock-page textarea, ' +
'#page_content form.lock-page input[type="text"], '+
'#page_content form.lock-page input[type="number"], '+
'#page_content form.lock-page select').each(function (i) {
$(this).data('lock-id', i);
// val-hash is the hash of default value of the field
// so that it can be compared with new value hash
// to check whether field was modified or not.
$(this).data('val-hash', AJAX.hash($(this).val()));
});
// initializes lock-page elements (input types checkbox and radio buttons)
// lock-id and val-hash data property
$('#page_content form.lock-page input[type="checkbox"], ' +
'#page_content form.lock-page input[type="radio"]').each(function (i) {
$(this).data('lock-id', i);
$(this).data('val-hash', AJAX.hash($(this).is(":checked")));
});
});
/**
* jQuery plugin to correctly filter input fields by value, needed
* because some nasty values may break selector syntax
*/
(function ($) {
$.fn.filterByValue = function (value) {
return this.filter(function () {
return $(this).val() === value;
});
};
})(jQuery);
/**
* Return value of a cell in a table.
*/
function PMA_getCellValue(td) {
var $td = $(td);
if ($td.is('.null')) {
return '';
} else if ((! $td.is('.to_be_saved')
|| $td.is('.set'))
&& $td.data('original_data')
) {
return $td.data('original_data');
} else {
return $td.text();
}
}
$(window).on('popstate', function (event, data) {
$('#printcss').attr('media','print');
return true;
});
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$(document).off('click', 'a.themeselect');
$(document).off('change', '.autosubmit');
$('a.take_theme').unbind('click');
});
AJAX.registerOnload('functions.js', function () {
/**
* Theme selector.
*/
$(document).on('click', 'a.themeselect', function (e) {
window.open(
e.target,
'themes',
'left=10,top=20,width=510,height=350,scrollbars=yes,status=yes,resizable=yes'
);
return false;
});
/**
* Automatic form submission on change.
*/
$(document).on('change', '.autosubmit', function (e) {
$(this).closest('form').submit();
});
/**
* Theme changer.
*/
$('a.take_theme').click(function (e) {
var what = this.name;
if (window.opener && window.opener.document.forms.setTheme.elements.set_theme) {
window.opener.document.forms.setTheme.elements.set_theme.value = what;
window.opener.document.forms.setTheme.submit();
window.close();
return false;
}
return true;
});
});
/**
* Produce print preview
*/
function printPreview()
{
$('#printcss').attr('media','all');
createPrintAndBackButtons();
}
/**
* Create print and back buttons in preview page
*/
function createPrintAndBackButtons() {
var back_button = $("",{
type: 'button',
value: PMA_messages.back,
id: 'back_button_print_view'
});
back_button.click(removePrintAndBackButton);
back_button.appendTo('#page_content');
var print_button = $("",{
type: 'button',
value: PMA_messages.print,
id: 'print_button_print_view'
});
print_button.click(printPage);
print_button.appendTo('#page_content');
}
/**
* Remove print and back buttons and revert to normal view
*/
function removePrintAndBackButton(){
$('#printcss').attr('media','print');
$('#back_button_print_view').remove();
$('#print_button_print_view').remove();
}
/**
* Print page
*/
function printPage(){
if (typeof(window.print) != 'undefined') {
window.print();
}
}
/**
* Print button
*/
function copyToClipboard()
{
var textArea = document.createElement("textarea");
//
// *** This styling is an extra step which is likely not required. ***
//
// Why is it here? To ensure:
// 1. the element is able to have focus and selection.
// 2. if element was to flash render it has minimal visual impact.
// 3. less flakyness with selection and copying which **might** occur if
// the textarea element is not visible.
//
// The likelihood is the element won't even render, not even a flash,
// so some of these are just precautions. However in IE the element
// is visible whilst the popup box asking the user for permission for
// the web page to copy to the clipboard.
//
// Place in top-left corner of screen regardless of scroll position.
textArea.style.position = 'fixed';
textArea.style.top = 0;
textArea.style.left = 0;
// Ensure it has a small width and height. Setting to 1px / 1em
// doesn't work as this gives a negative w/h on some browsers.
textArea.style.width = '2em';
textArea.style.height = '2em';
// We don't need padding, reducing the size if it does flash render.
textArea.style.padding = 0;
// Clean up any borders.
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
// Avoid flash of white box if rendered for any reason.
textArea.style.background = 'transparent';
textArea.value = '';
var elementList = $('#serverinfo a');
elementList.each(function(){
textArea.value += $(this).text().split(':')[1].trim() + '/';
});
textArea.value += '\t\t' + window.location.href;
textArea.value += '\n';
elementList = $('.notice,.success');
elementList.each(function(){
textArea.value += $(this).clone().children().remove().end().text() + '\n\n';
});
elementList = $('.sql pre');
elementList.each(function() {
textArea.value += $(this).text() + '\n\n';
});
elementList = $('.table_results .column_heading a');
elementList.each(function() {
textArea.value += $(this).clone().children().remove().end().text() + '\t';
});
textArea.value += '\n';
elementList = $('tbody .odd,tbody .even');
elementList.each(function() {
var childElementList = $(this).find('.data span');
childElementList.each(function(){
textArea.value += $(this).clone().children().remove().end().text() + '\t';
});
textArea.value += '\n';
});
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
} catch (err) {
alert('Sorry! Unable to copy');
}
document.body.removeChild(textArea);
}
/**
* Unbind all event handlers before tearing down a page
*/
AJAX.registerTeardown('functions.js', function () {
$('input#print').unbind('click');
$(document).off('click', 'a.create_view.ajax');
$(document).off('keydown', '#createViewDialog input, #createViewDialog select');
$(document).off('change', '#fkc_checkbox');
});
AJAX.registerOnload('functions.js', function () {
$('input#print').click(printPage);
/**
* Ajaxification for the "Create View" action
*/
$(document).on('click', 'a.create_view.ajax', function (e) {
e.preventDefault();
PMA_createViewDialog($(this));
});
/**
* Attach Ajax event handlers for input fields in the editor
* and used to submit the Ajax request when the ENTER key is pressed.
*/
if ($('#createViewDialog').length !== 0) {
$(document).on('keydown', '#createViewDialog input, #createViewDialog select', function (e) {
if (e.which === 13) { // 13 is the ENTER key
e.preventDefault();
// with preventing default, selection by