/** * SVG-edit Utilities * * Licensed under the Apache License, Version 2 * * Copyright(c) 2010 Alexis Deveria * Copyright(c) 2010 Jeff Schiller */ // Dependencies: // 1) jQuery (function() { if (!window.svgedit) { window.svgedit = {}; } if (!svgedit.Utilities) { svgedit.Utilities = {}; } // Constants // String used to encode base64. var KEYSTR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var XLINKNS = "http://www.w3.org/1999/xlink"; // Function: svgedit.Utilities.toXml // Converts characters in a string to XML-friendly entities. // // Example: "&" becomes "&" // // Parameters: // str - The string to be converted // // Returns: // The converted string svgedit.Utilities.toXml = function(str) { return $('

').text(str).html(); }; // Function: svgedit.Utilities.fromXml // Converts XML entities in a string to single characters. // Example: "&" becomes "&" // // Parameters: // str - The string to be converted // // Returns: // The converted string svgedit.Utilities.fromXml = function(str) { return $('

').html(str).text(); }; // This code was written by Tyler Akins and has been placed in the // public domain. It would be nice if you left this header intact. // Base64 code from Tyler Akins -- http://rumkin.com // schiller: Removed string concatenation in favour of Array.join() optimization, // also precalculate the size of the array needed. // Function: svgedit.Utilities.encode64 // Converts a string to base64 svgedit.Utilities.encode64 = function(input) { // base64 strings are 4/3 larger than the original string // input = svgedit.Utilities.encodeUTF8(input); // convert non-ASCII characters input = svgedit.Utilities.convertToXMLReferences(input); if(window.btoa) return window.btoa(input); // Use native if available var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0, p = 0; do { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output[p++] = KEYSTR.charAt(enc1); output[p++] = KEYSTR.charAt(enc2); output[p++] = KEYSTR.charAt(enc3); output[p++] = KEYSTR.charAt(enc4); } while (i < input.length); return output.join(''); }; // Function: svgedit.Utilities.decode64 // Converts a string from base64 svgedit.Utilities.decode64 = function(input) { if(window.atob) return window.atob(input); var output = ""; var chr1, chr2, chr3 = ""; var enc1, enc2, enc3, enc4 = ""; var i = 0; // remove all characters that are not A-Z, a-z, 0-9, +, /, or = input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); do { enc1 = KEYSTR.indexOf(input.charAt(i++)); enc2 = KEYSTR.indexOf(input.charAt(i++)); enc3 = KEYSTR.indexOf(input.charAt(i++)); enc4 = KEYSTR.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } chr1 = chr2 = chr3 = ""; enc1 = enc2 = enc3 = enc4 = ""; } while (i < input.length); return unescape(output); }; // Currently not being used, so commented out for now // based on http://phpjs.org/functions/utf8_encode:577 // codedread:does not seem to work with webkit-based browsers on OSX // "encodeUTF8": function(input) { // //return unescape(encodeURIComponent(input)); //may or may not work // var output = ''; // for (var n = 0; n < input.length; n++){ // var c = input.charCodeAt(n); // if (c < 128) { // output += input[n]; // } // else if (c > 127) { // if (c < 2048){ // output += String.fromCharCode((c >> 6) | 192); // } // else { // output += String.fromCharCode((c >> 12) | 224) + String.fromCharCode((c >> 6) & 63 | 128); // } // output += String.fromCharCode((c & 63) | 128); // } // } // return output; // }, // Function: svgedit.Utilities.convertToXMLReferences // Converts a string to use XML references svgedit.Utilities.convertToXMLReferences = function(input) { var output = ''; for (var n = 0; n < input.length; n++){ var c = input.charCodeAt(n); if (c < 128) { output += input[n]; } else if(c > 127) { output += ("&#" + c + ";"); } } return output; }; // Function: rectsIntersect // Check if two rectangles (BBoxes objects) intersect each other // // Paramaters: // r1 - The first BBox-like object // r2 - The second BBox-like object // // Returns: // Boolean that's true if rectangles intersect svgedit.Utilities.rectsIntersect = function(r1, r2) { return r2.x < (r1.x+r1.width) && (r2.x+r2.width) > r1.x && r2.y < (r1.y+r1.height) && (r2.y+r2.height) > r1.y; }; // Function: text2xml // Cross-browser compatible method of converting a string to an XML tree // found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f svgedit.Utilities.text2xml = function(sXML) { if(sXML.indexOf('= 0) { sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns'); } var out; try{ var dXML = (window.DOMParser)?new DOMParser():new ActiveXObject("Microsoft.XMLDOM"); dXML.async = false; } catch(e){ throw new Error("XML Parser could not be instantiated"); }; try{ if(dXML.loadXML) out = (dXML.loadXML(sXML))?dXML:false; else out = dXML.parseFromString(sXML, "text/xml"); } catch(e){ throw new Error("Error parsing XML string"); }; return out; }; // Function: bboxToObj // Converts a SVGRect into an object. // // Parameters: // bbox - a SVGRect // // Returns: // An object with properties names x, y, width, height. svgedit.Utilities.bboxToObj = function(bbox) { return { x: bbox.x, y: bbox.y, width: bbox.width, height: bbox.height } }; // Function: walkTree // Walks the tree and executes the callback on each element in a top-down fashion // // Parameters: // elem - DOM element to traverse // cbFn - Callback function to run on each element svgedit.Utilities.walkTree = function(elem, cbFn){ if (elem && elem.nodeType == 1) { cbFn(elem); var i = elem.childNodes.length; while (i--) { svgedit.Utilities.walkTree(elem.childNodes.item(i), cbFn); } } }; // Function: walkTreePost // Walks the tree and executes the callback on each element in a depth-first fashion // TODO: FIXME: Shouldn't this be calling walkTreePost? // // Parameters: // elem - DOM element to traverse // cbFn - Callback function to run on each element svgedit.Utilities.walkTreePost = function(elem, cbFn) { if (elem && elem.nodeType == 1) { var i = elem.childNodes.length; while (i--) { svgedit.Utilities.walkTree(elem.childNodes.item(i), cbFn); } cbFn(elem); } }; // Function: svgedit.Utilities.getUrlFromAttr // Extracts the URL from the url(...) syntax of some attributes. // Three variants: // * // * // * // // Parameters: // attrVal - The attribute value as a string // // Returns: // String with just the URL, like someFile.svg#foo svgedit.Utilities.getUrlFromAttr = function(attrVal) { if (attrVal) { // url("#somegrad") if (attrVal.indexOf('url("') === 0) { return attrVal.substring(5,attrVal.indexOf('"',6)); } // url('#somegrad') else if (attrVal.indexOf("url('") === 0) { return attrVal.substring(5,attrVal.indexOf("'",6)); } else if (attrVal.indexOf("url(") === 0) { return attrVal.substring(4,attrVal.indexOf(')')); } } return null; }; // Function: svgedit.Utilities.getHref // Returns the given element's xlink:href value svgedit.Utilities.getHref = function(elem) { return elem.getAttributeNS(XLINKNS, "href"); } // Function: svgedit.Utilities.setHref // Sets the given element's xlink:href value svgedit.Utilities.setHref = function(elem, val) { elem.setAttributeNS(XLINKNS, "xlink:href", val); } // Function: findDefs // Parameters: // svgElement - The element. // // Returns: // The document's element, create it first if necessary svgedit.Utilities.findDefs = function(svgElement) { var svgElement = svgDoc.documentElement; var defs = svgElement.getElementsByTagNameNS(svgns, "defs"); if (defs.length > 0) { defs = defs[0]; } else { // first child is a comment, so call nextSibling defs = svgElement.insertBefore( svgElement.ownerDocument.createElementNS(svgns, "defs" ), svgElement.firstChild.nextSibling); } return defs; }; })();