├── History.md ├── .gitignore ├── .travis.yml ├── .npmrc ├── .editorconfig ├── .eslintrc ├── browserify.js ├── test ├── index.html └── viewport.spec.js ├── package.json ├── dist ├── viewport.min.js ├── viewport.min.js.map └── viewport.js ├── README.md └── index.js /History.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | 4 | # Dependency directory 5 | node_modules 6 | 7 | # Trash 8 | .DS_Store 9 | 10 | # Test Files that should be ignored 11 | coverage 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6.9.1 4 | # Send coverage data to Coveralls 5 | after_script: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # More options: https://docs.npmjs.com/misc/config 2 | 3 | # Dependencies saved to package.json will be configured with an exact version 4 | # rather than using npm's default semver range operator. 5 | save-exact=true 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint-config-airbnb-base/legacy", 4 | "eslint-config-airbnb-base/rules/strict" 5 | ], 6 | "rules": { 7 | "max-len": ["warn", 120, 2, { 8 | "ignoreUrls": true, 9 | "ignoreComments": false 10 | }], 11 | "no-param-reassign": ["error", { "props": false }] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /browserify.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const browserify = require('browserify'); 3 | 4 | if (!fs.existsSync('./dist')) { 5 | fs.mkdirSync('./dist'); 6 | } 7 | 8 | browserify({ debug: false, standalone: 'viewport' }) 9 | .require('./index.js', { entry: true }) 10 | .bundle() 11 | .on('error', err => console.log(`Error: ${err.message}`)) 12 | .pipe(fs.createWriteStream('dist/viewport.js')); 13 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Viewport Component 6 | 7 | 8 | 13 | 14 | 15 |

Please, open your console and start to scroll and resize the viewport!

