From 28cf477ae42b6c239681d1992dcdea127fe6e6bb Mon Sep 17 00:00:00 2001 From: Jason Kridner Date: Fri, 19 Apr 2013 23:48:45 -0500 Subject: [PATCH] More jquery js files referenced by bonescript --- static/jquery.dimensions.js | 121 ++++ static/jquery.svg.js | 1394 +++++++++++++++++++++++++++++++++++++++++ static/jquery.ui.accordion.js | 731 +++++++++++++++++++++ 3 files changed, 2246 insertions(+) create mode 100644 static/jquery.dimensions.js create mode 100644 static/jquery.svg.js create mode 100755 static/jquery.ui.accordion.js diff --git a/static/jquery.dimensions.js b/static/jquery.dimensions.js new file mode 100644 index 000000000..422924104 --- /dev/null +++ b/static/jquery.dimensions.js @@ -0,0 +1,121 @@ +// JavaScript Document +/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * $LastChangedDate$ + * $Rev$ + * + * Version: @VERSION + * + * Requires: jQuery 1.2+ + */ + +(function($){ + +$.dimensions = { + version: '@VERSION' +}; + +// Create innerHeight, innerWidth, outerHeight and outerWidth methods +$.each( [ 'Height', 'Width' ], function(i, name){ + + // innerHeight and innerWidth + $.fn[ 'inner' + name ] = function() { + if (!this[0]) return; + + var torl = name == 'Height' ? 'Top' : 'Left', // top or left + borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right + + return this.css('display') != 'none' ? this[0]['client' + name] : num( this, name.toLowerCase() ) + num(this, 'padding' + torl) + num(this, 'padding' + borr); + }; + + // outerHeight and outerWidth + $.fn[ 'outer' + name ] = function(options) { + if (!this[0]) return; + + var torl = name == 'Height' ? 'Top' : 'Left', // top or left + borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right + + options = $.extend({ margin: false }, options || {}); + + var val = this.css('display') != 'none' ? + this[0]['offset' + name] : + num( this, name.toLowerCase() ) + + num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width') + + num(this, 'padding' + torl) + num(this, 'padding' + borr); + + return val + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0); + }; +}); + +// Create scrollLeft and scrollTop methods +$.each( ['Left', 'Top'], function(i, name) { + $.fn[ 'scroll' + name ] = function(val) { + if (!this[0]) return; + + return val != undefined ? + + // Set the scroll offset + this.each(function() { + this == window || this == document ? + window.scrollTo( + name == 'Left' ? val : $(window)[ 'scrollLeft' ](), + name == 'Top' ? val : $(window)[ 'scrollTop' ]() + ) : + this[ 'scroll' + name ] = val; + }) : + + // Return the scroll offset + this[0] == window || this[0] == document ? + self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] || + $.boxModel && document.documentElement[ 'scroll' + name ] || + document.body[ 'scroll' + name ] : + this[0][ 'scroll' + name ]; + }; +}); + +$.fn.extend({ + position: function() { + var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results; + + if (elem) { + // Get *real* offsetParent + offsetParent = this.offsetParent(); + + // Get correct offsets + offset = this.offset(); + parentOffset = offsetParent.offset(); + + // Subtract element margins + offset.top -= num(elem, 'marginTop'); + offset.left -= num(elem, 'marginLeft'); + + // Add offsetParent borders + parentOffset.top += num(offsetParent, 'borderTopWidth'); + parentOffset.left += num(offsetParent, 'borderLeftWidth'); + + // Subtract the two offsets + results = { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + }; + } + + return results; + }, + + offsetParent: function() { + var offsetParent = this[0].offsetParent; + while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') ) + offsetParent = offsetParent.offsetParent; + return $(offsetParent); + } +}); + +function num(el, prop) { + return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0; +}; + +})(jQuery); + diff --git a/static/jquery.svg.js b/static/jquery.svg.js new file mode 100644 index 000000000..5fb13455d --- /dev/null +++ b/static/jquery.svg.js @@ -0,0 +1,1394 @@ +/* http://keith-wood.name/svg.html + SVG for jQuery v1.4.4. + Written by Keith Wood (kbwood{at}iinet.com.au) August 2007. + Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and + MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. + Please attribute the author if you use it. */ + +(function($) { // Hide scope, no $ conflict + +/* SVG manager. + Use the singleton instance of this class, $.svg, + to interact with the SVG functionality. */ +function SVGManager() { + this._settings = []; // Settings to be remembered per SVG object + this._extensions = []; // List of SVG extensions added to SVGWrapper + // for each entry [0] is extension name, [1] is extension class (function) + // the function takes one parameter - the SVGWrapper instance + this.regional = []; // Localisations, indexed by language, '' for default (English) + this.regional[''] = {errorLoadingText: 'Error loading', + notSupportedText: 'This browser does not support SVG'}; + this.local = this.regional['']; // Current localisation + this._uuid = new Date().getTime(); + this._renesis = detectActiveX('RenesisX.RenesisCtrl'); +} + +/* Determine whether a given ActiveX control is available. + @param classId (string) the ID for the ActiveX control + @return (boolean) true if found, false if not */ +function detectActiveX(classId) { + try { + return !!(window.ActiveXObject && new ActiveXObject(classId)); + } + catch (e) { + return false; + } +} + +var PROP_NAME = 'svgwrapper'; + +$.extend(SVGManager.prototype, { + /* Class name added to elements to indicate already configured with SVG. */ + markerClassName: 'hasSVG', + + /* SVG namespace. */ + svgNS: 'http://www.w3.org/2000/svg', + /* XLink namespace. */ + xlinkNS: 'http://www.w3.org/1999/xlink', + + /* SVG wrapper class. */ + _wrapperClass: SVGWrapper, + + /* Camel-case versions of attribute names containing dashes or are reserved words. */ + _attrNames: {class_: 'class', in_: 'in', + alignmentBaseline: 'alignment-baseline', baselineShift: 'baseline-shift', + clipPath: 'clip-path', clipRule: 'clip-rule', + colorInterpolation: 'color-interpolation', + colorInterpolationFilters: 'color-interpolation-filters', + colorRendering: 'color-rendering', dominantBaseline: 'dominant-baseline', + enableBackground: 'enable-background', fillOpacity: 'fill-opacity', + fillRule: 'fill-rule', floodColor: 'flood-color', + floodOpacity: 'flood-opacity', fontFamily: 'font-family', + fontSize: 'font-size', fontSizeAdjust: 'font-size-adjust', + fontStretch: 'font-stretch', fontStyle: 'font-style', + fontVariant: 'font-variant', fontWeight: 'font-weight', + glyphOrientationHorizontal: 'glyph-orientation-horizontal', + glyphOrientationVertical: 'glyph-orientation-vertical', + horizAdvX: 'horiz-adv-x', horizOriginX: 'horiz-origin-x', + imageRendering: 'image-rendering', letterSpacing: 'letter-spacing', + lightingColor: 'lighting-color', markerEnd: 'marker-end', + markerMid: 'marker-mid', markerStart: 'marker-start', + stopColor: 'stop-color', stopOpacity: 'stop-opacity', + strikethroughPosition: 'strikethrough-position', + strikethroughThickness: 'strikethrough-thickness', + strokeDashArray: 'stroke-dasharray', strokeDashOffset: 'stroke-dashoffset', + strokeLineCap: 'stroke-linecap', strokeLineJoin: 'stroke-linejoin', + strokeMiterLimit: 'stroke-miterlimit', strokeOpacity: 'stroke-opacity', + strokeWidth: 'stroke-width', textAnchor: 'text-anchor', + textDecoration: 'text-decoration', textRendering: 'text-rendering', + underlinePosition: 'underline-position', underlineThickness: 'underline-thickness', + vertAdvY: 'vert-adv-y', vertOriginY: 'vert-origin-y', + wordSpacing: 'word-spacing', writingMode: 'writing-mode'}, + + /* Add the SVG object to its container. */ + _attachSVG: function(container, settings) { + var svg = (container.namespaceURI == this.svgNS ? container : null); + var container = (svg ? null : container); + if ($(container || svg).hasClass(this.markerClassName)) { + return; + } + if (typeof settings == 'string') { + settings = {loadURL: settings}; + } + else if (typeof settings == 'function') { + settings = {onLoad: settings}; + } + $(container || svg).addClass(this.markerClassName); + try { + if (!svg) { + svg = document.createElementNS(this.svgNS, 'svg'); + svg.setAttribute('version', '1.1'); + if (container.clientWidth > 0) { + svg.setAttribute('width', container.clientWidth); + } + if (container.clientHeight > 0) { + svg.setAttribute('height', container.clientHeight); + } + container.appendChild(svg); + } + this._afterLoad(container, svg, settings || {}); + } + catch (e) { + if ($.browser.msie) { + if (!container.id) { + container.id = 'svg' + (this._uuid++); + } + this._settings[container.id] = settings; + container.innerHTML = ''; + } + else { + container.innerHTML = '

