This repository has been archived by the owner on Dec 8, 2017. It is now read-only.
forked from jonathantneal/svg4everybody
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsvg4everybody.js
215 lines (170 loc) · 5.8 KB
/
svg4everybody.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*! svg4everybody v2.1.0 | github.com/jonathantneal/svg4everybody */
function embed(node, target) {
// if the target exists
if (target) {
// create a document fragment to hold the contents of the target
var fragment = document.createDocumentFragment();
var svg = getSVGAncestor(node);
// cache the closest matching viewBox
var viewBox = !svg.hasAttribute('viewBox') && target.getAttribute('viewBox');
// conditionally set the viewBox on the svg
if (viewBox) {
svg.setAttribute('viewBox', viewBox);
}
// clone the target
var clone = target.cloneNode(true);
// copy the contents of the clone into the fragment
while (clone.childNodes.length) {
fragment.appendChild(clone.firstChild);
}
// append the fragment into the svg
node.appendChild(fragment);
}
}
function loadreadystatechange(xhr) {
// listen to changes in the request
xhr.onreadystatechange = function () {
// if the request is ready
if (xhr.readyState === 4) {
// get the cached html document
var cachedDocument = xhr._cachedDocument;
// ensure the cached html document based on the xhr response
if (!cachedDocument) {
cachedDocument = xhr._cachedDocument = document.implementation.createHTMLDocument('');
cachedDocument.body.innerHTML = xhr.responseText;
xhr._cachedTarget = {};
}
// clear the xhr embeds list and embed each item
xhr._embeds.splice(0).map(function (item) {
// get the cached target
var target = xhr._cachedTarget[item.id];
// ensure the cached target
if (!target) {
target = xhr._cachedTarget[item.id] = cachedDocument.getElementById(item.id);
}
// embed the target into the svg
embed(item.node, target);
});
}
};
// test the ready state change immediately
xhr.onreadystatechange();
}
function svg4everybody(rawopts) {
var opts = Object(rawopts);
// create legacy support variables
var nosvg;
var fallback;
// if running with legacy support
if (LEGACY_SUPPORT) {
// configure the fallback method
fallback = opts.fallback || function (src) {
return src.replace(/\?[^#]+/, '').replace('#', '.').replace(/^\./, '') + '.png' + (/\?[^#]+/.exec(src) || [''])[0];
};
// set whether to shiv <svg> and <use> elements and use image fallbacks
nosvg = 'nosvg' in opts ? opts.nosvg : /\bMSIE [1-8]\b/.test(navigator.userAgent);
// conditionally shiv <svg> and <use>
if (nosvg) {
document.createElement('svg');
document.createElement('use');
}
}
// set whether the polyfill will be activated or not
var polyfill;
var olderIEUA = /\bMSIE [1-8]\.0\b/;
var newerIEUA = /\bTrident\/[567]\b|\bMSIE (?:9|10)\.0\b/;
var webkitUA = /\bAppleWebKit\/(\d+)\b/;
var olderEdgeUA = /\bEdge\/12\.(\d+)\b/;
if ('polyfill' in opts) {
polyfill = opts.polyfill;
} else if (LEGACY_SUPPORT) {
polyfill = olderIEUA.test(navigator.userAgent) || newerIEUA.test(navigator.userAgent) || (navigator.userAgent.match(olderEdgeUA) || [])[1] < 10547 || (navigator.userAgent.match(webkitUA) || [])[1] < 537;
} else {
polyfill = newerIEUA.test(navigator.userAgent) || (navigator.userAgent.match(olderEdgeUA) || [])[1] < 10547 || (navigator.userAgent.match(webkitUA) || [])[1] < 537;
}
// create xhr requests object
var requests = {};
// use request animation frame or a timeout to search the dom for svgs
var requestAnimationFrame = window.requestAnimationFrame || setTimeout;
// get a live collection of use elements on the page
var uses = document.getElementsByTagName('use');
function oninterval() {
// get the cached <use> index
var index = 0;
// while the index exists in the live <use> collection
while (index < uses.length) {
// get the current <use>
var use = uses[index];
// get the current <svg>
var parent = use.parentNode;
var svg = getSVGAncestor(parent);
if (svg) {
var src = use.getAttribute('xlink:href');
// if running with legacy support
if (LEGACY_SUPPORT && nosvg) {
// create a new fallback image
var img = document.createElement('img');
// force display in older IE
img.style.cssText = 'display:inline-block;height:100%;width:100%';
// set the fallback size using the svg size
img.setAttribute('width', svg.getAttribute('width') || svg.clientWidth);
img.setAttribute('height', svg.getAttribute('height') || svg.clientHeight);
// set the fallback src
img.src = fallback(src, svg, use);
// replace the <use> with the fallback image
parent.replaceChild(img, use);
} else if (polyfill) {
if (!opts.validate || opts.validate(src, svg, use)) {
// remove the <use> element
parent.removeChild(use);
// parse the src and get the url and id
var srcSplit = src.split('#');
var url = srcSplit.shift();
var id = srcSplit.join('#');
// if the link is external
if (url.length) {
// get the cached xhr request
var xhr = requests[url];
// ensure the xhr request exists
if (!xhr) {
xhr = requests[url] = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr._embeds = [];
}
// add the svg and id as an item to the xhr embeds list
xhr._embeds.push({
node: parent,
id: id
});
// prepare the xhr ready state change event
loadreadystatechange(xhr);
} else {
// embed the local id into the svg
embed(parent, document.getElementById(id));
}
}
}
} else {
// increase the index when the previous value was not "valid"
++index;
}
}
// continue the interval
requestAnimationFrame(oninterval, 67);
}
// conditionally start the interval if the polyfill is active
if (polyfill) {
oninterval();
}
}
function getSVGAncestor(node) {
var svg = node;
while (svg.nodeName.toLowerCase() !== 'svg') {
svg = svg.parentNode;
if (!svg) {
break;
}
}
return svg;
}