├── 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 | });
--------------------------------------------------------------------------------