/* -------------------- configuration -------------------- */ /* * The key below needs to be set individually by you if you want to use the Dropbox load/save feature. * To do that, first sign up with Dropbox (may require a specific developer / SDK sign-up), go to * https://www.dropbox.com/developers/apps and use "Create app" to add a new app. Call it, for instance, * "wwwsqldesigner", and give it the "App Folder" permission. Unter "OAuth 2", "Redirect URIs", add * the URL to the "dropbox-oauth-receiver.html" file on your server. E.g, if you install wwwsqldesigner * on your local web server under "http://localhost/sqldesigner/", then add * http://localhost/sqldesigner/dropbox-oauth-receiver.html as a Redirection URI. * Copy the shown "App key" and paste it here below: */ var dropboxAppKey = null; // "your app key"; /* -------------------- globals -------------------- */ function _(str) { /* getText */ if (!(str in window.LOCALE)) { return str; } return window.LOCALE[str]; } if (typeof String.prototype.endsWith !== 'function') { String.prototype.endsWith = function(suffix) { return this.indexOf(suffix, this.length - suffix.length) !== -1; }; } var DATATYPES = false; var LOCALE = {}; var SQL = {}; /* -------------------- base visual element -------------------- */ SQL.Visual = OZ.Class(); /* abstract parent */ SQL.Visual.prototype.init = function() { this._init(); this._build(); } SQL.Visual.prototype._init = function() { this.dom = { container: null, title: null }; this.data = { title:"" } } SQL.Visual.prototype._build = function() {} SQL.Visual.prototype.toXML = function() {} SQL.Visual.prototype.fromXML = function(node) {} SQL.Visual.prototype.destroy = function() { /* "destructor" */ var p = this.dom.container.parentNode; if (p && p.nodeType == 1) { p.removeChild(this.dom.container); } } SQL.Visual.prototype.setTitle = function(text) { if (!text) { return; } this.data.title = text; this.dom.title.innerHTML = text; } SQL.Visual.prototype.getTitle = function() { return this.data.title; } SQL.Visual.prototype.redraw = function() {} /* --------------------- table row ( = db column) ------------ */ SQL.Row = OZ.Class().extend(SQL.Visual); SQL.Row.prototype.init = function(owner, title, data) { this.owner = owner; this.relations = []; this.keys = []; this.selected = false; this.expanded = false; SQL.Visual.prototype.init.apply(this); this.data.type = 0; this.data.size = ""; this.data.def = null; this.data.nll = true; this.data.ai = false; this.data.comment = ""; if (data) { this.update(data); } this.setTitle(title); } SQL.Row.prototype._build = function() { this.dom.container = OZ.DOM.elm("tbody"); this.dom.content = OZ.DOM.elm("tr"); this.dom.selected = OZ.DOM.elm("div", {className:"selected",innerHTML:"» "}); this.dom.title = OZ.DOM.elm("div", {className:"title"}); var td1 = OZ.DOM.elm("td"); var td2 = OZ.DOM.elm("td", {className:"typehint"}); this.dom.typehint = td2; OZ.DOM.append( [this.dom.container, this.dom.content], [this.dom.content, td1, td2], [td1, this.dom.selected, this.dom.title] ); this.enter = this.bind(this.enter); this.changeComment = this.bind(this.changeComment); OZ.Event.add(this.dom.container, "click",this.bind(this.click)); OZ.Event.add(this.dom.container, "dblclick",this.bind(this.dblclick)); } SQL.Row.prototype.select = function() { if (this.selected) { return; } this.selected = true; this.redraw(); } SQL.Row.prototype.deselect = function() { if (!this.selected) { return; } this.selected = false; this.redraw(); this.collapse(); } SQL.Row.prototype.setTitle = function(t) { var old = this.getTitle(); for (var i=0;i\n'; var elm = this.getDataType(); var t = elm.getAttribute("sql"); if (this.data.size.length) { t += "("+this.data.size+")"; } xml += ""+t+"\n"; if (this.data.def || this.data.def === null) { var q = elm.getAttribute("quote"); var d = this.data.def; if (d === null) { d = "NULL"; } else if (d != "CURRENT_TIMESTAMP") { d = q+d+q; } xml += ""+d+""; } for (var i=0;i\n'; } if (this.data.comment) { var escaped = this.data.comment.replace(/&/g, "&").replace(/>/g, ">").replace(/\n"; } xml += "\n"; return xml; } SQL.Row.prototype.fromXML = function(node) { var name = node.getAttribute("name"); var obj = { type:0, size:"" }; obj.nll = (node.getAttribute("null") == "1"); obj.ai = (node.getAttribute("autoincrement") == "1"); var cs = node.getElementsByTagName("comment"); if (cs.length && cs[0].firstChild) { obj.comment = cs[0].firstChild.nodeValue; } var d = node.getElementsByTagName("datatype"); if (d.length && d[0].firstChild) { var s = d[0].firstChild.nodeValue; var r = s.match(/^([^\(]+)(\((.*)\))?.*$/); var type = r[1]; if (r[3]) { obj.size = r[3]; } var types = window.DATATYPES.getElementsByTagName("type"); for (var i=0;i 0; } SQL.Row.prototype.enter = function(e) { if (e.keyCode == 13) { this.collapse(); } } /* --------------------------- relation (connector) ----------- */ SQL.Relation = OZ.Class().extend(SQL.Visual); SQL.Relation._counter = 0; SQL.Relation.prototype.init = function(owner, row1, row2) { this.owner = owner; this.row1 = row1; this.row2 = row2; this.color = "#000"; this.hidden = false; SQL.Visual.prototype.init.apply(this); /* if one of the rows already has relations, inherit color */ var all = row1.relations.concat(row2.relations); if (all.length) { /* inherit */ this.color = all[0].getColor(); } else if (CONFIG.RELATION_COLORS) { /* pick next */ this.constructor._counter++; var colorIndex = this.constructor._counter - 1; this.color = CONFIG.RELATION_COLORS[colorIndex % CONFIG.RELATION_COLORS.length]; } this.row1.addRelation(this); this.row2.addRelation(this); this.dom = []; if (this.owner.vector) { var path = document.createElementNS(this.owner.svgNS, "path"); path.setAttribute("stroke", this.color); path.setAttribute("stroke-width", CONFIG.RELATION_THICKNESS); path.setAttribute("fill", "none"); this.owner.dom.svg.appendChild(path); this.dom.push(path); } else { for (var i=0;i<3;i++) { var div = OZ.DOM.elm("div",{position:"absolute",className:"relation",backgroundColor:this.color}); this.dom.push(div); if (i & 1) { /* middle */ OZ.Style.set(div, {width:CONFIG.RELATION_THICKNESS+"px"}); } else { /* first & last */ OZ.Style.set(div, {height:CONFIG.RELATION_THICKNESS+"px"}); } this.owner.dom.container.appendChild(div); } } this.redraw(); } SQL.Relation.prototype.getColor = function() { return this.color; } SQL.Relation.prototype.show = function() { this.hidden = false; for (var i=0;i\n'; for (var i=0;i/g, ">").replace(/\n"; } xml += "\n"; return xml; } SQL.Table.prototype.fromXML = function(node) { var name = node.getAttribute("name"); this.setTitle(name); var x = parseInt(node.getAttribute("x")) || 0; var y = parseInt(node.getAttribute("y")) || 0; this.moveTo(x, y); var rows = node.getElementsByTagName("row"); for (var i=0;i 1) { return; } var event = e.touches[0]; } else { var event = e; } for (var i=0;i\n'; for (var i=0;i\n'; } xml += '\n'; return xml; } SQL.Key.prototype.fromXML = function(node) { this.setType(node.getAttribute("type")); this.setName(node.getAttribute("name")); var parts = node.getElementsByTagName("part"); for (var i=0;i 1) { return; } var event = e.touches[0]; } else { var event = e; } var dx = event.clientX - this.x; var dy = event.clientY - this.y; if (this.l + dx < 0) { dx = -this.l; } if (this.t + dy < 0) { dy = -this.t; } if (this.l + this.w + 4 + dx > this.width) { dx = this.width - 4 - this.l - this.w; } if (this.t + this.h + 4 + dy > this.height) { dy = this.height - 4 - this.t - this.h; } this.x += dx; this.y += dy; this.l += dx; this.t += dy; var coefX = this.width / this.owner.width; var coefY = this.height / this.owner.height; var left = this.l / coefX; var top = this.t / coefY; if (OZ.webkit) { document.body.scrollLeft = Math.round(left); document.body.scrollTop = Math.round(top); } else { document.documentElement.scrollLeft = Math.round(left); document.documentElement.scrollTop = Math.round(top); } this.redraw(); } SQL.Map.prototype.up = function(e) { /* mouseup */ this.flag = false; this.dom.container.style.cursor = ""; OZ.Event.remove(this.documentMove); OZ.Event.remove(this.documentUp); } SQL.Map.prototype.sync = function() { /* when window changes, adjust map */ var dims = OZ.DOM.win(); var scroll = OZ.DOM.scroll(); var scaleX = this.width / this.owner.width; var scaleY = this.height / this.owner.height; var w = dims[0] * scaleX - 4 - 0; var h = dims[1] * scaleY - 4 - 0; var x = scroll[0] * scaleX; var y = scroll[1] * scaleY; this.w = Math.round(w); this.h = Math.round(h); this.l = Math.round(x); this.t = Math.round(y); this.redraw(); } SQL.Map.prototype.redraw = function() { this.dom.port.style.width = this.w+"px"; this.dom.port.style.height = this.h+"px"; this.dom.port.style.left = this.l+"px"; this.dom.port.style.top = this.t+"px"; } /* --------------------- io ------------ */ SQL.IO = OZ.Class(); SQL.IO.prototype.init = function(owner) { this.owner = owner; this._name = ""; /* last used keyword */ this.dom = { container:OZ.$("io") }; var ids = ["saveload","clientlocalsave", "clientsave", "clientlocalload", "clientlocallist","clientload", "clientsql", "clientdropboxsave", "clientdropboxload", "clientdropboxlist", "quicksave", "serversave", "serverload", "serverlist", "serverimport"]; for (var i=0;i= (5*1024*1024)/2) { /* this is a very big db structure... */ alert("Warning: your database structure is above 5 megabytes in size, this is above the localStorage single key limit allowed by some browsers, example Mozilla Firefox 10"); return; } var key = prompt(_("serversaveprompt"), this._name); if (!key) { return; } this._name = key; key = "wwwsqldesigner_databases_" + (key || "default"); try { localStorage.setItem(key, xml); if (localStorage.getItem(key) != xml) { throw new Error("Content verification failed"); } } catch (e) { alert("Error saving database structure to localStorage! ("+e.message+")"); } } SQL.IO.prototype.clientlocalload = function() { if (!window.localStorage) { alert("Sorry, your browser does not seem to support localStorage."); return; } var key = prompt(_("serverloadprompt"), this._name); if (!key) { return; } this._name = key; key = "wwwsqldesigner_databases_" + (key || "default"); try { var xml = localStorage.getItem(key); if (!xml) { throw new Error("No data available"); } } catch (e) { alert("Error loading database structure from localStorage! ("+e.message+")"); return; } this.fromXMLText(xml); } SQL.IO.prototype.clientlocallist = function() { if (!window.localStorage) { alert("Sorry, your browser does not seem to support localStorage."); return; } /* --- Define some useful vars --- */ var baseKeysName = "wwwsqldesigner_databases_"; var localLen = localStorage.length; var data = ""; var schemasFound = false; var code = 200; /* --- work --- */ try { for (var i = 0; i< localLen; ++i) { var key = localStorage.key(i); if((new RegExp(baseKeysName)).test(key)) { var result = key.substring(baseKeysName.length); schemasFound = true; data += result + "\n"; } } if (!schemasFound) { throw new Error("No data available"); } } catch (e) { alert("Error loading database names from localStorage! ("+e.message+")"); return; } this.listresponse(data, code); } /* ------------------------- Dropbox start ------------------------ */ /* * The following code uses this lib: https://github.com/dropbox/dropbox-js */ var dropboxClient = null; if (dropboxAppKey) { dropboxClient = new Dropbox.Client({ key: dropboxAppKey }); } else { // Here we should remove the Dropbox buttons but I (TT) honestly don't know how to do that without including something like jquery. } var showDropboxError = function(error) { var prefix = _("Dropbox error")+": "; var msg = error.status; switch (error.status) { case Dropbox.ApiError.INVALID_TOKEN: // If you're using dropbox.js, the only cause behind this error is that // the user token expired. // Get the user through the authentication flow again. msg = _("Invalid Token (expired)"); break; case Dropbox.ApiError.NOT_FOUND: // The file or folder you tried to access is not in the user's Dropbox. // Handling this error is specific to your application. msg = _("File not found"); break; case Dropbox.ApiError.OVER_QUOTA: // The user is over their Dropbox quota. // Tell them their Dropbox is full. Refreshing the page won't help. msg = _("Dropbox is full"); break; case Dropbox.ApiError.RATE_LIMITED: // Too many API requests. Tell the user to try again later. // Long-term, optimize your code to use fewer API calls. break; case Dropbox.ApiError.NETWORK_ERROR: // An error occurred at the XMLHttpRequest layer. // Most likely, the user's network connection is down. // API calls will not succeed until the user gets back online. msg = _("Network error"); break; case Dropbox.ApiError.INVALID_PARAM: case Dropbox.ApiError.OAUTH_ERROR: case Dropbox.ApiError.INVALID_METHOD: default: // Caused by a bug in dropbox.js, in your application, or in Dropbox. // Tell the user an error occurred, ask them to refresh the page. } alert (prefix+msg); }; var showDropboxAuthenticate = function() { if (!dropboxClient) return false; // We want to use a popup window for authentication as the default redirection won't work for us as it'll make us lose our schema data dropboxClient.authDriver(new Dropbox.AuthDriver.Popup({ receiverUrl: "dropbox-oauth-receiver.html" })); // Now let's authenticate us var success = false; dropboxClient.authenticate( function(error, client) { if (error) { showDropboxError(error); return; } success = true; return; }); return success; } SQL.IO.prototype.clientdropboxsave = function() { if (!showDropboxAuthenticate()) return; var key = prompt(_("serversaveprompt"), this._name); if (!key) { return; } if (key.endsWith(".xml")) { // remove ".xml" from name key = key.substr(0, key.length-4); } this._name = key; var filename = (key || "default") + ".xml"; var xml = this.owner.toXML(); dropboxClient.writeFile(filename, xml, function(error, stat) { if (error) { return showDropboxError(error); } alert(filename+" "+_("was saved to Dropbox")); }); } SQL.IO.prototype.clientdropboxload = function() { if (!showDropboxAuthenticate()) return; var key = prompt(_("serverloadprompt"), this._name); if (!key) { return; } if (key.endsWith(".xml")) { // remove ".xml" from name key = key.substr(0, key.length-4); } this._name = key; var filename = (key || "default") + ".xml"; var sql_io = this; dropboxClient.readFile(filename, function(error, data) { if (error) { return showDropboxError(error); } sql_io.fromXMLText(data); }); } SQL.IO.prototype.clientdropboxlist = function() { if (!showDropboxAuthenticate()) return; var sql_io = this; sql_io.listresponse("Loading...", 200); dropboxClient.readdir("/", function(error, entries) { if (error) { sql_io.listresponse("", 200); return showDropboxError(error); } var data = entries.join("\n")+"\n"; sql_io.listresponse(data, 200); }); } /* ------------------------- Dropbox end ------------------------ */ SQL.IO.prototype.clientsql = function() { var bp = this.owner.getOption("staticpath"); var path = bp + "db/"+window.DATATYPES.getAttribute("db")+"/output.xsl"; this.owner.window.showThrobber(); OZ.Request(path, this.bind(this.finish), {xml:true}); } SQL.IO.prototype.finish = function(xslDoc) { this.owner.window.hideThrobber(); var xml = this.owner.toXML(); var sql = ""; try { if (window.XSLTProcessor && window.DOMParser) { var parser = new DOMParser(); var xmlDoc = parser.parseFromString(xml, "text/xml"); var xsl = new XSLTProcessor(); xsl.importStylesheet(xslDoc); var result = xsl.transformToDocument(xmlDoc); sql = result.documentElement.textContent; } else if (window.ActiveXObject || "ActiveXObject" in window) { var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.loadXML(xml); sql = xmlDoc.transformNode(xslDoc); } else { throw new Error("No XSLT processor available"); } } catch(e) { alert(_("xmlerror")+': '+e.message); return; } this.dom.ta.value = sql; } SQL.IO.prototype.serversave = function(e, keyword) { var name = keyword || prompt(_("serversaveprompt"), this._name); if (!name) { return; } this._name = name; var xml = this.owner.toXML(); var bp = this.owner.getOption("xhrpath"); var url = bp + "backend/"+this.dom.backend.value+"/?action=save&keyword="+encodeURIComponent(name); var h = {"Content-type":"application/xml"}; this.owner.window.showThrobber(); this.owner.setTitle(name); OZ.Request(url, this.saveresponse, {xml:true, method:"post", data:xml, headers:h}); } SQL.IO.prototype.quicksave = function(e) { this.serversave(e, this._name); } SQL.IO.prototype.serverload = function(e, keyword) { var name = keyword || prompt(_("serverloadprompt"), this._name); if (!name) { return; } this._name = name; var bp = this.owner.getOption("xhrpath"); var url = bp + "backend/"+this.dom.backend.value+"/?action=load&keyword="+encodeURIComponent(name); this.owner.window.showThrobber(); this.name = name; OZ.Request(url, this.loadresponse, {xml:true}); } SQL.IO.prototype.serverlist = function(e) { var bp = this.owner.getOption("xhrpath"); var url = bp + "backend/"+this.dom.backend.value+"/?action=list"; this.owner.window.showThrobber(); OZ.Request(url, this.listresponse); } SQL.IO.prototype.serverimport = function(e) { var name = prompt(_("serverimportprompt"), ""); if (!name) { return; } var bp = this.owner.getOption("xhrpath"); var url = bp + "backend/"+this.dom.backend.value+"/?action=import&database="+name; this.owner.window.showThrobber(); OZ.Request(url, this.importresponse, {xml:true}); } SQL.IO.prototype.check = function(code) { switch (code) { case 201: case 404: case 500: case 501: case 503: var lang = "http"+code; this.dom.ta.value = _("httpresponse")+": "+_(lang); return false; break; default: return true; } } SQL.IO.prototype.saveresponse = function(data, code) { this.owner.window.hideThrobber(); this.check(code); } SQL.IO.prototype.loadresponse = function(data, code) { this.owner.window.hideThrobber(); if (!this.check(code)) { return; } this.fromXML(data); this.owner.setTitle(this.name); } SQL.IO.prototype.listresponse = function(data, code) { this.owner.window.hideThrobber(); if (!this.check(code)) { return; } this.dom.ta.value = data; } SQL.IO.prototype.importresponse = function(data, code) { this.owner.window.hideThrobber(); if (!this.check(code)) { return; } if (this.fromXML(data)) { this.owner.alignTables(); } } SQL.IO.prototype.press = function(e) { switch (e.keyCode) { case 113: if (OZ.opera) { e.preventDefault(); } this.quicksave(e); break; } } /* --------------------- table manager ------------ */ SQL.TableManager = OZ.Class(); SQL.TableManager.prototype.init = function(owner) { this.owner = owner; this.dom = { container:OZ.$("table"), name:OZ.$("tablename"), comment:OZ.$("tablecomment") }; this.selection = []; this.adding = false; var ids = ["addtable","removetable","aligntables","cleartables","addrow","edittable","tablekeys"]; for (var i=0;i 1) { this.dom.removetable.value = _("removetables"); } } else { this.dom.removetable.disabled = true; this.dom.removetable.value = _("removetable"); } for (var i=0;i=x && tx=x && tx1x1)) && ((ty>=y && ty=y && ty1y1))) { this.selection.push(t); } } this.processSelection(); } SQL.TableManager.prototype.click = function(e) { /* finish adding new table */ var newtable = false; if (this.adding) { this.adding = false; OZ.DOM.removeClass("area","adding"); this.dom.addtable.value = this.oldvalue; var scroll = OZ.DOM.scroll(); var x = e.clientX + scroll[0]; var y = e.clientY + scroll[1]; newtable = this.owner.addTable(_("newtable"),x,y); var r = newtable.addRow("id",{ai:true}); var k = newtable.addKey("PRIMARY",""); k.addRow(r); } this.select(newtable); this.owner.rowManager.select(false); if (this.selection.length == 1) { this.edit(e); } } SQL.TableManager.prototype.preAdd = function(e) { /* click add new table */ if (this.adding) { this.adding = false; OZ.DOM.removeClass("area","adding"); this.dom.addtable.value = this.oldvalue; } else { this.adding = true; OZ.DOM.addClass("area","adding"); this.oldvalue = this.dom.addtable.value; this.dom.addtable.value = "["+_("addpending")+"]"; } } SQL.TableManager.prototype.clear = function(e) { /* remove all tables */ if (!this.owner.tables.length) { return; } var result = confirm(_("confirmall")+" ?"); if (!result) { return; } this.owner.clearTables(); } SQL.TableManager.prototype.remove = function(e) { var titles = this.selection.slice(0); for (var i=0;i=0;i--) { var r = rels[i]; if (r.row2 == this.selected) { this.owner.removeRelation(r); } } this.redraw(); } SQL.RowManager.prototype.endCreate = function() { this.creating = false; this.dom.foreigncreate.value = _("foreigncreate"); } SQL.RowManager.prototype.endConnect = function() { this.connecting = false; this.dom.foreignconnect.value = _("foreignconnect"); } SQL.RowManager.prototype.up = function(e) { this.selected.up(); this.redraw(); } SQL.RowManager.prototype.down = function(e) { this.selected.down(); this.redraw(); } SQL.RowManager.prototype.remove = function(e) { var result = confirm(_("confirmrow")+" '"+this.selected.getTitle()+"' ?"); if (!result) { return; } var t = this.selected.owner; this.selected.owner.removeRow(this.selected); var next = false; if (t.rows) { next = t.rows[t.rows.length-1]; } this.select(next); } SQL.RowManager.prototype.redraw = function() { this.endCreate(); this.endConnect(); if (this.selected) { var table = this.selected.owner; var rows = table.rows; this.dom.uprow.disabled = (rows[0] == this.selected); this.dom.downrow.disabled = (rows[rows.length-1] == this.selected); this.dom.removerow.disabled = false; this.dom.editrow.disabled = false; this.dom.foreigncreate.disabled = !(this.selected.isUnique()); this.dom.foreignconnect.disabled = !(this.selected.isUnique()); this.dom.foreigndisconnect.disabled = true; var rels = this.selected.relations; for (var i=0;i=0;i--) { var k = this.table.keys[i]; if (!k.rows.length) { this.table.removeKey(k); } } } SQL.KeyManager.prototype.sync = function(table) { /* sync content with given table */ this.table = table; this.dom.listlabel.innerHTML = _("keyslistlabel").replace(/%s/,table.getTitle()); OZ.DOM.clear(this.dom.list); for (var i=0;i 1) { this.dom.title.removeChild(this.dom.title.childNodes[1]); } var txt = OZ.DOM.text(title); this.dom.title.appendChild(txt); this.dom.background.style.visibility = "visible"; OZ.DOM.clear(this.dom.content); this.dom.content.appendChild(content); var win = OZ.DOM.win(); var scroll = OZ.DOM.scroll(); this.dom.container.style.left = Math.round(scroll[0] + (win[0] - this.dom.container.offsetWidth)/2)+"px"; this.dom.container.style.top = Math.round(scroll[1] + (win[1] - this.dom.container.offsetHeight)/2)+"px"; this.dom.cancel.style.visibility = (this.callback ? "" : "hidden"); this.dom.container.style.visibility = "visible"; var formElements = ["input","select","textarea"]; var all = this.dom.container.getElementsByTagName("*"); for (var i=0;i max) { max = z; } } OZ.$("controls").style.zIndex = max+5; return max; } SQL.Designer.prototype.addTable = function(name, x, y) { var max = this.getMaxZ(); var t = new SQL.Table(this, name, x, y, max+1); this.tables.push(t); this.dom.container.appendChild(t.dom.container); return t; } SQL.Designer.prototype.removeTable = function(t) { this.tableManager.select(false); this.rowManager.select(false); var idx = this.tables.indexOf(t); if (idx == -1) { return; } t.destroy(); this.tables.splice(idx,1); } SQL.Designer.prototype.addRelation = function(row1, row2) { var r = new SQL.Relation(this, row1, row2); this.relations.push(r); return r; } SQL.Designer.prototype.removeRelation = function(r) { var idx = this.relations.indexOf(r); if (idx == -1) { return; } r.destroy(); this.relations.splice(idx,1); } SQL.Designer.prototype.getCookie = function() { var c = document.cookie; var obj = {}; var parts = c.split(";"); for (var i=0;i old) { t.setZ(t.getZ()-1); } } var m = table.dom.mini; m.parentNode.appendChild(m); } SQL.Designer.prototype.clearTables = function() { while (this.tables.length) { this.removeTable(this.tables[0]); } this.setTitle(false); } SQL.Designer.prototype.alignTables = function() { var win = OZ.DOM.win(); var avail = win[0] - OZ.$("bar").offsetWidth; var x = 10; var y = 10; var max = 0; this.tables.sort(function(a,b){ return b.getRelations().length - a.getRelations().length; }); for (var i=0;i avail) { x = 10; y += 10 + max; max = 0; } t.moveTo(x,y); x += 10 + w; if (h > max) { max = h; } } this.sync(); } SQL.Designer.prototype.findNamedTable = function(name) { /* find row specified as table(row) */ for (var i=0;i\n'; xml += '\n'; /* serialize datatypes */ if (window.XMLSerializer) { var s = new XMLSerializer(); xml += s.serializeToString(window.DATATYPES); } else if (window.DATATYPES.xml) { xml += window.DATATYPES.xml; } else { alert(_("errorxml")+': '+e.message); } for (var i=0;i