├── .gitignore ├── .travis.yml ├── css ├── main.css └── main.styl ├── spec ├── lib │ ├── jasmine_favicon.png │ ├── jasmine.css │ ├── boot.js │ ├── jasmine2-junit.js │ ├── jasmine2-runner.js │ └── jasmine-html.js ├── SpecRunner.html ├── spec.coffee ├── spec.js └── es5-shim.js ├── testem.json ├── index.html ├── bower.json ├── index.jade ├── package.json ├── karma.conf.js ├── readme.md ├── dist ├── any-resize-event.min.js └── any-resize-event.js ├── gulpfile.js ├── js ├── any-resize-event.coffee └── any-resize-event.js └── npm-debug.log /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | .test{position:absolute;display:block;background:#f1f1f1;width:100%;height:100px;margin-left:30px} -------------------------------------------------------------------------------- /spec/lib/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legomushroom/resize/HEAD/spec/lib/jasmine_favicon.png -------------------------------------------------------------------------------- /testem.json: -------------------------------------------------------------------------------- 1 | { 2 | "framework": "jasmine", 3 | "src_files": [ 4 | "js/any-resize-event.js", 5 | "spec/**/*.js" 6 | ] 7 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | doc 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /css/main.styl: -------------------------------------------------------------------------------- 1 | // @import 'assets/imports.styl' 2 | // @import 'css-assets/normalize.styl' 3 | 4 | // @import 'css-assets/font/stylesheet.css' 5 | // @import 'css-assets/general' 6 | // @import 'css-assets/elements' 7 | // @import 'css-assets/blocks' 8 | // @import 'css-assets/layouts' 9 | // @import 'css-assets/effects' 10 | // @import 'css-assets/icons' 11 | 12 | 13 | .test 14 | position absolute 15 | display block 16 | background #f1f1f1 17 | width 100% 18 | height 100px 19 | margin-left 30px -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "any resize event", 3 | "version": "1.0.0", 4 | "homepage": "https://github.com/legomushroom/resize", 5 | "authors": [ 6 | "@legomushroom " 7 | ], 8 | "description": "Adds \"onresize\" event to any html element", 9 | "main": "dist/any-resize-event.js", 10 | "moduleType": [ 11 | "amd", 12 | "globals", 13 | "node" 14 | ], 15 | "keywords": [ 16 | "onresize", 17 | "resize", 18 | "event", 19 | "html", 20 | "polyfill" 21 | ], 22 | "license": "MIT", 23 | "ignore": [ 24 | "**/.*", 25 | "node_modules", 26 | "bower_components", 27 | "test", 28 | "tests" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /spec/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Javascript Tests with JUnit output 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /index.jade: -------------------------------------------------------------------------------- 1 | doctype 2 | html 3 | head 4 | meta(charset='UTF-8') 5 | title doc 6 | link(href="favicon.ico", rel="icon", type="image/png") 7 | link(rel="stylesheet", type="text/css", href="css/main.css") 8 | 9 | body 10 | #js-test.test 11 | //- p content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content 12 | 13 | 14 | //- iframe(id="js-test-iframe", name="a", style="width:100%; height: 100%; opacity: 0;") 15 | //- script. 16 | //- var iframe = document.getElementById('js-test-iframe'); 17 | //- var iframe2 = iframe.cloneNode(true); 18 | //- document.body.appendChild(iframe2); 19 | //- iframe2.contentWindow.onresize = function(){ 20 | //- console.log('a'); 21 | //- } 22 | 23 | //- script. 24 | //- test = document.querySelector('#js-test'); 25 | //- console.log(test); 26 | //- oldFun = HTMLDivElement.prototype.addEventListener; 27 | //- fun = function(){ 28 | //- console.log('redefine'); 29 | //- oldFun.apply(this, arguments) 30 | //- } 31 | //- HTMLDivElement.prototype.addEventListener = fun; 32 | //- test.addEventListener('click', function(){ 33 | //- console.log('click') 34 | //- }); 35 | 36 | //- Element.addEventListener('click') 37 | //- console.log(Element.prototype.addEventListener); 38 | //- console.log(iframe.contentWindow) 39 | //- console.log(a) 40 | 41 | script(src="js/any-resize-event.js") 42 | script(src="js/main.js") 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "any-resize-event", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "author": "@LegoMushroom (http://legomushroom.com)", 6 | "private": false, 7 | "scripts": { 8 | "test": "karma start --single-run" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "ansi-styles": "^1.1.0", 13 | "escape-string-regexp": "^1.0.0", 14 | "gulp": "3.8.10", 15 | "gulp-autoprefixer": "0.0.6", 16 | "gulp-changed": "~0.2.0", 17 | "gulp-clone": "^1.0.0", 18 | "gulp-coffee": "~1.4.1", 19 | "gulp-coffeelint": "0.4.0", 20 | "gulp-jade": "~0.4.2", 21 | "gulp-jasmine2-phantomjs": "0.2.0", 22 | "gulp-livereload": "~1.2.0", 23 | "gulp-minify-css": "~0.3.0", 24 | "gulp-notify": "~0.5.1", 25 | "gulp-plumber": "0.6.6", 26 | "gulp-rename": "^1.2.0", 27 | "gulp-stylus": "0.0.12", 28 | "gulp-uglify": "1.0.1", 29 | "gulp-util": "3.0.1", 30 | "gulp-watch": "2.0.0", 31 | "has-ansi": "^0.1.0", 32 | "karma": "^0.12.21", 33 | "karma-chrome-launcher": "^0.1.4", 34 | "karma-cli": "0.0.4", 35 | "karma-jasmine": "^0.2.0", 36 | "karma-phantomjs-launcher": "^0.1.4", 37 | "strip-ansi": "^0.3.0", 38 | "supports-color": "^0.2.0", 39 | "testem": "0.6.23" 40 | }, 41 | "description": "Adds \"onresize\" event to any html element", 42 | "main": "dist/any-resize-event.js", 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/legomushroom/resize.git" 46 | }, 47 | "keywords": [ 48 | "onresie", 49 | "resize", 50 | "event", 51 | "html", 52 | "polyfill" 53 | ], 54 | "bugs": { 55 | "url": "https://github.com/legomushroom/resize/issues" 56 | }, 57 | "homepage": "https://github.com/legomushroom/resize" 58 | } 59 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sun Dec 07 2014 13:58:11 GMT+0200 (EET) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['jasmine'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'dist/any-resize-event.js', 19 | 'spec/spec.js' 20 | ], 21 | 22 | 23 | // list of files to exclude 24 | // exclude: [ 25 | // 'dist/any-resize-event.js' 26 | // ], 27 | 28 | 29 | // preprocess matching files before serving them to the browser 30 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 31 | preprocessors: { 32 | }, 33 | 34 | 35 | // test results reporter to use 36 | // possible values: 'dots', 'progress' 37 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 38 | reporters: ['progress'], 39 | 40 | 41 | // web server port 42 | port: 9876, 43 | 44 | 45 | // enable / disable colors in the output (reporters and logs) 46 | colors: true, 47 | 48 | 49 | // level of logging 50 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 51 | logLevel: config.LOG_INFO, 52 | 53 | 54 | // enable / disable watching file and executing tests whenever any file changes 55 | autoWatch: true, 56 | 57 | 58 | // start these browsers 59 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 60 | browsers: ['PhantomJS'], 61 | // browsers: ['Chrome'], 62 | 63 | 64 | // Continuous Integration mode 65 | // if true, Karma captures browsers, runs the tests and exits 66 | singleRun: false 67 | }); 68 | }; 69 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Any HTML Element Resize Event 2 | ================ 3 | [![Build Status](https://travis-ci.org/legomushroom/resize.svg?branch=master)](https://travis-ci.org/legomushroom/resize) [![npm version](https://badge.fury.io/js/any-resize-event.svg)](http://badge.fury.io/js/any-resize-event) 4 | 5 | Adds **"onresize"** event to any html element. 6 | It is tiny (about 800 bytes min + gzip) and dependency free. 7 | 8 | _*timer is used as a fallback for elements that can not have child nodes(images, inputs etc)_ 9 | 10 | ### Usage 11 | 12 | Just link source file in your html. Add **"onresize"** event listener to any element as you usually do. Plays well with jquery too. [sandbox](http://codepen.io/sol0mka/pen/FnizC) 13 | 14 | ###Contibuting 15 | 16 | Pull request is way to go. Uses coffeescript as js preprocessor so I'm expecting changes in **any-resize-event.coffee** file. 17 | 18 | ### Environment 19 | Uses [gulp](http://gulpjs.com/) as task runner. 20 | ```sh 21 | [sudo] npm istall 22 | ``` 23 | launch gulp: 24 | ```sh 25 | gulp 26 | ``` 27 | ### Tests 28 | Please test your code. [KarmaJS](http://karma-runner.github.io/0.12/index.html) as tests enviroment and [jasmine](http://jasmine.github.io/) as testing framework. 29 | Launch testem: 30 | ```sh 31 | karma start 32 | ``` 33 | You are all set. 34 | 35 | ### Browsers' support 36 | It works just everywhere: 37 |
38 | Chrome 1+ 39 |
40 | Firefox 1+ 41 |
42 | IE 4+ 43 |
44 | Safari 1+ 45 |
46 | Opera 4+ 47 | 48 | 49 | ### License 50 | The MIT License (MIT) 51 | Copyright (c) 2014 Oleg Solomka(Legomushroom) legomushroom@gmail.com http://legomushroom.com 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy 54 | of this software and associated documentation files (the "Software"), to deal 55 | in the Software without restriction, including without limitation the rights 56 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 57 | copies of the Software, and to permit persons to whom the Software is 58 | furnished to do so, subject to the following conditions: 59 | 60 | The above copyright notice and this permission notice shall be included in 61 | all copies or substantial portions of the Software. 62 | 63 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 64 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 65 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 66 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 67 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 68 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 69 | THE SOFTWARE. -------------------------------------------------------------------------------- /dist/any-resize-event.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | LegoMushroom @legomushroom http://legomushroom.com 3 | MIT License 2014 4 | */ 5 | (function(){var e;e=function(){function e(e){this.o=null!=e?e:{},window.isAnyResizeEventInited||(this.vars(),this.redefineProto())}return e.prototype.vars=function(){return window.isAnyResizeEventInited=!0,this.allowedProtos=[HTMLDivElement,HTMLFormElement,HTMLLinkElement,HTMLBodyElement,HTMLParagraphElement,HTMLFieldSetElement,HTMLLegendElement,HTMLLabelElement,HTMLButtonElement,HTMLUListElement,HTMLOListElement,HTMLLIElement,HTMLHeadingElement,HTMLQuoteElement,HTMLPreElement,HTMLBRElement,HTMLFontElement,HTMLHRElement,HTMLModElement,HTMLParamElement,HTMLMapElement,HTMLTableElement,HTMLTableCaptionElement,HTMLImageElement,HTMLTableCellElement,HTMLSelectElement,HTMLInputElement,HTMLTextAreaElement,HTMLAnchorElement,HTMLObjectElement,HTMLTableColElement,HTMLTableSectionElement,HTMLTableRowElement],this.timerElements={img:1,textarea:1,input:1,embed:1,object:1,svg:1,canvas:1,tr:1,tbody:1,thead:1,tfoot:1,a:1,select:1,option:1,optgroup:1,dl:1,dt:1,br:1,basefont:1,font:1,col:1,iframe:1}},e.prototype.redefineProto=function(){var e,t,n,o;return t=this,o=function(){var o,i,r,a;for(r=this.allowedProtos,a=[],e=o=0,i=r.length;i>o;e=++o)n=r[e],null!=n.prototype&&a.push(function(e){var n,o;return n=e.prototype.addEventListener||e.prototype.attachEvent,function(n){var o;return o=function(){var e;return(this!==window||this!==document)&&(e="onresize"===arguments[0]&&!this.isAnyResizeEventInited,e&&t.handleResize({args:arguments,that:this})),n.apply(this,arguments)},e.prototype.addEventListener?e.prototype.addEventListener=o:e.prototype.attachEvent?e.prototype.attachEvent=o:void 0}(n),o=e.prototype.removeEventListener||e.prototype.detachEvent,function(t){var n;return n=function(){return this.isAnyResizeEventInited=!1,this.iframe&&this.removeChild(this.iframe),t.apply(this,arguments)},e.prototype.removeEventListener?e.prototype.removeEventListener=n:e.prototype.detachEvent?e.prototype.detachEvent=wrappedListener:void 0}(o)}(n));return a}.call(this)},e.prototype.handleResize=function(e){var t,n,o,i,r,a;return n=e.that,this.timerElements[n.tagName.toLowerCase()]?this.initTimer(n):(o=document.createElement("iframe"),n.appendChild(o),o.style.width="100%",o.style.height="100%",o.style.position="absolute",o.style.zIndex=-999,o.style.opacity=0,o.style.top=0,o.style.left=0,t=window.getComputedStyle?getComputedStyle(n):n.currentStyle,r="static"===t.position&&""===n.style.position,i=""===t.position&&""===n.style.position,(r||i)&&(n.style.position="relative"),null!=(a=o.contentWindow)&&(a.onresize=function(e){return function(){return e.dispatchEvent(n)}}(this)),n.iframe=o),n.isAnyResizeEventInited=!0},e.prototype.initTimer=function(e){var t,n;return n=0,t=0,this.interval=setInterval(function(o){return function(){var i,r;return r=e.offsetWidth,i=e.offsetHeight,r!==n||i!==t?(o.dispatchEvent(e),n=r,t=i):void 0}}(this),this.o.interval||62.5)},e.prototype.dispatchEvent=function(e){var t;return document.createEvent?(t=document.createEvent("HTMLEvents"),t.initEvent("onresize",!1,!1),e.dispatchEvent(t)):document.createEventObject?(t=document.createEventObject(),e.fireEvent("onresize",t)):!1},e.prototype.destroy=function(){var e,t,n,o,i,r,a;for(clearInterval(this.interval),this.interval=null,window.isAnyResizeEventInited=!1,t=this,r=this.allowedProtos,a=[],e=o=0,i=r.length;i>o;e=++o)n=r[e],null!=n.prototype&&a.push(function(e){var t;return t=e.prototype.addEventListener||e.prototype.attachEvent,e.prototype.addEventListener?e.prototype.addEventListener=Element.prototype.addEventListener:e.prototype.attachEvent&&(e.prototype.attachEvent=Element.prototype.attachEvent),e.prototype.removeEventListener?e.prototype.removeEventListener=Element.prototype.removeEventListener:e.prototype.detachEvent?e.prototype.detachEvent=Element.prototype.detachEvent:void 0}(n));return a},e}(),"function"==typeof define&&define.amd?define("any-resize-event",[],function(){return new e}):"object"==typeof module&&"object"==typeof module.exports?module.exports=new e:("undefined"!=typeof window&&null!==window&&(window.AnyResizeEvent=e),"undefined"!=typeof window&&null!==window&&(window.anyResizeEvent=new e))}).call(this); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var minifycss = require('gulp-minify-css'); 3 | var stylus = require('gulp-stylus'); 4 | var autoprefixer = require('gulp-autoprefixer'); 5 | var notify = require('gulp-notify'); 6 | var livereload = require('gulp-livereload'); 7 | var coffee = require('gulp-coffee'); 8 | var changed = require('gulp-changed'); 9 | var jade = require('gulp-jade'); 10 | var watch = require('gulp-jade'); 11 | var watch = require('gulp-jade'); 12 | var coffeelint = require('gulp-coffeelint'); 13 | var plumber = require('gulp-plumber'); 14 | var uglify = require('gulp-uglify'); 15 | var jasminePhantomJs = require('gulp-jasmine2-phantomjs'); 16 | var clone = require('gulp-clone'); 17 | var rename = require("gulp-rename"); 18 | 19 | var devFolder = ''; 20 | var distFolder = ''; 21 | 22 | var paths = { 23 | src: { 24 | js: devFolder + 'js/**/*.coffee', 25 | mainJs: devFolder + 'js/any-resize-event.js', 26 | css: devFolder + 'css/**/*.styl', 27 | kit: devFolder + 'css/kit.jade', 28 | index: devFolder + 'index.jade', 29 | partials: devFolder + 'css/partials/**/*.jade', 30 | templates:devFolder + 'templates/**/*.jade', 31 | tests: distFolder + 'spec/**/*.coffee' 32 | }, 33 | dist:{ 34 | js: distFolder + 'js/', 35 | tests: distFolder + 'spec/', 36 | css: distFolder + 'css/', 37 | kit: distFolder + 'css/', 38 | index: distFolder 39 | } 40 | } 41 | 42 | 43 | gulp.task('stylus', function(){ 44 | return gulp.src(devFolder + 'css/main.styl') 45 | .pipe(stylus()) 46 | .pipe(autoprefixer('last 4 version')) 47 | .pipe(minifycss()) 48 | .pipe(gulp.dest(paths.dist.css)) 49 | .pipe(livereload()) 50 | }); 51 | 52 | 53 | gulp.task('coffee', function(e){ 54 | return gulp.src(paths.src.js) 55 | .pipe(plumber()) 56 | .pipe(changed(paths.src.js)) 57 | .pipe(coffeelint()) 58 | .pipe(coffeelint.reporter()) 59 | .pipe(coffee()) 60 | .pipe(gulp.dest(paths.dist.js)) 61 | .pipe(livereload()) 62 | }); 63 | 64 | gulp.task('build', function() { 65 | return gulp.src(paths.src.mainJs) 66 | .pipe(clone()) 67 | .pipe(gulp.dest('dist/')) 68 | .pipe(uglify({ preserveComments: 'some' })) 69 | .pipe(rename('any-resize-event.min.js')) 70 | .pipe(gulp.dest('dist/')) 71 | }); 72 | 73 | gulp.task('coffee:tests', function(e){ 74 | return gulp.src(paths.src.tests) 75 | .pipe(plumber()) 76 | .pipe(changed(paths.src.tests)) 77 | .pipe(coffeelint()) 78 | .pipe(coffeelint.reporter()) 79 | .pipe(coffee()) 80 | .pipe(gulp.dest(paths.dist.tests)) 81 | .pipe(livereload()) 82 | }); 83 | 84 | gulp.task('test', function(){ 85 | return gulp.src('spec/SpecRunner.html') 86 | .pipe(jasminePhantomJs()); 87 | }); 88 | 89 | gulp.task('kit:jade', function(e){ 90 | return gulp.src(paths.src.kit) 91 | .pipe(jade({pretty:true})) 92 | .pipe(gulp.dest(paths.dist.kit)) 93 | .pipe(livereload()) 94 | }); 95 | 96 | gulp.task('index:jade', function(e){ 97 | return gulp.src(paths.src.index) 98 | .pipe(jade({pretty:true})) 99 | .pipe(gulp.dest(paths.dist.index)) 100 | .pipe(livereload()) 101 | }); 102 | 103 | gulp.task('default', function(){ 104 | var server = livereload(); 105 | 106 | gulp.watch(paths.src.css, function(e){ 107 | gulp.run('stylus'); 108 | }); 109 | 110 | gulp.watch(paths.src.js, function(e){ 111 | gulp.run('coffee', 'build'); 112 | server.changed(e.path) 113 | }); 114 | 115 | gulp.watch(paths.src.tests, function(e){ 116 | gulp.run('coffee:tests'); 117 | server.changed(e.path) 118 | }); 119 | 120 | gulp.watch(paths.src.kit, function(e){ 121 | gulp.run('kit:jade'); 122 | server.changed(e.path); 123 | }); 124 | 125 | gulp.watch(paths.src.index, function(e){ 126 | gulp.run('index:jade'); 127 | server.changed(e.path); 128 | }); 129 | 130 | gulp.watch(paths.src.partials, function(e){ 131 | gulp.run('kit:jade'); 132 | gulp.run('index:jade'); 133 | server.changed(e.path); 134 | }); 135 | 136 | gulp.watch(paths.src.templates, function(e){ 137 | gulp.run('index:jade'); 138 | server.changed(e.path); 139 | }); 140 | 141 | }); 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /spec/lib/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | .html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | .html-reporter a { text-decoration: none; } 5 | .html-reporter a:hover { text-decoration: underline; } 6 | .html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; } 7 | .html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } 8 | .html-reporter .banner .version { margin-left: 14px; } 9 | .html-reporter #jasmine_content { position: fixed; right: 100%; } 10 | .html-reporter .version { color: #aaaaaa; } 11 | .html-reporter .banner { margin-top: 14px; } 12 | .html-reporter .duration { color: #aaaaaa; float: right; } 13 | .html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } 14 | .html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; } 15 | .html-reporter .symbol-summary li.passed { font-size: 14px; } 16 | .html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; } 17 | .html-reporter .symbol-summary li.failed { line-height: 9px; } 18 | .html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 19 | .html-reporter .symbol-summary li.disabled { font-size: 14px; } 20 | .html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } 21 | .html-reporter .symbol-summary li.pending { line-height: 17px; } 22 | .html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; } 23 | .html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 24 | .html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 25 | .html-reporter .bar.failed { background-color: #b03911; } 26 | .html-reporter .bar.passed { background-color: #a6b779; } 27 | .html-reporter .bar.skipped { background-color: #bababa; } 28 | .html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } 29 | .html-reporter .bar.menu a { color: #333333; } 30 | .html-reporter .bar a { color: white; } 31 | .html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; } 32 | .html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; } 33 | .html-reporter .running-alert { background-color: #666666; } 34 | .html-reporter .results { margin-top: 14px; } 35 | .html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 36 | .html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 37 | .html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 38 | .html-reporter.showDetails .summary { display: none; } 39 | .html-reporter.showDetails #details { display: block; } 40 | .html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 41 | .html-reporter .summary { margin-top: 14px; } 42 | .html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } 43 | .html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } 44 | .html-reporter .summary li.passed a { color: #5e7d00; } 45 | .html-reporter .summary li.failed a { color: #b03911; } 46 | .html-reporter .summary li.pending a { color: #ba9d37; } 47 | .html-reporter .description + .suite { margin-top: 0; } 48 | .html-reporter .suite { margin-top: 14px; } 49 | .html-reporter .suite a { color: #333333; } 50 | .html-reporter .failures .spec-detail { margin-bottom: 28px; } 51 | .html-reporter .failures .spec-detail .description { background-color: #b03911; } 52 | .html-reporter .failures .spec-detail .description a { color: white; } 53 | .html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; } 54 | .html-reporter .result-message span.result { display: block; } 55 | .html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 56 | -------------------------------------------------------------------------------- /js/any-resize-event.coffee: -------------------------------------------------------------------------------- 1 | ###! 2 | LegoMushroom @legomushroom http://legomushroom.com 3 | MIT License 2014 4 | ### 5 | 6 | # TODO 7 | # travis ci tests as at https://github.com/larrymyers/react-mini-router 8 | 9 | class Main 10 | constructor:(@o={})-> 11 | return if window.isAnyResizeEventInited 12 | @vars() 13 | @redefineProto() 14 | 15 | vars:-> 16 | window.isAnyResizeEventInited = true 17 | @allowedProtos = [ 18 | HTMLDivElement, 19 | HTMLFormElement, 20 | HTMLLinkElement, 21 | HTMLBodyElement, 22 | HTMLParagraphElement, 23 | HTMLFieldSetElement, 24 | HTMLLegendElement, 25 | HTMLLabelElement, 26 | HTMLButtonElement, 27 | HTMLUListElement, 28 | HTMLOListElement, 29 | HTMLLIElement, 30 | HTMLHeadingElement, 31 | HTMLQuoteElement, 32 | HTMLPreElement, 33 | HTMLBRElement, 34 | HTMLFontElement, 35 | HTMLHRElement, 36 | HTMLModElement, 37 | HTMLParamElement, 38 | HTMLMapElement, 39 | HTMLTableElement, 40 | HTMLTableCaptionElement, 41 | HTMLImageElement, 42 | HTMLTableCellElement, 43 | HTMLSelectElement, 44 | HTMLInputElement, 45 | HTMLTextAreaElement, 46 | HTMLAnchorElement, 47 | HTMLObjectElement, 48 | HTMLTableColElement, 49 | HTMLTableSectionElement, 50 | HTMLTableRowElement 51 | ] 52 | @timerElements = 53 | img: 1 54 | textarea: 1 55 | input: 1 56 | embed: 1 57 | object: 1 58 | svg: 1 59 | canvas: 1 60 | tr: 1 61 | tbody: 1 62 | thead: 1 63 | tfoot: 1 64 | a: 1 65 | select: 1 66 | option: 1 67 | optgroup: 1 68 | dl: 1 69 | dt: 1 70 | br: 1 71 | basefont: 1 72 | font: 1 73 | col: 1 74 | iframe: 1 75 | 76 | redefineProto:-> 77 | it = @ 78 | t = for proto, i in @allowedProtos 79 | if !proto::? then continue 80 | do (proto)-> 81 | listener = proto::addEventListener or proto::attachEvent 82 | do (listener)-> 83 | wrappedListener = -> 84 | if @ isnt window or @ isnt document 85 | option = arguments[0] is 'onresize' and !@isAnyResizeEventInited 86 | option and it.handleResize 87 | args:arguments 88 | that:@ 89 | listener.apply(@,arguments) 90 | if proto::addEventListener 91 | proto::addEventListener = wrappedListener 92 | else if proto::attachEvent 93 | proto::attachEvent = wrappedListener 94 | 95 | remover = proto::removeEventListener or proto::detachEvent 96 | do (remover)-> 97 | wrappedRemover = -> 98 | @isAnyResizeEventInited = false 99 | @iframe and @removeChild @iframe 100 | remover.apply(@,arguments) 101 | if proto::removeEventListener 102 | proto::removeEventListener = wrappedRemover 103 | else if proto::detachEvent 104 | proto::detachEvent = wrappedListener 105 | 106 | handleResize:(args)-> 107 | el = args.that 108 | if !@timerElements[el.tagName.toLowerCase()] 109 | iframe = document.createElement 'iframe' 110 | el.appendChild iframe 111 | iframe.style.width = '100%' 112 | iframe.style.height = '100%' 113 | iframe.style.position = 'absolute' 114 | iframe.style.zIndex = -999 115 | iframe.style.opacity = 0 116 | iframe.style.top = 0 117 | iframe.style.left = 0 118 | 119 | computedStyle = if window.getComputedStyle 120 | getComputedStyle(el) 121 | else el.currentStyle 122 | 123 | isStatic = computedStyle.position is 'static' and el.style.position is '' 124 | isEmpty = computedStyle.position is '' and el.style.position is '' 125 | if isStatic or isEmpty 126 | el.style.position = 'relative' 127 | iframe.contentWindow?.onresize = (e)=> @dispatchEvent el 128 | el.iframe = iframe 129 | else @initTimer(el) 130 | el.isAnyResizeEventInited = true 131 | 132 | initTimer:(el)-> 133 | width = 0 134 | height = 0 135 | @interval = setInterval => 136 | newWidth = el.offsetWidth 137 | newHeight = el.offsetHeight 138 | if newWidth isnt width or newHeight isnt height 139 | @dispatchEvent el 140 | width = newWidth 141 | height = newHeight 142 | , @o.interval or 62.5 143 | 144 | dispatchEvent:(el)-> 145 | if document.createEvent 146 | e = document.createEvent 'HTMLEvents' 147 | e.initEvent 'onresize', false, false 148 | el.dispatchEvent e 149 | else if document.createEventObject 150 | e = document.createEventObject() 151 | el.fireEvent 'onresize', e 152 | else return false 153 | 154 | destroy:-> 155 | clearInterval @interval 156 | @interval = null 157 | window.isAnyResizeEventInited = false 158 | 159 | it = @ 160 | for proto, i in @allowedProtos 161 | if !proto::? then continue 162 | do (proto)-> 163 | listener = proto::addEventListener or proto::attachEvent 164 | if proto::addEventListener 165 | proto::addEventListener = Element::addEventListener 166 | else if proto::attachEvent 167 | proto::attachEvent = Element::attachEvent 168 | 169 | if proto::removeEventListener 170 | proto::removeEventListener = Element::removeEventListener 171 | else if proto::detachEvent 172 | proto::detachEvent = Element::detachEvent 173 | 174 | if (typeof define is "function") and define.amd 175 | define "any-resize-event", [], -> new Main 176 | else if (typeof module is "object") and (typeof module.exports is "object") 177 | module.exports = new Main 178 | else 179 | window?.AnyResizeEvent = Main 180 | window?.anyResizeEvent = new Main 181 | -------------------------------------------------------------------------------- /spec/spec.coffee: -------------------------------------------------------------------------------- 1 | describe 'resizer', -> 2 | # window.anyResizeEvent.destroy() 3 | addEvent = (el, type, handler)-> 4 | if el.addEventListener 5 | el.addEventListener type, handler, false 6 | else if el.attachEvent 7 | el.attachEvent type, handler, false 8 | 9 | removeEvent = (el, type, handler)-> 10 | if el.removeEventListener 11 | el.removeEventListener type, handler, false 12 | else if el.detachEvent 13 | el.detachEvent type, handler, false 14 | 15 | main = null 16 | beforeListener = null 17 | describe 'enviroment', -> 18 | it 'should allow to write to Element prototype', -> 19 | Element::testProperty = 'test' 20 | expect(Element::testProperty).toBe('test') 21 | 22 | it 'should have a dispatch event functionality', -> 23 | isIE = !!document.createEventObject and !!document.fireEvent 24 | isNormalBrowser = !!document.createEvent and !!document.dispatchEvent 25 | expect(isIE or isNormalBrowser).toBe(true) 26 | 27 | it 'should have a addEventListener or attachEvent', -> 28 | div = document.createElement 'div' 29 | expect(div.addEventListener or div.attachEvent).toBeTruthy() 30 | 31 | it 'should have a removeEventListener or detachEvent', -> 32 | div = document.createElement 'div' 33 | expect(div.removeEventListener or div.detachEvent).toBeTruthy() 34 | 35 | it 'should have a computedStyle functionality', -> 36 | el = document.createElement 'div' 37 | expect(window.getComputedStyle or el.currentStyle).toBeDefined() 38 | 39 | it 'should have size detection functionality', -> 40 | el = document.createElement 'div' 41 | document.body.appendChild el 42 | expect(el.offsetWidth).toBeDefined() 43 | expect(el.offsetHeight).toBeDefined() 44 | 45 | it 'should have size detection functionality', -> 46 | el = document.createElement 'div' 47 | expect(typeof el.appendChild is 'function').toBe(true) 48 | 49 | describe 'DOM:', -> 50 | it 'should add iframe to the element', -> 51 | el = document.createElement 'div' 52 | document.body.appendChild el 53 | addEvent el, 'onresize', (->) 54 | expect(el.hasChildNodes()).toBe(true) 55 | 56 | it 'should have an access to iframe window', -> 57 | el = document.createElement 'div' 58 | addEvent el, 'onresize', (->) 59 | iframe = el.children[0] 60 | document.body.appendChild el 61 | expect(iframe.contentWindow).toBeDefined() 62 | 63 | describe 'iframe onresize method', -> 64 | beforeEach (done)-> setTimeout((-> done()), 2) 65 | 66 | it 'iframe should have onresize method', -> 67 | el = document.createElement 'div' 68 | document.body.appendChild el 69 | addEvent el, 'onresize', (->) 70 | iframe = el.children[0] 71 | expect(iframe.contentWindow.onresize or main.interval).toBeDefined() 72 | 73 | it 'should add position: relative style to static element', -> 74 | el = document.createElement 'div' 75 | addEvent el, 'onresize', (->) 76 | expect(el.style.position).toBe('relative') 77 | 78 | it 'should not alter absolute position style', -> 79 | el = document.createElement 'div' 80 | el.style.position = 'absolute' 81 | addEvent el, 'onresize', (->) 82 | expect(el.style.position).toBe('absolute') 83 | 84 | it 'should not alter fixed position style', -> 85 | el = document.createElement 'div' 86 | el.style.position = 'fixed' 87 | addEvent el, 'onresize', (->) 88 | expect(el.style.position).toBe('fixed') 89 | 90 | it 'iframe should have right styles', -> 91 | el = document.createElement 'div' 92 | addEvent el, 'onresize', (->) 93 | iframe = el.children[0] 94 | expect(iframe.style.position).toBe('absolute') 95 | expect(iframe.style.width).toBe('100%') 96 | expect(iframe.style.height).toBe('100%') 97 | expect(iframe.style.zIndex+'').toBe('-999') 98 | expect(parseInt(iframe.style.top,10)).toBe(0) 99 | expect(parseInt(iframe.style.left,10)).toBe(0) 100 | expect(iframe.style.opacity).toBe('0') 101 | 102 | describe 'constrains:', -> 103 | it 'should work on resize event only ', -> 104 | el = document.createElement 'div' 105 | addEvent el, 'click', (->) 106 | # el.addEventListener 'click', (->), false 107 | iframe = el.children[0] 108 | document.body.appendChild el 109 | expect(el.children.length).toBe(0) 110 | 111 | it 'should be initialized only once', -> 112 | new window.AnyResizeEvent 113 | el = document.createElement 'div' 114 | addEvent el, 'onresize', (->) 115 | iframe = el.children[0] 116 | document.body.appendChild el 117 | expect(el.children.length).toBe(1) 118 | 119 | it 'should add only one listener', -> 120 | el = document.createElement 'div' 121 | addEvent el, 'onresize', (->) 122 | addEvent el, 'onresize', (->) 123 | iframe = el.children[0] 124 | document.body.appendChild el 125 | expect(el.children.length).toBe(1) 126 | 127 | it 'should removeEventListener', -> 128 | el = document.createElement 'div' 129 | fun = -> 130 | addEvent el, 'onresize', fun 131 | removeEvent el, 'onresize', fun 132 | document.body.appendChild el 133 | expect(el.isAnyResizeEventInited).toBe(false) 134 | 135 | it 'should remove iframe after removeEventListener', -> 136 | el = document.createElement 'div' 137 | fun = -> 138 | addEvent el, 'onresize', fun 139 | removeEvent el, 'onresize', fun 140 | document.body.appendChild el 141 | expect(el.hasChildNodes()).toBe(false) 142 | 143 | it 'should fail when removeEvent was called before addEvent', -> 144 | el = document.createElement 'div' 145 | isError = false 146 | fun = -> 147 | try 148 | removeEvent el, 'onresize', fun 149 | catch e 150 | isError = true 151 | 152 | expect(isError).toBe(false) 153 | 154 | describe 'scope', -> 155 | scope = null 156 | el = document.createElement 'div' 157 | beforeEach (done)-> 158 | document.body.appendChild el 159 | addEvent el, 'onresize', -> scope = @ 160 | # setTimeout => 161 | # need a timeout in real spec runner 162 | el.style.width = '201px' 163 | setTimeout (-> done()), 25 164 | # , 150 165 | 166 | it 'should have node\'s scope' , -> expect(scope).toEqual(el) 167 | 168 | it 'should reverse old listener on destroy', -> 169 | window.anyResizeEvent.destroy() 170 | main = new window.AnyResizeEvent 171 | el = document.createElement 'div' 172 | addEvent el, 'onresize', (->) 173 | main.destroy() 174 | expect(HTMLDivElement::addEventListener).toBe(Element::addEventListener) 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /spec/lib/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = { 36 | describe: function(description, specDefinitions) { 37 | return env.describe(description, specDefinitions); 38 | }, 39 | 40 | xdescribe: function(description, specDefinitions) { 41 | return env.xdescribe(description, specDefinitions); 42 | }, 43 | 44 | it: function(desc, func) { 45 | return env.it(desc, func); 46 | }, 47 | 48 | xit: function(desc, func) { 49 | return env.xit(desc, func); 50 | }, 51 | 52 | beforeEach: function(beforeEachFunction) { 53 | return env.beforeEach(beforeEachFunction); 54 | }, 55 | 56 | afterEach: function(afterEachFunction) { 57 | return env.afterEach(afterEachFunction); 58 | }, 59 | 60 | expect: function(actual) { 61 | return env.expect(actual); 62 | }, 63 | 64 | pending: function() { 65 | return env.pending(); 66 | }, 67 | 68 | spyOn: function(obj, methodName) { 69 | return env.spyOn(obj, methodName); 70 | }, 71 | 72 | jsApiReporter: new jasmine.JsApiReporter({ 73 | timer: new jasmine.Timer() 74 | }) 75 | }; 76 | 77 | /** 78 | * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 79 | */ 80 | if (typeof window == "undefined" && typeof exports == "object") { 81 | extend(exports, jasmineInterface); 82 | } else { 83 | extend(window, jasmineInterface); 84 | } 85 | 86 | /** 87 | * Expose the interface for adding custom equality testers. 88 | */ 89 | jasmine.addCustomEqualityTester = function(tester) { 90 | env.addCustomEqualityTester(tester); 91 | }; 92 | 93 | /** 94 | * Expose the interface for adding custom expectation matchers 95 | */ 96 | jasmine.addMatchers = function(matchers) { 97 | return env.addMatchers(matchers); 98 | }; 99 | 100 | /** 101 | * Expose the mock interface for the JavaScript timeout functions 102 | */ 103 | jasmine.clock = function() { 104 | return env.clock; 105 | }; 106 | 107 | /** 108 | * ## Runner Parameters 109 | * 110 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 111 | */ 112 | 113 | var queryString = new jasmine.QueryString({ 114 | getWindowLocation: function() { return window.location; } 115 | }); 116 | 117 | var catchingExceptions = queryString.getParam("catch"); 118 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 119 | 120 | /** 121 | * ## Reporters 122 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 123 | */ 124 | var htmlReporter = new jasmine.HtmlReporter({ 125 | env: env, 126 | onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, 127 | getContainer: function() { return document.body; }, 128 | createElement: function() { return document.createElement.apply(document, arguments); }, 129 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 130 | timer: new jasmine.Timer() 131 | }); 132 | 133 | /** 134 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 135 | */ 136 | env.addReporter(jasmineInterface.jsApiReporter); 137 | var JUnitXmlReporter = jasmineRequire.JUnitXmlReporter() 138 | env.addReporter(new JUnitXmlReporter()); 139 | env.addReporter(htmlReporter); 140 | 141 | /** 142 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 143 | */ 144 | var specFilter = new jasmine.HtmlSpecFilter({ 145 | filterString: function() { return queryString.getParam("spec"); } 146 | }); 147 | 148 | env.specFilter = function(spec) { 149 | return specFilter.matches(spec.getFullName()); 150 | }; 151 | 152 | /** 153 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 154 | */ 155 | window.setTimeout = window.setTimeout; 156 | window.setInterval = window.setInterval; 157 | window.clearTimeout = window.clearTimeout; 158 | window.clearInterval = window.clearInterval; 159 | 160 | /** 161 | * ## Execution 162 | * 163 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 164 | */ 165 | var currentWindowOnload = window.onload; 166 | 167 | window.onload = function() { 168 | if (currentWindowOnload) { 169 | currentWindowOnload(); 170 | } 171 | htmlReporter.initialize(); 172 | env.execute(); 173 | }; 174 | 175 | /** 176 | * Helper function for readability above. 177 | */ 178 | function extend(destination, source) { 179 | for (var property in source) destination[property] = source[property]; 180 | return destination; 181 | } 182 | 183 | }()); 184 | -------------------------------------------------------------------------------- /spec/lib/jasmine2-junit.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | "use strict"; 3 | 4 | function getJasmineRequireObj() { 5 | if (typeof module !== "undefined" && module.exports) { 6 | return exports; 7 | } else { 8 | window.jasmineRequire = window.jasmineRequire || {}; 9 | return window.jasmineRequire; 10 | } 11 | } 12 | 13 | if (typeof getJasmineRequireObj() == 'undefined') { 14 | throw new Error("jasmine 2.0 must be loaded before jasmine-junit"); 15 | } 16 | 17 | getJasmineRequireObj().JUnitXmlReporter = function() { 18 | 19 | 20 | function JUnitXmlReporter(options) { 21 | var runStartTime; 22 | var specStartTime; 23 | var suiteLevel = -1; 24 | var suites = [] 25 | var currentSuite; 26 | var totalNumberOfSpecs; 27 | var totalNumberOfFailures; 28 | 29 | this.jasmineStarted = function(started) { 30 | totalNumberOfSpecs = started.totalSpecsDefined; 31 | runStartTime = new Date(); 32 | }; 33 | 34 | this.jasmineDone = function() { 35 | console.log('Jasmine ran in ', elapsed(runStartTime, new Date()), ' seconds') 36 | window.done = true 37 | }; 38 | 39 | this.suiteStarted = function(result) { 40 | suiteLevel++; 41 | if (suiteLevel == 0) { 42 | totalNumberOfSpecs = 0; 43 | totalNumberOfFailures = 0; 44 | suites.push(result); 45 | currentSuite = result; 46 | currentSuite.startTime = new Date(); 47 | currentSuite.noOfSpecs = 0; 48 | currentSuite.noOfFails = 0; 49 | currentSuite.specs = []; 50 | } 51 | }; 52 | 53 | this.suiteDone = function(result) { 54 | if (suiteLevel == 0) { 55 | currentSuite.endTime = new Date(); 56 | writeFile('.', descToFilename(result.description), suiteToJUnitXml(currentSuite)) 57 | } 58 | suiteLevel--; 59 | }; 60 | 61 | this.specStarted = function(result) { 62 | specStartTime = new Date(); 63 | }; 64 | 65 | this.specDone = function(result) { 66 | totalNumberOfSpecs++; 67 | 68 | if (isFailed(result)) { 69 | currentSuite.noOfFails++; 70 | } 71 | result.startTime = specStartTime; 72 | result.endTime = new Date(); 73 | currentSuite.specs.push(result); 74 | currentSuite.noOfSpecs++; 75 | }; 76 | 77 | return this; 78 | 79 | } 80 | 81 | return JUnitXmlReporter; 82 | }; 83 | 84 | function isFailed(result) { 85 | return result.status === 'failed' 86 | } 87 | 88 | function isSkipped(result) { 89 | return result.status === 'pending' 90 | } 91 | 92 | function suiteToJUnitXml(suite) { 93 | var resultXml = '\n'; 94 | resultXml += '\n'; 95 | resultXml += '\t\n' 96 | for (var i = 0; i < suite.specs.length; i++) { 97 | resultXml += specToJUnitXml(suite.specs[i], suite.id); 98 | } 99 | resultXml += '\t\n\n\n' 100 | return resultXml; 101 | } 102 | 103 | function specToJUnitXml(spec, suiteId) { 104 | var xml = '\t\t\n'; 106 | if (isSkipped(spec)) { 107 | xml += '\t\t\t\n'; 108 | } 109 | if (isFailed(spec)) { 110 | xml += failedToJUnitXml(spec.failedExpectations) 111 | } 112 | xml += '\t\t\n' 113 | return xml; 114 | } 115 | 116 | function failedToJUnitXml(failedExpectations) { 117 | var failure; 118 | var failureXml = "" 119 | for (var i = 0; i < failedExpectations.length; i++) { 120 | failure = failedExpectations[i]; 121 | failureXml += '\t\t\t\n'; 122 | failureXml += escapeInvalidXmlChars(failure.stack || failure.message); 123 | failureXml += "\t\t\t\n"; 124 | } 125 | 126 | return failureXml; 127 | } 128 | 129 | function descToFilename(desc) { 130 | return 'TEST-' + desc + '.xml'; 131 | } 132 | 133 | function ISODateString(d) { 134 | function pad(n) { 135 | return n < 10 ? '0' + n : n; 136 | } 137 | 138 | return d.getFullYear() + '-' + 139 | pad(d.getMonth() + 1) + '-' + 140 | pad(d.getDate()) + 'T' + 141 | pad(d.getHours()) + ':' + 142 | pad(d.getMinutes()) + ':' + 143 | pad(d.getSeconds()); 144 | } 145 | 146 | function elapsed(startTime, endTime) { 147 | return (endTime - startTime) / 1000; 148 | } 149 | 150 | function trim(str) { 151 | return str.replace(/^\s+/, "").replace(/\s+$/, ""); 152 | } 153 | 154 | function escapeInvalidXmlChars(str) { 155 | return str.replace(//g, ">") 157 | .replace(/\"/g, """) 158 | .replace(/\'/g, "'") 159 | .replace(/\&/g, "&"); 160 | } 161 | 162 | function writeFile(path, filename, text) { 163 | function getQualifiedFilename(separator) { 164 | if (path && path.substr(-1) !== separator && filename.substr(0) !== separator) { 165 | path += separator; 166 | } 167 | return path + filename; 168 | } 169 | 170 | // PhantomJS 171 | if(typeof(__phantom_writeFile) !== 'undefined') { 172 | try { 173 | // turn filename into a qualified path 174 | filename = getQualifiedFilename(window.fs_path_separator); 175 | // function injected by jasmine-runner.js 176 | __phantom_writeFile(filename, text); 177 | return; 178 | } catch (error) { 179 | console.log('Error writing file', error) 180 | } 181 | } 182 | 183 | // Node.js 184 | if(typeof(global) !== 'undefined') { 185 | try { 186 | var fs = require("fs"); 187 | var nodejs_path = require("path"); 188 | var fd = fs.openSync(nodejs_path.join(path, filename), "w"); 189 | fs.writeSync(fd, text, 0); 190 | fs.closeSync(fd); 191 | return; 192 | } catch (error) { 193 | console.log('Error writing file', error) 194 | } 195 | } 196 | } 197 | 198 | })() -------------------------------------------------------------------------------- /js/any-resize-event.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | LegoMushroom @legomushroom http://legomushroom.com 4 | MIT License 2014 5 | */ 6 | 7 | (function() { 8 | var Main; 9 | 10 | Main = (function() { 11 | function Main(o) { 12 | this.o = o != null ? o : {}; 13 | if (window.isAnyResizeEventInited) { 14 | return; 15 | } 16 | this.vars(); 17 | this.redefineProto(); 18 | } 19 | 20 | Main.prototype.vars = function() { 21 | window.isAnyResizeEventInited = true; 22 | this.allowedProtos = [HTMLDivElement, HTMLFormElement, HTMLLinkElement, HTMLBodyElement, HTMLParagraphElement, HTMLFieldSetElement, HTMLLegendElement, HTMLLabelElement, HTMLButtonElement, HTMLUListElement, HTMLOListElement, HTMLLIElement, HTMLHeadingElement, HTMLQuoteElement, HTMLPreElement, HTMLBRElement, HTMLFontElement, HTMLHRElement, HTMLModElement, HTMLParamElement, HTMLMapElement, HTMLTableElement, HTMLTableCaptionElement, HTMLImageElement, HTMLTableCellElement, HTMLSelectElement, HTMLInputElement, HTMLTextAreaElement, HTMLAnchorElement, HTMLObjectElement, HTMLTableColElement, HTMLTableSectionElement, HTMLTableRowElement]; 23 | return this.timerElements = { 24 | img: 1, 25 | textarea: 1, 26 | input: 1, 27 | embed: 1, 28 | object: 1, 29 | svg: 1, 30 | canvas: 1, 31 | tr: 1, 32 | tbody: 1, 33 | thead: 1, 34 | tfoot: 1, 35 | a: 1, 36 | select: 1, 37 | option: 1, 38 | optgroup: 1, 39 | dl: 1, 40 | dt: 1, 41 | br: 1, 42 | basefont: 1, 43 | font: 1, 44 | col: 1, 45 | iframe: 1 46 | }; 47 | }; 48 | 49 | Main.prototype.redefineProto = function() { 50 | var i, it, proto, t; 51 | it = this; 52 | return t = (function() { 53 | var _i, _len, _ref, _results; 54 | _ref = this.allowedProtos; 55 | _results = []; 56 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 57 | proto = _ref[i]; 58 | if (proto.prototype == null) { 59 | continue; 60 | } 61 | _results.push((function(proto) { 62 | var listener, remover; 63 | listener = proto.prototype.addEventListener || proto.prototype.attachEvent; 64 | (function(listener) { 65 | var wrappedListener; 66 | wrappedListener = function() { 67 | var option; 68 | if (this !== window || this !== document) { 69 | option = arguments[0] === 'onresize' && !this.isAnyResizeEventInited; 70 | option && it.handleResize({ 71 | args: arguments, 72 | that: this 73 | }); 74 | } 75 | return listener.apply(this, arguments); 76 | }; 77 | if (proto.prototype.addEventListener) { 78 | return proto.prototype.addEventListener = wrappedListener; 79 | } else if (proto.prototype.attachEvent) { 80 | return proto.prototype.attachEvent = wrappedListener; 81 | } 82 | })(listener); 83 | remover = proto.prototype.removeEventListener || proto.prototype.detachEvent; 84 | return (function(remover) { 85 | var wrappedRemover; 86 | wrappedRemover = function() { 87 | this.isAnyResizeEventInited = false; 88 | this.iframe && this.removeChild(this.iframe); 89 | return remover.apply(this, arguments); 90 | }; 91 | if (proto.prototype.removeEventListener) { 92 | return proto.prototype.removeEventListener = wrappedRemover; 93 | } else if (proto.prototype.detachEvent) { 94 | return proto.prototype.detachEvent = wrappedListener; 95 | } 96 | })(remover); 97 | })(proto)); 98 | } 99 | return _results; 100 | }).call(this); 101 | }; 102 | 103 | Main.prototype.handleResize = function(args) { 104 | var computedStyle, el, iframe, isEmpty, isStatic, _ref; 105 | el = args.that; 106 | if (!this.timerElements[el.tagName.toLowerCase()]) { 107 | iframe = document.createElement('iframe'); 108 | el.appendChild(iframe); 109 | iframe.style.width = '100%'; 110 | iframe.style.height = '100%'; 111 | iframe.style.position = 'absolute'; 112 | iframe.style.zIndex = -999; 113 | iframe.style.opacity = 0; 114 | iframe.style.top = 0; 115 | iframe.style.left = 0; 116 | computedStyle = window.getComputedStyle ? getComputedStyle(el) : el.currentStyle; 117 | isStatic = computedStyle.position === 'static' && el.style.position === ''; 118 | isEmpty = computedStyle.position === '' && el.style.position === ''; 119 | if (isStatic || isEmpty) { 120 | el.style.position = 'relative'; 121 | } 122 | if ((_ref = iframe.contentWindow) != null) { 123 | _ref.onresize = (function(_this) { 124 | return function(e) { 125 | return _this.dispatchEvent(el); 126 | }; 127 | })(this); 128 | } 129 | el.iframe = iframe; 130 | } else { 131 | this.initTimer(el); 132 | } 133 | return el.isAnyResizeEventInited = true; 134 | }; 135 | 136 | Main.prototype.initTimer = function(el) { 137 | var height, width; 138 | width = 0; 139 | height = 0; 140 | return this.interval = setInterval((function(_this) { 141 | return function() { 142 | var newHeight, newWidth; 143 | newWidth = el.offsetWidth; 144 | newHeight = el.offsetHeight; 145 | if (newWidth !== width || newHeight !== height) { 146 | _this.dispatchEvent(el); 147 | width = newWidth; 148 | return height = newHeight; 149 | } 150 | }; 151 | })(this), this.o.interval || 62.5); 152 | }; 153 | 154 | Main.prototype.dispatchEvent = function(el) { 155 | var e; 156 | if (document.createEvent) { 157 | e = document.createEvent('HTMLEvents'); 158 | e.initEvent('onresize', false, false); 159 | return el.dispatchEvent(e); 160 | } else if (document.createEventObject) { 161 | e = document.createEventObject(); 162 | return el.fireEvent('onresize', e); 163 | } else { 164 | return false; 165 | } 166 | }; 167 | 168 | Main.prototype.destroy = function() { 169 | var i, it, proto, _i, _len, _ref, _results; 170 | clearInterval(this.interval); 171 | this.interval = null; 172 | window.isAnyResizeEventInited = false; 173 | it = this; 174 | _ref = this.allowedProtos; 175 | _results = []; 176 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 177 | proto = _ref[i]; 178 | if (proto.prototype == null) { 179 | continue; 180 | } 181 | _results.push((function(proto) { 182 | var listener; 183 | listener = proto.prototype.addEventListener || proto.prototype.attachEvent; 184 | if (proto.prototype.addEventListener) { 185 | proto.prototype.addEventListener = Element.prototype.addEventListener; 186 | } else if (proto.prototype.attachEvent) { 187 | proto.prototype.attachEvent = Element.prototype.attachEvent; 188 | } 189 | if (proto.prototype.removeEventListener) { 190 | return proto.prototype.removeEventListener = Element.prototype.removeEventListener; 191 | } else if (proto.prototype.detachEvent) { 192 | return proto.prototype.detachEvent = Element.prototype.detachEvent; 193 | } 194 | })(proto)); 195 | } 196 | return _results; 197 | }; 198 | 199 | return Main; 200 | 201 | })(); 202 | 203 | if ((typeof define === "function") && define.amd) { 204 | define("any-resize-event", [], function() { 205 | return new Main; 206 | }); 207 | } else if ((typeof module === "object") && (typeof module.exports === "object")) { 208 | module.exports = new Main; 209 | } else { 210 | if (typeof window !== "undefined" && window !== null) { 211 | window.AnyResizeEvent = Main; 212 | } 213 | if (typeof window !== "undefined" && window !== null) { 214 | window.anyResizeEvent = new Main; 215 | } 216 | } 217 | 218 | }).call(this); 219 | -------------------------------------------------------------------------------- /dist/any-resize-event.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | LegoMushroom @legomushroom http://legomushroom.com 4 | MIT License 2014 5 | */ 6 | 7 | (function() { 8 | var Main; 9 | 10 | Main = (function() { 11 | function Main(o) { 12 | this.o = o != null ? o : {}; 13 | if (window.isAnyResizeEventInited) { 14 | return; 15 | } 16 | this.vars(); 17 | this.redefineProto(); 18 | } 19 | 20 | Main.prototype.vars = function() { 21 | window.isAnyResizeEventInited = true; 22 | this.allowedProtos = [HTMLDivElement, HTMLFormElement, HTMLLinkElement, HTMLBodyElement, HTMLParagraphElement, HTMLFieldSetElement, HTMLLegendElement, HTMLLabelElement, HTMLButtonElement, HTMLUListElement, HTMLOListElement, HTMLLIElement, HTMLHeadingElement, HTMLQuoteElement, HTMLPreElement, HTMLBRElement, HTMLFontElement, HTMLHRElement, HTMLModElement, HTMLParamElement, HTMLMapElement, HTMLTableElement, HTMLTableCaptionElement, HTMLImageElement, HTMLTableCellElement, HTMLSelectElement, HTMLInputElement, HTMLTextAreaElement, HTMLAnchorElement, HTMLObjectElement, HTMLTableColElement, HTMLTableSectionElement, HTMLTableRowElement]; 23 | return this.timerElements = { 24 | img: 1, 25 | textarea: 1, 26 | input: 1, 27 | embed: 1, 28 | object: 1, 29 | svg: 1, 30 | canvas: 1, 31 | tr: 1, 32 | tbody: 1, 33 | thead: 1, 34 | tfoot: 1, 35 | a: 1, 36 | select: 1, 37 | option: 1, 38 | optgroup: 1, 39 | dl: 1, 40 | dt: 1, 41 | br: 1, 42 | basefont: 1, 43 | font: 1, 44 | col: 1, 45 | iframe: 1 46 | }; 47 | }; 48 | 49 | Main.prototype.redefineProto = function() { 50 | var i, it, proto, t; 51 | it = this; 52 | return t = (function() { 53 | var _i, _len, _ref, _results; 54 | _ref = this.allowedProtos; 55 | _results = []; 56 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 57 | proto = _ref[i]; 58 | if (proto.prototype == null) { 59 | continue; 60 | } 61 | _results.push((function(proto) { 62 | var listener, remover; 63 | listener = proto.prototype.addEventListener || proto.prototype.attachEvent; 64 | (function(listener) { 65 | var wrappedListener; 66 | wrappedListener = function() { 67 | var option; 68 | if (this !== window || this !== document) { 69 | option = arguments[0] === 'onresize' && !this.isAnyResizeEventInited; 70 | option && it.handleResize({ 71 | args: arguments, 72 | that: this 73 | }); 74 | } 75 | return listener.apply(this, arguments); 76 | }; 77 | if (proto.prototype.addEventListener) { 78 | return proto.prototype.addEventListener = wrappedListener; 79 | } else if (proto.prototype.attachEvent) { 80 | return proto.prototype.attachEvent = wrappedListener; 81 | } 82 | })(listener); 83 | remover = proto.prototype.removeEventListener || proto.prototype.detachEvent; 84 | return (function(remover) { 85 | var wrappedRemover; 86 | wrappedRemover = function() { 87 | this.isAnyResizeEventInited = false; 88 | this.iframe && this.removeChild(this.iframe); 89 | return remover.apply(this, arguments); 90 | }; 91 | if (proto.prototype.removeEventListener) { 92 | return proto.prototype.removeEventListener = wrappedRemover; 93 | } else if (proto.prototype.detachEvent) { 94 | return proto.prototype.detachEvent = wrappedListener; 95 | } 96 | })(remover); 97 | })(proto)); 98 | } 99 | return _results; 100 | }).call(this); 101 | }; 102 | 103 | Main.prototype.handleResize = function(args) { 104 | var computedStyle, el, iframe, isEmpty, isStatic, _ref; 105 | el = args.that; 106 | if (!this.timerElements[el.tagName.toLowerCase()]) { 107 | iframe = document.createElement('iframe'); 108 | el.appendChild(iframe); 109 | iframe.style.width = '100%'; 110 | iframe.style.height = '100%'; 111 | iframe.style.position = 'absolute'; 112 | iframe.style.zIndex = -999; 113 | iframe.style.opacity = 0; 114 | iframe.style.top = 0; 115 | iframe.style.left = 0; 116 | computedStyle = window.getComputedStyle ? getComputedStyle(el) : el.currentStyle; 117 | isStatic = computedStyle.position === 'static' && el.style.position === ''; 118 | isEmpty = computedStyle.position === '' && el.style.position === ''; 119 | if (isStatic || isEmpty) { 120 | el.style.position = 'relative'; 121 | } 122 | if ((_ref = iframe.contentWindow) != null) { 123 | _ref.onresize = (function(_this) { 124 | return function(e) { 125 | return _this.dispatchEvent(el); 126 | }; 127 | })(this); 128 | } 129 | el.iframe = iframe; 130 | } else { 131 | this.initTimer(el); 132 | } 133 | return el.isAnyResizeEventInited = true; 134 | }; 135 | 136 | Main.prototype.initTimer = function(el) { 137 | var height, width; 138 | width = 0; 139 | height = 0; 140 | return this.interval = setInterval((function(_this) { 141 | return function() { 142 | var newHeight, newWidth; 143 | newWidth = el.offsetWidth; 144 | newHeight = el.offsetHeight; 145 | if (newWidth !== width || newHeight !== height) { 146 | _this.dispatchEvent(el); 147 | width = newWidth; 148 | return height = newHeight; 149 | } 150 | }; 151 | })(this), this.o.interval || 62.5); 152 | }; 153 | 154 | Main.prototype.dispatchEvent = function(el) { 155 | var e; 156 | if (document.createEvent) { 157 | e = document.createEvent('HTMLEvents'); 158 | e.initEvent('onresize', false, false); 159 | return el.dispatchEvent(e); 160 | } else if (document.createEventObject) { 161 | e = document.createEventObject(); 162 | return el.fireEvent('onresize', e); 163 | } else { 164 | return false; 165 | } 166 | }; 167 | 168 | Main.prototype.destroy = function() { 169 | var i, it, proto, _i, _len, _ref, _results; 170 | clearInterval(this.interval); 171 | this.interval = null; 172 | window.isAnyResizeEventInited = false; 173 | it = this; 174 | _ref = this.allowedProtos; 175 | _results = []; 176 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { 177 | proto = _ref[i]; 178 | if (proto.prototype == null) { 179 | continue; 180 | } 181 | _results.push((function(proto) { 182 | var listener; 183 | listener = proto.prototype.addEventListener || proto.prototype.attachEvent; 184 | if (proto.prototype.addEventListener) { 185 | proto.prototype.addEventListener = Element.prototype.addEventListener; 186 | } else if (proto.prototype.attachEvent) { 187 | proto.prototype.attachEvent = Element.prototype.attachEvent; 188 | } 189 | if (proto.prototype.removeEventListener) { 190 | return proto.prototype.removeEventListener = Element.prototype.removeEventListener; 191 | } else if (proto.prototype.detachEvent) { 192 | return proto.prototype.detachEvent = Element.prototype.detachEvent; 193 | } 194 | })(proto)); 195 | } 196 | return _results; 197 | }; 198 | 199 | return Main; 200 | 201 | })(); 202 | 203 | if ((typeof define === "function") && define.amd) { 204 | define("any-resize-event", [], function() { 205 | return new Main; 206 | }); 207 | } else if ((typeof module === "object") && (typeof module.exports === "object")) { 208 | module.exports = new Main; 209 | } else { 210 | if (typeof window !== "undefined" && window !== null) { 211 | window.AnyResizeEvent = Main; 212 | } 213 | if (typeof window !== "undefined" && window !== null) { 214 | window.anyResizeEvent = new Main; 215 | } 216 | } 217 | 218 | }).call(this); 219 | -------------------------------------------------------------------------------- /spec/lib/jasmine2-runner.js: -------------------------------------------------------------------------------- 1 | /* globals jasmine, phantom */ 2 | // Verify arguments 3 | if (phantom.args.length === 0) { 4 | console.log("Simple JasmineBDD test runner for phantom.js"); 5 | console.log("Usage: phantomjs-testrunner.js url_to_runner.html"); 6 | console.log("Accepts http:// and file:// urls"); 7 | console.log(""); 8 | console.log("NOTE: This script depends on jasmine.TrivialReporter being used\non the page, for the DOM elements it creates.\n"); 9 | phantom.exit(2); 10 | } 11 | else { 12 | var args = phantom.args; 13 | var fs = require("fs"), 14 | pages = [], 15 | page, address, resultsKey, i, l; 16 | 17 | 18 | var setupPageFn = function(p, k) { 19 | return function() { 20 | overloadPageEvaluate(p); 21 | setupWriteFileFunction(p, k, fs.separator); 22 | }; 23 | }; 24 | 25 | for (i = 0, l = args.length; i < l; i++) { 26 | address = args[i]; 27 | console.log("Loading " + address); 28 | 29 | // create a WebPage object to work with 30 | page = require("webpage").create(); 31 | page.url = address; 32 | 33 | // When initialized, inject the reporting functions before the page is loaded 34 | // (and thus before it will try to utilize the functions) 35 | resultsKey = "__jr" + Math.ceil(Math.random() * 1000000); 36 | page.onInitialized = setupPageFn(page, resultsKey); 37 | page.open(address, processPage(null, page, resultsKey)); 38 | pages.push(page); 39 | 40 | page.onConsoleMessage = logAndWorkAroundDefaultLineBreaking; 41 | } 42 | 43 | // bail when all pages have been processed 44 | setInterval(function(){ 45 | var exit_code = 0; 46 | for (i = 0, l = pages.length; i < l; i++) { 47 | page = pages[i]; 48 | if (page.__exit_code === null) { 49 | // wait until later 50 | return; 51 | } 52 | exit_code |= page.__exit_code; 53 | } 54 | phantom.exit(exit_code); 55 | }, 100); 56 | } 57 | 58 | // Thanks to hoisting, these helpers are still available when needed above 59 | /** 60 | * Logs a message. Does not add a line-break for single characters '.' and 'F' or lines ending in ' ...' 61 | * 62 | * @param msg 63 | */ 64 | function logAndWorkAroundDefaultLineBreaking(msg) { 65 | var interpretAsWithoutNewline = /(^(\033\[\d+m)*[\.F](\033\[\d+m)*$)|( \.\.\.$)/; 66 | if (navigator.userAgent.indexOf("Windows") < 0 && interpretAsWithoutNewline.test(msg)) { 67 | try { 68 | var system = require('system'); 69 | system.stdout.write(msg); 70 | } catch (e) { 71 | var fs = require('fs'); 72 | fs.write('/dev/stdout', msg, 'w'); 73 | } 74 | } else { 75 | console.log(msg); 76 | } 77 | } 78 | 79 | /** 80 | * Stringifies the function, replacing any %placeholders% with mapped values. 81 | * 82 | * @param {function} fn The function to replace occurrences within. 83 | * @param {object} replacements Key => Value object of string replacements. 84 | */ 85 | function replaceFunctionPlaceholders(fn, replacements) { 86 | if (replacements && typeof replacements === "object") { 87 | fn = fn.toString(); 88 | for (var p in replacements) { 89 | if (replacements.hasOwnProperty(p)) { 90 | var match = new RegExp("%" + p + "%", "g"); 91 | do { 92 | fn = fn.replace(match, replacements[p]); 93 | } while(fn.indexOf(match) !== -1); 94 | } 95 | } 96 | } 97 | return fn; 98 | } 99 | 100 | /** 101 | * Replaces the "evaluate" method with one we can easily do substitution with. 102 | * 103 | * @param {phantomjs.WebPage} page The WebPage object to overload 104 | */ 105 | function overloadPageEvaluate(page) { 106 | page._evaluate = page.evaluate; 107 | page.evaluate = function(fn, replacements) { return page._evaluate(replaceFunctionPlaceholders(fn, replacements)); }; 108 | return page; 109 | } 110 | 111 | /** Stubs a fake writeFile function into the test runner. 112 | * 113 | * @param {phantomjs.WebPage} page The WebPage object to inject functions into. 114 | * @param {string} key The name of the global object in which file data should 115 | * be stored for later retrieval. 116 | */ 117 | // TODO: not bothering with error checking for now (closed environment) 118 | function setupWriteFileFunction(page, key, path_separator) { 119 | page.evaluate(function(){ 120 | window["%resultsObj%"] = {}; 121 | window.fs_path_separator = "%fs_path_separator%"; 122 | window.__phantom_writeFile = function(filename, text) { 123 | window["%resultsObj%"][filename] = text; 124 | }; 125 | }, {resultsObj: key, fs_path_separator: path_separator.replace("\\", "\\\\")}); 126 | } 127 | 128 | /** 129 | * Returns the loaded page's filename => output object. 130 | * 131 | * @param {phantomjs.WebPage} page The WebPage object to retrieve data from. 132 | * @param {string} key The name of the global object to be returned. Should 133 | * be the same key provided to setupWriteFileFunction. 134 | */ 135 | function getXmlResults(page, key) { 136 | return page.evaluate(function(){ 137 | return window["%resultsObj%"] || {}; 138 | }, {resultsObj: key}); 139 | } 140 | 141 | /** 142 | * Processes a page. 143 | * 144 | * @param {string} status The status from opening the page via WebPage#open. 145 | * @param {phantomjs.WebPage} page The WebPage to be processed. 146 | */ 147 | function processPage(status, page, resultsKey) { 148 | if (status === null && page) { 149 | page.__exit_code = null; 150 | return function(stat){ 151 | processPage(stat, page, resultsKey); 152 | }; 153 | } 154 | if (status !== "success") { 155 | console.error("Unable to load resource: " + address); 156 | page.__exit_code = 2; 157 | } 158 | else { 159 | var isFinished = function() { 160 | return page.evaluate(function(){ 161 | // if there's a JUnitXmlReporter, return a boolean indicating if it is finished 162 | if (window.done) { 163 | return window.done 164 | } 165 | // otherwise, see if there is anything in a "finished-at" element 166 | return false; 167 | }); 168 | }; 169 | var getResults = function() { 170 | return page.evaluate(function(){ 171 | return document.getElementsByClassName("bar").length && 172 | document.getElementsByClassName("bar")[0].innerHTML.match(/(\d+) spec.* (\d+) failure.*/) || 173 | ["Unable to determine success or failure."]; 174 | }); 175 | }; 176 | var timeout = 60000; 177 | var loopInterval = 100; 178 | var ival = setInterval(function(){ 179 | if (isFinished()) { 180 | // get the results that need to be written to disk 181 | var fs = require("fs"), 182 | xml_results = getXmlResults(page, resultsKey), 183 | output; 184 | for (var filename in xml_results) { 185 | if (xml_results.hasOwnProperty(filename) && (output = xml_results[filename]) && typeof(output) === "string") { 186 | fs.write(filename, output, "w"); 187 | } 188 | } 189 | 190 | // print out a success / failure message of the results 191 | var results = getResults(); 192 | var failures = Number(results[2]); 193 | if (failures > 0) { 194 | console.error(results[0]) 195 | page.__exit_code = 1; 196 | clearInterval(ival); 197 | } 198 | else { 199 | console.log(results[0]); 200 | page.__exit_code = 0; 201 | clearInterval(ival); 202 | } 203 | } 204 | else { 205 | timeout -= loopInterval; 206 | if (timeout <= 0) { 207 | console.log('Page has timed out; aborting.'); 208 | page.__exit_code = 2; 209 | clearInterval(ival); 210 | } 211 | } 212 | }, loopInterval); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /spec/spec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | describe('resizer', function() { 3 | var addEvent, beforeListener, main, removeEvent; 4 | addEvent = function(el, type, handler) { 5 | if (el.addEventListener) { 6 | return el.addEventListener(type, handler, false); 7 | } else if (el.attachEvent) { 8 | return el.attachEvent(type, handler, false); 9 | } 10 | }; 11 | removeEvent = function(el, type, handler) { 12 | if (el.removeEventListener) { 13 | return el.removeEventListener(type, handler, false); 14 | } else if (el.detachEvent) { 15 | return el.detachEvent(type, handler, false); 16 | } 17 | }; 18 | main = null; 19 | beforeListener = null; 20 | describe('enviroment', function() { 21 | it('should allow to write to Element prototype', function() { 22 | Element.prototype.testProperty = 'test'; 23 | return expect(Element.prototype.testProperty).toBe('test'); 24 | }); 25 | it('should have a dispatch event functionality', function() { 26 | var isIE, isNormalBrowser; 27 | isIE = !!document.createEventObject && !!document.fireEvent; 28 | isNormalBrowser = !!document.createEvent && !!document.dispatchEvent; 29 | return expect(isIE || isNormalBrowser).toBe(true); 30 | }); 31 | it('should have a addEventListener or attachEvent', function() { 32 | var div; 33 | div = document.createElement('div'); 34 | return expect(div.addEventListener || div.attachEvent).toBeTruthy(); 35 | }); 36 | it('should have a removeEventListener or detachEvent', function() { 37 | var div; 38 | div = document.createElement('div'); 39 | return expect(div.removeEventListener || div.detachEvent).toBeTruthy(); 40 | }); 41 | it('should have a computedStyle functionality', function() { 42 | var el; 43 | el = document.createElement('div'); 44 | return expect(window.getComputedStyle || el.currentStyle).toBeDefined(); 45 | }); 46 | it('should have size detection functionality', function() { 47 | var el; 48 | el = document.createElement('div'); 49 | document.body.appendChild(el); 50 | expect(el.offsetWidth).toBeDefined(); 51 | return expect(el.offsetHeight).toBeDefined(); 52 | }); 53 | return it('should have size detection functionality', function() { 54 | var el; 55 | el = document.createElement('div'); 56 | return expect(typeof el.appendChild === 'function').toBe(true); 57 | }); 58 | }); 59 | describe('DOM:', function() { 60 | it('should add iframe to the element', function() { 61 | var el; 62 | el = document.createElement('div'); 63 | document.body.appendChild(el); 64 | addEvent(el, 'onresize', (function() {})); 65 | return expect(el.hasChildNodes()).toBe(true); 66 | }); 67 | it('should have an access to iframe window', function() { 68 | var el, iframe; 69 | el = document.createElement('div'); 70 | addEvent(el, 'onresize', (function() {})); 71 | iframe = el.children[0]; 72 | document.body.appendChild(el); 73 | return expect(iframe.contentWindow).toBeDefined(); 74 | }); 75 | describe('iframe onresize method', function() { 76 | beforeEach(function(done) { 77 | return setTimeout((function() { 78 | return done(); 79 | }), 2); 80 | }); 81 | return it('iframe should have onresize method', function() { 82 | var el, iframe; 83 | el = document.createElement('div'); 84 | document.body.appendChild(el); 85 | addEvent(el, 'onresize', (function() {})); 86 | iframe = el.children[0]; 87 | return expect(iframe.contentWindow.onresize || main.interval).toBeDefined(); 88 | }); 89 | }); 90 | it('should add position: relative style to static element', function() { 91 | var el; 92 | el = document.createElement('div'); 93 | addEvent(el, 'onresize', (function() {})); 94 | return expect(el.style.position).toBe('relative'); 95 | }); 96 | it('should not alter absolute position style', function() { 97 | var el; 98 | el = document.createElement('div'); 99 | el.style.position = 'absolute'; 100 | addEvent(el, 'onresize', (function() {})); 101 | return expect(el.style.position).toBe('absolute'); 102 | }); 103 | it('should not alter fixed position style', function() { 104 | var el; 105 | el = document.createElement('div'); 106 | el.style.position = 'fixed'; 107 | addEvent(el, 'onresize', (function() {})); 108 | return expect(el.style.position).toBe('fixed'); 109 | }); 110 | return it('iframe should have right styles', function() { 111 | var el, iframe; 112 | el = document.createElement('div'); 113 | addEvent(el, 'onresize', (function() {})); 114 | iframe = el.children[0]; 115 | expect(iframe.style.position).toBe('absolute'); 116 | expect(iframe.style.width).toBe('100%'); 117 | expect(iframe.style.height).toBe('100%'); 118 | expect(iframe.style.zIndex + '').toBe('-999'); 119 | expect(parseInt(iframe.style.top, 10)).toBe(0); 120 | expect(parseInt(iframe.style.left, 10)).toBe(0); 121 | return expect(iframe.style.opacity).toBe('0'); 122 | }); 123 | }); 124 | return describe('constrains:', function() { 125 | it('should work on resize event only ', function() { 126 | var el, iframe; 127 | el = document.createElement('div'); 128 | addEvent(el, 'click', (function() {})); 129 | iframe = el.children[0]; 130 | document.body.appendChild(el); 131 | return expect(el.children.length).toBe(0); 132 | }); 133 | it('should be initialized only once', function() { 134 | var el, iframe; 135 | new window.AnyResizeEvent; 136 | el = document.createElement('div'); 137 | addEvent(el, 'onresize', (function() {})); 138 | iframe = el.children[0]; 139 | document.body.appendChild(el); 140 | return expect(el.children.length).toBe(1); 141 | }); 142 | it('should add only one listener', function() { 143 | var el, iframe; 144 | el = document.createElement('div'); 145 | addEvent(el, 'onresize', (function() {})); 146 | addEvent(el, 'onresize', (function() {})); 147 | iframe = el.children[0]; 148 | document.body.appendChild(el); 149 | return expect(el.children.length).toBe(1); 150 | }); 151 | it('should removeEventListener', function() { 152 | var el, fun; 153 | el = document.createElement('div'); 154 | fun = function() {}; 155 | addEvent(el, 'onresize', fun); 156 | removeEvent(el, 'onresize', fun); 157 | document.body.appendChild(el); 158 | return expect(el.isAnyResizeEventInited).toBe(false); 159 | }); 160 | it('should remove iframe after removeEventListener', function() { 161 | var el, fun; 162 | el = document.createElement('div'); 163 | fun = function() {}; 164 | addEvent(el, 'onresize', fun); 165 | removeEvent(el, 'onresize', fun); 166 | document.body.appendChild(el); 167 | return expect(el.hasChildNodes()).toBe(false); 168 | }); 169 | it('should fail when removeEvent was called before addEvent', function() { 170 | var e, el, fun, isError; 171 | el = document.createElement('div'); 172 | isError = false; 173 | fun = function() {}; 174 | try { 175 | removeEvent(el, 'onresize', fun); 176 | } catch (_error) { 177 | e = _error; 178 | isError = true; 179 | } 180 | return expect(isError).toBe(false); 181 | }); 182 | describe('scope', function() { 183 | var el, scope; 184 | scope = null; 185 | el = document.createElement('div'); 186 | beforeEach(function(done) { 187 | document.body.appendChild(el); 188 | addEvent(el, 'onresize', function() { 189 | return scope = this; 190 | }); 191 | el.style.width = '201px'; 192 | return setTimeout((function() { 193 | return done(); 194 | }), 25); 195 | }); 196 | return it('should have node\'s scope', function() { 197 | return expect(scope).toEqual(el); 198 | }); 199 | }); 200 | return it('should reverse old listener on destroy', function() { 201 | var el; 202 | window.anyResizeEvent.destroy(); 203 | main = new window.AnyResizeEvent; 204 | el = document.createElement('div'); 205 | addEvent(el, 'onresize', (function() {})); 206 | main.destroy(); 207 | return expect(HTMLDivElement.prototype.addEventListener).toBe(Element.prototype.addEventListener); 208 | }); 209 | }); 210 | }); 211 | 212 | }).call(this); 213 | -------------------------------------------------------------------------------- /spec/lib/jasmine-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2013 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | jasmineRequire.html = function(j$) { 24 | j$.ResultsNode = jasmineRequire.ResultsNode(); 25 | j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 26 | j$.QueryString = jasmineRequire.QueryString(); 27 | j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 28 | }; 29 | 30 | jasmineRequire.HtmlReporter = function(j$) { 31 | 32 | var noopTimer = { 33 | start: function() {}, 34 | elapsed: function() { return 0; } 35 | }; 36 | 37 | function HtmlReporter(options) { 38 | var env = options.env || {}, 39 | getContainer = options.getContainer, 40 | createElement = options.createElement, 41 | createTextNode = options.createTextNode, 42 | onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 43 | timer = options.timer || noopTimer, 44 | results = [], 45 | specsExecuted = 0, 46 | failureCount = 0, 47 | pendingSpecCount = 0, 48 | htmlReporterMain, 49 | symbols; 50 | 51 | this.initialize = function() { 52 | htmlReporterMain = createDom("div", {className: "html-reporter"}, 53 | createDom("div", {className: "banner"}, 54 | createDom("span", {className: "title"}, "Jasmine"), 55 | createDom("span", {className: "version"}, j$.version) 56 | ), 57 | createDom("ul", {className: "symbol-summary"}), 58 | createDom("div", {className: "alert"}), 59 | createDom("div", {className: "results"}, 60 | createDom("div", {className: "failures"}) 61 | ) 62 | ); 63 | getContainer().appendChild(htmlReporterMain); 64 | 65 | symbols = find(".symbol-summary"); 66 | }; 67 | 68 | var totalSpecsDefined; 69 | this.jasmineStarted = function(options) { 70 | totalSpecsDefined = options.totalSpecsDefined || 0; 71 | timer.start(); 72 | }; 73 | 74 | var summary = createDom("div", {className: "summary"}); 75 | 76 | var topResults = new j$.ResultsNode({}, "", null), 77 | currentParent = topResults; 78 | 79 | this.suiteStarted = function(result) { 80 | currentParent.addChild(result, "suite"); 81 | currentParent = currentParent.last(); 82 | }; 83 | 84 | this.suiteDone = function(result) { 85 | if (currentParent == topResults) { 86 | return; 87 | } 88 | 89 | currentParent = currentParent.parent; 90 | }; 91 | 92 | this.specStarted = function(result) { 93 | currentParent.addChild(result, "spec"); 94 | }; 95 | 96 | var failures = []; 97 | this.specDone = function(result) { 98 | if (result.status != "disabled") { 99 | specsExecuted++; 100 | } 101 | 102 | symbols.appendChild(createDom("li", { 103 | className: result.status, 104 | id: "spec_" + result.id, 105 | title: result.fullName 106 | } 107 | )); 108 | 109 | if (result.status == "failed") { 110 | failureCount++; 111 | 112 | var failure = 113 | createDom("div", {className: "spec-detail failed"}, 114 | createDom("div", {className: "description"}, 115 | createDom("a", {title: result.fullName, href: specHref(result)}, result.fullName) 116 | ), 117 | createDom("div", {className: "messages"}) 118 | ); 119 | var messages = failure.childNodes[1]; 120 | 121 | for (var i = 0; i < result.failedExpectations.length; i++) { 122 | var expectation = result.failedExpectations[i]; 123 | messages.appendChild(createDom("div", {className: "result-message"}, expectation.message)); 124 | messages.appendChild(createDom("div", {className: "stack-trace"}, expectation.stack)); 125 | } 126 | 127 | failures.push(failure); 128 | } 129 | 130 | if (result.status == "pending") { 131 | pendingSpecCount++; 132 | } 133 | }; 134 | 135 | this.jasmineDone = function() { 136 | var banner = find(".banner"); 137 | banner.appendChild(createDom("span", {className: "duration"}, "finished in " + timer.elapsed() / 1000 + "s")); 138 | 139 | var alert = find(".alert"); 140 | 141 | alert.appendChild(createDom("span", { className: "exceptions" }, 142 | createDom("label", { className: "label", 'for': "raise-exceptions" }, "raise exceptions"), 143 | createDom("input", { 144 | className: "raise", 145 | id: "raise-exceptions", 146 | type: "checkbox" 147 | }) 148 | )); 149 | var checkbox = find("input"); 150 | 151 | checkbox.checked = !env.catchingExceptions(); 152 | checkbox.onclick = onRaiseExceptionsClick; 153 | 154 | if (specsExecuted < totalSpecsDefined) { 155 | var skippedMessage = "Ran " + specsExecuted + " of " + totalSpecsDefined + " specs - run all"; 156 | alert.appendChild( 157 | createDom("span", {className: "bar skipped"}, 158 | createDom("a", {href: "?", title: "Run all specs"}, skippedMessage) 159 | ) 160 | ); 161 | } 162 | var statusBarMessage = "" + pluralize("spec", specsExecuted) + ", " + pluralize("failure", failureCount); 163 | if (pendingSpecCount) { statusBarMessage += ", " + pluralize("pending spec", pendingSpecCount); } 164 | 165 | var statusBarClassName = "bar " + ((failureCount > 0) ? "failed" : "passed"); 166 | alert.appendChild(createDom("span", {className: statusBarClassName}, statusBarMessage)); 167 | 168 | var results = find(".results"); 169 | results.appendChild(summary); 170 | 171 | summaryList(topResults, summary); 172 | 173 | function summaryList(resultsTree, domParent) { 174 | var specListNode; 175 | for (var i = 0; i < resultsTree.children.length; i++) { 176 | var resultNode = resultsTree.children[i]; 177 | if (resultNode.type == "suite") { 178 | var suiteListNode = createDom("ul", {className: "suite", id: "suite-" + resultNode.result.id}, 179 | createDom("li", {className: "suite-detail"}, 180 | createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) 181 | ) 182 | ); 183 | 184 | summaryList(resultNode, suiteListNode); 185 | domParent.appendChild(suiteListNode); 186 | } 187 | if (resultNode.type == "spec") { 188 | if (domParent.getAttribute("class") != "specs") { 189 | specListNode = createDom("ul", {className: "specs"}); 190 | domParent.appendChild(specListNode); 191 | } 192 | specListNode.appendChild( 193 | createDom("li", { 194 | className: resultNode.result.status, 195 | id: "spec-" + resultNode.result.id 196 | }, 197 | createDom("a", {href: specHref(resultNode.result)}, resultNode.result.description) 198 | ) 199 | ); 200 | } 201 | } 202 | } 203 | 204 | if (failures.length) { 205 | alert.appendChild( 206 | createDom('span', {className: "menu bar spec-list"}, 207 | createDom("span", {}, "Spec List | "), 208 | createDom('a', {className: "failures-menu", href: "#"}, "Failures"))); 209 | alert.appendChild( 210 | createDom('span', {className: "menu bar failure-list"}, 211 | createDom('a', {className: "spec-list-menu", href: "#"}, "Spec List"), 212 | createDom("span", {}, " | Failures "))); 213 | 214 | find(".failures-menu").onclick = function() { 215 | setMenuModeTo('failure-list'); 216 | }; 217 | find(".spec-list-menu").onclick = function() { 218 | setMenuModeTo('spec-list'); 219 | }; 220 | 221 | setMenuModeTo('failure-list'); 222 | 223 | var failureNode = find(".failures"); 224 | for (var i = 0; i < failures.length; i++) { 225 | failureNode.appendChild(failures[i]); 226 | } 227 | } 228 | }; 229 | 230 | return this; 231 | 232 | function find(selector) { 233 | return getContainer().querySelector(selector); 234 | } 235 | 236 | function createDom(type, attrs, childrenVarArgs) { 237 | var el = createElement(type); 238 | 239 | for (var i = 2; i < arguments.length; i++) { 240 | var child = arguments[i]; 241 | 242 | if (typeof child === 'string') { 243 | el.appendChild(createTextNode(child)); 244 | } else { 245 | if (child) { 246 | el.appendChild(child); 247 | } 248 | } 249 | } 250 | 251 | for (var attr in attrs) { 252 | if (attr == "className") { 253 | el[attr] = attrs[attr]; 254 | } else { 255 | el.setAttribute(attr, attrs[attr]); 256 | } 257 | } 258 | 259 | return el; 260 | } 261 | 262 | function pluralize(singular, count) { 263 | var word = (count == 1 ? singular : singular + "s"); 264 | 265 | return "" + count + " " + word; 266 | } 267 | 268 | function specHref(result) { 269 | return "?spec=" + encodeURIComponent(result.fullName); 270 | } 271 | 272 | function setMenuModeTo(mode) { 273 | htmlReporterMain.setAttribute("class", "html-reporter " + mode); 274 | } 275 | } 276 | 277 | return HtmlReporter; 278 | }; 279 | 280 | jasmineRequire.HtmlSpecFilter = function() { 281 | function HtmlSpecFilter(options) { 282 | var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 283 | var filterPattern = new RegExp(filterString); 284 | 285 | this.matches = function(specName) { 286 | return filterPattern.test(specName); 287 | }; 288 | } 289 | 290 | return HtmlSpecFilter; 291 | }; 292 | 293 | jasmineRequire.ResultsNode = function() { 294 | function ResultsNode(result, type, parent) { 295 | this.result = result; 296 | this.type = type; 297 | this.parent = parent; 298 | 299 | this.children = []; 300 | 301 | this.addChild = function(result, type) { 302 | this.children.push(new ResultsNode(result, type, this)); 303 | }; 304 | 305 | this.last = function() { 306 | return this.children[this.children.length - 1]; 307 | }; 308 | } 309 | 310 | return ResultsNode; 311 | }; 312 | 313 | jasmineRequire.QueryString = function() { 314 | function QueryString(options) { 315 | 316 | this.setParam = function(key, value) { 317 | var paramMap = queryStringToParamMap(); 318 | paramMap[key] = value; 319 | options.getWindowLocation().search = toQueryString(paramMap); 320 | }; 321 | 322 | this.getParam = function(key) { 323 | return queryStringToParamMap()[key]; 324 | }; 325 | 326 | return this; 327 | 328 | function toQueryString(paramMap) { 329 | var qStrPairs = []; 330 | for (var prop in paramMap) { 331 | qStrPairs.push(encodeURIComponent(prop) + "=" + encodeURIComponent(paramMap[prop])); 332 | } 333 | return "?" + qStrPairs.join('&'); 334 | } 335 | 336 | function queryStringToParamMap() { 337 | var paramStr = options.getWindowLocation().search.substring(1), 338 | params = [], 339 | paramMap = {}; 340 | 341 | if (paramStr.length > 0) { 342 | params = paramStr.split('&'); 343 | for (var i = 0; i < params.length; i++) { 344 | var p = params[i].split('='); 345 | var value = decodeURIComponent(p[1]); 346 | if (value === "true" || value === "false") { 347 | value = JSON.parse(value); 348 | } 349 | paramMap[decodeURIComponent(p[0])] = value; 350 | } 351 | } 352 | 353 | return paramMap; 354 | } 355 | 356 | } 357 | 358 | return QueryString; 359 | }; 360 | -------------------------------------------------------------------------------- /npm-debug.log: -------------------------------------------------------------------------------- 1 | 0 info it worked if it ends with ok 2 | 1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'install' ] 3 | 2 info using npm@1.4.28 4 | 3 info using node@v0.10.33 5 | 4 warn package.json app-name@0.0.0 No repository field. 6 | 5 verbose readDependencies using package.json deps 7 | 6 verbose install where, deps [ '/Applications/MAMP/htdocs/live-projects/resize', 8 | 6 verbose install [ 'gulp', 9 | 6 verbose install 'gulp-util', 10 | 6 verbose install 'gulp-minify-css', 11 | 6 verbose install 'gulp-stylus', 12 | 6 verbose install 'gulp-autoprefixer', 13 | 6 verbose install 'gulp-notify', 14 | 6 verbose install 'gulp-livereload', 15 | 6 verbose install 'gulp-coffee', 16 | 6 verbose install 'gulp-changed', 17 | 6 verbose install 'gulp-jade', 18 | 6 verbose install 'gulp-watch', 19 | 6 verbose install 'gulp-coffeelint', 20 | 6 verbose install 'gulp-plumber', 21 | 6 verbose install 'gulp-uglify', 22 | 6 verbose install 'testem', 23 | 6 verbose install 'gulp-jasmine2-phantomjs', 24 | 6 verbose install 'ansi-styles', 25 | 6 verbose install 'escape-string-regexp', 26 | 6 verbose install 'has-ansi', 27 | 6 verbose install 'strip-ansi', 28 | 6 verbose install 'supports-color', 29 | 6 verbose install 'karma', 30 | 6 verbose install 'karma-jasmine', 31 | 6 verbose install 'karma-chrome-launcher', 32 | 6 verbose install 'karma-phantomjs-launcher' ] ] 33 | 7 info preinstall app-name@0.0.0 34 | 8 verbose readDependencies using package.json deps 35 | 9 verbose already installed skipping gulp@3.8.10 /Applications/MAMP/htdocs/live-projects/resize 36 | 10 verbose already installed skipping gulp-util@3.0.1 /Applications/MAMP/htdocs/live-projects/resize 37 | 11 verbose already installed skipping gulp-minify-css@~0.3.0 /Applications/MAMP/htdocs/live-projects/resize 38 | 12 verbose already installed skipping gulp-stylus@0.0.12 /Applications/MAMP/htdocs/live-projects/resize 39 | 13 verbose already installed skipping gulp-autoprefixer@0.0.6 /Applications/MAMP/htdocs/live-projects/resize 40 | 14 verbose already installed skipping gulp-notify@~0.5.1 /Applications/MAMP/htdocs/live-projects/resize 41 | 15 verbose already installed skipping gulp-livereload@~1.2.0 /Applications/MAMP/htdocs/live-projects/resize 42 | 16 verbose already installed skipping gulp-coffee@~1.4.1 /Applications/MAMP/htdocs/live-projects/resize 43 | 17 verbose already installed skipping gulp-changed@~0.2.0 /Applications/MAMP/htdocs/live-projects/resize 44 | 18 verbose already installed skipping gulp-jade@~0.4.2 /Applications/MAMP/htdocs/live-projects/resize 45 | 19 verbose already installed skipping gulp-watch@2.0.0 /Applications/MAMP/htdocs/live-projects/resize 46 | 20 verbose already installed skipping gulp-coffeelint@0.4.0 /Applications/MAMP/htdocs/live-projects/resize 47 | 21 verbose already installed skipping gulp-plumber@0.6.6 /Applications/MAMP/htdocs/live-projects/resize 48 | 22 verbose already installed skipping gulp-uglify@1.0.1 /Applications/MAMP/htdocs/live-projects/resize 49 | 23 verbose already installed skipping testem@0.6.23 /Applications/MAMP/htdocs/live-projects/resize 50 | 24 verbose already installed skipping gulp-jasmine2-phantomjs@0.2.0 /Applications/MAMP/htdocs/live-projects/resize 51 | 25 verbose already installed skipping ansi-styles@^1.1.0 /Applications/MAMP/htdocs/live-projects/resize 52 | 26 verbose already installed skipping escape-string-regexp@^1.0.0 /Applications/MAMP/htdocs/live-projects/resize 53 | 27 verbose already installed skipping has-ansi@^0.1.0 /Applications/MAMP/htdocs/live-projects/resize 54 | 28 verbose already installed skipping strip-ansi@^0.3.0 /Applications/MAMP/htdocs/live-projects/resize 55 | 29 verbose already installed skipping supports-color@^0.2.0 /Applications/MAMP/htdocs/live-projects/resize 56 | 30 verbose cache add [ 'karma@^0.12.21', null ] 57 | 31 verbose cache add name=undefined spec="karma@^0.12.21" args=["karma@^0.12.21",null] 58 | 32 verbose parsed url { protocol: null, 59 | 32 verbose parsed url slashes: null, 60 | 32 verbose parsed url auth: null, 61 | 32 verbose parsed url host: null, 62 | 32 verbose parsed url port: null, 63 | 32 verbose parsed url hostname: null, 64 | 32 verbose parsed url hash: null, 65 | 32 verbose parsed url search: null, 66 | 32 verbose parsed url query: null, 67 | 32 verbose parsed url pathname: 'karma@^0.12.21', 68 | 32 verbose parsed url path: 'karma@^0.12.21', 69 | 32 verbose parsed url href: 'karma@^0.12.21' } 70 | 33 verbose cache add [ 'karma-jasmine@^0.1.6', null ] 71 | 34 verbose cache add name=undefined spec="karma-jasmine@^0.1.6" args=["karma-jasmine@^0.1.6",null] 72 | 35 verbose parsed url { protocol: null, 73 | 35 verbose parsed url slashes: null, 74 | 35 verbose parsed url auth: null, 75 | 35 verbose parsed url host: null, 76 | 35 verbose parsed url port: null, 77 | 35 verbose parsed url hostname: null, 78 | 35 verbose parsed url hash: null, 79 | 35 verbose parsed url search: null, 80 | 35 verbose parsed url query: null, 81 | 35 verbose parsed url pathname: 'karma-jasmine@^0.1.6', 82 | 35 verbose parsed url path: 'karma-jasmine@^0.1.6', 83 | 35 verbose parsed url href: 'karma-jasmine@^0.1.6' } 84 | 36 verbose cache add [ 'karma-chrome-launcher@^0.1.4', null ] 85 | 37 verbose cache add name=undefined spec="karma-chrome-launcher@^0.1.4" args=["karma-chrome-launcher@^0.1.4",null] 86 | 38 verbose parsed url { protocol: null, 87 | 38 verbose parsed url slashes: null, 88 | 38 verbose parsed url auth: null, 89 | 38 verbose parsed url host: null, 90 | 38 verbose parsed url port: null, 91 | 38 verbose parsed url hostname: null, 92 | 38 verbose parsed url hash: null, 93 | 38 verbose parsed url search: null, 94 | 38 verbose parsed url query: null, 95 | 38 verbose parsed url pathname: 'karma-chrome-launcher@^0.1.4', 96 | 38 verbose parsed url path: 'karma-chrome-launcher@^0.1.4', 97 | 38 verbose parsed url href: 'karma-chrome-launcher@^0.1.4' } 98 | 39 verbose cache add name="karma" spec="^0.12.21" args=["karma","^0.12.21"] 99 | 40 verbose parsed url { protocol: null, 100 | 40 verbose parsed url slashes: null, 101 | 40 verbose parsed url auth: null, 102 | 40 verbose parsed url host: null, 103 | 40 verbose parsed url port: null, 104 | 40 verbose parsed url hostname: null, 105 | 40 verbose parsed url hash: null, 106 | 40 verbose parsed url search: null, 107 | 40 verbose parsed url query: null, 108 | 40 verbose parsed url pathname: '^0.12.21', 109 | 40 verbose parsed url path: '^0.12.21', 110 | 40 verbose parsed url href: '^0.12.21' } 111 | 41 verbose addNamed [ 'karma', '^0.12.21' ] 112 | 42 verbose addNamed [ null, '>=0.12.21-0 <0.13.0-0' ] 113 | 43 verbose cache add name="karma-jasmine" spec="^0.1.6" args=["karma-jasmine","^0.1.6"] 114 | 44 verbose parsed url { protocol: null, 115 | 44 verbose parsed url slashes: null, 116 | 44 verbose parsed url auth: null, 117 | 44 verbose parsed url host: null, 118 | 44 verbose parsed url port: null, 119 | 44 verbose parsed url hostname: null, 120 | 44 verbose parsed url hash: null, 121 | 44 verbose parsed url search: null, 122 | 44 verbose parsed url query: null, 123 | 44 verbose parsed url pathname: '^0.1.6', 124 | 44 verbose parsed url path: '^0.1.6', 125 | 44 verbose parsed url href: '^0.1.6' } 126 | 45 verbose addNamed [ 'karma-jasmine', '^0.1.6' ] 127 | 46 verbose addNamed [ null, '>=0.1.6-0 <0.2.0-0' ] 128 | 47 verbose cache add [ 'karma-phantomjs-launcher@^0.1.4', null ] 129 | 48 verbose cache add name=undefined spec="karma-phantomjs-launcher@^0.1.4" args=["karma-phantomjs-launcher@^0.1.4",null] 130 | 49 verbose parsed url { protocol: null, 131 | 49 verbose parsed url slashes: null, 132 | 49 verbose parsed url auth: null, 133 | 49 verbose parsed url host: null, 134 | 49 verbose parsed url port: null, 135 | 49 verbose parsed url hostname: null, 136 | 49 verbose parsed url hash: null, 137 | 49 verbose parsed url search: null, 138 | 49 verbose parsed url query: null, 139 | 49 verbose parsed url pathname: 'karma-phantomjs-launcher@^0.1.4', 140 | 49 verbose parsed url path: 'karma-phantomjs-launcher@^0.1.4', 141 | 49 verbose parsed url href: 'karma-phantomjs-launcher@^0.1.4' } 142 | 50 verbose cache add name="karma-chrome-launcher" spec="^0.1.4" args=["karma-chrome-launcher","^0.1.4"] 143 | 51 verbose parsed url { protocol: null, 144 | 51 verbose parsed url slashes: null, 145 | 51 verbose parsed url auth: null, 146 | 51 verbose parsed url host: null, 147 | 51 verbose parsed url port: null, 148 | 51 verbose parsed url hostname: null, 149 | 51 verbose parsed url hash: null, 150 | 51 verbose parsed url search: null, 151 | 51 verbose parsed url query: null, 152 | 51 verbose parsed url pathname: '^0.1.4', 153 | 51 verbose parsed url path: '^0.1.4', 154 | 51 verbose parsed url href: '^0.1.4' } 155 | 52 verbose addNamed [ 'karma-chrome-launcher', '^0.1.4' ] 156 | 53 verbose addNamed [ null, '>=0.1.4-0 <0.2.0-0' ] 157 | 54 silly lockFile 35ff5c57-karma-0-12-21 karma@^0.12.21 158 | 55 verbose lock karma@^0.12.21 /Users/mac/.npm/35ff5c57-karma-0-12-21.lock 159 | 56 silly lockFile 4aaa2489-karma-jasmine-0-1-6 karma-jasmine@^0.1.6 160 | 57 verbose lock karma-jasmine@^0.1.6 /Users/mac/.npm/4aaa2489-karma-jasmine-0-1-6.lock 161 | 58 silly lockFile cd7d8138-karma-chrome-launcher-0-1-4 karma-chrome-launcher@^0.1.4 162 | 59 verbose lock karma-chrome-launcher@^0.1.4 /Users/mac/.npm/cd7d8138-karma-chrome-launcher-0-1-4.lock 163 | 60 verbose cache add name="karma-phantomjs-launcher" spec="^0.1.4" args=["karma-phantomjs-launcher","^0.1.4"] 164 | 61 verbose parsed url { protocol: null, 165 | 61 verbose parsed url slashes: null, 166 | 61 verbose parsed url auth: null, 167 | 61 verbose parsed url host: null, 168 | 61 verbose parsed url port: null, 169 | 61 verbose parsed url hostname: null, 170 | 61 verbose parsed url hash: null, 171 | 61 verbose parsed url search: null, 172 | 61 verbose parsed url query: null, 173 | 61 verbose parsed url pathname: '^0.1.4', 174 | 61 verbose parsed url path: '^0.1.4', 175 | 61 verbose parsed url href: '^0.1.4' } 176 | 62 verbose addNamed [ 'karma-phantomjs-launcher', '^0.1.4' ] 177 | 63 verbose addNamed [ null, '>=0.1.4-0 <0.2.0-0' ] 178 | 64 silly lockFile a2b6b896-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@^0.1.4 179 | 65 verbose lock karma-phantomjs-launcher@^0.1.4 /Users/mac/.npm/a2b6b896-karma-phantomjs-launcher-0-1-4.lock 180 | 66 silly addNameRange { name: 'karma', range: '>=0.12.21-0 <0.13.0-0', hasData: false } 181 | 67 silly addNameRange { name: 'karma-jasmine', 182 | 67 silly addNameRange range: '>=0.1.6-0 <0.2.0-0', 183 | 67 silly addNameRange hasData: false } 184 | 68 silly addNameRange { name: 'karma-chrome-launcher', 185 | 68 silly addNameRange range: '>=0.1.4-0 <0.2.0-0', 186 | 68 silly addNameRange hasData: false } 187 | 69 silly addNameRange { name: 'karma-phantomjs-launcher', 188 | 69 silly addNameRange range: '>=0.1.4-0 <0.2.0-0', 189 | 69 silly addNameRange hasData: false } 190 | 70 verbose request where is /karma 191 | 71 verbose request registry https://registry.npmjs.org/ 192 | 72 verbose request id dad2ccb5a3077fbb 193 | 73 verbose url raw /karma 194 | 74 verbose url resolving [ 'https://registry.npmjs.org/', './karma' ] 195 | 75 verbose url resolved https://registry.npmjs.org/karma 196 | 76 verbose request where is https://registry.npmjs.org/karma 197 | 77 info trying registry request attempt 1 at 13:53:25 198 | 78 http GET https://registry.npmjs.org/karma 199 | 79 verbose request where is /karma-jasmine 200 | 80 verbose request registry https://registry.npmjs.org/ 201 | 81 verbose url raw /karma-jasmine 202 | 82 verbose url resolving [ 'https://registry.npmjs.org/', './karma-jasmine' ] 203 | 83 verbose url resolved https://registry.npmjs.org/karma-jasmine 204 | 84 verbose request where is https://registry.npmjs.org/karma-jasmine 205 | 85 info trying registry request attempt 1 at 13:53:25 206 | 86 http GET https://registry.npmjs.org/karma-jasmine 207 | 87 verbose request where is /karma-chrome-launcher 208 | 88 verbose request registry https://registry.npmjs.org/ 209 | 89 verbose url raw /karma-chrome-launcher 210 | 90 verbose url resolving [ 'https://registry.npmjs.org/', './karma-chrome-launcher' ] 211 | 91 verbose url resolved https://registry.npmjs.org/karma-chrome-launcher 212 | 92 verbose request where is https://registry.npmjs.org/karma-chrome-launcher 213 | 93 info trying registry request attempt 1 at 13:53:25 214 | 94 http GET https://registry.npmjs.org/karma-chrome-launcher 215 | 95 verbose request where is /karma-phantomjs-launcher 216 | 96 verbose request registry https://registry.npmjs.org/ 217 | 97 verbose url raw /karma-phantomjs-launcher 218 | 98 verbose url resolving [ 'https://registry.npmjs.org/', './karma-phantomjs-launcher' ] 219 | 99 verbose url resolved https://registry.npmjs.org/karma-phantomjs-launcher 220 | 100 verbose request where is https://registry.npmjs.org/karma-phantomjs-launcher 221 | 101 info trying registry request attempt 1 at 13:53:25 222 | 102 http GET https://registry.npmjs.org/karma-phantomjs-launcher 223 | 103 http 200 https://registry.npmjs.org/karma-chrome-launcher 224 | 104 silly registry.get cb [ 200, 225 | 104 silly registry.get { date: 'Sun, 07 Dec 2014 11:53:26 GMT', 226 | 104 silly registry.get server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)', 227 | 104 silly registry.get etag: '"3GTYYJ0BEOOVL3FAGRP3432XH"', 228 | 104 silly registry.get 'content-type': 'application/json', 229 | 104 silly registry.get 'cache-control': 'max-age=60', 230 | 104 silly registry.get 'content-length': '15114', 231 | 104 silly registry.get 'accept-ranges': 'bytes', 232 | 104 silly registry.get via: '1.1 varnish', 233 | 104 silly registry.get age: '54', 234 | 104 silly registry.get 'x-served-by': 'cache-fra1239-FRA', 235 | 104 silly registry.get 'x-cache': 'HIT', 236 | 104 silly registry.get 'x-cache-hits': '1', 237 | 104 silly registry.get 'x-timer': 'S1417953206.046063,VS0,VE0', 238 | 104 silly registry.get vary: 'Accept', 239 | 104 silly registry.get 'keep-alive': 'timeout=10, max=50', 240 | 104 silly registry.get connection: 'Keep-Alive' } ] 241 | 105 silly addNameRange number 2 { name: 'karma-chrome-launcher', 242 | 105 silly addNameRange range: '>=0.1.4-0 <0.2.0-0', 243 | 105 silly addNameRange hasData: true } 244 | 106 silly addNameRange versions [ 'karma-chrome-launcher', 245 | 106 silly addNameRange [ '0.0.1', 246 | 106 silly addNameRange '0.0.2', 247 | 106 silly addNameRange '0.1.0', 248 | 106 silly addNameRange '0.1.1', 249 | 106 silly addNameRange '0.1.2', 250 | 106 silly addNameRange '0.1.3', 251 | 106 silly addNameRange '0.1.4', 252 | 106 silly addNameRange '0.1.5', 253 | 106 silly addNameRange '0.1.6', 254 | 106 silly addNameRange '0.1.7' ] ] 255 | 107 verbose addNamed [ 'karma-chrome-launcher', '0.1.7' ] 256 | 108 verbose addNamed [ '0.1.7', '0.1.7' ] 257 | 109 silly lockFile ced0a4a4-karma-chrome-launcher-0-1-7 karma-chrome-launcher@0.1.7 258 | 110 verbose lock karma-chrome-launcher@0.1.7 /Users/mac/.npm/ced0a4a4-karma-chrome-launcher-0-1-7.lock 259 | 111 silly lockFile 709393aa--karma-chrome-launcher-0-1-7-tgz https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 260 | 112 verbose lock https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz /Users/mac/.npm/709393aa--karma-chrome-launcher-0-1-7-tgz.lock 261 | 113 verbose addRemoteTarball [ 'https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz', 262 | 113 verbose addRemoteTarball 'c248cc01d5ae17dafdb16319d0badf637dfb6e59' ] 263 | 114 info retry fetch attempt 1 at 13:53:25 264 | 115 verbose fetch to= /tmp/npm-80088-6GEyfJWh/registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 265 | 116 http GET https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 266 | 117 http 200 https://registry.npmjs.org/karma-phantomjs-launcher 267 | 118 silly registry.get cb [ 200, 268 | 118 silly registry.get { date: 'Sun, 07 Dec 2014 11:53:26 GMT', 269 | 118 silly registry.get server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)', 270 | 118 silly registry.get etag: '"66UFY5MR6A83JYRYD5F5XPBQP"', 271 | 118 silly registry.get 'content-type': 'application/json', 272 | 118 silly registry.get 'cache-control': 'max-age=60', 273 | 118 silly registry.get 'content-length': '12786', 274 | 118 silly registry.get 'accept-ranges': 'bytes', 275 | 118 silly registry.get via: '1.1 varnish', 276 | 118 silly registry.get age: '0', 277 | 118 silly registry.get 'x-served-by': 'cache-fra1221-FRA', 278 | 118 silly registry.get 'x-cache': 'HIT', 279 | 118 silly registry.get 'x-cache-hits': '1', 280 | 118 silly registry.get 'x-timer': 'S1417953206.060962,VS0,VE435', 281 | 118 silly registry.get vary: 'Accept', 282 | 118 silly registry.get 'keep-alive': 'timeout=10, max=50', 283 | 118 silly registry.get connection: 'Keep-Alive' } ] 284 | 119 silly addNameRange number 2 { name: 'karma-phantomjs-launcher', 285 | 119 silly addNameRange range: '>=0.1.4-0 <0.2.0-0', 286 | 119 silly addNameRange hasData: true } 287 | 120 silly addNameRange versions [ 'karma-phantomjs-launcher', 288 | 120 silly addNameRange [ '0.0.1', 289 | 120 silly addNameRange '0.0.2', 290 | 120 silly addNameRange '0.0.3', 291 | 120 silly addNameRange '0.1.0', 292 | 120 silly addNameRange '0.1.1', 293 | 120 silly addNameRange '0.1.2', 294 | 120 silly addNameRange '0.1.3', 295 | 120 silly addNameRange '0.1.4' ] ] 296 | 121 verbose addNamed [ 'karma-phantomjs-launcher', '0.1.4' ] 297 | 122 verbose addNamed [ '0.1.4', '0.1.4' ] 298 | 123 silly lockFile 5b4ecc13-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@0.1.4 299 | 124 verbose lock karma-phantomjs-launcher@0.1.4 /Users/mac/.npm/5b4ecc13-karma-phantomjs-launcher-0-1-4.lock 300 | 125 silly lockFile 6f63103b-rma-phantomjs-launcher-0-1-4-tgz https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 301 | 126 verbose lock https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz /Users/mac/.npm/6f63103b-rma-phantomjs-launcher-0-1-4-tgz.lock 302 | 127 verbose addRemoteTarball [ 'https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz', 303 | 127 verbose addRemoteTarball '4ef96e4322ff63ae5d918e51c25b213723238f30' ] 304 | 128 info retry fetch attempt 1 at 13:53:26 305 | 129 verbose fetch to= /tmp/npm-80088-6GEyfJWh/registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 306 | 130 http GET https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 307 | 131 http 200 https://registry.npmjs.org/karma-jasmine 308 | 132 silly registry.get cb [ 200, 309 | 132 silly registry.get { date: 'Sun, 07 Dec 2014 11:53:26 GMT', 310 | 132 silly registry.get server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)', 311 | 132 silly registry.get etag: '"4XGLXSUPV5LJRNFSOX64GYABP"', 312 | 132 silly registry.get 'content-type': 'application/json', 313 | 132 silly registry.get 'cache-control': 'max-age=60', 314 | 132 silly registry.get 'content-length': '25407', 315 | 132 silly registry.get 'accept-ranges': 'bytes', 316 | 132 silly registry.get via: '1.1 varnish', 317 | 132 silly registry.get age: '0', 318 | 132 silly registry.get 'x-served-by': 'cache-fra1245-FRA', 319 | 132 silly registry.get 'x-cache': 'HIT', 320 | 132 silly registry.get 'x-cache-hits': '1', 321 | 132 silly registry.get 'x-timer': 'S1417953206.027463,VS0,VE424', 322 | 132 silly registry.get vary: 'Accept', 323 | 132 silly registry.get 'keep-alive': 'timeout=10, max=50', 324 | 132 silly registry.get connection: 'Keep-Alive' } ] 325 | 133 silly addNameRange number 2 { name: 'karma-jasmine', 326 | 133 silly addNameRange range: '>=0.1.6-0 <0.2.0-0', 327 | 133 silly addNameRange hasData: true } 328 | 134 silly addNameRange versions [ 'karma-jasmine', 329 | 134 silly addNameRange [ '0.0.1', 330 | 134 silly addNameRange '0.0.2', 331 | 134 silly addNameRange '0.0.3', 332 | 134 silly addNameRange '0.1.0', 333 | 134 silly addNameRange '0.1.1', 334 | 134 silly addNameRange '0.1.2', 335 | 134 silly addNameRange '0.1.3', 336 | 134 silly addNameRange '0.1.4', 337 | 134 silly addNameRange '0.1.5', 338 | 134 silly addNameRange '0.2.0', 339 | 134 silly addNameRange '0.2.1', 340 | 134 silly addNameRange '0.2.2', 341 | 134 silly addNameRange '0.2.3', 342 | 134 silly addNameRange '0.3.0', 343 | 134 silly addNameRange '0.3.1', 344 | 134 silly addNameRange '0.3.2' ] ] 345 | 135 silly lockFile 4aaa2489-karma-jasmine-0-1-6 karma-jasmine@^0.1.6 346 | 136 silly lockFile 4aaa2489-karma-jasmine-0-1-6 karma-jasmine@^0.1.6 347 | 137 http 200 https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 348 | 138 silly lockFile 709393aa--karma-chrome-launcher-0-1-7-tgz https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 349 | 139 silly lockFile 709393aa--karma-chrome-launcher-0-1-7-tgz https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-0.1.7.tgz 350 | 140 silly lockFile ced0a4a4-karma-chrome-launcher-0-1-7 karma-chrome-launcher@0.1.7 351 | 141 silly lockFile ced0a4a4-karma-chrome-launcher-0-1-7 karma-chrome-launcher@0.1.7 352 | 142 silly lockFile cd7d8138-karma-chrome-launcher-0-1-4 karma-chrome-launcher@^0.1.4 353 | 143 silly lockFile cd7d8138-karma-chrome-launcher-0-1-4 karma-chrome-launcher@^0.1.4 354 | 144 http 200 https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 355 | 145 silly lockFile 6f63103b-rma-phantomjs-launcher-0-1-4-tgz https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 356 | 146 silly lockFile 6f63103b-rma-phantomjs-launcher-0-1-4-tgz https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.1.4.tgz 357 | 147 silly lockFile 5b4ecc13-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@0.1.4 358 | 148 silly lockFile 5b4ecc13-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@0.1.4 359 | 149 silly lockFile a2b6b896-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@^0.1.4 360 | 150 silly lockFile a2b6b896-karma-phantomjs-launcher-0-1-4 karma-phantomjs-launcher@^0.1.4 361 | 151 http 200 https://registry.npmjs.org/karma 362 | 152 silly registry.get cb [ 200, 363 | 152 silly registry.get { date: 'Sun, 07 Dec 2014 11:53:26 GMT', 364 | 152 silly registry.get server: 'CouchDB/1.5.0 (Erlang OTP/R16B03)', 365 | 152 silly registry.get etag: '"15YVGD0JTB84ABQ2G388546QU"', 366 | 152 silly registry.get 'content-type': 'application/json', 367 | 152 silly registry.get 'cache-control': 'max-age=60', 368 | 152 silly registry.get 'content-length': '595402', 369 | 152 silly registry.get 'accept-ranges': 'bytes', 370 | 152 silly registry.get via: '1.1 varnish', 371 | 152 silly registry.get age: '4', 372 | 152 silly registry.get 'x-served-by': 'cache-fra1246-FRA', 373 | 152 silly registry.get 'x-cache': 'HIT', 374 | 152 silly registry.get 'x-cache-hits': '1', 375 | 152 silly registry.get 'x-timer': 'S1417953206.017991,VS0,VE2', 376 | 152 silly registry.get vary: 'Accept', 377 | 152 silly registry.get 'keep-alive': 'timeout=10, max=50', 378 | 152 silly registry.get connection: 'Keep-Alive' } ] 379 | 153 silly addNameRange number 2 { name: 'karma', range: '>=0.12.21-0 <0.13.0-0', hasData: true } 380 | 154 silly addNameRange versions [ 'karma', 381 | 154 silly addNameRange [ '0.8.0', 382 | 154 silly addNameRange '0.9.0-dart', 383 | 154 silly addNameRange '0.8.1', 384 | 154 silly addNameRange '0.8.2', 385 | 154 silly addNameRange '0.8.3', 386 | 154 silly addNameRange '0.9.0', 387 | 154 silly addNameRange '0.8.4', 388 | 154 silly addNameRange '0.9.1', 389 | 154 silly addNameRange '0.8.5', 390 | 154 silly addNameRange '0.9.2', 391 | 154 silly addNameRange '0.9.2-dart', 392 | 154 silly addNameRange '0.9.3', 393 | 154 silly addNameRange '0.8.6', 394 | 154 silly addNameRange '0.9.4', 395 | 154 silly addNameRange '0.8.7', 396 | 154 silly addNameRange '0.9.5', 397 | 154 silly addNameRange '0.9.6', 398 | 154 silly addNameRange '0.8.8', 399 | 154 silly addNameRange '0.9.7', 400 | 154 silly addNameRange '0.9.8', 401 | 154 silly addNameRange '0.10.0', 402 | 154 silly addNameRange '0.10.1', 403 | 154 silly addNameRange '0.10.2', 404 | 154 silly addNameRange '0.11.0', 405 | 154 silly addNameRange '0.11.1', 406 | 154 silly addNameRange '0.10.3', 407 | 154 silly addNameRange '0.10.4', 408 | 154 silly addNameRange '0.11.2', 409 | 154 silly addNameRange '0.11.3', 410 | 154 silly addNameRange '0.10.5', 411 | 154 silly addNameRange '0.11.4', 412 | 154 silly addNameRange '0.11.5', 413 | 154 silly addNameRange '0.10.6', 414 | 154 silly addNameRange '0.11.6', 415 | 154 silly addNameRange '0.10.7', 416 | 154 silly addNameRange '0.11.7', 417 | 154 silly addNameRange '0.11.8', 418 | 154 silly addNameRange '0.11.9', 419 | 154 silly addNameRange '0.10.8', 420 | 154 silly addNameRange '0.11.10', 421 | 154 silly addNameRange '0.11.11', 422 | 154 silly addNameRange '0.11.12', 423 | 154 silly addNameRange '0.11.11-dev', 424 | 154 silly addNameRange '0.10.9', 425 | 154 silly addNameRange '0.11.12-dev', 426 | 154 silly addNameRange '0.11.12-dev2', 427 | 154 silly addNameRange '0.11.13', 428 | 154 silly addNameRange '0.11.14', 429 | 154 silly addNameRange '0.12.0', 430 | 154 silly addNameRange '0.10.10', 431 | 154 silly addNameRange '0.12.1', 432 | 154 silly addNameRange '0.12.2', 433 | 154 silly addNameRange '0.12.3', 434 | 154 silly addNameRange '0.12.4', 435 | 154 silly addNameRange '0.12.5', 436 | 154 silly addNameRange '0.12.6', 437 | 154 silly addNameRange '0.12.6-beta-43e6e28', 438 | 154 silly addNameRange '0.12.7', 439 | 154 silly addNameRange '0.12.8', 440 | 154 silly addNameRange '0.12.9', 441 | 154 silly addNameRange '0.12.10', 442 | 154 silly addNameRange '0.12.11', 443 | 154 silly addNameRange '0.12.12', 444 | 154 silly addNameRange '0.12.11-beta-3029418', 445 | 154 silly addNameRange '0.12.13', 446 | 154 silly addNameRange '0.12.14', 447 | 154 silly addNameRange '0.12.15', 448 | 154 silly addNameRange '0.12.16', 449 | 154 silly addNameRange '0.12.16-beta-905422d', 450 | 154 silly addNameRange '0.12.17', 451 | 154 silly addNameRange '0.12.18', 452 | 154 silly addNameRange '0.12.19', 453 | 154 silly addNameRange '0.12.20', 454 | 154 silly addNameRange '0.12.21', 455 | 154 silly addNameRange '0.12.22', 456 | 154 silly addNameRange '0.12.23', 457 | 154 silly addNameRange '0.12.24', 458 | 154 silly addNameRange '0.12.24-beta-6cf7955', 459 | 154 silly addNameRange '0.12.25', 460 | 154 silly addNameRange '0.12.25-beta-37a7958', 461 | 154 silly addNameRange '0.12.25-beta-ad5bc24', 462 | 154 silly addNameRange '0.12.26', 463 | 154 silly addNameRange '0.12.27', 464 | 154 silly addNameRange '0.12.28', 465 | 154 silly addNameRange '0.12.28-beta-b9be580' ] ] 466 | 155 verbose addNamed [ 'karma', '0.12.28' ] 467 | 156 verbose addNamed [ '0.12.28', '0.12.28' ] 468 | 157 silly lockFile 89295513-karma-0-12-28 karma@0.12.28 469 | 158 verbose lock karma@0.12.28 /Users/mac/.npm/89295513-karma-0-12-28.lock 470 | 159 silly lockFile 1642552f-pmjs-org-karma-karma-0-12-28-tgz https://registry.npmjs.org/karma/-/karma-0.12.28.tgz 471 | 160 verbose lock https://registry.npmjs.org/karma/-/karma-0.12.28.tgz /Users/mac/.npm/1642552f-pmjs-org-karma-karma-0-12-28-tgz.lock 472 | 161 verbose addRemoteTarball [ 'https://registry.npmjs.org/karma/-/karma-0.12.28.tgz', 473 | 161 verbose addRemoteTarball '80111f75ae99c9a0b0974ad0c98e6271bc2318fc' ] 474 | 162 info retry fetch attempt 1 at 13:53:27 475 | 163 verbose fetch to= /tmp/npm-80088-6GEyfJWh/registry.npmjs.org/karma/-/karma-0.12.28.tgz 476 | 164 http GET https://registry.npmjs.org/karma/-/karma-0.12.28.tgz 477 | 165 http 200 https://registry.npmjs.org/karma/-/karma-0.12.28.tgz 478 | 166 silly lockFile 1642552f-pmjs-org-karma-karma-0-12-28-tgz https://registry.npmjs.org/karma/-/karma-0.12.28.tgz 479 | 167 silly lockFile 1642552f-pmjs-org-karma-karma-0-12-28-tgz https://registry.npmjs.org/karma/-/karma-0.12.28.tgz 480 | 168 silly lockFile 89295513-karma-0-12-28 karma@0.12.28 481 | 169 silly lockFile 89295513-karma-0-12-28 karma@0.12.28 482 | 170 silly lockFile 35ff5c57-karma-0-12-21 karma@^0.12.21 483 | 171 silly lockFile 35ff5c57-karma-0-12-21 karma@^0.12.21 484 | 172 error notarget No compatible version found: karma-jasmine@'>=0.1.6-0 <0.2.0-0' 485 | 172 error notarget Valid install targets: 486 | 172 error notarget ["0.0.1","0.0.2","0.0.3","0.1.0","0.1.1","0.1.2","0.1.3","0.1.4","0.1.5","0.2.0","0.2.1","0.2.2","0.2.3","0.3.0","0.3.1","0.3.2"] 487 | 172 error notarget 488 | 172 error notarget This is most likely not a problem with npm itself. 489 | 172 error notarget In most cases you or one of your dependencies are requesting 490 | 172 error notarget a package version that doesn't exist. 491 | 173 error System Darwin 14.0.0 492 | 174 error command "/usr/local/bin/node" "/usr/local/bin/npm" "install" 493 | 175 error cwd /Applications/MAMP/htdocs/live-projects/resize 494 | 176 error node -v v0.10.33 495 | 177 error npm -v 1.4.28 496 | 178 error code ETARGET 497 | 179 verbose exit [ 1, true ] 498 | -------------------------------------------------------------------------------- /spec/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 | //Add semicolon to prevent IIFE from being passed as argument to concated code. 10 | ; 11 | 12 | // UMD (Universal Module Definition) 13 | // see https://github.com/umdjs/umd/blob/master/returnExports.js 14 | (function (root, factory) { 15 | if (typeof define === 'function' && define.amd) { 16 | // AMD. Register as an anonymous module. 17 | define(factory); 18 | } else if (typeof exports === 'object') { 19 | // Node. Does not work with strict CommonJS, but 20 | // only CommonJS-like enviroments that support module.exports, 21 | // like Node. 22 | module.exports = factory(); 23 | } else { 24 | // Browser globals (root is window) 25 | root.returnExports = factory(); 26 | } 27 | }(this, function () { 28 | 29 | /** 30 | * Brings an environment as close to ECMAScript 5 compliance 31 | * as is possible with the facilities of erstwhile engines. 32 | * 33 | * Annotated ES5: http://es5.github.com/ (specific links below) 34 | * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 35 | * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ 36 | */ 37 | 38 | // Shortcut to an often accessed properties, in order to avoid multiple 39 | // dereference that costs universally. 40 | var ArrayPrototype = Array.prototype; 41 | var ObjectPrototype = Object.prototype; 42 | var FunctionPrototype = Function.prototype; 43 | var StringPrototype = String.prototype; 44 | var NumberPrototype = Number.prototype; 45 | var array_slice = ArrayPrototype.slice; 46 | var array_splice = ArrayPrototype.splice; 47 | var array_push = ArrayPrototype.push; 48 | var array_unshift = ArrayPrototype.unshift; 49 | var call = FunctionPrototype.call; 50 | 51 | // Having a toString local variable name breaks in Opera so use _toString. 52 | var _toString = ObjectPrototype.toString; 53 | 54 | var isFunction = function (val) { 55 | return ObjectPrototype.toString.call(val) === '[object Function]'; 56 | }; 57 | var isRegex = function (val) { 58 | return ObjectPrototype.toString.call(val) === '[object RegExp]'; 59 | }; 60 | var isArray = function isArray(obj) { 61 | return _toString.call(obj) === "[object Array]"; 62 | }; 63 | var isString = function isString(obj) { 64 | return _toString.call(obj) === "[object String]"; 65 | }; 66 | var isArguments = function isArguments(value) { 67 | var str = _toString.call(value); 68 | var isArgs = str === '[object Arguments]'; 69 | if (!isArgs) { 70 | isArgs = !isArray(value) 71 | && value !== null 72 | && typeof value === 'object' 73 | && typeof value.length === 'number' 74 | && value.length >= 0 75 | && isFunction(value.callee); 76 | } 77 | return isArgs; 78 | }; 79 | 80 | var supportsDescriptors = Object.defineProperty && (function () { 81 | try { 82 | Object.defineProperty({}, 'x', {}); 83 | return true; 84 | } catch (e) { /* this is ES3 */ 85 | return false; 86 | } 87 | }()); 88 | 89 | // Define configurable, writable and non-enumerable props 90 | // if they don't exist. 91 | var defineProperty; 92 | if (supportsDescriptors) { 93 | defineProperty = function (object, name, method, forceAssign) { 94 | if (!forceAssign && (name in object)) { return; } 95 | Object.defineProperty(object, name, { 96 | configurable: true, 97 | enumerable: false, 98 | writable: true, 99 | value: method 100 | }); 101 | }; 102 | } else { 103 | defineProperty = function (object, name, method, forceAssign) { 104 | if (!forceAssign && (name in object)) { return; } 105 | object[name] = method; 106 | }; 107 | } 108 | var defineProperties = function (object, map, forceAssign) { 109 | for (var name in map) { 110 | if (ObjectPrototype.hasOwnProperty.call(map, name)) { 111 | defineProperty(object, name, map[name], forceAssign); 112 | } 113 | } 114 | }; 115 | 116 | // 117 | // Util 118 | // ====== 119 | // 120 | 121 | // ES5 9.4 122 | // http://es5.github.com/#x9.4 123 | // http://jsperf.com/to-integer 124 | 125 | function toInteger(n) { 126 | n = +n; 127 | if (n !== n) { // isNaN 128 | n = 0; 129 | } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { 130 | n = (n > 0 || -1) * Math.floor(Math.abs(n)); 131 | } 132 | return n; 133 | } 134 | 135 | function isPrimitive(input) { 136 | var type = typeof input; 137 | return ( 138 | input === null || 139 | type === "undefined" || 140 | type === "boolean" || 141 | type === "number" || 142 | type === "string" 143 | ); 144 | } 145 | 146 | function toPrimitive(input) { 147 | var val, valueOf, toStr; 148 | if (isPrimitive(input)) { 149 | return input; 150 | } 151 | valueOf = input.valueOf; 152 | if (isFunction(valueOf)) { 153 | val = valueOf.call(input); 154 | if (isPrimitive(val)) { 155 | return val; 156 | } 157 | } 158 | toStr = input.toString; 159 | if (isFunction(toStr)) { 160 | val = toStr.call(input); 161 | if (isPrimitive(val)) { 162 | return val; 163 | } 164 | } 165 | throw new TypeError(); 166 | } 167 | 168 | // ES5 9.9 169 | // http://es5.github.com/#x9.9 170 | var toObject = function (o) { 171 | if (o == null) { // this matches both null and undefined 172 | throw new TypeError("can't convert " + o + " to object"); 173 | } 174 | return Object(o); 175 | }; 176 | 177 | var ToUint32 = function ToUint32(x) { 178 | return x >>> 0; 179 | }; 180 | 181 | // 182 | // Function 183 | // ======== 184 | // 185 | 186 | // ES-5 15.3.4.5 187 | // http://es5.github.com/#x15.3.4.5 188 | 189 | function Empty() {} 190 | 191 | defineProperties(FunctionPrototype, { 192 | bind: function bind(that) { // .length is 1 193 | // 1. Let Target be the this value. 194 | var target = this; 195 | // 2. If IsCallable(Target) is false, throw a TypeError exception. 196 | if (!isFunction(target)) { 197 | throw new TypeError("Function.prototype.bind called on incompatible " + target); 198 | } 199 | // 3. Let A be a new (possibly empty) internal list of all of the 200 | // argument values provided after thisArg (arg1, arg2 etc), in order. 201 | // XXX slicedArgs will stand in for "A" if used 202 | var args = array_slice.call(arguments, 1); // for normal call 203 | // 4. Let F be a new native ECMAScript object. 204 | // 11. Set the [[Prototype]] internal property of F to the standard 205 | // built-in Function prototype object as specified in 15.3.3.1. 206 | // 12. Set the [[Call]] internal property of F as described in 207 | // 15.3.4.5.1. 208 | // 13. Set the [[Construct]] internal property of F as described in 209 | // 15.3.4.5.2. 210 | // 14. Set the [[HasInstance]] internal property of F as described in 211 | // 15.3.4.5.3. 212 | var binder = function () { 213 | 214 | if (this instanceof bound) { 215 | // 15.3.4.5.2 [[Construct]] 216 | // When the [[Construct]] internal method of a function object, 217 | // F that was created using the bind function is called with a 218 | // list of arguments ExtraArgs, the following steps are taken: 219 | // 1. Let target be the value of F's [[TargetFunction]] 220 | // internal property. 221 | // 2. If target has no [[Construct]] internal method, a 222 | // TypeError exception is thrown. 223 | // 3. Let boundArgs be the value of F's [[BoundArgs]] internal 224 | // property. 225 | // 4. Let args be a new list containing the same values as the 226 | // list boundArgs in the same order followed by the same 227 | // values as the list ExtraArgs in the same order. 228 | // 5. Return the result of calling the [[Construct]] internal 229 | // method of target providing args as the arguments. 230 | 231 | var result = target.apply( 232 | this, 233 | args.concat(array_slice.call(arguments)) 234 | ); 235 | if (Object(result) === result) { 236 | return result; 237 | } 238 | return this; 239 | 240 | } else { 241 | // 15.3.4.5.1 [[Call]] 242 | // When the [[Call]] internal method of a function object, F, 243 | // which was created using the bind function is called with a 244 | // this value and a list of arguments ExtraArgs, the following 245 | // steps are taken: 246 | // 1. Let boundArgs be the value of F's [[BoundArgs]] internal 247 | // property. 248 | // 2. Let boundThis be the value of F's [[BoundThis]] internal 249 | // property. 250 | // 3. Let target be the value of F's [[TargetFunction]] internal 251 | // property. 252 | // 4. Let args be a new list containing the same values as the 253 | // list boundArgs in the same order followed by the same 254 | // values as the list ExtraArgs in the same order. 255 | // 5. Return the result of calling the [[Call]] internal method 256 | // of target providing boundThis as the this value and 257 | // providing args as the arguments. 258 | 259 | // equiv: target.call(this, ...boundArgs, ...args) 260 | return target.apply( 261 | that, 262 | args.concat(array_slice.call(arguments)) 263 | ); 264 | 265 | } 266 | 267 | }; 268 | 269 | // 15. If the [[Class]] internal property of Target is "Function", then 270 | // a. Let L be the length property of Target minus the length of A. 271 | // b. Set the length own property of F to either 0 or L, whichever is 272 | // larger. 273 | // 16. Else set the length own property of F to 0. 274 | 275 | var boundLength = Math.max(0, target.length - args.length); 276 | 277 | // 17. Set the attributes of the length own property of F to the values 278 | // specified in 15.3.5.1. 279 | var boundArgs = []; 280 | for (var i = 0; i < boundLength; i++) { 281 | boundArgs.push("$" + i); 282 | } 283 | 284 | // XXX Build a dynamic function with desired amount of arguments is the only 285 | // way to set the length property of a function. 286 | // In environments where Content Security Policies enabled (Chrome extensions, 287 | // for ex.) all use of eval or Function costructor throws an exception. 288 | // However in all of these environments Function.prototype.bind exists 289 | // and so this code will never be executed. 290 | var bound = Function("binder", "return function (" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder); 291 | 292 | if (target.prototype) { 293 | Empty.prototype = target.prototype; 294 | bound.prototype = new Empty(); 295 | // Clean up dangling references. 296 | Empty.prototype = null; 297 | } 298 | 299 | // TODO 300 | // 18. Set the [[Extensible]] internal property of F to true. 301 | 302 | // TODO 303 | // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). 304 | // 20. Call the [[DefineOwnProperty]] internal method of F with 305 | // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: 306 | // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and 307 | // false. 308 | // 21. Call the [[DefineOwnProperty]] internal method of F with 309 | // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, 310 | // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, 311 | // and false. 312 | 313 | // TODO 314 | // NOTE Function objects created using Function.prototype.bind do not 315 | // have a prototype property or the [[Code]], [[FormalParameters]], and 316 | // [[Scope]] internal properties. 317 | // XXX can't delete prototype in pure-js. 318 | 319 | // 22. Return F. 320 | return bound; 321 | } 322 | }); 323 | 324 | // _Please note: Shortcuts are defined after `Function.prototype.bind` as we 325 | // us it in defining shortcuts. 326 | var owns = call.bind(ObjectPrototype.hasOwnProperty); 327 | 328 | // If JS engine supports accessors creating shortcuts. 329 | var defineGetter; 330 | var defineSetter; 331 | var lookupGetter; 332 | var lookupSetter; 333 | var supportsAccessors; 334 | if ((supportsAccessors = owns(ObjectPrototype, "__defineGetter__"))) { 335 | defineGetter = call.bind(ObjectPrototype.__defineGetter__); 336 | defineSetter = call.bind(ObjectPrototype.__defineSetter__); 337 | lookupGetter = call.bind(ObjectPrototype.__lookupGetter__); 338 | lookupSetter = call.bind(ObjectPrototype.__lookupSetter__); 339 | } 340 | 341 | // 342 | // Array 343 | // ===== 344 | // 345 | 346 | // ES5 15.4.4.12 347 | // http://es5.github.com/#x15.4.4.12 348 | var spliceNoopReturnsEmptyArray = (function () { 349 | var a = [1, 2]; 350 | var result = a.splice(); 351 | return a.length === 2 && isArray(result) && result.length === 0; 352 | }()); 353 | defineProperties(ArrayPrototype, { 354 | // Safari 5.0 bug where .splice() returns undefined 355 | splice: function splice(start, deleteCount) { 356 | if (arguments.length === 0) { 357 | return []; 358 | } else { 359 | return array_splice.apply(this, arguments); 360 | } 361 | } 362 | }, spliceNoopReturnsEmptyArray); 363 | 364 | var spliceWorksWithEmptyObject = (function () { 365 | var obj = {}; 366 | ArrayPrototype.splice.call(obj, 0, 0, 1); 367 | return obj.length === 1; 368 | }()); 369 | defineProperties(ArrayPrototype, { 370 | splice: function splice(start, deleteCount) { 371 | if (arguments.length === 0) { return []; } 372 | var args = arguments; 373 | this.length = Math.max(toInteger(this.length), 0); 374 | if (arguments.length > 0 && typeof deleteCount !== 'number') { 375 | args = array_slice.call(arguments); 376 | if (args.length < 2) { 377 | args.push(this.length - start); 378 | } else { 379 | args[1] = toInteger(deleteCount); 380 | } 381 | } 382 | return array_splice.apply(this, args); 383 | } 384 | }, !spliceWorksWithEmptyObject); 385 | 386 | // ES5 15.4.4.12 387 | // http://es5.github.com/#x15.4.4.13 388 | // Return len+argCount. 389 | // [bugfix, ielt8] 390 | // IE < 8 bug: [].unshift(0) === undefined but should be "1" 391 | var hasUnshiftReturnValueBug = [].unshift(0) !== 1; 392 | defineProperties(ArrayPrototype, { 393 | unshift: function () { 394 | array_unshift.apply(this, arguments); 395 | return this.length; 396 | } 397 | }, hasUnshiftReturnValueBug); 398 | 399 | // ES5 15.4.3.2 400 | // http://es5.github.com/#x15.4.3.2 401 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray 402 | defineProperties(Array, { isArray: isArray }); 403 | 404 | // The IsCallable() check in the Array functions 405 | // has been replaced with a strict check on the 406 | // internal class of the object to trap cases where 407 | // the provided function was actually a regular 408 | // expression literal, which in V8 and 409 | // JavaScriptCore is a typeof "function". Only in 410 | // V8 are regular expression literals permitted as 411 | // reduce parameters, so it is desirable in the 412 | // general case for the shim to match the more 413 | // strict and common behavior of rejecting regular 414 | // expressions. 415 | 416 | // ES5 15.4.4.18 417 | // http://es5.github.com/#x15.4.4.18 418 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach 419 | 420 | // Check failure of by-index access of string characters (IE < 9) 421 | // and failure of `0 in boxedString` (Rhino) 422 | var boxedString = Object("a"); 423 | var splitString = boxedString[0] !== "a" || !(0 in boxedString); 424 | 425 | var properlyBoxesContext = function properlyBoxed(method) { 426 | // Check node 0.6.21 bug where third parameter is not boxed 427 | var properlyBoxesNonStrict = true; 428 | var properlyBoxesStrict = true; 429 | if (method) { 430 | method.call('foo', function (_, __, context) { 431 | if (typeof context !== 'object') { properlyBoxesNonStrict = false; } 432 | }); 433 | 434 | method.call([1], function () { 435 | 'use strict'; 436 | properlyBoxesStrict = typeof this === 'string'; 437 | }, 'x'); 438 | } 439 | return !!method && properlyBoxesNonStrict && properlyBoxesStrict; 440 | }; 441 | 442 | defineProperties(ArrayPrototype, { 443 | forEach: function forEach(fun /*, thisp*/) { 444 | var object = toObject(this), 445 | self = splitString && isString(this) ? this.split('') : object, 446 | thisp = arguments[1], 447 | i = -1, 448 | length = self.length >>> 0; 449 | 450 | // If no callback function or if callback is not a callable function 451 | if (!isFunction(fun)) { 452 | throw new TypeError(); // TODO message 453 | } 454 | 455 | while (++i < length) { 456 | if (i in self) { 457 | // Invoke the callback function with call, passing arguments: 458 | // context, property value, property key, thisArg object 459 | // context 460 | fun.call(thisp, self[i], i, object); 461 | } 462 | } 463 | } 464 | }, !properlyBoxesContext(ArrayPrototype.forEach)); 465 | 466 | // ES5 15.4.4.19 467 | // http://es5.github.com/#x15.4.4.19 468 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map 469 | defineProperties(ArrayPrototype, { 470 | map: function map(fun /*, thisp*/) { 471 | var object = toObject(this), 472 | self = splitString && isString(this) ? this.split('') : object, 473 | length = self.length >>> 0, 474 | result = Array(length), 475 | thisp = arguments[1]; 476 | 477 | // If no callback function or if callback is not a callable function 478 | if (!isFunction(fun)) { 479 | throw new TypeError(fun + " is not a function"); 480 | } 481 | 482 | for (var i = 0; i < length; i++) { 483 | if (i in self) { 484 | result[i] = fun.call(thisp, self[i], i, object); 485 | } 486 | } 487 | return result; 488 | } 489 | }, !properlyBoxesContext(ArrayPrototype.map)); 490 | 491 | // ES5 15.4.4.20 492 | // http://es5.github.com/#x15.4.4.20 493 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter 494 | defineProperties(ArrayPrototype, { 495 | filter: function filter(fun /*, thisp */) { 496 | var object = toObject(this), 497 | self = splitString && isString(this) ? this.split('') : object, 498 | length = self.length >>> 0, 499 | result = [], 500 | value, 501 | thisp = arguments[1]; 502 | 503 | // If no callback function or if callback is not a callable function 504 | if (!isFunction(fun)) { 505 | throw new TypeError(fun + " is not a function"); 506 | } 507 | 508 | for (var i = 0; i < length; i++) { 509 | if (i in self) { 510 | value = self[i]; 511 | if (fun.call(thisp, value, i, object)) { 512 | result.push(value); 513 | } 514 | } 515 | } 516 | return result; 517 | } 518 | }, !properlyBoxesContext(ArrayPrototype.filter)); 519 | 520 | // ES5 15.4.4.16 521 | // http://es5.github.com/#x15.4.4.16 522 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every 523 | defineProperties(ArrayPrototype, { 524 | every: function every(fun /*, thisp */) { 525 | var object = toObject(this), 526 | self = splitString && isString(this) ? this.split('') : object, 527 | length = self.length >>> 0, 528 | thisp = arguments[1]; 529 | 530 | // If no callback function or if callback is not a callable function 531 | if (!isFunction(fun)) { 532 | throw new TypeError(fun + " is not a function"); 533 | } 534 | 535 | for (var i = 0; i < length; i++) { 536 | if (i in self && !fun.call(thisp, self[i], i, object)) { 537 | return false; 538 | } 539 | } 540 | return true; 541 | } 542 | }, !properlyBoxesContext(ArrayPrototype.every)); 543 | 544 | // ES5 15.4.4.17 545 | // http://es5.github.com/#x15.4.4.17 546 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some 547 | defineProperties(ArrayPrototype, { 548 | some: function some(fun /*, thisp */) { 549 | var object = toObject(this), 550 | self = splitString && isString(this) ? this.split('') : object, 551 | length = self.length >>> 0, 552 | thisp = arguments[1]; 553 | 554 | // If no callback function or if callback is not a callable function 555 | if (!isFunction(fun)) { 556 | throw new TypeError(fun + " is not a function"); 557 | } 558 | 559 | for (var i = 0; i < length; i++) { 560 | if (i in self && fun.call(thisp, self[i], i, object)) { 561 | return true; 562 | } 563 | } 564 | return false; 565 | } 566 | }, !properlyBoxesContext(ArrayPrototype.some)); 567 | 568 | // ES5 15.4.4.21 569 | // http://es5.github.com/#x15.4.4.21 570 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce 571 | var reduceCoercesToObject = false; 572 | if (ArrayPrototype.reduce) { 573 | reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; 574 | } 575 | defineProperties(ArrayPrototype, { 576 | reduce: function reduce(fun /*, initial*/) { 577 | var object = toObject(this), 578 | self = splitString && isString(this) ? this.split('') : object, 579 | length = self.length >>> 0; 580 | 581 | // If no callback function or if callback is not a callable function 582 | if (!isFunction(fun)) { 583 | throw new TypeError(fun + " is not a function"); 584 | } 585 | 586 | // no value to return if no initial value and an empty array 587 | if (!length && arguments.length === 1) { 588 | throw new TypeError("reduce of empty array with no initial value"); 589 | } 590 | 591 | var i = 0; 592 | var result; 593 | if (arguments.length >= 2) { 594 | result = arguments[1]; 595 | } else { 596 | do { 597 | if (i in self) { 598 | result = self[i++]; 599 | break; 600 | } 601 | 602 | // if array contains no values, no initial value to return 603 | if (++i >= length) { 604 | throw new TypeError("reduce of empty array with no initial value"); 605 | } 606 | } while (true); 607 | } 608 | 609 | for (; i < length; i++) { 610 | if (i in self) { 611 | result = fun.call(void 0, result, self[i], i, object); 612 | } 613 | } 614 | 615 | return result; 616 | } 617 | }, !reduceCoercesToObject); 618 | 619 | // ES5 15.4.4.22 620 | // http://es5.github.com/#x15.4.4.22 621 | // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight 622 | var reduceRightCoercesToObject = false; 623 | if (ArrayPrototype.reduceRight) { 624 | reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; 625 | } 626 | defineProperties(ArrayPrototype, { 627 | reduceRight: function reduceRight(fun /*, initial*/) { 628 | var object = toObject(this), 629 | self = splitString && isString(this) ? this.split('') : object, 630 | length = self.length >>> 0; 631 | 632 | // If no callback function or if callback is not a callable function 633 | if (!isFunction(fun)) { 634 | throw new TypeError(fun + " is not a function"); 635 | } 636 | 637 | // no value to return if no initial value, empty array 638 | if (!length && arguments.length === 1) { 639 | throw new TypeError("reduceRight of empty array with no initial value"); 640 | } 641 | 642 | var result, i = length - 1; 643 | if (arguments.length >= 2) { 644 | result = arguments[1]; 645 | } else { 646 | do { 647 | if (i in self) { 648 | result = self[i--]; 649 | break; 650 | } 651 | 652 | // if array contains no values, no initial value to return 653 | if (--i < 0) { 654 | throw new TypeError("reduceRight of empty array with no initial value"); 655 | } 656 | } while (true); 657 | } 658 | 659 | if (i < 0) { 660 | return result; 661 | } 662 | 663 | do { 664 | if (i in self) { 665 | result = fun.call(void 0, result, self[i], i, object); 666 | } 667 | } while (i--); 668 | 669 | return result; 670 | } 671 | }, !reduceRightCoercesToObject); 672 | 673 | // ES5 15.4.4.14 674 | // http://es5.github.com/#x15.4.4.14 675 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf 676 | var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1; 677 | defineProperties(ArrayPrototype, { 678 | indexOf: function indexOf(sought /*, fromIndex */ ) { 679 | var self = splitString && isString(this) ? this.split('') : toObject(this), 680 | length = self.length >>> 0; 681 | 682 | if (!length) { 683 | return -1; 684 | } 685 | 686 | var i = 0; 687 | if (arguments.length > 1) { 688 | i = toInteger(arguments[1]); 689 | } 690 | 691 | // handle negative indices 692 | i = i >= 0 ? i : Math.max(0, length + i); 693 | for (; i < length; i++) { 694 | if (i in self && self[i] === sought) { 695 | return i; 696 | } 697 | } 698 | return -1; 699 | } 700 | }, hasFirefox2IndexOfBug); 701 | 702 | // ES5 15.4.4.15 703 | // http://es5.github.com/#x15.4.4.15 704 | // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf 705 | var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; 706 | defineProperties(ArrayPrototype, { 707 | lastIndexOf: function lastIndexOf(sought /*, fromIndex */) { 708 | var self = splitString && isString(this) ? this.split('') : toObject(this), 709 | length = self.length >>> 0; 710 | 711 | if (!length) { 712 | return -1; 713 | } 714 | var i = length - 1; 715 | if (arguments.length > 1) { 716 | i = Math.min(i, toInteger(arguments[1])); 717 | } 718 | // handle negative indices 719 | i = i >= 0 ? i : length - Math.abs(i); 720 | for (; i >= 0; i--) { 721 | if (i in self && sought === self[i]) { 722 | return i; 723 | } 724 | } 725 | return -1; 726 | } 727 | }, hasFirefox2LastIndexOfBug); 728 | 729 | // 730 | // Object 731 | // ====== 732 | // 733 | 734 | // ES5 15.2.3.14 735 | // http://es5.github.com/#x15.2.3.14 736 | 737 | // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation 738 | var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'), 739 | hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'), 740 | dontEnums = [ 741 | "toString", 742 | "toLocaleString", 743 | "valueOf", 744 | "hasOwnProperty", 745 | "isPrototypeOf", 746 | "propertyIsEnumerable", 747 | "constructor" 748 | ], 749 | dontEnumsLength = dontEnums.length; 750 | 751 | defineProperties(Object, { 752 | keys: function keys(object) { 753 | var isFn = isFunction(object), 754 | isArgs = isArguments(object), 755 | isObject = object !== null && typeof object === 'object', 756 | isStr = isObject && isString(object); 757 | 758 | if (!isObject && !isFn && !isArgs) { 759 | throw new TypeError("Object.keys called on a non-object"); 760 | } 761 | 762 | var theKeys = []; 763 | var skipProto = hasProtoEnumBug && isFn; 764 | if (isStr || isArgs) { 765 | for (var i = 0; i < object.length; ++i) { 766 | theKeys.push(String(i)); 767 | } 768 | } else { 769 | for (var name in object) { 770 | if (!(skipProto && name === 'prototype') && owns(object, name)) { 771 | theKeys.push(String(name)); 772 | } 773 | } 774 | } 775 | 776 | if (hasDontEnumBug) { 777 | var ctor = object.constructor, 778 | skipConstructor = ctor && ctor.prototype === object; 779 | for (var j = 0; j < dontEnumsLength; j++) { 780 | var dontEnum = dontEnums[j]; 781 | if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { 782 | theKeys.push(dontEnum); 783 | } 784 | } 785 | } 786 | return theKeys; 787 | } 788 | }); 789 | 790 | var keysWorksWithArguments = Object.keys && (function () { 791 | // Safari 5.0 bug 792 | return Object.keys(arguments).length === 2; 793 | }(1, 2)); 794 | var originalKeys = Object.keys; 795 | defineProperties(Object, { 796 | keys: function keys(object) { 797 | if (isArguments(object)) { 798 | return originalKeys(ArrayPrototype.slice.call(object)); 799 | } else { 800 | return originalKeys(object); 801 | } 802 | } 803 | }, !keysWorksWithArguments); 804 | 805 | // 806 | // Date 807 | // ==== 808 | // 809 | 810 | // ES5 15.9.5.43 811 | // http://es5.github.com/#x15.9.5.43 812 | // This function returns a String value represent the instance in time 813 | // represented by this Date object. The format of the String is the Date Time 814 | // string format defined in 15.9.1.15. All fields are present in the String. 815 | // The time zone is always UTC, denoted by the suffix Z. If the time value of 816 | // this object is not a finite Number a RangeError exception is thrown. 817 | var negativeDate = -62198755200000; 818 | var negativeYearString = "-000001"; 819 | var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; 820 | 821 | defineProperties(Date.prototype, { 822 | toISOString: function toISOString() { 823 | var result, length, value, year, month; 824 | if (!isFinite(this)) { 825 | throw new RangeError("Date.prototype.toISOString called on non-finite value."); 826 | } 827 | 828 | year = this.getUTCFullYear(); 829 | 830 | month = this.getUTCMonth(); 831 | // see https://github.com/es-shims/es5-shim/issues/111 832 | year += Math.floor(month / 12); 833 | month = (month % 12 + 12) % 12; 834 | 835 | // the date time string format is specified in 15.9.1.15. 836 | result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; 837 | year = ( 838 | (year < 0 ? "-" : (year > 9999 ? "+" : "")) + 839 | ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6) 840 | ); 841 | 842 | length = result.length; 843 | while (length--) { 844 | value = result[length]; 845 | // pad months, days, hours, minutes, and seconds to have two 846 | // digits. 847 | if (value < 10) { 848 | result[length] = "0" + value; 849 | } 850 | } 851 | // pad milliseconds to have three digits. 852 | return ( 853 | year + "-" + result.slice(0, 2).join("-") + 854 | "T" + result.slice(2).join(":") + "." + 855 | ("000" + this.getUTCMilliseconds()).slice(-3) + "Z" 856 | ); 857 | } 858 | }, hasNegativeDateBug); 859 | 860 | 861 | // ES5 15.9.5.44 862 | // http://es5.github.com/#x15.9.5.44 863 | // This function provides a String representation of a Date object for use by 864 | // JSON.stringify (15.12.3). 865 | var dateToJSONIsSupported = false; 866 | try { 867 | dateToJSONIsSupported = ( 868 | Date.prototype.toJSON && 869 | new Date(NaN).toJSON() === null && 870 | new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && 871 | Date.prototype.toJSON.call({ // generic 872 | toISOString: function () { 873 | return true; 874 | } 875 | }) 876 | ); 877 | } catch (e) { 878 | } 879 | if (!dateToJSONIsSupported) { 880 | Date.prototype.toJSON = function toJSON(key) { 881 | // When the toJSON method is called with argument key, the following 882 | // steps are taken: 883 | 884 | // 1. Let O be the result of calling ToObject, giving it the this 885 | // value as its argument. 886 | // 2. Let tv be toPrimitive(O, hint Number). 887 | var o = Object(this), 888 | tv = toPrimitive(o), 889 | toISO; 890 | // 3. If tv is a Number and is not finite, return null. 891 | if (typeof tv === "number" && !isFinite(tv)) { 892 | return null; 893 | } 894 | // 4. Let toISO be the result of calling the [[Get]] internal method of 895 | // O with argument "toISOString". 896 | toISO = o.toISOString; 897 | // 5. If IsCallable(toISO) is false, throw a TypeError exception. 898 | if (typeof toISO !== "function") { 899 | throw new TypeError("toISOString property is not callable"); 900 | } 901 | // 6. Return the result of calling the [[Call]] internal method of 902 | // toISO with O as the this value and an empty argument list. 903 | return toISO.call(o); 904 | 905 | // NOTE 1 The argument is ignored. 906 | 907 | // NOTE 2 The toJSON function is intentionally generic; it does not 908 | // require that its this value be a Date object. Therefore, it can be 909 | // transferred to other kinds of objects for use as a method. However, 910 | // it does require that any such object have a toISOString method. An 911 | // object is free to use the argument key to filter its 912 | // stringification. 913 | }; 914 | } 915 | 916 | // ES5 15.9.4.2 917 | // http://es5.github.com/#x15.9.4.2 918 | // based on work shared by Daniel Friesen (dantman) 919 | // http://gist.github.com/303249 920 | var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; 921 | var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')); 922 | var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z")); 923 | if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { 924 | // XXX global assignment won't work in embeddings that use 925 | // an alternate object for the context. 926 | Date = (function (NativeDate) { 927 | 928 | // Date.length === 7 929 | function Date(Y, M, D, h, m, s, ms) { 930 | var length = arguments.length; 931 | if (this instanceof NativeDate) { 932 | var date = length === 1 && String(Y) === Y ? // isString(Y) 933 | // We explicitly pass it through parse: 934 | new NativeDate(Date.parse(Y)) : 935 | // We have to manually make calls depending on argument 936 | // length here 937 | length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : 938 | length >= 6 ? new NativeDate(Y, M, D, h, m, s) : 939 | length >= 5 ? new NativeDate(Y, M, D, h, m) : 940 | length >= 4 ? new NativeDate(Y, M, D, h) : 941 | length >= 3 ? new NativeDate(Y, M, D) : 942 | length >= 2 ? new NativeDate(Y, M) : 943 | length >= 1 ? new NativeDate(Y) : 944 | new NativeDate(); 945 | // Prevent mixups with unfixed Date object 946 | date.constructor = Date; 947 | return date; 948 | } 949 | return NativeDate.apply(this, arguments); 950 | } 951 | 952 | // 15.9.1.15 Date Time String Format. 953 | var isoDateExpression = new RegExp("^" + 954 | "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 955 | // 6-digit extended year 956 | "(?:-(\\d{2})" + // optional month capture 957 | "(?:-(\\d{2})" + // optional day capture 958 | "(?:" + // capture hours:minutes:seconds.milliseconds 959 | "T(\\d{2})" + // hours capture 960 | ":(\\d{2})" + // minutes capture 961 | "(?:" + // optional :seconds.milliseconds 962 | ":(\\d{2})" + // seconds capture 963 | "(?:(\\.\\d{1,}))?" + // milliseconds capture 964 | ")?" + 965 | "(" + // capture UTC offset component 966 | "Z|" + // UTC capture 967 | "(?:" + // offset specifier +/-hours:minutes 968 | "([-+])" + // sign capture 969 | "(\\d{2})" + // hours offset capture 970 | ":(\\d{2})" + // minutes offset capture 971 | ")" + 972 | ")?)?)?)?" + 973 | "$"); 974 | 975 | var months = [ 976 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 977 | ]; 978 | 979 | function dayFromMonth(year, month) { 980 | var t = month > 1 ? 1 : 0; 981 | return ( 982 | months[month] + 983 | Math.floor((year - 1969 + t) / 4) - 984 | Math.floor((year - 1901 + t) / 100) + 985 | Math.floor((year - 1601 + t) / 400) + 986 | 365 * (year - 1970) 987 | ); 988 | } 989 | 990 | function toUTC(t) { 991 | return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t)); 992 | } 993 | 994 | // Copy any custom methods a 3rd party library may have added 995 | for (var key in NativeDate) { 996 | Date[key] = NativeDate[key]; 997 | } 998 | 999 | // Copy "native" methods explicitly; they may be non-enumerable 1000 | Date.now = NativeDate.now; 1001 | Date.UTC = NativeDate.UTC; 1002 | Date.prototype = NativeDate.prototype; 1003 | Date.prototype.constructor = Date; 1004 | 1005 | // Upgrade Date.parse to handle simplified ISO 8601 strings 1006 | Date.parse = function parse(string) { 1007 | var match = isoDateExpression.exec(string); 1008 | if (match) { 1009 | // parse months, days, hours, minutes, seconds, and milliseconds 1010 | // provide default values if necessary 1011 | // parse the UTC offset component 1012 | var year = Number(match[1]), 1013 | month = Number(match[2] || 1) - 1, 1014 | day = Number(match[3] || 1) - 1, 1015 | hour = Number(match[4] || 0), 1016 | minute = Number(match[5] || 0), 1017 | second = Number(match[6] || 0), 1018 | millisecond = Math.floor(Number(match[7] || 0) * 1000), 1019 | // When time zone is missed, local offset should be used 1020 | // (ES 5.1 bug) 1021 | // see https://bugs.ecmascript.org/show_bug.cgi?id=112 1022 | isLocalTime = Boolean(match[4] && !match[8]), 1023 | signOffset = match[9] === "-" ? 1 : -1, 1024 | hourOffset = Number(match[10] || 0), 1025 | minuteOffset = Number(match[11] || 0), 1026 | result; 1027 | if ( 1028 | hour < ( 1029 | minute > 0 || second > 0 || millisecond > 0 ? 1030 | 24 : 25 1031 | ) && 1032 | minute < 60 && second < 60 && millisecond < 1000 && 1033 | month > -1 && month < 12 && hourOffset < 24 && 1034 | minuteOffset < 60 && // detect invalid offsets 1035 | day > -1 && 1036 | day < ( 1037 | dayFromMonth(year, month + 1) - 1038 | dayFromMonth(year, month) 1039 | ) 1040 | ) { 1041 | result = ( 1042 | (dayFromMonth(year, month) + day) * 24 + 1043 | hour + 1044 | hourOffset * signOffset 1045 | ) * 60; 1046 | result = ( 1047 | (result + minute + minuteOffset * signOffset) * 60 + 1048 | second 1049 | ) * 1000 + millisecond; 1050 | if (isLocalTime) { 1051 | result = toUTC(result); 1052 | } 1053 | if (-8.64e15 <= result && result <= 8.64e15) { 1054 | return result; 1055 | } 1056 | } 1057 | return NaN; 1058 | } 1059 | return NativeDate.parse.apply(this, arguments); 1060 | }; 1061 | 1062 | return Date; 1063 | })(Date); 1064 | } 1065 | 1066 | // ES5 15.9.4.4 1067 | // http://es5.github.com/#x15.9.4.4 1068 | if (!Date.now) { 1069 | Date.now = function now() { 1070 | return new Date().getTime(); 1071 | }; 1072 | } 1073 | 1074 | 1075 | // 1076 | // Number 1077 | // ====== 1078 | // 1079 | 1080 | // ES5.1 15.7.4.5 1081 | // http://es5.github.com/#x15.7.4.5 1082 | var hasToFixedBugs = NumberPrototype.toFixed && ( 1083 | (0.00008).toFixed(3) !== '0.000' 1084 | || (0.9).toFixed(0) !== '1' 1085 | || (1.255).toFixed(2) !== '1.25' 1086 | || (1000000000000000128).toFixed(0) !== "1000000000000000128" 1087 | ); 1088 | 1089 | var toFixedHelpers = { 1090 | base: 1e7, 1091 | size: 6, 1092 | data: [0, 0, 0, 0, 0, 0], 1093 | multiply: function multiply(n, c) { 1094 | var i = -1; 1095 | while (++i < toFixedHelpers.size) { 1096 | c += n * toFixedHelpers.data[i]; 1097 | toFixedHelpers.data[i] = c % toFixedHelpers.base; 1098 | c = Math.floor(c / toFixedHelpers.base); 1099 | } 1100 | }, 1101 | divide: function divide(n) { 1102 | var i = toFixedHelpers.size, c = 0; 1103 | while (--i >= 0) { 1104 | c += toFixedHelpers.data[i]; 1105 | toFixedHelpers.data[i] = Math.floor(c / n); 1106 | c = (c % n) * toFixedHelpers.base; 1107 | } 1108 | }, 1109 | numToString: function numToString() { 1110 | var i = toFixedHelpers.size; 1111 | var s = ''; 1112 | while (--i >= 0) { 1113 | if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { 1114 | var t = String(toFixedHelpers.data[i]); 1115 | if (s === '') { 1116 | s = t; 1117 | } else { 1118 | s += '0000000'.slice(0, 7 - t.length) + t; 1119 | } 1120 | } 1121 | } 1122 | return s; 1123 | }, 1124 | pow: function pow(x, n, acc) { 1125 | return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); 1126 | }, 1127 | log: function log(x) { 1128 | var n = 0; 1129 | while (x >= 4096) { 1130 | n += 12; 1131 | x /= 4096; 1132 | } 1133 | while (x >= 2) { 1134 | n += 1; 1135 | x /= 2; 1136 | } 1137 | return n; 1138 | } 1139 | }; 1140 | 1141 | defineProperties(NumberPrototype, { 1142 | toFixed: function toFixed(fractionDigits) { 1143 | var f, x, s, m, e, z, j, k; 1144 | 1145 | // Test for NaN and round fractionDigits down 1146 | f = Number(fractionDigits); 1147 | f = f !== f ? 0 : Math.floor(f); 1148 | 1149 | if (f < 0 || f > 20) { 1150 | throw new RangeError("Number.toFixed called with invalid number of decimals"); 1151 | } 1152 | 1153 | x = Number(this); 1154 | 1155 | // Test for NaN 1156 | if (x !== x) { 1157 | return "NaN"; 1158 | } 1159 | 1160 | // If it is too big or small, return the string value of the number 1161 | if (x <= -1e21 || x >= 1e21) { 1162 | return String(x); 1163 | } 1164 | 1165 | s = ""; 1166 | 1167 | if (x < 0) { 1168 | s = "-"; 1169 | x = -x; 1170 | } 1171 | 1172 | m = "0"; 1173 | 1174 | if (x > 1e-21) { 1175 | // 1e-21 < x < 1e21 1176 | // -70 < log2(x) < 70 1177 | e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; 1178 | z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); 1179 | z *= 0x10000000000000; // Math.pow(2, 52); 1180 | e = 52 - e; 1181 | 1182 | // -18 < e < 122 1183 | // x = z / 2 ^ e 1184 | if (e > 0) { 1185 | toFixedHelpers.multiply(0, z); 1186 | j = f; 1187 | 1188 | while (j >= 7) { 1189 | toFixedHelpers.multiply(1e7, 0); 1190 | j -= 7; 1191 | } 1192 | 1193 | toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); 1194 | j = e - 1; 1195 | 1196 | while (j >= 23) { 1197 | toFixedHelpers.divide(1 << 23); 1198 | j -= 23; 1199 | } 1200 | 1201 | toFixedHelpers.divide(1 << j); 1202 | toFixedHelpers.multiply(1, 1); 1203 | toFixedHelpers.divide(2); 1204 | m = toFixedHelpers.numToString(); 1205 | } else { 1206 | toFixedHelpers.multiply(0, z); 1207 | toFixedHelpers.multiply(1 << (-e), 0); 1208 | m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f); 1209 | } 1210 | } 1211 | 1212 | if (f > 0) { 1213 | k = m.length; 1214 | 1215 | if (k <= f) { 1216 | m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m; 1217 | } else { 1218 | m = s + m.slice(0, k - f) + '.' + m.slice(k - f); 1219 | } 1220 | } else { 1221 | m = s + m; 1222 | } 1223 | 1224 | return m; 1225 | } 1226 | }, hasToFixedBugs); 1227 | 1228 | 1229 | // 1230 | // String 1231 | // ====== 1232 | // 1233 | 1234 | // ES5 15.5.4.14 1235 | // http://es5.github.com/#x15.5.4.14 1236 | 1237 | // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] 1238 | // Many browsers do not split properly with regular expressions or they 1239 | // do not perform the split correctly under obscure conditions. 1240 | // See http://blog.stevenlevithan.com/archives/cross-browser-split 1241 | // I've tested in many browsers and this seems to cover the deviant ones: 1242 | // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] 1243 | // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] 1244 | // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not 1245 | // [undefined, "t", undefined, "e", ...] 1246 | // ''.split(/.?/) should be [], not [""] 1247 | // '.'.split(/()()/) should be ["."], not ["", "", "."] 1248 | 1249 | var string_split = StringPrototype.split; 1250 | if ( 1251 | 'ab'.split(/(?:ab)*/).length !== 2 || 1252 | '.'.split(/(.?)(.?)/).length !== 4 || 1253 | 'tesst'.split(/(s)*/)[1] === "t" || 1254 | 'test'.split(/(?:)/, -1).length !== 4 || 1255 | ''.split(/.?/).length || 1256 | '.'.split(/()()/).length > 1 1257 | ) { 1258 | (function () { 1259 | var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group 1260 | 1261 | StringPrototype.split = function (separator, limit) { 1262 | var string = this; 1263 | if (separator === void 0 && limit === 0) { 1264 | return []; 1265 | } 1266 | 1267 | // If `separator` is not a regex, use native split 1268 | if (_toString.call(separator) !== "[object RegExp]") { 1269 | return string_split.call(this, separator, limit); 1270 | } 1271 | 1272 | var output = [], 1273 | flags = (separator.ignoreCase ? "i" : "") + 1274 | (separator.multiline ? "m" : "") + 1275 | (separator.extended ? "x" : "") + // Proposed for ES6 1276 | (separator.sticky ? "y" : ""), // Firefox 3+ 1277 | lastLastIndex = 0, 1278 | // Make `global` and avoid `lastIndex` issues by working with a copy 1279 | separator2, match, lastIndex, lastLength; 1280 | separator = new RegExp(separator.source, flags + "g"); 1281 | string += ""; // Type-convert 1282 | if (!compliantExecNpcg) { 1283 | // Doesn't need flags gy, but they don't hurt 1284 | separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags); 1285 | } 1286 | /* Values for `limit`, per the spec: 1287 | * If undefined: 4294967295 // Math.pow(2, 32) - 1 1288 | * If 0, Infinity, or NaN: 0 1289 | * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; 1290 | * If negative number: 4294967296 - Math.floor(Math.abs(limit)) 1291 | * If other: Type-convert, then use the above rules 1292 | */ 1293 | limit = limit === void 0 ? 1294 | -1 >>> 0 : // Math.pow(2, 32) - 1 1295 | ToUint32(limit); 1296 | while (match = separator.exec(string)) { 1297 | // `separator.lastIndex` is not reliable cross-browser 1298 | lastIndex = match.index + match[0].length; 1299 | if (lastIndex > lastLastIndex) { 1300 | output.push(string.slice(lastLastIndex, match.index)); 1301 | // Fix browsers whose `exec` methods don't consistently return `undefined` for 1302 | // nonparticipating capturing groups 1303 | if (!compliantExecNpcg && match.length > 1) { 1304 | match[0].replace(separator2, function () { 1305 | for (var i = 1; i < arguments.length - 2; i++) { 1306 | if (arguments[i] === void 0) { 1307 | match[i] = void 0; 1308 | } 1309 | } 1310 | }); 1311 | } 1312 | if (match.length > 1 && match.index < string.length) { 1313 | ArrayPrototype.push.apply(output, match.slice(1)); 1314 | } 1315 | lastLength = match[0].length; 1316 | lastLastIndex = lastIndex; 1317 | if (output.length >= limit) { 1318 | break; 1319 | } 1320 | } 1321 | if (separator.lastIndex === match.index) { 1322 | separator.lastIndex++; // Avoid an infinite loop 1323 | } 1324 | } 1325 | if (lastLastIndex === string.length) { 1326 | if (lastLength || !separator.test("")) { 1327 | output.push(""); 1328 | } 1329 | } else { 1330 | output.push(string.slice(lastLastIndex)); 1331 | } 1332 | return output.length > limit ? output.slice(0, limit) : output; 1333 | }; 1334 | }()); 1335 | 1336 | // [bugfix, chrome] 1337 | // If separator is undefined, then the result array contains just one String, 1338 | // which is the this value (converted to a String). If limit is not undefined, 1339 | // then the output array is truncated so that it contains no more than limit 1340 | // elements. 1341 | // "0".split(undefined, 0) -> [] 1342 | } else if ("0".split(void 0, 0).length) { 1343 | StringPrototype.split = function split(separator, limit) { 1344 | if (separator === void 0 && limit === 0) { return []; } 1345 | return string_split.call(this, separator, limit); 1346 | }; 1347 | } 1348 | 1349 | var str_replace = StringPrototype.replace; 1350 | var replaceReportsGroupsCorrectly = (function () { 1351 | var groups = []; 1352 | 'x'.replace(/x(.)?/g, function (match, group) { 1353 | groups.push(group); 1354 | }); 1355 | return groups.length === 1 && typeof groups[0] === 'undefined'; 1356 | }()); 1357 | 1358 | if (!replaceReportsGroupsCorrectly) { 1359 | StringPrototype.replace = function replace(searchValue, replaceValue) { 1360 | var isFn = isFunction(replaceValue); 1361 | var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); 1362 | if (!isFn || !hasCapturingGroups) { 1363 | return str_replace.call(this, searchValue, replaceValue); 1364 | } else { 1365 | var wrappedReplaceValue = function (match) { 1366 | var length = arguments.length; 1367 | var originalLastIndex = searchValue.lastIndex; 1368 | searchValue.lastIndex = 0; 1369 | var args = searchValue.exec(match); 1370 | searchValue.lastIndex = originalLastIndex; 1371 | args.push(arguments[length - 2], arguments[length - 1]); 1372 | return replaceValue.apply(this, args); 1373 | }; 1374 | return str_replace.call(this, searchValue, wrappedReplaceValue); 1375 | } 1376 | }; 1377 | } 1378 | 1379 | // ECMA-262, 3rd B.2.3 1380 | // Not an ECMAScript standard, although ECMAScript 3rd Edition has a 1381 | // non-normative section suggesting uniform semantics and it should be 1382 | // normalized across all browsers 1383 | // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE 1384 | var string_substr = StringPrototype.substr; 1385 | var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b"; 1386 | defineProperties(StringPrototype, { 1387 | substr: function substr(start, length) { 1388 | return string_substr.call( 1389 | this, 1390 | start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start, 1391 | length 1392 | ); 1393 | } 1394 | }, hasNegativeSubstrBug); 1395 | 1396 | // ES5 15.5.4.20 1397 | // whitespace from: http://es5.github.io/#x15.5.4.20 1398 | var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + 1399 | "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + 1400 | "\u2029\uFEFF"; 1401 | var zeroWidth = '\u200b'; 1402 | var wsRegexChars = "[" + ws + "]"; 1403 | var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*"); 1404 | var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$"); 1405 | var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); 1406 | defineProperties(StringPrototype, { 1407 | // http://blog.stevenlevithan.com/archives/faster-trim-javascript 1408 | // http://perfectionkills.com/whitespace-deviations/ 1409 | trim: function trim() { 1410 | if (this === void 0 || this === null) { 1411 | throw new TypeError("can't convert " + this + " to object"); 1412 | } 1413 | return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); 1414 | } 1415 | }, hasTrimWhitespaceBug); 1416 | 1417 | // ES-5 15.1.2.2 1418 | if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { 1419 | parseInt = (function (origParseInt) { 1420 | var hexRegex = /^0[xX]/; 1421 | return function parseIntES5(str, radix) { 1422 | str = String(str).trim(); 1423 | if (!Number(radix)) { 1424 | radix = hexRegex.test(str) ? 16 : 10; 1425 | } 1426 | return origParseInt(str, radix); 1427 | }; 1428 | }(parseInt)); 1429 | } 1430 | 1431 | })); 1432 | --------------------------------------------------------------------------------