├── .gitignore ├── .npmrc ├── .travis.yml ├── Gruntfile.js ├── README.md ├── bower.json ├── bower_components └── es5-shim │ └── es5-shim.js ├── console-log-div.js ├── demo.html ├── images ├── console-log-demo.png └── console-log-div.png ├── package.json ├── test ├── existing.html └── index.html └── utils ├── .jshintrc ├── eslint.json └── jscs.json /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | node_modules/ 3 | .grunt/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=http://registry.npmjs.org/ 2 | save-exact=true 3 | progress=false 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: false 8 | node_js: 9 | - '4' 10 | before_install: 11 | - npm i -g npm@^2.0.0 12 | before_script: 13 | - npm prune 14 | after_success: 15 | - npm run semantic-release 16 | branches: 17 | except: 18 | - "/^v\\d+\\.\\d+\\.\\d+$/" 19 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function (grunt) { 3 | var sourceFiles = ['console-log-div.js']; 4 | var testPages = ['test/index.html', 'test/existing.html']; 5 | 6 | grunt.initConfig({ 7 | 8 | filenames: { 9 | options: { 10 | valid: 'dashes', 11 | except: 'verify-md5.js' 12 | }, 13 | src: sourceFiles 14 | }, 15 | 16 | jshint: { 17 | all: sourceFiles, 18 | options: { 19 | jshintrc: 'utils/.jshintrc', 20 | reporter: require('jshint-summary') 21 | } 22 | }, 23 | 24 | eslint: { 25 | target: sourceFiles, 26 | options: { 27 | config: 'utils/eslint.json', 28 | rulesdir: ['./node_modules/eslint-rules'] 29 | } 30 | }, 31 | 32 | jscs: { 33 | src: sourceFiles, 34 | options: { 35 | config: 'utils/jscs.json' 36 | } 37 | }, 38 | 39 | 'clean-console': { 40 | test: { 41 | options: { 42 | url: testPages, 43 | timeout: 1 // seconds to wait for any errors, 44 | } 45 | } 46 | }, 47 | 48 | 'gh-pages': { 49 | options: { 50 | base: '.' 51 | }, 52 | src: [ 53 | 'README.md', 54 | 'console-log-div.js', 55 | 'test/index.html', 56 | 'test/existing.html', 57 | 'bower_components/es5-shim/es5-shim.js' 58 | ] 59 | } 60 | }); 61 | 62 | var plugins = module.require('matchdep').filterDev('grunt-*'); 63 | plugins.forEach(grunt.loadNpmTasks); 64 | 65 | grunt.registerTask('lint', ['filenames', 'jshint', 'eslint', 'jscs']); 66 | grunt.registerTask('test', ['clean-console']); 67 | grunt.registerTask('default', ['deps-ok', 'nice-package', 'lint', 'sync']); 68 | }; 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # console-log-div 2 | 3 | > Clones console.log calls to a created div in the page. Great for demos and experiments. 4 | 5 | [Demo](http://glebbahmutov.com/console-log-div/test/index.html), 6 | [Better short JS demos blog post](http://glebbahmutov.com/blog/better-short-javascript-demos/) 7 | 8 | [![NPM][console-log-div-icon] ][console-log-div-url] 9 | 10 | [![Build status][console-log-div-ci-image] ][console-log-div-ci-url] 11 | [![dependencies][console-log-div-dependencies-image] ][console-log-div-dependencies-url] 12 | [![devdependencies][console-log-div-devdependencies-image] ][console-log-div-devdependencies-url] 13 | [![semantic-release][semantic-image] ][semantic-url] 14 | 15 | ![console-log-div image][console-log-div image] 16 | 17 | ## Use 18 | 19 | * Grab using npm or bower under name `console-log-div`. 20 | * Include 'console-log-div.js' in your page. `console.log` calls will be shown in the div on the page. 21 | 22 | ``` 23 | 24 | ``` 25 | 26 | The created element will have class `.console-log-div` and id `console-log-div` thus you can style it. 27 | The inner text will has id `console-log-text`. 28 | 29 | ``` 30 | 39 | ``` 40 | 41 | ## Customize existing fieldset 42 | 43 | Instead of adding a new element at the end of the body, you can mirror console output to an existing `fieldset` 44 | element. Just give it id `console-log-div`. 45 | 46 |
47 |

The fieldset above will mirror console.log calls

