Merge remote-tracking branch 'origin/master'

This commit is contained in:
Pootle server 2011-08-12 22:40:21 +02:00
commit b791272247
17 changed files with 2977 additions and 515 deletions

View File

@ -43,6 +43,7 @@ phpMyAdmin - ChangeLog
+ AJAX for table Operations copy table
- bug #3380946 [export] no uid Query result export (Suhosin limit)
+ Grid editing in browse mode (replaces row inline edit)
+ Zoom-search in table Search
3.4.5.0 (not yet released)
- bug #3375325 [interface] Page list in navigation frame looks odd

View File

@ -14,7 +14,7 @@
* This is needed for cookie based authentication to encrypt password in
* cookie
*/
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
$cfg['blowfish_secret'] = 'a8b7c6d'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */
/*
* Servers configuration

View File

@ -57,6 +57,7 @@ require_once './libraries/db_structure.lib.php';
$titles = PMA_buildActionTitles();
// 1. No tables
if ($num_tables == 0) {
echo '<p>' . __('No tables found in database') . '</p>' . "\n";

View File

@ -12,6 +12,7 @@ if(!window.console) {
window.console.dir = function(str) {};
}
// <3 IE
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
@ -27,7 +28,7 @@ if(!Array.indexOf){
// canvg(target, s)
// empty parameters: replace all 'svg' elements on page with 'canvas' elements
// target: canvas element or the id of a canvas element
// s: svg string, url to svg file, or xml document
// s: svg string or url to svg file
// opts: optional hash of options
// ignoreMouse: true => ignore mouse events
// ignoreAnimation: true => ignore animations
@ -74,11 +75,7 @@ if(!Array.indexOf){
svg.opts = opts;
var ctx = target.getContext('2d');
if (typeof(s.documentElement) != 'undefined') {
// load from xml doc
svg.loadXmlDoc(ctx, s);
}
else if (s.substr(0,1) == '<') {
if (s.substr(0,1) == '<') {
// load from xml string
svg.loadXml(ctx, s);
}
@ -92,7 +89,6 @@ if(!Array.indexOf){
var svg = { };
svg.FRAMERATE = 30;
svg.MAX_VIRTUAL_PIXELS = 30000;
// globals
svg.init = function(ctx) {
@ -103,7 +99,6 @@ if(!Array.indexOf){
svg.ctx = ctx;
svg.ViewPort = new (function () {
this.viewPorts = [];
this.Clear = function() { this.viewPorts = []; }
this.SetCurrent = function(width, height) { this.viewPorts.push({ width: width, height: height }); }
this.RemoveCurrent = function() { this.viewPorts.pop(); }
this.Current = function() { return this.viewPorts[this.viewPorts.length - 1]; }
@ -556,7 +551,7 @@ if(!Array.indexOf){
}
}
var data = svg.trim(svg.compressSpaces(v)).split(/\s(?=[a-z])/);
var data = v.split(/\s(?=[a-z])/);
for (var i=0; i<data.length; i++) {
var type = data[i].split('(')[0];
var s = data[i].split('(')[1].replace(')','');
@ -621,7 +616,7 @@ if(!Array.indexOf){
return a;
}
// get or create style, crawls up node tree
// get or create style
this.style = function(name, createIfNotExists) {
var s = this.styles[name];
if (s != null) return s;
@ -630,14 +625,6 @@ if(!Array.indexOf){
if (a != null && a.hasValue()) {
return a;
}
var p = this.parent;
if (p != null) {
var ps = p.style(name);
if (ps != null && ps.hasValue()) {
return ps;
}
}
s = new svg.Property(name, '');
if (createIfNotExists == true) this.styles[name] = s;
@ -648,9 +635,6 @@ if(!Array.indexOf){
this.render = function(ctx) {
// don't render display=none
if (this.attribute('display').value == 'none') return;
// don't render visibility=hidden
if (this.attribute('visibility').value == 'hidden') return;
ctx.save();
this.setContext(ctx);
@ -697,7 +681,7 @@ if(!Array.indexOf){
}
// add tag styles
var styles = svg.Styles[node.nodeName];
var styles = svg.Styles[this.type];
if (styles != null) {
for (var name in styles) {
this.styles[name] = styles[name];
@ -714,12 +698,6 @@ if(!Array.indexOf){
this.styles[name] = styles[name];
}
}
styles = svg.Styles[node.nodeName+'.'+classes[j]];
if (styles != null) {
for (var name in styles) {
this.styles[name] = styles[name];
}
}
}
}
@ -878,7 +856,7 @@ if(!Array.indexOf){
var width = svg.ViewPort.width();
var height = svg.ViewPort.height();
if (typeof(this.root) == 'undefined' && this.attribute('width').hasValue() && this.attribute('height').hasValue()) {
if (this.attribute('width').hasValue() && this.attribute('height').hasValue()) {
width = this.attribute('width').Length.toPixels('x');
height = this.attribute('height').Length.toPixels('y');
@ -1208,6 +1186,9 @@ if(!Array.indexOf){
pp.reset();
var bb = new svg.BoundingBox();
if(this.attribute('visibility').value=='hidden') return;
if (ctx != null) ctx.beginPath();
while (!pp.isEnd()) {
pp.nextCommand();
@ -1488,37 +1469,6 @@ if(!Array.indexOf){
for (var i=0; i<stopsContainer.stops.length; i++) {
g.addColorStop(stopsContainer.stops[i].offset, stopsContainer.stops[i].color);
}
if (this.attribute('gradientTransform').hasValue()) {
// render as transformed pattern on temporary canvas
var rootView = svg.ViewPort.viewPorts[0];
var rect = new svg.Element.rect();
rect.attributes['x'] = new svg.Property('x', -svg.MAX_VIRTUAL_PIXELS/3.0);
rect.attributes['y'] = new svg.Property('y', -svg.MAX_VIRTUAL_PIXELS/3.0);
rect.attributes['width'] = new svg.Property('width', svg.MAX_VIRTUAL_PIXELS);
rect.attributes['height'] = new svg.Property('height', svg.MAX_VIRTUAL_PIXELS);
var group = new svg.Element.g();
group.attributes['transform'] = new svg.Property('transform', this.attribute('gradientTransform').value);
group.children = [ rect ];
var tempSvg = new svg.Element.svg();
tempSvg.attributes['x'] = new svg.Property('x', 0);
tempSvg.attributes['y'] = new svg.Property('y', 0);
tempSvg.attributes['width'] = new svg.Property('width', rootView.width);
tempSvg.attributes['height'] = new svg.Property('height', rootView.height);
tempSvg.children = [ group ];
var c = document.createElement('canvas');
c.width = rootView.width;
c.height = rootView.height;
var tempCtx = c.getContext('2d');
tempCtx.fillStyle = g;
tempSvg.render(tempCtx);
return tempCtx.createPattern(c, 'no-repeat');
}
return g;
}
}
@ -1544,8 +1494,16 @@ if(!Array.indexOf){
var y2 = (this.gradientUnits == 'objectBoundingBox'
? bb.y() + bb.height() * this.attribute('y2').numValue()
: this.attribute('y2').Length.toPixels('y'));
return ctx.createLinearGradient(x1, y1, x2, y2);
var p1 = new svg.Point(x1, y1);
var p2 = new svg.Point(x2, y2);
if (this.attribute('gradientTransform').hasValue()) {
var transform = new svg.Transform(this.attribute('gradientTransform').value);
transform.applyToPoint(p1);
transform.applyToPoint(p2);
}
return ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
}
}
svg.Element.linearGradient.prototype = new svg.Element.GradientBase;
@ -1582,7 +1540,22 @@ if(!Array.indexOf){
? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
: this.attribute('r').Length.toPixels());
return ctx.createRadialGradient(fx, fy, 0, cx, cy, r);
var c = new svg.Point(cx, cy);
var f = new svg.Point(fx, fy);
if (this.attribute('gradientTransform').hasValue()) {
var transform = new svg.Transform(this.attribute('gradientTransform').value);
transform.applyToPoint(c);
transform.applyToPoint(f);
for (var i=0; i<transform.transforms.length; i++) {
// average the scaling part of the transform, apply to radius
var scale1 = transform.transforms[i].m[0];
var scale2 = transform.transforms[i].m[3];
r = r * ((scale1 + scale2) / 2.0);
}
}
return ctx.createRadialGradient(f.x, f.y, 0, c.x, c.y, r);
}
}
svg.Element.radialGradient.prototype = new svg.Element.GradientBase;
@ -1720,73 +1693,6 @@ if(!Array.indexOf){
}
svg.Element.animateTransform.prototype = new svg.Element.animate;
// font element
svg.Element.font = function(node) {
this.base = svg.Element.ElementBase;
this.base(node);
this.horizAdvX = this.attribute('horiz-adv-x').numValue();
this.isRTL = false;
this.isArabic = false;
this.fontFace = null;
this.missingGlyph = null;
this.glyphs = [];
for (var i=0; i<this.children.length; i++) {
var child = this.children[i];
if (child.type == 'font-face') {
this.fontFace = child;
if (child.style('font-family').hasValue()) {
svg.Definitions[child.style('font-family').value] = this;
}
}
else if (child.type == 'missing-glyph') this.missingGlyph = child;
else if (child.type == 'glyph') {
if (child.arabicForm != '') {
this.isRTL = true;
this.isArabic = true;
if (typeof(this.glyphs[child.unicode]) == 'undefined') this.glyphs[child.unicode] = [];
this.glyphs[child.unicode][child.arabicForm] = child;
}
else {
this.glyphs[child.unicode] = child;
}
}
}
}
svg.Element.font.prototype = new svg.Element.ElementBase;
// font-face element
svg.Element.fontface = function(node) {
this.base = svg.Element.ElementBase;
this.base(node);
this.ascent = this.attribute('ascent').value;
this.descent = this.attribute('descent').value;
this.unitsPerEm = this.attribute('units-per-em').numValue();
}
svg.Element.fontface.prototype = new svg.Element.ElementBase;
// missing-glyph element
svg.Element.missingglyph = function(node) {
this.base = svg.Element.path;
this.base(node);
this.horizAdvX = 0;
}
svg.Element.missingglyph.prototype = new svg.Element.path;
// glyph element
svg.Element.glyph = function(node) {
this.base = svg.Element.path;
this.base(node);
this.horizAdvX = this.attribute('horiz-adv-x').numValue();
this.unicode = this.attribute('unicode').value;
this.arabicForm = this.attribute('arabic-form').value;
}
svg.Element.glyph.prototype = new svg.Element.path;
// text element
svg.Element.text = function(node) {
this.base = svg.Element.RenderedElementBase;
@ -1809,16 +1715,19 @@ if(!Array.indexOf){
this.baseSetContext = this.setContext;
this.setContext = function(ctx) {
this.baseSetContext(ctx);
if (this.style('text-anchor').hasValue()) {
var textAnchor = this.style('text-anchor').value;
if (this.attribute('text-anchor').hasValue()) {
var textAnchor = this.attribute('text-anchor').value;
ctx.textAlign = textAnchor == 'middle' ? 'center' : textAnchor;
}
if (this.attribute('alignment-baseline').hasValue()) ctx.textBaseline = this.attribute('alignment-baseline').value;
}
this.renderChildren = function(ctx) {
if(this.attribute('visibility').value=='hidden') return;
var x = this.attribute('x').Length.toPixels('x');
var y = this.attribute('y').Length.toPixels('y');
for (var i=0; i<this.children.length; i++) {
var child = this.children[i];
@ -1850,63 +1759,8 @@ if(!Array.indexOf){
this.base = svg.Element.RenderedElementBase;
this.base(node);
this.getGlyph = function(font, text, i) {
var c = text[i];
var glyph = null;
if (font.isArabic) {
var arabicForm = 'isolated';
if ((i==0 || text[i-1]==' ') && i<text.length-2 && text[i+1]!=' ') arabicForm = 'terminal';
if (i>0 && text[i-1]!=' ' && i<text.length-2 && text[i+1]!=' ') arabicForm = 'medial';
if (i>0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial';
if (typeof(font.glyphs[c]) != 'undefined') {
glyph = font.glyphs[c][arabicForm];
if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c];
}
}
else {
glyph = font.glyphs[c];
}
if (glyph == null) glyph = font.missingGlyph;
return glyph;
}
this.renderChildren = function(ctx) {
var customFont = this.parent.style('font-family').Definition.getDefinition();
if (customFont != null) {
var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);
var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle);
var text = this.getText();
if (customFont.isRTL) text = text.split("").reverse().join("");
if (this.parent.style('text-anchor').value == 'middle') {
this.x = this.x - this.measureText(ctx) / 2.0;
}
var dx = svg.ToNumberArray(this.parent.attribute('dx').value);
for (var i=0; i<text.length; i++) {
var glyph = this.getGlyph(customFont, text, i);
var scale = fontSize / customFont.fontFace.unitsPerEm;
ctx.translate(this.x, this.y);
ctx.scale(scale, -scale);
var lw = ctx.lineWidth;
ctx.lineWidth = ctx.lineWidth * customFont.fontFace.unitsPerEm / fontSize;
if (fontStyle == 'italic') ctx.transform(1, 0, .4, 1, 0, 0);
glyph.render(ctx);
if (fontStyle == 'italic') ctx.transform(1, 0, -.4, 1, 0, 0);
ctx.lineWidth = lw;
ctx.scale(1/scale, -1/scale);
ctx.translate(-this.x, -this.y);
this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / customFont.fontFace.unitsPerEm;
if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) {
this.x += dx[i];
}
}
return;
}
if (ctx.strokeStyle != '') ctx.strokeText(svg.compressSpaces(this.getText()), this.x, this.y);
if (ctx.fillStyle != '') ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);
ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);
}
this.getText = function() {
@ -1914,23 +1768,6 @@ if(!Array.indexOf){
}
this.measureText = function(ctx) {
var customFont = this.parent.style('font-family').Definition.getDefinition();
if (customFont != null) {
var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);
var measure = 0;
var text = this.getText();
if (customFont.isRTL) text = text.split("").reverse().join("");
var dx = svg.ToNumberArray(this.parent.attribute('dx').value);
for (var i=0; i<text.length; i++) {
var glyph = this.getGlyph(customFont, text, i);
measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm;
if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) {
measure += dx[i];
}
}
return measure;
}
var textToMeasure = svg.compressSpaces(this.getText());
if (!ctx.measureText) return textToMeasure.length * 10;
return ctx.measureText(textToMeasure).width;
@ -1943,9 +1780,8 @@ if(!Array.indexOf){
this.base = svg.Element.TextElementBase;
this.base(node);
this.text = node.nodeType == 3 ? node.nodeValue : // text
node.childNodes.length > 0 ? node.childNodes[0].nodeValue : // element
node.text;
// TEXT ELEMENT
this.text = node.nodeType == 3 ? node.nodeValue : node.childNodes[0].nodeValue;
this.getText = function() {
return this.text;
}
@ -2095,9 +1931,8 @@ if(!Array.indexOf){
this.base = svg.Element.ElementBase;
this.base(node);
// text, or spaces then CDATA
var css = node.childNodes[0].nodeValue + (node.childNodes.length > 1 ? node.childNodes[1].nodeValue : '');
css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments
var css = node.childNodes[0].nodeValue;
css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(\/\/.*)/gm, ''); // remove comments
css = svg.compressSpaces(css); // replace whitespace
var cssDefs = css.split('}');
for (var i=0; i<cssDefs.length; i++) {
@ -2110,31 +1945,14 @@ if(!Array.indexOf){
if (cssClass != '') {
var props = {};
for (var k=0; k<cssProps.length; k++) {
var prop = cssProps[k].indexOf(':');
var name = cssProps[k].substr(0, prop);
var value = cssProps[k].substr(prop + 1, cssProps[k].length - prop);
var prop = cssProps[k].split(':');
var name = prop[0];
var value = prop[1];
if (name != null && value != null) {
props[svg.trim(name)] = new svg.Property(svg.trim(name), svg.trim(value));
props[svg.trim(prop[0])] = new svg.Property(svg.trim(prop[0]), svg.trim(prop[1]));
}
}
svg.Styles[cssClass] = props;
if (cssClass == '@font-face') {
var fontFamily = props['font-family'].value.replace(/"/g,'');
var srcs = props['src'].value.split(',');
for (var s=0; s<srcs.length; s++) {
if (srcs[s].indexOf('format("svg")') > 0) {
var urlStart = srcs[s].indexOf('url');
var urlEnd = srcs[s].indexOf(')', urlStart);
var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6);
var doc = svg.parseXml(svg.ajax(url));
var fonts = doc.getElementsByTagName('font');
for (var f=0; f<fonts.length; f++) {
var font = svg.CreateElement(fonts[f]);
svg.Definitions[fontFamily] = font;
}
}
}
}
}
}
}
@ -2186,10 +2004,6 @@ if(!Array.indexOf){
}
}
}
this.render = function(ctx) {
// NO RENDER
}
}
svg.Element.clipPath.prototype = new svg.Element.ElementBase;
@ -2210,8 +2024,7 @@ if(!Array.indexOf){
// element factory
svg.CreateElement = function(node) {
var className = node.nodeName.replace(/^[^:]+:/,''); // remove namespace
className = className.replace(/\-/g,''); // remove dashes
var className = node.nodeName.replace(/^[^:]+:/,'');
var e = null;
if (typeof(svg.Element[className]) != 'undefined') {
e = new svg.Element[className](node);
@ -2231,10 +2044,6 @@ if(!Array.indexOf){
// load from xml
svg.loadXml = function(ctx, xml) {
svg.loadXmlDoc(ctx, svg.parseXml(xml));
}
svg.loadXmlDoc = function(ctx, dom) {
svg.init(ctx);
var mapXY = function(p) {
@ -2261,24 +2070,19 @@ if(!Array.indexOf){
};
}
var dom = svg.parseXml(xml);
var e = svg.CreateElement(dom.documentElement);
e.root = true;
// render loop
var isFirstRender = true;
var draw = function() {
svg.ViewPort.Clear();
if (ctx.canvas.parentNode) svg.ViewPort.SetCurrent(ctx.canvas.parentNode.clientWidth, ctx.canvas.parentNode.clientHeight);
if (svg.opts == null || svg.opts['ignoreDimensions'] != true) {
// set canvas size
if (e.style('width').hasValue()) {
ctx.canvas.width = e.style('width').Length.toPixels('x');
ctx.canvas.style.width = ctx.canvas.width + 'px';
ctx.canvas.width = e.style('width').Length.toPixels(ctx.canvas.parentNode.clientWidth);
}
if (e.style('height').hasValue()) {
ctx.canvas.height = e.style('height').Length.toPixels('y');
ctx.canvas.style.height = ctx.canvas.height + 'px';
ctx.canvas.height = e.style('height').Length.toPixels(ctx.canvas.parentNode.clientHeight);
}
}
svg.ViewPort.SetCurrent(ctx.canvas.clientWidth, ctx.canvas.clientHeight);

288
js/canvg/rgbcolor.js Normal file
View File

@ -0,0 +1,288 @@
/**
* A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com>
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it
*/
function RGBColor(color_string)
{
this.ok = false;
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1,6);
}
color_string = color_string.replace(/ /g,'');
color_string = color_string.toLowerCase();
// before getting into regexps, try simple matches
// and overwrite the input
var simple_colors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred : 'cd5c5c',
indigo : '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
for (var key in simple_colors) {
if (color_string == key) {
color_string = simple_colors[key];
}
}
// emd of simple type-in colors
// array of color definition objects
var color_defs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits){
return [
parseInt(bits[1]),
parseInt(bits[2]),
parseInt(bits[3])
];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process: function (bits){
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process: function (bits){
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
// search through the definitions to find a match
for (var i = 0; i < color_defs.length; i++) {
var re = color_defs[i].re;
var processor = color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
// some getters
this.toRGB = function () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}
this.toHex = function () {
var r = this.r.toString(16);
var g = this.g.toString(16);
var b = this.b.toString(16);
if (r.length == 1) r = '0' + r;
if (g.length == 1) g = '0' + g;
if (b.length == 1) b = '0' + b;
return '#' + r + g + b;
}
// help
this.getHelpXML = function () {
var examples = new Array();
// add regexps
for (var i = 0; i < color_defs.length; i++) {
var example = color_defs[i].example;
for (var j = 0; j < example.length; j++) {
examples[examples.length] = example[j];
}
}
// add type-in colors
for (var sc in simple_colors) {
examples[examples.length] = sc;
}
var xml = document.createElement('ul');
xml.setAttribute('id', 'rgbcolor-examples');
for (var i = 0; i < examples.length; i++) {
try {
var list_item = document.createElement('li');
var list_color = new RGBColor(examples[i]);
var example_div = document.createElement('div');
example_div.style.cssText =
'margin: 3px; '
+ 'border: 1px solid black; '
+ 'background:' + list_color.toHex() + '; '
+ 'color:' + list_color.toHex()
;
example_div.appendChild(document.createTextNode('test'));
var list_item_value = document.createTextNode(
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
);
list_item.appendChild(example_div);
list_item.appendChild(list_item_value);
xml.appendChild(list_item);
} catch(e){}
}
return xml;
}
}

335
js/date.js Normal file
View File

@ -0,0 +1,335 @@
// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================
// HISTORY
// ------------------------------------------------------------------
// May 17, 2003: Fixed bug in parseDate() for dates <1970
// March 11, 2003: Added parseDate() function
// March 11, 2003: Added "NNN" formatting option. Doesn't match up
// perfectly with SimpleDateFormat formats, but
// backwards-compatability was required.
// ------------------------------------------------------------------
// These functions use the same 'format' strings as the
// java.text.SimpleDateFormat class, with minor exceptions.
// The format string consists of the following abbreviations:
//
// Field | Full Form | Short Form
// -------------+--------------------+-----------------------
// Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
// Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
// | NNN (abbr.) |
// Day of Month | dd (2 digits) | d (1 or 2 digits)
// Day of Week | EE (name) | E (abbr)
// Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
// Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
// Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
// Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
// Minute | mm (2 digits) | m (1 or 2 digits)
// Second | ss (2 digits) | s (1 or 2 digits)
// AM/PM | a |
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
// "MMM d, y" matches: January 01, 2000
// Dec 1, 1900
// Nov 20, 00
// "M/d/yy" matches: 01/20/00
// 9/2/00
// "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------
var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}
// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
function isDate(val,format) {
var date=getDateFromFormat(val,format);
if (date==0) { return false; }
return true;
}
// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
// Compare two date strings to see which is greater.
// Returns:
// 1 if date1 is greater than date2
// 0 if date2 is greater than date1 of if they are the same
// -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
function compareDates(date1,dateformat1,date2,dateformat2) {
var d1=getDateFromFormat(date1,dateformat1);
var d2=getDateFromFormat(date2,dateformat2);
if (d1==0 || d2==0) {
return -1;
}
else if (d1 > d2) {
return 1;
}
return 0;
}
// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
function formatDate(date,format) {
format=format+"";
var result="";
var i_format=0;
var c="";
var token="";
var y=date.getYear()+"";
var M=date.getMonth()+1;
var d=date.getDate();
var E=date.getDay();
var H=date.getHours();
var m=date.getMinutes();
var s=date.getSeconds();
var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
// Convert real date parts into formatted versions
var value=new Object();
if (y.length < 4) {y=""+(y-0+1900);}
value["y"]=""+y;
value["yyyy"]=y;
value["yy"]=y.substring(2,4);
value["M"]=M;
value["MM"]=LZ(M);
value["MMM"]=MONTH_NAMES[M-1];
value["NNN"]=MONTH_NAMES[M+11];
value["d"]=d;
value["dd"]=LZ(d);
value["E"]=DAY_NAMES[E+7];
value["EE"]=DAY_NAMES[E];
value["H"]=H;
value["HH"]=LZ(H);
if (H==0){value["h"]=12;}
else if (H>12){value["h"]=H-12;}
else {value["h"]=H;}
value["hh"]=LZ(value["h"]);
if (H>11){value["K"]=H-12;} else {value["K"]=H;}
value["k"]=H+1;
value["KK"]=LZ(value["K"]);
value["kk"]=LZ(value["k"]);
if (H > 11) { value["a"]="PM"; }
else { value["a"]="AM"; }
value["m"]=m;
value["mm"]=LZ(m);
value["s"]=s;
value["ss"]=LZ(s);
while (i_format < format.length) {
c=format.charAt(i_format);
token="";
while ((format.charAt(i_format)==c) && (i_format < format.length)) {
token += format.charAt(i_format++);
}
if (value[token] != null) { result=result + value[token]; }
else { result=result + token; }
}
return result;
}
// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
function _isInteger(val) {
var digits="1234567890";
for (var i=0; i < val.length; i++) {
if (digits.indexOf(val.charAt(i))==-1) { return false; }
}
return true;
}
function _getInt(str,i,minlength,maxlength) {
for (var x=maxlength; x>=minlength; x--) {
var token=str.substring(i,i+x);
if (token.length < minlength) { return null; }
if (_isInteger(token)) { return token; }
}
return null;
}
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
val=val+"";
format=format+"";
var i_val=0;
var i_format=0;
var c="";
var token="";
var token2="";
var x,y;
var now=new Date();
var year=now.getYear();
var month=now.getMonth()+1;
var date=1;
var hh=now.getHours();
var mm=now.getMinutes();
var ss=now.getSeconds();
var ampm="";
while (i_format < format.length) {
// Get next token from format string
c=format.charAt(i_format);
token="";
while ((format.charAt(i_format)==c) && (i_format < format.length)) {
token += format.charAt(i_format++);
}
// Extract contents of value based on format token
if (token=="yyyy" || token=="yy" || token=="y") {
if (token=="yyyy") { x=4;y=4; }
if (token=="yy") { x=2;y=2; }
if (token=="y") { x=2;y=4; }
year=_getInt(val,i_val,x,y);
if (year==null) { return 0; }
i_val += year.length;
if (year.length==2) {
if (year > 70) { year=1900+(year-0); }
else { year=2000+(year-0); }
}
}
else if (token=="MMM"||token=="NNN"){
month=0;
for (var i=0; i<MONTH_NAMES.length; i++) {
var month_name=MONTH_NAMES[i];
if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
if (token=="MMM"||(token=="NNN"&&i>11)) {
month=i+1;
if (month>12) { month -= 12; }
i_val += month_name.length;
break;
}
}
}
if ((month < 1)||(month>12)){return 0;}
}
else if (token=="EE"||token=="E"){
for (var i=0; i<DAY_NAMES.length; i++) {
var day_name=DAY_NAMES[i];
if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
i_val += day_name.length;
break;
}
}
}
else if (token=="MM"||token=="M") {
month=_getInt(val,i_val,token.length,2);
if(month==null||(month<1)||(month>12)){return 0;}
i_val+=month.length;}
else if (token=="dd"||token=="d") {
date=_getInt(val,i_val,token.length,2);
if(date==null||(date<1)||(date>31)){return 0;}
i_val+=date.length;}
else if (token=="hh"||token=="h") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<1)||(hh>12)){return 0;}
i_val+=hh.length;}
else if (token=="HH"||token=="H") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<0)||(hh>23)){return 0;}
i_val+=hh.length;}
else if (token=="KK"||token=="K") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<0)||(hh>11)){return 0;}
i_val+=hh.length;}
else if (token=="kk"||token=="k") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<1)||(hh>24)){return 0;}
i_val+=hh.length;hh--;}
else if (token=="mm"||token=="m") {
mm=_getInt(val,i_val,token.length,2);
if(mm==null||(mm<0)||(mm>59)){return 0;}
i_val+=mm.length;}
else if (token=="ss"||token=="s") {
ss=_getInt(val,i_val,token.length,2);
if(ss==null||(ss<0)||(ss>59)){return 0;}
i_val+=ss.length;}
else if (token=="a") {
if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
else {return 0;}
i_val+=2;}
else {
if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
else {i_val+=token.length;}
}
}
// If there are any trailing characters left in the value, it doesn't match
if (i_val != val.length) { return 0; }
// Is date valid for month?
if (month==2) {
// Check for leap year
if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
if (date > 29){ return 0; }
}
else { if (date > 28) { return 0; } }
}
if ((month==4)||(month==6)||(month==9)||(month==11)) {
if (date > 30) { return 0; }
}
// Correct hours value
if (hh<12 && ampm=="PM") { hh=hh-0+12; }
else if (hh>11 && ampm=="AM") { hh-=12; }
var newdate=new Date(year,month-1,date,hh,mm,ss);
return newdate.getTime();
}
// ------------------------------------------------------------------
// parseDate( date_string [, prefer_euro_format] )
//
// This function takes a date string and tries to match it to a
// number of possible date formats to get the value. It will try to
// match against the following international formats, in this order:
// y-M-d MMM d, y MMM d,y y-MMM-d d-MMM-y MMM d
// M/d/y M-d-y M.d.y MMM-d M/d M-d
// d/M/y d-M-y d.M.y d-MMM d/M d-M
// A second argument may be passed to instruct the method to search
// for formats like d/M/y (european format) before M/d/y (American).
// Returns a Date object or null if no patterns match.
// ------------------------------------------------------------------
function parseDate(val) {
var preferEuro=(arguments.length==2)?arguments[1]:false;
generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
var d=null;
for (var i=0; i<checkList.length; i++) {
var l=window[checkList[i]];
for (var j=0; j<l.length; j++) {
d=getDateFromFormat(val,l[j]);
if (d!=0) { return new Date(d); }
}
}
return null;
}

