OLD | NEW |
(Empty) | |
| 1 /*! |
| 2 * classList.js: Cross-browser full element.classList implementation. |
| 3 * 1.2.201711092 |
| 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 ( |
| 19 !("classList" in document.createElement("_")) |
| 20 || document.createElementNS |
| 21 && !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g
")) |
| 22 ) { |
| 23 |
| 24 (function (view) { |
| 25 |
| 26 "use strict"; |
| 27 |
| 28 if (!('Element' in view)) return; |
| 29 |
| 30 var |
| 31 classListProp = "classList" |
| 32 , protoProp = "prototype" |
| 33 , elemCtrProto = view.Element[protoProp] |
| 34 , objCtr = Object |
| 35 , strTrim = String[protoProp].trim || function () { |
| 36 return this.replace(/^\s+|\s+$/g, ""); |
| 37 } |
| 38 , arrIndexOf = Array[protoProp].indexOf || function (item) { |
| 39 var |
| 40 i = 0 |
| 41 , len = this.length |
| 42 ; |
| 43 for (; i < len; i++) { |
| 44 if (i in this && this[i] === item) { |
| 45 return i; |
| 46 } |
| 47 } |
| 48 return -1; |
| 49 } |
| 50 // Vendors: please allow content code to instantiate DOMExceptions |
| 51 , DOMEx = function (type, message) { |
| 52 this.name = type; |
| 53 this.code = DOMException[type]; |
| 54 this.message = message; |
| 55 } |
| 56 , checkTokenAndGetIndex = function (classList, token) { |
| 57 if (token === "") { |
| 58 throw new DOMEx( |
| 59 "SYNTAX_ERR" |
| 60 , "The token must not be empty." |
| 61 ); |
| 62 } |
| 63 if (/\s/.test(token)) { |
| 64 throw new DOMEx( |
| 65 "INVALID_CHARACTER_ERR" |
| 66 , "The token must not contain space characters." |
| 67 ); |
| 68 } |
| 69 return arrIndexOf.call(classList, token); |
| 70 } |
| 71 , ClassList = function (elem) { |
| 72 var |
| 73 trimmedClasses = strTrim.call(elem.getAttribute("class") || "") |
| 74 , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] |
| 75 , i = 0 |
| 76 , len = classes.length |
| 77 ; |
| 78 for (; i < len; i++) { |
| 79 this.push(classes[i]); |
| 80 } |
| 81 this._updateClassName = function () { |
| 82 elem.setAttribute("class", this.toString()); |
| 83 }; |
| 84 } |
| 85 , classListProto = ClassList[protoProp] = [] |
| 86 , classListGetter = function () { |
| 87 return new ClassList(this); |
| 88 } |
| 89 ; |
| 90 // Most DOMException implementations don't allow calling DOMException's toStri
ng() |
| 91 // on non-DOMExceptions. Error's toString() is sufficient here. |
| 92 DOMEx[protoProp] = Error[protoProp]; |
| 93 classListProto.item = function (i) { |
| 94 return this[i] || null; |
| 95 }; |
| 96 classListProto.contains = function (token) { |
| 97 return !~checkTokenAndGetIndex(this, token + ""); |
| 98 }; |
| 99 classListProto.add = function () { |
| 100 var |
| 101 tokens = arguments |
| 102 , i = 0 |
| 103 , l = tokens.length |
| 104 , token |
| 105 , updated = false |
| 106 ; |
| 107 do { |
| 108 token = tokens[i] + ""; |
| 109 if (~checkTokenAndGetIndex(this, token)) { |
| 110 this.push(token); |
| 111 updated = true; |
| 112 } |
| 113 } |
| 114 while (++i < l); |
| 115 |
| 116 if (updated) { |
| 117 this._updateClassName(); |
| 118 } |
| 119 }; |
| 120 classListProto.remove = function () { |
| 121 var |
| 122 tokens = arguments |
| 123 , i = 0 |
| 124 , l = tokens.length |
| 125 , token |
| 126 , updated = false |
| 127 , index |
| 128 ; |
| 129 do { |
| 130 token = tokens[i] + ""; |
| 131 index = checkTokenAndGetIndex(this, token); |
| 132 while (~index) { |
| 133 this.splice(index, 1); |
| 134 updated = true; |
| 135 index = checkTokenAndGetIndex(this, token); |
| 136 } |
| 137 } |
| 138 while (++i < l); |
| 139 |
| 140 if (updated) { |
| 141 this._updateClassName(); |
| 142 } |
| 143 }; |
| 144 classListProto.toggle = function (token, force) { |
| 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.replace = function (token, replacement_token) { |
| 164 var index = checkTokenAndGetIndex(token + ""); |
| 165 if (~index) { |
| 166 this.splice(index, 1, replacement_token); |
| 167 this._updateClassName(); |
| 168 } |
| 169 } |
| 170 classListProto.toString = function () { |
| 171 return this.join(" "); |
| 172 }; |
| 173 |
| 174 if (objCtr.defineProperty) { |
| 175 var classListPropDesc = { |
| 176 get: classListGetter |
| 177 , enumerable: true |
| 178 , configurable: true |
| 179 }; |
| 180 try { |
| 181 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); |
| 182 } catch (ex) { // IE 8 doesn't support enumerable:true |
| 183 // adding undefined to fight this issue https://github.com/eligrey/classLi
st.js/issues/36 |
| 184 // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected |
| 185 if (ex.number === undefined || ex.number === -0x7FF5EC54) { |
| 186 classListPropDesc.enumerable = false; |
| 187 objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); |
| 188 } |
| 189 } |
| 190 } else if (objCtr[protoProp].__defineGetter__) { |
| 191 elemCtrProto.__defineGetter__(classListProp, classListGetter); |
| 192 } |
| 193 |
| 194 }(self)); |
| 195 |
| 196 } |
| 197 |
| 198 // There is full or partial native classList support, so just check if we need |
| 199 // to normalize the add/remove and toggle APIs. |
| 200 |
| 201 (function () { |
| 202 "use strict"; |
| 203 |
| 204 var testElement = document.createElement("_"); |
| 205 |
| 206 testElement.classList.add("c1", "c2"); |
| 207 |
| 208 // Polyfill for IE 10/11 and Firefox <26, where classList.add and |
| 209 // classList.remove exist but support only one argument at a time. |
| 210 if (!testElement.classList.contains("c2")) { |
| 211 var createMethod = function(method) { |
| 212 var original = DOMTokenList.prototype[method]; |
| 213 |
| 214 DOMTokenList.prototype[method] = function(token) { |
| 215 var i, len = arguments.length; |
| 216 |
| 217 for (i = 0; i < len; i++) { |
| 218 token = arguments[i]; |
| 219 original.call(this, token); |
| 220 } |
| 221 }; |
| 222 }; |
| 223 createMethod('add'); |
| 224 createMethod('remove'); |
| 225 } |
| 226 |
| 227 testElement.classList.toggle("c3", false); |
| 228 |
| 229 // Polyfill for IE 10 and Firefox <24, where classList.toggle does not |
| 230 // support the second argument. |
| 231 if (testElement.classList.contains("c3")) { |
| 232 var _toggle = DOMTokenList.prototype.toggle; |
| 233 |
| 234 DOMTokenList.prototype.toggle = function(token, force) { |
| 235 if (1 in arguments && !this.contains(token) === !force) { |
| 236 return force; |
| 237 } else { |
| 238 return _toggle.call(this, token); |
| 239 } |
| 240 }; |
| 241 |
| 242 } |
| 243 |
| 244 // replace() polyfill |
| 245 if (!("replace" in document.createElement("_").classList)) { |
| 246 DOMTokenList.prototype.replace = function (token, replacement_token) { |
| 247 var |
| 248 tokens = this.toString().split(" ") |
| 249 , index = tokens.indexOf(token + "") |
| 250 ; |
| 251 if (~index) { |
| 252 tokens = tokens.slice(index); |
| 253 this.remove.apply(this, tokens); |
| 254 this.add(replacement_token); |
| 255 this.add.apply(this, tokens.slice(1)); |
| 256 } |
| 257 } |
| 258 } |
| 259 |
| 260 testElement = null; |
| 261 }()); |
| 262 |
| 263 } |
OLD | NEW |