History

Add classList polyfill for IE, which doesn't support it on SVG elements

Thibaut Courouble committed 9 years ago

Commit 0e134da1 parent 30dd32c2 files · +240 −1Browse files

Unified · Split

2 files
  1. assets/javascripts/app/app.coffee +0 −1
  2. assets/javascripts/vendor/classlist.js +240 −0
assets/javascripts/app/app.coffee+0−1
@@ -250,7 +250,6 @@ · 249 unmodified lines
250250 bind: !!Function::bind
251251 pushState: !!history.pushState
252252 matchMedia: !!window.matchMedia
253− classList: !!document.body.classList
254253 insertAdjacentHTML: !!document.body.insertAdjacentHTML
255254 defaultPrevented: document.createEvent('CustomEvent').defaultPrevented is false
256255 cssGradients: supportsCssGradients()
assets/javascripts/vendor/classlist.js+240−0
@@ -0,0 +1,240 @@
1+/*
2+ * classList.js: Cross-browser full element.classList implementation.
3+ * 1.1.20170427
4+ *
5+ * By Eli Grey, http://eligrey.com
6+ * License: Dedicated to the public domain.
7+ * See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
8+ */
9+
10+/*global self, document, DOMException */
11+
12+/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
13+
14+if ("document" in self) {
15+
16+// Full polyfill for browsers with no classList support
17+// Including IE < Edge missing SVGElement.classList
18+if (!("classList" in document.createElement("_"))
19+ || document.createElementNS && !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g"))) {
20+
21+(function (view) {
22+
23+"use strict";
24+
25+if (!('Element' in view)) return;
26+
27+var
28+ classListProp = "classList"
29+ , protoProp = "prototype"
30+ , elemCtrProto = view.Element[protoProp]
31+ , objCtr = Object
32+ , strTrim = String[protoProp].trim || function () {
33+ return this.replace(/^\s+|\s+$/g, "");
34+ }
35+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
36+ var
37+ i = 0
38+ , len = this.length
39+ ;
40+ for (; i < len; i++) {
41+ if (i in this && this[i] === item) {
42+ return i;
43+ }
44+ }
45+ return -1;
46+ }
47+ // Vendors: please allow content code to instantiate DOMExceptions
48+ , DOMEx = function (type, message) {
49+ this.name = type;
50+ this.code = DOMException[type];
51+ this.message = message;
52+ }
53+ , checkTokenAndGetIndex = function (classList, token) {
54+ if (token === "") {
55+ throw new DOMEx(
56+ "SYNTAX_ERR"
57+ , "An invalid or illegal string was specified"
58+ );
59+ }
60+ if (/\s/.test(token)) {
61+ throw new DOMEx(
62+ "INVALID_CHARACTER_ERR"
63+ , "String contains an invalid character"
64+ );
65+ }
66+ return arrIndexOf.call(classList, token);
67+ }
68+ , ClassList = function (elem) {
69+ var
70+ trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
71+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
72+ , i = 0
73+ , len = classes.length
74+ ;
75+ for (; i < len; i++) {
76+ this.push(classes[i]);
77+ }
78+ this._updateClassName = function () {
79+ elem.setAttribute("class", this.toString());
80+ };
81+ }
82+ , classListProto = ClassList[protoProp] = []
83+ , classListGetter = function () {
84+ return new ClassList(this);
85+ }
86+;
87+// Most DOMException implementations don't allow calling DOMException's toString()
88+// on non-DOMExceptions. Error's toString() is sufficient here.
89+DOMEx[protoProp] = Error[protoProp];
90+classListProto.item = function (i) {
91+ return this[i] || null;
92+};
93+classListProto.contains = function (token) {
94+ token += "";
95+ return checkTokenAndGetIndex(this, token) !== -1;
96+};
97+classListProto.add = function () {
98+ var
99+ tokens = arguments
100+ , i = 0
101+ , l = tokens.length
102+ , token
103+ , updated = false
104+ ;
105+ do {
106+ token = tokens[i] + "";
107+ if (checkTokenAndGetIndex(this, token) === -1) {
108+ this.push(token);
109+ updated = true;
110+ }
111+ }
112+ while (++i < l);
113+
114+ if (updated) {
115+ this._updateClassName();
116+ }
117+};
118+classListProto.remove = function () {
119+ var
120+ tokens = arguments
121+ , i = 0
122+ , l = tokens.length
123+ , token
124+ , updated = false
125+ , index
126+ ;
127+ do {
128+ token = tokens[i] + "";
129+ index = checkTokenAndGetIndex(this, token);
130+ while (index !== -1) {
131+ this.splice(index, 1);
132+ updated = true;
133+ index = checkTokenAndGetIndex(this, token);
134+ }
135+ }
136+ while (++i < l);
137+
138+ if (updated) {
139+ this._updateClassName();
140+ }
141+};
142+classListProto.toggle = function (token, force) {
143+ token += "";
144+
145+ var
146+ result = this.contains(token)
147+ , method = result ?
148+ force !== true && "remove"
149+ :
150+ force !== false && "add"
151+ ;
152+
153+ if (method) {
154+ this[method](token);
155+ }
156+
157+ if (force === true || force === false) {
158+ return force;
159+ } else {
160+ return !result;
161+ }
162+};
163+classListProto.toString = function () {
164+ return this.join(" ");
165+};
166+
167+if (objCtr.defineProperty) {
168+ var classListPropDesc = {
169+ get: classListGetter
170+ , enumerable: true
171+ , configurable: true
172+ };
173+ try {
174+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
175+ } catch (ex) { // IE 8 doesn't support enumerable:true
176+ // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
177+ // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
178+ if (ex.number === undefined || ex.number === -0x7FF5EC54) {
179+ classListPropDesc.enumerable = false;
180+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
181+ }
182+ }
183+} else if (objCtr[protoProp].__defineGetter__) {
184+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
185+}
186+
187+}(self));
188+
189+}
190+
191+// There is full or partial native classList support, so just check if we need
192+// to normalize the add/remove and toggle APIs.
193+
194+(function () {
195+ "use strict";
196+
197+ var testElement = document.createElement("_");
198+
199+ testElement.classList.add("c1", "c2");
200+
201+ // Polyfill for IE 10/11 and Firefox <26, where classList.add and
202+ // classList.remove exist but support only one argument at a time.
203+ if (!testElement.classList.contains("c2")) {
204+ var createMethod = function(method) {
205+ var original = DOMTokenList.prototype[method];
206+
207+ DOMTokenList.prototype[method] = function(token) {
208+ var i, len = arguments.length;
209+
210+ for (i = 0; i < len; i++) {
211+ token = arguments[i];
212+ original.call(this, token);
213+ }
214+ };
215+ };
216+ createMethod('add');
217+ createMethod('remove');
218+ }
219+
220+ testElement.classList.toggle("c3", false);
221+
222+ // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
223+ // support the second argument.
224+ if (testElement.classList.contains("c3")) {
225+ var _toggle = DOMTokenList.prototype.toggle;
226+
227+ DOMTokenList.prototype.toggle = function(token, force) {
228+ if (1 in arguments && !this.contains(token) === !force) {
229+ return force;
230+ } else {
231+ return _toggle.call(this, token);
232+ }
233+ };
234+
235+ }
236+
237+ testElement = null;
238+}());
239+
240+}