OLD | NEW |
(Empty) | |
| 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, classListProp
Desc); |
| 175 } catch (ex) { // IE 8 doesn't support enumerable:true |
| 176 // adding undefined to fight this issue https://github.com/eligr
ey/classList.js/issues/36 |
| 177 // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affec
ted |
| 178 if (ex.number === undefined || ex.number === -0x7FF5EC54) { |
| 179 classListPropDesc.enumerable = false; |
| 180 objCtr.defineProperty(elemCtrProto, classListProp, class
ListPropDesc); |
| 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 } |
OLD | NEW |