View File

@ -258,6 +258,12 @@ $js_messages['strSave'] = __('Save');
$js_messages['strHideSearchCriteria'] = __('Hide search criteria');
$js_messages['strShowSearchCriteria'] = __('Show search criteria');
/* For tbl_zoom_plot.js */
$js_messages['strZoomSearch'] = __('Zoom Search');
$js_messages['strDisplayHelp'] = __('* Each point represents a data row.<br>* Hovering over a point will show its label.<br>* Drag and select an area in the plot to zoom into it.<br>* Click reset zoom link to come back to original state.<br>* Click a data point to view and possibly edit the data row.<br>* The plot can be resized by dragging it along the bottom right corner.<br>* Strings are converted into integer for plotting');
$js_messages['strInputNull'] = __('<b>Select two columns</b>');
$js_messages['strSameInputs'] = __('<b>Select two different columns</b>');
/* For tbl_change.js */
$js_messages['strIgnore'] = __('Ignore');

View File

@ -66,7 +66,7 @@ $(document).ready(function() {
if (typeof response == 'string') {
// found results
$("#sqlqueryresults").html(response);
$("#sqlqueryresults").trigger('makegrid');
$("#sqlqueryresults").trigger('appendAnchor');
$('#tbl_search_form')
// work around for bug #3168569 - Issue on toggling the "Hide search criteria" in chrome.
.slideToggle()

605
js/tbl_zoom_plot.js Normal file
View File

@ -0,0 +1,605 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
** @fileoverview JavaScript functions used on tbl_select.php
**
** @requires jQuery
** @requires js/functions.js
**/
/**
** Display Help/Info
**/
function displayHelp() {
var msgbox = PMA_ajaxShowMessage(PMA_messages['strDisplayHelp'],10000);
msgbox.click(function() {
PMA_ajaxRemoveMessage(msgbox);
});
}
/**
** Extend the array object for max function
** @param array
**/
Array.max = function (array) {
return Math.max.apply( Math, array );
}
/**
** Extend the array object for min function
** @param array
**/
Array.min = function (array) {
return Math.min.apply( Math, array );
}
/**
** Checks if a string contains only numeric value
** @param n: String (to be checked)
**/
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
/**
** Checks if an object is empty
** @param n: Object (to be checked)
**/
function isEmpty(obj) {
var name;
for (name in obj) {
return false;
}
return true;
}
/**
** Converts a timestamp into the format of its field type
** @param val Integer Timestamp
** @param type String Field type(datetime/timestamp/time/date)
**/
function getDate(val,type) {
if(type.toString().search(/datetime/i) != -1 || type.toString().search(/timestamp/i) != -1) {
return Highcharts.dateFormat('%Y-%m-%e %H:%M:%S', val)
}
else if(type.toString().search(/time/i) != -1) {
return Highcharts.dateFormat('%H:%M:%S', val + 19800000)
}
else if (type.toString().search(/date/i) != -1) {
return Highcharts.dateFormat('%Y-%m-%e', val)
}
}
/**
** Converts a date/time into timestamp
** @param val String Date
** @param type Sring Field type(datetime/timestamp/time/date)
**/
function getTimeStamp(val,type) {
if(type.toString().search(/datetime/i) != -1 || type.toString().search(/timestamp/i) != -1) {
return getDateFromFormat(val,'yyyy-MM-dd HH:mm:ss', val)
}
else if(type.toString().search(/time/i) != -1) {
return getDateFromFormat('1970-01-01 ' + val,'yyyy-MM-dd HH:mm:ss')
}
else if (type.toString().search(/date/i) != -1) {
return getDateFromFormat(val,'yyyy-MM-dd')
}
}
/**
** Classifies the field type into numeric,timeseries or text
** @param field: field type (as in database structure)
**/
function getType(field) {
if(field.toString().search(/int/i) != -1 || field.toString().search(/decimal/i) != -1 || field.toString().search(/year/i) != -1)
return 'numeric';
else if(field.toString().search(/time/i) != -1 || field.toString().search(/date/i) != -1)
return 'time';
else
return 'text';
}
/**
** Converts a categorical array into numeric array
** @param array categorical values array
**/
function getCord(arr) {
var newCord = new Array();
var original = $.extend(true,[],arr);
var arr = jQuery.unique(arr).sort();
$.each(original, function(index,value) {
newCord.push(jQuery.inArray(value,arr));
});
return [newCord,arr,original];
}
/**
** Scrolls the view to the display section
**/
function scrollToChart() {
var x = $('#dataDisplay').offset().top - 100; // 100 provides buffer in viewport
$('html,body').animate({scrollTop: x}, 500);
}
$(document).ready(function() {
/**
** Set a parameter for all Ajax queries made on this page. Don't let the
** web server serve cached pages
**/
$.ajaxSetup({
cache: 'false'
});
var cursorMode = ($("input[name='mode']:checked").val() == 'edit') ? 'crosshair' : 'pointer';
var currentChart = null;
var currentData = null;
var xLabel = $('#tableid_0').val();
var yLabel = $('#tableid_1').val();
var xType = $('#types_0').val();
var yType = $('#types_1').val();
var dataLabel = $('#dataLabel').val();
// Get query result
var data = jQuery.parseJSON($('#querydata').html());
/**
** Input form submit on field change
**/
$('#tableid_0').change(function() {
$('#zoom_search_form').submit();
})
$('#tableid_1').change(function() {
$('#zoom_search_form').submit();
})
$('#tableid_2').change(function() {
$('#zoom_search_form').submit();
})
$('#tableid_3').change(function() {
$('#zoom_search_form').submit();
})
/**
* Input form validation
**/
$('#inputFormSubmitId').click(function() {
if ($('#tableid_0').get(0).selectedIndex == 0 || $('#tableid_1').get(0).selectedIndex == 0)
PMA_ajaxShowMessage(PMA_messages['strInputNull']);
else if (xLabel == yLabel)
PMA_ajaxShowMessage(PMA_messages['strSameInputs']);
});
/**
** Prepare a div containing a link, otherwise it's incorrectly displayed
** after a couple of clicks
**/
$('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
.insertAfter('#zoom_search_form')
// don't show it until we have results on-screen
.hide();
$('#togglesearchformlink')
.html(PMA_messages['strShowSearchCriteria'])
.bind('click', function() {
var $link = $(this);
$('#zoom_search_form').slideToggle();
if ($link.text() == PMA_messages['strHideSearchCriteria']) {
$link.text(PMA_messages['strShowSearchCriteria']);
} else {
$link.text(PMA_messages['strHideSearchCriteria']);
}
// avoid default click action
return false;
});
/**
** Set dialog properties for the data display form
**/
$("#dataDisplay").dialog({
autoOpen: false,
title: 'Data point content',
modal: false, //false otherwise other dialogues like timepicker may not function properly
height: $('#dataDisplay').height() + 80,
width: $('#dataDisplay').width() + 80
});
/*
* Handle submit of zoom_display_form
*/
$("#submitForm").click(function(event) {
//Prevent default submission of form
event.preventDefault();
//Find changed values by comparing form values with selectedRow Object
var newValues = new Array();//Stores the values changed from original
var it = 4;
var xChange = false;
var yChange = false;
for (key in selectedRow) {
if (key != 'where_clause'){
var oldVal = selectedRow[key];
var newVal = ($('#fields_null_id_' + it).attr('checked')) ? null : $('#fieldID_' + it).val();
if (oldVal != newVal){
selectedRow[key] = newVal;
newValues[key] = newVal;
if(key == xLabel) {
xChange = true;
data[currentData][xLabel] = newVal;
}
else if(key == yLabel) {
yChange = true;
data[currentData][yLabel] = newVal;
}
}
}
it++
}//End data update
//Update the chart series and replot
if (xChange || yChange) {
var newSeries = new Array();
newSeries[0] = new Object();
newSeries[0].marker = {
symbol: 'circle'
};
//Logic similar to plot generation, replot only if xAxis changes or yAxis changes. Code includes a lot of checks so as to replot only when necessary
if(xChange) {
xCord[currentData] = selectedRow[xLabel];
if(xType == 'numeric') {
currentChart.series[0].data[currentData].update({ x : selectedRow[xLabel] });
currentChart.xAxis[0].setExtremes(Array.min(xCord) - 6,Array.max(xCord) + 6);
}
else if(xType == 'time') {
currentChart.series[0].data[currentData].update({ x : getTimeStamp(selectedRow[xLabel],$('#types_0').val())});
}
else {
var tempX = getCord(xCord);
var tempY = getCord(yCord);
var i = 0;
newSeries[0].data = new Array();
xCord = tempX[2];
yCord = tempY[2];
$.each(data,function(key,value) {
if(yType != 'text')
newSeries[0].data.push({ name: value[dataLabel], x: tempX[0][i], y: value[yLabel], marker: {fillColor: colorCodes[i % 8]} , id: i } );
else
newSeries[0].data.push({ name: value[dataLabel], x: tempX[0][i], y: tempY[0][i], marker: {fillColor: colorCodes[i % 8]} , id: i } );
i++;
});
currentSettings.xAxis.labels = { formatter : function() {
if(tempX[1][this.value] && tempX[1][this.value].length > 10)
return tempX[1][this.value].substring(0,10)
else
return tempX[1][this.value];
}
}
currentSettings.series = newSeries;
currentChart = PMA_createChart(currentSettings);
}
}
if(yChange) {
yCord[currentData] = selectedRow[yLabel];
if(yType == 'numeric') {
currentChart.series[0].data[currentData].update({ y : selectedRow[yLabel] });
currentChart.yAxis[0].setExtremes(Array.min(yCord) - 6,Array.max(yCord) + 6);
}
else if(yType =='time') {
currentChart.series[0].data[currentData].update({ y : getTimeStamp(selectedRow[yLabel],$('#types_1').val())});
}
else {
var tempX = getCord(xCord);
var tempY = getCord(yCord);
var i = 0;
newSeries[0].data = new Array();
xCord = tempX[2];
yCord = tempY[2];
$.each(data,function(key,value) {
if(xType != 'text' )
newSeries[0].data.push({ name: value[dataLabel], x: value[xLabel], y: tempY[0][i], marker: {fillColor: colorCodes[i % 8]} , id: i } );
else
newSeries[0].data.push({ name: value[dataLabel], x: tempX[0][i], y: tempY[0][i], marker: {fillColor: colorCodes[i % 8]} , id: i } );
i++;
});
currentSettings.yAxis.labels = { formatter : function() {
if(tempY[1][this.value] && tempY[1][this.value].length > 10)
return tempY[1][this.value].substring(0,10)
else
return tempY[1][this.value];
}
}
currentSettings.series = newSeries;
currentChart = PMA_createChart(currentSettings);
}
}
currentChart.series[0].data[currentData].select();
}
//End plot update
//Generate SQL query for update
if (!isEmpty(newValues)) {
var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
for (key in newValues) {
if(key != 'where_clause') {
sql_query += '`' + key + '`=' ;
var value = newValues[key];
if(!isNumeric(value) && value != null)
sql_query += '\'' + value + '\' ,';
else
sql_query += value + ' ,';
}
}
sql_query = sql_query.substring(0, sql_query.length - 1);
sql_query += ' WHERE ' + PMA_urldecode(data[currentData]['where_clause']);
//Post SQL query to sql.php
$.post('sql.php', {
'token' : window.parent.token,
'db' : window.parent.db,
'ajax_request' : true,
'sql_query' : sql_query,
'inline_edit' : false
}, function(data) {
if(data.success == true) {
$('#sqlqueryresults').html(data.sql_query);
$("#sqlqueryresults").trigger('appendAnchor');
}
else
PMA_ajaxShowMessage(data.error);
})//End $.post
}//End database update
$("#dataDisplay").dialog("close");
});//End submit handler
/*
* Generate plot using Highcharts
*/
if (data != null) {
$('#zoom_search_form')
.slideToggle()
.hide();
$('#togglesearchformlink')
.text(PMA_messages['strShowSearchCriteria'])
$('#togglesearchformdiv').show();
var selectedRow;
var columnNames = new Array();
var colorCodes = ['#FF0000','#00FFFF','#0000FF','#0000A0','#FF0080','#800080','#FFFF00','#00FF00','#FF00FF'];
var series = new Array();
var xCord = new Array();
var yCord = new Array();
var xCat = new Array();
var yCat = new Array();
var tempX, tempY;
var it = 0;
// Set the basic plot settings
var currentSettings = {
chart: {
renderTo: 'querychart',
type: 'scatter',
zoomType: 'xy',
width:$('#resizer').width() -3,
height:$('#resizer').height()-20
},
credits: {
enabled: false
},
exporting: { enabled: false },
label: { text: $('#dataLabel').val() },
plotOptions: {
series: {
allowPointSelect: true,
cursor: 'pointer',
showInLegend: false,
dataLabels: {
enabled: false,
},
point: {
events: {
click: function() {
var id = this.id;
var fid = 4;
currentData = id;
// Make AJAX request to tbl_zoom_select.php for getting the complete row info
var post_params = {
'ajax_request' : true,
'get_data_row' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'where_clause' : data[id]['where_clause'],
'token' : window.parent.token,
}
$.post('tbl_zoom_select.php', post_params, function(data) {
// Row is contained in data.row_info, now fill the displayResultForm with row values
for ( key in data.row_info) {
if (data.row_info[key] == null)
$('#fields_null_id_' + fid).attr('checked', true);
else
$('#fieldID_' + fid).val(data.row_info[key]);
fid++;
}
selectedRow = new Object();
selectedRow = data.row_info;
});
$("#dataDisplay").dialog("open");
},
}
}
}
},
tooltip: {
formatter: function() {
return this.point.name;
}
},
title: { text: 'Query Results' },
xAxis: {
title: { text: $('#tableid_0').val() },
},
yAxis: {
min: null,
title: { text: $('#tableid_1').val() },
},
}
$('#resizer').resizable({
resize: function() {
currentChart.setSize(
this.offsetWidth -3,
this.offsetHeight -20,
false
);
}
});
// Classify types as either numeric,time,text
xType = getType(xType);
yType = getType(yType);
//Set the axis type based on the field
currentSettings.xAxis.type = (xType == 'time') ? 'datetime' : 'linear';
currentSettings.yAxis.type = (yType == 'time') ? 'datetime' : 'linear';
// Formulate series data for plot
series[0] = new Object();
series[0].data = new Array();
series[0].marker = {
symbol: 'circle'
};
if (xType != 'text' && yType != 'text') {
$.each(data,function(key,value) {
var xVal = (xType == 'numeric') ? value[xLabel] : getTimeStamp(value[xLabel],$('#types_0').val());
var yVal = (yType == 'numeric') ? value[yLabel] : getTimeStamp(value[yLabel],$('#types_1').val());
series[0].data.push({ name: value[dataLabel], x: xVal, y: yVal, marker: {fillColor: colorCodes[it % 8]} , id: it } );
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
it++;
});
if(xType == 'numeric') {
currentSettings.xAxis.max = Array.max(xCord) + 6
currentSettings.xAxis.min = Array.min(xCord) - 6
}
else {
currentSettings.xAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_0').val());
}}
}
if(yType == 'numeric') {
currentSettings.yAxis.max = Array.max(yCord) + 6
currentSettings.yAxis.min = Array.min(yCord) - 6
}
else {
currentSettings.yAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_1').val());
}}
}
}
else if (xType =='text' && yType !='text') {
$.each(data,function(key,value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempX = getCord(xCord);
$.each(data,function(key,value) {
var yVal = (yType == 'numeric') ? value[yLabel] : getTimeStamp(value[yLabel],$('#types_1').val());
series[0].data.push({ name: value[dataLabel], x: tempX[0][it], y: yVal, marker: {fillColor: colorCodes[it % 8]} , id: it } );
it++;
});
currentSettings.xAxis.labels = { formatter : function() {
if(tempX[1][this.value] && tempX[1][this.value].length > 10)
return tempX[1][this.value].substring(0,10)
else
return tempX[1][this.value];
}
}
if(yType == 'numeric') {
currentSettings.yAxis.max = Array.max(yCord) + 6
currentSettings.yAxis.min = Array.min(yCord) - 6
}
else {
currentSettings.yAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_1').val());
}}
}
xCord = tempX[2];
}
else if (xType !='text' && yType =='text') {
$.each(data,function(key,value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempY = getCord(yCord);
$.each(data,function(key,value) {
var xVal = (xType == 'numeric') ? value[xLabel] : getTimeStamp(value[xLabel],$('#types_0').val());
series[0].data.push({ name: value[dataLabel], y: tempY[0][it], x: xVal, marker: {fillColor: colorCodes[it % 8]} , id: it } );
it++;
});
if(xType == 'numeric') {
currentSettings.xAxis.max = Array.max(xCord) + 6
currentSettings.xAxis.min = Array.min(xCord) - 6
}
else {
currentSettings.xAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_0').val());
}}
}
currentSettings.yAxis.labels = { formatter : function() {
if(tempY[1][this.value] && tempY[1][this.value].length > 10)
return tempY[1][this.value].substring(0,10)
else
return tempY[1][this.value];
}
}
yCord = tempY[2];
}
else if (xType =='text' && yType =='text') {
$.each(data,function(key,value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempX = getCord(xCord);
tempY = getCord(yCord);
$.each(data,function(key,value) {
series[0].data.push({ name: value[dataLabel], x: tempX[0][it], y: tempY[0][it], marker: {fillColor: colorCodes[it % 8]} , id: it } );
it++;
});
currentSettings.xAxis.labels = { formatter : function() {
if(tempX[1][this.value] && tempX[1][this.value].length > 10)
return tempX[1][this.value].substring(0,10)
else
return tempX[1][this.value];
}
}
currentSettings.yAxis.labels = { formatter : function() {
if(tempY[1][this.value] && tempY[1][this.value].length > 10)
return tempY[1][this.value].substring(0,10)
else
return tempY[1][this.value];
}
}
xCord = tempX[2];
yCord = tempY[2];
}
currentSettings.series = series;
currentChart = PMA_createChart(currentSettings);
scrollToChart();
}
});

View File

@ -413,6 +413,7 @@ $goto_whitelist = array(
'tbl_replace.php',
'tbl_row_action.php',
'tbl_select.php',
'tbl_zoom_select.php',
//'themes.php',
'transformation_overview.php',
'transformation_wrapper.php',

View File

@ -1137,7 +1137,6 @@ $cfg['DefaultTabDatabase'] = 'db_structure.php';
*/
$cfg['DefaultTabTable'] = 'sql.php';
/*******************************************************************************
* Export defaults
*/
@ -1845,7 +1844,6 @@ $cfg['Export']['xml_export_contents'] = true;
*/
$cfg['Export']['yaml_structure_or_data'] = 'data';
/*******************************************************************************
* Import defaults
*/
@ -2443,7 +2441,6 @@ $cfg['UserprefsDisallow'] = array();
*/
$cfg['UserprefsDeveloperTab'] = false;
/*******************************************************************************
* Window title settings
*/
@ -2554,9 +2551,7 @@ $cfg['DefaultQueryDatabase'] = '';
/*******************************************************************************
* SQL Query box settings
* These are the links display in all of the SQL Query boxes
*/
/**
*
* @global array $cfg['SQLQuery']
*/
$cfg['SQLQuery'] = array();
@ -2628,7 +2623,7 @@ $cfg['SaveDir'] = '';
$cfg['TempDir'] = '';
/*******************************************************************************
/**
* Misc. settings
*/
@ -2673,12 +2668,7 @@ $cfg['LinkLengthLimit'] = 1000;
*/
$cfg['DisableMultiTableMaintenance'] = false;
/*******************************************************************************
* SQL Parser
*/
/**
* SQL Parser Settings
*
* @global array $cfg['SQP']
@ -2708,10 +2698,6 @@ $cfg['SQP']['fmtIndUnit'] = 'em';
/*******************************************************************************
* SQL Validator
*/
/**
* If you wish to use the SQL Validator service, you should be aware of the
* following:
* All SQL statements are stored anonymously for statistical purposes.
@ -2746,10 +2732,6 @@ $cfg['SQLValidator']['password'] = '';
/*******************************************************************************
* Developers ONLY!
*/
/**
* Debugging settings
*
* @global array $cfg['DBG']
*/
@ -2768,50 +2750,328 @@ $cfg['DBG']['sql'] = false;
*/
/**
* Column types
*
* Fill in this array to overwrite data from data_*.inc.php files
* Column types;
* VARCHAR, TINYINT, TEXT and DATE are listed first, based on estimated popularity
*
* @global array $cfg['ColumnTypes']
*/
$cfg['ColumnTypes'] = array();
$cfg['ColumnTypes'] = array(
// most used
'INT',
'VARCHAR',
'TEXT',
'DATE',
// numeric
'NUMERIC' => array(
'TINYINT',
'SMALLINT',
'MEDIUMINT',
'INT',
'BIGINT',
'-',
'DECIMAL',
'FLOAT',
'DOUBLE',
'REAL',
'-',
'BIT',
'BOOLEAN',
'SERIAL',
),
// Date/Time
'DATE and TIME' => array(
'DATE',
'DATETIME',
'TIMESTAMP',
'TIME',
'YEAR',
),
// Text
'STRING' => array(
'CHAR',
'VARCHAR',
'-',
'TINYTEXT',
'TEXT',
'MEDIUMTEXT',
'LONGTEXT',
'-',
'BINARY',
'VARBINARY',
'-',
'TINYBLOB',
'MEDIUMBLOB',
'BLOB',
'LONGBLOB',
'-',
'ENUM',
'SET',
),
'SPATIAL' => array(
'GEOMETRY',
'POINT',
'LINESTRING',
'POLYGON',
'MULTIPOINT',
'MULTILINESTRING',
'MULTIPOLYGON',
'GEOMETRYCOLLECTION',
),
);
/**
* Attributes
*
* Fill in this array to overwrite data from data_*.inc.php files
*
* @global array $cfg['AttributeTypes']
*/
$cfg['AttributeTypes'] = array();
$cfg['AttributeTypes'] = array(
'',
'BINARY',
'UNSIGNED',
'UNSIGNED ZEROFILL',
'on update CURRENT_TIMESTAMP',
);
if ($cfg['ShowFunctionFields']) {
/**
* Available functions
*
* Fill in this array to overwrite data from data_*.inc.php files
*
* @global array $cfg['Functions']
*/
$cfg['Functions'] = array();
$cfg['Functions'] = array(
'ABS',
'ACOS',
'ASCII',
'ASIN',
'ATAN',
'BIN',
'BIT_COUNT',
'BIT_LENGTH',
'CEILING',
'CHAR',
'CHAR_LENGTH',
'COMPRESS',
'COS',
'COT',
'CRC32',
'CURDATE',
'CURRENT_USER',
'CURTIME',
'DATE',
'DAYNAME',
'DEGREES',
'DES_DECRYPT',
'DES_ENCRYPT',
'ENCRYPT',
'EXP',
'FLOOR',
'FROM_DAYS',
'FROM_UNIXTIME',
'HEX',
'INET_ATON',
'INET_NTOA',
'LENGTH',
'LN',
'LOG',
'LOG10',
'LOG2',
'LOWER',
'MD5',
'NOW',
'OCT',
'OLD_PASSWORD',
'ORD',
'PASSWORD',
'RADIANS',
'RAND',
'REVERSE',
'ROUND',
'SEC_TO_TIME',
'SHA1',
'SOUNDEX',
'SPACE',
'SQRT',
'STDDEV_POP',
'STDDEV_SAMP',
'TAN',
'TIMESTAMP',
'TIME_TO_SEC',
'UNCOMPRESS',
'UNHEX',
'UNIX_TIMESTAMP',
'UPPER',
'USER',
'UTC_DATE',
'UTC_TIME',
'UTC_TIMESTAMP',
'UUID',
'VAR_POP',
'VAR_SAMP',
'YEAR',
);
/**
* Which column types will be mapped to which Group?
*
* Fill in this array to overwrite data from data_*.inc.php files
*
* @global array $cfg['RestrictColumnTypes']
*/
$cfg['RestrictColumnTypes'] = array();
$cfg['RestrictColumnTypes'] = array(
'TINYINT' => 'FUNC_NUMBER',
'SMALLINT' => 'FUNC_NUMBER',
'MEDIUMINT' => 'FUNC_NUMBER',
'INT' => 'FUNC_NUMBER',
'BIGINT' => 'FUNC_NUMBER',
'DECIMAL' => 'FUNC_NUMBER',
'FLOAT' => 'FUNC_NUMBER',
'DOUBLE' => 'FUNC_NUMBER',
'REAL' => 'FUNC_NUMBER',
'BIT' => 'FUNC_NUMBER',
'BOOLEAN' => 'FUNC_NUMBER',
'SERIAL' => 'FUNC_NUMBER',
'DATE' => 'FUNC_DATE',
'DATETIME' => 'FUNC_DATE',
'TIMESTAMP' => 'FUNC_DATE',
'TIME' => 'FUNC_DATE',
'YEAR' => 'FUNC_DATE',
'CHAR' => 'FUNC_CHAR',
'VARCHAR' => 'FUNC_CHAR',
'TINYTEXT' => 'FUNC_CHAR',
'TEXT' => 'FUNC_CHAR',
'MEDIUMTEXT' => 'FUNC_CHAR',
'LONGTEXT' => 'FUNC_CHAR',
'BINARY' => 'FUNC_CHAR',
'VARBINARY' => 'FUNC_CHAR',
'TINYBLOB' => 'FUNC_CHAR',
'MEDIUMBLOB' => 'FUNC_CHAR',
'BLOB' => 'FUNC_CHAR',
'LONGBLOB' => 'FUNC_CHAR',
'ENUM' => '',
'SET' => '',
'GEOMETRY' => 'FUNC_SPATIAL',
'POINT' => 'FUNC_SPATIAL',
'LINESTRING' => 'FUNC_SPATIAL',
'POLYGON' => 'FUNC_SPATIAL',
'MULTIPOINT' => 'FUNC_SPATIAL',
'MULTILINESTRING' => 'FUNC_SPATIAL',
'MULTIPOLYGON' => 'FUNC_SPATIAL',
'GEOMETRYCOLLECTION' => 'FUNC_SPATIAL',
);
/**
* Map above defined groups to any function
*
* Fill in this array to overwrite data from data_*.inc.php files
*
* @global array $cfg['RestrictFunctions']
*/
$cfg['RestrictFunctions'] = array();
$cfg['RestrictFunctions'] = array(
'FUNC_CHAR' => array(
'BIN',
'CHAR',
'CURRENT_USER',
'COMPRESS',
'DAYNAME',
'DES_DECRYPT',
'DES_ENCRYPT',
'ENCRYPT',
'HEX',
'INET_NTOA',
'LOWER',
'MD5',
'OLD_PASSWORD',
'PASSWORD',
'REVERSE',
'SHA1',
'SOUNDEX',
'SPACE',
'UNCOMPRESS',
'UNHEX',
'UPPER',
'USER',
'UUID',
),
'FUNC_DATE' => array(
'CURDATE',
'CURTIME',
'DATE',
'FROM_DAYS',
'FROM_UNIXTIME',
'NOW',
'SEC_TO_TIME',
'TIMESTAMP',
'UTC_DATE',
'UTC_TIME',
'UTC_TIMESTAMP',
'YEAR',
),
'FUNC_NUMBER' => array(
'ABS',
'ACOS',
'ASCII',
'ASIN',
'ATAN',
'BIT_LENGTH',
'BIT_COUNT',
'CEILING',
'CHAR_LENGTH',
'COS',
'COT',
'CRC32',
'DEGREES',
'EXP',
'FLOOR',
'INET_ATON',
'LENGTH',
'LN',
'LOG',
'LOG2',
'LOG10',
'OCT',
'ORD',
'RADIANS',
'RAND',
'ROUND',
'SQRT',
'STDDEV_POP',
'STDDEV_SAMP',
'TAN',
'TIME_TO_SEC',
'UNIX_TIMESTAMP',
'VAR_POP',
'VAR_SAMP',
),
'FUNC_SPATIAL' => array(
'GeomFromText',
'GeomFromWKB',
'GeomCollFromText',
'LineFromText',
'MLineFromText',
'PointFromText',
'MPointFromText',
'PolyFromText',
'MPolyFromText',
'GeomCollFromWKB',
'LineFromWKB',
'MLineFromWKB',
'PointFromWKB',
'MPointFromWKB',
'PolyFromWKB',
'MPolyFromWKB',
),
);
/**
* Default functions for above defined groups
@ -2825,6 +3085,97 @@ if ($cfg['ShowFunctionFields']) {
'first_timestamp' => 'NOW',
'pk_char36' => 'UUID',
);
}
} // end if
/**
* Search operators
*
* @global array $cfg['NumOperators']
*/
$cfg['NumOperators'] = array(
'=',
'>',
'>=',
'<',
'<=',
'!=',
'LIKE',
'NOT LIKE',
'IN (...)',
'NOT IN (...)',
'BETWEEN',
'NOT BETWEEN',
);
/**
* Search operators
*
* @global array $cfg['TextOperators']
*/
$cfg['TextOperators'] = array(
'LIKE',
'LIKE %...%',
'NOT LIKE',
'=',
'!=',
'REGEXP',
'REGEXP ^...$',
'NOT REGEXP',
"= ''",
"!= ''",
'IN (...)',
'NOT IN (...)',
'BETWEEN',
'NOT BETWEEN',
);
/**
* Search operators
*
* @global array $cfg['EnumOperators']
*/
$cfg['EnumOperators'] = array(
'=',
'!=',
);
/**
* Search operators
*
* @global array $cfg['SetOperators']
*/
$cfg['SetOperators'] = array(
'IN',
'NOT IN',
);
/**
* Search operators
*
* @global array $cfg['NullOperators']
*/
$cfg['NullOperators'] = array(
'IS NULL',
'IS NOT NULL',
);
/**
* Search operators
*
* @global array $cfg['UnaryOperators']
*/
$cfg['UnaryOperators'] = array(
'IS NULL' => 1,
'IS NOT NULL' => 1,
"= ''" => 1,
"!= ''" => 1
);
/**
* Max rows retreived for zoom search
*/
$cfg['maxRowPlotLimit'] = 500;
?>

View File

@ -0,0 +1,267 @@
<?php
/**
* Generates the SVG needed for the plot
*
* @package phpMyAdmin
*/
require_once 'pma_svg_data_point.php';
class PMA_Scatter_Plot
{
/**
* @var array Raw data for the plot
*/
private $_data;
/**
* @var array Data points of the plot
*/
private $_dataPoints;
/**
* @var array Set of default settigs values are here.
*/
private $_settings = array(
// Array of colors to be used for plot.
'colors' => array(
'#BCE02E',
'#E0642E',
'#E0D62E',
'#2E97E0',
'#B02EE0',
'#E02E75',
'#5CE02E',
'#E0B02E',
'#000000',
'#0022E0',
'#726CB1',
'#481A36',
'#BAC658',
'#127224',
'#825119',
'#238C74',
'#4C489B',
'#87C9BF',
),
// Plot background color.
'bgColor' => '#84AD83',
// The width of the plot.
'width' => 520,
// The height of the plot.
'height' => 325,
// Default X Axis label. If empty, label will be taken from the data.
'xLabel' => '',
// Default Y Axis label. If empty, label will be taken from the data.
'yLabel' => '',
// Data point label. If empty, label will be taken from the data.
'dataLabel' => '',
);
/**
* @var array Options that the user has specified.
*/
private $_userSpecifiedSettings = null;
/**
* Returns the settings array
*
* @return the settings array.
*/
public function getSettings()
{
return $this->_settings;
}
/**
* Returns the data array
*
* @return the data array.
*/
public function getData()
{
return $this->_data;
}
/**
* Constructor. Stores user specified options.
*
* @param array $data Data for the visualization
* @param array $options Users specified options
*/
public function __construct($data, $options)
{
$this->_userSpecifiedSettings = $options;
$this->_data = $data;
}
/**
* All the variable initialization, options handling has to be done here.
*/
protected function init()
{
$this->_handleOptions();
}
/**
* A function which handles passed parameters. Useful if desired
* chart needs to be a little bit different from the default one.
*/
private function _handleOptions()
{
$this->_dataPoints = array();
if (! is_null($this->_userSpecifiedSettings)) {
foreach (array_keys($this->_userSpecifiedSettings) as $key){
$this->_settings[$key] = $this->_userSpecifiedSettings[$key];
}
}
if ($this->_settings['dataLabel'] == '') {
$labels = array_keys($this->_data[0]);
$this->_settings['dataLabel'] = $labels[0];
}
}
/**
* Generate the visualization in SVG format.
*
* @return the generated image resource
*/
private function _svg()
{
$this->init();
$output = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
$output .= '<svg version="1.1" xmlns:svg="http://www.w3.org/2000/svg"'
. ' xmlns="http://www.w3.org/2000/svg" width="' . $this->_settings['width'] . '"'
. ' height="' . $this->_settings['height'] . '">';
$output .= '<g id="groupPanel">';
$output .= '<defs>
<path id="myTextPath1"
d="M10,190 L10,50"/>
<path id="myTextPath2"
d="M250,10 L370,10"/>
</defs>';
$output .= '<text x="6" y="190" style="font-family: Arial; font-size : 54; stroke:none; fill:#000000;" >
<textPath xlink:href="#myTextPath1" >';
$output .= $this->_settings['yLabel'];
$output .= '</textPath>
</text>';
$output .= '<text x="250" y="10" style="font-family: Arial; font-size : 54; stroke:none; fill:#000000;" >
<textPath xlink:href="#myTextPath2" >';
$output .= $this->_settings['xLabel'];
$output .= '</textPath>
</text>';
$scale_data = $this->_scaleDataSet($this->_data, $this->_settings['xLabel'], $this->_settings['yLabel']);
$output .= $this->_prepareDataSet($this->_data, 0, $scale_data, $this->_settings['dataLabel']);
$output .= '</g>';
$output .= '</svg>';
return $output;
}
/**
* Get the visualization as a SVG.
*
* @return the visualization as a SVG
*/
public function asSVG()
{
$output = $this->_svg();
return $output;
}
/**
* Calculates the scale, horizontal and vertical offset that should be used.
*
* @param array $data Row data
*
* @return an array containing the scale, x and y offsets
*/
private function _scaleDataSet($data,$xField,$yField)
{
// Currently assuming only numeric fields are selected
$coordinates = array();
foreach ($data as $row) {
$coordinates[0][] = $row[$xField];
$coordinates[1][] = $row[$yField];
}
for ($i = 0 ; $i < 2 ; $i++) {
$maxC = ($i == 0) ? 500 : 320;
if( !is_numeric($coordinates[$i][0])) {
$uniqueC = array_unique($coordinates[$i]);
$countC = count(array_unique($coordinates[$i]));
$map = $tmp = array();
foreach ($uniqueC as $uc) {
$tmp[] = $uc;
}
for ($j = 0 ; $j < $countC ; $j++) {
$map[$tmp[$j]] = 20 + $j * $maxC / $countC;
}
for($j = 0 ; $j < count($coordinates[$i]) ; $j++) {
$coordinates[$i][$j] = $map[$coordinates[$i][$j]];
}
}
elseif (is_numeric($coordinates[$i][0])) {
$maxC = max($coordinates[$i]);
for($j = 0 ; $j < count($coordinates[$i]) ; $j++) {
if ($i == 0)
$coordinates[$i][$j] = 20 + 500 * $coordinates[$i][$j] / $maxC;
else
$coordinates[$i][$j] = 20 + 320 * (1 - $coordinates[$i][$j] / $maxC);
}
}
}
return $coordinates;
}
/**
* Prepares and return the dataset as needed by the visualization.
*
* @param array $data Raw data
* @param int $color_number Start index to the color array
* @param array $scale_data Data related to scaling
* @param string $label Label for the data points
* @param image $results Image object in the case of png
*
* @return the formatted array of data.
*/
private function _prepareDataSet($data, $color_number, $scale_data, $label)
{
$result = '';
// loop through the rows
for($i = 0 ; $i < count($data) ; $i++) {
$index = $color_number % sizeof($this->_settings['colors']);
$data_element = new PMA_SVG_Data_Point($scale_data[0][$i],$scale_data[1][$i],$data[$i][$label],$data[$i]);
$options = array('color' => $this->_settings['colors'][$index], 'id' => $i);
$this->_dataPoints[] = $data_element;
$result .= $data_element->prepareRowAsSVG($options);
$color_number++;
}
return $result;
}
}
?>

View File

@ -0,0 +1,50 @@
<?php
/**
* Base class for the plot data type classes.
*
* @package phpMyAdmin
*/
abstract class PMA_SVG_Data_Element{
protected $label = '';
protected $dataRow = array();
/**
* Store user specified label and dataRow
* @param string $label users specified label
* @param array $dataRow A data row from the query result
*/
function __construct($label,$dataRow)
{
$this->label = $label;
$this->dataRow = $dataRow;
}
/**
* Handles the generation of each Data Row/Element as a SVG element
* @return the code related to a row in the GIS dataset
*/
public abstract function prepareRowAsSVG($options);
public function getLabel()
{
return $this->label;
}
public function setLabel($label)
{
$this->label = $label;
}
public function getDataRow()
{
return $this->dataRow;
}
public function setDataRow($dataRow)
{
$this->dataRow = $dataRow;
}
}
?>

View File

@ -0,0 +1,86 @@
<?php
/**
* Handles the visualization of Data Point objects.
*
* @package phpMyAdmin
*/
require_once 'pma_svg_data_element.php';
class PMA_SVG_Data_Point extends PMA_SVG_Data_Element
{
/*
* X-Coordinate of the point
*/
private $cx;
/*
* Y-Coordinate of the point
*/
private $cy;
/*
* A private constructor; prevents direct creation of object.
*/
public function __construct($cx, $cy, $label, $dataRow)
{
parent::__construct($label,$dataRow);
$this->cx = $cx;
$this->cy = $cy;
}
public function prepareRowAsSVG($options)
{
return $this->prepareSvg($options);
}
/**
* Prepares and returns the code related to a row in the query result as SVG.
*
* @param array $options Array containing options related to properties of the point
*
* @return the code related to a row in the query result.
*/
protected function prepareSvg($options)
{
$point_options = array(
'name' => $this->label . '_' .$options['id'],
'id' => $this->label . 'id' . '_' . $options['id'],
'class' => 'point',
'fill' => 'white',
'stroke' => $options['color'],
'stroke-width'=> 2,
);
$row = '<circle cx="' . $this->cx . '" cy="' . $this->cy . '" r=".1"';
foreach ($point_options as $option => $val) {
$row .= ' ' . $option . '="' . trim($val) . '"';
}
$row .= '/>';
return $row;
}
public function getCx()
{
return $this->cx;
}
public function setCx($cx)
{
$this->cx = $cx;
}
public function getCy()
{
return $this->cy;
}
public function setCy($cy)
{
$this->cy = $cy;
}
}
?>

View File

@ -0,0 +1,390 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Functions for the table-search page and zoom-search page
*
* Funtion PMA_tbl_getFields : Returns the fields of a table
* Funtion PMA_tbl_search_getWhereClause : Returns the where clause for query generation
*
* @package phpMyAdmin
*/
require_once 'url_generating.lib.php';
/**
* PMA_tbl_setTitle() sets the title for foreign keys display link
*
* @param $propertiesIconic Type of icon property
* @param $themeImage Icon Image
* @return string $str Value of the Title
*
*/
function PMA_tbl_setTitle($propertiesIconic,$pmaThemeImage){
if ($propertiesIconic == true) {
$str = '<img class="icon" width="16" height="16" src="' . $pmaThemeImage
.'b_browse.png" alt="' . __('Browse foreign values') . '" title="'
. __('Browse foreign values') . '" />';
if ($propertiesIconic === 'both') {
$str .= __('Browse foreign values');
return $str;
}
} else {
return __('Browse foreign values');
}
}
/**
* PMA_tbl_getFields() gets all the fields of a table along with their types,collations and whether null or not.
*
* @uses PMA_DBI_query()
* @uses PMA_backquote()
* @uses PMA_DBI_num_rows()
* @uses PMA_DBI_fetch_assoc()
* @uses PMA_DBI_free_result()
* @uses preg_replace()
* @uses str_replace()
* @uses strncasecmp()
* @uses empty()
*
* @param $db Selected database
* @param $table Selected table
*
* @return array($fields_list,$fields_type,$fields_collation,$fields_null) Array containing the field list, field types, collations and null constatint
*
*/
function PMA_tbl_getFields($table,$db) {
// Gets the list and number of fields
$result = PMA_DBI_query('SHOW FULL FIELDS FROM ' . PMA_backquote($table) . ' FROM ' . PMA_backquote($db) . ';', null, PMA_DBI_QUERY_STORE);
$fields_cnt = PMA_DBI_num_rows($result);
$fields_list = $fields_null = $fields_type = $fields_collation = array();
while ($row = PMA_DBI_fetch_assoc($result)) {
$fields_list[] = $row['Field'];
$type = $row['Type'];
// reformat mysql query output
if (strncasecmp($type, 'set', 3) == 0
|| strncasecmp($type, 'enum', 4) == 0) {
$type = str_replace(',', ', ', $type);
} else {
// strip the "BINARY" attribute, except if we find "BINARY(" because
// this would be a BINARY or VARBINARY field type
if (!preg_match('@BINARY[\(]@i', $type)) {
$type = preg_replace('@BINARY@i', '', $type);
}
$type = preg_replace('@ZEROFILL@i', '', $type);
$type = preg_replace('@UNSIGNED@i', '', $type);
$type = strtolower($type);
}
if (empty($type)) {
$type = '&nbsp;';
}
$fields_null[] = $row['Null'];
$fields_type[] = $type;
$fields_collation[] = !empty($row['Collation']) && $row['Collation'] != 'NULL'
? $row['Collation']
: '';
} // end while
PMA_DBI_free_result($result);
unset($result, $type);
return array($fields_list,$fields_type,$fields_collation,$fields_null);
}
/* PMA_tbl_setTableHeader() sets the table header for displaying a table in query-by-example format
*
* @return HTML content, the tags and content for table header
*
*/
function PMA_tbl_setTableHeader(){
return '<thead>
<tr><th>' . __('Column') . '</th>
<th>' . __('Type') . '</th>
<th>' . __('Collation') . '</th>
<th>' . __('Operator') . '</th>
<th>' . __('Value') . '</th>
</tr>
</thead>';
}
/* PMA_tbl_getSubTabs() returns an array with necessary configrations to create sub-tabs(Table Search and Zoom Search) in the table_select page
*
* @return array $subtabs Array containing configuration (icon,text,link,id,args) of sub-tabs for Table Search and Zoom search
*
*/
function PMA_tbl_getSubTabs(){
$subtabs = array();
$subtabs['search']['icon'] = 'b_search.png';
$subtabs['search']['text'] = __('Table Search');
$subtabs['search']['link'] = 'tbl_select.php';
$subtabs['search']['id'] = 'tbl_search_id';
$subtabs['search']['args']['pos'] = 0;
$subtabs['zoom']['icon'] = 'b_props.png';
$subtabs['zoom']['link'] = 'tbl_zoom_select.php';
$subtabs['zoom']['text'] = __('Zoom Search');
$subtabs['zoom']['id'] = 'zoom_search_id';
return $subtabs;
}
/* PMA_tbl_getForeignFields_Values() creates the HTML content for: 1) Browsing foreign data for a field. 2) Creating elements for search criteria input on fields.
*
* @uses PMA_foreignDropdown
* @uses PMA_generate_common_url
* @uses isset()
* @uses is_array()
* @uses in_array()
* @uses urlencode()
* @uses str_replace()
* @uses stbstr()
*
* @param $foreigners Array of foreign keys
* @param $foreignData Foreign keys data
* @param $field Column name
* @param $tbl_fields_type Column type
* @param $i Column index
* @param $db Selected database
* @param $table Selected table
* @param $titles Selected title
* @param $foreignMaxLimit Max limit of displaying foreign elements
* @param $fields Array of search criteria inputs
*
* @return string $str HTML content for viewing foreing data and elements for search criteria input.
*
*/
function PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fields_type, $i, $db, $table,$titles,$foreignMaxLimit, $fields){
$str = '';
if ($foreigners && isset($foreigners[$field]) && is_array($foreignData['disp_row'])) {
// f o r e i g n k e y s
$str .= ' <select name="fields[' . $i . ']" id="fieldID_' . $i .'">' . "\n";
// go back to first row
// here, the 4th parameter is empty because there is no current
// value of data for the dropdown (the search page initial values
// are displayed empty)
$str .= PMA_foreignDropdown($foreignData['disp_row'],
$foreignData['foreign_field'],
$foreignData['foreign_display'],
'', $foreignMaxLimit);
$str .= ' </select>' . "\n";
}
elseif ($foreignData['foreign_link'] == true) {
if(isset($fields[$i]) && is_string($fields[$i])){
$str .= '<input type="text" id="fieldID_' . $i .'"name="fields[' . $i . '] " value="' . $fields[$i] . '"';
'id="field_' . md5($field) . '[' . $i .']"
class="textfield"/>' ;
}
else{
$str .= '<input type="text" id="fieldID_' . $i .'"name="fields[' . $i . '] "';
'id="field_' . md5($field) . '[' . $i .']"
class="textfield" />' ;
}
?>
<?php $str .= '<script type="text/javascript">';
// <![CDATA[
$str .= <<<EOT
<a target="_blank" onclick="window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes'); return false" href="browse_foreigners.php?
EOT;
$str .= '' . PMA_generate_common_url($db, $table) . '&amp;field=' . urlencode($field) . '&amp;fieldkey=' . $i . '">' . str_replace("'", "\'", $titles['Browse']) . '</a>';
// ]]
$str .= '</script>';
}
elseif (strncasecmp($tbl_fields_type[$i], 'enum', 4) == 0) {
// e n u m s
$enum_value=explode(', ', str_replace("'", '', substr($tbl_fields_type[$i], 5, -1)));
$cnt_enum_value = count($enum_value);
$str .= '<select name="fields[' . ($i) . '][]" id="fieldID_' . $i .'"'
.' multiple="multiple" size="' . min(3, $cnt_enum_value) . '">' . "\n";
for ($j = 0; $j < $cnt_enum_value; $j++) {
if(isset($fields[$i]) && is_array($fields[$i]) && in_array($enum_value[$j],$fields[$i])){
$str .= ' <option value="' . $enum_value[$j] . '" Selected>'
. $enum_value[$j] . '</option>';
}
else{
$str .= ' <option value="' . $enum_value[$j] . '">'
. $enum_value[$j] . '</option>';
}
} // end for
$str .= ' </select>' . "\n";
}
else {
// o t h e r c a s e s
$the_class = 'textfield';
$type = $tbl_fields_type[$i];
if ($type == 'date') {
$the_class .= ' datefield';
} elseif ($type == 'datetime' || substr($type, 0, 9) == 'timestamp') {
$the_class .= ' datetimefield';
}
if(isset($fields[$i]) && is_string($fields[$i])){
$str .= ' <input type="text" name="fields[' . $i . ']" '
.' size="40" class="' . $the_class . '" id="fieldID_' . $i .'" value = "' . $fields[$i] . '"/>' . "\n";
}
else{
$str .= ' <input type="text" name="fields[' . $i . ']"'
.' size="40" class="' . $the_class . '" id="fieldID_' . $i .'" />' . "\n";
}
};
return $str;
}
/* PMA_tbl_search_getWhereClause() Return the where clause for query generation based on the inputs provided.
*
* @uses PMA_backquote
* @uses PMA_sqlAddslashes
* @uses preg_match
* @uses isset()
* @uses in_array()
* @uses str_replace()
* @uses strpos()
* @uses explode()
* @uses trim()
*
* @param $fields Search criteria input
* @param $names Name of the field(column) on which search criteria is submitted
* @param $types Type of the field
* @param $collations Field collation
* @param $func_type Search fucntion/operator
* @param $unaryFlag Whether operator unary or not
*
* @return string $str HTML content for viewing foreing data and elements for search criteria input.
*
*/
function PMA_tbl_search_getWhereClause($fields, $names, $types, $collations, $func_type, $unaryFlag){
$w = '';
if($unaryFlag){
$fields = '';
$w = PMA_backquote($names) . ' ' . $func_type;
} elseif (strncasecmp($types, 'enum', 4) == 0) {
if (!empty($fields)) {
if (! is_array($fields)) {
$fields = explode(',', $fields);
}
$enum_selected_count = count($fields);
if ($func_type == '=' && $enum_selected_count > 1) {
$func_type = 'IN';
$parens_open = '(';
$parens_close = ')';
} elseif ($func_type == '!=' && $enum_selected_count > 1) {
$func_type = 'NOT IN';
$parens_open = '(';
$parens_close = ')';
} else {
$parens_open = '';
$parens_close = '';
}
$enum_where = '\'' . PMA_sqlAddslashes($fields[0]) . '\'';
for ($e = 1; $e < $enum_selected_count; $e++) {
$enum_where .= ', \'' . PMA_sqlAddslashes($fields[$e]) . '\'';
}
$w = PMA_backquote($names) . ' ' . $func_type . ' ' . $parens_open . $enum_where . $parens_close;
}
} elseif ($fields != '') {
// For these types we quote the value. Even if it's another type (like INT),
// for a LIKE we always quote the value. MySQL converts strings to numbers
// and numbers to strings as necessary during the comparison
if (preg_match('@char|binary|blob|text|set|date|time|year@i', $types) || strpos(' ' . $func_type, 'LIKE')) {
$quot = '\'';
} else {
$quot = '';
}
// LIKE %...%
if ($func_type == 'LIKE %...%') {
$func_type = 'LIKE';
$fields = '%' . $fields . '%';
}
if ($func_type == 'REGEXP ^...$') {
$func_type = 'REGEXP';
$fields = '^' . $fields . '$';
}
if ($func_type == 'IN (...)' || $func_type == 'NOT IN (...)' || $func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN') {
$func_type = str_replace(' (...)', '', $func_type);
// quote values one by one
$values = explode(',', $fields);
foreach ($values as &$value)
$value = $quot . PMA_sqlAddslashes(trim($value)) . $quot;
if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN')
$w = PMA_backquote($names) . ' ' . $func_type . ' ' . (isset($values[0]) ? $values[0] : '') . ' AND ' . (isset($values[1]) ? $values[1] : '');
else
$w = PMA_backquote($names) . ' ' . $func_type . ' (' . implode(',', $values) . ')';
}
else {
$w = PMA_backquote($names) . ' ' . $func_type . ' ' . $quot . PMA_sqlAddslashes($fields) . $quot;;
}
} // end if
return $w;
}
/**
* Formats a SVG plot for the query results.
*
* @param array $data Data for the status chart
* @param array &$settings Settings used to generate the chart
*
* @return string HTML and JS code for the SVG plot
*/
function PMA_SVG_scatter_plot($data, &$settings)
{
require_once './libraries/svg_plot/pma_scatter_plot.php';
if (empty($data)) {
// empty data
return '';
} else {
$scatter_plot = new PMA_Scatter_Plot($data, $settings);
if ($settings != null) {
foreach ($scatter_plot->getSettings() as $setting => $val) {
if (! isset($settings[$setting])) {
$settings[$setting] = $val;
}
}
}
return $scatter_plot->asSVG();
}
}
?>

View File

@ -15,6 +15,7 @@
*/
require_once './libraries/common.inc.php';
require_once './libraries/mysql_charsets.lib.php';
require_once './libraries/tbl_select.lib.php';
$GLOBALS['js_include'][] = 'makegrid.js';
$GLOBALS['js_include'][] = 'sql.js';
@ -22,18 +23,8 @@ $GLOBALS['js_include'][] = 'tbl_select.js';
$GLOBALS['js_include'][] = 'tbl_change.js';
$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
if ($GLOBALS['cfg']['PropertiesIconic'] == true) {
$titles['Browse'] =
'<img class="icon" width="16" height="16" src="' . $pmaThemeImage
.'b_browse.png" alt="' . __('Browse foreign values') . '" title="'
. __('Browse foreign values') . '" />';
if ($GLOBALS['cfg']['PropertiesIconic'] === 'both') {
$titles['Browse'] .= __('Browse foreign values');
}
} else {
$titles['Browse'] = __('Browse foreign values');
}
$titles['Browse'] = PMA_tbl_setTitle($GLOBALS['cfg']['PropertiesIconic'], $pmaThemeImage);
/**
* Not selection yet required -> displays the selection form
@ -61,45 +52,26 @@ if (! isset($param) || $param[0] == '') {
$err_url = $goto . '?' . PMA_generate_common_url($db, $table);
// Gets the list and number of fields
$result = PMA_DBI_query('SHOW FULL FIELDS FROM ' . PMA_backquote($table) . ' FROM ' . PMA_backquote($db) . ';', null, PMA_DBI_QUERY_STORE);
$fields_cnt = PMA_DBI_num_rows($result);
$fields_list = $fields_null = $fields_type = $fields_collation = array();
while ($row = PMA_DBI_fetch_assoc($result)) {
$fields_list[] = $row['Field'];
$type = $row['Type'];
// reformat mysql query output
if (strncasecmp($type, 'set', 3) == 0
|| strncasecmp($type, 'enum', 4) == 0) {
$type = str_replace(',', ', ', $type);
} else {
// strip the "BINARY" attribute, except if we find "BINARY(" because
// this would be a BINARY or VARBINARY field type
if (!preg_match('@BINARY[\(]@i', $type)) {
$type = preg_replace('@BINARY@i', '', $type);
}
$type = preg_replace('@ZEROFILL@i', '', $type);
$type = preg_replace('@UNSIGNED@i', '', $type);
$type = strtolower($type);
}
if (empty($type)) {
$type = '&nbsp;';
}
$fields_null[] = $row['Null'];
$fields_type[] = $type;
$fields_collation[] = !empty($row['Collation']) && $row['Collation'] != 'NULL'
? $row['Collation']
: '';
} // end while
PMA_DBI_free_result($result);
unset($result, $type);
list($fields_list, $fields_type, $fields_collation, $fields_null) = PMA_tbl_getFields($table,$db);
$fields_cnt = count($fields_list);
// retrieve keys into foreign fields, if any
// check also foreigners even if relwork is FALSE (to get
// foreign keys from innodb)
$foreigners = PMA_getForeigners($db, $table);
?>
<fieldset id="fieldset_subtab">
<?php
$url_params = array();
$url_params['db'] = $db;
$url_params['table'] = $table;
echo PMA_generate_html_tabs(PMA_tbl_getSubTabs(), $url_params);
?>
<form method="post" action="tbl_select.php" name="insertForm" id="tbl_search_form" <?php echo ($GLOBALS['cfg']['AjaxEnable'] ? ' class="ajax"' : ''); ?>>
<?php echo PMA_generate_common_hidden_inputs($db, $table); ?>
<input type="hidden" name="goto" value="<?php echo $goto; ?>" />
@ -110,14 +82,7 @@ if (! isset($param) || $param[0] == '') {
<fieldset id="fieldset_table_qbe">
<legend><?php echo __('Do a "query by example" (wildcard: "%")') ?></legend>
<table class="data">
<thead>
<tr><th><?php echo __('Column'); ?></th>
<th><?php echo __('Type'); ?></th>
<th><?php echo __('Collation'); ?></th>
<th><?php echo __('Operator'); ?></th>
<th><?php echo __('Value'); ?></th>
</tr>
</thead>
<?php echo PMA_tbl_setTableHeader(); ?>
<tbody>
<?php
$odd_row = true;
@ -130,57 +95,31 @@ if (! isset($param) || $param[0] == '') {
<td><?php echo $fields_collation[$i]; ?></td>
<td><select name="func[]">
<?php
// determine valid operators
if (strncasecmp($fields_type[$i], 'enum', 4) == 0) {
// enum operators
$operators = array(
'=',
'!=',
);
foreach ($GLOBALS['cfg']['EnumOperators'] as $fc) {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
} elseif (preg_match('@char|blob|text|set@i', $fields_type[$i])) {
// text operators
$operators = array(
'LIKE',
'LIKE %...%',
'NOT LIKE',
'=',
'!=',
'REGEXP',
'REGEXP ^...$',
'NOT REGEXP',
"= ''",
"!= ''",
'IN (...)',
'NOT IN (...)',
'BETWEEN',
'NOT BETWEEN',
);
} else {
// numeric operators
$operators = array(
'=',
'>',
'>=',
'<',
'<=',
'!=',
'LIKE',
'NOT LIKE',
'IN (...)',
'NOT IN (...)',
'BETWEEN',
'NOT BETWEEN',
);
} // end if... else...
// if field can be NULL, add IS NULL and IS NOT NULL
if ($fields_null[$i]) {
$operators[] = 'IS NULL';
$operators[] = 'IS NOT NULL';
}
foreach ($operators as $op) {
foreach ($GLOBALS['cfg']['TextOperators'] as $fc) {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($op) . '">' . htmlspecialchars($op) . '</option>';
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
} else {
foreach ($GLOBALS['cfg']['NumOperators'] as $fc) {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
} // end if... else...
if ($fields_null[$i]) {
foreach ($GLOBALS['cfg']['NullOperators'] as $fc) {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
}
?>
@ -192,54 +131,9 @@ if (! isset($param) || $param[0] == '') {
$foreignData = PMA_getForeignData($foreigners, $field, false, '', '');
if ($foreigners && isset($foreigners[$field]) && is_array($foreignData['disp_row'])) {
// f o r e i g n k e y s
echo ' <select name="fields[' . $i . ']">' . "\n";
// go back to first row
// here, the 4th parameter is empty because there is no current
// value of data for the dropdown (the search page initial values
// are displayed empty)
echo PMA_foreignDropdown($foreignData['disp_row'],
$foreignData['foreign_field'],
$foreignData['foreign_display'],
'', $GLOBALS['cfg']['ForeignKeyMaxLimit']);
echo ' </select>' . "\n";
} elseif ($foreignData['foreign_link'] == true) {
?>
<input type="text" name="fields[<?php echo $i; ?>]"
id="field_<?php echo md5($field); ?>[<?php echo $i; ?>]"
class="textfield" />
<script type="text/javascript">
// <![CDATA[
document.writeln('<a target="_blank" onclick="window.open(this.href, \'foreigners\', \'width=640,height=240,scrollbars=yes\'); return false" href="browse_foreigners.php?<?php echo PMA_generate_common_url($db, $table); ?>&amp;field=<?php echo urlencode($field); ?>&amp;fieldkey=<?php echo $i; ?>"><?php echo str_replace("'", "\'", $titles['Browse']); ?></a>');
// ]]>
</script>
<?php
} elseif (strncasecmp($fields_type[$i], 'enum', 4) == 0) {
// e n u m s
$enum_value=explode(', ', str_replace("'", '', substr($fields_type[$i], 5, -1)));
$cnt_enum_value = count($enum_value);
echo ' <select name="fields[' . $i . '][]"'
.' multiple="multiple" size="' . min(3, $cnt_enum_value) . '">' . "\n";
for ($j = 0; $j < $cnt_enum_value; $j++) {
echo ' <option value="' . $enum_value[$j] . '">'
. $enum_value[$j] . '</option>';
} // end for
echo ' </select>' . "\n";
} else {
// o t h e r c a s e s
$the_class = 'textfield';
$type = $fields_type[$i];
if ($type == 'date') {
$the_class .= ' datefield';
} elseif ($type == 'datetime' || substr($type, 0, 9) == 'timestamp') {
$the_class .= ' datetimefield';
}
echo ' <input type="text" name="fields[' . $i . ']"'
.' size="40" class="' . $the_class . '" id="field_' . $i . '" />' . "\n";
};
?>
echo PMA_getForeignFields_Values($foreigners, $foreignData, $field, $fields_type, $i, $db, $table, $titles,$GLOBALS['cfg']['ForeignKeyMaxLimit'], '' );
?>
<input type="hidden" name="names[<?php echo $i; ?>]"
value="<?php echo htmlspecialchars($fields_list[$i]); ?>" />
<input type="hidden" name="types[<?php echo $i; ?>]"
@ -321,13 +215,20 @@ if (! isset($param) || $param[0] == '') {
<div id="sqlqueryresults"></div>
<?php
require './libraries/footer.inc.php';
?>
</fieldset>
<?php
}
/**
* Selection criteria have been submitted -> do the work
*/
else {
echo "ZZ";
// Builds the query
$sql_query = 'SELECT ' . (isset($distinct) ? 'DISTINCT ' : '');
@ -354,88 +255,18 @@ else {
$sql_query .= ' WHERE ' . $where;
} else {
$w = $charsets = array();
$unary_operators = array(
'IS NULL' => 1,
'IS NOT NULL' => 1,
"= ''" => 1,
"!= ''" => 1
);
$cnt_func = count($func);
reset($func);
while (list($i, $func_type) = each($func)) {
list($charsets[$i]) = explode('_', $collations[$i]);
if (isset($unary_operators[$func_type])) {
$fields[$i] = '';
$w[] = PMA_backquote($names[$i]) . ' ' . $func_type;
} elseif (strncasecmp($types[$i], 'enum', 4) == 0) {
if (!empty($fields[$i])) {
if (! is_array($fields[$i])) {
$fields[$i] = explode(',', $fields[$i]);
}
$enum_selected_count = count($fields[$i]);
if ($func_type == '=' && $enum_selected_count > 1) {
$func_type = $func[$i] = 'IN';
$parens_open = '(';
$parens_close = ')';
} elseif ($func_type == '!=' && $enum_selected_count > 1) {
$func_type = $func[$i] = 'NOT IN';
$parens_open = '(';
$parens_close = ')';
} else {
$parens_open = '';
$parens_close = '';
}
$enum_where = '\'' . PMA_sqlAddSlashes($fields[$i][0]) . '\'';
for ($e = 1; $e < $enum_selected_count; $e++) {
$enum_where .= ', \'' . PMA_sqlAddSlashes($fields[$i][$e]) . '\'';
}
$w[] = PMA_backquote($names[$i]) . ' ' . $func_type . ' ' . $parens_open . $enum_where . $parens_close;
}
} elseif ($fields[$i] != '') {
// For these types we quote the value. Even if it's another type (like INT),
// for a LIKE we always quote the value. MySQL converts strings to numbers
// and numbers to strings as necessary during the comparison
if (preg_match('@char|binary|blob|text|set|date|time|year@i', $types[$i]) || strpos(' ' . $func_type, 'LIKE')) {
$quot = '\'';
} else {
$quot = '';
}
// LIKE %...%
if ($func_type == 'LIKE %...%') {
$func_type = 'LIKE';
$fields[$i] = '%' . $fields[$i] . '%';
}
if ($func_type == 'REGEXP ^...$') {
$func_type = 'REGEXP';
$fields[$i] = '^' . $fields[$i] . '$';
}
if ($func_type == 'IN (...)' || $func_type == 'NOT IN (...)' || $func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN') {
$func_type = str_replace(' (...)', '', $func_type);
// quote values one by one
$values = explode(',', $fields[$i]);
foreach ($values as &$value)
$value = $quot . PMA_sqlAddSlashes(trim($value)) . $quot;
if ($func_type == 'BETWEEN' || $func_type == 'NOT BETWEEN')
$w[] = PMA_backquote($names[$i]) . ' ' . $func_type . ' ' . (isset($values[0]) ? $values[0] : '') . ' AND ' . (isset($values[1]) ? $values[1] : '');
else
$w[] = PMA_backquote($names[$i]) . ' ' . $func_type . ' (' . implode(',', $values) . ')';
}
else {
$w[] = PMA_backquote($names[$i]) . ' ' . $func_type . ' ' . $quot . PMA_sqlAddSlashes($fields[$i]) . $quot;;
}
} // end if
list($charsets[$i]) = explode('_', $collations[$i]);
$unaryFlag = (isset($GLOBALS['cfg']['UnaryOperators'][$func_type]) && $GLOBALS['cfg']['UnaryOperators'][$func_type] == 1) ? true : false;
$whereClause = PMA_tbl_search_getWhereClause($fields[$i],$names[$i], $types[$i], $collations[$i], $func_type, $unaryFlag);
if($whereClause)
$w[] = $whereClause;
} // end for
//print_r($w);
if ($w) {
$sql_query .= ' WHERE ' . implode(' AND ', $w);
}
@ -444,7 +275,6 @@ else {
if ($orderField != '--nil--') {
$sql_query .= ' ORDER BY ' . PMA_backquote($orderField) . ' ' . $order;
} // end if
require './sql.php';
}

447
tbl_zoom_select.php Normal file
View File

@ -0,0 +1,447 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Handles table zoom search tab
*
* display table zoom search form, create SQL queries from form data
*
*/
/**
* Gets some core libraries
*/
require_once './libraries/common.inc.php';
require_once './libraries/mysql_charsets.lib.php';
require_once './libraries/tbl_select.lib.php';
require_once './libraries/relation.lib.php';
require_once './libraries/tbl_info.inc.php';
$GLOBALS['js_include'][] = 'makegrid.js';
$GLOBALS['js_include'][] = 'sql.js';
$GLOBALS['js_include'][] = 'functions.js';
$GLOBALS['js_include'][] = 'tbl_zoom_plot.js';
$GLOBALS['js_include'][] = 'date.js';
$GLOBALS['js_include'][] = 'highcharts/highcharts.js';
/* Files required for chart exporting */
$GLOBALS['js_include'][] = 'highcharts/exporting.js';
$GLOBALS['js_include'][] = 'canvg/canvg.js';
$GLOBALS['js_include'][] = 'canvg/rgbcolor.js';
$GLOBALS['js_include'][] = 'jquery/jquery-ui-1.8.custom.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
/**
* Handle AJAX request for data row on point select
* @var post_params Object containing parameters for the POST request
*/
if (isset($_REQUEST['get_data_row']) && $_REQUEST['get_data_row'] == true) {
$extra_data = array();
$row_info_query = 'SELECT * FROM `' . $_REQUEST['db'] . '`.`' . $_REQUEST['table'] . '` WHERE ' . $_REQUEST['where_clause'];
$result = PMA_DBI_query( $row_info_query . ";" , null, PMA_DBI_QUERY_STORE);
$fields_meta = PMA_DBI_get_fields_meta($result);
while ($row = PMA_DBI_fetch_assoc($result))
$extra_data['row_info'] = $row;
PMA_ajaxResponse(NULL, true, $extra_data);
}
$titles['Browse'] = PMA_tbl_setTitle($GLOBALS['cfg']['PropertiesIconic'], $pmaThemeImage);
/**
* Not selection yet required -> displays the selection form
*/
// Gets some core libraries
require_once './libraries/tbl_common.php';
//$err_url = 'tbl_select.php' . $err_url;
$url_query .= '&amp;goto=tbl_select.php&amp;back=tbl_select.php';
/**
* Gets tables informations
*/
require_once './libraries/tbl_info.inc.php';
/**
* Displays top menu links
*/
require_once './libraries/tbl_links.inc.php';
if (! isset($goto)) {
$goto = $GLOBALS['cfg']['DefaultTabTable'];
}
// Defines the url to return to in case of error in the next sql statement
$err_url = $goto . '?' . PMA_generate_common_url($db, $table);
// Gets the list and number of fields
list($fields_list, $fields_type, $fields_collation, $fields_null) = PMA_tbl_getFields($table,$db);
$fields_cnt = count($fields_list);
// retrieve keys into foreign fields, if any
// check also foreigners even if relwork is FALSE (to get
// foreign keys from innodb)
$foreigners = PMA_getForeigners($db, $table);
$flag = 1;
$tbl_fields_type = $tbl_fields_collation = $tbl_fields_null = array();
if(!isset($zoom_submit) && !isset($inputs))
$dataLabel = PMA_getDisplayField($db,$table);
?>
<div id="sqlqueryresults"></div>
<fieldset id="fieldset_subtab">
<?php
$url_params = array();
$url_params['db'] = $db;
$url_params['table'] = $table;
echo PMA_generate_html_tabs(PMA_tbl_getSubTabs(), $url_params);
/**
* Set the field name,type,collation and whether null on select of a coulmn
*/
if(isset($inputs) && ($inputs[0] != __('pma_null') || $inputs[1] != __('pma_null')))
{
$flag = 2;
for($i = 0 ; $i < 4 ; $i++)
{
if($inputs[$i] != __('pma_null'))
{
$key = array_search($inputs[$i],$fields_list);
$tbl_fields_type[$i] = $fields_type[$key];
$tbl_fields_collation[$i] = $fields_collation[$key];
$tbl_fields_null[$i] = $fields_null[$key];
}
}
}
?>
<?php
/*
* Form for input criteria
*/
?>
<form method="post" action="tbl_zoom_select.php" name="zoomInputForm" id="zoom_search_form" <?php echo ($GLOBALS['cfg']['AjaxEnable'] ? ' class="ajax"' : ''); ?>>
<?php echo PMA_generate_common_hidden_inputs($db, $table); ?>
<input type="hidden" name="goto" value="<?php echo $goto; ?>" />
<input type="hidden" name="back" value="tbl_zoom_select.php" />
<input type="hidden" name="flag" id="id_flag" value=<?php echo $flag; ?> />
<fieldset id="inputSection">
<legend><?php echo __('Do a "query by example" (wildcard: "%") for two different columns') ?></legend>
<table class="data">
<?php echo PMA_tbl_setTableHeader();?>
<tbody>
<?php
$odd_row = true;
for($i = 0 ; $i < 4 ; $i++){
if($i == 2){
echo "<tr><td>";
echo __("Additional search criteria");
echo "</td><tr>";
}
?>
<tr class="noclick <?php echo $odd_row ? 'odd' : 'even'; $odd_row = ! $odd_row; ?>">
<th><select name="inputs[]" id=<?php echo 'tableid_' . $i?> >
<option value= <?php echo __('pma_null')?>><?php echo __('None'); ?> </option>
<?php
for ($j = 0 ; $j < $fields_cnt ; $j++){
if(isset($inputs[$i]) && $inputs[$i] == htmlspecialchars($fields_list[$j])){?>
<option value=<?php echo htmlspecialchars($fields_list[$j]);?> Selected> <?php echo htmlspecialchars($fields_list[$j]);?></option>
<?php
}
else{ ?>
<option value=<?php echo htmlspecialchars($fields_list[$j]);?> > <?php echo htmlspecialchars($fields_list[$j]);?></option>
<?php
}
} ?>
</select></th>
<td><?php if(isset($tbl_fields_type[$i]))echo $tbl_fields_type[$i]; ?></td>
<td><?php if(isset($tbl_fields_collation[$i]))echo $tbl_fields_collation[$i]; ?></td>
<td>
<?php if(isset($inputs) && $inputs[$i] != __('pma_null')){ ?>
<select name="zoomFunc[]">
<?php
if (strncasecmp($tbl_fields_type[$i], 'enum', 4) == 0) {
foreach ($GLOBALS['cfg']['EnumOperators'] as $fc) {
if(isset($zoomFunc[$i]) && $zoomFunc[$i] == htmlspecialchars($fc)){
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '" Selected>'
. htmlspecialchars($fc) . '</option>';
}
else {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
}
} elseif (preg_match('@char|blob|text|set@i', $tbl_fields_type[$i])) {
foreach ($GLOBALS['cfg']['TextOperators'] as $fc) {
if(isset($zoomFunc[$i]) && $zoomFunc[$i] == $fc){
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '" Selected>'
. htmlspecialchars($fc) . '</option>';
}
else {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
}
} else {
foreach ($GLOBALS['cfg']['NumOperators'] as $fc) {
if(isset($zoomFunc[$i]) && $zoomFunc[$i] == $fc){
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '" Selected>'
. htmlspecialchars($fc) . '</option>';
}
else {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
}
} // end if... else...
if ($tbl_fields_null[$i]) {
foreach ($GLOBALS['cfg']['NullOperators'] as $fc) {
if(isset($zoomFunc[$i]) && $zoomFunc[$i] == $fc){
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '" Selected>'
. htmlspecialchars($fc) . '</option>';
}
else {
echo "\n" . ' '
. '<option value="' . htmlspecialchars($fc) . '">'
. htmlspecialchars($fc) . '</option>';
}
}
}
?>
</select>
</td>
<td>
<?php
$field = $inputs[$i];
$foreignData = PMA_getForeignData($foreigners, $field, false, '', '');
if (isset($fields))
echo PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fields_type, $i ,$db, $table, $titles, $GLOBALS['cfg']['ForeignKeyMaxLimit'], $fields);
else
echo PMA_getForeignFields_Values($foreigners, $foreignData, $field, $tbl_fields_type, $i ,$db, $table, $titles, $GLOBALS['cfg']['ForeignKeyMaxLimit'], '');
}
else{ ?>
</td><td></td>
<?php } ?>
</td>
</tr>
<input type="hidden" name="types[<?php echo $i; ?>]" id="types_<?php echo $i; ?>"
value="<?php if(isset($tbl_fields_type[$i]))echo $tbl_fields_type[$i]; ?>" />
<input type="hidden" name="collations[<?php echo $i; ?>]"
value="<?php if(isset($tbl_fields_collation[$i]))echo $tbl_fields_collation[$i]; ?>" />
<?php
}//end for
?>
</table>
<?php
/*
* Other inputs like data label and mode go after selection of column criteria
*/
//Set default datalabel if not selected
if(isset($zoom_submit) && $inputs[0] != __('pma_null') && $inputs[1] != __('pma_null')) {
if ($dataLabel == '')
$dataLabel = PMA_getDisplayField($db,$table);
}
?>
<table class="data">
<tr><td><label for="label"><?php echo __("Data Label"); ?></label>&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</td>
<td><select name="dataLabel" id='dataLabel' >
<option value = ''> <?php echo __('None'); ?> </option>
<?php
for ($j = 0 ; $j < $fields_cnt ; $j++){
if(isset($dataLabel) && $dataLabel == htmlspecialchars($fields_list[$j])){?>
<option value=<?php echo htmlspecialchars($fields_list[$j]);?> Selected> <?php echo htmlspecialchars($fields_list[$j]);?></option>
<?php
}
else{ ?>
<option value=<?php echo htmlspecialchars($fields_list[$j]);?> > <?php echo htmlspecialchars($fields_list[$j]);?></option>
<?php
}
} ?>
</select>
</td></tr>
<tr><td><label for="label"><?php echo __("Maximum rows to plot"); ?></label></td>
<td>
<?php if(isset($maxPlotLimit)) { ?>
<input type="text" name="maxPlotLimit" value="<?php echo $maxPlotLimit; ?>" /></td></tr>
<?php
}
else { ?>
<input type="text" name="maxPlotLimit" value="<?php echo $GLOBALS['cfg']['maxRowPlotLimit']; ?>" /></td></tr>
<?php
} ?>
</table>
</fieldset>
<fieldset class="tblFooters">
<input type="hidden" name="max_number_of_fields"
value="<?php echo $fields_cnt; ?>" />
<input type="submit" name="zoom_submit" id="inputFormSubmitId" value="<?php echo __('Go'); ?>" />
</fieldset>
</form>
<?php
/*
* Handle the input criteria and gerate the query result
* Form for displaying query results
*/
if(isset($zoom_submit) && $inputs[0] != __('pma_null') && $inputs[1] != __('pma_null') && $inputs[0] != $inputs[1]) {
/*
* Query generation part
*/
$w = $data = array();
$sql_query = 'SELECT *';
//Add the table
$sql_query .= ' FROM ' . PMA_backquote($table);
for($i = 0 ; $i < 4 ; $i++){
if($inputs[$i] == __('pma_null'))
continue;
$tmp = array();
// The where clause
$charsets = array();
$cnt_func = count($zoomFunc[$i]);
$func_type = $zoomFunc[$i];
list($charsets[$i]) = explode('_', $collations[$i]);
$unaryFlag = (isset($GLOBALS['cfg']['UnaryOperators'][$func_type]) && $GLOBALS['cfg']['UnaryOperators'][$func_type] == 1) ? true : false;
$whereClause = PMA_tbl_search_getWhereClause($fields[$i],$inputs[$i], $types[$i], $collations[$i], $func_type, $unaryFlag);
if($whereClause)
$w[] = $whereClause;
} // end for
if ($w) {
$sql_query .= ' WHERE ' . implode(' AND ', $w);
}
$sql_query .= ' LIMIT ' . $maxPlotLimit;
/*
* Query execution part
*/
$result = PMA_DBI_query( $sql_query . ";" , null, PMA_DBI_QUERY_STORE);
$fields_meta = PMA_DBI_get_fields_meta($result);
while ($row = PMA_DBI_fetch_assoc($result)) {
//Need a row with indexes as 0,1,2 for the PMA_getUniqueCondition hence using a temporary array
$tmpRow = array();
foreach($row as $val)
$tmpRow[] = $val;
//Get unique conditon on each row (will be needed for row update)
$uniqueCondition = PMA_getUniqueCondition($result, $fields_cnt, $fields_meta, $tmpRow, true);
//Append it to row array as where_clause
$row['where_clause'] = $uniqueCondition[0];
if($dataLabel == $inputs[0] || $dataLabel == $inputs[1])
$data[] = array($inputs[0] => $row[$inputs[0]], $inputs[1] => $row[$inputs[1]], 'where_clause' => $uniqueCondition[0]);
else
$data[] = array($inputs[0] => $row[$inputs[0]], $inputs[1] => $row[$inputs[1]], $dataLabel => $row[$dataLabel], 'where_clause' => $uniqueCondition[0]);
}
?>
<?php
/*
* Form for displaying point data and also the scatter plot
*/
?>
<form method="post" action="tbl_zoom_select.php" name="displayResultForm" id="zoom_display_form" <?php echo ($GLOBALS['cfg']['AjaxEnable'] ? ' class="ajax"' : ''); ?>>
<?php echo PMA_generate_common_hidden_inputs($db, $table); ?>
<input type="hidden" name="goto" value="<?php echo $goto; ?>" />
<input type="hidden" name="back" value="tbl_zoom_select.php" />
<fieldset id="displaySection">
<legend><?php echo __('Browse/Edit the points') ?></legend>
<center>
<?php
//JSON encode the data(query result)
if(isset($zoom_submit) && !empty($data)){ ?>
<div id='resizer' style="width:600px;height:400px">
<?php if (isset($data)) ?><center> <a href="#" onClick="displayHelp();"><?php echo __('How to use'); ?></a> </center>
<div id="querydata" style="display:none">
<?php if(isset($data)) echo json_encode($data); ?>
</div>
<div id="querychart" style="float:right"></div>
</div>
<?php
} ?>
</center>
<fieldset id='dataDisplay' style="display:none">
<fieldset>
<table class="data">
<thead>
<tr>
<th> <?php echo __('Column'); ?> </th>
<th> <?php echo __('Null'); ?> </th>
<th> <?php echo __('Value'); ?> </th>
</tr>
</thead>
<tbody>
<?php
$odd_row = true;
for ($i = 4; $i < $fields_cnt + 4 ; $i++) {
$tbl_fields_type[$i] = $fields_type[$i - 4];
$fieldpopup = $fields_list[$i - 4];
$foreignData = PMA_getForeignData($foreigners, $fieldpopup, false, '', '');
?>
<tr class="noclick <?php echo $odd_row ? 'odd' : 'even'; $odd_row = ! $odd_row; ?>">
<th><?php echo htmlspecialchars($fields_list[$i - 4]); ?></th>
<th><?php echo '<input type="checkbox" class="checkbox_null" name="fields_null[ ' . $i . ' ]" id="fields_null_id_' . $i . '" />'; ?></th>
<th><?php echo PMA_getForeignFields_Values($foreigners, $foreignData, $fieldpopup, $tbl_fields_type, $i, $db, $table, $titles,$GLOBALS['cfg']['ForeignKeyMaxLimit'], '' ); ?> </th>
</tr>
<?php
} ?>
</tbody>
</table>
</fieldset>
<fieldset class="tblFooters">
<input type="submit" id="submitForm" name="edit_point" value="<?php echo __('Submit'); ?>" />
</fieldset>
</fieldset>
</fieldset>
<input type="hidden" id="queryID" name="sql_query" />
</form>
</fieldset>
<?php
}
?>
<?php
require './libraries/footer.inc.php';
?>