From 5894398c3609dfd795f714cc8cefb758d39656d4 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 13 May 2018 18:47:00 +0800 Subject: [PATCH] - Linting: ESLint (or ignore) JavaScript files; unfinished: editor/jgraduate and editor/extensions folders, editor/ (root), test/ (root) HTML - Fix: An apparent bug in jquery.svgicons.js whereby a variable `holder` was declared in too nested of a scope - Fix: `addBezierCurve` in canvg.js had undeclared `i` - Fix: Undeclared variable in opera widget - Fix: Screencast `showNotes` --- .eslintignore | 10 + editor/canvg/canvg.js | 5607 +++++++++-------- editor/canvg/rgbcolor.js | 553 +- editor/contextmenu/jquery.contextMenu.js | 326 +- editor/jgraduate/jpicker.js | 4016 ++++++------ editor/jgraduate/jquery.jgraduate.js | 1200 ++-- editor/spinbtn/JQuerySpinBtn.js | 300 +- editor/svgicons/jquery.svgicons.js | 705 +-- firefox-extension/content/svg-edit-overlay.js | 7 +- .../content/svg-edit-overlay.xul | 6 +- firefox-extension/handlers.js | 79 +- opera-widget/handlers.js | 55 +- opera-widget/index.html | 14 +- screencasts/svgopen2010/index.html | 4 +- screencasts/svgopen2010/script.js | 705 +-- wave/wave.js | 255 +- 16 files changed, 6846 insertions(+), 6996 deletions(-) diff --git a/.eslintignore b/.eslintignore index c4cd4b21..4c9b7d6c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,13 @@ node_modules + editor/jspdf/jspdf.min.js editor/jspdf/underscore-min.js +jgraduate/jpicker.min.js +jgraduate/jquery.jgraduate.js +jquery-ui +jquerybbq +js-hotkeys +spinbtn/JQuerySpinBtn.min.js +test/qunit +test/sinon +wave/json2.js diff --git a/editor/canvg/canvg.js b/editor/canvg/canvg.js index f0d6d98c..a125543f 100644 --- a/editor/canvg/canvg.js +++ b/editor/canvg/canvg.js @@ -1,2384 +1,2401 @@ +/* eslint-disable no-var, no-redeclare, new-cap */ +/* globals RGBColor, stackBlurCanvasRGBA, ActiveXObject */ /* * canvg.js - Javascript SVG parser and renderer on Canvas - * MIT Licensed + * MIT Licensed * Gabe Lerner (gabelerner@gmail.com) * http://code.google.com/p/canvg/ * * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ */ -(function(){ - // 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 - // opts: optional hash of options - // ignoreMouse: true => ignore mouse events - // ignoreAnimation: true => ignore animations - // ignoreDimensions: true => does not try to resize canvas - // ignoreClear: true => does not clear canvas - // offsetX: int => draws at a x offset - // offsetY: int => draws at a y offset - // scaleWidth: int => scales horizontally to width - // scaleHeight: int => scales vertically to height - // renderCallback: function => will call the function after the first render is completed - // forceRedraw: function => will call the function on every frame, if it returns true, will redraw - this.canvg = function (target, s, opts) { - // no parameters - if (target == null && s == null && opts == null) { - var svgTags = document.querySelectorAll('svg'); - for (var i=0; i ignore mouse events +// ignoreAnimation: true => ignore animations +// ignoreDimensions: true => does not try to resize canvas +// ignoreClear: true => does not clear canvas +// offsetX: int => draws at a x offset +// offsetY: int => draws at a y offset +// scaleWidth: int => scales horizontally to width +// scaleHeight: int => scales vertically to height +// renderCallback: function => will call the function after the first render is completed +// forceRedraw: function => will call the function on every frame, if it returns true, will redraw +canvg = function (target, s, opts) { + // no parameters + if (target == null && s == null && opts == null) { + var svgTags = document.querySelectorAll('svg'); + for (var i = 0; i < svgTags.length; i++) { + var svgTag = svgTags[i]; + var c = document.createElement('canvas'); + c.width = svgTag.clientWidth; + c.height = svgTag.clientHeight; + svgTag.parentNode.insertBefore(c, svgTag); + svgTag.parentNode.removeChild(svgTag); + var div = document.createElement('div'); + div.appendChild(svgTag); + canvg(c, div.innerHTML); } + return; } - function build(opts) { - var svg = { opts: opts }; - - svg.FRAMERATE = 30; - svg.MAX_VIRTUAL_PIXELS = 30000; - - svg.log = function(msg) {}; - if (svg.opts['log'] == true && typeof(console) != 'undefined') { - svg.log = function(msg) { console.log(msg); }; + if (typeof target === 'string') { + target = document.getElementById(target); + } + + // store class on canvas + if (target.svg != null) target.svg.stop(); + var svg = build(opts || {}); + // on i.e. 8 for flash canvas, we can't assign the property so check for it + if (!(target.childNodes.length === 1 && target.childNodes[0].nodeName === 'OBJECT')) { + target.svg = svg; + } + + var ctx = target.getContext('2d'); + if (typeof s.documentElement !== 'undefined') { + // load from xml doc + svg.loadXmlDoc(ctx, s); + } else if (s.substr(0, 1) === '<') { + // load from xml string + svg.loadXml(ctx, s); + } else { + // load from url + svg.load(ctx, s); + } +}; + +function build (opts) { + var svg = {opts: opts}; + + svg.FRAMERATE = 30; + svg.MAX_VIRTUAL_PIXELS = 30000; + + svg.log = function (msg) {}; + if (svg.opts.log === true && typeof console !== 'undefined') { + svg.log = function (msg) { console.log(msg); }; + }; + + // globals + svg.init = function (ctx) { + var uniqueId = 0; + svg.UniqueId = function () { uniqueId++; return 'canvg' + uniqueId; }; + svg.Definitions = {}; + svg.Styles = {}; + svg.Animations = []; + svg.Images = []; + 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]; }; + this.width = function () { return this.Current().width; }; + this.height = function () { return this.Current().height; }; + this.ComputeSize = function (d) { + if (d != null && typeof d === 'number') return d; + if (d === 'x') return this.width(); + if (d === 'y') return this.height(); + return Math.sqrt(Math.pow(this.width(), 2) + Math.pow(this.height(), 2)) / Math.sqrt(2); + }; + }(); + }; + svg.init(); + + // images loaded + svg.ImagesLoaded = function () { + for (var i = 0; i < svg.Images.length; i++) { + if (!svg.Images[i].loaded) return false; + } + return true; + }; + + // trim + svg.trim = function (s) { return s.replace(/^\s+|\s+$/g, ''); }; + + // compress spaces + svg.compressSpaces = function (s) { return s.replace(/[\s\r\t\n]+/gm, ' '); }; + + // ajax + svg.ajax = function (url) { + var AJAX; + if (window.XMLHttpRequest) { + AJAX = new XMLHttpRequest(); + } else { + AJAX = new ActiveXObject('Microsoft.XMLHTTP'); + } + if (AJAX) { + AJAX.open('GET', url, false); + AJAX.send(null); + return AJAX.responseText; + } + return null; + }; + + // parse xml + svg.parseXml = function (xml) { + if (window.DOMParser) { + var parser = new DOMParser(); + return parser.parseFromString(xml, 'text/xml'); + } else { + xml = xml.replace(/]*>/, ''); + var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); + xmlDoc.async = 'false'; + xmlDoc.loadXML(xml); + return xmlDoc; + } + }; + + svg.Property = function (name, value) { + this.name = name; + this.value = value; + }; + svg.Property.prototype.getValue = function () { + return this.value; + }; + + svg.Property.prototype.hasValue = function () { + return (this.value != null && this.value !== ''); + }; + + // return the numerical value of the property + svg.Property.prototype.numValue = function () { + if (!this.hasValue()) return 0; + + var n = parseFloat(this.value); + if ((this.value + '').match(/%$/)) { + n = n / 100.0; + } + return n; + }; + + svg.Property.prototype.valueOrDefault = function (def) { + if (this.hasValue()) return this.value; + return def; + }; + + svg.Property.prototype.numValueOrDefault = function (def) { + if (this.hasValue()) return this.numValue(); + return def; + }; + + // color extensions + // augment the current color value with the opacity + svg.Property.prototype.addOpacity = function (opacityProp) { + var newValue = this.value; + if (opacityProp.value != null && opacityProp.value !== '' && typeof this.value === 'string') { // can only add opacity to colors, not patterns + var color = new RGBColor(this.value); + if (color.ok) { + newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacityProp.numValue() + ')'; + } + } + return new svg.Property(this.name, newValue); + }; + + // definition extensions + // get the definition from the definitions table + svg.Property.prototype.getDefinition = function () { + var name = this.value.match(/#([^)'"]+)/); + if (name) { name = name[1]; } + if (!name) { name = this.value; } + return svg.Definitions[name]; + }; + + svg.Property.prototype.isUrlDefinition = function () { + return this.value.indexOf('url(') === 0; + }; + + svg.Property.prototype.getFillStyleDefinition = function (e, opacityProp) { + var def = this.getDefinition(); + + // gradient + if (def != null && def.createGradient) { + return def.createGradient(svg.ctx, e, opacityProp); + } + + // pattern + if (def != null && def.createPattern) { + if (def.getHrefAttribute().hasValue()) { + var pt = def.attribute('patternTransform'); + def = def.getHrefAttribute().getDefinition(); + if (pt.hasValue()) { def.attribute('patternTransform', true).value = pt.value; } + } + return def.createPattern(svg.ctx, e); + } + + return null; + }; + + // length extensions + svg.Property.prototype.getDPI = function (viewPort) { + return 96.0; // TODO: compute? + }; + + svg.Property.prototype.getEM = function (viewPort) { + var em = 12; + + var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); + if (fontSize.hasValue()) em = fontSize.toPixels(viewPort); + + return em; + }; + + svg.Property.prototype.getUnits = function () { + var s = this.value + ''; + return s.replace(/[0-9.-]/g, ''); + }; + + // get the length as pixels + svg.Property.prototype.toPixels = function (viewPort, processPercent) { + if (!this.hasValue()) return 0; + var s = this.value + ''; + if (s.match(/em$/)) return this.numValue() * this.getEM(viewPort); + if (s.match(/ex$/)) return this.numValue() * this.getEM(viewPort) / 2.0; + if (s.match(/px$/)) return this.numValue(); + if (s.match(/pt$/)) return this.numValue() * this.getDPI(viewPort) * (1.0 / 72.0); + if (s.match(/pc$/)) return this.numValue() * 15; + if (s.match(/cm$/)) return this.numValue() * this.getDPI(viewPort) / 2.54; + if (s.match(/mm$/)) return this.numValue() * this.getDPI(viewPort) / 25.4; + if (s.match(/in$/)) return this.numValue() * this.getDPI(viewPort); + if (s.match(/%$/)) return this.numValue() * svg.ViewPort.ComputeSize(viewPort); + var n = this.numValue(); + if (processPercent && n < 1.0) return n * svg.ViewPort.ComputeSize(viewPort); + return n; + }; + + // time extensions + // get the time as milliseconds + svg.Property.prototype.toMilliseconds = function () { + if (!this.hasValue()) return 0; + var s = this.value + ''; + if (s.match(/s$/)) return this.numValue() * 1000; + if (s.match(/ms$/)) return this.numValue(); + return this.numValue(); + }; + + // angle extensions + // get the angle as radians + svg.Property.prototype.toRadians = function () { + if (!this.hasValue()) return 0; + var s = this.value + ''; + if (s.match(/deg$/)) return this.numValue() * (Math.PI / 180.0); + if (s.match(/grad$/)) return this.numValue() * (Math.PI / 200.0); + if (s.match(/rad$/)) return this.numValue(); + return this.numValue() * (Math.PI / 180.0); + }; + + // text extensions + // get the text baseline + var textBaselineMapping = { + 'baseline': 'alphabetic', + 'before-edge': 'top', + 'text-before-edge': 'top', + 'middle': 'middle', + 'central': 'middle', + 'after-edge': 'bottom', + 'text-after-edge': 'bottom', + 'ideographic': 'ideographic', + 'alphabetic': 'alphabetic', + 'hanging': 'hanging', + 'mathematical': 'alphabetic' + }; + svg.Property.prototype.toTextBaseline = function () { + if (!this.hasValue()) return null; + return textBaselineMapping[this.value]; + }; + + // fonts + svg.Font = new function () { + this.Styles = 'normal|italic|oblique|inherit'; + this.Variants = 'normal|small-caps|inherit'; + this.Weights = 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit'; + + this.CreateFont = function (fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { + var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); + return { + fontFamily: fontFamily || f.fontFamily, + fontSize: fontSize || f.fontSize, + fontStyle: fontStyle || f.fontStyle, + fontWeight: fontWeight || f.fontWeight, + fontVariant: fontVariant || f.fontVariant, + toString: function () { + return [ + this.fontStyle, this.fontVariant, this.fontWeight, + this.fontSize, this.fontFamily + ].join(' '); + } + }; }; - - // globals - svg.init = function(ctx) { - var uniqueId = 0; - svg.UniqueId = function () { uniqueId++; return 'canvg' + uniqueId; }; - svg.Definitions = {}; - svg.Styles = {}; - svg.Animations = []; - svg.Images = []; - 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]; } - this.width = function() { return this.Current().width; } - this.height = function() { return this.Current().height; } - this.ComputeSize = function(d) { - if (d != null && typeof(d) == 'number') return d; - if (d == 'x') return this.width(); - if (d == 'y') return this.height(); - return Math.sqrt(Math.pow(this.width(), 2) + Math.pow(this.height(), 2)) / Math.sqrt(2); - } - }); - } - svg.init(); - - // images loaded - svg.ImagesLoaded = function() { - for (var i=0; i -1) { + if (d[i] !== 'inherit') f.fontStyle = d[i]; set.fontStyle = true; + } else if (!set.fontVariant && that.Variants.indexOf(d[i]) > -1) { + if (d[i] !== 'inherit') f.fontVariant = d[i]; set.fontStyle = set.fontVariant = true; + } else if (!set.fontWeight && that.Weights.indexOf(d[i]) > -1) { + if (d[i] !== 'inherit') f.fontWeight = d[i]; set.fontStyle = set.fontVariant = set.fontWeight = true; + } else if (!set.fontSize) { + if (d[i] !== 'inherit') f.fontSize = d[i].split('/')[0]; set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true; + } else { + if (d[i] !== 'inherit') ff += d[i]; + } } - return null; - } - - // parse xml - svg.parseXml = function(xml) { - if (window.DOMParser) - { - var parser = new DOMParser(); - return parser.parseFromString(xml, 'text/xml'); - } - else - { - xml = xml.replace(/]*>/, ''); - var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(xml); - return xmlDoc; - } - } - - svg.Property = function(name, value) { - this.name = name; - this.value = value; - } - svg.Property.prototype.getValue = function() { - return this.value; - } - - svg.Property.prototype.hasValue = function() { - return (this.value != null && this.value !== ''); - } - - // return the numerical value of the property - svg.Property.prototype.numValue = function() { - if (!this.hasValue()) return 0; - - var n = parseFloat(this.value); - if ((this.value + '').match(/%$/)) { - n = n / 100.0; - } - return n; - } - - svg.Property.prototype.valueOrDefault = function(def) { - if (this.hasValue()) return this.value; - return def; - } - - svg.Property.prototype.numValueOrDefault = function(def) { - if (this.hasValue()) return this.numValue(); - return def; - } - - // color extensions - // augment the current color value with the opacity - svg.Property.prototype.addOpacity = function(opacityProp) { - var newValue = this.value; - if (opacityProp.value != null && opacityProp.value != '' && typeof(this.value)=='string') { // can only add opacity to colors, not patterns - var color = new RGBColor(this.value); - if (color.ok) { - newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacityProp.numValue() + ')'; - } - } - return new svg.Property(this.name, newValue); - } - - // definition extensions - // get the definition from the definitions table - svg.Property.prototype.getDefinition = function() { - var name = this.value.match(/#([^\)'"]+)/); - if (name) { name = name[1]; } - if (!name) { name = this.value; } - return svg.Definitions[name]; - } - - svg.Property.prototype.isUrlDefinition = function() { - return this.value.indexOf('url(') == 0 - } - - svg.Property.prototype.getFillStyleDefinition = function(e, opacityProp) { - var def = this.getDefinition(); - - // gradient - if (def != null && def.createGradient) { - return def.createGradient(svg.ctx, e, opacityProp); - } - - // pattern - if (def != null && def.createPattern) { - if (def.getHrefAttribute().hasValue()) { - var pt = def.attribute('patternTransform'); - def = def.getHrefAttribute().getDefinition(); - if (pt.hasValue()) { def.attribute('patternTransform', true).value = pt.value; } - } - return def.createPattern(svg.ctx, e); - } - - return null; - } - - // length extensions - svg.Property.prototype.getDPI = function(viewPort) { - return 96.0; // TODO: compute? - } - - svg.Property.prototype.getEM = function(viewPort) { - var em = 12; - - var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); - if (fontSize.hasValue()) em = fontSize.toPixels(viewPort); - - return em; - } - - svg.Property.prototype.getUnits = function() { - var s = this.value+''; - return s.replace(/[0-9\.\-]/g,''); - } - - // get the length as pixels - svg.Property.prototype.toPixels = function(viewPort, processPercent) { - if (!this.hasValue()) return 0; - var s = this.value+''; - if (s.match(/em$/)) return this.numValue() * this.getEM(viewPort); - if (s.match(/ex$/)) return this.numValue() * this.getEM(viewPort) / 2.0; - if (s.match(/px$/)) return this.numValue(); - if (s.match(/pt$/)) return this.numValue() * this.getDPI(viewPort) * (1.0 / 72.0); - if (s.match(/pc$/)) return this.numValue() * 15; - if (s.match(/cm$/)) return this.numValue() * this.getDPI(viewPort) / 2.54; - if (s.match(/mm$/)) return this.numValue() * this.getDPI(viewPort) / 25.4; - if (s.match(/in$/)) return this.numValue() * this.getDPI(viewPort); - if (s.match(/%$/)) return this.numValue() * svg.ViewPort.ComputeSize(viewPort); - var n = this.numValue(); - if (processPercent && n < 1.0) return n * svg.ViewPort.ComputeSize(viewPort); - return n; - } + if (ff !== '') f.fontFamily = ff; + return f; + }; + }(); - // time extensions - // get the time as milliseconds - svg.Property.prototype.toMilliseconds = function() { - if (!this.hasValue()) return 0; - var s = this.value+''; - if (s.match(/s$/)) return this.numValue() * 1000; - if (s.match(/ms$/)) return this.numValue(); - return this.numValue(); + // points and paths + svg.ToNumberArray = function (s) { + var a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' '); + for (var i = 0; i < a.length; i++) { + a[i] = parseFloat(a[i]); + } + return a; + }; + svg.Point = function (x, y) { + this.x = x; + this.y = y; + }; + svg.Point.prototype.angleTo = function (p) { + return Math.atan2(p.y - this.y, p.x - this.x); + }; + + svg.Point.prototype.applyTransform = function (v) { + var xp = this.x * v[0] + this.y * v[2] + v[4]; + var yp = this.x * v[1] + this.y * v[3] + v[5]; + this.x = xp; + this.y = yp; + }; + + svg.CreatePoint = function (s) { + var a = svg.ToNumberArray(s); + return new svg.Point(a[0], a[1]); + }; + svg.CreatePath = function (s) { + var a = svg.ToNumberArray(s); + var path = []; + for (var i = 0; i < a.length; i += 2) { + path.push(new svg.Point(a[i], a[i + 1])); + } + return path; + }; + + // bounding box + svg.BoundingBox = function (x1, y1, x2, y2) { // pass in initial points if you want + this.x1 = Number.NaN; + this.y1 = Number.NaN; + this.x2 = Number.NaN; + this.y2 = Number.NaN; + + this.x = function () { return this.x1; }; + this.y = function () { return this.y1; }; + this.width = function () { return this.x2 - this.x1; }; + this.height = function () { return this.y2 - this.y1; }; + + this.addPoint = function (x, y) { + if (x != null) { + if (isNaN(this.x1) || isNaN(this.x2)) { + this.x1 = x; + this.x2 = x; } - - // angle extensions - // get the angle as radians - svg.Property.prototype.toRadians = function() { - if (!this.hasValue()) return 0; - var s = this.value+''; - if (s.match(/deg$/)) return this.numValue() * (Math.PI / 180.0); - if (s.match(/grad$/)) return this.numValue() * (Math.PI / 200.0); - if (s.match(/rad$/)) return this.numValue(); - return this.numValue() * (Math.PI / 180.0); + if (x < this.x1) this.x1 = x; + if (x > this.x2) this.x2 = x; + } + + if (y != null) { + if (isNaN(this.y1) || isNaN(this.y2)) { + this.y1 = y; + this.y2 = y; } - - // text extensions - // get the text baseline - var textBaselineMapping = { - 'baseline': 'alphabetic', - 'before-edge': 'top', - 'text-before-edge': 'top', - 'middle': 'middle', - 'central': 'middle', - 'after-edge': 'bottom', - 'text-after-edge': 'bottom', - 'ideographic': 'ideographic', - 'alphabetic': 'alphabetic', - 'hanging': 'hanging', - 'mathematical': 'alphabetic' + if (y < this.y1) this.y1 = y; + if (y > this.y2) this.y2 = y; + } + }; + this.addX = function (x) { this.addPoint(x, null); }; + this.addY = function (y) { this.addPoint(null, y); }; + + this.addBoundingBox = function (bb) { + this.addPoint(bb.x1, bb.y1); + this.addPoint(bb.x2, bb.y2); + }; + + this.addQuadraticCurve = function (p0x, p0y, p1x, p1y, p2x, p2y) { + var cp1x = p0x + 2 / 3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp1y = p0y + 2 / 3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) + var cp2x = cp1x + 1 / 3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) + var cp2y = cp1y + 1 / 3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) + this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); + }; + + this.addBezierCurve = function (p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { + // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; + this.addPoint(p0[0], p0[1]); + this.addPoint(p3[0], p3[1]); + + for (var i = 0; i <= 1; i++) { + var f = function (t) { + return Math.pow(1 - t, 3) * p0[i] + + 3 * Math.pow(1 - t, 2) * t * p1[i] + + 3 * (1 - t) * Math.pow(t, 2) * p2[i] + + Math.pow(t, 3) * p3[i]; }; - svg.Property.prototype.toTextBaseline = function () { - if (!this.hasValue()) return null; - return textBaselineMapping[this.value]; + + var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; + var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; + var c = 3 * p1[i] - 3 * p0[i]; + + if (a === 0) { + if (b === 0) continue; + var t = -c / b; + if (t > 0 && t < 1) { + if (i === 0) this.addX(f(t)); + if (i === 1) this.addY(f(t)); + } + continue; + } + + var b2ac = Math.pow(b, 2) - 4 * c * a; + if (b2ac < 0) continue; + var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); + if (t1 > 0 && t1 < 1) { + if (i === 0) this.addX(f(t1)); + if (i === 1) this.addY(f(t1)); + } + var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); + if (t2 > 0 && t2 < 1) { + if (i === 0) this.addX(f(t2)); + if (i === 1) this.addY(f(t2)); } - - // fonts - svg.Font = new (function() { - this.Styles = 'normal|italic|oblique|inherit'; - this.Variants = 'normal|small-caps|inherit'; - this.Weights = 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit'; - - this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { - var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); - return { - fontFamily: fontFamily || f.fontFamily, - fontSize: fontSize || f.fontSize, - fontStyle: fontStyle || f.fontStyle, - fontWeight: fontWeight || f.fontWeight, - fontVariant: fontVariant || f.fontVariant, - toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } - } } - - var that = this; - this.Parse = function(s) { - var f = {}; - var d = svg.trim(svg.compressSpaces(s || '')).split(' '); - var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } - var ff = ''; - for (var i=0; i= 0; i--) { + this.transforms[i].unapply(ctx); } - return a; - } - svg.Point = function(x, y) { - this.x = x; - this.y = y; - } - svg.Point.prototype.angleTo = function(p) { - return Math.atan2(p.y - this.y, p.x - this.x); + }; + + this.applyToPoint = function (p) { + for (var i = 0; i < this.transforms.length; i++) { + this.transforms[i].applyToPoint(p); } - - svg.Point.prototype.applyTransform = function(v) { - var xp = this.x * v[0] + this.y * v[2] + v[4]; - var yp = this.x * v[1] + this.y * v[3] + v[5]; - this.x = xp; - this.y = yp; + }; + + var data = svg.trim(svg.compressSpaces(v)).replace(/\)([a-zA-Z])/g, ') $1').replace(/\)(\s?,\s?)/g, ') ').split(/\s(?=[a-z])/); + for (var i = 0; i < data.length; i++) { + var type = svg.trim(data[i].split('(')[0]); + var s = data[i].split('(')[1].replace(')', ''); + var transform = new this.Type[type](s); + transform.type = type; + this.transforms.push(transform); + } + }; + + // aspect ratio + svg.AspectRatio = function (ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) { + // aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute + aspectRatio = svg.compressSpaces(aspectRatio); + aspectRatio = aspectRatio.replace(/^defer\s/, ''); // ignore defer + var align = aspectRatio.split(' ')[0] || 'xMidYMid'; + var meetOrSlice = aspectRatio.split(' ')[1] || 'meet'; + + // calculate scale + var scaleX = width / desiredWidth; + var scaleY = height / desiredHeight; + var scaleMin = Math.min(scaleX, scaleY); + var scaleMax = Math.max(scaleX, scaleY); + if (meetOrSlice === 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; } + if (meetOrSlice === 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; } + + refX = new svg.Property('refX', refX); + refY = new svg.Property('refY', refY); + if (refX.hasValue() && refY.hasValue()) { + ctx.translate(-scaleMin * refX.toPixels('x'), -scaleMin * refY.toPixels('y')); + } else { + // align + if (align.match(/^xMid/) && ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) ctx.translate(width / 2.0 - desiredWidth / 2.0, 0); + if (align.match(/YMid$/) && ((meetOrSlice === 'meet' && scaleMin === scaleX) || (meetOrSlice === 'slice' && scaleMax === scaleX))) ctx.translate(0, height / 2.0 - desiredHeight / 2.0); + if (align.match(/^xMax/) && ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) ctx.translate(width - desiredWidth, 0); + if (align.match(/YMax$/) && ((meetOrSlice === 'meet' && scaleMin === scaleX) || (meetOrSlice === 'slice' && scaleMax === scaleX))) ctx.translate(0, height - desiredHeight); + } + + // scale + if (align === 'none') ctx.scale(scaleX, scaleY); + else if (meetOrSlice === 'meet') ctx.scale(scaleMin, scaleMin); + else if (meetOrSlice === 'slice') ctx.scale(scaleMax, scaleMax); + + // translate + ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY); + }; + + // elements + svg.Element = {}; + + svg.EmptyProperty = new svg.Property('EMPTY', ''); + + svg.Element.ElementBase = function (node) { + this.attributes = {}; + this.styles = {}; + this.children = []; + + // get or create attribute + this.attribute = function (name, createIfNotExists) { + var a = this.attributes[name]; + if (a != null) return a; + + if (createIfNotExists === true) { a = new svg.Property(name, ''); this.attributes[name] = a; } + return a || svg.EmptyProperty; + }; + + this.getHrefAttribute = function () { + for (var a in this.attributes) { + if (a.match(/:href$/)) { + return this.attributes[a]; + } + } + return svg.EmptyProperty; + }; + + // get or create style, crawls up node tree + this.style = function (name, createIfNotExists, skipAncestors) { + var s = this.styles[name]; + if (s != null) return s; + + var a = this.attribute(name); + if (a != null && a.hasValue()) { + this.styles[name] = a; // move up to me to cache + return a; } - svg.CreatePoint = function(s) { - var a = svg.ToNumberArray(s); - return new svg.Point(a[0], a[1]); - } - svg.CreatePath = function(s) { - var a = svg.ToNumberArray(s); - var path = []; - for (var i=0; i this.x2) this.x2 = x; - } - - if (y != null) { - if (isNaN(this.y1) || isNaN(this.y2)) { - this.y1 = y; - this.y2 = y; - } - if (y < this.y1) this.y1 = y; - if (y > this.y2) this.y2 = y; - } - } - this.addX = function(x) { this.addPoint(x, null); } - this.addY = function(y) { this.addPoint(null, y); } - - this.addBoundingBox = function(bb) { - this.addPoint(bb.x1, bb.y1); - this.addPoint(bb.x2, bb.y2); - } - - this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { - var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) - var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) - this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); - } - - this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { - // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; - this.addPoint(p0[0], p0[1]); - this.addPoint(p3[0], p3[1]); - - for (i=0; i<=1; i++) { - var f = function(t) { - return Math.pow(1-t, 3) * p0[i] - + 3 * Math.pow(1-t, 2) * t * p1[i] - + 3 * (1-t) * Math.pow(t, 2) * p2[i] - + Math.pow(t, 3) * p3[i]; - } - - var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; - var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; - var c = 3 * p1[i] - 3 * p0[i]; - - if (a == 0) { - if (b == 0) continue; - var t = -c / b; - if (0 < t && t < 1) { - if (i == 0) this.addX(f(t)); - if (i == 1) this.addY(f(t)); - } - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - if (b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - if (0 < t1 && t1 < 1) { - if (i == 0) this.addX(f(t1)); - if (i == 1) this.addY(f(t1)); - } - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - if (0 < t2 && t2 < 1) { - if (i == 0) this.addX(f(t2)); - if (i == 1) this.addY(f(t2)); + if (skipAncestors !== true) { + var p = this.parent; + if (p != null) { + var ps = p.style(name); + if (ps != null && ps.hasValue()) { + return ps; } } } - - this.isPointInBox = function(x, y) { - return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); + + if (createIfNotExists === true) { s = new svg.Property(name, ''); this.styles[name] = s; } + return s || svg.EmptyProperty; + }; + + // base render + this.render = function (ctx) { + // don't render display=none + if (this.style('display').value === 'none') return; + + // don't render visibility=hidden + if (this.style('visibility').value === 'hidden') return; + + ctx.save(); + if (this.attribute('mask').hasValue()) { // mask + var mask = this.attribute('mask').getDefinition(); + if (mask != null) mask.apply(ctx, this); + } else if (this.style('filter').hasValue()) { // filter + var filter = this.style('filter').getDefinition(); + if (filter != null) filter.apply(ctx, this); + } else { + this.setContext(ctx); + this.renderChildren(ctx); + this.clearContext(ctx); } - - this.addPoint(x1, y1); - this.addPoint(x2, y2); - } - - // transforms - svg.Transform = function(v) { - var that = this; - this.Type = {} - - // translate - this.Type.translate = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.translate(this.p.x || 0.0, this.p.y || 0.0); - } - this.unapply = function(ctx) { - ctx.translate(-1.0 * this.p.x || 0.0, -1.0 * this.p.y || 0.0); - } - this.applyToPoint = function(p) { - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); + ctx.restore(); + }; + + // base set context + this.setContext = function (ctx) { + // OVERRIDE ME! + }; + + // base clear context + this.clearContext = function (ctx) { + // OVERRIDE ME! + }; + + // base render children + this.renderChildren = function (ctx) { + for (var i = 0; i < this.children.length; i++) { + this.children[i].render(ctx); + } + }; + + this.addChild = function (childNode, create) { + var child = childNode; + if (create) child = svg.CreateElement(childNode); + child.parent = this; + if (child.type !== 'title') { this.children.push(child); } + }; + + if (node != null && node.nodeType === 1) { // ELEMENT_NODE + // add children + for (var i = 0; i < node.childNodes.length; i++) { + var childNode = node.childNodes[i]; + if (childNode.nodeType === 1) this.addChild(childNode, true); // ELEMENT_NODE + if (this.captureTextNodes && (childNode.nodeType === 3 || childNode.nodeType === 4)) { + var text = childNode.nodeValue || childNode.text || ''; + if (svg.trim(svg.compressSpaces(text)) !== '') { + this.addChild(new svg.Element.tspan(childNode), false); // TEXT_NODE + } } } - - // rotate - this.Type.rotate = function(s) { - var a = svg.ToNumberArray(s); - this.angle = new svg.Property('angle', a[0]); - this.cx = a[1] || 0; - this.cy = a[2] || 0; - this.apply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(this.angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.unapply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(-1.0 * this.angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.applyToPoint = function(p) { - var a = this.angle.toRadians(); - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); - p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); - } + + // add attributes + for (var i = 0; i < node.attributes.length; i++) { + var attribute = node.attributes[i]; + this.attributes[attribute.nodeName] = new svg.Property(attribute.nodeName, attribute.nodeValue); } - - this.Type.scale = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); - } - this.unapply = function(ctx) { - ctx.scale(1.0 / this.p.x || 1.0, 1.0 / this.p.y || this.p.x || 1.0); - } - this.applyToPoint = function(p) { - p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); - } - } - - this.Type.matrix = function(s) { - this.m = svg.ToNumberArray(s); - this.apply = function(ctx) { - ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); - } - this.applyToPoint = function(p) { - p.applyTransform(this.m); - } - } - - this.Type.SkewBase = function(s) { - this.base = that.Type.matrix; - this.base(s); - this.angle = new svg.Property('angle', s); - } - this.Type.SkewBase.prototype = new this.Type.matrix; - - this.Type.skewX = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, 0, Math.tan(this.angle.toRadians()), 1, 0, 0]; - } - this.Type.skewX.prototype = new this.Type.SkewBase; - - this.Type.skewY = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, Math.tan(this.angle.toRadians()), 0, 1, 0, 0]; - } - this.Type.skewY.prototype = new this.Type.SkewBase; - - this.transforms = []; - - this.apply = function(ctx) { - for (var i=0; i=0; i--) { - this.transforms[i].unapply(ctx); - } - } - - this.applyToPoint = function(p) { - for (var i=0; i= this.tokens.length - 1; + }; + + this.isCommandOrEnd = function () { + if (this.isEnd()) return true; + return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; + }; + + this.isRelativeCommand = function () { + switch (this.command) { + case 'm': + case 'l': + case 'h': + case 'v': + case 'c': + case 's': + case 'q': + case 't': + case 'a': + case 'z': + return true; } - - this.isEnd = function() { - return this.i >= this.tokens.length - 1; + return false; + }; + + this.getToken = function () { + this.i++; + return this.tokens[this.i]; + }; + + this.getScalar = function () { + return parseFloat(this.getToken()); + }; + + this.nextCommand = function () { + this.previousCommand = this.command; + this.command = this.getToken(); + }; + + this.getPoint = function () { + var p = new svg.Point(this.getScalar(), this.getScalar()); + return this.makeAbsolute(p); + }; + + this.getAsControlPoint = function () { + var p = this.getPoint(); + this.control = p; + return p; + }; + + this.getAsCurrentPoint = function () { + var p = this.getPoint(); + this.current = p; + return p; + }; + + this.getReflectedControlPoint = function () { + if (this.previousCommand.toLowerCase() !== 'c' && + this.previousCommand.toLowerCase() !== 's' && + this.previousCommand.toLowerCase() !== 'q' && + this.previousCommand.toLowerCase() !== 't') { + return this.current; } - - this.isCommandOrEnd = function() { - if (this.isEnd()) return true; - return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; + + // reflect point + var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); + return p; + }; + + this.makeAbsolute = function (p) { + if (this.isRelativeCommand()) { + p.x += this.current.x; + p.y += this.current.y; } - - this.isRelativeCommand = function() { - switch(this.command) - { - case 'm': - case 'l': - case 'h': - case 'v': - case 'c': - case 's': - case 'q': - case 't': - case 'a': - case 'z': - return true; - break; - } - return false; + return p; + }; + + this.addMarker = function (p, from, priorTo) { + // if the last angle isn't filled in because we didn't have this point yet ... + if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length - 1] == null) { + this.angles[this.angles.length - 1] = this.points[this.points.length - 1].angleTo(priorTo); } - - this.getToken = function() { - this.i++; - return this.tokens[this.i]; - } - - this.getScalar = function() { - return parseFloat(this.getToken()); - } - - this.nextCommand = function() { - this.previousCommand = this.command; - this.command = this.getToken(); - } - - this.getPoint = function() { - var p = new svg.Point(this.getScalar(), this.getScalar()); - return this.makeAbsolute(p); - } - - this.getAsControlPoint = function() { - var p = this.getPoint(); - this.control = p; - return p; - } - - this.getAsCurrentPoint = function() { - var p = this.getPoint(); - this.current = p; - return p; - } - - this.getReflectedControlPoint = function() { - if (this.previousCommand.toLowerCase() != 'c' && - this.previousCommand.toLowerCase() != 's' && - this.previousCommand.toLowerCase() != 'q' && - this.previousCommand.toLowerCase() != 't' ){ - return this.current; - } - - // reflect point - var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); - return p; - } - - this.makeAbsolute = function(p) { - if (this.isRelativeCommand()) { - p.x += this.current.x; - p.y += this.current.y; - } - return p; - } - - this.addMarker = function(p, from, priorTo) { - // if the last angle isn't filled in because we didn't have this point yet ... - if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { - this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); - } - this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); - } - - this.addMarkerAngle = function(p, a) { - this.points.push(p); - this.angles.push(a); - } - - this.getMarkerPoints = function() { return this.points; } - this.getMarkerAngles = function() { - for (var i=0; i 1) { - rx *= Math.sqrt(l); - ry *= Math.sqrt(l); - } - // cx', cy' - var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( - ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / - (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) - ); - if (isNaN(s)) s = 0; - var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); - // cx, cy - var centp = new svg.Point( - (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, - (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y - ); - // vector magnitude - var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } - // ratio between two vectors - var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } - // angle between two vectors - var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } - // initial angle - var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); - // angle delta - var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; - var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; - var ad = a(u, v); - if (r(u,v) <= -1) ad = Math.PI; - if (r(u,v) >= 1) ad = 0; - - // for markers - var dir = 1 - sweepFlag ? 1.0 : -1.0; - var ah = a1 + dir * (ad / 2.0); - var halfWay = new svg.Point( - centp.x + rx * Math.cos(ah), - centp.y + ry * Math.sin(ah) - ); - pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2); - pp.addMarkerAngle(cp, ah - dir * Math.PI); - - bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better - if (ctx != null) { - var r = rx > ry ? rx : ry; - var sx = rx > ry ? 1 : rx / ry; - var sy = rx > ry ? ry / rx : 1; - - ctx.translate(centp.x, centp.y); - ctx.rotate(xAxisRotation); - ctx.scale(sx, sy); - ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); - ctx.scale(1/sx, 1/sy); - ctx.rotate(-xAxisRotation); - ctx.translate(-centp.x, -centp.y); - } - } - break; - case 'Z': - case 'z': - if (ctx != null) ctx.closePath(); - pp.current = pp.start; + if (ctx != null) ctx.lineTo(p.x, p.y); } - } + break; + case 'L': + case 'l': + while (!pp.isCommandOrEnd()) { + var c = pp.current; + var p = pp.getAsCurrentPoint(); + pp.addMarker(p, c); + bb.addPoint(p.x, p.y); + if (ctx != null) ctx.lineTo(p.x, p.y); + } + break; + case 'H': + case 'h': + while (!pp.isCommandOrEnd()) { + var newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y); + pp.addMarker(newP, pp.current); + pp.current = newP; + bb.addPoint(pp.current.x, pp.current.y); + if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y); + } + break; + case 'V': + case 'v': + while (!pp.isCommandOrEnd()) { + var newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar()); + pp.addMarker(newP, pp.current); + pp.current = newP; + bb.addPoint(pp.current.x, pp.current.y); + if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y); + } + break; + case 'C': + case 'c': + while (!pp.isCommandOrEnd()) { + var curr = pp.current; + var p1 = pp.getPoint(); + var cntrl = pp.getAsControlPoint(); + var cp = pp.getAsCurrentPoint(); + pp.addMarker(cp, cntrl, p1); + bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); + if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); + } + break; + case 'S': + case 's': + while (!pp.isCommandOrEnd()) { + var curr = pp.current; + var p1 = pp.getReflectedControlPoint(); + var cntrl = pp.getAsControlPoint(); + var cp = pp.getAsCurrentPoint(); + pp.addMarker(cp, cntrl, p1); + bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); + if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y); + } + break; + case 'Q': + case 'q': + while (!pp.isCommandOrEnd()) { + var curr = pp.current; + var cntrl = pp.getAsControlPoint(); + var cp = pp.getAsCurrentPoint(); + pp.addMarker(cp, cntrl, cntrl); + bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y); + if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y); + } + break; + case 'T': + case 't': + while (!pp.isCommandOrEnd()) { + var curr = pp.current; + var cntrl = pp.getReflectedControlPoint(); + pp.control = cntrl; + var cp = pp.getAsCurrentPoint(); + pp.addMarker(cp, cntrl, cntrl); + bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y); + if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y); + } + break; + case 'A': + case 'a': + while (!pp.isCommandOrEnd()) { + var curr = pp.current; + var rx = pp.getScalar(); + var ry = pp.getScalar(); + var xAxisRotation = pp.getScalar() * (Math.PI / 180.0); + var largeArcFlag = pp.getScalar(); + var sweepFlag = pp.getScalar(); + var cp = pp.getAsCurrentPoint(); - return bb; + // Conversion from endpoint to center parameterization + // https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter + + // x1', y1' + var currp = new svg.Point( + Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0, + -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0 + ); + // adjust radii + var l = Math.pow(currp.x, 2) / Math.pow(rx, 2) + Math.pow(currp.y, 2) / Math.pow(ry, 2); + if (l > 1) { + rx *= Math.sqrt(l); + ry *= Math.sqrt(l); + } + // cx', cy' + var s = (largeArcFlag === sweepFlag ? -1 : 1) * Math.sqrt( + ((Math.pow(rx, 2) * Math.pow(ry, 2)) - (Math.pow(rx, 2) * Math.pow(currp.y, 2)) - (Math.pow(ry, 2) * Math.pow(currp.x, 2))) / + (Math.pow(rx, 2) * Math.pow(currp.y, 2) + Math.pow(ry, 2) * Math.pow(currp.x, 2)) + ); + if (isNaN(s)) s = 0; + var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); + // cx, cy + var centp = new svg.Point( + (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, + (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y + ); + // vector magnitude + var m = function (v) { return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)); }; + // ratio between two vectors + var r = function (u, v) { return (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v)); }; + // angle between two vectors + var a = function (u, v) { return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(r(u, v)); }; + // initial angle + var a1 = a([1, 0], [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry]); + // angle delta + var u = [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry]; + var v = [(-currp.x - cpp.x) / rx, (-currp.y - cpp.y) / ry]; + var ad = a(u, v); + if (r(u, v) <= -1) ad = Math.PI; + if (r(u, v) >= 1) ad = 0; + + // for markers + var dir = 1 - sweepFlag ? 1.0 : -1.0; + var ah = a1 + dir * (ad / 2.0); + var halfWay = new svg.Point( + centp.x + rx * Math.cos(ah), + centp.y + ry * Math.sin(ah) + ); + pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2); + pp.addMarkerAngle(cp, ah - dir * Math.PI); + + bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better + if (ctx != null) { + var r = rx > ry ? rx : ry; + var sx = rx > ry ? 1 : rx / ry; + var sy = rx > ry ? ry / rx : 1; + + ctx.translate(centp.x, centp.y); + ctx.rotate(xAxisRotation); + ctx.scale(sx, sy); + ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); + ctx.scale(1 / sx, 1 / sy); + ctx.rotate(-xAxisRotation); + ctx.translate(-centp.x, -centp.y); + } + } + break; + case 'Z': + case 'z': + if (ctx != null) ctx.closePath(); + pp.current = pp.start; + } } - this.getMarkers = function() { - var points = this.PathParser.getMarkerPoints(); - var angles = this.PathParser.getMarkerAngles(); - - var markers = []; - for (var i=0; i 1) this.offset = 1; - - var stopColor = this.style('stop-color'); - if (this.style('stop-opacity').hasValue()) stopColor = stopColor.addOpacity(this.style('stop-opacity')); - this.color = stopColor.value; - } - svg.Element.stop.prototype = new svg.Element.ElementBase; - - // animation base element - svg.Element.AnimateBase = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - svg.Animations.push(this); - - this.duration = 0.0; - this.begin = this.attribute('begin').toMilliseconds(); - this.maxDuration = this.begin + this.attribute('dur').toMilliseconds(); - - this.getProperty = function() { - var attributeType = this.attribute('attributeType').value; - var attributeName = this.attribute('attributeName').value; - - if (attributeType == 'CSS') { - return this.parent.style(attributeName, true); - } - return this.parent.attribute(attributeName, true); - }; - - this.initialValue = null; - this.initialUnits = ''; - this.removed = false; - this.calcValue = function() { - // OVERRIDE ME! - return ''; - } - - this.update = function(delta) { - // set initial value - if (this.initialValue == null) { - this.initialValue = this.getProperty().value; - this.initialUnits = this.getProperty().getUnits(); - } - - // if we're past the end time - if (this.duration > this.maxDuration) { - // loop for indefinitely repeating animations - if (this.attribute('repeatCount').value == 'indefinite' - || this.attribute('repeatDur').value == 'indefinite') { - this.duration = 0.0 - } - else if (this.attribute('fill').valueOrDefault('remove') == 'freeze' && !this.frozen) { - this.frozen = true; - this.parent.animationFrozen = true; - this.parent.animationFrozenValue = this.getProperty().value; - } - else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { - this.removed = true; - this.getProperty().value = this.parent.animationFrozen ? this.parent.animationFrozenValue : this.initialValue; - return true; - } - return false; - } - this.duration = this.duration + delta; - - // if we're past the begin time - var updated = false; - if (this.begin < this.duration) { - var newValue = this.calcValue(); // tween - - if (this.attribute('type').hasValue()) { - // for transform, etc. - var type = this.attribute('type').value; - newValue = type + '(' + newValue + ')'; - } - - this.getProperty().value = newValue; - updated = true; - } - - return updated; - } - - this.from = this.attribute('from'); - this.to = this.attribute('to'); - this.values = this.attribute('values'); - if (this.values.hasValue()) this.values.value = this.values.value.split(';'); - - // fraction of duration we've covered - this.progress = function() { - var ret = { progress: (this.duration - this.begin) / (this.maxDuration - this.begin) }; - if (this.values.hasValue()) { - var p = ret.progress * (this.values.value.length - 1); - var lb = Math.floor(p), ub = Math.ceil(p); - ret.from = new svg.Property('from', parseFloat(this.values.value[lb])); - ret.to = new svg.Property('to', parseFloat(this.values.value[ub])); - ret.progress = (p - lb) / (ub - lb); - } - else { - ret.from = this.from; - ret.to = this.to; - } - return ret; - } - } - svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; - - // animate element - svg.Element.animate = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var p = this.progress(); - - // tween value linearly - var newValue = p.from.numValue() + (p.to.numValue() - p.from.numValue()) * p.progress; - return newValue + this.initialUnits; - }; - } - svg.Element.animate.prototype = new svg.Element.AnimateBase; - - // animate color element - svg.Element.animateColor = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); + var r = (this.gradientUnits === 'objectBoundingBox' + ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue() + : this.attribute('r').toPixels()); - this.calcValue = function() { - var p = this.progress(); - var from = new RGBColor(p.from.value); - var to = new RGBColor(p.to.value); - - if (from.ok && to.ok) { - // tween color linearly - var r = from.r + (to.r - from.r) * p.progress; - var g = from.g + (to.g - from.g) * p.progress; - var b = from.b + (to.b - from.b) * p.progress; - return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; - } - return this.attribute('from').value; - }; - } - svg.Element.animateColor.prototype = new svg.Element.AnimateBase; - - // animate transform element - svg.Element.animateTransform = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var p = this.progress(); - - // tween value linearly - var from = svg.ToNumberArray(p.from.value); - var to = svg.ToNumberArray(p.to.value); - var newValue = ''; - for (var i=0; i 1) this.offset = 1; + + var stopColor = this.style('stop-color'); + if (this.style('stop-opacity').hasValue()) stopColor = stopColor.addOpacity(this.style('stop-opacity')); + this.color = stopColor.value; + }; + svg.Element.stop.prototype = new svg.Element.ElementBase(); + + // animation base element + svg.Element.AnimateBase = function (node) { + this.base = svg.Element.ElementBase; + this.base(node); + + svg.Animations.push(this); + + this.duration = 0.0; + this.begin = this.attribute('begin').toMilliseconds(); + this.maxDuration = this.begin + this.attribute('dur').toMilliseconds(); + + this.getProperty = function () { + var attributeType = this.attribute('attributeType').value; + var attributeName = this.attribute('attributeName').value; + + if (attributeType === 'CSS') { + return this.parent.style(attributeName, true); } - - this.getBoundingBox = function () { - var x = this.attribute('x').toPixels('x'); - var y = this.attribute('y').toPixels('y'); + return this.parent.attribute(attributeName, true); + }; + + this.initialValue = null; + this.initialUnits = ''; + this.removed = false; + + this.calcValue = function () { + // OVERRIDE ME! + return ''; + }; + + this.update = function (delta) { + // set initial value + if (this.initialValue == null) { + this.initialValue = this.getProperty().value; + this.initialUnits = this.getProperty().getUnits(); + } + + // if we're past the end time + if (this.duration > this.maxDuration) { + // loop for indefinitely repeating animations + if (this.attribute('repeatCount').value === 'indefinite' || + this.attribute('repeatDur').value === 'indefinite') { + this.duration = 0.0; + } else if (this.attribute('fill').valueOrDefault('remove') === 'freeze' && !this.frozen) { + this.frozen = true; + this.parent.animationFrozen = true; + this.parent.animationFrozenValue = this.getProperty().value; + } else if (this.attribute('fill').valueOrDefault('remove') === 'remove' && !this.removed) { + this.removed = true; + this.getProperty().value = this.parent.animationFrozen ? this.parent.animationFrozenValue : this.initialValue; + return true; + } + return false; + } + this.duration = this.duration + delta; + + // if we're past the begin time + var updated = false; + if (this.begin < this.duration) { + var newValue = this.calcValue(); // tween + + if (this.attribute('type').hasValue()) { + // for transform, etc. + var type = this.attribute('type').value; + newValue = type + '(' + newValue + ')'; + } + + this.getProperty().value = newValue; + updated = true; + } + + return updated; + }; + + this.from = this.attribute('from'); + this.to = this.attribute('to'); + this.values = this.attribute('values'); + if (this.values.hasValue()) this.values.value = this.values.value.split(';'); + + // fraction of duration we've covered + this.progress = function () { + var ret = { progress: (this.duration - this.begin) / (this.maxDuration - this.begin) }; + if (this.values.hasValue()) { + var p = ret.progress * (this.values.value.length - 1); + var lb = Math.floor(p), ub = Math.ceil(p); + ret.from = new svg.Property('from', parseFloat(this.values.value[lb])); + ret.to = new svg.Property('to', parseFloat(this.values.value[ub])); + ret.progress = (p - lb) / (ub - lb); + } else { + ret.from = this.from; + ret.to = this.to; + } + return ret; + }; + }; + svg.Element.AnimateBase.prototype = new svg.Element.ElementBase(); + + // animate element + svg.Element.animate = function (node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function () { + var p = this.progress(); + + // tween value linearly + var newValue = p.from.numValue() + (p.to.numValue() - p.from.numValue()) * p.progress; + return newValue + this.initialUnits; + }; + }; + svg.Element.animate.prototype = new svg.Element.AnimateBase(); + + // animate color element + svg.Element.animateColor = function (node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function () { + var p = this.progress(); + var from = new RGBColor(p.from.value); + var to = new RGBColor(p.to.value); + + if (from.ok && to.ok) { + // tween color linearly + var r = from.r + (to.r - from.r) * p.progress; + var g = from.g + (to.g - from.g) * p.progress; + var b = from.b + (to.b - from.b) * p.progress; + return 'rgb(' + parseInt(r, 10) + ',' + parseInt(g, 10) + ',' + parseInt(b, 10) + ')'; + } + return this.attribute('from').value; + }; + }; + svg.Element.animateColor.prototype = new svg.Element.AnimateBase(); + + // animate transform element + svg.Element.animateTransform = function (node) { + this.base = svg.Element.AnimateBase; + this.base(node); + + this.calcValue = function () { + var p = this.progress(); + + // tween value linearly + var from = svg.ToNumberArray(p.from.value); + var to = svg.ToNumberArray(p.to.value); + var newValue = ''; + for (var i = 0; i < from.length; i++) { + newValue += from[i] + (to[i] - from[i]) * p.progress + ' '; + } + return newValue; + }; + }; + 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.captureTextNodes = true; + this.base = svg.Element.RenderedElementBase; + this.base(node); + + this.baseSetContext = this.setContext; + this.setContext = function (ctx) { + this.baseSetContext(ctx); + + var textBaseline = this.style('dominant-baseline').toTextBaseline(); + if (textBaseline == null) textBaseline = this.style('alignment-baseline').toTextBaseline(); + if (textBaseline != null) ctx.textBaseline = textBaseline; + }; + + this.getBoundingBox = function () { + var x = this.attribute('x').toPixels('x'); + var y = this.attribute('y').toPixels('y'); + var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); + return new svg.BoundingBox(x, y - fontSize, x + Math.floor(fontSize * 2.0 / 3.0) * this.children[0].getText().length, y); + }; + + this.renderChildren = function (ctx) { + this.x = this.attribute('x').toPixels('x'); + this.y = this.attribute('y').toPixels('y'); + this.x += this.getAnchorDelta(ctx, this, 0); + for (var i = 0; i < this.children.length; i++) { + this.renderChild(ctx, this, i); + } + }; + + this.getAnchorDelta = function (ctx, parent, startI) { + var textAnchor = this.style('text-anchor').valueOrDefault('start'); + if (textAnchor !== 'start') { + var width = 0; + for (var i = startI; i < parent.children.length; i++) { + var child = parent.children[i]; + if (i > startI && child.attribute('x').hasValue()) break; // new group + width += child.measureTextRecursive(ctx); + } + return -1 * (textAnchor === 'end' ? width : width / 2.0); + } + return 0; + }; + + this.renderChild = function (ctx, parent, i) { + var child = parent.children[i]; + if (child.attribute('x').hasValue()) { + child.x = child.attribute('x').toPixels('x') + this.getAnchorDelta(ctx, parent, i); + if (child.attribute('dx').hasValue()) child.x += child.attribute('dx').toPixels('x'); + } else { + if (this.attribute('dx').hasValue()) this.x += this.attribute('dx').toPixels('x'); + if (child.attribute('dx').hasValue()) this.x += child.attribute('dx').toPixels('x'); + child.x = this.x; + } + this.x = child.x + child.measureText(ctx); + + if (child.attribute('y').hasValue()) { + child.y = child.attribute('y').toPixels('y'); + if (child.attribute('dy').hasValue()) child.y += child.attribute('dy').toPixels('y'); + } else { + if (this.attribute('dy').hasValue()) this.y += this.attribute('dy').toPixels('y'); + if (child.attribute('dy').hasValue()) this.y += child.attribute('dy').toPixels('y'); + child.y = this.y; + } + this.y = child.y; + + child.render(ctx); + + for (var i = 0; i < child.children.length; i++) { + this.renderChild(ctx, child, i); + } + }; + }; + svg.Element.text.prototype = new svg.Element.RenderedElementBase(); + + // text base + svg.Element.TextElementBase = function (node) { + 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').getDefinition(); + if (customFont != null) { var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); - return new svg.BoundingBox(x, y - fontSize, x + Math.floor(fontSize * 2.0 / 3.0) * this.children[0].getText().length, y); - } - - this.renderChildren = function(ctx) { - this.x = this.attribute('x').toPixels('x'); - this.y = this.attribute('y').toPixels('y'); - this.x += this.getAnchorDelta(ctx, this, 0); - for (var i=0; i startI && child.attribute('x').hasValue()) break; // new group - width += child.measureTextRecursive(ctx); - } - return -1 * (textAnchor == 'end' ? width : width / 2.0); - } - return 0; - } - - this.renderChild = function(ctx, parent, i) { - var child = parent.children[i]; - if (child.attribute('x').hasValue()) { - child.x = child.attribute('x').toPixels('x') + this.getAnchorDelta(ctx, parent, i); - if (child.attribute('dx').hasValue()) child.x += child.attribute('dx').toPixels('x'); - } - else { - if (this.attribute('dx').hasValue()) this.x += this.attribute('dx').toPixels('x'); - if (child.attribute('dx').hasValue()) this.x += child.attribute('dx').toPixels('x'); - child.x = this.x; - } - this.x = child.x + child.measureText(ctx); - - if (child.attribute('y').hasValue()) { - child.y = child.attribute('y').toPixels('y'); - if (child.attribute('dy').hasValue()) child.y += child.attribute('dy').toPixels('y'); - } - else { - if (this.attribute('dy').hasValue()) this.y += this.attribute('dy').toPixels('y'); - if (child.attribute('dy').hasValue()) this.y += child.attribute('dy').toPixels('y'); - child.y = this.y; - } - this.y = child.y; - - child.render(ctx); - - for (var i=0; i0 && text[i-1]!=' ' && i0 && 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').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(""); - - var dx = svg.ToNumberArray(this.parent.attribute('dx').value); - for (var i=0; i 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 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; } } } @@ -2387,536 +2404,544 @@ } } } - svg.Element.style.prototype = new svg.Element.ElementBase; - - // use element - svg.Element.use = function(node) { - this.base = svg.Element.RenderedElementBase; - this.base(node); - - this.baseSetContext = this.setContext; - this.setContext = function(ctx) { - this.baseSetContext(ctx); - if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').toPixels('x'), 0); - if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').toPixels('y')); - } - - var element = this.getHrefAttribute().getDefinition(); - - this.path = function(ctx) { - if (element != null) element.path(ctx); - } - - this.getBoundingBox = function() { - if (element != null) return element.getBoundingBox(); - } - - this.renderChildren = function(ctx) { - if (element != null) { - var tempSvg = element; - if (element.type == 'symbol') { - // render me using a temporary svg element in symbol cases (http://www.w3.org/TR/SVG/struct.html#UseElement) - tempSvg = new svg.Element.svg(); - tempSvg.type = 'svg'; - tempSvg.attributes['viewBox'] = new svg.Property('viewBox', element.attribute('viewBox').value); - tempSvg.attributes['preserveAspectRatio'] = new svg.Property('preserveAspectRatio', element.attribute('preserveAspectRatio').value); - tempSvg.attributes['overflow'] = new svg.Property('overflow', element.attribute('overflow').value); - tempSvg.children = element.children; - } - if (tempSvg.type == 'svg') { - // if symbol or svg, inherit width/height from me - if (this.attribute('width').hasValue()) tempSvg.attributes['width'] = new svg.Property('width', this.attribute('width').value); - if (this.attribute('height').hasValue()) tempSvg.attributes['height'] = new svg.Property('height', this.attribute('height').value); - } - var oldParent = tempSvg.parent; - tempSvg.parent = null; - tempSvg.render(ctx); - tempSvg.parent = oldParent; - } - } - } - svg.Element.use.prototype = new svg.Element.RenderedElementBase; - - // mask element - svg.Element.mask = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - this.apply = function(ctx, element) { - // render as temp svg - var x = this.attribute('x').toPixels('x'); - var y = this.attribute('y').toPixels('y'); - var width = this.attribute('width').toPixels('x'); - var height = this.attribute('height').toPixels('y'); - - if (width == 0 && height == 0) { - var bb = new svg.BoundingBox(); - for (var i=0; i * @link http://www.phpied.com/rgb-color-parser-in-javascript/ * @license Use it if you like it */ -function RGBColor(color_string) { 'use strict'; - this.ok = false; +function RGBColor (colorString) { // eslint-disable-line no-unused-vars + 'use strict'; + this.ok = false; - // strip any leading # - if (color_string.charAt(0) === '#') { // remove # if any - color_string = color_string.substr(1,6); - } + // strip any leading # + if (colorString.charAt(0) === '#') { // remove # if any + colorString = colorString.substr(1, 6); + } - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); + colorString = colorString.replace(/ /g, ''); + colorString = colorString.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' - }; - var key; - for (key in simple_colors) { - if (simple_colors.hasOwnProperty(key)) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - } - // emd of simple type-in colors + // before getting into regexps, try simple matches + // and overwrite the input + var simpleColors = { + 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' + }; + var key; + for (key in simpleColors) { + if (simpleColors.hasOwnProperty(key)) { + if (colorString === key) { + colorString = simpleColors[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], 10), - parseInt(bits[2], 10), - parseInt(bits[3], 10) - ]; - } - }, - { - 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) - ]; - } - } - ]; + // array of color definition objects + var colorDefs = [ + { + 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], 10), + parseInt(bits[2], 10), + parseInt(bits[3], 10) + ]; + } + }, + { + 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) + ]; + } + } + ]; - var i; - // search through the definitions to find a match - for (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) { - var channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } + var i; + // search through the definitions to find a match + for (i = 0; i < colorDefs.length; i++) { + var re = colorDefs[i].re; + var processor = colorDefs[i].process; + var bits = re.exec(colorString); + if (bits) { + var 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); - // 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; + }; - // 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 i, j; - var examples = []; - // add regexps - for (i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - var sc; - for (sc in simple_colors) { - if (simple_colors.hasOwnProperty(sc)) { - examples[examples.length] = sc; - } - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (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; - - }; + // help + this.getHelpXML = function () { + var i, j; + var examples = []; + // add regexps + for (i = 0; i < colorDefs.length; i++) { + var example = colorDefs[i].example; + for (j = 0; j < example.length; j++) { + examples[examples.length] = example[j]; + } + } + // add type-in colors + var sc; + for (sc in simpleColors) { + if (simpleColors.hasOwnProperty(sc)) { + examples[examples.length] = sc; + } + } + var xml = document.createElement('ul'); + xml.setAttribute('id', 'rgbcolor-examples'); + for (i = 0; i < examples.length; i++) { + try { + var listItem = document.createElement('li'); + var listColor = new RGBColor(examples[i]); + var exampleDiv = document.createElement('div'); + exampleDiv.style.cssText = + 'margin: 3px; ' + + 'border: 1px solid black; ' + + 'background:' + listColor.toHex() + '; ' + + 'color:' + listColor.toHex() + ; + exampleDiv.appendChild(document.createTextNode('test')); + var listItemValue = document.createTextNode( + ' ' + examples[i] + ' -> ' + listColor.toRGB() + ' -> ' + listColor.toHex() + ); + listItem.appendChild(exampleDiv); + listItem.appendChild(listItemValue); + xml.appendChild(listItem); + } catch (e) {} + } + return xml; + }; } diff --git a/editor/contextmenu/jquery.contextMenu.js b/editor/contextmenu/jquery.contextMenu.js index 76126019..2dc92679 100755 --- a/editor/contextmenu/jquery.contextMenu.js +++ b/editor/contextmenu/jquery.contextMenu.js @@ -1,3 +1,5 @@ +/* eslint-disable no-var */ +/* globals jQuery, $, svgedit */ // jQuery Context Menu Plugin // // Version 1.01 @@ -13,191 +15,191 @@ // This plugin is dual-licensed under the GNU General Public License // and the MIT License and is copyright A Beautiful Site, LLC. // -if(jQuery)( function() { - var win = $(window); - var doc = $(document); +if (jQuery) { + (function () { + var win = $(window); + var doc = $(document); - $.extend($.fn, { - - contextMenu: function(o, callback) { - // Defaults - if( o.menu == undefined ) return false; - if( o.inSpeed == undefined ) o.inSpeed = 150; - if( o.outSpeed == undefined ) o.outSpeed = 75; - // 0 needs to be -1 for expected results (no fade) - if( o.inSpeed == 0 ) o.inSpeed = -1; - if( o.outSpeed == 0 ) o.outSpeed = -1; - // Loop each context menu - $(this).each( function() { - var el = $(this); - var offset = $(el).offset(); - - var menu = $('#' + o.menu); + $.extend($.fn, { - // Add contextMenu class - menu.addClass('contextMenu'); - // Simulate a true right click - $(this).bind( "mousedown", function(e) { - var evt = e; - $(this).mouseup( function(e) { - var srcElement = $(this); - srcElement.unbind('mouseup'); - if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) { - e.stopPropagation(); - // Hide context menus that may be showing - $(".contextMenu").hide(); - // Get this context menu - - if( el.hasClass('disabled') ) return false; - - // Detect mouse position - var d = {}, x = e.pageX, y = e.pageY; - - var x_off = win.width() - menu.width(), - y_off = win.height() - menu.height(); + contextMenu: function (o, callback) { + // Defaults + if (o.menu === undefined) return false; + if (o.inSpeed === undefined) o.inSpeed = 150; + if (o.outSpeed === undefined) o.outSpeed = 75; + // 0 needs to be -1 for expected results (no fade) + if (o.inSpeed === 0) o.inSpeed = -1; + if (o.outSpeed === 0) o.outSpeed = -1; + // Loop each context menu + $(this).each(function () { + var el = $(this); + var offset = $(el).offset(); - if(x > x_off - 15) x = x_off-15; - if(y > y_off - 30) y = y_off-30; // 30 is needed to prevent scrollbars in FF - - // Show the menu - doc.unbind('click'); - menu.css({ top: y, left: x }).fadeIn(o.inSpeed); - // Hover events - menu.find('A').mouseover( function() { - menu.find('LI.hover').removeClass('hover'); - $(this).parent().addClass('hover'); - }).mouseout( function() { - menu.find('LI.hover').removeClass('hover'); - }); - - // Keyboard - doc.keypress( function(e) { - switch( e.keyCode ) { + var menu = $('#' + o.menu); + + // Add contextMenu class + menu.addClass('contextMenu'); + // Simulate a true right click + $(this).bind('mousedown', function (e) { + var evt = e; + $(this).mouseup(function (e) { + var srcElement = $(this); + srcElement.unbind('mouseup'); + if (evt.button === 2 || o.allowLeft || + (evt.ctrlKey && svgedit.browser.isMac())) { + e.stopPropagation(); + // Hide context menus that may be showing + $('.contextMenu').hide(); + // Get this context menu + + if (el.hasClass('disabled')) return false; + + // Detect mouse position + var x = e.pageX, y = e.pageY; + + var xOff = win.width() - menu.width(), + yOff = win.height() - menu.height(); + + if (x > xOff - 15) x = xOff - 15; + if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF + + // Show the menu + doc.unbind('click'); + menu.css({ top: y, left: x }).fadeIn(o.inSpeed); + // Hover events + menu.find('A').mouseover(function () { + menu.find('LI.hover').removeClass('hover'); + $(this).parent().addClass('hover'); + }).mouseout(function () { + menu.find('LI.hover').removeClass('hover'); + }); + + // Keyboard + doc.keypress(function (e) { + switch (e.keyCode) { case 38: // up - if( !menu.find('LI.hover').length ) { + if (!menu.find('LI.hover').length) { menu.find('LI:last').addClass('hover'); } else { menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:last').addClass('hover'); + if (!menu.find('LI.hover').length) menu.find('LI:last').addClass('hover'); } - break; + break; case 40: // down - if( menu.find('LI.hover').length == 0 ) { + if (menu.find('LI.hover').length === 0) { menu.find('LI:first').addClass('hover'); } else { menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:first').addClass('hover'); + if (!menu.find('LI.hover').length) menu.find('LI:first').addClass('hover'); } - break; + break; case 13: // enter menu.find('LI.hover A').trigger('click'); - break; + break; case 27: // esc doc.trigger('click'); - break - } - }); - - // When items are selected - menu.find('A').unbind('mouseup'); - menu.find('LI:not(.disabled) A').mouseup( function() { - doc.unbind('click').unbind('keypress'); - $(".contextMenu").hide(); - // Callback - if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); - return false; - }); - - // Hide bindings - setTimeout( function() { // Delay for Mozilla - doc.click( function() { + break; + } + }); + + // When items are selected + menu.find('A').unbind('mouseup'); + menu.find('LI:not(.disabled) A').mouseup(function () { doc.unbind('click').unbind('keypress'); - menu.fadeOut(o.outSpeed); + $('.contextMenu').hide(); + // Callback + if (callback) callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y}); return false; }); - }, 0); - } + + // Hide bindings + setTimeout(function () { // Delay for Mozilla + doc.click(function () { + doc.unbind('click').unbind('keypress'); + menu.fadeOut(o.outSpeed); + return false; + }); + }, 0); + } + }); }); + + // Disable text selection + if ($.browser.mozilla) { + $('#' + o.menu).each(function () { $(this).css({'MozUserSelect': 'none'}); }); + } else if ($.browser.msie) { + $('#' + o.menu).each(function () { $(this).bind('selectstart.disableTextSelect', function () { return false; }); }); + } else { + $('#' + o.menu).each(function () { $(this).bind('mousedown.disableTextSelect', function () { return false; }); }); + } + // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) + $(el).add($('UL.contextMenu')).bind('contextmenu', function () { return false; }); }); - - // Disable text selection - if( $.browser.mozilla ) { - $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); - } else if( $.browser.msie ) { - $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); - } else { - $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); + return $(this); + }, + + // Disable context menu items on the fly + disableContextMenuItems: function (o) { + if (o === undefined) { + // Disable all + $(this).find('LI').addClass('disabled'); + return $(this); } - // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) - $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); - - }); - return $(this); - }, - - // Disable context menu items on the fly - disableContextMenuItems: function(o) { - if( o == undefined ) { - // Disable all - $(this).find('LI').addClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); - + $(this).each(function () { + if (o !== undefined) { + var d = o.split(','); + for (var i = 0; i < d.length; i++) { + $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); + } } + }); + return $(this); + }, + + // Enable context menu items on the fly + enableContextMenuItems: function (o) { + if (o === undefined) { + // Enable all + $(this).find('LI.disabled').removeClass('disabled'); + return $(this); } - }); - return( $(this) ); - }, - - // Enable context menu items on the fly - enableContextMenuItems: function(o) { - if( o == undefined ) { - // Enable all - $(this).find('LI.disabled').removeClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); - + $(this).each(function () { + if (o !== undefined) { + var d = o.split(','); + for (var i = 0; i < d.length; i++) { + $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); + } } - } - }); - return( $(this) ); - }, - - // Disable context menu(s) - disableContextMenu: function() { - $(this).each( function() { - $(this).addClass('disabled'); - }); - return( $(this) ); - }, - - // Enable context menu(s) - enableContextMenu: function() { - $(this).each( function() { - $(this).removeClass('disabled'); - }); - return( $(this) ); - }, - - // Destroy context menu(s) - destroyContextMenu: function() { - // Destroy specified context menus - $(this).each( function() { - // Disable action - $(this).unbind('mousedown').unbind('mouseup'); - }); - return( $(this) ); - } - - }); -})(jQuery); \ No newline at end of file + }); + return $(this); + }, + + // Disable context menu(s) + disableContextMenu: function () { + $(this).each(function () { + $(this).addClass('disabled'); + }); + return $(this); + }, + + // Enable context menu(s) + enableContextMenu: function () { + $(this).each(function () { + $(this).removeClass('disabled'); + }); + return $(this); + }, + + // Destroy context menu(s) + destroyContextMenu: function () { + // Destroy specified context menus + $(this).each(function () { + // Disable action + $(this).unbind('mousedown').unbind('mouseup'); + }); + return $(this); + } + + }); + })(jQuery); +} diff --git a/editor/jgraduate/jpicker.js b/editor/jgraduate/jpicker.js index 683052cc..37b99a61 100755 --- a/editor/jgraduate/jpicker.js +++ b/editor/jgraduate/jpicker.js @@ -1,4 +1,6 @@ -/* +/* eslint-disable no-var */ +/* globals jQuery */ +/* * jPicker 1.1.6 * * jQuery Plugin for Photoshop style color picker @@ -10,2082 +12,1944 @@ * Painstakingly ported from John Dyers' excellent work on his own color picker based on the Prototype framework. * * John Dyers' website: (http://johndyer.name) - * Color Picker page: (http://johndyer.name/post/2007/09/PhotoShop-like-JavaScript-Color-Picker.aspx) + * Color Picker page: (http://johndyer.name/post/2007/09/PhotoShop-like-JavaScript-Color-Picker.aspx) * */ -(function($, version) +(function ($, version) { +Math.precision = function (value, precision) { + if (precision === undefined) precision = 0; + return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision); +}; +var Slider = // encapsulate slider functionality for the ColorMap and ColorBar - could be useful to use a jQuery UI draggable for this with certain extensions + function (bar, options) { + var $this = this, // private properties, methods, and events - keep these variables and classes invisible to outside code + arrow = bar.find('img:first'), // the arrow image to drag + minX = 0, + maxX = 100, + rangeX = 100, + minY = 0, + maxY = 100, + rangeY = 100, + x = 0, + y = 0, + offset, + timeout, + changeEvents = [], + fireChangeEvents = + function (context) { + for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); + }, + mouseDown = // bind the mousedown to the bar not the arrow for quick snapping to the clicked location + function (e) { + var off = bar.offset(); + offset = { l: off.left | 0, t: off.top | 0 }; + clearTimeout(timeout); + timeout = setTimeout( // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run + function () { + setValuesFromMousePosition.call($this, e); + }, 0); + // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing + $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); + e.preventDefault(); // don't try to select anything or drag the image to the desktop + }, + mouseMove = // set the values as the mouse moves + function (e) { + clearTimeout(timeout); + timeout = setTimeout( + function () { + setValuesFromMousePosition.call($this, e); + }, 0); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + mouseUp = // unbind the document events - they aren't needed when not dragging + function (e) { + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + e.stopPropagation(); + e.preventDefault(); + return false; + }, + setValuesFromMousePosition = // calculate mouse position and set value within the current range + function (e) { + var locX = e.pageX - offset.l, + locY = e.pageY - offset.t, + barW = bar.w, // local copies for YUI compressor + barH = bar.h; + // keep the arrow within the bounds of the bar + if (locX < 0) locX = 0; + else if (locX > barW) locX = barW; + if (locY < 0) locY = 0; + else if (locY > barH) locY = barH; + val.call($this, 'xy', { x: ((locX / barW) * rangeX) + minX, y: ((locY / barH) * rangeY) + minY }); + }, + draw = + function () { + var arrowOffsetX = 0, + arrowOffsetY = 0, + barW = bar.w, + barH = bar.h, + arrowW = arrow.w, + arrowH = arrow.h; + setTimeout( + function () { + if (rangeX > 0) { // range is greater than zero + // constrain to bounds + if (x === maxX) arrowOffsetX = barW; + else arrowOffsetX = ((x / rangeX) * barW) | 0; + } + if (rangeY > 0) { // range is greater than zero + // constrain to bounds + if (y === maxY) arrowOffsetY = barH; + else arrowOffsetY = ((y / rangeY) * barH) | 0; + } + // if arrow width is greater than bar width, center arrow and prevent horizontal dragging + if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) + else arrowOffsetX -= arrowW >> 1; + // if arrow height is greater than bar height, center arrow and prevent vertical dragging + if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1); + else arrowOffsetY -= arrowH >> 1; + // set the arrow position based on these offsets + arrow.css({ left: arrowOffsetX + 'px', top: arrowOffsetY + 'px' }); + }, 0); + }, + val = + function (name, value, context) { + var set = value !== undefined; + if (!set) { + if (name === undefined || name == null) name = 'xy'; + switch (name.toLowerCase()) { + case 'x': return x; + case 'y': return y; + case 'xy': + default: return { x: x, y: y }; + } + } + if (context != null && context === $this) return; + var changed = false, + newX, + newY; + if (name == null) name = 'xy'; + switch (name.toLowerCase()) { + case 'x': + newX = value && (value.x && value.x | 0 || value | 0) || 0; + break; + case 'y': + newY = value && (value.y && value.y | 0 || value | 0) || 0; + break; + case 'xy': + default: + newX = value && value.x && value.x | 0 || 0; + newY = value && value.y && value.y | 0 || 0; + break; + } + if (newX != null) { + if (newX < minX) newX = minX; + else if (newX > maxX) newX = maxX; + if (x !== newX) { + x = newX; + changed = true; + } + } + if (newY != null) { + if (newY < minY) newY = minY; + else if (newY > maxY) newY = maxY; + if (y !== newY) { + y = newY; + changed = true; + } + } + changed && fireChangeEvents.call($this, context || $this); + }, + range = + function (name, value) { + var set = value !== undefined; + if (!set) { + if (name === undefined || name == null) name = 'all'; + switch (name.toLowerCase()) { + case 'minx': return minX; + case 'maxx': return maxX; + case 'rangex': return { minX: minX, maxX: maxX, rangeX: rangeX }; + case 'miny': return minY; + case 'maxy': return maxY; + case 'rangey': return { minY: minY, maxY: maxY, rangeY: rangeY }; + case 'all': + default: return { minX: minX, maxX: maxX, rangeX: rangeX, minY: minY, maxY: maxY, rangeY: rangeY }; + } + } + var changed = false, + newMinX, + newMaxX, + newMinY, + newMaxY; + if (name == null) name = 'all'; + switch (name.toLowerCase()) { + case 'minx': + newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0; + break; + case 'maxx': + newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0; + break; + case 'rangex': + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + break; + case 'miny': + newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0; + break; + case 'maxy': + newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0; + break; + case 'rangey': + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; + case 'all': + default: + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; + } + if (newMinX != null && minX !== newMinX) { + minX = newMinX; + rangeX = maxX - minX; + } + if (newMaxX != null && maxX !== newMaxX) { + maxX = newMaxX; + rangeX = maxX - minX; + } + if (newMinY != null && minY !== newMinY) { + minY = newMinY; + rangeY = maxY - minY; + } + if (newMaxY != null && maxY !== newMaxY) { + maxY = newMaxY; + rangeY = maxY - minY; + } + }, + bind = + function (callback) { + if ($.isFunction(callback)) changeEvents.push(callback); + }, + unbind = + function (callback) { + if (!$.isFunction(callback)) return; + var i; + while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1); + }, + destroy = + function () { + // unbind all possible events and null objects + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + bar.unbind('mousedown', mouseDown); + bar = null; + arrow = null; + changeEvents = null; + }; + $.extend(true, $this, // public properties, methods, and event bindings - these we need to access from other controls + { + val: val, + range: range, + bind: bind, + unbind: unbind, + destroy: destroy + }); + // initialize this control + arrow.src = options.arrow && options.arrow.image; + arrow.w = options.arrow && options.arrow.width || arrow.width(); + arrow.h = options.arrow && options.arrow.height || arrow.height(); + bar.w = options.map && options.map.width || bar.width(); + bar.h = options.map && options.map.height || bar.height(); + // bind mousedown event + bar.bind('mousedown', mouseDown); + bind.call($this, draw); + }, + ColorValuePicker = // controls for all the input elements for the typing in color values + function (picker, color, bindedHex, alphaPrecision) { + var $this = this, // private properties and methods + inputs = picker.find('td.Text input'), + red = inputs.eq(3), + green = inputs.eq(4), + blue = inputs.eq(5), + alpha = inputs.length > 7 ? inputs.eq(6) : null, + hue = inputs.eq(0), + saturation = inputs.eq(1), + value = inputs.eq(2), + hex = inputs.eq(inputs.length > 7 ? 7 : 6), + ahex = inputs.length > 7 ? inputs.eq(8) : null, + keyDown = // input box key down - use arrows to alter color + function (e) { + if (e.target.value === '' && e.target !== hex.get(0) && (bindedHex != null && e.target !== bindedHex.get(0) || bindedHex == null)) return; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + switch (e.keyCode) { + case 38: + red.val(setValueInRange.call($this, (red.val() << 0) + 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + case 40: + red.val(setValueInRange.call($this, (red.val() << 0) - 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + } + break; + case green.get(0): + switch (e.keyCode) { + case 38: + green.val(setValueInRange.call($this, (green.val() << 0) + 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + case 40: + green.val(setValueInRange.call($this, (green.val() << 0) - 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + } + break; + case blue.get(0): + switch (e.keyCode) { + case 38: + blue.val(setValueInRange.call($this, (blue.val() << 0) + 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + case 40: + blue.val(setValueInRange.call($this, (blue.val() << 0) - 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + } + break; + case alpha && alpha.get(0): + switch (e.keyCode) { + case 38: + alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) + 1, 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + case 40: + alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) - 1, 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + return false; + } + break; + case hue.get(0): + switch (e.keyCode) { + case 38: + hue.val(setValueInRange.call($this, (hue.val() << 0) + 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + case 40: + hue.val(setValueInRange.call($this, (hue.val() << 0) - 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + } + break; + case saturation.get(0): + switch (e.keyCode) { + case 38: + saturation.val(setValueInRange.call($this, (saturation.val() << 0) + 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + case 40: + saturation.val(setValueInRange.call($this, (saturation.val() << 0) - 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + } + break; + case value.get(0): + switch (e.keyCode) { + case 38: + value.val(setValueInRange.call($this, (value.val() << 0) + 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + case 40: + value.val(setValueInRange.call($this, (value.val() << 0) - 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + } + break; + } + }, + keyUp = // input box key up - validate value and set color + function (e) { + if (e.target.value === '' && e.target !== hex.get(0) && (bindedHex != null && e.target !== bindedHex.get(0) || bindedHex == null)) return; + if (!validateKey(e)) return e; + switch (e.target) { + case red.get(0): + red.val(setValueInRange.call($this, red.val(), 0, 255)); + color.val('r', red.val(), e.target); + break; + case green.get(0): + green.val(setValueInRange.call($this, green.val(), 0, 255)); + color.val('g', green.val(), e.target); + break; + case blue.get(0): + blue.val(setValueInRange.call($this, blue.val(), 0, 255)); + color.val('b', blue.val(), e.target); + break; + case alpha && alpha.get(0): + alpha.val(setValueInRange.call($this, alpha.val(), 0, 100)); + color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); + break; + case hue.get(0): + hue.val(setValueInRange.call($this, hue.val(), 0, 360)); + color.val('h', hue.val(), e.target); + break; + case saturation.get(0): + saturation.val(setValueInRange.call($this, saturation.val(), 0, 100)); + color.val('s', saturation.val(), e.target); + break; + case value.get(0): + value.val(setValueInRange.call($this, value.val(), 0, 100)); + color.val('v', value.val(), e.target); + break; + case hex.get(0): + hex.val(hex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); + bindedHex && bindedHex.val(hex.val()); + color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); + break; + case bindedHex && bindedHex.get(0): + bindedHex.val(bindedHex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); + hex.val(bindedHex.val()); + color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); + break; + case ahex && ahex.get(0): + ahex.val(ahex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 2)); + color.val('a', ahex.val() != null ? parseInt(ahex.val(), 16) : null, e.target); + break; + } + }, + blur = // input box blur - reset to original if value empty + function (e) { + if (color.val() != null) { + switch (e.target) { + case red.get(0): red.val(color.val('r')); break; + case green.get(0): green.val(color.val('g')); break; + case blue.get(0): blue.val(color.val('b')); break; + case alpha && alpha.get(0): alpha.val(Math.precision((color.val('a') * 100) / 255, alphaPrecision)); break; + case hue.get(0): hue.val(color.val('h')); break; + case saturation.get(0): saturation.val(color.val('s')); break; + case value.get(0): value.val(color.val('v')); break; + case hex.get(0): + case bindedHex && bindedHex.get(0): + hex.val(color.val('hex')); + bindedHex && bindedHex.val(color.val('hex')); + break; + case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; + } + } + }, + validateKey = // validate key + function (e) { + switch (e.keyCode) { + case 9: + case 16: + case 29: + case 37: + case 39: + return false; + case 'c'.charCodeAt(): + case 'v'.charCodeAt(): + if (e.ctrlKey) return false; + } + return true; + }, + setValueInRange = // constrain value within range + function (value, min, max) { + if (value == '' || isNaN(value)) return min; + if (value > max) return max; + if (value < min) return min; + return value; + }, + colorChanged = + function (ui, context) { + var all = ui.val('all'); + if (context !== red.get(0)) red.val(all != null ? all.r : ''); + if (context !== green.get(0)) green.val(all != null ? all.g : ''); + if (context !== blue.get(0)) blue.val(all != null ? all.b : ''); + if (alpha && context !== alpha.get(0)) alpha.val(all != null ? Math.precision((all.a * 100) / 255, alphaPrecision) : ''); + if (context !== hue.get(0)) hue.val(all != null ? all.h : ''); + if (context !== saturation.get(0)) saturation.val(all != null ? all.s : ''); + if (context !== value.get(0)) value.val(all != null ? all.v : ''); + if (context !== hex.get(0) && (bindedHex && context !== bindedHex.get(0) || !bindedHex)) hex.val(all != null ? all.hex : ''); + if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(all != null ? all.hex : ''); + if (ahex && context !== ahex.get(0)) ahex.val(all != null ? all.ahex.substring(6) : ''); + }, + destroy = + function () { + // unbind all events and null objects + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); + color.unbind(colorChanged); + red = null; + green = null; + blue = null; + alpha = null; + hue = null; + saturation = null; + value = null; + hex = null; + ahex = null; + }; + $.extend(true, $this, // public properties and methods + { + destroy: destroy + }); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); + color.bind(colorChanged); + }; +$.jPicker = { - Math.precision = function(value, precision) - { - if (precision === undefined) precision = 0; - return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision); - }; - var Slider = // encapsulate slider functionality for the ColorMap and ColorBar - could be useful to use a jQuery UI draggable for this with certain extensions - function(bar, options) - { - var $this = this, // private properties, methods, and events - keep these variables and classes invisible to outside code - arrow = bar.find('img:first'), // the arrow image to drag - minX = 0, - maxX = 100, - rangeX = 100, - minY = 0, - maxY = 100, - rangeY = 100, - x = 0, - y = 0, - offset, - timeout, - changeEvents = new Array(), - fireChangeEvents = - function(context) - { - for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); - }, - mouseDown = // bind the mousedown to the bar not the arrow for quick snapping to the clicked location - function(e) - { - var off = bar.offset(); - offset = { l: off.left | 0, t: off.top | 0 }; - clearTimeout(timeout); - timeout = setTimeout( // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run - function() - { - setValuesFromMousePosition.call($this, e); - }, 0); - // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing - $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); - e.preventDefault(); // don't try to select anything or drag the image to the desktop - }, - mouseMove = // set the values as the mouse moves - function(e) - { - clearTimeout(timeout); - timeout = setTimeout( - function() - { - setValuesFromMousePosition.call($this, e); - }, 0); - e.stopPropagation(); - e.preventDefault(); - return false; - }, - mouseUp = // unbind the document events - they aren't needed when not dragging - function(e) - { - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - e.stopPropagation(); - e.preventDefault(); - return false; - }, - setValuesFromMousePosition = // calculate mouse position and set value within the current range - function(e) - { - var locX = e.pageX - offset.l, - locY = e.pageY - offset.t, - barW = bar.w, // local copies for YUI compressor - barH = bar.h; - // keep the arrow within the bounds of the bar - if (locX < 0) locX = 0; - else if (locX > barW) locX = barW; - if (locY < 0) locY = 0; - else if (locY > barH) locY = barH; - val.call($this, 'xy', { x: ((locX / barW) * rangeX) + minX, y: ((locY / barH) * rangeY) + minY }); - }, - draw = - function() - { - var arrowOffsetX = 0, - arrowOffsetY = 0, - barW = bar.w, - barH = bar.h, - arrowW = arrow.w, - arrowH = arrow.h; - setTimeout( - function() - { - if (rangeX > 0) // range is greater than zero - { - // constrain to bounds - if (x == maxX) arrowOffsetX = barW; - else arrowOffsetX = ((x / rangeX) * barW) | 0; - } - if (rangeY > 0) // range is greater than zero - { - // constrain to bounds - if (y == maxY) arrowOffsetY = barH; - else arrowOffsetY = ((y / rangeY) * barH) | 0; - } - // if arrow width is greater than bar width, center arrow and prevent horizontal dragging - if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) - else arrowOffsetX -= arrowW >> 1; - // if arrow height is greater than bar height, center arrow and prevent vertical dragging - if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1); - else arrowOffsetY -= arrowH >> 1; - // set the arrow position based on these offsets - arrow.css({ left: arrowOffsetX + 'px', top: arrowOffsetY + 'px' }); - }, 0); - }, - val = - function(name, value, context) - { - var set = value !== undefined; - if (!set) - { - if (name === undefined || name == null) name = 'xy'; - switch (name.toLowerCase()) - { - case 'x': return x; - case 'y': return y; - case 'xy': - default: return { x: x, y: y }; - } - } - if (context != null && context == $this) return; - var changed = false, - newX, - newY; - if (name == null) name = 'xy'; - switch (name.toLowerCase()) - { - case 'x': - newX = value && (value.x && value.x | 0 || value | 0) || 0; - break; - case 'y': - newY = value && (value.y && value.y | 0 || value | 0) || 0; - break; - case 'xy': - default: - newX = value && value.x && value.x | 0 || 0; - newY = value && value.y && value.y | 0 || 0; - break; - } - if (newX != null) - { - if (newX < minX) newX = minX; - else if (newX > maxX) newX = maxX; - if (x != newX) - { - x = newX; - changed = true; - } - } - if (newY != null) - { - if (newY < minY) newY = minY; - else if (newY > maxY) newY = maxY; - if (y != newY) - { - y = newY; - changed = true; - } - } - changed && fireChangeEvents.call($this, context || $this); - }, - range = - function (name, value) - { - var set = value !== undefined; - if (!set) - { - if (name === undefined || name == null) name = 'all'; - switch (name.toLowerCase()) - { - case 'minx': return minX; - case 'maxx': return maxX; - case 'rangex': return { minX: minX, maxX: maxX, rangeX: rangeX }; - case 'miny': return minY; - case 'maxy': return maxY; - case 'rangey': return { minY: minY, maxY: maxY, rangeY: rangeY }; - case 'all': - default: return { minX: minX, maxX: maxX, rangeX: rangeX, minY: minY, maxY: maxY, rangeY: rangeY }; - } - } - var changed = false, - newMinX, - newMaxX, - newMinY, - newMaxY; - if (name == null) name = 'all'; - switch (name.toLowerCase()) - { - case 'minx': - newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0; - break; - case 'maxx': - newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0; - break; - case 'rangex': - newMinX = value && value.minX && value.minX | 0 || 0; - newMaxX = value && value.maxX && value.maxX | 0 || 0; - break; - case 'miny': - newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0; - break; - case 'maxy': - newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0; - break; - case 'rangey': - newMinY = value && value.minY && value.minY | 0 || 0; - newMaxY = value && value.maxY && value.maxY | 0 || 0; - break; - case 'all': - default: - newMinX = value && value.minX && value.minX | 0 || 0; - newMaxX = value && value.maxX && value.maxX | 0 || 0; - newMinY = value && value.minY && value.minY | 0 || 0; - newMaxY = value && value.maxY && value.maxY | 0 || 0; - break; - } - if (newMinX != null && minX != newMinX) - { - minX = newMinX; - rangeX = maxX - minX; - } - if (newMaxX != null && maxX != newMaxX) - { - maxX = newMaxX; - rangeX = maxX - minX; - } - if (newMinY != null && minY != newMinY) - { - minY = newMinY; - rangeY = maxY - minY; - } - if (newMaxY != null && maxY != newMaxY) - { - maxY = newMaxY; - rangeY = maxY - minY; - } - }, - bind = - function (callback) - { - if ($.isFunction(callback)) changeEvents.push(callback); - }, - unbind = - function (callback) - { - if (!$.isFunction(callback)) return; - var i; - while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1); - }, - destroy = - function() - { - // unbind all possible events and null objects - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - bar.unbind('mousedown', mouseDown); - bar = null; - arrow = null; - changeEvents = null; - }; - $.extend(true, $this, // public properties, methods, and event bindings - these we need to access from other controls - { - val: val, - range: range, - bind: bind, - unbind: unbind, - destroy: destroy - }); - // initialize this control - arrow.src = options.arrow && options.arrow.image; - arrow.w = options.arrow && options.arrow.width || arrow.width(); - arrow.h = options.arrow && options.arrow.height || arrow.height(); - bar.w = options.map && options.map.width || bar.width(); - bar.h = options.map && options.map.height || bar.height(); - // bind mousedown event - bar.bind('mousedown', mouseDown); - bind.call($this, draw); - }, - ColorValuePicker = // controls for all the input elements for the typing in color values - function(picker, color, bindedHex, alphaPrecision) - { - var $this = this, // private properties and methods - inputs = picker.find('td.Text input'), - red = inputs.eq(3), - green = inputs.eq(4), - blue = inputs.eq(5), - alpha = inputs.length > 7 ? inputs.eq(6) : null, - hue = inputs.eq(0), - saturation = inputs.eq(1), - value = inputs.eq(2), - hex = inputs.eq(inputs.length > 7 ? 7 : 6), - ahex = inputs.length > 7 ? inputs.eq(8) : null, - keyDown = // input box key down - use arrows to alter color - function(e) - { - if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return; - if (!validateKey(e)) return e; - switch (e.target) - { - case red.get(0): - switch (e.keyCode) - { - case 38: - red.val(setValueInRange.call($this, (red.val() << 0) + 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; - case 40: - red.val(setValueInRange.call($this, (red.val() << 0) - 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; - } - break; - case green.get(0): - switch (e.keyCode) - { - case 38: - green.val(setValueInRange.call($this, (green.val() << 0) + 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - case 40: - green.val(setValueInRange.call($this, (green.val() << 0) - 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - } - break; - case blue.get(0): - switch (e.keyCode) - { - case 38: - blue.val(setValueInRange.call($this, (blue.val() << 0) + 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - case 40: - blue.val(setValueInRange.call($this, (blue.val() << 0) - 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - } - break; - case alpha && alpha.get(0): - switch (e.keyCode) - { - case 38: - alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) + 1, 0, 100)); - color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); - return false; - case 40: - alpha.val(setValueInRange.call($this, parseFloat(alpha.val()) - 1, 0, 100)); - color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); - return false; - } - break; - case hue.get(0): - switch (e.keyCode) - { - case 38: - hue.val(setValueInRange.call($this, (hue.val() << 0) + 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - case 40: - hue.val(setValueInRange.call($this, (hue.val() << 0) - 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - } - break; - case saturation.get(0): - switch (e.keyCode) - { - case 38: - saturation.val(setValueInRange.call($this, (saturation.val() << 0) + 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - case 40: - saturation.val(setValueInRange.call($this, (saturation.val() << 0) - 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - } - break; - case value.get(0): - switch (e.keyCode) - { - case 38: - value.val(setValueInRange.call($this, (value.val() << 0) + 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - case 40: - value.val(setValueInRange.call($this, (value.val() << 0) - 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - } - break; - } - }, - keyUp = // input box key up - validate value and set color - function(e) - { - if (e.target.value == '' && e.target != hex.get(0) && (bindedHex != null && e.target != bindedHex.get(0) || bindedHex == null)) return; - if (!validateKey(e)) return e; - switch (e.target) - { - case red.get(0): - red.val(setValueInRange.call($this, red.val(), 0, 255)); - color.val('r', red.val(), e.target); - break; - case green.get(0): - green.val(setValueInRange.call($this, green.val(), 0, 255)); - color.val('g', green.val(), e.target); - break; - case blue.get(0): - blue.val(setValueInRange.call($this, blue.val(), 0, 255)); - color.val('b', blue.val(), e.target); - break; - case alpha && alpha.get(0): - alpha.val(setValueInRange.call($this, alpha.val(), 0, 100)); - color.val('a', Math.precision((alpha.val() * 255) / 100, alphaPrecision), e.target); - break; - case hue.get(0): - hue.val(setValueInRange.call($this, hue.val(), 0, 360)); - color.val('h', hue.val(), e.target); - break; - case saturation.get(0): - saturation.val(setValueInRange.call($this, saturation.val(), 0, 100)); - color.val('s', saturation.val(), e.target); - break; - case value.get(0): - value.val(setValueInRange.call($this, value.val(), 0, 100)); - color.val('v', value.val(), e.target); - break; - case hex.get(0): - hex.val(hex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); - bindedHex && bindedHex.val(hex.val()); - color.val('hex', hex.val() != '' ? hex.val() : null, e.target); - break; - case bindedHex && bindedHex.get(0): - bindedHex.val(bindedHex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 6)); - hex.val(bindedHex.val()); - color.val('hex', bindedHex.val() != '' ? bindedHex.val() : null, e.target); - break; - case ahex && ahex.get(0): - ahex.val(ahex.val().replace(/[^a-fA-F0-9]/g, '').toLowerCase().substring(0, 2)); - color.val('a', ahex.val() != null ? parseInt(ahex.val(), 16) : null, e.target); - break; - } - }, - blur = // input box blur - reset to original if value empty - function(e) - { - if (color.val() != null) - { - switch (e.target) - { - case red.get(0): red.val(color.val('r')); break; - case green.get(0): green.val(color.val('g')); break; - case blue.get(0): blue.val(color.val('b')); break; - case alpha && alpha.get(0): alpha.val(Math.precision((color.val('a') * 100) / 255, alphaPrecision)); break; - case hue.get(0): hue.val(color.val('h')); break; - case saturation.get(0): saturation.val(color.val('s')); break; - case value.get(0): value.val(color.val('v')); break; - case hex.get(0): - case bindedHex && bindedHex.get(0): - hex.val(color.val('hex')); - bindedHex && bindedHex.val(color.val('hex')); - break; - case ahex && ahex.get(0): ahex.val(color.val('ahex').substring(6)); break; - } - } - }, - validateKey = // validate key - function(e) - { - switch(e.keyCode) - { - case 9: - case 16: - case 29: - case 37: - case 39: - return false; - case 'c'.charCodeAt(): - case 'v'.charCodeAt(): - if (e.ctrlKey) return false; - } - return true; - }, - setValueInRange = // constrain value within range - function(value, min, max) - { - if (value == '' || isNaN(value)) return min; - if (value > max) return max; - if (value < min) return min; - return value; - }, - colorChanged = - function(ui, context) - { - var all = ui.val('all'); - if (context != red.get(0)) red.val(all != null ? all.r : ''); - if (context != green.get(0)) green.val(all != null ? all.g : ''); - if (context != blue.get(0)) blue.val(all != null ? all.b : ''); - if (alpha && context != alpha.get(0)) alpha.val(all != null ? Math.precision((all.a * 100) / 255, alphaPrecision) : ''); - if (context != hue.get(0)) hue.val(all != null ? all.h : ''); - if (context != saturation.get(0)) saturation.val(all != null ? all.s : ''); - if (context != value.get(0)) value.val(all != null ? all.v : ''); - if (context != hex.get(0) && (bindedHex && context != bindedHex.get(0) || !bindedHex)) hex.val(all != null ? all.hex : ''); - if (bindedHex && context != bindedHex.get(0) && context != hex.get(0)) bindedHex.val(all != null ? all.hex : ''); - if (ahex && context != ahex.get(0)) ahex.val(all != null ? all.ahex.substring(6) : ''); - }, - destroy = - function() - { - // unbind all events and null objects - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); - color.unbind(colorChanged); - red = null; - green = null; - blue = null; - alpha = null; - hue = null; - saturation = null; - value = null; - hex = null; - ahex = null; - }; - $.extend(true, $this, // public properties and methods - { - destroy: destroy - }); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); - color.bind(colorChanged); - }; - $.jPicker = - { - List: [], // array holding references to each active instance of the control - Color: // color object - we will be able to assign by any color space type or retrieve any color space info - // we want this public so we can optionally assign new color objects to initial values using inputs other than a string hex value (also supported) - function(init) - { - var $this = this, - r, - g, - b, - a, - h, - s, - v, - changeEvents = new Array(), - fireChangeEvents = - function(context) - { - for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); - }, - val = - function(name, value, context) - { - // Kind of ugly - var set = Boolean(value); - if (set && value.ahex === "") value.ahex = "00000000"; - if (!set) - { - if (name === undefined || name == null || name == '') name = 'all'; - if (r == null) return null; - switch (name.toLowerCase()) - { - case 'ahex': return ColorMethods.rgbaToHex({ r: r, g: g, b: b, a: a }); - case 'hex': return val('ahex').substring(0, 6); - case 'all': return { r: r, g: g, b: b, a: a, h: h, s: s, v: v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') }; - default: - var ret={}; - for (var i = 0; i < name.length; i++) - { - switch (name.charAt(i)) - { - case 'r': - if (name.length == 1) ret = r; - else ret.r = r; - break; - case 'g': - if (name.length == 1) ret = g; - else ret.g = g; - break; - case 'b': - if (name.length == 1) ret = b; - else ret.b = b; - break; - case 'a': - if (name.length == 1) ret = a; - else ret.a = a; - break; - case 'h': - if (name.length == 1) ret = h; - else ret.h = h; - break; - case 's': - if (name.length == 1) ret = s; - else ret.s = s; - break; - case 'v': - if (name.length == 1) ret = v; - else ret.v = v; - break; - } - } - return ret == {} ? val.call($this, 'all') : ret; - break; - } - } - if (context != null && context == $this) return; - var changed = false; - if (name == null) name = ''; - if (value == null) - { - if (r != null) - { - r = null; - changed = true; - } - if (g != null) - { - g = null; - changed = true; - } - if (b != null) - { - b = null; - changed = true; - } - if (a != null) - { - a = null; - changed = true; - } - if (h != null) - { - h = null; - changed = true; - } - if (s != null) - { - s = null; - changed = true; - } - if (v != null) - { - v = null; - changed = true; - } - changed && fireChangeEvents.call($this, context || $this); - return; - } - switch (name.toLowerCase()) - { - case 'ahex': - case 'hex': - var ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || 'none'); + List: [], // array holding references to each active instance of the control + Color: // color object - we will be able to assign by any color space type or retrieve any color space info + // we want this public so we can optionally assign new color objects to initial values using inputs other than a string hex value (also supported) + function (init) { + var $this = this, + r, + g, + b, + a, + h, + s, + v, + changeEvents = [], + fireChangeEvents = + function (context) { + for (var i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context); + }, + val = + function (name, value, context) { + // Kind of ugly + var set = Boolean(value); + if (set && value.ahex === '') value.ahex = '00000000'; + if (!set) { + if (name === undefined || name == null || name === '') name = 'all'; + if (r == null) return null; + switch (name.toLowerCase()) { + case 'ahex': return ColorMethods.rgbaToHex({ r: r, g: g, b: b, a: a }); + case 'hex': return val('ahex').substring(0, 6); + case 'all': return { r: r, g: g, b: b, a: a, h: h, s: s, v: v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') }; + default: + var ret = {}; + for (var i = 0; i < name.length; i++) { + switch (name.charAt(i)) { + case 'r': + if (name.length == 1) ret = r; + else ret.r = r; + break; + case 'g': + if (name.length == 1) ret = g; + else ret.g = g; + break; + case 'b': + if (name.length == 1) ret = b; + else ret.b = b; + break; + case 'a': + if (name.length == 1) ret = a; + else ret.a = a; + break; + case 'h': + if (name.length == 1) ret = h; + else ret.h = h; + break; + case 's': + if (name.length == 1) ret = s; + else ret.s = s; + break; + case 'v': + if (name.length == 1) ret = v; + else ret.v = v; + break; + } + } + return ret == {} ? val.call($this, 'all') : ret; + } + } + if (context != null && context === $this) return; + var changed = false; + if (name == null) name = ''; + if (value == null) { + if (r != null) { + r = null; + changed = true; + } + if (g != null) { + g = null; + changed = true; + } + if (b != null) { + b = null; + changed = true; + } + if (a != null) { + a = null; + changed = true; + } + if (h != null) { + h = null; + changed = true; + } + if (s != null) { + s = null; + changed = true; + } + if (v != null) { + v = null; + changed = true; + } + changed && fireChangeEvents.call($this, context || $this); + return; + } + switch (name.toLowerCase()) { + case 'ahex': + case 'hex': + var ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || 'none'); - val.call($this, 'rgba', { r: ret.r, g: ret.g, b: ret.b, a: name == 'ahex' ? ret.a : a != null ? a : 255 }, context); - break; - default: - if (value && (value.ahex != null || value.hex != null)) - { - val.call($this, 'ahex', value.ahex || value.hex || '00000000', context); - return; - } - var newV = {}, rgb = false, hsv = false; - if (value.r !== undefined && !name.indexOf('r') == -1) name += 'r'; - if (value.g !== undefined && !name.indexOf('g') == -1) name += 'g'; - if (value.b !== undefined && !name.indexOf('b') == -1) name += 'b'; - if (value.a !== undefined && !name.indexOf('a') == -1) name += 'a'; - if (value.h !== undefined && !name.indexOf('h') == -1) name += 'h'; - if (value.s !== undefined && !name.indexOf('s') == -1) name += 's'; - if (value.v !== undefined && !name.indexOf('v') == -1) name += 'v'; - for (var i = 0; i < name.length; i++) - { - switch (name.charAt(i)) - { - case 'r': - if (hsv) continue; - rgb = true; - newV.r = value && value.r && value.r | 0 || value && value | 0 || 0; - if (newV.r < 0) newV.r = 0; - else if (newV.r > 255) newV.r = 255; - if (r != newV.r) - { - r = newV.r; - changed = true; - } - break; - case 'g': - if (hsv) continue; - rgb = true; - newV.g = value && value.g && value.g | 0 || value && value | 0 || 0; - if (newV.g < 0) newV.g = 0; - else if (newV.g > 255) newV.g = 255; - if (g != newV.g) - { - g = newV.g; - changed = true; - } - break; - case 'b': - if (hsv) continue; - rgb = true; - newV.b = value && value.b && value.b | 0 || value && value | 0 || 0; - if (newV.b < 0) newV.b = 0; - else if (newV.b > 255) newV.b = 255; - if (b != newV.b) - { - b = newV.b; - changed = true; - } - break; - case 'a': - newV.a = value && value.a != null ? value.a | 0 : value != null ? value | 0 : 255; - if (newV.a < 0) newV.a = 0; - else if (newV.a > 255) newV.a = 255; - if (a != newV.a) - { - a = newV.a; - changed = true; - } - break; - case 'h': - if (rgb) continue; - hsv = true; - newV.h = value && value.h && value.h | 0 || value && value | 0 || 0; - if (newV.h < 0) newV.h = 0; - else if (newV.h > 360) newV.h = 360; - if (h != newV.h) - { - h = newV.h; - changed = true; - } - break; - case 's': - if (rgb) continue; - hsv = true; - newV.s = value && value.s != null ? value.s | 0 : value != null ? value | 0 : 100; - if (newV.s < 0) newV.s = 0; - else if (newV.s > 100) newV.s = 100; - if (s != newV.s) - { - s = newV.s; - changed = true; - } - break; - case 'v': - if (rgb) continue; - hsv = true; - newV.v = value && value.v != null ? value.v | 0 : value != null ? value | 0 : 100; - if (newV.v < 0) newV.v = 0; - else if (newV.v > 100) newV.v = 100; - if (v != newV.v) - { - v = newV.v; - changed = true; - } - break; - } - } - if (changed) - { - if (rgb) - { - r = r || 0; - g = g || 0; - b = b || 0; - var ret = ColorMethods.rgbToHsv({ r: r, g: g, b: b }); - h = ret.h; - s = ret.s; - v = ret.v; - } - else if (hsv) - { - h = h || 0; - s = s != null ? s : 100; - v = v != null ? v : 100; - var ret = ColorMethods.hsvToRgb({ h: h, s: s, v: v }); - r = ret.r; - g = ret.g; - b = ret.b; - } - a = a != null ? a : 255; - fireChangeEvents.call($this, context || $this); - } - break; - } - }, - bind = - function(callback) - { - if ($.isFunction(callback)) changeEvents.push(callback); - }, - unbind = - function(callback) - { - if (!$.isFunction(callback)) return; - var i; - while ((i = $.inArray(callback, changeEvents)) != -1) changeEvents.splice(i, 1); - }, - destroy = - function() - { - changeEvents = null; - } - $.extend(true, $this, // public properties and methods - { - val: val, - bind: bind, - unbind: unbind, - destroy: destroy - }); - if (init) - { - if (init.ahex != null) val('ahex', init); - else if (init.hex != null) val((init.a != null ? 'a' : '') + 'hex', init.a != null ? { ahex: init.hex + ColorMethods.intToHex(init.a) } : init); - else if (init.r != null && init.g != null && init.b != null) val('rgb' + (init.a != null ? 'a' : ''), init); - else if (init.h != null && init.s != null && init.v != null) val('hsv' + (init.a != null ? 'a' : ''), init); - } - }, - ColorMethods: // color conversion methods - make public to give use to external scripts - { - hexToRgba: - function(hex) - { - if (hex === '' || hex === 'none') return { r: null, g: null, b: null, a: null }; - hex = this.validateHex(hex); - var r = '00', g = '00', b = '00', a = '255'; - if (hex.length == 6) hex += 'ff'; - if (hex.length > 6) - { - r = hex.substring(0, 2); - g = hex.substring(2, 4); - b = hex.substring(4, 6); - a = hex.substring(6, hex.length); - } - else - { - if (hex.length > 4) - { - r = hex.substring(4, hex.length); - hex = hex.substring(0, 4); - } - if (hex.length > 2) - { - g = hex.substring(2, hex.length); - hex = hex.substring(0, 2); - } - if (hex.length > 0) b = hex.substring(0, hex.length); - } - return { r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) }; - }, - validateHex: - function(hex) - { - //if (typeof hex === "object") return ""; - hex = hex.toLowerCase().replace(/[^a-f0-9]/g, ''); - if (hex.length > 8) hex = hex.substring(0, 8); - return hex; - }, - rgbaToHex: - function(rgba) - { - return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); - }, - intToHex: - function(dec) - { - var result = (dec | 0).toString(16); - if (result.length == 1) result = ('0' + result); - return result.toLowerCase(); - }, - hexToInt: - function(hex) - { - return parseInt(hex, 16); - }, - rgbToHsv: - function(rgb) - { - var r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = { h: 0, s: 0, v: 0 }, min = 0, max = 0, delta; - if (r >= g && r >= b) - { - max = r; - min = g > b ? b : g; - } - else if (g >= b && g >= r) - { - max = g; - min = r > b ? b : r; - } - else - { - max = b; - min = g > r ? r : g; - } - hsv.v = max; - hsv.s = max ? (max - min) / max : 0; - if (!hsv.s) hsv.h = 0; - else - { - delta = max - min; - if (r == max) hsv.h = (g - b) / delta; - else if (g == max) hsv.h = 2 + (b - r) / delta; - else hsv.h = 4 + (r - g) / delta; - hsv.h = parseInt(hsv.h * 60); - if (hsv.h < 0) hsv.h += 360; - } - hsv.s = (hsv.s * 100) | 0; - hsv.v = (hsv.v * 100) | 0; - return hsv; - }, - hsvToRgb: - function(hsv) - { - var rgb = { r: 0, g: 0, b: 0, a: 100 }, h = hsv.h, s = hsv.s, v = hsv.v; - if (s == 0) - { - if (v == 0) rgb.r = rgb.g = rgb.b = 0; - else rgb.r = rgb.g = rgb.b = (v * 255 / 100) | 0; - } - else - { - if (h == 360) h = 0; - h /= 60; - s = s / 100; - v = v / 100; - var i = h | 0, - f = h - i, - p = v * (1 - s), - q = v * (1 - (s * f)), - t = v * (1 - (s * (1 - f))); - switch (i) - { - case 0: - rgb.r = v; - rgb.g = t; - rgb.b = p; - break; - case 1: - rgb.r = q; - rgb.g = v; - rgb.b = p; - break; - case 2: - rgb.r = p; - rgb.g = v; - rgb.b = t; - break; - case 3: - rgb.r = p; - rgb.g = q; - rgb.b = v; - break; - case 4: - rgb.r = t; - rgb.g = p; - rgb.b = v; - break; - case 5: - rgb.r = v; - rgb.g = p; - rgb.b = q; - break; - } - rgb.r = (rgb.r * 255) | 0; - rgb.g = (rgb.g * 255) | 0; - rgb.b = (rgb.b * 255) | 0; - } - return rgb; - } - } - }; - var Color = $.jPicker.Color, List = $.jPicker.List, ColorMethods = $.jPicker.ColorMethods; // local copies for YUI compressor - $.fn.jPicker = - function(options) - { - var $arguments = arguments; - return this.each( - function() - { - var $this = this, settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor - if ($($this).get(0).nodeName.toLowerCase() == 'input') // Add color picker icon if binding to an input element and bind the events to the input - { - $.extend(true, settings, - { - window: - { - bindToInput: true, - expandable: true, - input: $($this) - } - }); - if($($this).val()=='') - { - settings.color.active = new Color({ hex: null }); - settings.color.current = new Color({ hex: null }); - } - else if (ColorMethods.validateHex($($this).val())) - { - settings.color.active = new Color({ hex: $($this).val(), a: settings.color.active.val('a') }); - settings.color.current = new Color({ hex: $($this).val(), a: settings.color.active.val('a') }); - } - } - if (settings.window.expandable) - $($this).after('    '); - else settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results - var isLessThanIE7 = parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters, // needed to run the AlphaImageLoader function for IE6 - container = null, - colorMapDiv = null, - colorBarDiv = null, - colorMapL1 = null, // different layers of colorMap and colorBar - colorMapL2 = null, - colorMapL3 = null, - colorBarL1 = null, - colorBarL2 = null, - colorBarL3 = null, - colorBarL4 = null, - colorBarL5 = null, - colorBarL6 = null, - colorMap = null, // color maps - colorBar = null, - colorPicker = null, - elementStartX = null, // Used to record the starting css positions for dragging the control - elementStartY = null, - pageStartX = null, // Used to record the mousedown coordinates for dragging the control - pageStartY = null, - activePreview = null, // color boxes above the radio buttons - currentPreview = null, - okButton = null, - cancelButton = null, - grid = null, // preset colors grid - iconColor = null, // iconColor for popup icon - iconAlpha = null, // iconAlpha for popup icon - iconImage = null, // iconImage popup icon - moveBar = null, // drag bar - setColorMode = // set color mode and update visuals for the new color mode - function(colorMode) - { - var active = color.active, // local copies for YUI compressor - clientPath = images.clientPath, - hex = active.val('hex'), - rgbMap, - rgbBar; - settings.color.mode = colorMode; - switch (colorMode) - { - case 'h': - setTimeout( - function() - { - setBG.call($this, colorMapDiv, 'transparent'); - setImgLoc.call($this, colorMapL1, 0); - setAlpha.call($this, colorMapL1, 100); - setImgLoc.call($this, colorMapL2, 260); - setAlpha.call($this, colorMapL2, 100); - setBG.call($this, colorBarDiv, 'transparent'); - setImgLoc.call($this, colorBarL1, 0); - setAlpha.call($this, colorBarL1, 100); - setImgLoc.call($this, colorBarL2, 260); - setAlpha.call($this, colorBarL2, 100); - setImgLoc.call($this, colorBarL3, 260); - setAlpha.call($this, colorBarL3, 100); - setImgLoc.call($this, colorBarL4, 260); - setAlpha.call($this, colorBarL4, 100); - setImgLoc.call($this, colorBarL6, 260); - setAlpha.call($this, colorBarL6, 100); - }, 0); - colorMap.range('all', { minX: 0, maxX: 100, minY: 0, maxY: 100 }); - colorBar.range('rangeY', { minY: 0, maxY: 360 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('s'), y: 100 - active.val('v') }, colorMap); - colorBar.val('y', 360 - active.val('h'), colorBar); - break; - case 's': - setTimeout( - function() - { - setBG.call($this, colorMapDiv, 'transparent'); - setImgLoc.call($this, colorMapL1, -260); - setImgLoc.call($this, colorMapL2, -520); - setImgLoc.call($this, colorBarL1, -260); - setImgLoc.call($this, colorBarL2, -520); - setImgLoc.call($this, colorBarL6, 260); - setAlpha.call($this, colorBarL6, 100); - }, 0); - colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); - colorBar.range('rangeY', { minY: 0, maxY: 100 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap); - colorBar.val('y', 100 - active.val('s'), colorBar); - break; - case 'v': - setTimeout( - function() - { - setBG.call($this, colorMapDiv, '000000'); - setImgLoc.call($this, colorMapL1, -780); - setImgLoc.call($this, colorMapL2, 260); - setBG.call($this, colorBarDiv, hex); - setImgLoc.call($this, colorBarL1, -520); - setImgLoc.call($this, colorBarL2, 260); - setAlpha.call($this, colorBarL2, 100); - setImgLoc.call($this, colorBarL6, 260); - setAlpha.call($this, colorBarL6, 100); - }, 0); - colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); - colorBar.range('rangeY', { minY: 0, maxY: 100 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('s') }, colorMap); - colorBar.val('y', 100 - active.val('v'), colorBar); - break; - case 'r': - rgbMap = -1040; - rgbBar = -780; - colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); - colorBar.range('rangeY', { minY: 0, maxY: 255 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('g') }, colorMap); - colorBar.val('y', 255 - active.val('r'), colorBar); - break; - case 'g': - rgbMap = -1560; - rgbBar = -1820; - colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); - colorBar.range('rangeY', { minY: 0, maxY: 255 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('b'), y: 255 - active.val('r') }, colorMap); - colorBar.val('y', 255 - active.val('g'), colorBar); - break; - case 'b': - rgbMap = -2080; - rgbBar = -2860; - colorMap.range('all', { minX: 0, maxX: 255, minY: 0, maxY: 255 }); - colorBar.range('rangeY', { minY: 0, maxY: 255 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('r'), y: 255 - active.val('g') }, colorMap); - colorBar.val('y', 255 - active.val('b'), colorBar); - break; - case 'a': - setTimeout( - function() - { - setBG.call($this, colorMapDiv, 'transparent'); - setImgLoc.call($this, colorMapL1, -260); - setImgLoc.call($this, colorMapL2, -520); - setImgLoc.call($this, colorBarL1, 260); - setImgLoc.call($this, colorBarL2, 260); - setAlpha.call($this, colorBarL2, 100); - setImgLoc.call($this, colorBarL6, 0); - setAlpha.call($this, colorBarL6, 100); - }, 0); - colorMap.range('all', { minX: 0, maxX: 360, minY: 0, maxY: 100 }); - colorBar.range('rangeY', { minY: 0, maxY: 255 }); - if (active.val('ahex') == null) break; - colorMap.val('xy', { x: active.val('h'), y: 100 - active.val('v') }, colorMap); - colorBar.val('y', 255 - active.val('a'), colorBar); - break; - default: - throw ('Invalid Mode'); - break; - } - switch (colorMode) - { - case 'h': - break; - case 's': - case 'v': - case 'a': - setTimeout( - function() - { - setAlpha.call($this, colorMapL1, 100); - setAlpha.call($this, colorBarL1, 100); - setImgLoc.call($this, colorBarL3, 260); - setAlpha.call($this, colorBarL3, 100); - setImgLoc.call($this, colorBarL4, 260); - setAlpha.call($this, colorBarL4, 100); - }, 0); - break; - case 'r': - case 'g': - case 'b': - setTimeout( - function() - { - setBG.call($this, colorMapDiv, 'transparent'); - setBG.call($this, colorBarDiv, 'transparent'); - setAlpha.call($this, colorBarL1, 100); - setAlpha.call($this, colorMapL1, 100); - setImgLoc.call($this, colorMapL1, rgbMap); - setImgLoc.call($this, colorMapL2, rgbMap - 260); - setImgLoc.call($this, colorBarL1, rgbBar - 780); - setImgLoc.call($this, colorBarL2, rgbBar - 520); - setImgLoc.call($this, colorBarL3, rgbBar); - setImgLoc.call($this, colorBarL4, rgbBar - 260); - setImgLoc.call($this, colorBarL6, 260); - setAlpha.call($this, colorBarL6, 100); - }, 0); - break; - } - if (active.val('ahex') == null) return; - activeColorChanged.call($this, active); - }, - activeColorChanged = // Update color when user changes text values - function(ui, context) - { - if (context == null || (context != colorBar && context != colorMap)) positionMapAndBarArrows.call($this, ui, context); - setTimeout( - function() - { - updatePreview.call($this, ui); - updateMapVisuals.call($this, ui); - updateBarVisuals.call($this, ui); - }, 0); - }, - mapValueChanged = // user has dragged the ColorMap pointer - function(ui, context) - { - var active = color.active; - if (context != colorMap && active.val() == null) return; - var xy = ui.val('all'); - switch (settings.color.mode) - { - case 'h': - active.val('sv', { s: xy.x, v: 100 - xy.y }, context); - break; - case 's': - case 'a': - active.val('hv', { h: xy.x, v: 100 - xy.y }, context); - break; - case 'v': - active.val('hs', { h: xy.x, s: 100 - xy.y }, context); - break; - case 'r': - active.val('gb', { g: 255 - xy.y, b: xy.x }, context); - break; - case 'g': - active.val('rb', { r: 255 - xy.y, b: xy.x }, context); - break; - case 'b': - active.val('rg', { r: xy.x, g: 255 - xy.y }, context); - break; - } - }, - colorBarValueChanged = // user has dragged the ColorBar slider - function(ui, context) - { - var active = color.active; - if (context != colorBar && active.val() == null) return; - switch (settings.color.mode) - { - case 'h': - active.val('h', { h: 360 - ui.val('y') }, context); - break; - case 's': - active.val('s', { s: 100 - ui.val('y') }, context); - break; - case 'v': - active.val('v', { v: 100 - ui.val('y') }, context); - break; - case 'r': - active.val('r', { r: 255 - ui.val('y') }, context); - break; - case 'g': - active.val('g', { g: 255 - ui.val('y') }, context); - break; - case 'b': - active.val('b', { b: 255 - ui.val('y') }, context); - break; - case 'a': - active.val('a', 255 - ui.val('y'), context); - break; - } - }, - positionMapAndBarArrows = // position map and bar arrows to match current color - function(ui, context) - { - if (context != colorMap) - { - switch (settings.color.mode) - { - case 'h': - var sv = ui.val('sv'); - colorMap.val('xy', { x: sv != null ? sv.s : 100, y: 100 - (sv != null ? sv.v : 100) }, context); - break; - case 's': - case 'a': - var hv = ui.val('hv'); - colorMap.val('xy', { x: hv && hv.h || 0, y: 100 - (hv != null ? hv.v : 100) }, context); - break; - case 'v': - var hs = ui.val('hs'); - colorMap.val('xy', { x: hs && hs.h || 0, y: 100 - (hs != null ? hs.s : 100) }, context); - break; - case 'r': - var bg = ui.val('bg'); - colorMap.val('xy', { x: bg && bg.b || 0, y: 255 - (bg && bg.g || 0) }, context); - break; - case 'g': - var br = ui.val('br'); - colorMap.val('xy', { x: br && br.b || 0, y: 255 - (br && br.r || 0) }, context); - break; - case 'b': - var rg = ui.val('rg'); - colorMap.val('xy', { x: rg && rg.r || 0, y: 255 - (rg && rg.g || 0) }, context); - break; - } - } - if (context != colorBar) - { - switch (settings.color.mode) - { - case 'h': - colorBar.val('y', 360 - (ui.val('h') || 0), context); - break; - case 's': - var s = ui.val('s'); - colorBar.val('y', 100 - (s != null ? s : 100), context); - break; - case 'v': - var v = ui.val('v'); - colorBar.val('y', 100 - (v != null ? v : 100), context); - break; - case 'r': - colorBar.val('y', 255 - (ui.val('r') || 0), context); - break; - case 'g': - colorBar.val('y', 255 - (ui.val('g') || 0), context); - break; - case 'b': - colorBar.val('y', 255 - (ui.val('b') || 0), context); - break; - case 'a': - var a = ui.val('a'); - colorBar.val('y', 255 - (a != null ? a : 255), context); - break; - } - } - }, - updatePreview = - function(ui) - { - try - { - var all = ui.val('all'); - activePreview.css({ backgroundColor: all && '#' + all.hex || 'transparent' }); - setAlpha.call($this, activePreview, all && Math.precision((all.a * 100) / 255, 4) || 0); - } - catch (e) { } - }, - updateMapVisuals = - function(ui) - { - switch (settings.color.mode) - { - case 'h': - setBG.call($this, colorMapDiv, new Color({ h: ui.val('h') || 0, s: 100, v: 100 }).val('hex')); - break; - case 's': - case 'a': - var s = ui.val('s'); - setAlpha.call($this, colorMapL2, 100 - (s != null ? s : 100)); - break; - case 'v': - var v = ui.val('v'); - setAlpha.call($this, colorMapL1, v != null ? v : 100); - break; - case 'r': - setAlpha.call($this, colorMapL2, Math.precision((ui.val('r') || 0) / 255 * 100, 4)); - break; - case 'g': - setAlpha.call($this, colorMapL2, Math.precision((ui.val('g') || 0) / 255 * 100, 4)); - break; - case 'b': - setAlpha.call($this, colorMapL2, Math.precision((ui.val('b') || 0) / 255 * 100)); - break; - } - var a = ui.val('a'); - setAlpha.call($this, colorMapL3, Math.precision(((255 - (a || 0)) * 100) / 255, 4)); - }, - updateBarVisuals = - function(ui) - { - switch (settings.color.mode) - { - case 'h': - var a = ui.val('a'); - setAlpha.call($this, colorBarL5, Math.precision(((255 - (a || 0)) * 100) / 255, 4)); - break; - case 's': - var hva = ui.val('hva'), - saturatedColor = new Color({ h: hva && hva.h || 0, s: 100, v: hva != null ? hva.v : 100 }); - setBG.call($this, colorBarDiv, saturatedColor.val('hex')); - setAlpha.call($this, colorBarL2, 100 - (hva != null ? hva.v : 100)); - setAlpha.call($this, colorBarL5, Math.precision(((255 - (hva && hva.a || 0)) * 100) / 255, 4)); - break; - case 'v': - var hsa = ui.val('hsa'), - valueColor = new Color({ h: hsa && hsa.h || 0, s: hsa != null ? hsa.s : 100, v: 100 }); - setBG.call($this, colorBarDiv, valueColor.val('hex')); - setAlpha.call($this, colorBarL5, Math.precision(((255 - (hsa && hsa.a || 0)) * 100) / 255, 4)); - break; - case 'r': - case 'g': - case 'b': - var hValue = 0, vValue = 0, rgba = ui.val('rgba'); - if (settings.color.mode == 'r') - { - hValue = rgba && rgba.b || 0; - vValue = rgba && rgba.g || 0; - } - else if (settings.color.mode == 'g') - { - hValue = rgba && rgba.b || 0; - vValue = rgba && rgba.r || 0; - } - else if (settings.color.mode == 'b') - { - hValue = rgba && rgba.r || 0; - vValue = rgba && rgba.g || 0; - } - var middle = vValue > hValue ? hValue : vValue; - setAlpha.call($this, colorBarL2, hValue > vValue ? Math.precision(((hValue - vValue) / (255 - vValue)) * 100, 4) : 0); - setAlpha.call($this, colorBarL3, vValue > hValue ? Math.precision(((vValue - hValue) / (255 - hValue)) * 100, 4) : 0); - setAlpha.call($this, colorBarL4, Math.precision((middle / 255) * 100, 4)); - setAlpha.call($this, colorBarL5, Math.precision(((255 - (rgba && rgba.a || 0)) * 100) / 255, 4)); - break; - case 'a': - var a = ui.val('a'); - setBG.call($this, colorBarDiv, ui.val('hex') || '000000'); - setAlpha.call($this, colorBarL5, a != null ? 0 : 100); - setAlpha.call($this, colorBarL6, a != null ? 100 : 0); - break; - } - }, - setBG = - function(el, c) - { - el.css({ backgroundColor: c && c.length == 6 && '#' + c || 'transparent' }); - }, - setImg = - function(img, src) - { - if (isLessThanIE7 && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) - { - img.attr('pngSrc', src); - img.css({ backgroundImage: 'none', filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' }); - } - else img.css({ backgroundImage: 'url(\'' + src + '\')' }); - }, - setImgLoc = - function(img, y) - { - img.css({ top: y + 'px' }); - }, - setAlpha = - function(obj, alpha) - { - obj.css({ visibility: alpha > 0 ? 'visible' : 'hidden' }); - if (alpha > 0 && alpha < 100) - { - if (isLessThanIE7) - { - var src = obj.attr('pngSrc'); - if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) - obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\') progid:DXImageTransform.Microsoft.Alpha(opacity=' + alpha + ')' }); - else obj.css({ opacity: Math.precision(alpha / 100, 4) }); - } - else obj.css({ opacity: Math.precision(alpha / 100, 4) }); - } - else if (alpha == 0 || alpha == 100) - { - if (isLessThanIE7) - { - var src = obj.attr('pngSrc'); - if (src != null && (src.indexOf('AlphaBar.png') != -1 || src.indexOf('Bars.png') != -1 || src.indexOf('Maps.png') != -1)) - obj.css({ filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' }); - else obj.css({ opacity: '' }); - } - else obj.css({ opacity: '' }); - } - }, - revertColor = // revert color to original color when opened - function() - { - color.active.val('ahex', color.current.val('ahex')); - }, - commitColor = // commit the color changes - function() - { - color.current.val('ahex', color.active.val('ahex')); - }, - radioClicked = - function(e) - { - $(this).parents('tbody:first').find('input:radio[value!="'+e.target.value+'"]').removeAttr('checked'); - setColorMode.call($this, e.target.value); - }, - currentClicked = - function() - { - revertColor.call($this); - }, - cancelClicked = - function() - { - revertColor.call($this); - settings.window.expandable && hide.call($this); - $.isFunction(cancelCallback) && cancelCallback.call($this, color.active, cancelButton); - }, - okClicked = - function() - { - commitColor.call($this); - settings.window.expandable && hide.call($this); - $.isFunction(commitCallback) && commitCallback.call($this, color.active, okButton); - }, - iconImageClicked = - function() - { - show.call($this); - }, - currentColorChanged = - function(ui, context) - { - var hex = ui.val('hex'); - currentPreview.css({ backgroundColor: hex && '#' + hex || 'transparent' }); - setAlpha.call($this, currentPreview, Math.precision(((ui.val('a') || 0) * 100) / 255, 4)); - }, - expandableColorChanged = - function(ui, context) - { - var hex = ui.val('hex'); - var va = ui.val('va'); - iconColor.css({ backgroundColor: hex && '#' + hex || 'transparent' }); - setAlpha.call($this, iconAlpha, Math.precision(((255 - (va && va.a || 0)) * 100) / 255, 4)); - if (settings.window.bindToInput&&settings.window.updateInputColor) - settings.window.input.css( - { - backgroundColor: hex && '#' + hex || 'transparent', - color: va == null || va.v > 75 ? '#000000' : '#ffffff' - }); - }, - moveBarMouseDown = - function(e) - { - var element = settings.window.element, // local copies for YUI compressor - page = settings.window.page; - elementStartX = parseInt(container.css('left')); - elementStartY = parseInt(container.css('top')); - pageStartX = e.pageX; - pageStartY = e.pageY; - // bind events to document to move window - we will unbind these on mouseup - $(document).bind('mousemove', documentMouseMove).bind('mouseup', documentMouseUp); - e.preventDefault(); // prevent attempted dragging of the column - }, - documentMouseMove = - function(e) - { - container.css({ left: elementStartX - (pageStartX - e.pageX) + 'px', top: elementStartY - (pageStartY - e.pageY) + 'px' }); - if (settings.window.expandable && !$.support.boxModel) container.prev().css({ left: container.css("left"), top: container.css("top") }); - e.stopPropagation(); - e.preventDefault(); - return false; - }, - documentMouseUp = - function(e) - { - $(document).unbind('mousemove', documentMouseMove).unbind('mouseup', documentMouseUp); - e.stopPropagation(); - e.preventDefault(); - return false; - }, - quickPickClicked = - function(e) - { - e.preventDefault(); - e.stopPropagation(); - color.active.val('ahex', $(this).attr('title') || null, e.target); - return false; - }, - commitCallback = $.isFunction($arguments[1]) && $arguments[1] || null, - liveCallback = $.isFunction($arguments[2]) && $arguments[2] || null, - cancelCallback = $.isFunction($arguments[3]) && $arguments[3] || null, - show = - function() - { - color.current.val('ahex', color.active.val('ahex')); - var attachIFrame = function() - { - if (!settings.window.expandable || $.support.boxModel) return; - var table = container.find('table:first'); - container.before('