48 | 49 | 50 | I used `fieldset` tag to place an html5 label on the top border. 51 | 52 | ## jsFiddle demos 53 | 54 | When showing demos on [jsfiddle][jsfiddle] or [plnkr][plnkr] 55 | you can use RawGit proxy 56 | 57 | ```html 58 | 59 | ``` 60 | 61 | [jsfiddle]: http://jsfiddle.net/ 62 | [plnkr]: http://plnkr.co/ 63 | 64 | ## Handling exceptions 65 | 66 | This library installs window error event listener, and prints the exception's message and location. 67 | For example throwing an error like this `throw new Error('this is a thrown error');` will generate text output 68 | 69 | EXCEPTION: Uncaught Error: this is a thrown error 70 | file:///console-log-div/test/index.html 39:13 71 | 72 | ## Console methods 73 | 74 | The following methods are mirrored into the div: `console.log, .warn, .error and .table`. 75 | 76 | ### Small print 77 | 78 | Author: Gleb Bahmutov © 2015 79 | 80 | * [@bahmutov](https://twitter.com/bahmutov) 81 | * [glebbahmutov.com](http://glebbahmutov.com) 82 | * [blog](http://glebbahmutov.com/blog) 83 | 84 | License: MIT - do anything with the code, but don't blame me if it does not work. 85 | 86 | Spread the word: tweet, star on github, etc. 87 | 88 | Support: if you find any problems with this module, email / tweet / 89 | [open issue](https://github.com/bahmutov/console-log-div/issues) on Github 90 | 91 | ## MIT License 92 | 93 | Copyright (c) 2015 Gleb Bahmutov 94 | 95 | Permission is hereby granted, free of charge, to any person 96 | obtaining a copy of this software and associated documentation 97 | files (the "Software"), to deal in the Software without 98 | restriction, including without limitation the rights to use, 99 | copy, modify, merge, publish, distribute, sublicense, and/or sell 100 | copies of the Software, and to permit persons to whom the 101 | Software is furnished to do so, subject to the following 102 | conditions: 103 | 104 | The above copyright notice and this permission notice shall be 105 | included in all copies or substantial portions of the Software. 106 | 107 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 108 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 109 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 110 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 111 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 112 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 113 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 114 | OTHER DEALINGS IN THE SOFTWARE. 115 | 116 | [console-log-div-icon]: https://nodei.co/npm/console-log-div.png?downloads=true 117 | [console-log-div-url]: https://npmjs.org/package/console-log-div 118 | [console-log-div-ci-image]: https://travis-ci.org/bahmutov/console-log-div.png?branch=master 119 | [console-log-div-ci-url]: https://travis-ci.org/bahmutov/console-log-div 120 | [console-log-div-dependencies-image]: https://david-dm.org/bahmutov/console-log-div.png 121 | [console-log-div-dependencies-url]: https://david-dm.org/bahmutov/console-log-div 122 | [console-log-div-devdependencies-image]: https://david-dm.org/bahmutov/console-log-div/dev-status.png 123 | [console-log-div-devdependencies-url]: https://david-dm.org/bahmutov/console-log-div#info=devDependencies 124 | [console-log-div image]: images/console-log-div.png 125 | [semantic-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg 126 | [semantic-url]: https://github.com/semantic-release/semantic-release 127 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "authors": [ 3 | "Gleb Bahmutov " 4 | ], 5 | "name": "console-log-div", 6 | "version": "0.0.0-semantic-release", 7 | "description": "Clones console.log calls to a created div in the page. Great for demos and experiments.", 8 | "license": "MIT", 9 | "homepage": "https://github.com/bahmutov/console-log-div", 10 | "keywords": [ 11 | "browser", 12 | "clone", 13 | "console", 14 | "div", 15 | "element", 16 | "log", 17 | "message", 18 | "page", 19 | "show", 20 | "visible" 21 | ] 22 | } -------------------------------------------------------------------------------- /bower_components/es5-shim/es5-shim.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/es-shims/es5-shim 3 | * @license es5-shim Copyright 2009-2014 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 | 10 | // UMD (Universal Module Definition) 11 | // see https://github.com/umdjs/umd/blob/master/returnExports.js 12 | // Add semicolon to prevent IIFE from being passed as argument to concatenated code. 13 | ;(function (root, factory) { 14 | 'use strict'; 15 | /*global define, exports, module */ 16 | if (typeof define === 'function' && define.amd) { 17 | // AMD. Register as an anonymous module. 18 | define(factory); 19 | } else if (typeof exports === 'object') { 20 | // Node. Does not work with strict CommonJS, but 21 | // only CommonJS-like enviroments that support module.exports, 22 | // like Node. 23 | module.exports = factory(); 24 | } else { 25 | // Browser globals (root is window) 26 | root.returnExports = factory(); 27 | } 28 | }(this, function () { 29 | 30 | /** 31 | * Brings an environment as close to ECMAScript 5 compliance 32 | * as is possible with the facilities of erstwhile engines. 33 | * 34 | * Annotated ES5: http://es5.github.com/ (specific links below) 35 | * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 36 | * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ 37 | */ 38 | 39 | // Shortcut to an often accessed properties, in order to avoid multiple 40 | // dereference that costs universally. 41 | var ArrayPrototype = Array.prototype; 42 | var ObjectPrototype = Object.prototype; 43 | var FunctionPrototype = Function.prototype; 44 | var StringPrototype = String.prototype; 45 | var NumberPrototype = Number.prototype; 46 | var array_slice = ArrayPrototype.slice; 47 | var array_splice = ArrayPrototype.splice; 48 | var array_push = ArrayPrototype.push; 49 | var array_unshift = ArrayPrototype.unshift; 50 | var call = FunctionPrototype.call; 51 | 52 | // Having a toString local variable name breaks in Opera so use to_string. 53 | var to_string = ObjectPrototype.toString; 54 | 55 | var isFunction = function (val) { 56 | return to_string.call(val) === '[object Function]'; 57 | }; 58 | var isRegex = function (val) { 59 | return to_string.call(val) === '[object RegExp]'; 60 | }; 61 | var isArray = function isArray(obj) { 62 | return to_string.call(obj) === '[object Array]'; 63 | }; 64 | var isString = function isString(obj) { 65 | return to_string.call(obj) === '[object String]'; 66 | }; 67 | var isArguments = function isArguments(value) { 68 | var str = to_string.call(value); 69 | var isArgs = str === '[object Arguments]'; 70 | if (!isArgs) { 71 | isArgs = !isArray(value) && 72 | value !== null && 73 | typeof value === 'object' && 74 | typeof value.length === 'number' && 75 | value.length >= 0 && 76 | isFunction(value.callee); 77 | } 78 | return isArgs; 79 | }; 80 | 81 | var supportsDescriptors = Object.defineProperty && (function () { 82 | try { 83 | Object.defineProperty({}, 'x', {}); 84 | return true; 85 | } catch (e) { /* this is ES3 */ 86 | return false; 87 | } 88 | }()); 89 | 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)) { return; } 96 | Object.defineProperty(object, name, { 97 | configurable: true, 98 | enumerable: false, 99 | writable: true, 100 | value: method 101 | }); 102 | }; 103 | } else { 104 | defineProperty = function (object, name, method, forceAssign) { 105 | if (!forceAssign && (name in object)) { return; } 106 | object[name] = method; 107 | }; 108 | } 109 | var defineProperties = function (object, map, forceAssign) { 110 | for (var name in map) { 111 | if (ObjectPrototype.hasOwnProperty.call(map, name)) { 112 | defineProperty(object, name, map[name], forceAssign); 113 | } 114 | } 115 | }; 116 | 117 | // 118 | // Util 119 | // ====== 120 | // 121 | 122 | // ES5 9.4 123 | // http://es5.github.com/#x9.4 124 | // http://jsperf.com/to-integer 125 | 126 | function toInteger(num) { 127 | var n = +num; 128 | if (n !== n) { // isNaN 129 | n = 0; 130 | } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { 131 | n = (n > 0 || -1) * Math.floor(Math.abs(n)); 132 | } 133 | return n; 134 | } 135 | 136 | function isPrimitive(input) { 137 | var type = typeof input; 138 | return input === null || 139 | type === 'undefined' || 140 | type === 'boolean' || 141 | type === 'number' || 142 | type === 'string'; 143 | } 144 | 145 | function toPrimitive(input) { 146 | var val, valueOf, toStr; 147 | if (isPrimitive(input)) { 148 | return input; 149 | } 150 | valueOf = input.valueOf; 151 | if (isFunction(valueOf)) { 152 | val = valueOf.call(input); 153 | if (isPrimitive(val)) { 154 | return val; 155 | } 156 | } 157 | toStr = input.toString; 158 | if (isFunction(toStr)) { 159 | val = toStr.call(input); 160 | if (isPrimitive(val)) { 161 | return val; 162 | } 163 | } 164 | throw new TypeError(); 165 | } 166 | 167 | var ES = { 168 | // ES5 9.9 169 | // http://es5.github.com/#x9.9 170 | ToObject: function (o) { 171 | /*jshint eqnull: true */ 172 | if (o == null) { // this matches both null and undefined 173 | throw new TypeError("can't convert " + o + ' to object'); 174 | } 175 | return Object(o); 176 | }, 177 | ToUint32: function ToUint32(x) { 178 | return x >>> 0; 179 | } 180 | }; 181 | 182 | // 183 | // Function 184 | // ======== 185 | // 186 | 187 | // ES-5 15.3.4.5 188 | // http://es5.github.com/#x15.3.4.5 189 | 190 | var Empty = function Empty() {}; 191 | 192 | defineProperties(FunctionPrototype, { 193 | bind: function bind(that) { // .length is 1 194 | // 1. Let Target be the this value. 195 | var target = this; 196 | // 2. If IsCallable(Target) is false, throw a TypeError exception. 197 | if (!isFunction(target)) { 198 | throw new TypeError('Function.prototype.bind called on incompatible ' + target); 199 | } 200 | // 3. Let A be a new (possibly empty) internal list of all of the 201 | // argument values provided after thisArg (arg1, arg2 etc), in order. 202 | // XXX slicedArgs will stand in for "A" if used 203 | var args = array_slice.call(arguments, 1); // for normal call 204 | // 4. Let F be a new native ECMAScript object. 205 | // 11. Set the [[Prototype]] internal property of F to the standard 206 | // built-in Function prototype object as specified in 15.3.3.1. 207 | // 12. Set the [[Call]] internal property of F as described in 208 | // 15.3.4.5.1. 209 | // 13. Set the [[Construct]] internal property of F as described in 210 | // 15.3.4.5.2. 211 | // 14. Set the [[HasInstance]] internal property of F as described in 212 | // 15.3.4.5.3. 213 | var bound; 214 | var binder = function () { 215 | 216 | if (this instanceof bound) { 217 | // 15.3.4.5.2 [[Construct]] 218 | // When the [[Construct]] internal method of a function object, 219 | // F that was created using the bind function is called with a 220 | // list of arguments ExtraArgs, the following steps are taken: 221 | // 1. Let target be the value of F's [[TargetFunction]] 222 | // internal property. 223 | // 2. If target has no [[Construct]] internal method, a 224 | // TypeError exception is thrown. 225 | // 3. Let boundArgs be the value of F's [[BoundArgs]] internal 226 | // property. 227 | // 4. Let args be a new list containing the same values as the 228 | // list boundArgs in the same order followed by the same 229 | // values as the list ExtraArgs in the same order. 230 | // 5. Return the result of calling the [[Construct]] internal 231 | // method of target providing args as the arguments. 232 | 233 | var result = target.apply( 234 | this, 235 | args.concat(array_slice.call(arguments)) 236 | ); 237 | if (Object(result) === result) { 238 | return result; 239 | } 240 | return this; 241 | 242 | } else { 243 | // 15.3.4.5.1 [[Call]] 244 | // When the [[Call]] internal method of a function object, F, 245 | // which was created using the bind function is called with a 246 | // this value and a list of arguments ExtraArgs, the following 247 | // steps are taken: 248 | // 1. Let boundArgs be the value of F's [[BoundArgs]] internal 249 | // property. 250 | // 2. Let boundThis be the value of F's [[BoundThis]] internal 251 | // property. 252 | // 3. Let target be the value of F's [[TargetFunction]] internal 253 | // property. 254 | // 4. Let args be a new list containing the same values as the 255 | // list boundArgs in the same order followed by the same 256 | // values as the list ExtraArgs in the same order. 257 | // 5. Return the result of calling the [[Call]] internal method 258 | // of target providing boundThis as the this value and 259 | // providing args as the arguments. 260 | 261 | // equiv: target.call(this, ...boundArgs, ...args) 262 | return target.apply( 263 | that, 264 | args.concat(array_slice.call(arguments)) 265 | ); 266 | 267 | } 268 | 269 | }; 270 | 271 | // 15. If the [[Class]] internal property of Target is "Function", then 272 | // a. Let L be the length property of Target minus the length of A. 273 | // b. Set the length own property of F to either 0 or L, whichever is 274 | // larger. 275 | // 16. Else set the length own property of F to 0. 276 | 277 | var boundLength = Math.max(0, target.length - args.length); 278 | 279 | // 17. Set the attributes of the length own property of F to the values 280 | // specified in 15.3.5.1. 281 | var boundArgs = []; 282 | for (var i = 0; i < boundLength; i++) { 283 | boundArgs.push('$' + i); 284 | } 285 | 286 | // XXX Build a dynamic function with desired amount of arguments is the only 287 | // way to set the length property of a function. 288 | // In environments where Content Security Policies enabled (Chrome extensions, 289 | // for ex.) all use of eval or Function costructor throws an exception. 290 | // However in all of these environments Function.prototype.bind exists 291 | // and so this code will never be executed. 292 | bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder); 293 | 294 | if (target.prototype) { 295 | Empty.prototype = target.prototype; 296 | bound.prototype = new Empty(); 297 | // Clean up dangling references. 298 | Empty.prototype = null; 299 | } 300 | 301 | // TODO 302 | // 18. Set the [[Extensible]] internal property of F to true. 303 | 304 | // TODO 305 | // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). 306 | // 20. Call the [[DefineOwnProperty]] internal method of F with 307 | // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: 308 | // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and 309 | // false. 310 | // 21. Call the [[DefineOwnProperty]] internal method of F with 311 | // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, 312 | // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, 313 | // and false. 314 | 315 | // TODO 316 | // NOTE Function objects created using Function.prototype.bind do not 317 | // have a prototype property or the [[Code]], [[FormalParameters]], and 318 | // [[Scope]] internal properties. 319 | // XXX can't delete prototype in pure-js. 320 | 321 | // 22. Return F. 322 | return bound; 323 | } 324 | }); 325 | 326 | // _Please note: Shortcuts are defined after `Function.prototype.bind` as we 327 | // us it in defining shortcuts. 328 | var owns = call.bind(ObjectPrototype.hasOwnProperty); 329 | 330 | // 331 | // Array 332 | // ===== 333 | // 334 | 335 | // ES5 15.4.4.12 336 | // http://es5.github.com/#x15.4.4.12 337 | var spliceNoopReturnsEmptyArray = (function () { 338 | var a = [1, 2]; 339 | var result = a.splice(); 340 | return a.length === 2 && isArray(result) && result.length === 0; 341 | }()); 342 | defineProperties(ArrayPrototype, { 343 | // Safari 5.0 bug where .splice() returns undefined 344 | splice: function splice(start, deleteCount) { 345 | if (arguments.length === 0) { 346 | return []; 347 | } else { 348 | return array_splice.apply(this, arguments); 349 | } 350 | } 351 | }, spliceNoopReturnsEmptyArray); 352 | 353 | var spliceWorksWithEmptyObject = (function () { 354 | var obj = {}; 355 | ArrayPrototype.splice.call(obj, 0, 0, 1); 356 | return obj.length === 1; 357 | }()); 358 | defineProperties(ArrayPrototype, { 359 | splice: function splice(start, deleteCount) { 360 | if (arguments.length === 0) { return []; } 361 | var args = arguments; 362 | this.length = Math.max(toInteger(this.length), 0); 363 | if (arguments.length > 0 && typeof deleteCount !== 'number') { 364 | args = array_slice.call(arguments); 365 | if (args.length < 2) { 366 | args.push(this.length - start); 367 | } else { 368 | args[1] = toInteger(deleteCount); 369 | } 370 | } 371 | return array_splice.apply(this, args); 372 | } 373 | }, !spliceWorksWithEmptyObject); 374 | 375 | // ES5 15.4.4.12 376 | // http://es5.github.com/#x15.4.4.13 377 | // Return len+argCount. 378 | // [bugfix, ielt8] 379 | // IE < 8 bug: [].unshift(0) === undefined but should be "1" 380 | var hasUnshiftReturnValueBug = [].unshift(0) !== 1; 381 | defineProperties(ArrayPrototype, { 382 | unshift: function () { 383 | array_unshift.apply(this, arguments); 384 | return this.length; 385 | } 386 | }, hasUnshiftReturnValueBug); 387 | 388 | // ES5 15.4.3.2 389 | // http://es5.github.com/#x15.4.3.2 390 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray 391 | defineProperties(Array, { isArray: isArray }); 392 | 393 | // The IsCallable() check in the Array functions 394 | // has been replaced with a strict check on the 395 | // internal class of the object to trap cases where 396 | // the provided function was actually a regular 397 | // expression literal, which in V8 and 398 | // JavaScriptCore is a typeof "function". Only in 399 | // V8 are regular expression literals permitted as 400 | // reduce parameters, so it is desirable in the 401 | // general case for the shim to match the more 402 | // strict and common behavior of rejecting regular 403 | // expressions. 404 | 405 | // ES5 15.4.4.18 406 | // http://es5.github.com/#x15.4.4.18 407 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach 408 | 409 | // Check failure of by-index access of string characters (IE < 9) 410 | // and failure of `0 in boxedString` (Rhino) 411 | var boxedString = Object('a'); 412 | var splitString = boxedString[0] !== 'a' || !(0 in boxedString); 413 | 414 | var properlyBoxesContext = function properlyBoxed(method) { 415 | // Check node 0.6.21 bug where third parameter is not boxed 416 | var properlyBoxesNonStrict = true; 417 | var properlyBoxesStrict = true; 418 | if (method) { 419 | method.call('foo', function (_, __, context) { 420 | if (typeof context !== 'object') { properlyBoxesNonStrict = false; } 421 | }); 422 | 423 | method.call([1], function () { 424 | 'use strict'; 425 | properlyBoxesStrict = typeof this === 'string'; 426 | }, 'x'); 427 | } 428 | return !!method && properlyBoxesNonStrict && properlyBoxesStrict; 429 | }; 430 | 431 | defineProperties(ArrayPrototype, { 432 | forEach: function forEach(fun /*, thisp*/) { 433 | var object = ES.ToObject(this), 434 | self = splitString && isString(this) ? this.split('') : object, 435 | thisp = arguments[1], 436 | i = -1, 437 | length = self.length >>> 0; 438 | 439 | // If no callback function or if callback is not a callable function 440 | if (!isFunction(fun)) { 441 | throw new TypeError(); // TODO message 442 | } 443 | 444 | while (++i < length) { 445 | if (i in self) { 446 | // Invoke the callback function with call, passing arguments: 447 | // context, property value, property key, thisArg object 448 | // context 449 | fun.call(thisp, self[i], i, object); 450 | } 451 | } 452 | } 453 | }, !properlyBoxesContext(ArrayPrototype.forEach)); 454 | 455 | // ES5 15.4.4.19 456 | // http://es5.github.com/#x15.4.4.19 457 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map 458 | defineProperties(ArrayPrototype, { 459 | map: function map(fun /*, thisp*/) { 460 | var object = ES.ToObject(this), 461 | self = splitString && isString(this) ? this.split('') : object, 462 | length = self.length >>> 0, 463 | result = Array(length), 464 | thisp = arguments[1]; 465 | 466 | // If no callback function or if callback is not a callable function 467 | if (!isFunction(fun)) { 468 | throw new TypeError(fun + ' is not a function'); 469 | } 470 | 471 | for (var i = 0; i < length; i++) { 472 | if (i in self) { 473 | result[i] = fun.call(thisp, self[i], i, object); 474 | } 475 | } 476 | return result; 477 | } 478 | }, !properlyBoxesContext(ArrayPrototype.map)); 479 | 480 | // ES5 15.4.4.20 481 | // http://es5.github.com/#x15.4.4.20 482 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter 483 | defineProperties(ArrayPrototype, { 484 | filter: function filter(fun /*, thisp */) { 485 | var object = ES.ToObject(this), 486 | self = splitString && isString(this) ? this.split('') : object, 487 | length = self.length >>> 0, 488 | result = [], 489 | value, 490 | thisp = arguments[1]; 491 | 492 | // If no callback function or if callback is not a callable function 493 | if (!isFunction(fun)) { 494 | throw new TypeError(fun + ' is not a function'); 495 | } 496 | 497 | for (var i = 0; i < length; i++) { 498 | if (i in self) { 499 | value = self[i]; 500 | if (fun.call(thisp, value, i, object)) { 501 | result.push(value); 502 | } 503 | } 504 | } 505 | return result; 506 | } 507 | }, !properlyBoxesContext(ArrayPrototype.filter)); 508 | 509 | // ES5 15.4.4.16 510 | // http://es5.github.com/#x15.4.4.16 511 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every 512 | defineProperties(ArrayPrototype, { 513 | every: function every(fun /*, thisp */) { 514 | var object = ES.ToObject(this), 515 | self = splitString && isString(this) ? this.split('') : object, 516 | length = self.length >>> 0, 517 | thisp = arguments[1]; 518 | 519 | // If no callback function or if callback is not a callable function 520 | if (!isFunction(fun)) { 521 | throw new TypeError(fun + ' is not a function'); 522 | } 523 | 524 | for (var i = 0; i < length; i++) { 525 | if (i in self && !fun.call(thisp, self[i], i, object)) { 526 | return false; 527 | } 528 | } 529 | return true; 530 | } 531 | }, !properlyBoxesContext(ArrayPrototype.every)); 532 | 533 | // ES5 15.4.4.17 534 | // http://es5.github.com/#x15.4.4.17 535 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some 536 | defineProperties(ArrayPrototype, { 537 | some: function some(fun /*, thisp */) { 538 | var object = ES.ToObject(this), 539 | self = splitString && isString(this) ? this.split('') : object, 540 | length = self.length >>> 0, 541 | thisp = arguments[1]; 542 | 543 | // If no callback function or if callback is not a callable function 544 | if (!isFunction(fun)) { 545 | throw new TypeError(fun + ' is not a function'); 546 | } 547 | 548 | for (var i = 0; i < length; i++) { 549 | if (i in self && fun.call(thisp, self[i], i, object)) { 550 | return true; 551 | } 552 | } 553 | return false; 554 | } 555 | }, !properlyBoxesContext(ArrayPrototype.some)); 556 | 557 | // ES5 15.4.4.21 558 | // http://es5.github.com/#x15.4.4.21 559 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce 560 | var reduceCoercesToObject = false; 561 | if (ArrayPrototype.reduce) { 562 | reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; 563 | } 564 | defineProperties(ArrayPrototype, { 565 | reduce: function reduce(fun /*, initial*/) { 566 | var object = ES.ToObject(this), 567 | self = splitString && isString(this) ? this.split('') : object, 568 | length = self.length >>> 0; 569 | 570 | // If no callback function or if callback is not a callable function 571 | if (!isFunction(fun)) { 572 | throw new TypeError(fun + ' is not a function'); 573 | } 574 | 575 | // no value to return if no initial value and an empty array 576 | if (!length && arguments.length === 1) { 577 | throw new TypeError('reduce of empty array with no initial value'); 578 | } 579 | 580 | var i = 0; 581 | var result; 582 | if (arguments.length >= 2) { 583 | result = arguments[1]; 584 | } else { 585 | do { 586 | if (i in self) { 587 | result = self[i++]; 588 | break; 589 | } 590 | 591 | // if array contains no values, no initial value to return 592 | if (++i >= length) { 593 | throw new TypeError('reduce of empty array with no initial value'); 594 | } 595 | } while (true); 596 | } 597 | 598 | for (; i < length; i++) { 599 | if (i in self) { 600 | result = fun.call(void 0, result, self[i], i, object); 601 | } 602 | } 603 | 604 | return result; 605 | } 606 | }, !reduceCoercesToObject); 607 | 608 | // ES5 15.4.4.22 609 | // http://es5.github.com/#x15.4.4.22 610 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight 611 | var reduceRightCoercesToObject = false; 612 | if (ArrayPrototype.reduceRight) { 613 | reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; 614 | } 615 | defineProperties(ArrayPrototype, { 616 | reduceRight: function reduceRight(fun /*, initial*/) { 617 | var object = ES.ToObject(this), 618 | self = splitString && isString(this) ? this.split('') : object, 619 | length = self.length >>> 0; 620 | 621 | // If no callback function or if callback is not a callable function 622 | if (!isFunction(fun)) { 623 | throw new TypeError(fun + ' is not a function'); 624 | } 625 | 626 | // no value to return if no initial value, empty array 627 | if (!length && arguments.length === 1) { 628 | throw new TypeError('reduceRight of empty array with no initial value'); 629 | } 630 | 631 | var result, i = length - 1; 632 | if (arguments.length >= 2) { 633 | result = arguments[1]; 634 | } else { 635 | do { 636 | if (i in self) { 637 | result = self[i--]; 638 | break; 639 | } 640 | 641 | // if array contains no values, no initial value to return 642 | if (--i < 0) { 643 | throw new TypeError('reduceRight of empty array with no initial value'); 644 | } 645 | } while (true); 646 | } 647 | 648 | if (i < 0) { 649 | return result; 650 | } 651 | 652 | do { 653 | if (i in self) { 654 | result = fun.call(void 0, result, self[i], i, object); 655 | } 656 | } while (i--); 657 | 658 | return result; 659 | } 660 | }, !reduceRightCoercesToObject); 661 | 662 | // ES5 15.4.4.14 663 | // http://es5.github.com/#x15.4.4.14 664 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf 665 | var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1; 666 | defineProperties(ArrayPrototype, { 667 | indexOf: function indexOf(sought /*, fromIndex */) { 668 | var self = splitString && isString(this) ? this.split('') : ES.ToObject(this), 669 | length = self.length >>> 0; 670 | 671 | if (!length) { 672 | return -1; 673 | } 674 | 675 | var i = 0; 676 | if (arguments.length > 1) { 677 | i = toInteger(arguments[1]); 678 | } 679 | 680 | // handle negative indices 681 | i = i >= 0 ? i : Math.max(0, length + i); 682 | for (; i < length; i++) { 683 | if (i in self && self[i] === sought) { 684 | return i; 685 | } 686 | } 687 | return -1; 688 | } 689 | }, hasFirefox2IndexOfBug); 690 | 691 | // ES5 15.4.4.15 692 | // http://es5.github.com/#x15.4.4.15 693 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf 694 | var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; 695 | defineProperties(ArrayPrototype, { 696 | lastIndexOf: function lastIndexOf(sought /*, fromIndex */) { 697 | var self = splitString && isString(this) ? this.split('') : ES.ToObject(this), 698 | length = self.length >>> 0; 699 | 700 | if (!length) { 701 | return -1; 702 | } 703 | var i = length - 1; 704 | if (arguments.length > 1) { 705 | i = Math.min(i, toInteger(arguments[1])); 706 | } 707 | // handle negative indices 708 | i = i >= 0 ? i : length - Math.abs(i); 709 | for (; i >= 0; i--) { 710 | if (i in self && sought === self[i]) { 711 | return i; 712 | } 713 | } 714 | return -1; 715 | } 716 | }, hasFirefox2LastIndexOfBug); 717 | 718 | // 719 | // Object 720 | // ====== 721 | // 722 | 723 | // ES5 15.2.3.14 724 | // http://es5.github.com/#x15.2.3.14 725 | 726 | // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation 727 | var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'), 728 | hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'), 729 | dontEnums = [ 730 | 'toString', 731 | 'toLocaleString', 732 | 'valueOf', 733 | 'hasOwnProperty', 734 | 'isPrototypeOf', 735 | 'propertyIsEnumerable', 736 | 'constructor' 737 | ], 738 | dontEnumsLength = dontEnums.length; 739 | 740 | defineProperties(Object, { 741 | keys: function keys(object) { 742 | var isFn = isFunction(object), 743 | isArgs = isArguments(object), 744 | isObject = object !== null && typeof object === 'object', 745 | isStr = isObject && isString(object); 746 | 747 | if (!isObject && !isFn && !isArgs) { 748 | throw new TypeError('Object.keys called on a non-object'); 749 | } 750 | 751 | var theKeys = []; 752 | var skipProto = hasProtoEnumBug && isFn; 753 | if (isStr || isArgs) { 754 | for (var i = 0; i < object.length; ++i) { 755 | theKeys.push(String(i)); 756 | } 757 | } else { 758 | for (var name in object) { 759 | if (!(skipProto && name === 'prototype') && owns(object, name)) { 760 | theKeys.push(String(name)); 761 | } 762 | } 763 | } 764 | 765 | if (hasDontEnumBug) { 766 | var ctor = object.constructor, 767 | skipConstructor = ctor && ctor.prototype === object; 768 | for (var j = 0; j < dontEnumsLength; j++) { 769 | var dontEnum = dontEnums[j]; 770 | if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { 771 | theKeys.push(dontEnum); 772 | } 773 | } 774 | } 775 | return theKeys; 776 | } 777 | }); 778 | 779 | var keysWorksWithArguments = Object.keys && (function () { 780 | // Safari 5.0 bug 781 | return Object.keys(arguments).length === 2; 782 | }(1, 2)); 783 | var originalKeys = Object.keys; 784 | defineProperties(Object, { 785 | keys: function keys(object) { 786 | if (isArguments(object)) { 787 | return originalKeys(ArrayPrototype.slice.call(object)); 788 | } else { 789 | return originalKeys(object); 790 | } 791 | } 792 | }, !keysWorksWithArguments); 793 | 794 | // 795 | // Date 796 | // ==== 797 | // 798 | 799 | // ES5 15.9.5.43 800 | // http://es5.github.com/#x15.9.5.43 801 | // This function returns a String value represent the instance in time 802 | // represented by this Date object. The format of the String is the Date Time 803 | // string format defined in 15.9.1.15. All fields are present in the String. 804 | // The time zone is always UTC, denoted by the suffix Z. If the time value of 805 | // this object is not a finite Number a RangeError exception is thrown. 806 | var negativeDate = -62198755200000; 807 | var negativeYearString = '-000001'; 808 | var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; 809 | 810 | defineProperties(Date.prototype, { 811 | toISOString: function toISOString() { 812 | var result, length, value, year, month; 813 | if (!isFinite(this)) { 814 | throw new RangeError('Date.prototype.toISOString called on non-finite value.'); 815 | } 816 | 817 | year = this.getUTCFullYear(); 818 | 819 | month = this.getUTCMonth(); 820 | // see https://github.com/es-shims/es5-shim/issues/111 821 | year += Math.floor(month / 12); 822 | month = (month % 12 + 12) % 12; 823 | 824 | // the date time string format is specified in 15.9.1.15. 825 | result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; 826 | year = ( 827 | (year < 0 ? '-' : (year > 9999 ? '+' : '')) + 828 | ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6) 829 | ); 830 | 831 | length = result.length; 832 | while (length--) { 833 | value = result[length]; 834 | // pad months, days, hours, minutes, and seconds to have two 835 | // digits. 836 | if (value < 10) { 837 | result[length] = '0' + value; 838 | } 839 | } 840 | // pad milliseconds to have three digits. 841 | return ( 842 | year + '-' + result.slice(0, 2).join('-') + 843 | 'T' + result.slice(2).join(':') + '.' + 844 | ('000' + this.getUTCMilliseconds()).slice(-3) + 'Z' 845 | ); 846 | } 847 | }, hasNegativeDateBug); 848 | 849 | 850 | // ES5 15.9.5.44 851 | // http://es5.github.com/#x15.9.5.44 852 | // This function provides a String representation of a Date object for use by 853 | // JSON.stringify (15.12.3). 854 | var dateToJSONIsSupported = false; 855 | try { 856 | dateToJSONIsSupported = ( 857 | Date.prototype.toJSON && 858 | new Date(NaN).toJSON() === null && 859 | new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && 860 | Date.prototype.toJSON.call({ // generic 861 | toISOString: function () { 862 | return true; 863 | } 864 | }) 865 | ); 866 | } catch (e) { 867 | } 868 | if (!dateToJSONIsSupported) { 869 | Date.prototype.toJSON = function toJSON(key) { 870 | // When the toJSON method is called with argument key, the following 871 | // steps are taken: 872 | 873 | // 1. Let O be the result of calling ToObject, giving it the this 874 | // value as its argument. 875 | // 2. Let tv be toPrimitive(O, hint Number). 876 | var o = Object(this), 877 | tv = toPrimitive(o), 878 | toISO; 879 | // 3. If tv is a Number and is not finite, return null. 880 | if (typeof tv === 'number' && !isFinite(tv)) { 881 | return null; 882 | } 883 | // 4. Let toISO be the result of calling the [[Get]] internal method of 884 | // O with argument "toISOString". 885 | toISO = o.toISOString; 886 | // 5. If IsCallable(toISO) is false, throw a TypeError exception. 887 | if (typeof toISO !== 'function') { 888 | throw new TypeError('toISOString property is not callable'); 889 | } 890 | // 6. Return the result of calling the [[Call]] internal method of 891 | // toISO with O as the this value and an empty argument list. 892 | return toISO.call(o); 893 | 894 | // NOTE 1 The argument is ignored. 895 | 896 | // NOTE 2 The toJSON function is intentionally generic; it does not 897 | // require that its this value be a Date object. Therefore, it can be 898 | // transferred to other kinds of objects for use as a method. However, 899 | // it does require that any such object have a toISOString method. An 900 | // object is free to use the argument key to filter its 901 | // stringification. 902 | }; 903 | } 904 | 905 | // ES5 15.9.4.2 906 | // http://es5.github.com/#x15.9.4.2 907 | // based on work shared by Daniel Friesen (dantman) 908 | // http://gist.github.com/303249 909 | var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; 910 | var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')); 911 | var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); 912 | if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { 913 | // XXX global assignment won't work in embeddings that use 914 | // an alternate object for the context. 915 | /*global Date: true */ 916 | Date = (function (NativeDate) { 917 | 918 | // Date.length === 7 919 | function Date(Y, M, D, h, m, s, ms) { 920 | var length = arguments.length; 921 | if (this instanceof NativeDate) { 922 | var date = length === 1 && String(Y) === Y ? // isString(Y) 923 | // We explicitly pass it through parse: 924 | new NativeDate(Date.parse(Y)) : 925 | // We have to manually make calls depending on argument 926 | // length here 927 | length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : 928 | length >= 6 ? new NativeDate(Y, M, D, h, m, s) : 929 | length >= 5 ? new NativeDate(Y, M, D, h, m) : 930 | length >= 4 ? new NativeDate(Y, M, D, h) : 931 | length >= 3 ? new NativeDate(Y, M, D) : 932 | length >= 2 ? new NativeDate(Y, M) : 933 | length >= 1 ? new NativeDate(Y) : 934 | new NativeDate(); 935 | // Prevent mixups with unfixed Date object 936 | date.constructor = Date; 937 | return date; 938 | } 939 | return NativeDate.apply(this, arguments); 940 | } 941 | 942 | // 15.9.1.15 Date Time String Format. 943 | var isoDateExpression = new RegExp('^' + 944 | '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign + 945 | // 6-digit extended year 946 | '(?:-(\\d{2})' + // optional month capture 947 | '(?:-(\\d{2})' + // optional day capture 948 | '(?:' + // capture hours:minutes:seconds.milliseconds 949 | 'T(\\d{2})' + // hours capture 950 | ':(\\d{2})' + // minutes capture 951 | '(?:' + // optional :seconds.milliseconds 952 | ':(\\d{2})' + // seconds capture 953 | '(?:(\\.\\d{1,}))?' + // milliseconds capture 954 | ')?' + 955 | '(' + // capture UTC offset component 956 | 'Z|' + // UTC capture 957 | '(?:' + // offset specifier +/-hours:minutes 958 | '([-+])' + // sign capture 959 | '(\\d{2})' + // hours offset capture 960 | ':(\\d{2})' + // minutes offset capture 961 | ')' + 962 | ')?)?)?)?' + 963 | '$'); 964 | 965 | var months = [ 966 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 967 | ]; 968 | 969 | function dayFromMonth(year, month) { 970 | var t = month > 1 ? 1 : 0; 971 | return ( 972 | months[month] + 973 | Math.floor((year - 1969 + t) / 4) - 974 | Math.floor((year - 1901 + t) / 100) + 975 | Math.floor((year - 1601 + t) / 400) + 976 | 365 * (year - 1970) 977 | ); 978 | } 979 | 980 | function toUTC(t) { 981 | return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t)); 982 | } 983 | 984 | // Copy any custom methods a 3rd party library may have added 985 | for (var key in NativeDate) { 986 | Date[key] = NativeDate[key]; 987 | } 988 | 989 | // Copy "native" methods explicitly; they may be non-enumerable 990 | Date.now = NativeDate.now; 991 | Date.UTC = NativeDate.UTC; 992 | Date.prototype = NativeDate.prototype; 993 | Date.prototype.constructor = Date; 994 | 995 | // Upgrade Date.parse to handle simplified ISO 8601 strings 996 | Date.parse = function parse(string) { 997 | var match = isoDateExpression.exec(string); 998 | if (match) { 999 | // parse months, days, hours, minutes, seconds, and milliseconds 1000 | // provide default values if necessary 1001 | // parse the UTC offset component 1002 | var year = Number(match[1]), 1003 | month = Number(match[2] || 1) - 1, 1004 | day = Number(match[3] || 1) - 1, 1005 | hour = Number(match[4] || 0), 1006 | minute = Number(match[5] || 0), 1007 | second = Number(match[6] || 0), 1008 | millisecond = Math.floor(Number(match[7] || 0) * 1000), 1009 | // When time zone is missed, local offset should be used 1010 | // (ES 5.1 bug) 1011 | // see https://bugs.ecmascript.org/show_bug.cgi?id=112 1012 | isLocalTime = Boolean(match[4] && !match[8]), 1013 | signOffset = match[9] === '-' ? 1 : -1, 1014 | hourOffset = Number(match[10] || 0), 1015 | minuteOffset = Number(match[11] || 0), 1016 | result; 1017 | if ( 1018 | hour < ( 1019 | minute > 0 || second > 0 || millisecond > 0 ? 1020 | 24 : 25 1021 | ) && 1022 | minute < 60 && second < 60 && millisecond < 1000 && 1023 | month > -1 && month < 12 && hourOffset < 24 && 1024 | minuteOffset < 60 && // detect invalid offsets 1025 | day > -1 && 1026 | day < ( 1027 | dayFromMonth(year, month + 1) - 1028 | dayFromMonth(year, month) 1029 | ) 1030 | ) { 1031 | result = ( 1032 | (dayFromMonth(year, month) + day) * 24 + 1033 | hour + 1034 | hourOffset * signOffset 1035 | ) * 60; 1036 | result = ( 1037 | (result + minute + minuteOffset * signOffset) * 60 + 1038 | second 1039 | ) * 1000 + millisecond; 1040 | if (isLocalTime) { 1041 | result = toUTC(result); 1042 | } 1043 | if (-8.64e15 <= result && result <= 8.64e15) { 1044 | return result; 1045 | } 1046 | } 1047 | return NaN; 1048 | } 1049 | return NativeDate.parse.apply(this, arguments); 1050 | }; 1051 | 1052 | return Date; 1053 | }(Date)); 1054 | /*global Date: false */ 1055 | } 1056 | 1057 | // ES5 15.9.4.4 1058 | // http://es5.github.com/#x15.9.4.4 1059 | if (!Date.now) { 1060 | Date.now = function now() { 1061 | return new Date().getTime(); 1062 | }; 1063 | } 1064 | 1065 | 1066 | // 1067 | // Number 1068 | // ====== 1069 | // 1070 | 1071 | // ES5.1 15.7.4.5 1072 | // http://es5.github.com/#x15.7.4.5 1073 | var hasToFixedBugs = NumberPrototype.toFixed && ( 1074 | (0.00008).toFixed(3) !== '0.000' || 1075 | (0.9).toFixed(0) !== '1' || 1076 | (1.255).toFixed(2) !== '1.25' || 1077 | (1000000000000000128).toFixed(0) !== '1000000000000000128' 1078 | ); 1079 | 1080 | var toFixedHelpers = { 1081 | base: 1e7, 1082 | size: 6, 1083 | data: [0, 0, 0, 0, 0, 0], 1084 | multiply: function multiply(n, c) { 1085 | var i = -1; 1086 | while (++i < toFixedHelpers.size) { 1087 | c += n * toFixedHelpers.data[i]; 1088 | toFixedHelpers.data[i] = c % toFixedHelpers.base; 1089 | c = Math.floor(c / toFixedHelpers.base); 1090 | } 1091 | }, 1092 | divide: function divide(n) { 1093 | var i = toFixedHelpers.size, c = 0; 1094 | while (--i >= 0) { 1095 | c += toFixedHelpers.data[i]; 1096 | toFixedHelpers.data[i] = Math.floor(c / n); 1097 | c = (c % n) * toFixedHelpers.base; 1098 | } 1099 | }, 1100 | numToString: function numToString() { 1101 | var i = toFixedHelpers.size; 1102 | var s = ''; 1103 | while (--i >= 0) { 1104 | if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { 1105 | var t = String(toFixedHelpers.data[i]); 1106 | if (s === '') { 1107 | s = t; 1108 | } else { 1109 | s += '0000000'.slice(0, 7 - t.length) + t; 1110 | } 1111 | } 1112 | } 1113 | return s; 1114 | }, 1115 | pow: function pow(x, n, acc) { 1116 | return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); 1117 | }, 1118 | log: function log(x) { 1119 | var n = 0; 1120 | while (x >= 4096) { 1121 | n += 12; 1122 | x /= 4096; 1123 | } 1124 | while (x >= 2) { 1125 | n += 1; 1126 | x /= 2; 1127 | } 1128 | return n; 1129 | } 1130 | }; 1131 | 1132 | defineProperties(NumberPrototype, { 1133 | toFixed: function toFixed(fractionDigits) { 1134 | var f, x, s, m, e, z, j, k; 1135 | 1136 | // Test for NaN and round fractionDigits down 1137 | f = Number(fractionDigits); 1138 | f = f !== f ? 0 : Math.floor(f); 1139 | 1140 | if (f < 0 || f > 20) { 1141 | throw new RangeError('Number.toFixed called with invalid number of decimals'); 1142 | } 1143 | 1144 | x = Number(this); 1145 | 1146 | // Test for NaN 1147 | if (x !== x) { 1148 | return 'NaN'; 1149 | } 1150 | 1151 | // If it is too big or small, return the string value of the number 1152 | if (x <= -1e21 || x >= 1e21) { 1153 | return String(x); 1154 | } 1155 | 1156 | s = ''; 1157 | 1158 | if (x < 0) { 1159 | s = '-'; 1160 | x = -x; 1161 | } 1162 | 1163 | m = '0'; 1164 | 1165 | if (x > 1e-21) { 1166 | // 1e-21 < x < 1e21 1167 | // -70 < log2(x) < 70 1168 | e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; 1169 | z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); 1170 | z *= 0x10000000000000; // Math.pow(2, 52); 1171 | e = 52 - e; 1172 | 1173 | // -18 < e < 122 1174 | // x = z / 2 ^ e 1175 | if (e > 0) { 1176 | toFixedHelpers.multiply(0, z); 1177 | j = f; 1178 | 1179 | while (j >= 7) { 1180 | toFixedHelpers.multiply(1e7, 0); 1181 | j -= 7; 1182 | } 1183 | 1184 | toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); 1185 | j = e - 1; 1186 | 1187 | while (j >= 23) { 1188 | toFixedHelpers.divide(1 << 23); 1189 | j -= 23; 1190 | } 1191 | 1192 | toFixedHelpers.divide(1 << j); 1193 | toFixedHelpers.multiply(1, 1); 1194 | toFixedHelpers.divide(2); 1195 | m = toFixedHelpers.numToString(); 1196 | } else { 1197 | toFixedHelpers.multiply(0, z); 1198 | toFixedHelpers.multiply(1 << (-e), 0); 1199 | m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f); 1200 | } 1201 | } 1202 | 1203 | if (f > 0) { 1204 | k = m.length; 1205 | 1206 | if (k <= f) { 1207 | m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m; 1208 | } else { 1209 | m = s + m.slice(0, k - f) + '.' + m.slice(k - f); 1210 | } 1211 | } else { 1212 | m = s + m; 1213 | } 1214 | 1215 | return m; 1216 | } 1217 | }, hasToFixedBugs); 1218 | 1219 | 1220 | // 1221 | // String 1222 | // ====== 1223 | // 1224 | 1225 | // ES5 15.5.4.14 1226 | // http://es5.github.com/#x15.5.4.14 1227 | 1228 | // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] 1229 | // Many browsers do not split properly with regular expressions or they 1230 | // do not perform the split correctly under obscure conditions. 1231 | // See http://blog.stevenlevithan.com/archives/cross-browser-split 1232 | // I've tested in many browsers and this seems to cover the deviant ones: 1233 | // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] 1234 | // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] 1235 | // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not 1236 | // [undefined, "t", undefined, "e", ...] 1237 | // ''.split(/.?/) should be [], not [""] 1238 | // '.'.split(/()()/) should be ["."], not ["", "", "."] 1239 | 1240 | var string_split = StringPrototype.split; 1241 | if ( 1242 | 'ab'.split(/(?:ab)*/).length !== 2 || 1243 | '.'.split(/(.?)(.?)/).length !== 4 || 1244 | 'tesst'.split(/(s)*/)[1] === 't' || 1245 | 'test'.split(/(?:)/, -1).length !== 4 || 1246 | ''.split(/.?/).length || 1247 | '.'.split(/()()/).length > 1 1248 | ) { 1249 | (function () { 1250 | var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group 1251 | 1252 | StringPrototype.split = function (separator, limit) { 1253 | var string = this; 1254 | if (typeof separator === 'undefined' && limit === 0) { 1255 | return []; 1256 | } 1257 | 1258 | // If `separator` is not a regex, use native split 1259 | if (to_string.call(separator) !== '[object RegExp]') { 1260 | return string_split.call(this, separator, limit); 1261 | } 1262 | 1263 | var output = [], 1264 | flags = (separator.ignoreCase ? 'i' : '') + 1265 | (separator.multiline ? 'm' : '') + 1266 | (separator.extended ? 'x' : '') + // Proposed for ES6 1267 | (separator.sticky ? 'y' : ''), // Firefox 3+ 1268 | lastLastIndex = 0, 1269 | // Make `global` and avoid `lastIndex` issues by working with a copy 1270 | separator2, match, lastIndex, lastLength; 1271 | separator = new RegExp(separator.source, flags + 'g'); 1272 | string += ''; // Type-convert 1273 | if (!compliantExecNpcg) { 1274 | // Doesn't need flags gy, but they don't hurt 1275 | separator2 = new RegExp('^' + separator.source + '$(?!\\s)', flags); 1276 | } 1277 | /* Values for `limit`, per the spec: 1278 | * If undefined: 4294967295 // Math.pow(2, 32) - 1 1279 | * If 0, Infinity, or NaN: 0 1280 | * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; 1281 | * If negative number: 4294967296 - Math.floor(Math.abs(limit)) 1282 | * If other: Type-convert, then use the above rules 1283 | */ 1284 | limit = typeof limit === 'undefined' ? 1285 | -1 >>> 0 : // Math.pow(2, 32) - 1 1286 | ES.ToUint32(limit); 1287 | while (match = separator.exec(string)) { 1288 | // `separator.lastIndex` is not reliable cross-browser 1289 | lastIndex = match.index + match[0].length; 1290 | if (lastIndex > lastLastIndex) { 1291 | output.push(string.slice(lastLastIndex, match.index)); 1292 | // Fix browsers whose `exec` methods don't consistently return `undefined` for 1293 | // nonparticipating capturing groups 1294 | if (!compliantExecNpcg && match.length > 1) { 1295 | match[0].replace(separator2, function () { 1296 | for (var i = 1; i < arguments.length - 2; i++) { 1297 | if (typeof arguments[i] === 'undefined') { 1298 | match[i] = void 0; 1299 | } 1300 | } 1301 | }); 1302 | } 1303 | if (match.length > 1 && match.index < string.length) { 1304 | array_push.apply(output, match.slice(1)); 1305 | } 1306 | lastLength = match[0].length; 1307 | lastLastIndex = lastIndex; 1308 | if (output.length >= limit) { 1309 | break; 1310 | } 1311 | } 1312 | if (separator.lastIndex === match.index) { 1313 | separator.lastIndex++; // Avoid an infinite loop 1314 | } 1315 | } 1316 | if (lastLastIndex === string.length) { 1317 | if (lastLength || !separator.test('')) { 1318 | output.push(''); 1319 | } 1320 | } else { 1321 | output.push(string.slice(lastLastIndex)); 1322 | } 1323 | return output.length > limit ? output.slice(0, limit) : output; 1324 | }; 1325 | }()); 1326 | 1327 | // [bugfix, chrome] 1328 | // If separator is undefined, then the result array contains just one String, 1329 | // which is the this value (converted to a String). If limit is not undefined, 1330 | // then the output array is truncated so that it contains no more than limit 1331 | // elements. 1332 | // "0".split(undefined, 0) -> [] 1333 | } else if ('0'.split(void 0, 0).length) { 1334 | StringPrototype.split = function split(separator, limit) { 1335 | if (typeof separator === 'undefined' && limit === 0) { return []; } 1336 | return string_split.call(this, separator, limit); 1337 | }; 1338 | } 1339 | 1340 | var str_replace = StringPrototype.replace; 1341 | var replaceReportsGroupsCorrectly = (function () { 1342 | var groups = []; 1343 | 'x'.replace(/x(.)?/g, function (match, group) { 1344 | groups.push(group); 1345 | }); 1346 | return groups.length === 1 && typeof groups[0] === 'undefined'; 1347 | }()); 1348 | 1349 | if (!replaceReportsGroupsCorrectly) { 1350 | StringPrototype.replace = function replace(searchValue, replaceValue) { 1351 | var isFn = isFunction(replaceValue); 1352 | var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); 1353 | if (!isFn || !hasCapturingGroups) { 1354 | return str_replace.call(this, searchValue, replaceValue); 1355 | } else { 1356 | var wrappedReplaceValue = function (match) { 1357 | var length = arguments.length; 1358 | var originalLastIndex = searchValue.lastIndex; 1359 | searchValue.lastIndex = 0; 1360 | var args = searchValue.exec(match) || []; 1361 | searchValue.lastIndex = originalLastIndex; 1362 | args.push(arguments[length - 2], arguments[length - 1]); 1363 | return replaceValue.apply(this, args); 1364 | }; 1365 | return str_replace.call(this, searchValue, wrappedReplaceValue); 1366 | } 1367 | }; 1368 | } 1369 | 1370 | // ECMA-262, 3rd B.2.3 1371 | // Not an ECMAScript standard, although ECMAScript 3rd Edition has a 1372 | // non-normative section suggesting uniform semantics and it should be 1373 | // normalized across all browsers 1374 | // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE 1375 | var string_substr = StringPrototype.substr; 1376 | var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; 1377 | defineProperties(StringPrototype, { 1378 | substr: function substr(start, length) { 1379 | return string_substr.call( 1380 | this, 1381 | start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start, 1382 | length 1383 | ); 1384 | } 1385 | }, hasNegativeSubstrBug); 1386 | 1387 | // ES5 15.5.4.20 1388 | // whitespace from: http://es5.github.io/#x15.5.4.20 1389 | var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + 1390 | '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + 1391 | '\u2029\uFEFF'; 1392 | var zeroWidth = '\u200b'; 1393 | var wsRegexChars = '[' + ws + ']'; 1394 | var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); 1395 | var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); 1396 | var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); 1397 | defineProperties(StringPrototype, { 1398 | // http://blog.stevenlevithan.com/archives/faster-trim-javascript 1399 | // http://perfectionkills.com/whitespace-deviations/ 1400 | trim: function trim() { 1401 | if (typeof this === 'undefined' || this === null) { 1402 | throw new TypeError("can't convert " + this + ' to object'); 1403 | } 1404 | return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); 1405 | } 1406 | }, hasTrimWhitespaceBug); 1407 | 1408 | // ES-5 15.1.2.2 1409 | if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { 1410 | /*global parseInt: true */ 1411 | parseInt = (function (origParseInt) { 1412 | var hexRegex = /^0[xX]/; 1413 | return function parseIntES5(str, radix) { 1414 | str = String(str).trim(); 1415 | if (!Number(radix)) { 1416 | radix = hexRegex.test(str) ? 16 : 10; 1417 | } 1418 | return origParseInt(str, radix); 1419 | }; 1420 | }(parseInt)); 1421 | } 1422 | 1423 | })); 1424 | -------------------------------------------------------------------------------- /console-log-div.js: -------------------------------------------------------------------------------- 1 | (function initConsoleLogDiv() { 2 | 'use strict'; 3 | 4 | 5 | if (console.log.toDiv) { 6 | return; 7 | } 8 | 9 | function toString(x) { 10 | if (x instanceof Error) { 11 | return x.message; 12 | } 13 | return typeof x === 'string' ? x : JSON.stringify(x); 14 | } 15 | 16 | var log = console.log.bind(console); 17 | var error = console.error.bind(console); 18 | var warn = console.warn.bind(console); 19 | var table = console.table ? console.table.bind(console) : null; 20 | var id = 'console-log-div'; 21 | 22 | function createOuterElement() { 23 | var outer = document.getElementById(id); 24 | if (!outer) { 25 | outer = document.createElement('fieldset'); 26 | outer.id = id; 27 | document.body.appendChild(outer); 28 | } 29 | outer.classList.add(id); 30 | 31 | var style = outer.style; 32 | // style.width = '100%'; 33 | // style.minHeight = '200px'; 34 | style.fontFamily = 'monospace'; 35 | style.marginTop = '20px'; 36 | style.marginLeft = '10px'; 37 | style.marginRight = '10px'; 38 | style.whiteSpace = 'pre'; 39 | style.border = '1px solid black'; 40 | style.borderRadius = '5px'; 41 | style.padding = '5px 10px'; 42 | return outer; 43 | } 44 | 45 | var logTo = (function createLogDiv() { 46 | 47 | var outer = createOuterElement(); 48 | 49 | var caption = document.createTextNode('console output'); 50 | var legend = document.createElement('legend'); 51 | legend.appendChild(caption); 52 | outer.appendChild(legend); 53 | 54 | var div = document.createElement('div'); 55 | div.id = 'console-log-text'; 56 | outer.appendChild(div); 57 | 58 | return div; 59 | }()); 60 | 61 | function printToDiv() { 62 | var msg = Array.prototype.slice.call(arguments, 0) 63 | .map(toString) 64 | .join(' '); 65 | var text = logTo.textContent; 66 | logTo.textContent = text + msg + '\n'; 67 | } 68 | 69 | function logWithCopy() { 70 | log.apply(null, arguments); 71 | printToDiv.apply(null, arguments); 72 | } 73 | 74 | console.log = logWithCopy; 75 | console.log.toDiv = true; 76 | 77 | console.error = function errorWithCopy() { 78 | error.apply(null, arguments); 79 | var args = Array.prototype.slice.call(arguments, 0); 80 | args.unshift('ERROR:'); 81 | printToDiv.apply(null, args); 82 | }; 83 | 84 | console.warn = function logWarning() { 85 | warn.apply(null, arguments); 86 | var args = Array.prototype.slice.call(arguments, 0); 87 | args.unshift('WARNING:'); 88 | printToDiv.apply(null, args); 89 | }; 90 | 91 | function printTable(objArr, keys) { 92 | 93 | var numCols = keys.length; 94 | var len = objArr.length; 95 | var $table = document.createElement('table'); 96 | $table.style.width = '100%'; 97 | $table.setAttribute('border', '1'); 98 | var $head = document.createElement('thead'); 99 | var $tdata = document.createElement('td'); 100 | $tdata.innerHTML = 'Index'; 101 | $head.appendChild($tdata); 102 | 103 | for (var k = 0; k < numCols; k++) { 104 | $tdata = document.createElement('td'); 105 | $tdata.innerHTML = keys[k]; 106 | $head.appendChild($tdata); 107 | } 108 | $table.appendChild($head); 109 | 110 | for (var i = 0; i < len; i++) { 111 | var $line = document.createElement('tr'); 112 | $tdata = document.createElement('td'); 113 | $tdata.innerHTML = i; 114 | $line.appendChild($tdata); 115 | 116 | for (var j = 0; j < numCols; j++) { 117 | $tdata = document.createElement('td'); 118 | $tdata.innerHTML = objArr[i][keys[j]]; 119 | $line.appendChild($tdata); 120 | } 121 | $table.appendChild($line); 122 | } 123 | var div = document.getElementById('console-log-text'); 124 | div.appendChild($table); 125 | } 126 | 127 | console.table = function logTable() { 128 | if (typeof table === 'function') { 129 | table.apply(null, arguments); 130 | } 131 | 132 | var objArr = arguments[0]; 133 | var keys; 134 | 135 | if (typeof objArr[0] !== 'undefined') { 136 | keys = Object.keys(objArr[0]); 137 | } 138 | printTable(objArr, keys); 139 | }; 140 | 141 | window.addEventListener('error', function (err) { 142 | printToDiv( 'EXCEPTION:', err.message + '\n ' + err.filename, err.lineno + ':' + err.colno); 143 | }); 144 | 145 | }()); 146 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | console-log-div 8 | 9 | 10 | 31 | 32 | 33 |

