adminerevo/adminer/static/editing.js

398 lines
11 KiB
JavaScript
Raw Normal View History

// Adminer specific functions
/** Load syntax highlighting
* @param string first three characters of MySQL version
*/
function bodyLoad(version) {
var jushRoot = '../externals/jush/';
var script = document.createElement('script');
script.src = jushRoot + 'jush.js';
script.onload = function () {
if (window.jush) { // IE runs in case of an error too
jush.create_links = ' target="_blank"';
jush.urls.sql[0] = 'http://dev.mysql.com/doc/refman/' + version + '/en/$key';
jush.urls.sqlset[0] = jush.urls.sql[0];
jush.urls.sqlstatus[0] = jush.urls.sql[0];
jush.style(jushRoot + 'jush.css');
jush.highlight_tag('pre', 0);
jush.highlight_tag('code');
}
};
script.onreadystatechange = function () {
if (/^(loaded|complete)$/.test(script.readyState)) {
script.onload();
}
};
document.body.appendChild(script);
}
/** Get value of select
* @param HTMLSelectElement
* @return string
*/
function selectValue(select) {
return select.value || select.options[select.selectedIndex].text;
}
/** Get value of dynamically created form field
* @param HTMLFormElement
* @param string
* @return HTMLElement
*/
function formField(form, name) {
for (var i=0; i < form.length; i++) {
if (form[i].name == name) {
return form[i];
}
}
}
/** Try to change input type to password or to text
* @param HTMLInputElement
* @param boolean
*/
function typePassword(el, disable) {
try {
el.type = (disable ? 'text' : 'password');
} catch (e) {
}
}
var added = '.', rowCount;
/** Escape string to use in regular expression
* @param string
* @return string
*/
function reEscape(s) {
return s.replace(/[\[\]\\^$*+?.(){|}]/, '\\$&');
}
/** Escape string to use as identifier
* @param string
* @return string
*/
function idfEscape(s) {
return '`' + s.replace(/`/, '``') + '`';
}
/** Detect foreign key
* @param HTMLInputElement
*/
function editingNameChange(field) {
var name = field.name.substr(0, field.name.length - 7);
var type = formField(field.form, name + '[type]');
var opts = type.options;
var table = reEscape(field.value);
var column = '';
var match;
if ((match = /(.+)_(.+)/.exec(table)) || (match = /(.*[a-z])([A-Z].*)/.exec(table))) { // limited to single word columns
table = match[1];
column = match[2];
}
var plural = '(?:e?s)?';
var tabCol = table + plural + '_?' + column;
var re = new RegExp('(^' + idfEscape(table + plural) + '\\.' + idfEscape(column) + '$' // table_column
+ '|^' + idfEscape(tabCol) + '\\.' // table
+ '|^' + idfEscape(column + plural) + '\\.' + idfEscape(table) + '$' // column_table
+ ')|\\.' + idfEscape(tabCol) + '$' // column
, 'i');
var candidate; // don't select anything with ambiguous match (like column `id`)
for (var i = opts.length; i--; ) {
if (opts[i].value.substr(0, 1) != '`') { // common type
if (i == opts.length - 2 && candidate && !match[1] && name == 'fields[1]') { // single target table, link to column, first field - probably `id`
return false;
}
break;
}
if (match = re.exec(opts[i].value)) {
if (candidate) {
return false;
}
candidate = i;
}
}
if (candidate) {
type.selectedIndex = candidate;
type.onchange();
}
}
/** Add table row for next field
* @param HTMLInputElement
* @param boolean
* @param boolean
* @return boolean
*/
function editingAddRow(button, allowed, focus) {
if (allowed && rowCount >= allowed) {
return false;
}
var match = /([0-9]+)(\.[0-9]+)?/.exec(button.name);
var x = match[0] + (match[2] ? added.substr(match[2].length) : added) + '1';
var row = button.parentNode.parentNode;
var row2 = row.cloneNode(true);
var tags = row.getElementsByTagName('select');
var tags2 = row2.getElementsByTagName('select');
for (var i=0; i < tags.length; i++) {
tags2[i].name = tags[i].name.replace(/([0-9.]+)/, x);
tags2[i].selectedIndex = tags[i].selectedIndex;
}
tags = row.getElementsByTagName('input');
tags2 = row2.getElementsByTagName('input');
var input = tags2[0]; // IE loose tags2 after insertBefore()
for (var i=0; i < tags.length; i++) {
if (tags[i].name == 'auto_increment_col') {
tags2[i].value = x;
tags2[i].checked = false;
}
tags2[i].name = tags[i].name.replace(/([0-9.]+)/, x);
if (/\[(orig|field|comment|default)/.test(tags[i].name)) {
tags2[i].value = '';
}
if (/\[(has_default)/.test(tags[i].name)) {
tags2[i].checked = false;
}
}
tags[0].onchange = function () {
editingNameChange(tags[0]);
};
row.parentNode.insertBefore(row2, row.nextSibling);
if (focus) {
input.onchange = function () {
editingNameChange(input);
};
input.focus();
}
added += '0';
rowCount++;
return true;
}
/** Remove table row for field
* @param HTMLInputElement
* @return boolean
*/
function editingRemoveRow(button) {
var field = formField(button.form, button.name.replace(/drop_col(.+)/, 'fields$1[field]'));
field.parentNode.removeChild(field);
button.parentNode.parentNode.style.display = 'none';
return true;
}
var lastType = '';
/** Clear length and hide collation or unsigned
* @param HTMLSelectElement
*/
function editingTypeChange(type) {
var name = type.name.substr(0, type.name.length - 6);
var text = selectValue(type);
for (var i=0; i < type.form.elements.length; i++) {
var el = type.form.elements[i];
if (el.name == name + '[length]' && !(
(/(char|binary)$/.test(lastType) && /(char|binary)$/.test(text))
|| (/(enum|set)$/.test(lastType) && /(enum|set)$/.test(text))
)) {
el.value = '';
}
if (el.name == name + '[collation]') {
el.className = (/(char|text|enum|set)$/.test(text) ? '' : 'hidden');
}
if (el.name == name + '[unsigned]') {
el.className = (/(int|float|double|decimal)$/.test(text) ? '' : 'hidden');
}
}
}
/** Edit enum or set
* @param HTMLInputElement
*/
function editingLengthFocus(field) {
var td = field.parentNode;
if (/(enum|set)$/.test(selectValue(td.previousSibling.firstChild))) {
var edit = document.getElementById('enum-edit');
var val = field.value;
edit.value = (/^'.+','.+'$/.test(val) ? val.substr(1, val.length - 2).replace(/','/g, "\n").replace(/''/g, "'") : val);
td.appendChild(edit);
field.style.display = 'none';
edit.style.display = 'inline';
edit.focus();
}
}
/** Finish editing of enum or set
* @param HTMLTextAreaElement
*/
function editingLengthBlur(edit) {
var field = edit.parentNode.firstChild;
var val = edit.value;
field.value = (/\n/.test(val) ? "'" + val.replace(/\n+$/, '').replace(/'/g, "''").replace(/\n/g, "','") + "'" : val);
field.style.display = 'inline';
edit.style.display = 'none';
}
/** Show or hide selected table column
* @param boolean
* @param number
*/
function columnShow(checked, column) {
var trs = document.getElementById('edit-fields').getElementsByTagName('tr');
for (var i=0; i < trs.length; i++) {
trs[i].getElementsByTagName('td')[column].className = (checked ? '' : 'hidden');
}
}
/** Display partition options
* @param HTMLSelectElement
*/
function partitionByChange(el) {
var partitionTable = /RANGE|LIST/.test(selectValue(el));
el.form['partitions'].className = (partitionTable || !el.selectedIndex ? 'hidden' : '');
document.getElementById('partition-table').className = (partitionTable ? '' : 'hidden');
}
/** Add next partition row
* @param HTMLInputElement
*/
function partitionNameChange(el) {
var row = el.parentNode.parentNode.cloneNode(true);
row.firstChild.firstChild.value = '';
el.parentNode.parentNode.parentNode.appendChild(row);
el.onchange = function () {};
}
/** Add row for foreign key
* @param HTMLSelectElement
*/
function foreignAddRow(field) {
var row = field.parentNode.parentNode.cloneNode(true);
var selects = row.getElementsByTagName('select');
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/\]/, '1$&');
selects[i].selectedIndex = 0;
}
field.parentNode.parentNode.parentNode.appendChild(row);
field.onchange = function () { };
}
/** Add row for indexes
* @param HTMLSelectElement
*/
function indexesAddRow(field) {
var row = field.parentNode.parentNode.cloneNode(true);
var spans = row.getElementsByTagName('span');
for (var i=0; i < spans.length - 1; i++) {
row.removeChild(spans[i]);
}
var selects = row.getElementsByTagName('select');
for (var i=0; i < selects.length; i++) {
selects[i].name = selects[i].name.replace(/indexes\[[0-9]+/, '$&1');
selects[i].selectedIndex = 0;
}
var input = row.getElementsByTagName('input')[0];
input.name = input.name.replace(/indexes\[[0-9]+/, '$&1');
input.value = '';
field.parentNode.parentNode.parentNode.appendChild(row);
field.onchange = function () { };
}
/** Add column for index
* @param HTMLSelectElement
*/
function indexesAddColumn(field) {
var column = field.parentNode.cloneNode(true);
var select = column.getElementsByTagName('select')[0];
select.name = select.name.replace(/\]\[[0-9]+/, '$&1');
select.selectedIndex = 0;
var input = column.getElementsByTagName('input')[0];
input.name = input.name.replace(/\]\[[0-9]+/, '$&1');
input.value = '';
field.parentNode.parentNode.appendChild(column);
field.onchange = function () { };
}
var that, x, y, em, tablePos;
/** Get mouse position
* @param HTMLElement
* @param MouseEvent
*/
function schemaMousedown(el, event) {
that = el;
x = event.clientX - el.offsetLeft;
y = event.clientY - el.offsetTop;
}
/** Move object
* @param MouseEvent
*/
function schemaMousemove(ev) {
if (that !== undefined) {
ev = ev || event;
var left = (ev.clientX - x) / em;
var top = (ev.clientY - y) / em;
var divs = that.getElementsByTagName('div');
var lineSet = { };
for (var i=0; i < divs.length; i++) {
if (divs[i].className == 'references') {
var div2 = document.getElementById((divs[i].id.substr(0, 4) == 'refs' ? 'refd' : 'refs') + divs[i].id.substr(4));
var ref = (tablePos[divs[i].title] ? tablePos[divs[i].title] : [ div2.parentNode.offsetTop / em, 0 ]);
var left1 = -1;
var isTop = true;
var id = divs[i].id.replace(/^ref.(.+)-.+/, '$1');
if (divs[i].parentNode != div2.parentNode) {
left1 = Math.min(0, ref[1] - left) - 1;
divs[i].style.left = left1 + 'em';
divs[i].getElementsByTagName('div')[0].style.width = -left1 + 'em';
var left2 = Math.min(0, left - ref[1]) - 1;
div2.style.left = left2 + 'em';
div2.getElementsByTagName('div')[0].style.width = -left2 + 'em';
isTop = (div2.offsetTop + ref[0] * em > divs[i].offsetTop + top * em);
}
if (!lineSet[id]) {
var line = document.getElementById(divs[i].id.replace(/^....(.+)-[0-9]+$/, 'refl$1'));
var shift = ev.clientY - y - that.offsetTop;
line.style.left = (left + left1) + 'em';
if (isTop) {
line.style.top = (line.offsetTop + shift) / em + 'em';
}
if (divs[i].parentNode != div2.parentNode) {
line = line.getElementsByTagName('div')[0];
line.style.height = (line.offsetHeight + (isTop ? -1 : 1) * shift) / em + 'em';
}
lineSet[id] = true;
}
}
}
that.style.left = left + 'em';
that.style.top = top + 'em';
}
}
/** Finish move
* @param MouseEvent
*/
function schemaMouseup(ev) {
if (that !== undefined) {
ev = ev || event;
tablePos[that.firstChild.firstChild.firstChild.data] = [ (ev.clientY - y) / em, (ev.clientX - x) / em ];
that = undefined;
var s = '';
for (var key in tablePos) {
s += '_' + key + ':' + Math.round(tablePos[key][0] * 10000) / 10000 + 'x' + Math.round(tablePos[key][1] * 10000) / 10000;
}
cookie('adminer_schema=' + encodeURIComponent(s.substr(1)), 30, '; path="' + location.pathname + location.search + '"');
}
}