├── LICENSE ├── src ├── batcher.js ├── watcher.js ├── vm.js ├── compile.js ├── directive.js ├── observer.js ├── es5-sham.js └── es5-shim.js ├── README.md └── index.html /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 wcflmy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/batcher.js: -------------------------------------------------------------------------------- 1 | var nextTick = (function () { 2 | var callbacks = [] 3 | var pending = false 4 | var timerFunc 5 | function nextTickHandler() { 6 | pending = false 7 | var copies = callbacks.slice(0) 8 | callbacks = [] 9 | for (var i = 0; i < copies.length; i++) { 10 | copies[i]() 11 | } 12 | } 13 | if (typeof MutationObserver !== 'undefined') { 14 | var counter = 1 15 | var observer = new MutationObserver(nextTickHandler) 16 | var textNode = document.createTextNode(counter) 17 | observer.observe(textNode, { 18 | characterData: true 19 | }) 20 | timerFunc = function () { 21 | counter = (counter + 1) % 2 22 | textNode.data = counter 23 | } 24 | } else { 25 | timerFunc = setTimeout 26 | } 27 | return function (cb, ctx) { 28 | var func = ctx 29 | ? function () { cb.call(ctx) } 30 | : cb 31 | callbacks.push(func) 32 | if (pending) return 33 | pending = true 34 | timerFunc(nextTickHandler, 0) 35 | } 36 | })() 37 | 38 | var batcher = (function() { 39 | var queue = [] 40 | var waiting = false 41 | 42 | function resetBatcherState() { 43 | queue = [] 44 | waiting = false 45 | } 46 | 47 | function flushBatcherQueue() { 48 | runBatcherQueue() 49 | resetBatcherState() 50 | } 51 | 52 | function runBatcherQueue() { 53 | for(var i=0; i 15 |
{{text}}
16 |
17 |
18 | {{model}} 19 |
I have a className of {{class}}
20 |
I have a bule color.
21 |
Click me!
22 |
{{say.hello}}{{message}}
23 |
I have a attribute of data-message
24 |
I am a computed value:{{hello}}
25 | 26 | 64 | ``` 65 | 66 | This is a library for learning vue, so DONOT use it in your production environment. 67 | 68 | ## Supported Features 69 | - reactive two-way data binding. 70 | - computed property. 71 | - directives: v-text, v-html, v-model, v-show, v-bind, v-on, v-if/v-else, v-for. 72 | - IE8 supported. 73 | 74 | ## Limitations 75 | Object.defineProperty only works on Dom object in IE8, javascript objects are replaced with Dom objects to support data binding, so you cannot use built-in Dom properties such as style, attributes in data property. 76 | ```javascript 77 | new VM({ 78 | el: '#app', 79 | data: { 80 | style: 'display:none', // it will cause error in IE8, and has no effect in Chrome 81 | obj: { 82 | attributes: 'attributes' // just don't use like this, please give another property name 83 | } 84 | } 85 | }) 86 | ``` 87 | 88 | 89 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | VM4IE8 6 | 7 | 8 |
9 |
Just input 'vm.ifShow=false' in console
10 |
11 |
{{text}}
12 |
13 |
14 | 15 | {{model}} 16 |
17 | I have a className of 18 | {{class}} 19 |
20 |
I have a bule color.
21 |
Click me!
22 |
23 | {{say.hello}} 24 | {{message}} 25 |
26 |
I have a attribute of data-message
27 |
28 | I am a computed value:{{hello}} 29 |
30 |
    31 |
  • 32 |
      33 |
    • {{i}}
    • 34 |
    35 |
  • 36 |
37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/compile.js: -------------------------------------------------------------------------------- 1 | var bindRE = /^v-bind:|^:/ 2 | var onRE = /^v-on:|^@/ 3 | var argRE = /:(.*)$/ 4 | 5 | function Compile(el, vm) { 6 | this.$vm = vm 7 | this.$el = el 8 | if (this.$el) { 9 | this.compile(this.$el) 10 | } 11 | } 12 | 13 | Compile.prototype.compile = function(node) { 14 | this.compileNode(node) 15 | if (node.childNodes && node.childNodes.length) { 16 | this.compileNodeList(node.childNodes) 17 | } 18 | } 19 | 20 | Compile.prototype.compileNode = function(node) { 21 | var type = node.nodeType 22 | if (type === 1 && node.tagName !== 'SCRIPT') { 23 | this.compileElementNode(node) 24 | } else if (type === 3 && node.data.trim()) { 25 | this.compileTextNode(node) 26 | } 27 | } 28 | 29 | Compile.prototype.compileNodeList = function(childNodes) { 30 | var self = this 31 | 32 | ;[].slice.call(childNodes).forEach(function (node) { 33 | self.compile(node) 34 | }) 35 | } 36 | 37 | Compile.prototype.compileElementNode = function(node) { 38 | var nodeAttrs = node.attributes, 39 | self = this 40 | 41 | ;[].slice.call(nodeAttrs).forEach(function (attr) { 42 | var name, rawName, dirName, arg, value 43 | 44 | name = rawName = attr.name 45 | value = attr.value 46 | 47 | // event handlers 48 | if (onRE.test(name)) { 49 | dirName = 'on' 50 | arg = name.replace(onRE, '') 51 | } else 52 | 53 | // attribute bindings 54 | if (bindRE.test(name)) { 55 | dirName = name.replace(bindRE, '') 56 | if (!dirName !== 'style' && dirName !== 'class') { 57 | arg = dirName 58 | dirName = 'bind' 59 | } 60 | } else 61 | 62 | // normal directives 63 | if (name.indexOf('v-') === 0) { 64 | // check arg 65 | arg = (arg = name.match(argRE)) && arg[1] 66 | if (arg) { 67 | name = name.replace(argRE, '') 68 | } 69 | // extract directive name 70 | dirName = name.slice(2) 71 | } 72 | 73 | if (dirName) { 74 | var directive = new Directive({ 75 | name: dirName, 76 | arg: arg, 77 | attr: rawName, 78 | expression: value 79 | }, self.$vm, node) 80 | self.$vm._directives.push(directive) 81 | directive._bind() 82 | } 83 | }) 84 | } 85 | 86 | Compile.prototype.compileTextNode = function(node) { 87 | var text = node.data.trim() 88 | var reg = /\{\{(.*)\}\}/ 89 | 90 | if (reg.test(text)) { 91 | var directive = new Directive({ 92 | name: 'text', 93 | expression: text.match(reg)[1] 94 | }, this.$vm, node) 95 | this.$vm._directives.push(directive) 96 | directive._bind() 97 | } 98 | } 99 | 100 | Compile.transclude = function (el, options) { 101 | function nodeToFragment(node) { 102 | // script template 103 | if (node.tagName === 'SCRIPT') { 104 | return stringToFragment(node.textContent) 105 | } 106 | var frag = document.createDocumentFragment() 107 | var child 108 | while (child = clone.firstChild) { 109 | frag.appendChild(child) 110 | } 111 | return frag 112 | } 113 | 114 | function stringToFragment(string) { 115 | var frag = document.createDocumentFragment() 116 | var node = document.createElement('div') 117 | node.innerHTML = string 118 | var child 119 | while (child = node.firstChild) { 120 | frag.appendChild(child) 121 | } 122 | return frag 123 | } 124 | 125 | if (options && options.template) { 126 | var template = options.template 127 | var frag 128 | if (typeof template === 'string') { 129 | if (template.charAt(0) === '#') { 130 | var node = document.getElementById(template.slice(1)) 131 | if (node) { 132 | frag = nodeToFragment(node) 133 | } 134 | } else { 135 | frag = stringToFragment(template) 136 | } 137 | } else if (template.nodeType) { 138 | frag = nodeToFragment(template) 139 | } 140 | el.appendChild(frag) 141 | } 142 | return el 143 | } 144 | -------------------------------------------------------------------------------- /src/directive.js: -------------------------------------------------------------------------------- 1 | function Directive(descriptor, vm, el) { 2 | this.vm = vm 3 | this.el = el 4 | this.descriptor = descriptor 5 | this._locked = false 6 | } 7 | 8 | Directive.prototype._bind = function() { 9 | var self = this 10 | 11 | if(this.el.removeAttribute) { 12 | this.el.removeAttribute(this.descriptor.attr || 'v-' + this.descriptor.name) 13 | } 14 | 15 | var def = Directive[this.descriptor.name] || {} 16 | // extend bind, update functions to the instance of Directive for fixing `this` 17 | for(var i in def) { 18 | this[i] = def[i] 19 | } 20 | 21 | if(this.bind) { 22 | this.bind() 23 | } 24 | 25 | if(this.update) { 26 | this._update = function(val, oldVal) { 27 | if(!self._locked) { 28 | self.update(val, oldVal) 29 | } 30 | } 31 | } else { 32 | this._update = function() {} 33 | } 34 | 35 | var watcher = this._watcher = new Watcher(this.vm, this.descriptor.expression, this._update, { 36 | process: this.process 37 | }) 38 | if(this.update) { 39 | this.update(watcher.value) 40 | } 41 | } 42 | 43 | // directives 44 | Directive.text = { 45 | update: function(val) { 46 | val = typeof val == 'undefined' ? '' : val 47 | if(this.el.nodeType == 3) { 48 | this.el.data = val // for {{text}} 49 | } else { // for 50 | this.el.textContent = val 51 | this.el.innerText = val // for IE8 52 | } 53 | } 54 | } 55 | 56 | Directive.html = { 57 | update: function(val) { 58 | this.el.innerHTML = typeof val == 'undefined' ? '' : val 59 | } 60 | } 61 | 62 | Directive.model = { 63 | bind: function() { 64 | var self = this 65 | 66 | // for IE8 67 | this.el.addEventListener('propertychange', function (e) { 68 | self._watcher.set(self.el.value) 69 | }) 70 | 71 | this.el.addEventListener('input', function(e) { 72 | self._watcher.set(self.el.value) 73 | }) 74 | }, 75 | update: function(val) { 76 | this.el.value = typeof val == 'undefined' ? '' : val 77 | } 78 | } 79 | 80 | Directive.show = { 81 | update: function(val) { 82 | this.el.style.display = val ? 'block' : 'none' 83 | } 84 | } 85 | 86 | Directive['class'] = { 87 | update: function(val, oldVal) { 88 | var className = this.el.className 89 | className = className.replace(oldVal, '').replace(/\s$/, '') 90 | var space = className && String(val) ? ' ' : '' 91 | this.el.className = className + space + val 92 | } 93 | } 94 | 95 | Directive.style = { 96 | update: function(val) { 97 | this.el.style.cssText = val 98 | } 99 | } 100 | 101 | Directive.bind = { 102 | update: function (val) { 103 | if(val != null && val !== false) 104 | this.el.setAttribute(this.descriptor.arg, val) 105 | } 106 | } 107 | 108 | Directive['if'] = { 109 | bind: function() { 110 | var next = this.el.nextElementSibling 111 | var parent = this.el.parentNode 112 | if (next && next.getAttribute('v-else') !== null) { 113 | next.removeAttribute('v-else') 114 | this.elseEl = next 115 | parent.removeChild(next) 116 | new Compile(this.elseEl, this.vm) 117 | } 118 | this.anchor = document.createTextNode('') 119 | // give a anchor for holding the place 120 | parent.replaceChild(this.anchor, this.el) 121 | new Compile(this.el, this.vm) 122 | }, 123 | update: function(value) { 124 | var trueEl = value ? this.el : this.elseEl 125 | var falseEl = value ? this.elseEl : this.el 126 | var parent = this.anchor.parentNode 127 | try { 128 | parent.removeChild(falseEl) 129 | } catch(e) {} 130 | parent.insertBefore(trueEl, this.anchor) 131 | } 132 | } 133 | 134 | // for IE8 135 | if(!document.addEventListener) { 136 | Object.defineProperty(Element.prototype, 'nextElementSibling', { 137 | get: function() { 138 | var ele = this; 139 | do { 140 | ele = ele.nextSibling; 141 | } while (ele && ele.nodeType !== 1); 142 | return ele; 143 | } 144 | }) 145 | } 146 | 147 | Directive['for'] = { 148 | bind: function() { 149 | var inMatch = this.descriptor.expression.match(/(.*) in (.*)/) 150 | if (inMatch) { 151 | this.alias = inMatch[1].trim() 152 | this.descriptor.expression = inMatch[2].trim() 153 | } 154 | var parent = this.el.parentNode 155 | this.anchor = document.createTextNode('') 156 | this.template = this.el.cloneNode(true) 157 | parent.replaceChild(this.anchor, this.el) 158 | }, 159 | update: function(value) { 160 | var parent = this.anchor.parentNode 161 | while(this.anchor !== parent.firstChild) { 162 | parent.removeChild(parent.firstChild) 163 | } 164 | this.frag = document.createDocumentFragment() 165 | for(var i=0; i originalLen - 1 ? originalLen - 1 : index 73 | index = index < 0 ? originalLen + index : index 74 | deleteCount = deleteCount > originalLen - index ? originalLen - index : deleteCount 75 | deleteCount = deleteCount < 0 ? 0 : deleteCount 76 | args = args.slice(2) 77 | var addedCount = args.length - deleteCount 78 | for (key = index; key < index + deleteCount; key++) { 79 | removed.push(this[key]) 80 | delete this[key] 81 | } 82 | move(this, index + deleteCount, addedCount) 83 | // copy added item 84 | for (i = 0; i < args.length; i++) { 85 | this[index + i] = (Observer.create(args[i]) || {}).data || args[i] 86 | inserted.push(this[index + i]) 87 | } 88 | this.length = originalLen + addedCount 89 | changed = true 90 | break 91 | case 'pop': 92 | removed.push(this[originalLen - 1]) 93 | delete this[originalLen - 1] 94 | this.length = originalLen - 1 95 | changed = true 96 | break 97 | case 'shift': 98 | removed.push(this[0]) 99 | for (key = 1; key < this.length; key++) { 100 | this[key - 1] = this[key] 101 | } 102 | delete this[originalLen - 1] 103 | this.length = originalLen - 1 104 | changed = true 105 | break 106 | case 'sort': 107 | case 'reverse': 108 | var copy = [] 109 | for (key = 0; key < this.length; key++) { 110 | copy[key] = this[key] 111 | } 112 | originalMethod.apply(copy, args) 113 | for (key = 0; key < this.length; key++) { 114 | this[key] = copy[key] 115 | } 116 | changed = true 117 | break 118 | default: 119 | // result = originalMethod.apply(this, args) 120 | break 121 | } 122 | if (changed) { 123 | if (inserted) ob.observeArray(inserted) 124 | if (removed) ob.unobserveArray(removed) 125 | // notify change 126 | ob.notify() 127 | } 128 | return result 129 | } 130 | }) 131 | 132 | function move(array, index, offset) { 133 | var key 134 | var originalLen = array.length 135 | if (offset > 0) { 136 | // copy the items from low to high 137 | for (key = originalLen - 1; key >= index; key--) { 138 | array[key + offset] = array[key] 139 | } 140 | } else { 141 | // copy the items from high to low 142 | for (key = index; key < originalLen; key++) { 143 | array[key + offset] = array[key] 144 | } 145 | } 146 | } 147 | 148 | Array.prototype.$set = function $set(index, val) { 149 | if (index >= this.length) { 150 | this.length = index + 1 151 | } 152 | return this.splice(index, 1, val)[0] 153 | } 154 | 155 | Array.prototype.$remove = function $remove(item) { 156 | /* istanbul ignore if */ 157 | if (!this.length) return 158 | var index = this.indexOf(item) 159 | if (index > -1) { 160 | return this.splice(index, 1) 161 | } 162 | } 163 | 164 | function Observer(data) { 165 | // store the original value 166 | this.value = data 167 | var proxy = createDomProxy() 168 | var keys = Object.keys(data) 169 | var i = keys.length 170 | // copy data to the proxy 171 | while (i--) { 172 | proxy[keys[i]] = data[keys[i]] 173 | } 174 | if(data.length) { // for Array 175 | proxy.length = data.length 176 | } 177 | proxy.__ob__ = this 178 | this.dep = new Dep() 179 | this.data = proxy 180 | this.keys = keys 181 | if(isArray(proxy)) { 182 | copyAugment(proxy, arrayMethods) 183 | this.observeArray(proxy) 184 | } else { 185 | this.walk(proxy) 186 | } 187 | } 188 | 189 | Observer.create = function (value) { 190 | if (!value || typeof value !== 'object') { 191 | return 192 | } 193 | var ob 194 | if ( 195 | value.__ob__ && 196 | value.__ob__ instanceof Observer 197 | ) { 198 | ob = value.__ob__ 199 | } else { 200 | ob = new Observer(value) 201 | } 202 | return ob 203 | } 204 | 205 | Observer.prototype.walk = function (obj) { 206 | var keys = this.keys 207 | var i = keys.length 208 | while (i--) { 209 | this.convert(keys[i], obj[keys[i]]) 210 | } 211 | } 212 | 213 | Observer.prototype.observeArray = function (items) { 214 | var i = items.length 215 | while (i--) { 216 | var ob = Observer.create(items[i]) 217 | items[i] = (ob || {}).data || items[i] 218 | if (ob) { 219 | (ob.parents || (ob.parents = [])).push(this) 220 | } 221 | } 222 | } 223 | 224 | Observer.prototype.unobserveArray = function (items) { 225 | var i = items.length 226 | while (i--) { 227 | var ob = items[i] && items[i].__ob__ 228 | if (ob) { 229 | ob.parents.$remove(this) 230 | } 231 | } 232 | } 233 | 234 | Observer.prototype.notify = function () { 235 | this.dep.notify() 236 | var parents = this.parents 237 | if (parents) { 238 | var i = parents.length 239 | while (i--) { 240 | parents[i].notify() 241 | } 242 | } 243 | } 244 | 245 | Observer.prototype.convert = function (key, val) { 246 | this.defineReactive(this.data, key, val) 247 | } 248 | 249 | var defineReactive = Observer.prototype.defineReactive = function (obj, key, val) { 250 | var dep = new Dep() 251 | dep.key = key 252 | // console.log('define: ', key, Dep.target) 253 | var childOb = Observer.create(val) 254 | val = (childOb || {}).data || val 255 | 256 | Object.defineProperty(obj, key, { 257 | configurable: true, 258 | get: function () { 259 | // console.log('get: ', key, Dep.target) 260 | if (Dep.target) { 261 | dep.depend() 262 | if(childOb) { 263 | childOb.dep.depend() 264 | } 265 | } 266 | return val 267 | }, 268 | set: function (newVal) { 269 | // console.log('set: ', key, Dep.target) 270 | if (newVal === val) { 271 | return 272 | } 273 | obj.__ob__.value[key] = newVal // update the original value 274 | childOb = Observer.create(newVal) 275 | val = (childOb || {}).data || newVal 276 | dep.notify() 277 | } 278 | }) 279 | } 280 | 281 | function createDomProxy() { 282 | var proxy = document.createElement('null') 283 | // copy Object.prototype's functions to proxy 284 | ;[ 285 | 'hasOwnProperty', 286 | 'isPrototypeOf', 287 | 'propertyIsEnumerable', 288 | 'toLocaleString', 289 | 'toString', 290 | 'valueOf' 291 | ].forEach(function (method) { 292 | proxy[method] = Object.prototype[method] 293 | }) 294 | return proxy 295 | } 296 | 297 | function isArray (array) { 298 | if (!array) return false 299 | var length = array.length 300 | return length === 0 || 301 | typeof length === 'number' && length > 0 && (length - 1) in array 302 | } 303 | 304 | function copyAugment(target, src) { 305 | for (var i in src) { 306 | target[i] = src[i] 307 | } 308 | } 309 | 310 | var uid = 0 311 | 312 | function Dep() { 313 | this.id = uid++ 314 | this.subs = [] 315 | } 316 | 317 | Dep.prototype = { 318 | addSub: function (sub) { 319 | this.subs.push(sub) 320 | }, 321 | 322 | depend: function () { 323 | Dep.target.addDep(this) 324 | }, 325 | 326 | removeSub: function (sub) { 327 | var index = this.subs.indexOf(sub) 328 | if (index != -1) { 329 | this.subs.splice(index, 1) 330 | } 331 | }, 332 | 333 | notify: function () { 334 | this.subs.forEach(function (sub) { 335 | sub.update() 336 | }) 337 | } 338 | } 339 | 340 | Dep.target = null -------------------------------------------------------------------------------- /src/es5-sham.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/es-shims/es5-shim 3 | * @license es5-shim Copyright 2009-2015 by contributors, MIT License 4 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 5 | */ 6 | 7 | // vim: ts=4 sts=4 sw=4 expandtab 8 | 9 | // Add semicolon to prevent IIFE from being passed as argument to concatenated code. 10 | ; 11 | 12 | // UMD (Universal Module Definition) 13 | // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js 14 | (function (root, factory) { 15 | 'use strict'; 16 | 17 | /* global define, exports, module */ 18 | if (typeof define === 'function' && define.amd) { 19 | // AMD. Register as an anonymous module. 20 | define(factory); 21 | } else if (typeof exports === 'object') { 22 | // Node. Does not work with strict CommonJS, but 23 | // only CommonJS-like enviroments that support module.exports, 24 | // like Node. 25 | module.exports = factory(); 26 | } else { 27 | // Browser globals (root is window) 28 | root.returnExports = factory(); 29 | } 30 | }(this, function () { 31 | 32 | var call = Function.call; 33 | var prototypeOfObject = Object.prototype; 34 | var owns = call.bind(prototypeOfObject.hasOwnProperty); 35 | var isEnumerable = call.bind(prototypeOfObject.propertyIsEnumerable); 36 | var toStr = call.bind(prototypeOfObject.toString); 37 | 38 | // If JS engine supports accessors creating shortcuts. 39 | var defineGetter; 40 | var defineSetter; 41 | var lookupGetter; 42 | var lookupSetter; 43 | var supportsAccessors = owns(prototypeOfObject, '__defineGetter__'); 44 | if (supportsAccessors) { 45 | /* eslint-disable no-underscore-dangle, no-restricted-properties */ 46 | defineGetter = call.bind(prototypeOfObject.__defineGetter__); 47 | defineSetter = call.bind(prototypeOfObject.__defineSetter__); 48 | lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); 49 | lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); 50 | /* eslint-enable no-underscore-dangle, no-restricted-properties */ 51 | } 52 | 53 | var isPrimitive = function isPrimitive(o) { 54 | return o == null || (typeof o !== 'object' && typeof o !== 'function'); 55 | }; 56 | 57 | // ES5 15.2.3.2 58 | // http://es5.github.com/#x15.2.3.2 59 | if (!Object.getPrototypeOf) { 60 | // https://github.com/es-shims/es5-shim/issues#issue/2 61 | // http://ejohn.org/blog/objectgetprototypeof/ 62 | // recommended by fschaefer on github 63 | // 64 | // sure, and webreflection says ^_^ 65 | // ... this will nerever possibly return null 66 | // ... Opera Mini breaks here with infinite loops 67 | Object.getPrototypeOf = function getPrototypeOf(object) { 68 | // eslint-disable-next-line no-proto 69 | var proto = object.__proto__; 70 | if (proto || proto === null) { 71 | return proto; 72 | } else if (toStr(object.constructor) === '[object Function]') { 73 | return object.constructor.prototype; 74 | } else if (object instanceof Object) { 75 | return prototypeOfObject; 76 | } else { 77 | // Correctly return null for Objects created with `Object.create(null)` 78 | // (shammed or native) or `{ __proto__: null}`. Also returns null for 79 | // cross-realm objects on browsers that lack `__proto__` support (like 80 | // IE <11), but that's the best we can do. 81 | return null; 82 | } 83 | }; 84 | } 85 | 86 | // ES5 15.2.3.3 87 | // http://es5.github.com/#x15.2.3.3 88 | 89 | var doesGetOwnPropertyDescriptorWork = function doesGetOwnPropertyDescriptorWork(object) { 90 | try { 91 | object.sentinel = 0; 92 | return Object.getOwnPropertyDescriptor(object, 'sentinel').value === 0; 93 | } catch (exception) { 94 | return false; 95 | } 96 | }; 97 | 98 | // check whether getOwnPropertyDescriptor works if it's given. Otherwise, shim partially. 99 | if (Object.defineProperty) { 100 | var getOwnPropertyDescriptorWorksOnObject = doesGetOwnPropertyDescriptorWork({}); 101 | var getOwnPropertyDescriptorWorksOnDom = typeof document === 'undefined' 102 | || doesGetOwnPropertyDescriptorWork(document.createElement('div')); 103 | if (!getOwnPropertyDescriptorWorksOnDom || !getOwnPropertyDescriptorWorksOnObject) { 104 | var getOwnPropertyDescriptorFallback = Object.getOwnPropertyDescriptor; 105 | } 106 | } 107 | 108 | if (!Object.getOwnPropertyDescriptor || getOwnPropertyDescriptorFallback) { 109 | var ERR_NON_OBJECT = 'Object.getOwnPropertyDescriptor called on a non-object: '; 110 | 111 | /* eslint-disable no-proto */ 112 | Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { 113 | if (isPrimitive(object)) { 114 | throw new TypeError(ERR_NON_OBJECT + object); 115 | } 116 | 117 | // make a valiant attempt to use the real getOwnPropertyDescriptor 118 | // for I8's DOM elements. 119 | if (getOwnPropertyDescriptorFallback) { 120 | try { 121 | return getOwnPropertyDescriptorFallback.call(Object, object, property); 122 | } catch (exception) { 123 | // try the shim if the real one doesn't work 124 | } 125 | } 126 | 127 | var descriptor; 128 | 129 | // If object does not owns property return undefined immediately. 130 | if (!owns(object, property)) { 131 | return descriptor; 132 | } 133 | 134 | // If object has a property then it's for sure `configurable`, and 135 | // probably `enumerable`. Detect enumerability though. 136 | descriptor = { 137 | enumerable: isEnumerable(object, property), 138 | configurable: true 139 | }; 140 | 141 | // If JS engine supports accessor properties then property may be a 142 | // getter or setter. 143 | if (supportsAccessors) { 144 | // Unfortunately `__lookupGetter__` will return a getter even 145 | // if object has own non getter property along with a same named 146 | // inherited getter. To avoid misbehavior we temporary remove 147 | // `__proto__` so that `__lookupGetter__` will return getter only 148 | // if it's owned by an object. 149 | var prototype = object.__proto__; 150 | var notPrototypeOfObject = object !== prototypeOfObject; 151 | // avoid recursion problem, breaking in Opera Mini when 152 | // Object.getOwnPropertyDescriptor(Object.prototype, 'toString') 153 | // or any other Object.prototype accessor 154 | if (notPrototypeOfObject) { 155 | object.__proto__ = prototypeOfObject; 156 | } 157 | 158 | var getter = lookupGetter(object, property); 159 | var setter = lookupSetter(object, property); 160 | 161 | if (notPrototypeOfObject) { 162 | // Once we have getter and setter we can put values back. 163 | object.__proto__ = prototype; 164 | } 165 | 166 | if (getter || setter) { 167 | if (getter) { 168 | descriptor.get = getter; 169 | } 170 | if (setter) { 171 | descriptor.set = setter; 172 | } 173 | // If it was accessor property we're done and return here 174 | // in order to avoid adding `value` to the descriptor. 175 | return descriptor; 176 | } 177 | } 178 | 179 | // If we got this far we know that object has an own property that is 180 | // not an accessor so we set it as a value and return descriptor. 181 | descriptor.value = object[property]; 182 | descriptor.writable = true; 183 | return descriptor; 184 | }; 185 | /* eslint-enable no-proto */ 186 | } 187 | 188 | // ES5 15.2.3.4 189 | // http://es5.github.com/#x15.2.3.4 190 | if (!Object.getOwnPropertyNames) { 191 | Object.getOwnPropertyNames = function getOwnPropertyNames(object) { 192 | return Object.keys(object); 193 | }; 194 | } 195 | 196 | // ES5 15.2.3.5 197 | // http://es5.github.com/#x15.2.3.5 198 | if (!Object.create) { 199 | 200 | // Contributed by Brandon Benvie, October, 2012 201 | var createEmpty; 202 | var supportsProto = !({ __proto__: null } instanceof Object); 203 | // the following produces false positives 204 | // in Opera Mini => not a reliable check 205 | // Object.prototype.__proto__ === null 206 | 207 | // Check for document.domain and active x support 208 | // No need to use active x approach when document.domain is not set 209 | // see https://github.com/es-shims/es5-shim/issues/150 210 | // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346 211 | /* global ActiveXObject */ 212 | var shouldUseActiveX = function shouldUseActiveX() { 213 | // return early if document.domain not set 214 | if (!document.domain) { 215 | return false; 216 | } 217 | 218 | try { 219 | return !!new ActiveXObject('htmlfile'); 220 | } catch (exception) { 221 | return false; 222 | } 223 | }; 224 | 225 | // This supports IE8 when document.domain is used 226 | // see https://github.com/es-shims/es5-shim/issues/150 227 | // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346 228 | var getEmptyViaActiveX = function getEmptyViaActiveX() { 229 | var empty; 230 | var xDoc; 231 | 232 | xDoc = new ActiveXObject('htmlfile'); 233 | 234 | var script = 'script'; 235 | xDoc.write('<' + script + '>'); 236 | xDoc.close(); 237 | 238 | empty = xDoc.parentWindow.Object.prototype; 239 | xDoc = null; 240 | 241 | return empty; 242 | }; 243 | 244 | // The original implementation using an iframe 245 | // before the activex approach was added 246 | // see https://github.com/es-shims/es5-shim/issues/150 247 | var getEmptyViaIFrame = function getEmptyViaIFrame() { 248 | var iframe = document.createElement('iframe'); 249 | var parent = document.body || document.documentElement; 250 | var empty; 251 | 252 | iframe.style.display = 'none'; 253 | parent.appendChild(iframe); 254 | // eslint-disable-next-line no-script-url 255 | iframe.src = 'javascript:'; 256 | 257 | empty = iframe.contentWindow.Object.prototype; 258 | parent.removeChild(iframe); 259 | iframe = null; 260 | 261 | return empty; 262 | }; 263 | 264 | /* global document */ 265 | if (supportsProto || typeof document === 'undefined') { 266 | createEmpty = function () { 267 | return { __proto__: null }; 268 | }; 269 | } else { 270 | // In old IE __proto__ can't be used to manually set `null`, nor does 271 | // any other method exist to make an object that inherits from nothing, 272 | // aside from Object.prototype itself. Instead, create a new global 273 | // object and *steal* its Object.prototype and strip it bare. This is 274 | // used as the prototype to create nullary objects. 275 | createEmpty = function () { 276 | // Determine which approach to use 277 | // see https://github.com/es-shims/es5-shim/issues/150 278 | var empty = shouldUseActiveX() ? getEmptyViaActiveX() : getEmptyViaIFrame(); 279 | 280 | delete empty.constructor; 281 | delete empty.hasOwnProperty; 282 | delete empty.propertyIsEnumerable; 283 | delete empty.isPrototypeOf; 284 | delete empty.toLocaleString; 285 | delete empty.toString; 286 | delete empty.valueOf; 287 | 288 | var Empty = function Empty() { }; 289 | Empty.prototype = empty; 290 | // short-circuit future calls 291 | createEmpty = function () { 292 | return new Empty(); 293 | }; 294 | return new Empty(); 295 | }; 296 | } 297 | 298 | Object.create = function create(prototype, properties) { 299 | 300 | var object; 301 | var Type = function Type() { }; // An empty constructor. 302 | 303 | if (prototype === null) { 304 | object = createEmpty(); 305 | } else { 306 | if (prototype !== null && isPrimitive(prototype)) { 307 | // In the native implementation `parent` can be `null` 308 | // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) 309 | // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` 310 | // like they are in modern browsers. Using `Object.create` on DOM elements 311 | // is...err...probably inappropriate, but the native version allows for it. 312 | throw new TypeError('Object prototype may only be an Object or null'); // same msg as Chrome 313 | } 314 | Type.prototype = prototype; 315 | object = new Type(); 316 | // IE has no built-in implementation of `Object.getPrototypeOf` 317 | // neither `__proto__`, but this manually setting `__proto__` will 318 | // guarantee that `Object.getPrototypeOf` will work as expected with 319 | // objects created using `Object.create` 320 | // eslint-disable-next-line no-proto 321 | object.__proto__ = prototype; 322 | } 323 | 324 | if (properties !== void 0) { 325 | Object.defineProperties(object, properties); 326 | } 327 | 328 | return object; 329 | }; 330 | } 331 | 332 | // ES5 15.2.3.6 333 | // http://es5.github.com/#x15.2.3.6 334 | 335 | // Patch for WebKit and IE8 standard mode 336 | // Designed by hax 337 | // related issue: https://github.com/es-shims/es5-shim/issues#issue/5 338 | // IE8 Reference: 339 | // http://msdn.microsoft.com/en-us/library/dd282900.aspx 340 | // http://msdn.microsoft.com/en-us/library/dd229916.aspx 341 | // WebKit Bugs: 342 | // https://bugs.webkit.org/show_bug.cgi?id=36423 343 | 344 | var doesDefinePropertyWork = function doesDefinePropertyWork(object) { 345 | try { 346 | Object.defineProperty(object, 'sentinel', {}); 347 | return 'sentinel' in object; 348 | } catch (exception) { 349 | return false; 350 | } 351 | }; 352 | 353 | // check whether defineProperty works if it's given. Otherwise, 354 | // shim partially. 355 | if (Object.defineProperty) { 356 | var definePropertyWorksOnObject = doesDefinePropertyWork({}); 357 | var definePropertyWorksOnDom = typeof document === 'undefined' 358 | || doesDefinePropertyWork(document.createElement('div')); 359 | if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { 360 | var definePropertyFallback = Object.defineProperty, 361 | definePropertiesFallback = Object.defineProperties; 362 | } 363 | } 364 | 365 | if (!Object.defineProperty || definePropertyFallback) { 366 | var ERR_NON_OBJECT_DESCRIPTOR = 'Property description must be an object: '; 367 | var ERR_NON_OBJECT_TARGET = 'Object.defineProperty called on non-object: '; 368 | var ERR_ACCESSORS_NOT_SUPPORTED = 'getters & setters can not be defined on this javascript engine'; 369 | 370 | Object.defineProperty = function defineProperty(object, property, descriptor) { 371 | if (isPrimitive(object)) { 372 | throw new TypeError(ERR_NON_OBJECT_TARGET + object); 373 | } 374 | if (isPrimitive(descriptor)) { 375 | throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); 376 | } 377 | // make a valiant attempt to use the real defineProperty 378 | // for I8's DOM elements. 379 | if (definePropertyFallback) { 380 | try { 381 | return definePropertyFallback.call(Object, object, property, descriptor); 382 | } catch (exception) { 383 | // try the shim if the real one doesn't work 384 | } 385 | } 386 | 387 | // If it's a data property. 388 | if ('value' in descriptor) { 389 | // fail silently if 'writable', 'enumerable', or 'configurable' 390 | // are requested but not supported 391 | /* 392 | // alternate approach: 393 | if ( // can't implement these features; allow false but not true 394 | ('writable' in descriptor && !descriptor.writable) || 395 | ('enumerable' in descriptor && !descriptor.enumerable) || 396 | ('configurable' in descriptor && !descriptor.configurable) 397 | )) 398 | throw new RangeError( 399 | 'This implementation of Object.defineProperty does not support configurable, enumerable, or writable.' 400 | ); 401 | */ 402 | 403 | if (supportsAccessors && (lookupGetter(object, property) || lookupSetter(object, property))) { 404 | // As accessors are supported only on engines implementing 405 | // `__proto__` we can safely override `__proto__` while defining 406 | // a property to make sure that we don't hit an inherited 407 | // accessor. 408 | /* eslint-disable no-proto */ 409 | var prototype = object.__proto__; 410 | object.__proto__ = prototypeOfObject; 411 | // Deleting a property anyway since getter / setter may be 412 | // defined on object itself. 413 | delete object[property]; 414 | object[property] = descriptor.value; 415 | // Setting original `__proto__` back now. 416 | object.__proto__ = prototype; 417 | /* eslint-enable no-proto */ 418 | } else { 419 | object[property] = descriptor.value; 420 | } 421 | } else { 422 | var hasGetter = 'get' in descriptor; 423 | var hasSetter = 'set' in descriptor; 424 | if (!supportsAccessors && (hasGetter || hasSetter)) { 425 | throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); 426 | } 427 | // If we got that far then getters and setters can be defined !! 428 | if (hasGetter) { 429 | defineGetter(object, property, descriptor.get); 430 | } 431 | if (hasSetter) { 432 | defineSetter(object, property, descriptor.set); 433 | } 434 | } 435 | return object; 436 | }; 437 | } 438 | 439 | // ES5 15.2.3.7 440 | // http://es5.github.com/#x15.2.3.7 441 | if (!Object.defineProperties || definePropertiesFallback) { 442 | Object.defineProperties = function defineProperties(object, properties) { 443 | // make a valiant attempt to use the real defineProperties 444 | if (definePropertiesFallback) { 445 | try { 446 | return definePropertiesFallback.call(Object, object, properties); 447 | } catch (exception) { 448 | // try the shim if the real one doesn't work 449 | } 450 | } 451 | 452 | Object.keys(properties).forEach(function (property) { 453 | if (property !== '__proto__') { 454 | Object.defineProperty(object, property, properties[property]); 455 | } 456 | }); 457 | return object; 458 | }; 459 | } 460 | 461 | // ES5 15.2.3.8 462 | // http://es5.github.com/#x15.2.3.8 463 | if (!Object.seal) { 464 | Object.seal = function seal(object) { 465 | if (Object(object) !== object) { 466 | throw new TypeError('Object.seal can only be called on Objects.'); 467 | } 468 | // this is misleading and breaks feature-detection, but 469 | // allows "securable" code to "gracefully" degrade to working 470 | // but insecure code. 471 | return object; 472 | }; 473 | } 474 | 475 | // ES5 15.2.3.9 476 | // http://es5.github.com/#x15.2.3.9 477 | if (!Object.freeze) { 478 | Object.freeze = function freeze(object) { 479 | if (Object(object) !== object) { 480 | throw new TypeError('Object.freeze can only be called on Objects.'); 481 | } 482 | // this is misleading and breaks feature-detection, but 483 | // allows "securable" code to "gracefully" degrade to working 484 | // but insecure code. 485 | return object; 486 | }; 487 | } 488 | 489 | // detect a Rhino bug and patch it 490 | try { 491 | Object.freeze(function () { }); 492 | } catch (exception) { 493 | Object.freeze = (function (freezeObject) { 494 | return function freeze(object) { 495 | if (typeof object === 'function') { 496 | return object; 497 | } else { 498 | return freezeObject(object); 499 | } 500 | }; 501 | }(Object.freeze)); 502 | } 503 | 504 | // ES5 15.2.3.10 505 | // http://es5.github.com/#x15.2.3.10 506 | if (!Object.preventExtensions) { 507 | Object.preventExtensions = function preventExtensions(object) { 508 | if (Object(object) !== object) { 509 | throw new TypeError('Object.preventExtensions can only be called on Objects.'); 510 | } 511 | // this is misleading and breaks feature-detection, but 512 | // allows "securable" code to "gracefully" degrade to working 513 | // but insecure code. 514 | return object; 515 | }; 516 | } 517 | 518 | // ES5 15.2.3.11 519 | // http://es5.github.com/#x15.2.3.11 520 | if (!Object.isSealed) { 521 | Object.isSealed = function isSealed(object) { 522 | if (Object(object) !== object) { 523 | throw new TypeError('Object.isSealed can only be called on Objects.'); 524 | } 525 | return false; 526 | }; 527 | } 528 | 529 | // ES5 15.2.3.12 530 | // http://es5.github.com/#x15.2.3.12 531 | if (!Object.isFrozen) { 532 | Object.isFrozen = function isFrozen(object) { 533 | if (Object(object) !== object) { 534 | throw new TypeError('Object.isFrozen can only be called on Objects.'); 535 | } 536 | return false; 537 | }; 538 | } 539 | 540 | // ES5 15.2.3.13 541 | // http://es5.github.com/#x15.2.3.13 542 | if (!Object.isExtensible) { 543 | Object.isExtensible = function isExtensible(object) { 544 | // 1. If Type(O) is not Object throw a TypeError exception. 545 | if (Object(object) !== object) { 546 | throw new TypeError('Object.isExtensible can only be called on Objects.'); 547 | } 548 | // 2. Return the Boolean value of the [[Extensible]] internal property of O. 549 | var name = ''; 550 | while (owns(object, name)) { 551 | name += '?'; 552 | } 553 | object[name] = true; 554 | var returnValue = owns(object, name); 555 | delete object[name]; 556 | return returnValue; 557 | }; 558 | } 559 | 560 | })); -------------------------------------------------------------------------------- /src/es5-shim.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/es-shims/es5-shim 3 | * @license es5-shim Copyright 2009-2015 by contributors, MIT License 4 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE 5 | */ 6 | 7 | // vim: ts=4 sts=4 sw=4 expandtab 8 | 9 | // Add semicolon to prevent IIFE from being passed as argument to concatenated code. 10 | ; 11 | 12 | // UMD (Universal Module Definition) 13 | // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js 14 | (function (root, factory) { 15 | 'use strict'; 16 | 17 | /* global define, exports, module */ 18 | if (typeof define === 'function' && define.amd) { 19 | // AMD. Register as an anonymous module. 20 | define(factory); 21 | } else if (typeof exports === 'object') { 22 | // Node. Does not work with strict CommonJS, but 23 | // only CommonJS-like enviroments that support module.exports, 24 | // like Node. 25 | module.exports = factory(); 26 | } else { 27 | // Browser globals (root is window) 28 | root.returnExports = factory(); 29 | } 30 | }(this, function () { 31 | /** 32 | * Brings an environment as close to ECMAScript 5 compliance 33 | * as is possible with the facilities of erstwhile engines. 34 | * 35 | * Annotated ES5: http://es5.github.com/ (specific links below) 36 | * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 37 | * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ 38 | */ 39 | 40 | // Shortcut to an often accessed properties, in order to avoid multiple 41 | // dereference that costs universally. This also holds a reference to known-good 42 | // functions. 43 | var $Array = Array; 44 | var ArrayPrototype = $Array.prototype; 45 | var $Object = Object; 46 | var ObjectPrototype = $Object.prototype; 47 | var $Function = Function; 48 | var FunctionPrototype = $Function.prototype; 49 | var $String = String; 50 | var StringPrototype = $String.prototype; 51 | var $Number = Number; 52 | var NumberPrototype = $Number.prototype; 53 | var array_slice = ArrayPrototype.slice; 54 | var array_splice = ArrayPrototype.splice; 55 | var array_push = ArrayPrototype.push; 56 | var array_unshift = ArrayPrototype.unshift; 57 | var array_concat = ArrayPrototype.concat; 58 | var array_join = ArrayPrototype.join; 59 | var call = FunctionPrototype.call; 60 | var apply = FunctionPrototype.apply; 61 | var max = Math.max; 62 | var min = Math.min; 63 | 64 | // Having a toString local variable name breaks in Opera so use to_string. 65 | var to_string = ObjectPrototype.toString; 66 | 67 | /* global Symbol */ 68 | /* eslint-disable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ 69 | var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; 70 | var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, constructorRegex = /^\s*class /, isES6ClassFn = function isES6ClassFn(value) { try { var fnStr = fnToStr.call(value); var singleStripped = fnStr.replace(/\/\/.*\n/g, ''); var multiStripped = singleStripped.replace(/\/\*[.\s\S]*\*\//g, ''); var spaceStripped = multiStripped.replace(/\n/mg, ' ').replace(/ {2}/g, ' '); return constructorRegex.test(spaceStripped); } catch (e) { return false; /* not a function */ } }, tryFunctionObject = function tryFunctionObject(value) { try { if (isES6ClassFn(value)) { return false; } fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]', isCallable = function isCallable(value) { if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } if (isES6ClassFn(value)) { return false; } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; }; 71 | 72 | var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; }; 73 | var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; }; 74 | /* eslint-enable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ 75 | 76 | /* inlined from http://npmjs.com/define-properties */ 77 | var supportsDescriptors = $Object.defineProperty && (function () { 78 | try { 79 | var obj = {}; 80 | $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); 81 | for (var _ in obj) { // jscs:ignore disallowUnusedVariables 82 | return false; 83 | } 84 | return obj.x === obj; 85 | } catch (e) { /* this is ES3 */ 86 | return false; 87 | } 88 | }()); 89 | var defineProperties = (function (has) { 90 | // Define configurable, writable, and non-enumerable props 91 | // if they don't exist. 92 | var defineProperty; 93 | if (supportsDescriptors) { 94 | defineProperty = function (object, name, method, forceAssign) { 95 | if (!forceAssign && (name in object)) { 96 | return; 97 | } 98 | $Object.defineProperty(object, name, { 99 | configurable: true, 100 | enumerable: false, 101 | writable: true, 102 | value: method 103 | }); 104 | }; 105 | } else { 106 | defineProperty = function (object, name, method, forceAssign) { 107 | if (!forceAssign && (name in object)) { 108 | return; 109 | } 110 | object[name] = method; 111 | }; 112 | } 113 | return function defineProperties(object, map, forceAssign) { 114 | for (var name in map) { 115 | if (has.call(map, name)) { 116 | defineProperty(object, name, map[name], forceAssign); 117 | } 118 | } 119 | }; 120 | }(ObjectPrototype.hasOwnProperty)); 121 | 122 | // 123 | // Util 124 | // ====== 125 | // 126 | 127 | /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ 128 | var isPrimitive = function isPrimitive(input) { 129 | var type = typeof input; 130 | return input === null || (type !== 'object' && type !== 'function'); 131 | }; 132 | 133 | var isActualNaN = $Number.isNaN || function isActualNaN(x) { 134 | return x !== x; 135 | }; 136 | 137 | var ES = { 138 | // ES5 9.4 139 | // http://es5.github.com/#x9.4 140 | // http://jsperf.com/to-integer 141 | /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */ 142 | ToInteger: function ToInteger(num) { 143 | var n = +num; 144 | if (isActualNaN(n)) { 145 | n = 0; 146 | } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { 147 | n = (n > 0 || -1) * Math.floor(Math.abs(n)); 148 | } 149 | return n; 150 | }, 151 | 152 | /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */ 153 | ToPrimitive: function ToPrimitive(input) { 154 | var val, valueOf, toStr; 155 | if (isPrimitive(input)) { 156 | return input; 157 | } 158 | valueOf = input.valueOf; 159 | if (isCallable(valueOf)) { 160 | val = valueOf.call(input); 161 | if (isPrimitive(val)) { 162 | return val; 163 | } 164 | } 165 | toStr = input.toString; 166 | if (isCallable(toStr)) { 167 | val = toStr.call(input); 168 | if (isPrimitive(val)) { 169 | return val; 170 | } 171 | } 172 | throw new TypeError(); 173 | }, 174 | 175 | // ES5 9.9 176 | // http://es5.github.com/#x9.9 177 | /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */ 178 | ToObject: function (o) { 179 | if (o == null) { // this matches both null and undefined 180 | throw new TypeError("can't convert " + o + ' to object'); 181 | } 182 | return $Object(o); 183 | }, 184 | 185 | /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ 186 | ToUint32: function ToUint32(x) { 187 | return x >>> 0; 188 | } 189 | }; 190 | 191 | // 192 | // Function 193 | // ======== 194 | // 195 | 196 | // ES-5 15.3.4.5 197 | // http://es5.github.com/#x15.3.4.5 198 | 199 | var Empty = function Empty() {}; 200 | 201 | defineProperties(FunctionPrototype, { 202 | bind: function bind(that) { // .length is 1 203 | // 1. Let Target be the this value. 204 | var target = this; 205 | // 2. If IsCallable(Target) is false, throw a TypeError exception. 206 | if (!isCallable(target)) { 207 | throw new TypeError('Function.prototype.bind called on incompatible ' + target); 208 | } 209 | // 3. Let A be a new (possibly empty) internal list of all of the 210 | // argument values provided after thisArg (arg1, arg2 etc), in order. 211 | // XXX slicedArgs will stand in for "A" if used 212 | var args = array_slice.call(arguments, 1); // for normal call 213 | // 4. Let F be a new native ECMAScript object. 214 | // 11. Set the [[Prototype]] internal property of F to the standard 215 | // built-in Function prototype object as specified in 15.3.3.1. 216 | // 12. Set the [[Call]] internal property of F as described in 217 | // 15.3.4.5.1. 218 | // 13. Set the [[Construct]] internal property of F as described in 219 | // 15.3.4.5.2. 220 | // 14. Set the [[HasInstance]] internal property of F as described in 221 | // 15.3.4.5.3. 222 | var bound; 223 | var binder = function () { 224 | 225 | if (this instanceof bound) { 226 | // 15.3.4.5.2 [[Construct]] 227 | // When the [[Construct]] internal method of a function object, 228 | // F that was created using the bind function is called with a 229 | // list of arguments ExtraArgs, the following steps are taken: 230 | // 1. Let target be the value of F's [[TargetFunction]] 231 | // internal property. 232 | // 2. If target has no [[Construct]] internal method, a 233 | // TypeError exception is thrown. 234 | // 3. Let boundArgs be the value of F's [[BoundArgs]] internal 235 | // property. 236 | // 4. Let args be a new list containing the same values as the 237 | // list boundArgs in the same order followed by the same 238 | // values as the list ExtraArgs in the same order. 239 | // 5. Return the result of calling the [[Construct]] internal 240 | // method of target providing args as the arguments. 241 | 242 | var result = apply.call( 243 | target, 244 | this, 245 | array_concat.call(args, array_slice.call(arguments)) 246 | ); 247 | if ($Object(result) === result) { 248 | return result; 249 | } 250 | return this; 251 | 252 | } else { 253 | // 15.3.4.5.1 [[Call]] 254 | // When the [[Call]] internal method of a function object, F, 255 | // which was created using the bind function is called with a 256 | // this value and a list of arguments ExtraArgs, the following 257 | // steps are taken: 258 | // 1. Let boundArgs be the value of F's [[BoundArgs]] internal 259 | // property. 260 | // 2. Let boundThis be the value of F's [[BoundThis]] internal 261 | // property. 262 | // 3. Let target be the value of F's [[TargetFunction]] internal 263 | // property. 264 | // 4. Let args be a new list containing the same values as the 265 | // list boundArgs in the same order followed by the same 266 | // values as the list ExtraArgs in the same order. 267 | // 5. Return the result of calling the [[Call]] internal method 268 | // of target providing boundThis as the this value and 269 | // providing args as the arguments. 270 | 271 | // equiv: target.call(this, ...boundArgs, ...args) 272 | return apply.call( 273 | target, 274 | that, 275 | array_concat.call(args, array_slice.call(arguments)) 276 | ); 277 | 278 | } 279 | 280 | }; 281 | 282 | // 15. If the [[Class]] internal property of Target is "Function", then 283 | // a. Let L be the length property of Target minus the length of A. 284 | // b. Set the length own property of F to either 0 or L, whichever is 285 | // larger. 286 | // 16. Else set the length own property of F to 0. 287 | 288 | var boundLength = max(0, target.length - args.length); 289 | 290 | // 17. Set the attributes of the length own property of F to the values 291 | // specified in 15.3.5.1. 292 | var boundArgs = []; 293 | for (var i = 0; i < boundLength; i++) { 294 | array_push.call(boundArgs, '$' + i); 295 | } 296 | 297 | // XXX Build a dynamic function with desired amount of arguments is the only 298 | // way to set the length property of a function. 299 | // In environments where Content Security Policies enabled (Chrome extensions, 300 | // for ex.) all use of eval or Function costructor throws an exception. 301 | // However in all of these environments Function.prototype.bind exists 302 | // and so this code will never be executed. 303 | bound = $Function('binder', 'return function (' + array_join.call(boundArgs, ',') + '){ return binder.apply(this, arguments); }')(binder); 304 | 305 | if (target.prototype) { 306 | Empty.prototype = target.prototype; 307 | bound.prototype = new Empty(); 308 | // Clean up dangling references. 309 | Empty.prototype = null; 310 | } 311 | 312 | // TODO 313 | // 18. Set the [[Extensible]] internal property of F to true. 314 | 315 | // TODO 316 | // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). 317 | // 20. Call the [[DefineOwnProperty]] internal method of F with 318 | // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: 319 | // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and 320 | // false. 321 | // 21. Call the [[DefineOwnProperty]] internal method of F with 322 | // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, 323 | // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, 324 | // and false. 325 | 326 | // TODO 327 | // NOTE Function objects created using Function.prototype.bind do not 328 | // have a prototype property or the [[Code]], [[FormalParameters]], and 329 | // [[Scope]] internal properties. 330 | // XXX can't delete prototype in pure-js. 331 | 332 | // 22. Return F. 333 | return bound; 334 | } 335 | }); 336 | 337 | // _Please note: Shortcuts are defined after `Function.prototype.bind` as we 338 | // use it in defining shortcuts. 339 | var owns = call.bind(ObjectPrototype.hasOwnProperty); 340 | var toStr = call.bind(ObjectPrototype.toString); 341 | var arraySlice = call.bind(array_slice); 342 | var arraySliceApply = apply.bind(array_slice); 343 | /* globals document */ 344 | if (typeof document === 'object' && document && document.documentElement) { 345 | try { 346 | arraySlice(document.documentElement.childNodes); 347 | } catch (e) { 348 | var origArraySlice = arraySlice; 349 | var origArraySliceApply = arraySliceApply; 350 | arraySlice = function arraySliceIE(arr) { 351 | var r = []; 352 | var i = arr.length; 353 | while (i-- > 0) { 354 | r[i] = arr[i]; 355 | } 356 | return origArraySliceApply(r, origArraySlice(arguments, 1)); 357 | }; 358 | arraySliceApply = function arraySliceApplyIE(arr, args) { 359 | return origArraySliceApply(arraySlice(arr), args); 360 | }; 361 | } 362 | } 363 | var strSlice = call.bind(StringPrototype.slice); 364 | var strSplit = call.bind(StringPrototype.split); 365 | var strIndexOf = call.bind(StringPrototype.indexOf); 366 | var pushCall = call.bind(array_push); 367 | var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); 368 | var arraySort = call.bind(ArrayPrototype.sort); 369 | 370 | // 371 | // Array 372 | // ===== 373 | // 374 | 375 | var isArray = $Array.isArray || function isArray(obj) { 376 | return toStr(obj) === '[object Array]'; 377 | }; 378 | 379 | // ES5 15.4.4.12 380 | // http://es5.github.com/#x15.4.4.13 381 | // Return len+argCount. 382 | // [bugfix, ielt8] 383 | // IE < 8 bug: [].unshift(0) === undefined but should be "1" 384 | var hasUnshiftReturnValueBug = [].unshift(0) !== 1; 385 | defineProperties(ArrayPrototype, { 386 | unshift: function () { 387 | array_unshift.apply(this, arguments); 388 | return this.length; 389 | } 390 | }, hasUnshiftReturnValueBug); 391 | 392 | // ES5 15.4.3.2 393 | // http://es5.github.com/#x15.4.3.2 394 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray 395 | defineProperties($Array, { isArray: isArray }); 396 | 397 | // The IsCallable() check in the Array functions 398 | // has been replaced with a strict check on the 399 | // internal class of the object to trap cases where 400 | // the provided function was actually a regular 401 | // expression literal, which in V8 and 402 | // JavaScriptCore is a typeof "function". Only in 403 | // V8 are regular expression literals permitted as 404 | // reduce parameters, so it is desirable in the 405 | // general case for the shim to match the more 406 | // strict and common behavior of rejecting regular 407 | // expressions. 408 | 409 | // ES5 15.4.4.18 410 | // http://es5.github.com/#x15.4.4.18 411 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach 412 | 413 | // Check failure of by-index access of string characters (IE < 9) 414 | // and failure of `0 in boxedString` (Rhino) 415 | var boxedString = $Object('a'); 416 | var splitString = boxedString[0] !== 'a' || !(0 in boxedString); 417 | 418 | var properlyBoxesContext = function properlyBoxed(method) { 419 | // Check node 0.6.21 bug where third parameter is not boxed 420 | var properlyBoxesNonStrict = true; 421 | var properlyBoxesStrict = true; 422 | var threwException = false; 423 | if (method) { 424 | try { 425 | method.call('foo', function (_, __, context) { 426 | if (typeof context !== 'object') { 427 | properlyBoxesNonStrict = false; 428 | } 429 | }); 430 | 431 | method.call([1], function () { 432 | 'use strict'; 433 | 434 | properlyBoxesStrict = typeof this === 'string'; 435 | }, 'x'); 436 | } catch (e) { 437 | threwException = true; 438 | } 439 | } 440 | return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict; 441 | }; 442 | 443 | defineProperties(ArrayPrototype, { 444 | forEach: function forEach(callbackfn/*, thisArg*/) { 445 | var object = ES.ToObject(this); 446 | var self = splitString && isString(this) ? strSplit(this, '') : object; 447 | var i = -1; 448 | var length = ES.ToUint32(self.length); 449 | var T; 450 | if (arguments.length > 1) { 451 | T = arguments[1]; 452 | } 453 | 454 | // If no callback function or if callback is not a callable function 455 | if (!isCallable(callbackfn)) { 456 | throw new TypeError('Array.prototype.forEach callback must be a function'); 457 | } 458 | 459 | while (++i < length) { 460 | if (i in self) { 461 | // Invoke the callback function with call, passing arguments: 462 | // context, property value, property key, thisArg object 463 | if (typeof T === 'undefined') { 464 | callbackfn(self[i], i, object); 465 | } else { 466 | callbackfn.call(T, self[i], i, object); 467 | } 468 | } 469 | } 470 | } 471 | }, !properlyBoxesContext(ArrayPrototype.forEach)); 472 | 473 | // ES5 15.4.4.19 474 | // http://es5.github.com/#x15.4.4.19 475 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map 476 | defineProperties(ArrayPrototype, { 477 | map: function map(callbackfn/*, thisArg*/) { 478 | var object = ES.ToObject(this); 479 | var self = splitString && isString(this) ? strSplit(this, '') : object; 480 | var length = ES.ToUint32(self.length); 481 | var result = $Array(length); 482 | var T; 483 | if (arguments.length > 1) { 484 | T = arguments[1]; 485 | } 486 | 487 | // If no callback function or if callback is not a callable function 488 | if (!isCallable(callbackfn)) { 489 | throw new TypeError('Array.prototype.map callback must be a function'); 490 | } 491 | 492 | for (var i = 0; i < length; i++) { 493 | if (i in self) { 494 | if (typeof T === 'undefined') { 495 | result[i] = callbackfn(self[i], i, object); 496 | } else { 497 | result[i] = callbackfn.call(T, self[i], i, object); 498 | } 499 | } 500 | } 501 | return result; 502 | } 503 | }, !properlyBoxesContext(ArrayPrototype.map)); 504 | 505 | // ES5 15.4.4.20 506 | // http://es5.github.com/#x15.4.4.20 507 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter 508 | defineProperties(ArrayPrototype, { 509 | filter: function filter(callbackfn/*, thisArg*/) { 510 | var object = ES.ToObject(this); 511 | var self = splitString && isString(this) ? strSplit(this, '') : object; 512 | var length = ES.ToUint32(self.length); 513 | var result = []; 514 | var value; 515 | var T; 516 | if (arguments.length > 1) { 517 | T = arguments[1]; 518 | } 519 | 520 | // If no callback function or if callback is not a callable function 521 | if (!isCallable(callbackfn)) { 522 | throw new TypeError('Array.prototype.filter callback must be a function'); 523 | } 524 | 525 | for (var i = 0; i < length; i++) { 526 | if (i in self) { 527 | value = self[i]; 528 | if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { 529 | pushCall(result, value); 530 | } 531 | } 532 | } 533 | return result; 534 | } 535 | }, !properlyBoxesContext(ArrayPrototype.filter)); 536 | 537 | // ES5 15.4.4.16 538 | // http://es5.github.com/#x15.4.4.16 539 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every 540 | defineProperties(ArrayPrototype, { 541 | every: function every(callbackfn/*, thisArg*/) { 542 | var object = ES.ToObject(this); 543 | var self = splitString && isString(this) ? strSplit(this, '') : object; 544 | var length = ES.ToUint32(self.length); 545 | var T; 546 | if (arguments.length > 1) { 547 | T = arguments[1]; 548 | } 549 | 550 | // If no callback function or if callback is not a callable function 551 | if (!isCallable(callbackfn)) { 552 | throw new TypeError('Array.prototype.every callback must be a function'); 553 | } 554 | 555 | for (var i = 0; i < length; i++) { 556 | if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { 557 | return false; 558 | } 559 | } 560 | return true; 561 | } 562 | }, !properlyBoxesContext(ArrayPrototype.every)); 563 | 564 | // ES5 15.4.4.17 565 | // http://es5.github.com/#x15.4.4.17 566 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some 567 | defineProperties(ArrayPrototype, { 568 | some: function some(callbackfn/*, thisArg */) { 569 | var object = ES.ToObject(this); 570 | var self = splitString && isString(this) ? strSplit(this, '') : object; 571 | var length = ES.ToUint32(self.length); 572 | var T; 573 | if (arguments.length > 1) { 574 | T = arguments[1]; 575 | } 576 | 577 | // If no callback function or if callback is not a callable function 578 | if (!isCallable(callbackfn)) { 579 | throw new TypeError('Array.prototype.some callback must be a function'); 580 | } 581 | 582 | for (var i = 0; i < length; i++) { 583 | if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { 584 | return true; 585 | } 586 | } 587 | return false; 588 | } 589 | }, !properlyBoxesContext(ArrayPrototype.some)); 590 | 591 | // ES5 15.4.4.21 592 | // http://es5.github.com/#x15.4.4.21 593 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce 594 | var reduceCoercesToObject = false; 595 | if (ArrayPrototype.reduce) { 596 | reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { 597 | return list; 598 | }) === 'object'; 599 | } 600 | defineProperties(ArrayPrototype, { 601 | reduce: function reduce(callbackfn/*, initialValue*/) { 602 | var object = ES.ToObject(this); 603 | var self = splitString && isString(this) ? strSplit(this, '') : object; 604 | var length = ES.ToUint32(self.length); 605 | 606 | // If no callback function or if callback is not a callable function 607 | if (!isCallable(callbackfn)) { 608 | throw new TypeError('Array.prototype.reduce callback must be a function'); 609 | } 610 | 611 | // no value to return if no initial value and an empty array 612 | if (length === 0 && arguments.length === 1) { 613 | throw new TypeError('reduce of empty array with no initial value'); 614 | } 615 | 616 | var i = 0; 617 | var result; 618 | if (arguments.length >= 2) { 619 | result = arguments[1]; 620 | } else { 621 | do { 622 | if (i in self) { 623 | result = self[i++]; 624 | break; 625 | } 626 | 627 | // if array contains no values, no initial value to return 628 | if (++i >= length) { 629 | throw new TypeError('reduce of empty array with no initial value'); 630 | } 631 | } while (true); 632 | } 633 | 634 | for (; i < length; i++) { 635 | if (i in self) { 636 | result = callbackfn(result, self[i], i, object); 637 | } 638 | } 639 | 640 | return result; 641 | } 642 | }, !reduceCoercesToObject); 643 | 644 | // ES5 15.4.4.22 645 | // http://es5.github.com/#x15.4.4.22 646 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight 647 | var reduceRightCoercesToObject = false; 648 | if (ArrayPrototype.reduceRight) { 649 | reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { 650 | return list; 651 | }) === 'object'; 652 | } 653 | defineProperties(ArrayPrototype, { 654 | reduceRight: function reduceRight(callbackfn/*, initial*/) { 655 | var object = ES.ToObject(this); 656 | var self = splitString && isString(this) ? strSplit(this, '') : object; 657 | var length = ES.ToUint32(self.length); 658 | 659 | // If no callback function or if callback is not a callable function 660 | if (!isCallable(callbackfn)) { 661 | throw new TypeError('Array.prototype.reduceRight callback must be a function'); 662 | } 663 | 664 | // no value to return if no initial value, empty array 665 | if (length === 0 && arguments.length === 1) { 666 | throw new TypeError('reduceRight of empty array with no initial value'); 667 | } 668 | 669 | var result; 670 | var i = length - 1; 671 | if (arguments.length >= 2) { 672 | result = arguments[1]; 673 | } else { 674 | do { 675 | if (i in self) { 676 | result = self[i--]; 677 | break; 678 | } 679 | 680 | // if array contains no values, no initial value to return 681 | if (--i < 0) { 682 | throw new TypeError('reduceRight of empty array with no initial value'); 683 | } 684 | } while (true); 685 | } 686 | 687 | if (i < 0) { 688 | return result; 689 | } 690 | 691 | do { 692 | if (i in self) { 693 | result = callbackfn(result, self[i], i, object); 694 | } 695 | } while (i--); 696 | 697 | return result; 698 | } 699 | }, !reduceRightCoercesToObject); 700 | 701 | // ES5 15.4.4.14 702 | // http://es5.github.com/#x15.4.4.14 703 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf 704 | var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; 705 | defineProperties(ArrayPrototype, { 706 | indexOf: function indexOf(searchElement/*, fromIndex */) { 707 | var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); 708 | var length = ES.ToUint32(self.length); 709 | 710 | if (length === 0) { 711 | return -1; 712 | } 713 | 714 | var i = 0; 715 | if (arguments.length > 1) { 716 | i = ES.ToInteger(arguments[1]); 717 | } 718 | 719 | // handle negative indices 720 | i = i >= 0 ? i : max(0, length + i); 721 | for (; i < length; i++) { 722 | if (i in self && self[i] === searchElement) { 723 | return i; 724 | } 725 | } 726 | return -1; 727 | } 728 | }, hasFirefox2IndexOfBug); 729 | 730 | // ES5 15.4.4.15 731 | // http://es5.github.com/#x15.4.4.15 732 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf 733 | var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; 734 | defineProperties(ArrayPrototype, { 735 | lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) { 736 | var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); 737 | var length = ES.ToUint32(self.length); 738 | 739 | if (length === 0) { 740 | return -1; 741 | } 742 | var i = length - 1; 743 | if (arguments.length > 1) { 744 | i = min(i, ES.ToInteger(arguments[1])); 745 | } 746 | // handle negative indices 747 | i = i >= 0 ? i : length - Math.abs(i); 748 | for (; i >= 0; i--) { 749 | if (i in self && searchElement === self[i]) { 750 | return i; 751 | } 752 | } 753 | return -1; 754 | } 755 | }, hasFirefox2LastIndexOfBug); 756 | 757 | // ES5 15.4.4.12 758 | // http://es5.github.com/#x15.4.4.12 759 | var spliceNoopReturnsEmptyArray = (function () { 760 | var a = [1, 2]; 761 | var result = a.splice(); 762 | return a.length === 2 && isArray(result) && result.length === 0; 763 | }()); 764 | defineProperties(ArrayPrototype, { 765 | // Safari 5.0 bug where .splice() returns undefined 766 | splice: function splice(start, deleteCount) { 767 | if (arguments.length === 0) { 768 | return []; 769 | } else { 770 | return array_splice.apply(this, arguments); 771 | } 772 | } 773 | }, !spliceNoopReturnsEmptyArray); 774 | 775 | var spliceWorksWithEmptyObject = (function () { 776 | var obj = {}; 777 | ArrayPrototype.splice.call(obj, 0, 0, 1); 778 | return obj.length === 1; 779 | }()); 780 | defineProperties(ArrayPrototype, { 781 | splice: function splice(start, deleteCount) { 782 | if (arguments.length === 0) { 783 | return []; 784 | } 785 | var args = arguments; 786 | this.length = max(ES.ToInteger(this.length), 0); 787 | if (arguments.length > 0 && typeof deleteCount !== 'number') { 788 | args = arraySlice(arguments); 789 | if (args.length < 2) { 790 | pushCall(args, this.length - start); 791 | } else { 792 | args[1] = ES.ToInteger(deleteCount); 793 | } 794 | } 795 | return array_splice.apply(this, args); 796 | } 797 | }, !spliceWorksWithEmptyObject); 798 | var spliceWorksWithLargeSparseArrays = (function () { 799 | // Per https://github.com/es-shims/es5-shim/issues/295 800 | // Safari 7/8 breaks with sparse arrays of size 1e5 or greater 801 | var arr = new $Array(1e5); 802 | // note: the index MUST be 8 or larger or the test will false pass 803 | arr[8] = 'x'; 804 | arr.splice(1, 1); 805 | // note: this test must be defined *after* the indexOf shim 806 | // per https://github.com/es-shims/es5-shim/issues/313 807 | return arr.indexOf('x') === 7; 808 | }()); 809 | var spliceWorksWithSmallSparseArrays = (function () { 810 | // Per https://github.com/es-shims/es5-shim/issues/295 811 | // Opera 12.15 breaks on this, no idea why. 812 | var n = 256; 813 | var arr = []; 814 | arr[n] = 'a'; 815 | arr.splice(n + 1, 0, 'b'); 816 | return arr[n] === 'a'; 817 | }()); 818 | defineProperties(ArrayPrototype, { 819 | splice: function splice(start, deleteCount) { 820 | var O = ES.ToObject(this); 821 | var A = []; 822 | var len = ES.ToUint32(O.length); 823 | var relativeStart = ES.ToInteger(start); 824 | var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len); 825 | var actualDeleteCount = min(max(ES.ToInteger(deleteCount), 0), len - actualStart); 826 | 827 | var k = 0; 828 | var from; 829 | while (k < actualDeleteCount) { 830 | from = $String(actualStart + k); 831 | if (owns(O, from)) { 832 | A[k] = O[from]; 833 | } 834 | k += 1; 835 | } 836 | 837 | var items = arraySlice(arguments, 2); 838 | var itemCount = items.length; 839 | var to; 840 | if (itemCount < actualDeleteCount) { 841 | k = actualStart; 842 | var maxK = len - actualDeleteCount; 843 | while (k < maxK) { 844 | from = $String(k + actualDeleteCount); 845 | to = $String(k + itemCount); 846 | if (owns(O, from)) { 847 | O[to] = O[from]; 848 | } else { 849 | delete O[to]; 850 | } 851 | k += 1; 852 | } 853 | k = len; 854 | var minK = len - actualDeleteCount + itemCount; 855 | while (k > minK) { 856 | delete O[k - 1]; 857 | k -= 1; 858 | } 859 | } else if (itemCount > actualDeleteCount) { 860 | k = len - actualDeleteCount; 861 | while (k > actualStart) { 862 | from = $String(k + actualDeleteCount - 1); 863 | to = $String(k + itemCount - 1); 864 | if (owns(O, from)) { 865 | O[to] = O[from]; 866 | } else { 867 | delete O[to]; 868 | } 869 | k -= 1; 870 | } 871 | } 872 | k = actualStart; 873 | for (var i = 0; i < items.length; ++i) { 874 | O[k] = items[i]; 875 | k += 1; 876 | } 877 | O.length = len - actualDeleteCount + itemCount; 878 | 879 | return A; 880 | } 881 | }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); 882 | 883 | var originalJoin = ArrayPrototype.join; 884 | var hasStringJoinBug; 885 | try { 886 | hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3'; 887 | } catch (e) { 888 | hasStringJoinBug = true; 889 | } 890 | if (hasStringJoinBug) { 891 | defineProperties(ArrayPrototype, { 892 | join: function join(separator) { 893 | var sep = typeof separator === 'undefined' ? ',' : separator; 894 | return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep); 895 | } 896 | }, hasStringJoinBug); 897 | } 898 | 899 | var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2'; 900 | if (hasJoinUndefinedBug) { 901 | defineProperties(ArrayPrototype, { 902 | join: function join(separator) { 903 | var sep = typeof separator === 'undefined' ? ',' : separator; 904 | return originalJoin.call(this, sep); 905 | } 906 | }, hasJoinUndefinedBug); 907 | } 908 | 909 | var pushShim = function push(item) { 910 | var O = ES.ToObject(this); 911 | var n = ES.ToUint32(O.length); 912 | var i = 0; 913 | while (i < arguments.length) { 914 | O[n + i] = arguments[i]; 915 | i += 1; 916 | } 917 | O.length = n + i; 918 | return n + i; 919 | }; 920 | 921 | var pushIsNotGeneric = (function () { 922 | var obj = {}; 923 | var result = Array.prototype.push.call(obj, undefined); 924 | return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0); 925 | }()); 926 | defineProperties(ArrayPrototype, { 927 | push: function push(item) { 928 | if (isArray(this)) { 929 | return array_push.apply(this, arguments); 930 | } 931 | return pushShim.apply(this, arguments); 932 | } 933 | }, pushIsNotGeneric); 934 | 935 | // This fixes a very weird bug in Opera 10.6 when pushing `undefined 936 | var pushUndefinedIsWeird = (function () { 937 | var arr = []; 938 | var result = arr.push(undefined); 939 | return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0); 940 | }()); 941 | defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird); 942 | 943 | // ES5 15.2.3.14 944 | // http://es5.github.io/#x15.4.4.10 945 | // Fix boxed string bug 946 | defineProperties(ArrayPrototype, { 947 | slice: function (start, end) { 948 | var arr = isString(this) ? strSplit(this, '') : this; 949 | return arraySliceApply(arr, arguments); 950 | } 951 | }, splitString); 952 | 953 | var sortIgnoresNonFunctions = (function () { 954 | try { 955 | [1, 2].sort(null); 956 | } catch (e) { 957 | try { 958 | [1, 2].sort({}); 959 | } catch (e2) { 960 | return false; 961 | } 962 | } 963 | return true; 964 | }()); 965 | var sortThrowsOnRegex = (function () { 966 | // this is a problem in Firefox 4, in which `typeof /a/ === 'function'` 967 | try { 968 | [1, 2].sort(/a/); 969 | return false; 970 | } catch (e) {} 971 | return true; 972 | }()); 973 | var sortIgnoresUndefined = (function () { 974 | // applies in IE 8, for one. 975 | try { 976 | [1, 2].sort(undefined); 977 | return true; 978 | } catch (e) {} 979 | return false; 980 | }()); 981 | defineProperties(ArrayPrototype, { 982 | sort: function sort(compareFn) { 983 | if (typeof compareFn === 'undefined') { 984 | return arraySort(this); 985 | } 986 | if (!isCallable(compareFn)) { 987 | throw new TypeError('Array.prototype.sort callback must be a function'); 988 | } 989 | return arraySort(this, compareFn); 990 | } 991 | }, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex); 992 | 993 | // 994 | // Object 995 | // ====== 996 | // 997 | 998 | // ES5 15.2.3.14 999 | // http://es5.github.com/#x15.2.3.14 1000 | 1001 | // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation 1002 | var hasDontEnumBug = !isEnum({ 'toString': null }, 'toString'); // jscs:ignore disallowQuotedKeysInObjects 1003 | var hasProtoEnumBug = isEnum(function () {}, 'prototype'); 1004 | var hasStringEnumBug = !owns('x', '0'); 1005 | var equalsConstructorPrototype = function (o) { 1006 | var ctor = o.constructor; 1007 | return ctor && ctor.prototype === o; 1008 | }; 1009 | var excludedKeys = { 1010 | $window: true, 1011 | $console: true, 1012 | $parent: true, 1013 | $self: true, 1014 | $frame: true, 1015 | $frames: true, 1016 | $frameElement: true, 1017 | $webkitIndexedDB: true, 1018 | $webkitStorageInfo: true, 1019 | $external: true, 1020 | $width: true, 1021 | $height: true, 1022 | $top: true, 1023 | $localStorage: true 1024 | }; 1025 | var hasAutomationEqualityBug = (function () { 1026 | /* globals window */ 1027 | if (typeof window === 'undefined') { 1028 | return false; 1029 | } 1030 | for (var k in window) { 1031 | try { 1032 | if (!excludedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { 1033 | equalsConstructorPrototype(window[k]); 1034 | } 1035 | } catch (e) { 1036 | return true; 1037 | } 1038 | } 1039 | return false; 1040 | }()); 1041 | var equalsConstructorPrototypeIfNotBuggy = function (object) { 1042 | if (typeof window === 'undefined' || !hasAutomationEqualityBug) { 1043 | return equalsConstructorPrototype(object); 1044 | } 1045 | try { 1046 | return equalsConstructorPrototype(object); 1047 | } catch (e) { 1048 | return false; 1049 | } 1050 | }; 1051 | var dontEnums = [ 1052 | 'toString', 1053 | 'toLocaleString', 1054 | 'valueOf', 1055 | 'hasOwnProperty', 1056 | 'isPrototypeOf', 1057 | 'propertyIsEnumerable', 1058 | 'constructor' 1059 | ]; 1060 | var dontEnumsLength = dontEnums.length; 1061 | 1062 | // taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js 1063 | // can be replaced with require('is-arguments') if we ever use a build process instead 1064 | var isStandardArguments = function isArguments(value) { 1065 | return toStr(value) === '[object Arguments]'; 1066 | }; 1067 | var isLegacyArguments = function isArguments(value) { 1068 | return value !== null 1069 | && typeof value === 'object' 1070 | && typeof value.length === 'number' 1071 | && value.length >= 0 1072 | && !isArray(value) 1073 | && isCallable(value.callee); 1074 | }; 1075 | var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments; 1076 | 1077 | defineProperties($Object, { 1078 | keys: function keys(object) { 1079 | var isFn = isCallable(object); 1080 | var isArgs = isArguments(object); 1081 | var isObject = object !== null && typeof object === 'object'; 1082 | var isStr = isObject && isString(object); 1083 | 1084 | if (!isObject && !isFn && !isArgs) { 1085 | throw new TypeError('Object.keys called on a non-object'); 1086 | } 1087 | 1088 | var theKeys = []; 1089 | var skipProto = hasProtoEnumBug && isFn; 1090 | if ((isStr && hasStringEnumBug) || isArgs) { 1091 | for (var i = 0; i < object.length; ++i) { 1092 | pushCall(theKeys, $String(i)); 1093 | } 1094 | } 1095 | 1096 | if (!isArgs) { 1097 | for (var name in object) { 1098 | if (!(skipProto && name === 'prototype') && owns(object, name)) { 1099 | pushCall(theKeys, $String(name)); 1100 | } 1101 | } 1102 | } 1103 | 1104 | if (hasDontEnumBug) { 1105 | var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); 1106 | for (var j = 0; j < dontEnumsLength; j++) { 1107 | var dontEnum = dontEnums[j]; 1108 | if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { 1109 | pushCall(theKeys, dontEnum); 1110 | } 1111 | } 1112 | } 1113 | return theKeys; 1114 | } 1115 | }); 1116 | 1117 | var keysWorksWithArguments = $Object.keys && (function () { 1118 | // Safari 5.0 bug 1119 | return $Object.keys(arguments).length === 2; 1120 | }(1, 2)); 1121 | var keysHasArgumentsLengthBug = $Object.keys && (function () { 1122 | var argKeys = $Object.keys(arguments); 1123 | return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1; 1124 | }(1)); 1125 | var originalKeys = $Object.keys; 1126 | defineProperties($Object, { 1127 | keys: function keys(object) { 1128 | if (isArguments(object)) { 1129 | return originalKeys(arraySlice(object)); 1130 | } else { 1131 | return originalKeys(object); 1132 | } 1133 | } 1134 | }, !keysWorksWithArguments || keysHasArgumentsLengthBug); 1135 | 1136 | // 1137 | // Date 1138 | // ==== 1139 | // 1140 | 1141 | var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0; 1142 | var aNegativeTestDate = new Date(-1509842289600292); 1143 | var aPositiveTestDate = new Date(1449662400000); 1144 | var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT'; 1145 | var hasToDateStringFormatBug; 1146 | var hasToStringFormatBug; 1147 | var timeZoneOffset = aNegativeTestDate.getTimezoneOffset(); 1148 | if (timeZoneOffset < -720) { 1149 | hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875'; 1150 | hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); 1151 | } else { 1152 | hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875'; 1153 | hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); 1154 | } 1155 | 1156 | var originalGetFullYear = call.bind(Date.prototype.getFullYear); 1157 | var originalGetMonth = call.bind(Date.prototype.getMonth); 1158 | var originalGetDate = call.bind(Date.prototype.getDate); 1159 | var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear); 1160 | var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth); 1161 | var originalGetUTCDate = call.bind(Date.prototype.getUTCDate); 1162 | var originalGetUTCDay = call.bind(Date.prototype.getUTCDay); 1163 | var originalGetUTCHours = call.bind(Date.prototype.getUTCHours); 1164 | var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes); 1165 | var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds); 1166 | var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds); 1167 | var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; 1168 | var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 1169 | var daysInMonth = function daysInMonth(month, year) { 1170 | return originalGetDate(new Date(year, month, 0)); 1171 | }; 1172 | 1173 | defineProperties(Date.prototype, { 1174 | getFullYear: function getFullYear() { 1175 | if (!this || !(this instanceof Date)) { 1176 | throw new TypeError('this is not a Date object.'); 1177 | } 1178 | var year = originalGetFullYear(this); 1179 | if (year < 0 && originalGetMonth(this) > 11) { 1180 | return year + 1; 1181 | } 1182 | return year; 1183 | }, 1184 | getMonth: function getMonth() { 1185 | if (!this || !(this instanceof Date)) { 1186 | throw new TypeError('this is not a Date object.'); 1187 | } 1188 | var year = originalGetFullYear(this); 1189 | var month = originalGetMonth(this); 1190 | if (year < 0 && month > 11) { 1191 | return 0; 1192 | } 1193 | return month; 1194 | }, 1195 | getDate: function getDate() { 1196 | if (!this || !(this instanceof Date)) { 1197 | throw new TypeError('this is not a Date object.'); 1198 | } 1199 | var year = originalGetFullYear(this); 1200 | var month = originalGetMonth(this); 1201 | var date = originalGetDate(this); 1202 | if (year < 0 && month > 11) { 1203 | if (month === 12) { 1204 | return date; 1205 | } 1206 | var days = daysInMonth(0, year + 1); 1207 | return (days - date) + 1; 1208 | } 1209 | return date; 1210 | }, 1211 | getUTCFullYear: function getUTCFullYear() { 1212 | if (!this || !(this instanceof Date)) { 1213 | throw new TypeError('this is not a Date object.'); 1214 | } 1215 | var year = originalGetUTCFullYear(this); 1216 | if (year < 0 && originalGetUTCMonth(this) > 11) { 1217 | return year + 1; 1218 | } 1219 | return year; 1220 | }, 1221 | getUTCMonth: function getUTCMonth() { 1222 | if (!this || !(this instanceof Date)) { 1223 | throw new TypeError('this is not a Date object.'); 1224 | } 1225 | var year = originalGetUTCFullYear(this); 1226 | var month = originalGetUTCMonth(this); 1227 | if (year < 0 && month > 11) { 1228 | return 0; 1229 | } 1230 | return month; 1231 | }, 1232 | getUTCDate: function getUTCDate() { 1233 | if (!this || !(this instanceof Date)) { 1234 | throw new TypeError('this is not a Date object.'); 1235 | } 1236 | var year = originalGetUTCFullYear(this); 1237 | var month = originalGetUTCMonth(this); 1238 | var date = originalGetUTCDate(this); 1239 | if (year < 0 && month > 11) { 1240 | if (month === 12) { 1241 | return date; 1242 | } 1243 | var days = daysInMonth(0, year + 1); 1244 | return (days - date) + 1; 1245 | } 1246 | return date; 1247 | } 1248 | }, hasNegativeMonthYearBug); 1249 | 1250 | defineProperties(Date.prototype, { 1251 | toUTCString: function toUTCString() { 1252 | if (!this || !(this instanceof Date)) { 1253 | throw new TypeError('this is not a Date object.'); 1254 | } 1255 | var day = originalGetUTCDay(this); 1256 | var date = originalGetUTCDate(this); 1257 | var month = originalGetUTCMonth(this); 1258 | var year = originalGetUTCFullYear(this); 1259 | var hour = originalGetUTCHours(this); 1260 | var minute = originalGetUTCMinutes(this); 1261 | var second = originalGetUTCSeconds(this); 1262 | return dayName[day] + ', ' 1263 | + (date < 10 ? '0' + date : date) + ' ' 1264 | + monthName[month] + ' ' 1265 | + year + ' ' 1266 | + (hour < 10 ? '0' + hour : hour) + ':' 1267 | + (minute < 10 ? '0' + minute : minute) + ':' 1268 | + (second < 10 ? '0' + second : second) + ' GMT'; 1269 | } 1270 | }, hasNegativeMonthYearBug || hasToUTCStringFormatBug); 1271 | 1272 | // Opera 12 has `,` 1273 | defineProperties(Date.prototype, { 1274 | toDateString: function toDateString() { 1275 | if (!this || !(this instanceof Date)) { 1276 | throw new TypeError('this is not a Date object.'); 1277 | } 1278 | var day = this.getDay(); 1279 | var date = this.getDate(); 1280 | var month = this.getMonth(); 1281 | var year = this.getFullYear(); 1282 | return dayName[day] + ' ' 1283 | + monthName[month] + ' ' 1284 | + (date < 10 ? '0' + date : date) + ' ' 1285 | + year; 1286 | } 1287 | }, hasNegativeMonthYearBug || hasToDateStringFormatBug); 1288 | 1289 | // can't use defineProperties here because of toString enumeration issue in IE <= 8 1290 | if (hasNegativeMonthYearBug || hasToStringFormatBug) { 1291 | Date.prototype.toString = function toString() { 1292 | if (!this || !(this instanceof Date)) { 1293 | throw new TypeError('this is not a Date object.'); 1294 | } 1295 | var day = this.getDay(); 1296 | var date = this.getDate(); 1297 | var month = this.getMonth(); 1298 | var year = this.getFullYear(); 1299 | var hour = this.getHours(); 1300 | var minute = this.getMinutes(); 1301 | var second = this.getSeconds(); 1302 | var timezoneOffset = this.getTimezoneOffset(); 1303 | var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60); 1304 | var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60); 1305 | return dayName[day] + ' ' 1306 | + monthName[month] + ' ' 1307 | + (date < 10 ? '0' + date : date) + ' ' 1308 | + year + ' ' 1309 | + (hour < 10 ? '0' + hour : hour) + ':' 1310 | + (minute < 10 ? '0' + minute : minute) + ':' 1311 | + (second < 10 ? '0' + second : second) + ' GMT' 1312 | + (timezoneOffset > 0 ? '-' : '+') 1313 | + (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) 1314 | + (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset); 1315 | }; 1316 | if (supportsDescriptors) { 1317 | $Object.defineProperty(Date.prototype, 'toString', { 1318 | configurable: true, 1319 | enumerable: false, 1320 | writable: true 1321 | }); 1322 | } 1323 | } 1324 | 1325 | // ES5 15.9.5.43 1326 | // http://es5.github.com/#x15.9.5.43 1327 | // This function returns a String value represent the instance in time 1328 | // represented by this Date object. The format of the String is the Date Time 1329 | // string format defined in 15.9.1.15. All fields are present in the String. 1330 | // The time zone is always UTC, denoted by the suffix Z. If the time value of 1331 | // this object is not a finite Number a RangeError exception is thrown. 1332 | var negativeDate = -62198755200000; 1333 | var negativeYearString = '-000001'; 1334 | var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; // eslint-disable-line max-len 1335 | var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z'; 1336 | 1337 | var getTime = call.bind(Date.prototype.getTime); 1338 | 1339 | defineProperties(Date.prototype, { 1340 | toISOString: function toISOString() { 1341 | if (!isFinite(this) || !isFinite(getTime(this))) { 1342 | // Adope Photoshop requires the second check. 1343 | throw new RangeError('Date.prototype.toISOString called on non-finite value.'); 1344 | } 1345 | 1346 | var year = originalGetUTCFullYear(this); 1347 | 1348 | var month = originalGetUTCMonth(this); 1349 | // see https://github.com/es-shims/es5-shim/issues/111 1350 | year += Math.floor(month / 12); 1351 | month = ((month % 12) + 12) % 12; 1352 | 1353 | // the date time string format is specified in 15.9.1.15. 1354 | var result = [ 1355 | month + 1, 1356 | originalGetUTCDate(this), 1357 | originalGetUTCHours(this), 1358 | originalGetUTCMinutes(this), 1359 | originalGetUTCSeconds(this) 1360 | ]; 1361 | year = ( 1362 | (year < 0 ? '-' : (year > 9999 ? '+' : '')) 1363 | + strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6) 1364 | ); 1365 | 1366 | for (var i = 0; i < result.length; ++i) { 1367 | // pad months, days, hours, minutes, and seconds to have two digits. 1368 | result[i] = strSlice('00' + result[i], -2); 1369 | } 1370 | // pad milliseconds to have three digits. 1371 | return ( 1372 | year + '-' + arraySlice(result, 0, 2).join('-') 1373 | + 'T' + arraySlice(result, 2).join(':') + '.' 1374 | + strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z' 1375 | ); 1376 | } 1377 | }, hasNegativeDateBug || hasSafari51DateBug); 1378 | 1379 | // ES5 15.9.5.44 1380 | // http://es5.github.com/#x15.9.5.44 1381 | // This function provides a String representation of a Date object for use by 1382 | // JSON.stringify (15.12.3). 1383 | var dateToJSONIsSupported = (function () { 1384 | try { 1385 | return Date.prototype.toJSON 1386 | && new Date(NaN).toJSON() === null 1387 | && new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 1388 | && Date.prototype.toJSON.call({ // generic 1389 | toISOString: function () { return true; } 1390 | }); 1391 | } catch (e) { 1392 | return false; 1393 | } 1394 | }()); 1395 | if (!dateToJSONIsSupported) { 1396 | Date.prototype.toJSON = function toJSON(key) { 1397 | // When the toJSON method is called with argument key, the following 1398 | // steps are taken: 1399 | 1400 | // 1. Let O be the result of calling ToObject, giving it the this 1401 | // value as its argument. 1402 | // 2. Let tv be ES.ToPrimitive(O, hint Number). 1403 | var O = $Object(this); 1404 | var tv = ES.ToPrimitive(O); 1405 | // 3. If tv is a Number and is not finite, return null. 1406 | if (typeof tv === 'number' && !isFinite(tv)) { 1407 | return null; 1408 | } 1409 | // 4. Let toISO be the result of calling the [[Get]] internal method of 1410 | // O with argument "toISOString". 1411 | var toISO = O.toISOString; 1412 | // 5. If IsCallable(toISO) is false, throw a TypeError exception. 1413 | if (!isCallable(toISO)) { 1414 | throw new TypeError('toISOString property is not callable'); 1415 | } 1416 | // 6. Return the result of calling the [[Call]] internal method of 1417 | // toISO with O as the this value and an empty argument list. 1418 | return toISO.call(O); 1419 | 1420 | // NOTE 1 The argument is ignored. 1421 | 1422 | // NOTE 2 The toJSON function is intentionally generic; it does not 1423 | // require that its this value be a Date object. Therefore, it can be 1424 | // transferred to other kinds of objects for use as a method. However, 1425 | // it does require that any such object have a toISOString method. An 1426 | // object is free to use the argument key to filter its 1427 | // stringification. 1428 | }; 1429 | } 1430 | 1431 | // ES5 15.9.4.2 1432 | // http://es5.github.com/#x15.9.4.2 1433 | // based on work shared by Daniel Friesen (dantman) 1434 | // http://gist.github.com/303249 1435 | var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; 1436 | var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z')); 1437 | var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); 1438 | if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { 1439 | // XXX global assignment won't work in embeddings that use 1440 | // an alternate object for the context. 1441 | /* global Date: true */ 1442 | var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1; 1443 | var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime()); 1444 | // eslint-disable-next-line no-implicit-globals, no-global-assign 1445 | Date = (function (NativeDate) { 1446 | // Date.length === 7 1447 | var DateShim = function Date(Y, M, D, h, m, s, ms) { 1448 | var length = arguments.length; 1449 | var date; 1450 | if (this instanceof NativeDate) { 1451 | var seconds = s; 1452 | var millis = ms; 1453 | if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) { 1454 | // work around a Safari 8/9 bug where it treats the seconds as signed 1455 | var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; 1456 | var sToShift = Math.floor(msToShift / 1e3); 1457 | seconds += sToShift; 1458 | millis -= sToShift * 1e3; 1459 | } 1460 | date = length === 1 && $String(Y) === Y // isString(Y) 1461 | // We explicitly pass it through parse: 1462 | ? new NativeDate(DateShim.parse(Y)) 1463 | // We have to manually make calls depending on argument 1464 | // length here 1465 | : length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) 1466 | : length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) 1467 | : length >= 5 ? new NativeDate(Y, M, D, h, m) 1468 | : length >= 4 ? new NativeDate(Y, M, D, h) 1469 | : length >= 3 ? new NativeDate(Y, M, D) 1470 | : length >= 2 ? new NativeDate(Y, M) 1471 | : length >= 1 ? new NativeDate(Y instanceof NativeDate ? +Y : Y) 1472 | : new NativeDate(); 1473 | } else { 1474 | date = NativeDate.apply(this, arguments); 1475 | } 1476 | if (!isPrimitive(date)) { 1477 | // Prevent mixups with unfixed Date object 1478 | defineProperties(date, { constructor: DateShim }, true); 1479 | } 1480 | return date; 1481 | }; 1482 | 1483 | // 15.9.1.15 Date Time String Format. 1484 | var isoDateExpression = new RegExp('^' 1485 | + '(\\d{4}|[+-]\\d{6})' // four-digit year capture or sign + 6-digit extended year 1486 | + '(?:-(\\d{2})' // optional month capture 1487 | + '(?:-(\\d{2})' // optional day capture 1488 | + '(?:' // capture hours:minutes:seconds.milliseconds 1489 | + 'T(\\d{2})' // hours capture 1490 | + ':(\\d{2})' // minutes capture 1491 | + '(?:' // optional :seconds.milliseconds 1492 | + ':(\\d{2})' // seconds capture 1493 | + '(?:(\\.\\d{1,}))?' // milliseconds capture 1494 | + ')?' 1495 | + '(' // capture UTC offset component 1496 | + 'Z|' // UTC capture 1497 | + '(?:' // offset specifier +/-hours:minutes 1498 | + '([-+])' // sign capture 1499 | + '(\\d{2})' // hours offset capture 1500 | + ':(\\d{2})' // minutes offset capture 1501 | + ')' 1502 | + ')?)?)?)?' 1503 | + '$'); 1504 | 1505 | var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; 1506 | 1507 | var dayFromMonth = function dayFromMonth(year, month) { 1508 | var t = month > 1 ? 1 : 0; 1509 | return ( 1510 | months[month] 1511 | + Math.floor((year - 1969 + t) / 4) 1512 | - Math.floor((year - 1901 + t) / 100) 1513 | + Math.floor((year - 1601 + t) / 400) 1514 | + (365 * (year - 1970)) 1515 | ); 1516 | }; 1517 | 1518 | var toUTC = function toUTC(t) { 1519 | var s = 0; 1520 | var ms = t; 1521 | if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) { 1522 | // work around a Safari 8/9 bug where it treats the seconds as signed 1523 | var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; 1524 | var sToShift = Math.floor(msToShift / 1e3); 1525 | s += sToShift; 1526 | ms -= sToShift * 1e3; 1527 | } 1528 | return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms)); 1529 | }; 1530 | 1531 | // Copy any custom methods a 3rd party library may have added 1532 | for (var key in NativeDate) { 1533 | if (owns(NativeDate, key)) { 1534 | DateShim[key] = NativeDate[key]; 1535 | } 1536 | } 1537 | 1538 | // Copy "native" methods explicitly; they may be non-enumerable 1539 | defineProperties(DateShim, { 1540 | now: NativeDate.now, 1541 | UTC: NativeDate.UTC 1542 | }, true); 1543 | DateShim.prototype = NativeDate.prototype; 1544 | defineProperties(DateShim.prototype, { constructor: DateShim }, true); 1545 | 1546 | // Upgrade Date.parse to handle simplified ISO 8601 strings 1547 | var parseShim = function parse(string) { 1548 | var match = isoDateExpression.exec(string); 1549 | if (match) { 1550 | // parse months, days, hours, minutes, seconds, and milliseconds 1551 | // provide default values if necessary 1552 | // parse the UTC offset component 1553 | var year = $Number(match[1]), 1554 | month = $Number(match[2] || 1) - 1, 1555 | day = $Number(match[3] || 1) - 1, 1556 | hour = $Number(match[4] || 0), 1557 | minute = $Number(match[5] || 0), 1558 | second = $Number(match[6] || 0), 1559 | millisecond = Math.floor($Number(match[7] || 0) * 1000), 1560 | // When time zone is missed, local offset should be used 1561 | // (ES 5.1 bug) 1562 | // see https://bugs.ecmascript.org/show_bug.cgi?id=112 1563 | isLocalTime = Boolean(match[4] && !match[8]), 1564 | signOffset = match[9] === '-' ? 1 : -1, 1565 | hourOffset = $Number(match[10] || 0), 1566 | minuteOffset = $Number(match[11] || 0), 1567 | result; 1568 | var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0; 1569 | if ( 1570 | hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) 1571 | && minute < 60 && second < 60 && millisecond < 1000 1572 | && month > -1 && month < 12 && hourOffset < 24 1573 | && minuteOffset < 60 // detect invalid offsets 1574 | && day > -1 1575 | && day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month)) 1576 | ) { 1577 | result = ( 1578 | ((dayFromMonth(year, month) + day) * 24) 1579 | + hour 1580 | + (hourOffset * signOffset) 1581 | ) * 60; 1582 | result = (( 1583 | ((result + minute + (minuteOffset * signOffset)) * 60) 1584 | + second 1585 | ) * 1000) + millisecond; 1586 | if (isLocalTime) { 1587 | result = toUTC(result); 1588 | } 1589 | if (-8.64e15 <= result && result <= 8.64e15) { 1590 | return result; 1591 | } 1592 | } 1593 | return NaN; 1594 | } 1595 | return NativeDate.parse.apply(this, arguments); 1596 | }; 1597 | defineProperties(DateShim, { parse: parseShim }); 1598 | 1599 | return DateShim; 1600 | }(Date)); 1601 | /* global Date: false */ 1602 | } 1603 | 1604 | // ES5 15.9.4.4 1605 | // http://es5.github.com/#x15.9.4.4 1606 | if (!Date.now) { 1607 | Date.now = function now() { 1608 | return new Date().getTime(); 1609 | }; 1610 | } 1611 | 1612 | // 1613 | // Number 1614 | // ====== 1615 | // 1616 | 1617 | // ES5.1 15.7.4.5 1618 | // http://es5.github.com/#x15.7.4.5 1619 | var hasToFixedBugs = NumberPrototype.toFixed && ( 1620 | (0.00008).toFixed(3) !== '0.000' 1621 | || (0.9).toFixed(0) !== '1' 1622 | || (1.255).toFixed(2) !== '1.25' 1623 | || (1000000000000000128).toFixed(0) !== '1000000000000000128' 1624 | ); 1625 | 1626 | var toFixedHelpers = { 1627 | base: 1e7, 1628 | size: 6, 1629 | data: [0, 0, 0, 0, 0, 0], 1630 | multiply: function multiply(n, c) { 1631 | var i = -1; 1632 | var c2 = c; 1633 | while (++i < toFixedHelpers.size) { 1634 | c2 += n * toFixedHelpers.data[i]; 1635 | toFixedHelpers.data[i] = c2 % toFixedHelpers.base; 1636 | c2 = Math.floor(c2 / toFixedHelpers.base); 1637 | } 1638 | }, 1639 | divide: function divide(n) { 1640 | var i = toFixedHelpers.size; 1641 | var c = 0; 1642 | while (--i >= 0) { 1643 | c += toFixedHelpers.data[i]; 1644 | toFixedHelpers.data[i] = Math.floor(c / n); 1645 | c = (c % n) * toFixedHelpers.base; 1646 | } 1647 | }, 1648 | numToString: function numToString() { 1649 | var i = toFixedHelpers.size; 1650 | var s = ''; 1651 | while (--i >= 0) { 1652 | if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { 1653 | var t = $String(toFixedHelpers.data[i]); 1654 | if (s === '') { 1655 | s = t; 1656 | } else { 1657 | s += strSlice('0000000', 0, 7 - t.length) + t; 1658 | } 1659 | } 1660 | } 1661 | return s; 1662 | }, 1663 | pow: function pow(x, n, acc) { 1664 | return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); 1665 | }, 1666 | log: function log(x) { 1667 | var n = 0; 1668 | var x2 = x; 1669 | while (x2 >= 4096) { 1670 | n += 12; 1671 | x2 /= 4096; 1672 | } 1673 | while (x2 >= 2) { 1674 | n += 1; 1675 | x2 /= 2; 1676 | } 1677 | return n; 1678 | } 1679 | }; 1680 | 1681 | var toFixedShim = function toFixed(fractionDigits) { 1682 | var f, x, s, m, e, z, j, k; 1683 | 1684 | // Test for NaN and round fractionDigits down 1685 | f = $Number(fractionDigits); 1686 | f = isActualNaN(f) ? 0 : Math.floor(f); 1687 | 1688 | if (f < 0 || f > 20) { 1689 | throw new RangeError('Number.toFixed called with invalid number of decimals'); 1690 | } 1691 | 1692 | x = $Number(this); 1693 | 1694 | if (isActualNaN(x)) { 1695 | return 'NaN'; 1696 | } 1697 | 1698 | // If it is too big or small, return the string value of the number 1699 | if (x <= -1e21 || x >= 1e21) { 1700 | return $String(x); 1701 | } 1702 | 1703 | s = ''; 1704 | 1705 | if (x < 0) { 1706 | s = '-'; 1707 | x = -x; 1708 | } 1709 | 1710 | m = '0'; 1711 | 1712 | if (x > 1e-21) { 1713 | // 1e-21 < x < 1e21 1714 | // -70 < log2(x) < 70 1715 | e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; 1716 | z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); 1717 | z *= 0x10000000000000; // Math.pow(2, 52); 1718 | e = 52 - e; 1719 | 1720 | // -18 < e < 122 1721 | // x = z / 2 ^ e 1722 | if (e > 0) { 1723 | toFixedHelpers.multiply(0, z); 1724 | j = f; 1725 | 1726 | while (j >= 7) { 1727 | toFixedHelpers.multiply(1e7, 0); 1728 | j -= 7; 1729 | } 1730 | 1731 | toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); 1732 | j = e - 1; 1733 | 1734 | while (j >= 23) { 1735 | toFixedHelpers.divide(1 << 23); 1736 | j -= 23; 1737 | } 1738 | 1739 | toFixedHelpers.divide(1 << j); 1740 | toFixedHelpers.multiply(1, 1); 1741 | toFixedHelpers.divide(2); 1742 | m = toFixedHelpers.numToString(); 1743 | } else { 1744 | toFixedHelpers.multiply(0, z); 1745 | toFixedHelpers.multiply(1 << (-e), 0); 1746 | m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f); 1747 | } 1748 | } 1749 | 1750 | if (f > 0) { 1751 | k = m.length; 1752 | 1753 | if (k <= f) { 1754 | m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m; 1755 | } else { 1756 | m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f); 1757 | } 1758 | } else { 1759 | m = s + m; 1760 | } 1761 | 1762 | return m; 1763 | }; 1764 | defineProperties(NumberPrototype, { toFixed: toFixedShim }, hasToFixedBugs); 1765 | 1766 | var hasToPrecisionUndefinedBug = (function () { 1767 | try { 1768 | return 1.0.toPrecision(undefined) === '1'; 1769 | } catch (e) { 1770 | return true; 1771 | } 1772 | }()); 1773 | var originalToPrecision = NumberPrototype.toPrecision; 1774 | defineProperties(NumberPrototype, { 1775 | toPrecision: function toPrecision(precision) { 1776 | return typeof precision === 'undefined' ? originalToPrecision.call(this) : originalToPrecision.call(this, precision); 1777 | } 1778 | }, hasToPrecisionUndefinedBug); 1779 | 1780 | // 1781 | // String 1782 | // ====== 1783 | // 1784 | 1785 | // ES5 15.5.4.14 1786 | // http://es5.github.com/#x15.5.4.14 1787 | 1788 | // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] 1789 | // Many browsers do not split properly with regular expressions or they 1790 | // do not perform the split correctly under obscure conditions. 1791 | // See http://blog.stevenlevithan.com/archives/cross-browser-split 1792 | // I've tested in many browsers and this seems to cover the deviant ones: 1793 | // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] 1794 | // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] 1795 | // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not 1796 | // [undefined, "t", undefined, "e", ...] 1797 | // ''.split(/.?/) should be [], not [""] 1798 | // '.'.split(/()()/) should be ["."], not ["", "", "."] 1799 | 1800 | if ( 1801 | 'ab'.split(/(?:ab)*/).length !== 2 1802 | || '.'.split(/(.?)(.?)/).length !== 4 1803 | || 'tesst'.split(/(s)*/)[1] === 't' 1804 | || 'test'.split(/(?:)/, -1).length !== 4 1805 | || ''.split(/.?/).length 1806 | || '.'.split(/()()/).length > 1 1807 | ) { 1808 | (function () { 1809 | var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group 1810 | var maxSafe32BitInt = Math.pow(2, 32) - 1; 1811 | 1812 | StringPrototype.split = function (separator, limit) { 1813 | var string = String(this); 1814 | if (typeof separator === 'undefined' && limit === 0) { 1815 | return []; 1816 | } 1817 | 1818 | // If `separator` is not a regex, use native split 1819 | if (!isRegex(separator)) { 1820 | return strSplit(this, separator, limit); 1821 | } 1822 | 1823 | var output = []; 1824 | var flags = (separator.ignoreCase ? 'i' : '') 1825 | + (separator.multiline ? 'm' : '') 1826 | + (separator.unicode ? 'u' : '') // in ES6 1827 | + (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6 1828 | lastLastIndex = 0, 1829 | // Make `global` and avoid `lastIndex` issues by working with a copy 1830 | separator2, match, lastIndex, lastLength; 1831 | var separatorCopy = new RegExp(separator.source, flags + 'g'); 1832 | if (!compliantExecNpcg) { 1833 | // Doesn't need flags gy, but they don't hurt 1834 | separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); 1835 | } 1836 | /* Values for `limit`, per the spec: 1837 | * If undefined: 4294967295 // maxSafe32BitInt 1838 | * If 0, Infinity, or NaN: 0 1839 | * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; 1840 | * If negative number: 4294967296 - Math.floor(Math.abs(limit)) 1841 | * If other: Type-convert, then use the above rules 1842 | */ 1843 | var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit); 1844 | match = separatorCopy.exec(string); 1845 | while (match) { 1846 | // `separatorCopy.lastIndex` is not reliable cross-browser 1847 | lastIndex = match.index + match[0].length; 1848 | if (lastIndex > lastLastIndex) { 1849 | pushCall(output, strSlice(string, lastLastIndex, match.index)); 1850 | // Fix browsers whose `exec` methods don't consistently return `undefined` for 1851 | // nonparticipating capturing groups 1852 | if (!compliantExecNpcg && match.length > 1) { 1853 | /* eslint-disable no-loop-func */ 1854 | match[0].replace(separator2, function () { 1855 | for (var i = 1; i < arguments.length - 2; i++) { 1856 | if (typeof arguments[i] === 'undefined') { 1857 | match[i] = void 0; 1858 | } 1859 | } 1860 | }); 1861 | /* eslint-enable no-loop-func */ 1862 | } 1863 | if (match.length > 1 && match.index < string.length) { 1864 | array_push.apply(output, arraySlice(match, 1)); 1865 | } 1866 | lastLength = match[0].length; 1867 | lastLastIndex = lastIndex; 1868 | if (output.length >= splitLimit) { 1869 | break; 1870 | } 1871 | } 1872 | if (separatorCopy.lastIndex === match.index) { 1873 | separatorCopy.lastIndex++; // Avoid an infinite loop 1874 | } 1875 | match = separatorCopy.exec(string); 1876 | } 1877 | if (lastLastIndex === string.length) { 1878 | if (lastLength || !separatorCopy.test('')) { 1879 | pushCall(output, ''); 1880 | } 1881 | } else { 1882 | pushCall(output, strSlice(string, lastLastIndex)); 1883 | } 1884 | return output.length > splitLimit ? arraySlice(output, 0, splitLimit) : output; 1885 | }; 1886 | }()); 1887 | 1888 | // [bugfix, chrome] 1889 | // If separator is undefined, then the result array contains just one String, 1890 | // which is the this value (converted to a String). If limit is not undefined, 1891 | // then the output array is truncated so that it contains no more than limit 1892 | // elements. 1893 | // "0".split(undefined, 0) -> [] 1894 | } else if ('0'.split(void 0, 0).length) { 1895 | StringPrototype.split = function split(separator, limit) { 1896 | if (typeof separator === 'undefined' && limit === 0) { 1897 | return []; 1898 | } 1899 | return strSplit(this, separator, limit); 1900 | }; 1901 | } 1902 | 1903 | var str_replace = StringPrototype.replace; 1904 | var replaceReportsGroupsCorrectly = (function () { 1905 | var groups = []; 1906 | 'x'.replace(/x(.)?/g, function (match, group) { 1907 | pushCall(groups, group); 1908 | }); 1909 | return groups.length === 1 && typeof groups[0] === 'undefined'; 1910 | }()); 1911 | 1912 | if (!replaceReportsGroupsCorrectly) { 1913 | StringPrototype.replace = function replace(searchValue, replaceValue) { 1914 | var isFn = isCallable(replaceValue); 1915 | var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); 1916 | if (!isFn || !hasCapturingGroups) { 1917 | return str_replace.call(this, searchValue, replaceValue); 1918 | } else { 1919 | var wrappedReplaceValue = function (match) { 1920 | var length = arguments.length; 1921 | var originalLastIndex = searchValue.lastIndex; 1922 | searchValue.lastIndex = 0; 1923 | var args = searchValue.exec(match) || []; 1924 | searchValue.lastIndex = originalLastIndex; 1925 | pushCall(args, arguments[length - 2], arguments[length - 1]); 1926 | return replaceValue.apply(this, args); 1927 | }; 1928 | return str_replace.call(this, searchValue, wrappedReplaceValue); 1929 | } 1930 | }; 1931 | } 1932 | 1933 | // ECMA-262, 3rd B.2.3 1934 | // Not an ECMAScript standard, although ECMAScript 3rd Edition has a 1935 | // non-normative section suggesting uniform semantics and it should be 1936 | // normalized across all browsers 1937 | // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE 1938 | var string_substr = StringPrototype.substr; 1939 | var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; 1940 | defineProperties(StringPrototype, { 1941 | substr: function substr(start, length) { 1942 | var normalizedStart = start; 1943 | if (start < 0) { 1944 | normalizedStart = max(this.length + start, 0); 1945 | } 1946 | return string_substr.call(this, normalizedStart, length); 1947 | } 1948 | }, hasNegativeSubstrBug); 1949 | 1950 | // ES5 15.5.4.20 1951 | // whitespace from: http://es5.github.io/#x15.5.4.20 1952 | var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' 1953 | + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' 1954 | + '\u2029\uFEFF'; 1955 | var zeroWidth = '\u200b'; 1956 | var wsRegexChars = '[' + ws + ']'; 1957 | var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); 1958 | var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); 1959 | var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); 1960 | defineProperties(StringPrototype, { 1961 | // http://blog.stevenlevithan.com/archives/faster-trim-javascript 1962 | // http://perfectionkills.com/whitespace-deviations/ 1963 | trim: function trim() { 1964 | if (typeof this === 'undefined' || this === null) { 1965 | throw new TypeError("can't convert " + this + ' to object'); 1966 | } 1967 | return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); 1968 | } 1969 | }, hasTrimWhitespaceBug); 1970 | var trim = call.bind(String.prototype.trim); 1971 | 1972 | var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1; 1973 | defineProperties(StringPrototype, { 1974 | lastIndexOf: function lastIndexOf(searchString) { 1975 | if (typeof this === 'undefined' || this === null) { 1976 | throw new TypeError("can't convert " + this + ' to object'); 1977 | } 1978 | var S = $String(this); 1979 | var searchStr = $String(searchString); 1980 | var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN; 1981 | var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos); 1982 | var start = min(max(pos, 0), S.length); 1983 | var searchLen = searchStr.length; 1984 | var k = start + searchLen; 1985 | while (k > 0) { 1986 | k = max(0, k - searchLen); 1987 | var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr); 1988 | if (index !== -1) { 1989 | return k + index; 1990 | } 1991 | } 1992 | return -1; 1993 | } 1994 | }, hasLastIndexBug); 1995 | 1996 | var originalLastIndexOf = StringPrototype.lastIndexOf; 1997 | defineProperties(StringPrototype, { 1998 | lastIndexOf: function lastIndexOf(searchString) { 1999 | return originalLastIndexOf.apply(this, arguments); 2000 | } 2001 | }, StringPrototype.lastIndexOf.length !== 1); 2002 | 2003 | // ES-5 15.1.2.2 2004 | // eslint-disable-next-line radix 2005 | if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { 2006 | /* global parseInt: true */ 2007 | parseInt = (function (origParseInt) { 2008 | var hexRegex = /^[-+]?0[xX]/; 2009 | return function parseInt(str, radix) { 2010 | if (typeof str === 'symbol') { 2011 | // handle Symbols in node 8.3/8.4 2012 | // eslint-disable-next-line no-implicit-coercion, no-unused-expressions 2013 | '' + str; // jscs:ignore disallowImplicitTypeConversion 2014 | } 2015 | 2016 | var string = trim(String(str)); 2017 | var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); 2018 | return origParseInt(string, defaultedRadix); 2019 | }; 2020 | }(parseInt)); 2021 | } 2022 | 2023 | // https://es5.github.io/#x15.1.2.3 2024 | if (1 / parseFloat('-0') !== -Infinity) { 2025 | /* global parseFloat: true */ 2026 | parseFloat = (function (origParseFloat) { 2027 | return function parseFloat(string) { 2028 | var inputString = trim(String(string)); 2029 | var result = origParseFloat(inputString); 2030 | return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result; 2031 | }; 2032 | }(parseFloat)); 2033 | } 2034 | 2035 | if (String(new RangeError('test')) !== 'RangeError: test') { 2036 | var errorToStringShim = function toString() { 2037 | if (typeof this === 'undefined' || this === null) { 2038 | throw new TypeError("can't convert " + this + ' to object'); 2039 | } 2040 | var name = this.name; 2041 | if (typeof name === 'undefined') { 2042 | name = 'Error'; 2043 | } else if (typeof name !== 'string') { 2044 | name = $String(name); 2045 | } 2046 | var msg = this.message; 2047 | if (typeof msg === 'undefined') { 2048 | msg = ''; 2049 | } else if (typeof msg !== 'string') { 2050 | msg = $String(msg); 2051 | } 2052 | if (!name) { 2053 | return msg; 2054 | } 2055 | if (!msg) { 2056 | return name; 2057 | } 2058 | return name + ': ' + msg; 2059 | }; 2060 | // can't use defineProperties here because of toString enumeration issue in IE <= 8 2061 | Error.prototype.toString = errorToStringShim; 2062 | } 2063 | 2064 | if (supportsDescriptors) { 2065 | var ensureNonEnumerable = function (obj, prop) { 2066 | if (isEnum(obj, prop)) { 2067 | var desc = Object.getOwnPropertyDescriptor(obj, prop); 2068 | if (desc.configurable) { 2069 | desc.enumerable = false; 2070 | Object.defineProperty(obj, prop, desc); 2071 | } 2072 | } 2073 | }; 2074 | ensureNonEnumerable(Error.prototype, 'message'); 2075 | if (Error.prototype.message !== '') { 2076 | Error.prototype.message = ''; 2077 | } 2078 | ensureNonEnumerable(Error.prototype, 'name'); 2079 | } 2080 | 2081 | if (String(/a/mig) !== '/a/gim') { 2082 | var regexToString = function toString() { 2083 | var str = '/' + this.source + '/'; 2084 | if (this.global) { 2085 | str += 'g'; 2086 | } 2087 | if (this.ignoreCase) { 2088 | str += 'i'; 2089 | } 2090 | if (this.multiline) { 2091 | str += 'm'; 2092 | } 2093 | return str; 2094 | }; 2095 | // can't use defineProperties here because of toString enumeration issue in IE <= 8 2096 | RegExp.prototype.toString = regexToString; 2097 | } 2098 | })); --------------------------------------------------------------------------------