Created
January 4, 2010 21:34
-
-
Save antimatter15/268884 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//this file hacked to be svg-edit only and work with JSONP | |
/* | |
* SVG Icon Loader 2.0 | |
* | |
* jQuery Plugin for loading SVG icons from a single file | |
* | |
* Copyright (c) 2009 Alexis Deveria | |
* http://a.deveria.com | |
* | |
* Apache 2 License | |
*/ | |
(function($) { | |
var svg_icons = {}; | |
$.svgIcons = function(file, opts) { | |
var svgns = "http://www.w3.org/2000/svg", | |
xlinkns = "http://www.w3.org/1999/xlink", | |
icon_w = opts.w?opts.w : 24, | |
icon_h = opts.h?opts.h : 24, | |
elems, svgdoc, testImg, | |
icons_made = false, data_loaded = false, load_attempts = 0, | |
ua = navigator.userAgent, isOpera = !!window.opera, isSafari = (ua.indexOf('Safari/') > -1 && ua.indexOf('Chrome/')==-1), | |
data_pre = 'data:image/svg+xml;charset=utf-8;base64,'; | |
if(opts.svgz) { | |
var data_el = $('<object data="' + file + '" type=image/svg+xml>').appendTo('body').hide(); | |
try { | |
svgdoc = data_el[0].contentDocument; | |
// TODO: IE still loads this, shouldn't even bother. | |
data_el.load(getIcons); | |
getIcons(0, true); // Opera will not run "load" event if file is already cached | |
} catch(err1) { | |
useFallback(); | |
} | |
} else { | |
$.ajax({ | |
url: "http://anti15.welfarehost.com/svgeditproxy.php?whoot=?", | |
dataType: 'jsonp', | |
success: function(data) { | |
if (window.DOMParser) | |
{ | |
parser=new DOMParser(); | |
xmlDoc=parser.parseFromString(data,"text/xml"); | |
} | |
else // Internet Explorer | |
{ | |
xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); | |
xmlDoc.async="false"; | |
xmlDoc.loadXML(data); | |
} | |
svgdoc = xmlDoc; | |
$(function() { | |
getIcons('ajax'); | |
}); | |
}, | |
error: function() { | |
$(function() { | |
useFallback(); | |
}); | |
} | |
}); | |
} | |
function getIcons(evt, no_wait) { | |
if(evt !== 'ajax') { | |
if(data_loaded) return; | |
// Webkit sometimes says svgdoc is undefined, other times | |
// it fails to load all nodes. Thus we must make sure the "eof" | |
// element is loaded. | |
svgdoc = data_el[0].contentDocument; // Needed again for Webkit | |
var isReady = (svgdoc && svgdoc.getElementById('svg_eof')); | |
if(!isReady && !(no_wait && isReady)) { | |
load_attempts++; | |
if(load_attempts < 50) { | |
setTimeout(getIcons, 20); | |
} else { | |
useFallback(); | |
data_loaded = true; | |
} | |
return; | |
} | |
data_loaded = true; | |
} | |
// Clean source SVGs (mostly for Inkscape files) | |
// TODO: Find a way to do this without crashing Safari (when converting to IMG) | |
$(svgdoc).find('metadata').remove().end() | |
.find('*').each(function(i, el) { | |
if(el.nodeName.indexOf(':') != -1) { | |
$(el).remove(); | |
} | |
var attrs = $.extend(false, el.attributes, {}); | |
for(i in attrs) { | |
var attr = attrs[i]; | |
var fullattr = attr.prefix?attr.prefix + ':' + attr.localName:''; | |
if(attr.prefix) { | |
el.removeAttribute(attr.localName); // for Opera | |
el.removeAttribute(fullattr); // for Webkit | |
} | |
if(fullattr == 'xlink:href') { | |
el.setAttribute('xlink:href', attr.nodeValue); | |
} | |
} | |
}); | |
elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent'); | |
var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; | |
testImg = $(new Image()).attr({ | |
src: testSrc, | |
width: 0, | |
height: 0 | |
}).appendTo('body') | |
.load(function () { | |
// Safari 4 crashes, Opera and Chrome don't | |
makeIcons(!isSafari); | |
}).error(function () { | |
makeIcons(); | |
}); | |
} | |
function makeIcons(toImage, fallback) { | |
if(icons_made) return; | |
if(opts.no_img) toImage = false; | |
var holder; | |
var setIcon = function(target, icon, id, setID) { | |
if(isOpera) icon.css('visibility','hidden'); | |
if(opts.replace) { | |
if(setID) icon.attr('id',id); | |
var cl = target.attr('class'); | |
if(cl) icon.attr('class','svg_icon '+cl); | |
target.replaceWith(icon); | |
} else { | |
target.append(icon); | |
} | |
if(isOpera) { | |
setTimeout(function() { | |
icon.attr('style','visibility:visible;'); | |
},1); | |
} | |
} | |
var addIcon = function(icon, id) { | |
if(opts.id_match === undefined || opts.id_match !== false) { | |
setIcon(holder, icon, id, true); | |
} | |
svg_icons[id] = icon; | |
} | |
if(toImage) { | |
var temp_holder = $(document.createElement('div')); | |
temp_holder.hide().appendTo('body'); | |
} | |
if(fallback) { | |
var path = opts.fallback_path?opts.fallback_path:''; | |
$.each(fallback, function(id, imgsrc) { | |
holder = $('#' + id); | |
var icon = $(new Image()) | |
.attr({ | |
'class':'svg_icon', | |
src: path + imgsrc, | |
'width': icon_w, | |
'height': icon_h, | |
'alt': 'icon' | |
}); | |
addIcon(icon, id); | |
}); | |
} else { | |
$.each(elems, function(i, elem) { | |
var id = elem.getAttribute('id'); | |
if(id == 'svg_eof') return; | |
holder = $('#' + id); | |
var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; | |
var svgroot = svgdoc.createElementNS(svgns, "svg"); | |
svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' ')); | |
$(svgroot).attr({ | |
"xmlns": svgns, | |
"width": icon_w, | |
"height": icon_h, | |
"xmlns:xlink": xlinkns, | |
"class": 'svg_icon' | |
}); | |
// Without cloning, Firefox will make another GET request. | |
// With cloning, causes issue in Opera/Win/Non-EN | |
if(!isOpera) svg = svg.cloneNode(true); | |
svgroot.appendChild(svg); | |
if(toImage) { | |
// Without cloning, Safari will crash | |
// With cloning, causes issue in Opera/Win/Non-EN | |
var svgcontent = isOpera?svgroot:svgroot.cloneNode(true); | |
temp_holder.empty().append(svgroot); | |
var str = data_pre + encode64(temp_holder.html()); | |
var icon = $(new Image()) | |
.attr({'class':'svg_icon', src:str}); | |
} else { | |
var icon = fixIDs($(svgroot), i); | |
} | |
addIcon(icon, id); | |
}); | |
} | |
if(opts.placement) { | |
$.each(opts.placement, function(sel, id) { | |
if(!svg_icons[id]) return; | |
$(sel).each(function(i) { | |
var copy = svg_icons[id].clone(); | |
if(i > 0 && !toImage) copy = fixIDs(copy, i, true); | |
setIcon($(this), copy, id); | |
}) | |
}); | |
} | |
if(!fallback) { | |
if(toImage) temp_holder.remove(); | |
if(data_el) data_el.remove(); | |
testImg.remove(); | |
} | |
if(opts.resize) $.resizeSvgIcons(opts.resize); | |
icons_made = true; | |
if(opts.callback) opts.callback(svg_icons); | |
} | |
function fixIDs(svg_el, svg_num, force) { | |
var defs = svg_el.find('defs'); | |
if(!defs.length) return svg_el; | |
defs.find('[id]').each(function(i) { | |
var id = this.id; | |
var no_dupes = ($(svgdoc).find('#' + id).length <= 1); | |
if(isOpera) no_dupes = false; // Opera didn't clone svg_el, so not reliable | |
if(!force && no_dupes) return; | |
var new_id = id + svg_num + i; | |
$(this).attr('id', new_id); | |
svg_el.find('[fill="url(#' + id + ')"]').each(function() { | |
$(this).attr('fill', 'url(#' + new_id + ')'); | |
}).end().find('[stroke="url(#' + id + ')"]').each(function() { | |
$(this).attr('stroke', 'url(#' + new_id + ')'); | |
}).end().find('use').each(function() { | |
if(this.getAttribute('xlink:href') == '#' + id) { | |
this.setAttributeNS(xlinkns,'href','#' + new_id); | |
} | |
}); | |
}); | |
return svg_el; | |
} | |
function useFallback() { | |
if(file.indexOf('.svgz') != -1) { | |
var reg_file = file.replace('.svgz','.svg'); | |
if(window.console) { | |
console.log('.svgz failed, trying with .svg'); | |
} | |
$.svgIcons(reg_file, opts); | |
} else if(opts.fallback) { | |
makeIcons(false, opts.fallback); | |
} | |
} | |
function encode64(input) { | |
// base64 strings are 4/3 larger than the original string | |
if(window.btoa) return window.btoa(input); | |
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
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(''); | |
} | |
} | |
$.getSvgIcon = function(id) { return svg_icons[id]; } | |
$.resizeSvgIcons = function(obj) { | |
// FF2 and older don't detect .svg_icon, so we change it detect svg elems instead | |
var change_sel = !$('.svg_icon:first').length; | |
$.each(obj, function(sel, size) { | |
var arr = $.isArray(size); | |
var w = arr?size[0]:size, | |
h = arr?size[1]:size; | |
if(change_sel) { | |
sel = sel.replace(/\.svg_icon/g,'svg'); | |
} | |
$(sel).each(function() { | |
this.setAttribute('width', w); | |
this.setAttribute('height', h); | |
}); | |
}); | |
} | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment