/* http://keith-wood.name/svg.html jQuery DOM compatibility for jQuery SVG v1.5.0. Written by Keith Wood (kbwood{at}iinet.com.au) April 2009. Available under the MIT (http://keith-wood.name/licence.html) license. Please attribute the author if you use it. */ (function($) { // Hide scope, no $ conflict var rclass = /[\t\r\n]/g, rspace = /\s+/, rwhitespace = "[\\x20\\t\\r\\n\\f]"; /** Retrieve the element classes. @private @param elem {Element} The element to examine. @return {string} The class names. */ function getClassNames(elem) { return (!$.svg.isSVGElem(elem) ? elem.className : (elem.className ? elem.className.baseVal : elem.getAttribute('class'))) || ''; } /** Set the element classes. @private @param elem {Element} The element to update. @param classes {string} The new class names. */ function setClassNames(elem, classes) { (elem.className ? elem.className.baseVal = classes : elem.setAttribute('class', classes)); } /** Support adding class names to SVG nodes. @param classNames {string} The classes to add. */ $.fn.addClass = function(origAddClass) { return function(classNames) { if ($.isFunction(classNames)) { return this.each(function(i) { $(this).addClass(classNames.call(this, i, getClassNames(this))); }); } var origArgs = arguments; classNames = classNames || ''; return this.each(function() { if ($.svg.isSVGElem(this)) { var node = this; $.each(classNames.split(/\s+/), function(i, className) { var classes = getClassNames(node); if ($.inArray(className, classes.split(/\s+/)) === -1) { setClassNames(node, classes += (classes ? ' ' : '') + className); } }); } else { origAddClass.apply($(this), origArgs); } }); }; }($.fn.addClass); /** Support removing class names from SVG nodes. @param classNames {string} The classes to remove. */ $.fn.removeClass = function(origRemoveClass) { return function(classNames) { if ($.isFunction(classNames)) { return this.each(function(i) { $(this).removeClass(classNames.call(this, i, getClassNames(this))); }); } var origArgs = arguments; classNames = classNames || ''; return this.each(function() { if ($.svg.isSVGElem(this)) { var node = this; $.each(classNames.split(/\s+/), function(i, className) { var classes = getClassNames(node); classes = $.grep(classes.split(/\s+/), function(n, i) { return n !== className; }).join(' '); setClassNames(node, classes); }); } else { origRemoveClass.apply($(this), origArgs); } }); }; }($.fn.removeClass); /** Support toggling class names on SVG nodes. @param classNames {string} The classes to toggle. */ $.fn.toggleClass = function(origToggleClass) { return function(classNames, state) { if ($.isFunction(classNames)) { return this.each(function(i) { $(this).toggleClass(classNames.call(this, i, getClassNames(this), state), state); }); } var origArgs = arguments; var hasState = (typeof state === 'boolean'); return this.each(function() { if ($.svg.isSVGElem(this)) { if (typeof classNames === 'string') { var node = $(this); $.each(classNames.split(/\s+/), function(i, className) { if (!hasState) { state = !node.hasClass(className); } node[(state ? 'add' : 'remove') + 'Class'](className); }); } else { var classes = getClassNames(this); if (classes) { $._data(this, '__className__', classes); // store className if set } // toggle whole className setClassNames(this, classes || classNames === false ? '' : $._data(this, '__className__') || ''); } } else { origToggleClass.apply($(this), origArgs); } }); }; }($.fn.toggleClass); /** Support checking class names on SVG nodes. @param className {string} The class to check. @return {boolean} true if this class is present, false if not. */ $.fn.hasClass = function(origHasClass) { return function(className) { className = className || ''; var found = false; this.each(function() { if ($.svg.isSVGElem(this)) { found = ($.inArray(className, getClassNames(this).split(/\s+/)) > -1); } else { found = (origHasClass.apply($(this), [className])); } return !found; }); return found; }; }($.fn.hasClass); /** Support attributes on SVG nodes. @param name {string} The attribute name. @param [value] {any} The new attribute value. @param type {boolean} Internal flag. @return {any} If an attribute value is requested. */ $.fn.attr = function(origAttr) { return function(name, value, type) { if (typeof name === 'string' && value === undefined) { // Return attribute value var val = origAttr.apply(this, arguments); if (val && val.baseVal && val.baseVal.numberOfItems != null) { // Multiple values value = ''; val = val.baseVal; if (name === 'transform') { for (var i = 0; i < val.numberOfItems; i++) { var item = val.getItem(i); switch (item.type) { case 1: value += ' matrix(' + item.matrix.a + ',' + item.matrix.b + ',' + item.matrix.c + ',' + item.matrix.d + ',' + item.matrix.e + ',' + item.matrix.f + ')'; break; case 2: value += ' translate(' + item.matrix.e + ',' + item.matrix.f + ')'; break; case 3: value += ' scale(' + item.matrix.a + ',' + item.matrix.d + ')'; break; case 4: value += ' rotate(' + item.angle + ')'; break; // Doesn't handle new origin case 5: value += ' skewX(' + item.angle + ')'; break; case 6: value += ' skewY(' + item.angle + ')'; break; } } val = value.substring(1); } else { val = val.getItem(0).valueAsString; } } return (val && val.baseVal ? val.baseVal.valueAsString : val); } var options = name; if (typeof name === 'string') { options = {}; options[name] = value; } if ($.isFunction(value)) { return $(this).each(function(i) { $(this).attr(name, value.call(this, i, $(this).attr(name))); }); } var origArgs = arguments; return $(this).each(function() { if ($.svg.isSVGElem(this)) { for (var n in options) { (type ? this.style[n] = options[n] : this.setAttribute(n, options[n])); } } else { origAttr.apply($(this), origArgs); } }); }; }($.fn.attr); /** Support removing attributes on SVG nodes. @param names {string} The names of the attributes to remove. */ $.fn.removeAttr = function(origRemoveAttr) { return function(names) { var origArgs = arguments; return this.each(function() { if ($.svg.isSVGElem(this)) { var node = this; $.each(names.split(/\s+/), function(i, name) { (node[name] && node[name].baseVal ? node[name].baseVal.value = null : node.removeAttribute(name)); }); } else { origRemoveAttr.apply($(this), origArgs); } }); }; }($.fn.removeAttr); /* Add numeric only properties. */ $.extend($.cssNumber, { 'stopOpacity': true, 'strokeMitrelimit': true, 'strokeOpacity': true }); /* Support retrieving CSS/attribute values on SVG nodes. */ if ($.cssProps) { $.css = function(origCSS) { return function(elem, name, numeric, extra) { var value = (name.match(/^svg.*/) ? $(elem).attr($.cssProps[name] || name) : ''); return value || origCSS(elem, name, numeric, extra); }; }($.css); } })(jQuery);