' + + this.local.notSupportedText + '

'; + } + } + }, + + /* SVG callback after loading - register SVG root. */ + _registerSVG: function() { + for (var i = 0; i < document.embeds.length; i++) { // Check all + var container = document.embeds[i].parentNode; + if (!$(container).hasClass($.svg.markerClassName) || // Not SVG + $.data(container, PROP_NAME)) { // Already done + continue; + } + var svg = null; + try { + svg = document.embeds[i].getSVGDocument(); + } + catch(e) { + setTimeout($.svg._registerSVG, 250); // Renesis takes longer to load + return; + } + svg = (svg ? svg.documentElement : null); + if (svg) { + $.svg._afterLoad(container, svg); + } + } + }, + + /* Post-processing once loaded. */ + _afterLoad: function(container, svg, settings) { + var settings = settings || this._settings[container.id]; + this._settings[container ? container.id : ''] = null; + var wrapper = new this._wrapperClass(svg, container); + $.data(container || svg, PROP_NAME, wrapper); + try { + if (settings.loadURL) { // Load URL + wrapper.load(settings.loadURL, settings); + } + if (settings.settings) { // Additional settings + wrapper.configure(settings.settings); + } + if (settings.onLoad && !settings.loadURL) { // Onload callback + settings.onLoad.apply(container || svg, [wrapper]); + } + } + catch (e) { + alert(e); + } + }, + + /* Return the SVG wrapper created for a given container. + @param container (string) selector for the container or + (element) the container for the SVG object or + jQuery collection - first entry is the container + @return (SVGWrapper) the corresponding SVG wrapper element, or null if not attached */ + _getSVG: function(container) { + container = (typeof container == 'string' ? $(container)[0] : + (container.jquery ? container[0] : container)); + return $.data(container, PROP_NAME); + }, + + /* Remove the SVG functionality from a div. + @param container (element) the container for the SVG object */ + _destroySVG: function(container) { + var $container = $(container); + if (!$container.hasClass(this.markerClassName)) { + return; + } + $container.removeClass(this.markerClassName); + if (container.namespaceURI != this.svgNS) { + $container.empty(); + } + $.removeData(container, PROP_NAME); + }, + + /* Extend the SVGWrapper object with an embedded class. + The constructor function must take a single parameter that is + a reference to the owning SVG root object. This allows the + extension to access the basic SVG functionality. + @param name (string) the name of the SVGWrapper attribute to access the new class + @param extClass (function) the extension class constructor */ + addExtension: function(name, extClass) { + this._extensions.push([name, extClass]); + }, + + /* Does this node belong to SVG? + @param node (element) the node to be tested + @return (boolean) true if an SVG node, false if not */ + isSVGElem: function(node) { + return (node.nodeType == 1 && node.namespaceURI == $.svg.svgNS); + } +}); + +/* The main SVG interface, which encapsulates the SVG element. + Obtain a reference from $().svg('get') */ +function SVGWrapper(svg, container) { + this._svg = svg; // The SVG root node + this._container = container; // The containing div + for (var i = 0; i < $.svg._extensions.length; i++) { + var extension = $.svg._extensions[i]; + this[extension[0]] = new extension[1](this); + } +} + +$.extend(SVGWrapper.prototype, { + + /* Retrieve the width of the SVG object. */ + _width: function() { + return (this._container ? this._container.clientWidth : this._svg.width); + }, + + /* Retrieve the height of the SVG object. */ + _height: function() { + return (this._container ? this._container.clientHeight : this._svg.height); + }, + + /* Retrieve the root SVG element. + @return the top-level SVG element */ + root: function() { + return this._svg; + }, + + /* Configure a SVG node. + @param node (element, optional) the node to configure + @param settings (object) additional settings for the root + @param clear (boolean) true to remove existing attributes first, + false to add to what is already there (optional) + @return (SVGWrapper) this root */ + configure: function(node, settings, clear) { + if (!node.nodeName) { + clear = settings; + settings = node; + node = this._svg; + } + if (clear) { + for (var i = node.attributes.length - 1; i >= 0; i--) { + var attr = node.attributes.item(i); + if (!(attr.nodeName == 'onload' || attr.nodeName == 'version' || + attr.nodeName.substring(0, 5) == 'xmlns')) { + node.attributes.removeNamedItem(attr.nodeName); + } + } + } + for (var attrName in settings) { + node.setAttribute($.svg._attrNames[attrName] || attrName, settings[attrName]); + } + return this; + }, + + /* Locate a specific element in the SVG document. + @param id (string) the element's identifier + @return (element) the element reference, or null if not found */ + getElementById: function(id) { + return this._svg.ownerDocument.getElementById(id); + }, + + /* Change the attributes for a SVG node. + @param element (SVG element) the node to change + @param settings (object) the new settings + @return (SVGWrapper) this root */ + change: function(element, settings) { + if (element) { + for (var name in settings) { + if (settings[name] == null) { + element.removeAttribute($.svg._attrNames[name] || name); + } + else { + element.setAttribute($.svg._attrNames[name] || name, settings[name]); + } + } + } + return this; + }, + + /* Check for parent being absent and adjust arguments accordingly. */ + _args: function(values, names, optSettings) { + names.splice(0, 0, 'parent'); + names.splice(names.length, 0, 'settings'); + var args = {}; + var offset = 0; + if (values[0] != null && values[0].jquery) { + values[0] = values[0][0]; + } + if (values[0] != null && !(typeof values[0] == 'object' && values[0].nodeName)) { + args['parent'] = null; + offset = 1; + } + for (var i = 0; i < values.length; i++) { + args[names[i + offset]] = values[i]; + } + if (optSettings) { + $.each(optSettings, function(i, value) { + if (typeof args[value] == 'object') { + args.settings = args[value]; + args[value] = null; + } + }); + } + return args; + }, + + /* Add a title. + @param parent (element or jQuery) the parent node for the new title (optional) + @param text (string) the text of the title + @param settings (object) additional settings for the title (optional) + @return (element) the new title node */ + title: function(parent, text, settings) { + var args = this._args(arguments, ['text']); + var node = this._makeNode(args.parent, 'title', args.settings || {}); + node.appendChild(this._svg.ownerDocument.createTextNode(args.text)); + return node; + }, + + /* Add a description. + @param parent (element or jQuery) the parent node for the new description (optional) + @param text (string) the text of the description + @param settings (object) additional settings for the description (optional) + @return (element) the new description node */ + describe: function(parent, text, settings) { + var args = this._args(arguments, ['text']); + var node = this._makeNode(args.parent, 'desc', args.settings || {}); + node.appendChild(this._svg.ownerDocument.createTextNode(args.text)); + return node; + }, + + /* Add a definitions node. + @param parent (element or jQuery) the parent node for the new definitions (optional) + @param id (string) the ID of this definitions (optional) + @param settings (object) additional settings for the definitions (optional) + @return (element) the new definitions node */ + defs: function(parent, id, settings) { + var args = this._args(arguments, ['id'], ['id']); + return this._makeNode(args.parent, 'defs', $.extend( + (args.id ? {id: args.id} : {}), args.settings || {})); + }, + + /* Add a symbol definition. + @param parent (element or jQuery) the parent node for the new symbol (optional) + @param id (string) the ID of this symbol + @param x1 (number) the left coordinate for this symbol + @param y1 (number) the top coordinate for this symbol + @param width (number) the width of this symbol + @param height (number) the height of this symbol + @param settings (object) additional settings for the symbol (optional) + @return (element) the new symbol node */ + symbol: function(parent, id, x1, y1, width, height, settings) { + var args = this._args(arguments, ['id', 'x1', 'y1', 'width', 'height']); + return this._makeNode(args.parent, 'symbol', $.extend({id: args.id, + viewBox: args.x1 + ' ' + args.y1 + ' ' + args.width + ' ' + args.height}, + args.settings || {})); + }, + + /* Add a marker definition. + @param parent (element or jQuery) the parent node for the new marker (optional) + @param id (string) the ID of this marker + @param refX (number) the x-coordinate for the reference point + @param refY (number) the y-coordinate for the reference point + @param mWidth (number) the marker viewport width + @param mHeight (number) the marker viewport height + @param orient (string or int) 'auto' or angle (degrees) (optional) + @param settings (object) additional settings for the marker (optional) + @return (element) the new marker node */ + marker: function(parent, id, refX, refY, mWidth, mHeight, orient, settings) { + var args = this._args(arguments, ['id', 'refX', 'refY', + 'mWidth', 'mHeight', 'orient'], ['orient']); + return this._makeNode(args.parent, 'marker', $.extend( + {id: args.id, refX: args.refX, refY: args.refY, markerWidth: args.mWidth, + markerHeight: args.mHeight, orient: args.orient || 'auto'}, args.settings || {})); + }, + + /* Add a style node. + @param parent (element or jQuery) the parent node for the new node (optional) + @param styles (string) the CSS styles + @param settings (object) additional settings for the node (optional) + @return (element) the new style node */ + style: function(parent, styles, settings) { + var args = this._args(arguments, ['styles']); + var node = this._makeNode(args.parent, 'style', $.extend( + {type: 'text/css'}, args.settings || {})); + node.appendChild(this._svg.ownerDocument.createTextNode(args.styles)); + if ($.browser.opera) { + $('head').append(''); + } + return node; + }, + + /* Add a script node. + @param parent (element or jQuery) the parent node for the new node (optional) + @param script (string) the JavaScript code + @param type (string) the MIME type for the code (optional, default 'text/javascript') + @param settings (object) additional settings for the node (optional) + @return (element) the new script node */ + script: function(parent, script, type, settings) { + var args = this._args(arguments, ['script', 'type'], ['type']); + var node = this._makeNode(args.parent, 'script', $.extend( + {type: args.type || 'text/javascript'}, args.settings || {})); + node.appendChild(this._svg.ownerDocument.createTextNode(args.script)); + if (!$.browser.mozilla) { + $.globalEval(args.script); + } + return node; + }, + + /* Add a linear gradient definition. + Specify all of x1, y1, x2, y2 or none of them. + @param parent (element or jQuery) the parent node for the new gradient (optional) + @param id (string) the ID for this gradient + @param stops (string[][]) the gradient stops, each entry is + [0] is offset (0.0-1.0 or 0%-100%), [1] is colour, + [2] is opacity (optional) + @param x1 (number) the x-coordinate of the gradient start (optional) + @param y1 (number) the y-coordinate of the gradient start (optional) + @param x2 (number) the x-coordinate of the gradient end (optional) + @param y2 (number) the y-coordinate of the gradient end (optional) + @param settings (object) additional settings for the gradient (optional) + @return (element) the new gradient node */ + linearGradient: function(parent, id, stops, x1, y1, x2, y2, settings) { + var args = this._args(arguments, + ['id', 'stops', 'x1', 'y1', 'x2', 'y2'], ['x1']); + var sets = $.extend({id: args.id}, + (args.x1 != null ? {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2} : {})); + return this._gradient(args.parent, 'linearGradient', + $.extend(sets, args.settings || {}), args.stops); + }, + + /* Add a radial gradient definition. + Specify all of cx, cy, r, fx, fy or none of them. + @param parent (element or jQuery) the parent node for the new gradient (optional) + @param id (string) the ID for this gradient + @param stops (string[][]) the gradient stops, each entry + [0] is offset, [1] is colour, [2] is opacity (optional) + @param cx (number) the x-coordinate of the largest circle centre (optional) + @param cy (number) the y-coordinate of the largest circle centre (optional) + @param r (number) the radius of the largest circle (optional) + @param fx (number) the x-coordinate of the gradient focus (optional) + @param fy (number) the y-coordinate of the gradient focus (optional) + @param settings (object) additional settings for the gradient (optional) + @return (element) the new gradient node */ + radialGradient: function(parent, id, stops, cx, cy, r, fx, fy, settings) { + var args = this._args(arguments, + ['id', 'stops', 'cx', 'cy', 'r', 'fx', 'fy'], ['cx']); + var sets = $.extend({id: args.id}, (args.cx != null ? + {cx: args.cx, cy: args.cy, r: args.r, fx: args.fx, fy: args.fy} : {})); + return this._gradient(args.parent, 'radialGradient', + $.extend(sets, args.settings || {}), args.stops); + }, + + /* Add a gradient node. */ + _gradient: function(parent, name, settings, stops) { + var node = this._makeNode(parent, name, settings); + for (var i = 0; i < stops.length; i++) { + var stop = stops[i]; + this._makeNode(node, 'stop', $.extend( + {offset: stop[0], stopColor: stop[1]}, + (stop[2] != null ? {stopOpacity: stop[2]} : {}))); + } + return node; + }, + + /* Add a pattern definition. + Specify all of vx, vy, xwidth, vheight or none of them. + @param parent (element or jQuery) the parent node for the new pattern (optional) + @param id (string) the ID for this pattern + @param x (number) the x-coordinate for the left edge of the pattern + @param y (number) the y-coordinate for the top edge of the pattern + @param width (number) the width of the pattern + @param height (number) the height of the pattern + @param vx (number) the minimum x-coordinate for view box (optional) + @param vy (number) the minimum y-coordinate for the view box (optional) + @param vwidth (number) the width of the view box (optional) + @param vheight (number) the height of the view box (optional) + @param settings (object) additional settings for the pattern (optional) + @return (element) the new pattern node */ + pattern: function(parent, id, x, y, width, height, vx, vy, vwidth, vheight, settings) { + var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height', + 'vx', 'vy', 'vwidth', 'vheight'], ['vx']); + var sets = $.extend({id: args.id, x: args.x, y: args.y, + width: args.width, height: args.height}, (args.vx != null ? + {viewBox: args.vx + ' ' + args.vy + ' ' + args.vwidth + ' ' + args.vheight} : {})); + return this._makeNode(args.parent, 'pattern', $.extend(sets, args.settings || {})); + }, + + /* Add a clip path definition. + @param parent (element) the parent node for the new element (optional) + @param id (string) the ID for this path + @param units (string) either 'userSpaceOnUse' (default) or 'objectBoundingBox' (optional) + @return (element) the new clipPath node */ + clipPath: function(parent, id, units, settings) { + var args = this._args(arguments, ['id', 'units']); + args.units = args.units || 'userSpaceOnUse'; + return this._makeNode(args.parent, 'clipPath', $.extend( + {id: args.id, clipPathUnits: args.units}, args.settings || {})); + }, + + /* Add a mask definition. + @param parent (element or jQuery) the parent node for the new mask (optional) + @param id (string) the ID for this mask + @param x (number) the x-coordinate for the left edge of the mask + @param y (number) the y-coordinate for the top edge of the mask + @param width (number) the width of the mask + @param height (number) the height of the mask + @param settings (object) additional settings for the mask (optional) + @return (element) the new mask node */ + mask: function(parent, id, x, y, width, height, settings) { + var args = this._args(arguments, ['id', 'x', 'y', 'width', 'height']); + return this._makeNode(args.parent, 'mask', $.extend( + {id: args.id, x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + }, + + /* Create a new path object. + @return (SVGPath) a new path object */ + createPath: function() { + return new SVGPath(); + }, + + /* Create a new text object. + @return (SVGText) a new text object */ + createText: function() { + return new SVGText(); + }, + + /* Add an embedded SVG element. + Specify all of vx, vy, vwidth, vheight or none of them. + @param parent (element or jQuery) the parent node for the new node (optional) + @param x (number) the x-coordinate for the left edge of the node + @param y (number) the y-coordinate for the top edge of the node + @param width (number) the width of the node + @param height (number) the height of the node + @param vx (number) the minimum x-coordinate for view box (optional) + @param vy (number) the minimum y-coordinate for the view box (optional) + @param vwidth (number) the width of the view box (optional) + @param vheight (number) the height of the view box (optional) + @param settings (object) additional settings for the node (optional) + @return (element) the new node */ + svg: function(parent, x, y, width, height, vx, vy, vwidth, vheight, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', + 'vx', 'vy', 'vwidth', 'vheight'], ['vx']); + var sets = $.extend({x: args.x, y: args.y, width: args.width, height: args.height}, + (args.vx != null ? {viewBox: args.vx + ' ' + args.vy + ' ' + + args.vwidth + ' ' + args.vheight} : {})); + return this._makeNode(args.parent, 'svg', $.extend(sets, args.settings || {})); + }, + + /* Create a group. + @param parent (element or jQuery) the parent node for the new group (optional) + @param id (string) the ID of this group (optional) + @param settings (object) additional settings for the group (optional) + @return (element) the new group node */ + group: function(parent, id, settings) { + var args = this._args(arguments, ['id'], ['id']); + return this._makeNode(args.parent, 'g', $.extend({id: args.id}, args.settings || {})); + }, + + /* Add a usage reference. + Specify all of x, y, width, height or none of them. + @param parent (element or jQuery) the parent node for the new node (optional) + @param x (number) the x-coordinate for the left edge of the node (optional) + @param y (number) the y-coordinate for the top edge of the node (optional) + @param width (number) the width of the node (optional) + @param height (number) the height of the node (optional) + @param ref (string) the ID of the definition node + @param settings (object) additional settings for the node (optional) + @return (element) the new node */ + use: function(parent, x, y, width, height, ref, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']); + if (typeof args.x == 'string') { + args.ref = args.x; + args.settings = args.y; + args.x = args.y = args.width = args.height = null; + } + var node = this._makeNode(args.parent, 'use', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Add a link, which applies to all child elements. + @param parent (element or jQuery) the parent node for the new link (optional) + @param ref (string) the target URL + @param settings (object) additional settings for the link (optional) + @return (element) the new link node */ + link: function(parent, ref, settings) { + var args = this._args(arguments, ['ref']); + var node = this._makeNode(args.parent, 'a', args.settings); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Add an image. + @param parent (element or jQuery) the parent node for the new image (optional) + @param x (number) the x-coordinate for the left edge of the image + @param y (number) the y-coordinate for the top edge of the image + @param width (number) the width of the image + @param height (number) the height of the image + @param ref (string) the path to the image + @param settings (object) additional settings for the image (optional) + @return (element) the new image node */ + image: function(parent, x, y, width, height, ref, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'ref']); + var node = this._makeNode(args.parent, 'image', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + args.settings || {})); + node.setAttributeNS($.svg.xlinkNS, 'href', args.ref); + return node; + }, + + /* Draw a path. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param path (string or SVGPath) the path to draw + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + path: function(parent, path, settings) { + var args = this._args(arguments, ['path']); + return this._makeNode(args.parent, 'path', $.extend( + {d: (args.path.path ? args.path.path() : args.path)}, args.settings || {})); + }, + + /* Draw a rectangle. + Specify both of rx and ry or neither. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param x (number) the x-coordinate for the left edge of the rectangle + @param y (number) the y-coordinate for the top edge of the rectangle + @param width (number) the width of the rectangle + @param height (number) the height of the rectangle + @param rx (number) the x-radius of the ellipse for the rounded corners (optional) + @param ry (number) the y-radius of the ellipse for the rounded corners (optional) + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + rect: function(parent, x, y, width, height, rx, ry, settings) { + var args = this._args(arguments, ['x', 'y', 'width', 'height', 'rx', 'ry'], ['rx']); + return this._makeNode(args.parent, 'rect', $.extend( + {x: args.x, y: args.y, width: args.width, height: args.height}, + (args.rx ? {rx: args.rx, ry: args.ry} : {}), args.settings || {})); + }, + + /* Draw a circle. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param cx (number) the x-coordinate for the centre of the circle + @param cy (number) the y-coordinate for the centre of the circle + @param r (number) the radius of the circle + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + circle: function(parent, cx, cy, r, settings) { + var args = this._args(arguments, ['cx', 'cy', 'r']); + return this._makeNode(args.parent, 'circle', $.extend( + {cx: args.cx, cy: args.cy, r: args.r}, args.settings || {})); + }, + + /* Draw an ellipse. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param cx (number) the x-coordinate for the centre of the ellipse + @param cy (number) the y-coordinate for the centre of the ellipse + @param rx (number) the x-radius of the ellipse + @param ry (number) the y-radius of the ellipse + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + ellipse: function(parent, cx, cy, rx, ry, settings) { + var args = this._args(arguments, ['cx', 'cy', 'rx', 'ry']); + return this._makeNode(args.parent, 'ellipse', $.extend( + {cx: args.cx, cy: args.cy, rx: args.rx, ry: args.ry}, args.settings || {})); + }, + + /* Draw a line. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param x1 (number) the x-coordinate for the start of the line + @param y1 (number) the y-coordinate for the start of the line + @param x2 (number) the x-coordinate for the end of the line + @param y2 (number) the y-coordinate for the end of the line + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + line: function(parent, x1, y1, x2, y2, settings) { + var args = this._args(arguments, ['x1', 'y1', 'x2', 'y2']); + return this._makeNode(args.parent, 'line', $.extend( + {x1: args.x1, y1: args.y1, x2: args.x2, y2: args.y2}, args.settings || {})); + }, + + /* Draw a polygonal line. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param points (number[][]) the x-/y-coordinates for the points on the line + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + polyline: function(parent, points, settings) { + var args = this._args(arguments, ['points']); + return this._poly(args.parent, 'polyline', args.points, args.settings); + }, + + /* Draw a polygonal shape. + @param parent (element or jQuery) the parent node for the new shape (optional) + @param points (number[][]) the x-/y-coordinates for the points on the shape + @param settings (object) additional settings for the shape (optional) + @return (element) the new shape node */ + polygon: function(parent, points, settings) { + var args = this._args(arguments, ['points']); + return this._poly(args.parent, 'polygon', args.points, args.settings); + }, + + /* Draw a polygonal line or shape. */ + _poly: function(parent, name, points, settings) { + var ps = ''; + for (var i = 0; i < points.length; i++) { + ps += points[i].join() + ' '; + } + return this._makeNode(parent, name, $.extend( + {points: $.trim(ps)}, settings || {})); + }, + + /* Draw text. + Specify both of x and y or neither of them. + @param parent (element or jQuery) the parent node for the text (optional) + @param x (number or number[]) the x-coordinate(s) for the text (optional) + @param y (number or number[]) the y-coordinate(s) for the text (optional) + @param value (string) the text content or + (SVGText) text with spans and references + @param settings (object) additional settings for the text (optional) + @return (element) the new text node */ + text: function(parent, x, y, value, settings) { + var args = this._args(arguments, ['x', 'y', 'value']); + if (typeof args.x == 'string' && arguments.length < 4) { + args.value = args.x; + args.settings = args.y; + args.x = args.y = null; + } + return this._text(args.parent, 'text', args.value, $.extend( + {x: (args.x && isArray(args.x) ? args.x.join(' ') : args.x), + y: (args.y && isArray(args.y) ? args.y.join(' ') : args.y)}, + args.settings || {})); + }, + + /* Draw text along a path. + @param parent (element or jQuery) the parent node for the text (optional) + @param path (string) the ID of the path + @param value (string) the text content or + (SVGText) text with spans and references + @param settings (object) additional settings for the text (optional) + @return (element) the new text node */ + textpath: function(parent, path, value, settings) { + var args = this._args(arguments, ['path', 'value']); + var node = this._text(args.parent, 'textPath', args.value, args.settings || {}); + node.setAttributeNS($.svg.xlinkNS, 'href', args.path); + return node; + }, + + /* Draw text. */ + _text: function(parent, name, value, settings) { + var node = this._makeNode(parent, name, settings); + if (typeof value == 'string') { + node.appendChild(node.ownerDocument.createTextNode(value)); + } + else { + for (var i = 0; i < value._parts.length; i++) { + var part = value._parts[i]; + if (part[0] == 'tspan') { + var child = this._makeNode(node, part[0], part[2]); + child.appendChild(node.ownerDocument.createTextNode(part[1])); + node.appendChild(child); + } + else if (part[0] == 'tref') { + var child = this._makeNode(node, part[0], part[2]); + child.setAttributeNS($.svg.xlinkNS, 'href', part[1]); + node.appendChild(child); + } + else if (part[0] == 'textpath') { + var set = $.extend({}, part[2]); + set.href = null; + var child = this._makeNode(node, part[0], set); + child.setAttributeNS($.svg.xlinkNS, 'href', part[2].href); + child.appendChild(node.ownerDocument.createTextNode(part[1])); + node.appendChild(child); + } + else { // straight text + node.appendChild(node.ownerDocument.createTextNode(part[1])); + } + } + } + return node; + }, + + /* Add a custom SVG element. + @param parent (element or jQuery) the parent node for the new element (optional) + @param name (string) the name of the element + @param settings (object) additional settings for the element (optional) + @return (element) the new custom node */ + other: function(parent, name, settings) { + var args = this._args(arguments, ['name']); + return this._makeNode(args.parent, args.name, args.settings || {}); + }, + + /* Create a shape node with the given settings. */ + _makeNode: function(parent, name, settings) { + parent = parent || this._svg; + var node = this._svg.ownerDocument.createElementNS($.svg.svgNS, name); + for (var name in settings) { + var value = settings[name]; + if (value != null && value != null && + (typeof value != 'string' || value != '')) { + node.setAttribute($.svg._attrNames[name] || name, value); + } + } + parent.appendChild(node); + return node; + }, + + /* Add an existing SVG node to the diagram. + @param parent (element or jQuery) the parent node for the new node (optional) + @param node (element) the new node to add or + (string) the jQuery selector for the node or + (jQuery collection) set of nodes to add + @return (SVGWrapper) this wrapper */ + add: function(parent, node) { + var args = this._args((arguments.length == 1 ? [null, parent] : arguments), ['node']); + var svg = this; + args.parent = args.parent || this._svg; + args.node = (args.node.jquery ? args.node : $(args.node)); + try { + if ($.svg._renesis) { + throw 'Force traversal'; + } + args.parent.appendChild(args.node.cloneNode(true)); + } + catch (e) { + args.node.each(function() { + var child = svg._cloneAsSVG(this); + if (child) { + args.parent.appendChild(child); + } + }); + } + return this; + }, + + /* Clone an existing SVG node and add it to the diagram. + @param parent (element or jQuery) the parent node for the new node (optional) + @param node (element) the new node to add or + (string) the jQuery selector for the node or + (jQuery collection) set of nodes to add + @return (element[]) collection of new nodes */ + clone: function(parent, node) { + var svg = this; + var args = this._args((arguments.length == 1 ? [null, parent] : arguments), ['node']); + args.parent = args.parent || this._svg; + args.node = (args.node.jquery ? args.node : $(args.node)); + var newNodes = []; + args.node.each(function() { + var child = svg._cloneAsSVG(this); + if (child) { + child.id = ''; + args.parent.appendChild(child); + newNodes.push(child); + } + }); + return newNodes; + }, + + /* SVG nodes must belong to the SVG namespace, so clone and ensure this is so. + @param node (element) the SVG node to clone + @return (element) the cloned node */ + _cloneAsSVG: function(node) { + var newNode = null; + if (node.nodeType == 1) { // element + newNode = this._svg.ownerDocument.createElementNS( + $.svg.svgNS, this._checkName(node.nodeName)); + for (var i = 0; i < node.attributes.length; i++) { + var attr = node.attributes.item(i); + if (attr.nodeName != 'xmlns' && attr.nodeValue) { + if (attr.prefix == 'xlink') { + newNode.setAttributeNS($.svg.xlinkNS, + attr.localName || attr.baseName, attr.nodeValue); + } + else { + newNode.setAttribute(this._checkName(attr.nodeName), attr.nodeValue); + } + } + } + for (var i = 0; i < node.childNodes.length; i++) { + var child = this._cloneAsSVG(node.childNodes[i]); + if (child) { + newNode.appendChild(child); + } + } + } + else if (node.nodeType == 3) { // text + if ($.trim(node.nodeValue)) { + newNode = this._svg.ownerDocument.createTextNode(node.nodeValue); + } + } + else if (node.nodeType == 4) { // CDATA + if ($.trim(node.nodeValue)) { + try { + newNode = this._svg.ownerDocument.createCDATASection(node.nodeValue); + } + catch (e) { + newNode = this._svg.ownerDocument.createTextNode( + node.nodeValue.replace(/&/g, '&'). + replace(//g, '>')); + } + } + } + return newNode; + }, + + /* Node names must be lower case and without SVG namespace prefix. */ + _checkName: function(name) { + name = (name.substring(0, 1) >= 'A' && name.substring(0, 1) <= 'Z' ? + name.toLowerCase() : name); + return (name.substring(0, 4) == 'svg:' ? name.substring(4) : name); + }, + + /* Load an external SVG document. + @param url (string) the location of the SVG document or + the actual SVG content + @param settings (boolean) see addTo below or + (function) see onLoad below or + (object) additional settings for the load with attributes below: + addTo (boolean) true to add to what's already there, + or false to clear the canvas first + changeSize (boolean) true to allow the canvas size to change, + or false to retain the original + onLoad (function) callback after the document has loaded, + 'this' is the container, receives SVG object and + optional error message as a parameter + parent (string or element or jQuery) the parent to load + into, defaults to top-level svg element + @return (SVGWrapper) this root */ + load: function(url, settings) { + settings = (typeof settings == 'boolean' ? {addTo: settings} : + (typeof settings == 'function' ? {onLoad: settings} : + (typeof settings == 'string' ? {parent: settings} : + (typeof settings == 'object' && settings.nodeName ? {parent: settings} : + (typeof settings == 'object' && settings.jquery ? {parent: settings} : + settings || {}))))); + if (!settings.parent && !settings.addTo) { + this.clear(false); + } + var size = [this._svg.getAttribute('width'), this._svg.getAttribute('height')]; + var wrapper = this; + // Report a problem with the load + var reportError = function(message) { + message = $.svg.local.errorLoadingText + ': ' + message; + if (settings.onLoad) { + settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper, message]); + } + else { + wrapper.text(null, 10, 20, message); + } + }; + // Create a DOM from SVG content + var loadXML4IE = function(data) { + var xml = new ActiveXObject('Microsoft.XMLDOM'); + xml.validateOnParse = false; + xml.resolveExternals = false; + xml.async = false; + xml.loadXML(data); + if (xml.parseError.errorCode != 0) { + reportError(xml.parseError.reason); + return null; + } + return xml; + }; + // Load the SVG DOM + var loadSVG = function(data) { + if (!data) { + return; + } + if (data.documentElement.nodeName != 'svg') { + var errors = data.getElementsByTagName('parsererror'); + var messages = (errors.length ? errors[0].getElementsByTagName('div') : []); // Safari + reportError(!errors.length ? '???' : + (messages.length ? messages[0] : errors[0]).firstChild.nodeValue); + return; + } + var parent = (settings.parent ? $(settings.parent)[0] : wrapper._svg); + var attrs = {}; + for (var i = 0; i < data.documentElement.attributes.length; i++) { + var attr = data.documentElement.attributes.item(i); + if (!(attr.nodeName == 'version' || attr.nodeName.substring(0, 5) == 'xmlns')) { + attrs[attr.nodeName] = attr.nodeValue; + } + } + wrapper.configure(parent, attrs, !settings.parent); + var nodes = data.documentElement.childNodes; + for (var i = 0; i < nodes.length; i++) { + try { + if ($.svg._renesis) { + throw 'Force traversal'; + } + parent.appendChild(wrapper._svg.ownerDocument.importNode(nodes[i], true)); + if (nodes[i].nodeName == 'script') { + $.globalEval(nodes[i].textContent); + } + } + catch (e) { + wrapper.add(parent, nodes[i]); + } + } + if (!settings.changeSize) { + wrapper.configure(parent, {width: size[0], height: size[1]}); + } + if (settings.onLoad) { + settings.onLoad.apply(wrapper._container || wrapper._svg, [wrapper]); + } + }; + if (url.match(''; + } + else { // Element + svgDoc = '<' + node.nodeName; + if (node.attributes) { + for (var i = 0; i < node.attributes.length; i++) { + var attr = node.attributes.item(i); + if (!($.trim(attr.nodeValue) == '' || attr.nodeValue.match(/^\[object/) || + attr.nodeValue.match(/^function/))) { + svgDoc += ' ' + (attr.namespaceURI == $.svg.xlinkNS ? 'xlink:' : '') + + attr.nodeName + '="' + attr.nodeValue + '"'; + } + } + } + if (node.firstChild) { + svgDoc += '>'; + var child = node.firstChild; + while (child) { + svgDoc += this._toSVG(child); + child = child.nextSibling; + } + svgDoc += ''; + } + else { + svgDoc += '/>'; + } + } + return svgDoc; + } +}); + +/* Helper to generate an SVG path. + Obtain an instance from the SVGWrapper object. + String calls together to generate the path and use its value: + var path = root.createPath(); + root.path(null, path.move(100, 100).line(300, 100).line(200, 300).close(), {fill: 'red'}); + or + root.path(null, path.move(100, 100).line([[300, 100], [200, 300]]).close(), {fill: 'red'}); */ +function SVGPath() { + this._path = ''; +} + +$.extend(SVGPath.prototype, { + /* Prepare to create a new path. + @return (SVGPath) this path */ + reset: function() { + this._path = ''; + return this; + }, + + /* Move the pointer to a position. + @param x (number) x-coordinate to move to or + (number[][]) x-/y-coordinates to move to + @param y (number) y-coordinate to move to (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + move: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 'm' : 'M'), x, y); + }, + + /* Draw a line to a position. + @param x (number) x-coordinate to move to or + (number[][]) x-/y-coordinates to move to + @param y (number) y-coordinate to move to (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + line: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 'l' : 'L'), x, y); + }, + + /* Draw a horizontal line to a position. + @param x (number) x-coordinate to draw to or + (number[]) x-coordinates to draw to + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + horiz: function(x, relative) { + this._path += (relative ? 'h' : 'H') + (isArray(x) ? x.join(' ') : x); + return this; + }, + + /* Draw a vertical line to a position. + @param y (number) y-coordinate to draw to or + (number[]) y-coordinates to draw to + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + vert: function(y, relative) { + this._path += (relative ? 'v' : 'V') + (isArray(y) ? y.join(' ') : y); + return this; + }, + + /* Draw a cubic Bézier curve. + @param x1 (number) x-coordinate of beginning control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y1 (number) y-coordinate of beginning control point (omitted if x1 is array) + @param x2 (number) x-coordinate of ending control point (omitted if x1 is array) + @param y2 (number) y-coordinate of ending control point (omitted if x1 is array) + @param x (number) x-coordinate of curve end (omitted if x1 is array) + @param y (number) y-coordinate of curve end (omitted if x1 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + curveC: function(x1, y1, x2, y2, x, y, relative) { + relative = (isArray(x1) ? y1 : relative); + return this._coords((relative ? 'c' : 'C'), x1, y1, x2, y2, x, y); + }, + + /* Continue a cubic Bézier curve. + Starting control point is the reflection of the previous end control point. + @param x2 (number) x-coordinate of ending control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y2 (number) y-coordinate of ending control point (omitted if x2 is array) + @param x (number) x-coordinate of curve end (omitted if x2 is array) + @param y (number) y-coordinate of curve end (omitted if x2 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + smoothC: function(x2, y2, x, y, relative) { + relative = (isArray(x2) ? y2 : relative); + return this._coords((relative ? 's' : 'S'), x2, y2, x, y); + }, + + /* Draw a quadratic Bézier curve. + @param x1 (number) x-coordinate of control point or + (number[][]) x-/y-coordinates of control and end points to draw to + @param y1 (number) y-coordinate of control point (omitted if x1 is array) + @param x (number) x-coordinate of curve end (omitted if x1 is array) + @param y (number) y-coordinate of curve end (omitted if x1 is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + curveQ: function(x1, y1, x, y, relative) { + relative = (isArray(x1) ? y1 : relative); + return this._coords((relative ? 'q' : 'Q'), x1, y1, x, y); + }, + + /* Continue a quadratic Bézier curve. + Control point is the reflection of the previous control point. + @param x (number) x-coordinate of curve end or + (number[][]) x-/y-coordinates of points to draw to + @param y (number) y-coordinate of curve end (omitted if x is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + smoothQ: function(x, y, relative) { + relative = (isArray(x) ? y : relative); + return this._coords((relative ? 't' : 'T'), x, y); + }, + + /* Generate a path command with (a list of) coordinates. */ + _coords: function(cmd, x1, y1, x2, y2, x3, y3) { + if (isArray(x1)) { + for (var i = 0; i < x1.length; i++) { + var cs = x1[i]; + this._path += (i == 0 ? cmd : ' ') + cs[0] + ',' + cs[1] + + (cs.length < 4 ? '' : ' ' + cs[2] + ',' + cs[3] + + (cs.length < 6 ? '': ' ' + cs[4] + ',' + cs[5])); + } + } + else { + this._path += cmd + x1 + ',' + y1 + + (x2 == null ? '' : ' ' + x2 + ',' + y2 + + (x3 == null ? '' : ' ' + x3 + ',' + y3)); + } + return this; + }, + + /* Draw an arc to a position. + @param rx (number) x-radius of arc or + (number/boolean[][]) x-/y-coordinates and flags for points to draw to + @param ry (number) y-radius of arc (omitted if rx is array) + @param xRotate (number) x-axis rotation (degrees, clockwise) (omitted if rx is array) + @param large (boolean) true to draw the large part of the arc, + false to draw the small part (omitted if rx is array) + @param clockwise (boolean) true to draw the clockwise arc, + false to draw the anti-clockwise arc (omitted if rx is array) + @param x (number) x-coordinate of arc end (omitted if rx is array) + @param y (number) y-coordinate of arc end (omitted if rx is array) + @param relative (boolean) true for coordinates relative to the current point, + false for coordinates being absolute + @return (SVGPath) this path */ + arc: function(rx, ry, xRotate, large, clockwise, x, y, relative) { + relative = (isArray(rx) ? ry : relative); + this._path += (relative ? 'a' : 'A'); + if (isArray(rx)) { + for (var i = 0; i < rx.length; i++) { + var cs = rx[i]; + this._path += (i == 0 ? '' : ' ') + cs[0] + ',' + cs[1] + ' ' + + cs[2] + ' ' + (cs[3] ? '1' : '0') + ',' + + (cs[4] ? '1' : '0') + ' ' + cs[5] + ',' + cs[6]; + } + } + else { + this._path += rx + ',' + ry + ' ' + xRotate + ' ' + + (large ? '1' : '0') + ',' + (clockwise ? '1' : '0') + ' ' + x + ',' + y; + } + return this; + }, + + /* Close the current path. + @return (SVGPath) this path */ + close: function() { + this._path += 'z'; + return this; + }, + + /* Return the string rendering of the specified path. + @return (string) stringified path */ + path: function() { + return this._path; + } +}); + +SVGPath.prototype.moveTo = SVGPath.prototype.move; +SVGPath.prototype.lineTo = SVGPath.prototype.line; +SVGPath.prototype.horizTo = SVGPath.prototype.horiz; +SVGPath.prototype.vertTo = SVGPath.prototype.vert; +SVGPath.prototype.curveCTo = SVGPath.prototype.curveC; +SVGPath.prototype.smoothCTo = SVGPath.prototype.smoothC; +SVGPath.prototype.curveQTo = SVGPath.prototype.curveQ; +SVGPath.prototype.smoothQTo = SVGPath.prototype.smoothQ; +SVGPath.prototype.arcTo = SVGPath.prototype.arc; + +/* Helper to generate an SVG text object. + Obtain an instance from the SVGWrapper object. + String calls together to generate the text and use its value: + var text = root.createText(); + root.text(null, x, y, text.string('This is '). + span('red', {fill: 'red'}).string('!'), {fill: 'blue'}); */ +function SVGText() { + this._parts = []; // The components of the text object +} + +$.extend(SVGText.prototype, { + /* Prepare to create a new text object. + @return (SVGText) this text */ + reset: function() { + this._parts = []; + return this; + }, + + /* Add a straight string value. + @param value (string) the actual text + @return (SVGText) this text object */ + string: function(value) { + this._parts[this._parts.length] = ['text', value]; + return this; + }, + + /* Add a separate text span that has its own settings. + @param value (string) the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + span: function(value, settings) { + this._parts[this._parts.length] = ['tspan', value, settings]; + return this; + }, + + /* Add a reference to a previously defined text string. + @param id (string) the ID of the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + ref: function(id, settings) { + this._parts[this._parts.length] = ['tref', id, settings]; + return this; + }, + + /* Add text drawn along a path. + @param id (string) the ID of the path + @param value (string) the actual text + @param settings (object) the settings for this text + @return (SVGText) this text object */ + path: function(id, value, settings) { + this._parts[this._parts.length] = ['textpath', value, + $.extend({href: id}, settings || {})]; + return this; + } +}); + +/* Attach the SVG functionality to a jQuery selection. + @param command (string) the command to run (optional, default 'attach') + @param options (object) the new settings to use for these SVG instances + @return jQuery (object) for chaining further calls */ +$.fn.svg = function(options) { + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && options == 'get') { + return $.svg['_' + options + 'SVG'].apply($.svg, [this[0]].concat(otherArgs)); + } + return this.each(function() { + if (typeof options == 'string') { + $.svg['_' + options + 'SVG'].apply($.svg, [this].concat(otherArgs)); + } + else { + $.svg._attachSVG(this, options || {}); + } + }); +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && a.constructor == Array); +} + +// Singleton primary SVG interface +$.svg = new SVGManager(); + +})(jQuery); diff --git a/static/jquery.ui.accordion.js b/static/jquery.ui.accordion.js new file mode 100755 index 000000000..55bbecba5 --- /dev/null +++ b/static/jquery.ui.accordion.js @@ -0,0 +1,731 @@ +/*! + * jQuery UI Accordion 1.9.2 + * http://jqueryui.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/accordion/ + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function( $, undefined ) { + +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.9.2", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid), + options = this.options; + + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ); + + this.headers = this.element.find( options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + this._hoverable( this.headers ); + this._focusable( this.headers ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .hide(); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active" ) + .toggleClass( "ui-corner-all ui-corner-top" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this._createIcons(); + this.refresh(); + + // ARIA + this.element.attr( "role", "tablist" ); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._on( this.headers, { keydown: "_keydown" }); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._setupEvents( options.event ); + }, + + _getCreateEventData: function() { + return { + header: this.active, + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var maxHeight, overflow, + heightStyle = this.options.heightStyle, + parent = this.element.parent(); + + + if ( heightStyle === "fill" ) { + // IE 6 treats height like minHeight, so we need to turn off overflow + // in order to get a reliable height + // we use the minHeight support test because we assume that only + // browsers that don't support minHeight will treat height as minHeight + if ( !$.support.minHeight ) { + overflow = parent.css( "overflow" ); + parent.css( "overflow", "hidden"); + } + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + if ( overflow ) { + parent.css( "overflow", overflow ); + } + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = {}; + if ( !event ) { + return; + } + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + this._on( this.headers, events ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + + this._trigger( "activate", null, data ); + } +}); + + + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // navigation options + (function( $, prototype ) { + $.extend( prototype.options, { + navigation: false, + navigationFilter: function() { + return this.href.toLowerCase() === location.href.toLowerCase(); + } + }); + + var _create = prototype._create; + prototype._create = function() { + if ( this.options.navigation ) { + var that = this, + headers = this.element.find( this.options.header ), + content = headers.next(), + current = headers.add( content ) + .find( "a" ) + .filter( this.options.navigationFilter ) + [ 0 ]; + if ( current ) { + headers.add( content ).each( function( index ) { + if ( $.contains( this, current ) ) { + that.options.active = Math.floor( index / 2 ); + return false; + } + }); + } + } + _create.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // height options + (function( $, prototype ) { + $.extend( prototype.options, { + heightStyle: null, // remove default so we fall back to old values + autoHeight: true, // use heightStyle: "auto" + clearStyle: false, // use heightStyle: "content" + fillSpace: false // use heightStyle: "fill" + }); + + var _create = prototype._create, + _setOption = prototype._setOption; + + $.extend( prototype, { + _create: function() { + this.options.heightStyle = this.options.heightStyle || + this._mergeHeightStyle(); + + _create.call( this ); + }, + + _setOption: function( key ) { + if ( key === "autoHeight" || key === "clearStyle" || key === "fillSpace" ) { + this.options.heightStyle = this._mergeHeightStyle(); + } + _setOption.apply( this, arguments ); + }, + + _mergeHeightStyle: function() { + var options = this.options; + + if ( options.fillSpace ) { + return "fill"; + } + + if ( options.clearStyle ) { + return "content"; + } + + if ( options.autoHeight ) { + return "auto"; + } + } + }); + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // icon options + (function( $, prototype ) { + $.extend( prototype.options.icons, { + activeHeader: null, // remove default so we fall back to old values + headerSelected: "ui-icon-triangle-1-s" + }); + + var _createIcons = prototype._createIcons; + prototype._createIcons = function() { + if ( this.options.icons ) { + this.options.icons.activeHeader = this.options.icons.activeHeader || + this.options.icons.headerSelected; + } + _createIcons.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // expanded active option, activate method + (function( $, prototype ) { + prototype.activate = prototype._activate; + + var _findActive = prototype._findActive; + prototype._findActive = function( index ) { + if ( index === -1 ) { + index = false; + } + if ( index && typeof index !== "number" ) { + index = this.headers.index( this.headers.filter( index ) ); + if ( index === -1 ) { + index = false; + } + } + return _findActive.call( this, index ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // resize method + jQuery.ui.accordion.prototype.resize = jQuery.ui.accordion.prototype.refresh; + + // change events + (function( $, prototype ) { + $.extend( prototype.options, { + change: null, + changestart: null + }); + + var _trigger = prototype._trigger; + prototype._trigger = function( type, event, data ) { + var ret = _trigger.apply( this, arguments ); + if ( !ret ) { + return false; + } + + if ( type === "beforeActivate" ) { + ret = _trigger.call( this, "changestart", event, { + oldHeader: data.oldHeader, + oldContent: data.oldPanel, + newHeader: data.newHeader, + newContent: data.newPanel + }); + } else if ( type === "activate" ) { + ret = _trigger.call( this, "change", event, { + oldHeader: data.oldHeader, + oldContent: data.oldPanel, + newHeader: data.newHeader, + newContent: data.newPanel + }); + } + return ret; + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); + + // animated option + // NOTE: this only provides support for "slide", "bounceslide", and easings + // not the full $.ui.accordion.animations API + (function( $, prototype ) { + $.extend( prototype.options, { + animate: null, + animated: "slide" + }); + + var _create = prototype._create; + prototype._create = function() { + var options = this.options; + if ( options.animate === null ) { + if ( !options.animated ) { + options.animate = false; + } else if ( options.animated === "slide" ) { + options.animate = 300; + } else if ( options.animated === "bounceslide" ) { + options.animate = { + duration: 200, + down: { + easing: "easeOutBounce", + duration: 1000 + } + }; + } else { + options.animate = options.animated; + } + } + + _create.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); +} + +})( jQuery ); -- 2.11.4.GIT