16 |
17 | 18 | 25 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "viewport-js", 3 | "version": "1.0.0", 4 | "description": "Gets the dimensions of the Viewport and beyond.", 5 | "repository": "git@github.com:pazguille/viewport.git", 6 | "author": "Guille Paz ", 7 | "scripts": { 8 | "build": "node browserify.js", 9 | "dist": "npm run build && uglifyjs ./dist/viewport.js -m -o ./dist/viewport.min.js --source-map ./dist/viewport.min.js.map", 10 | "test": "npm run build && NODE_ENV=test istanbul cover _mocha -- ./test/*.spec.js", 11 | "lint": "eslint index.js" 12 | }, 13 | "dependencies": { 14 | "decouple": "1.0.1", 15 | "jvent": "1.0.2" 16 | }, 17 | "devDependencies": { 18 | "better-assert": "1.0.2", 19 | "browserify": "14.1.0", 20 | "coveralls": "2.11.16", 21 | "eslint": "3.14.1", 22 | "eslint-config-airbnb-base": "11.1.0", 23 | "eslint-plugin-import": "2.2.0", 24 | "istanbul": "0.4.5", 25 | "jsdom": "9.11.0", 26 | "mkdirp": "0.5.1", 27 | "mocha": "3.2.0", 28 | "uglify-js": "2.7.5" 29 | }, 30 | "main": "index.js", 31 | "keywords": [ 32 | "viewport", 33 | "dimensions", 34 | "device", 35 | "window", 36 | "coordinates" 37 | ], 38 | "license": "MIT" 39 | } 40 | -------------------------------------------------------------------------------- /test/viewport.spec.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | const assert = require('better-assert'); 5 | const Jvent = require('jvent'); 6 | const jsdom = require('jsdom').jsdom; 7 | 8 | /** 9 | * Create window and document scene 10 | */ 11 | const document = jsdom(''); 12 | window = document.defaultView; 13 | window.screen = { width: 2000, height: 800, orientation: { type: 'potrait-principal' } }; 14 | window.document.documentElement.clientWidth = 1500; 15 | window.document.documentElement.clientHeight = 800; 16 | 17 | /** 18 | * Viewport 19 | */ 20 | const viewport = require('../'); 21 | 22 | /** 23 | * Tests 24 | */ 25 | describe('viewport', function () { 26 | it('should be an instance', function () { 27 | assert(typeof viewport === 'object'); 28 | }); 29 | 30 | it('should inherit from Jvent', function () { 31 | assert(viewport.constructor === Jvent); 32 | assert(viewport.on); 33 | assert(viewport.once); 34 | assert(viewport.off); 35 | assert(viewport.emit); 36 | }); 37 | 38 | it('should calculate viewport dimensions', function () { 39 | assert(viewport.width === 1500); 40 | assert(viewport.height === 800); 41 | }); 42 | 43 | it('should calculate viewport offset', function () { 44 | assert(typeof viewport.top === 'number'); 45 | assert(typeof viewport.bottom === 'number'); 46 | assert(typeof viewport.left === 'number'); 47 | assert(typeof viewport.right === 'number'); 48 | }); 49 | 50 | it('should calculate device', function () { 51 | assert(typeof viewport.device === 'object'); 52 | }); 53 | 54 | it('should calculate device orientation', function () { 55 | assert(viewport.device.orientation === 'potrait-principal'); 56 | }); 57 | 58 | it('should calculate device dimensions', function () { 59 | assert(viewport.device.width === 2000); 60 | assert(viewport.device.height === 800); 61 | }); 62 | 63 | it('should calculate scroll offset', function () { 64 | assert(typeof viewport.scrollY === 'number'); 65 | assert(typeof viewport.scrollX === 'number'); 66 | }); 67 | 68 | it('inViewport true', function () { 69 | const inViewport = viewport.inViewport({ 70 | getBoundingClientRect() { 71 | return { 72 | bottom: 232, 73 | left: 196, 74 | right: 800, 75 | top: 124, 76 | }; 77 | }, 78 | }); 79 | assert(typeof inViewport === 'boolean'); 80 | assert(inViewport === true); 81 | }); 82 | 83 | it('inViewport false', function () { 84 | const inViewport = viewport.inViewport({ 85 | getBoundingClientRect() { 86 | return { 87 | bottom: 232, 88 | left: 196, 89 | right: 800, 90 | top: -124, 91 | }; 92 | }, 93 | }); 94 | assert(typeof inViewport === 'boolean'); 95 | assert(inViewport === false); 96 | }); 97 | 98 | it('isVisible true', function () { 99 | const isVisible = viewport.isVisible({ 100 | getBoundingClientRect() { 101 | return { 102 | bottom: 232, 103 | left: 196, 104 | right: 800, 105 | top: 124, 106 | }; 107 | }, 108 | }); 109 | assert(typeof isVisible === 'boolean'); 110 | assert(isVisible === true); 111 | }); 112 | 113 | it('isVisible false', function () { 114 | const isVisible = viewport.isVisible({ 115 | getBoundingClientRect() { 116 | return { 117 | bottom: 232, 118 | top: 6000, 119 | }; 120 | }, 121 | }); 122 | assert(typeof isVisible === 'boolean'); 123 | assert(isVisible === false); 124 | }); 125 | }); 126 | -------------------------------------------------------------------------------- /dist/viewport.min.js: -------------------------------------------------------------------------------- 1 | (function(t){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=t()}else if(typeof define==="function"&&define.amd){define([],t)}else{var e;if(typeof window!=="undefined"){e=window}else if(typeof global!=="undefined"){e=global}else if(typeof self!=="undefined"){e=self}else{e=this}e.viewport=t()}})(function(){var t,e,i;return function t(e,i,n){function o(s,l){if(!i[s]){if(!e[s]){var c=typeof require=="function"&&require;if(!l&&c)return c(s,!0);if(r)return r(s,!0);var h=new Error("Cannot find module '"+s+"'");throw h.code="MODULE_NOT_FOUND",h}var f=i[s]={exports:{}};e[s][0].call(f.exports,function(t){var i=e[s][1][t];return o(i?i:t)},f,f.exports,t,e,i,n)}return i[s].exports}var r=typeof require=="function"&&require;for(var s=0;s=s.body.scrollHeight){this.emit("bottom")}return this};c.prototype.calculateOffset=function t(){this.top=this.scrollY;this.right=this.scrollX+this.width;this.bottom=this.scrollY+this.height;this.left=this.scrollX;return this};c.prototype.calculateOrientation=function t(){this.device.orientation=r.screen.orientation.type;return this};c.prototype.inViewport=function t(e){var i=e.getBoundingClientRect();return i.top>=0&&i.right<=this.width&&i.bottom<=this.height&&i.left>=0};c.prototype.isVisible=function t(e){var i=e.getBoundingClientRect();return i.bottom>=0&&i.top<=this.height};e.exports=new c},{decouple:2,jvent:3}],2:[function(t,e,i){"use strict";var n=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}();function o(t,e,i){var o,r=false;function s(t){o=t;l()}function l(){if(!r){n(c);r=true}}function c(){i.call(t,o);r=false}t.addEventListener(e,s,false);return s}e.exports=o},{}],3:[function(t,e,i){"use strict";function n(){}n.prototype.on=function(t,e){this._collection=this._collection||{};this._collection[t]=this._collection[t]||[];this._collection[t].push(e);return this};n.prototype.once=function(t,e){var i=this;function n(){i.off(t,n);e.apply(this,arguments)}n.listener=e;this.on(t,n);return this};n.prototype.off=function(t,e){var i=this._collection&&this._collection[t],n=0;if(i!==undefined){for(n;n 13 | ``` 14 | 15 | ## Usage 16 | First, add the following meta viewport: 17 | ```html 18 | 19 | ``` 20 | Then, initialize the Viewport: 21 | ```js 22 | var viewport = require('viewport'); 23 | ``` 24 | Now, starts to use it! 25 | ```js 26 | viewport.height // Returns the current height of the viewport. (Read below the API) 27 | ``` 28 | 29 | ## Browser Support 30 | - Chrome (OS X, Windows) 31 | - Firefox (OS X, Windows) 32 | - Opera (OS X, Windows) 33 | - Safari (OS X, Windows) 34 | - IE10+ 35 | 36 | ## API 37 | 38 | ### Viewport#width 39 | Returns the current `width` of viewport (in pixels). 40 | 41 | ### Viewport#height 42 | Returns the current `height` of viewport (in pixels). 43 | 44 | ### Viewport#calculateDimensions() 45 | Calculates/updates the dimensions (`width` and `height`) of viewport (in pixels). 46 | 47 | ### Viewport#top 48 | Returns offset `top` of viewport. 49 | 50 | ### Viewport#right 51 | Returns offset `right` of viewport. 52 | 53 | ### Viewport#bottom 54 | Returns offset `bottom` of viewport. 55 | 56 | ### Viewport#left 57 | Returns offset `left` of viewport. 58 | 59 | ### Viewport#calculateOffset() 60 | Calculates/updates the viewport position. 61 | 62 | ### Viewport#scrollY 63 | Returns vertical scroll position of viewport. 64 | 65 | ### Viewport#scrollX 66 | Returns horizontal scroll position of viewport. 67 | 68 | ### Viewport#calculateScroll() 69 | Calculates/updates the scroll positions (`scrollY` and `scrollX`) of viewport. 70 | 71 | ### Viewport#orientation 72 | Returns the device orientation: `portrait-primary`, `portrait-secondary`, `landscape-primary`, `landscape-secondary`. 73 | 74 | ### Viewport#calculateOrientation() 75 | Calculates/updates the device `orientation`. 76 | 77 | ### Viewport#device 78 | Device size is static and doesn't change when the page is resized. Returns an object with size of device (`width` and `height`). 79 | 80 | ### Viewport#inViewport() 81 | Calculate if an element is completely located in the viewport. Returns boolean. 82 | 83 | ### Viewport#isVisible() 84 | Calculates if an element is visible in the viewport. Returns boolean. 85 | 86 | ### Viewport#refresh() 87 | Updates the viewport dimension, viewport positions and orientation. 88 | 89 | ### Events 90 | - `scroll`: emitted when the viewport are scrolled. 91 | - `resize`: emitted when the dimensions of the viewport changes. 92 | - `bottom`: emitted when the viewport position is the bottom. 93 | - `top`: emitted when the viewport position is the top. 94 | 95 | ## With :heart: by 96 | 97 | - Guille Paz (Frontend developer | Web standards lover) 98 | - E-mail: [guille87paz@gmail.com](mailto:guille87paz@gmail.com) 99 | - Twitter: [@pazguille](http://twitter.com/pazguille) 100 | - Web: [https://pazguille.me](https://pazguille.me) 101 | 102 | ## License 103 | 104 | MIT license. Copyright © 2016. 105 | 106 | [npm-image]: https://img.shields.io/npm/v/horwheel.svg 107 | [lic-image]: https://img.shields.io/npm/l/horwheel.svg 108 | [npm-link]: https://npmjs.org/package/horwheel 109 | [deps-image]: https://img.shields.io/david/pazguille/horwheel.svg 110 | [deps-link]: https://david-dm.org/pazguille/horwheel 111 | [devdeps-image]: https://img.shields.io/david/dev/pazguille/horwheel.svg 112 | [devdeps-link]: https://david-dm.org/pazguille/horwheel#info=devDependencies 113 | [dt-image]: https://img.shields.io/npm/dt/horwheel.svg 114 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var Jvent = require('jvent'); 5 | var decouple = require('decouple'); 6 | 7 | /** 8 | * Scope variables 9 | */ 10 | var win = window; 11 | var doc = win.document; 12 | var docEl = doc.documentElement; 13 | 14 | /** 15 | * Viewport class 16 | */ 17 | function Viewport() { 18 | this.calculateDeviceDimensions(); 19 | this.refresh(); 20 | decouple(window, 'scroll', this.eventHandler.bind(this)); 21 | decouple(window, 'resize', this.eventHandler.bind(this)); 22 | return this; 23 | } 24 | 25 | /** 26 | * Inherit from an Event Emitter 27 | */ 28 | Viewport.prototype = new Jvent(); 29 | 30 | /** 31 | * Event handler for resize and scroll events. 32 | */ 33 | Viewport.prototype.eventHandler = function eventHandler(eve) { 34 | // // Updates viewport 35 | this.refresh(); 36 | // // Emits the current event 37 | this.emit(eve.type); 38 | }; 39 | 40 | /** 41 | * Updates the viewport dimension, viewport positions and orientation. 42 | */ 43 | Viewport.prototype.refresh = function refresh() { 44 | this.calculateDimensions(); 45 | this.calculateScroll(); 46 | this.calculateOffset(); 47 | this.calculateOrientation(); 48 | return this; 49 | }; 50 | 51 | /** 52 | * Calculates device size. 53 | * The size is static and does not change when the page is resized. 54 | * Returns an object with size of device (`width` and `height`). 55 | */ 56 | Viewport.prototype.calculateDeviceDimensions = function calculateDeviceDimensions() { 57 | this.device = {}; 58 | this.device.height = win.screen.height; 59 | this.device.width = win.screen.width; 60 | this.device.orientation = win.screen.orientation.type; 61 | return this; 62 | }; 63 | 64 | /** 65 | * Calculates/updates the dimensions (`width` and `height`) of viewport (in pixels). 66 | */ 67 | Viewport.prototype.calculateDimensions = function calculateDimensions() { 68 | this.height = docEl.clientHeight; 69 | this.width = docEl.clientWidth; 70 | return this; 71 | }; 72 | 73 | /** 74 | * Calculates/updates the scroll positions (`scrollY` and `scrollX`) of viewport. 75 | */ 76 | Viewport.prototype.calculateScroll = function calculateScroll() { 77 | var cachedTop = this.scrollY; 78 | var cachedBottom = this.height + cachedTop; 79 | var bottom; 80 | 81 | this.scrollY = win.pageYOffset; 82 | this.scrollX = win.pageXOffset; 83 | bottom = this.height + this.scrollY; 84 | 85 | if (cachedTop !== this.scrollY && this.scrollY === 0) { 86 | this.emit('top'); 87 | } else if (cachedBottom !== bottom && bottom >= doc.body.scrollHeight) { 88 | this.emit('bottom'); 89 | } 90 | return this; 91 | }; 92 | 93 | /** 94 | * Calculates/updates the viewport position. 95 | */ 96 | Viewport.prototype.calculateOffset = function calculateOffset() { 97 | this.top = this.scrollY; 98 | this.right = this.scrollX + this.width; 99 | this.bottom = this.scrollY + this.height; 100 | this.left = this.scrollX; 101 | return this; 102 | }; 103 | 104 | /** 105 | * Calculates/updates the device `orientation`. 106 | * Returns the device orientation: `portrait-primary`, `portrait-secondary`, `landscape-primary`, `landscape-secondary`. 107 | */ 108 | Viewport.prototype.calculateOrientation = function calculateOrientation() { 109 | this.device.orientation = win.screen.orientation.type; 110 | return this; 111 | }; 112 | 113 | /** 114 | * Calculate if an element is completely located in the viewport. Returns boolean. 115 | */ 116 | Viewport.prototype.inViewport = function inViewport(el) { 117 | var r = el.getBoundingClientRect(); 118 | return (r.top >= 0) && (r.right <= this.width) 119 | && (r.bottom <= this.height) && (r.left >= 0); 120 | }; 121 | 122 | /** 123 | * Calculates if an element is visible in the viewport. Returns boolean. 124 | */ 125 | Viewport.prototype.isVisible = function isVisible(el) { 126 | var r = el.getBoundingClientRect(); 127 | return (r.bottom >= 0 && r.top <= this.height); 128 | }; 129 | 130 | /** 131 | * Expose Viewport instance 132 | */ 133 | module.exports = new Viewport(); 134 | -------------------------------------------------------------------------------- /dist/viewport.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["./dist/viewport.js"],"names":["f","exports","module","define","amd","g","window","global","self","this","viewport","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length","1","Jvent","decouple","win","doc","document","docEl","documentElement","Viewport","calculateDeviceDimensions","refresh","eventHandler","bind","prototype","eve","emit","type","calculateDimensions","calculateScroll","calculateOffset","calculateOrientation","device","height","screen","width","orientation","clientHeight","clientWidth","cachedTop","scrollY","cachedBottom","bottom","pageYOffset","scrollX","pageXOffset","body","scrollHeight","top","right","left","inViewport","el","getBoundingClientRect","isVisible","jvent","2","requestAnimFrame","requestAnimationFrame","webkitRequestAnimationFrame","callback","setTimeout","node","event","fn","tracking","captureEvent","track","update","addEventListener","3","on","listener","_collection","push","once","that","off","apply","arguments","listeners","j","undefined","splice","removeAllListeners","args","slice","shift","len"],"mappings":"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","file":"./dist/viewport.min.js"} -------------------------------------------------------------------------------- /dist/viewport.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.viewport = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= doc.body.scrollHeight) { 89 | this.emit('bottom'); 90 | } 91 | return this; 92 | }; 93 | 94 | /** 95 | * Calculates/updates the viewport position. 96 | */ 97 | Viewport.prototype.calculateOffset = function calculateOffset() { 98 | this.top = this.scrollY; 99 | this.right = this.scrollX + this.width; 100 | this.bottom = this.scrollY + this.height; 101 | this.left = this.scrollX; 102 | return this; 103 | }; 104 | 105 | /** 106 | * Calculates/updates the device `orientation`. 107 | * Returns the device orientation: `portrait-primary`, `portrait-secondary`, `landscape-primary`, `landscape-secondary`. 108 | */ 109 | Viewport.prototype.calculateOrientation = function calculateOrientation() { 110 | this.device.orientation = win.screen.orientation.type; 111 | return this; 112 | }; 113 | 114 | /** 115 | * Calculate if an element is completely located in the viewport. Returns boolean. 116 | */ 117 | Viewport.prototype.inViewport = function inViewport(el) { 118 | var r = el.getBoundingClientRect(); 119 | return (r.top >= 0) && (r.right <= this.width) 120 | && (r.bottom <= this.height) && (r.left >= 0); 121 | }; 122 | 123 | /** 124 | * Calculates if an element is visible in the viewport. Returns boolean. 125 | */ 126 | Viewport.prototype.isVisible = function isVisible(el) { 127 | var r = el.getBoundingClientRect(); 128 | return (r.bottom >= 0 && r.top <= this.height); 129 | }; 130 | 131 | /** 132 | * Expose Viewport instance 133 | */ 134 | module.exports = new Viewport(); 135 | 136 | },{"decouple":2,"jvent":3}],2:[function(require,module,exports){ 137 | 'use strict'; 138 | 139 | var requestAnimFrame = (function() { 140 | return window.requestAnimationFrame || 141 | window.webkitRequestAnimationFrame || 142 | function (callback) { 143 | window.setTimeout(callback, 1000 / 60); 144 | }; 145 | }()); 146 | 147 | function decouple(node, event, fn) { 148 | var eve, 149 | tracking = false; 150 | 151 | function captureEvent(e) { 152 | eve = e; 153 | track(); 154 | } 155 | 156 | function track() { 157 | if (!tracking) { 158 | requestAnimFrame(update); 159 | tracking = true; 160 | } 161 | } 162 | 163 | function update() { 164 | fn.call(node, eve); 165 | tracking = false; 166 | } 167 | 168 | node.addEventListener(event, captureEvent, false); 169 | 170 | return captureEvent; 171 | } 172 | 173 | /** 174 | * Expose decouple 175 | */ 176 | module.exports = decouple; 177 | 178 | },{}],3:[function(require,module,exports){ 179 | 'use strict'; 180 | 181 | function Jvent() {} 182 | 183 | /** 184 | * Adds a listener to the collection for a specified event. 185 | * @public 186 | * @function 187 | * @name Jvent#on 188 | * @param {string} event Event name. 189 | * @param {function} listener Listener function. 190 | * @example 191 | * // Will add a event listener to the "ready" event 192 | * var startDoingStuff = function (event, param1, param2, ...) { 193 | * // Some code here! 194 | * }; 195 | * 196 | * me.on("ready", startDoingStuff); 197 | */ 198 | Jvent.prototype.on = function(event, listener) { 199 | this._collection = this._collection || {}; 200 | this._collection[event] = this._collection[event] || []; 201 | this._collection[event].push(listener); 202 | return this; 203 | }; 204 | 205 | /** 206 | * Adds a one time listener to the collection for a specified event. It will execute only once. 207 | * @public 208 | * @function 209 | * @name Jvent#once 210 | * @param {string} event Event name. 211 | * @param {function} listener Listener function. 212 | * @returns itself 213 | * @example 214 | * // Will add a event handler to the "contentLoad" event once 215 | * me.once("contentLoad", startDoingStuff); 216 | */ 217 | Jvent.prototype.once = function (event, listener) { 218 | var that = this; 219 | 220 | function fn() { 221 | that.off(event, fn); 222 | listener.apply(this, arguments); 223 | } 224 | 225 | fn.listener = listener; 226 | 227 | this.on(event, fn); 228 | 229 | return this; 230 | }; 231 | 232 | /** 233 | * Removes a listener from the collection for a specified event. 234 | * @public 235 | * @function 236 | * @name Jvent#off 237 | * @param {string} event Event name. 238 | * @param {function} listener Listener function. 239 | * @returns itself 240 | * @example 241 | * // Will remove event handler to the "ready" event 242 | * var startDoingStuff = function () { 243 | * // Some code here! 244 | * }; 245 | * 246 | * me.off("ready", startDoingStuff); 247 | */ 248 | Jvent.prototype.off = function (event, listener) { 249 | 250 | var listeners = this._collection && this._collection[event], 251 | j = 0; 252 | 253 | if (listeners !== undefined) { 254 | for (j; j < listeners.length; j += 1) { 255 | if (listeners[j] === listener || listeners[j].listener === listener) { 256 | listeners.splice(j, 1); 257 | break; 258 | } 259 | } 260 | 261 | if (listeners.length === 0) { 262 | this.removeAllListeners(event); 263 | } 264 | } 265 | 266 | return this; 267 | }; 268 | 269 | /** 270 | * Removes all listeners from the collection for a specified event. 271 | * @public 272 | * @function 273 | * @name Jvent#removeAllListeners 274 | * @param {string} event Event name. 275 | * @returns itself 276 | * @example 277 | * me.removeAllListeners("ready"); 278 | */ 279 | Jvent.prototype.removeAllListeners = function (event) { 280 | this._collection = this._collection || {}; 281 | delete this._collection[event]; 282 | return this; 283 | }; 284 | 285 | /** 286 | * Returns all listeners from the collection for a specified event. 287 | * @public 288 | * @function 289 | * @name Jvent#listeners 290 | * @param {string} event Event name. 291 | * @returns Array 292 | * @example 293 | * me.listeners("ready"); 294 | */ 295 | Jvent.prototype.listeners = function (event) { 296 | this._collection = this._collection || {}; 297 | return this._collection[event]; 298 | }; 299 | 300 | /** 301 | * Execute each item in the listener collection in order with the specified data. 302 | * @name Jvent#emit 303 | * @public 304 | * @protected 305 | * @param {string} event The name of the event you want to emit. 306 | * @param {...object} var_args Data to pass to the listeners. 307 | * @example 308 | * // Will emit the "ready" event with "param1" and "param2" as arguments. 309 | * me.emit("ready", "param1", "param2"); 310 | */ 311 | Jvent.prototype.emit = function () { 312 | if (this._collection === undefined) { 313 | return this; 314 | } 315 | 316 | var args = [].slice.call(arguments, 0), // converted to array 317 | event = args.shift(), 318 | listeners = this._collection[event], 319 | i = 0, 320 | len; 321 | 322 | if (listeners) { 323 | listeners = listeners.slice(0); 324 | len = listeners.length; 325 | for (i; i < len; i += 1) { 326 | listeners[i].apply(this, args); 327 | } 328 | } 329 | 330 | return this; 331 | }; 332 | 333 | /** 334 | * Expose Jvent 335 | */ 336 | module.exports = Jvent; 337 | 338 | },{}]},{},[1])(1) 339 | }); --------------------------------------------------------------------------------