console-log-div

34 |

A new div will be created automatically and will mirror console.log calls

35 | 36 | 37 | 38 | 39 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /images/console-log-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahmutov/console-log-div/7e424717ca6515239bc2ce22723d6644e33d1c6b/images/console-log-demo.png -------------------------------------------------------------------------------- /images/console-log-div.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahmutov/console-log-div/7e424717ca6515239bc2ce22723d6644e33d1c6b/images/console-log-div.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "console-log-div", 3 | "description": "Clones console.log calls to a created div in the page. Great for demos and experiments.", 4 | "version": "0.0.0-semantic-release", 5 | "author": "Gleb Bahmutov ", 6 | "bugs": { 7 | "url": "https://github.com/bahmutov/console-log-div/issues" 8 | }, 9 | "config": { 10 | "pre-git": { 11 | "commit-msg": "simple", 12 | "pre-commit": [ 13 | "npm run build", 14 | "npm run e2e -- --force" 15 | ], 16 | "pre-push": [], 17 | "post-commit": [], 18 | "post-checkout": [], 19 | "post-merge": [] 20 | } 21 | }, 22 | "contributors": [], 23 | "devDependencies": { 24 | "eslint-rules": "0.4.3", 25 | "grunt": "0.4.5", 26 | "grunt-clean-console": "0.3.0", 27 | "grunt-cli": "0.1.13", 28 | "grunt-contrib-jshint": "1.0.0", 29 | "grunt-contrib-watch": "1.0.0", 30 | "grunt-deps-ok": "0.9.0", 31 | "grunt-eslint": "6.0.0", 32 | "grunt-filenames": "0.4.0", 33 | "grunt-gh-pages": "1.1.0", 34 | "grunt-jscs": "2.8.0", 35 | "grunt-nice-package": "0.10.2", 36 | "grunt-npm2bower-sync": "0.9.1", 37 | "jshint-summary": "0.4.0", 38 | "matchdep": "1.0.1", 39 | "mocha": "3.0.2", 40 | "pre-git": "3.10.0", 41 | "semantic-release": "6.2.1" 42 | }, 43 | "engines": { 44 | "node": "> 0.10.*" 45 | }, 46 | "homepage": "https://github.com/bahmutov/console-log-div", 47 | "keywords": [ 48 | "browser", 49 | "clone", 50 | "console", 51 | "div", 52 | "element", 53 | "log", 54 | "message", 55 | "page", 56 | "show", 57 | "visible" 58 | ], 59 | "license": "MIT", 60 | "main": "console-log-div.js", 61 | "repository": { 62 | "type": "git", 63 | "url": "https://github.com/bahmutov/console-log-div.git" 64 | }, 65 | "scripts": { 66 | "build": "grunt", 67 | "commit": "commit-wizard", 68 | "e2e": "grunt clean-console", 69 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 70 | "test": "grunt" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /test/existing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | existing console-log-div 7 | 8 | 25 | 26 | 27 |

existing console-log-div

28 |
29 | 30 |

The fieldset above will mirror console.log calls

31 | 32 | 33 | 34 | 42 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | console-log-div 7 | 8 | 25 | 26 | 27 |

console-log-div

28 |

A new div will be created automatically and will mirror console.log calls

29 | 30 | 31 | 32 | 33 | 34 | 35 | 40 | 50 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /utils/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "maxerr" : 50, 3 | 4 | "indent" : 2, 5 | "bitwise" : true, 6 | "camelcase" : true, 7 | "curly" : true, 8 | "eqeqeq" : true, 9 | "forin" : true, 10 | "immed" : false, 11 | "latedef" : false, 12 | "newcap" : true, 13 | "noarg" : true, 14 | "noempty" : true, 15 | "nonew" : false, 16 | "plusplus" : false, 17 | "quotmark" : "single", 18 | "undef" : true, 19 | "unused" : true, 20 | "strict" : false, 21 | "trailing" : false, 22 | "maxparams" : 4, 23 | "maxdepth" : 3, 24 | "maxstatements" : 30, 25 | "maxcomplexity" : 20, 26 | "maxlen" : 120, 27 | 28 | "asi" : false, 29 | "boss" : false, 30 | "debug" : false, 31 | "eqnull" : false, 32 | "es5" : false, 33 | "esnext" : false, 34 | "moz" : false, 35 | "evil" : false, 36 | "expr" : false, 37 | "funcscope" : false, 38 | "globalstrict" : false, 39 | "iterator" : false, 40 | "lastsemic" : false, 41 | "laxbreak" : false, 42 | "laxcomma" : false, 43 | "loopfunc" : false, 44 | "multistr" : false, 45 | "proto" : false, 46 | "scripturl" : false, 47 | "smarttabs" : true, 48 | "shadow" : false, 49 | "sub" : false, 50 | "supernew" : false, 51 | "validthis" : false, 52 | 53 | "browser" : true, 54 | "couch" : false, 55 | "devel" : true, 56 | "dojo" : false, 57 | "jquery" : false, 58 | "mootools" : false, 59 | "node" : false, 60 | "nonstandard" : false, 61 | "prototypejs" : false, 62 | "rhino" : false, 63 | "worker" : false, 64 | "wsh" : false, 65 | "yui" : false, 66 | 67 | "nomen" : false, 68 | "onevar" : false, 69 | "passfail" : false, 70 | "white" : false, 71 | 72 | "globals" : { 73 | "require": true, 74 | "module": true, 75 | "$": false 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /utils/eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | // this is JSON file, but ESLint allows C-style comments 3 | 4 | "env": { 5 | "browser": true, 6 | "node": false 7 | }, 8 | 9 | // 0 - turn rule off 10 | // 1 - rule generates warnings 11 | // 2 - rule generates errors 12 | "rules": { 13 | "camelcase": 0, 14 | "camel_case": 0, 15 | "strict": 0, 16 | "no-undef": 1, 17 | "no-console": 0, 18 | "no-unused-vars": 1, 19 | "no-underscore-dangle": 0, 20 | "quotes": [2, "single"], 21 | "brace-style": [2, "1tbs"], 22 | "eol-last": 2, 23 | "semi": [2, "always"], 24 | "no-extra-strict": 0, 25 | "no-single-line-objects": 2, 26 | "no-nested-ternary": 2, 27 | "no-space-before-semi": 2, 28 | "no-shadow": 2, 29 | "no-undef-init": 2, 30 | "no-undefined": 0, 31 | "no-sequences": 2, 32 | "no-for-loops": 2, 33 | "no-process-exit": 0, 34 | "consistent-return": 0 35 | }, 36 | 37 | "globals": { 38 | "console": true, 39 | "module": true, 40 | "require": true, 41 | "Promise": true 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /utils/jscs.json: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": true, 3 | "requireDotNotation": true, 4 | "requireSpaceAfterLineComment": true, 5 | "validateQuoteMarks": "'", 6 | "validateIndentation": 2, 7 | "requireSpacesInFunctionExpression": { 8 | "beforeOpeningCurlyBrace": true 9 | }, 10 | "requireSpacesInAnonymousFunctionExpression": { 11 | "beforeOpeningRoundBrace": true, 12 | "beforeOpeningCurlyBrace": true 13 | }, 14 | "requireSpacesInsideObjectBrackets": "all" 15 | } 16 | --------------------------------------------------------------------------------