├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── crossvent.js └── crossvent.min.js ├── gulpfile.js ├── package.json └── src ├── crossvent.js └── eventmap.js /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "newcap": true, 5 | "noarg": true, 6 | "noempty": true, 7 | "nonew": true, 8 | "sub": true, 9 | "validthis": true, 10 | "undef": true, 11 | "trailing": true, 12 | "boss": true, 13 | "eqnull": true, 14 | "strict": true, 15 | "immed": true, 16 | "expr": true, 17 | "latedef": "nofunc", 18 | "quotmark": "single", 19 | "indent": 2, 20 | "node": true, 21 | "browser": true 22 | } 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.5.4 Mortal Kombat 3 2 | 3 | - Crossvent now ignores API limitations on the server-side, instead of throwing 4 | 5 | # v1.5.2 Fix Up 6 | 7 | - Fixed a bug in IE8 where attempting to remove an undefined event listener would throw 8 | 9 | # v1.5.1 Power Up 10 | 11 | - Crossvent now exports an empty API on the server-side, instead of throwing 12 | 13 | # v1.5.0 Classic Poets 14 | 15 | - Fall back to classic events for non-made-up event types 16 | 17 | # v1.4.0 Fabricator 18 | 19 | - Added optional custom event model for `.fabricate` 20 | 21 | # v1.3.2 Ice Bug 22 | 23 | - `e.which` gets normalized across browsers, `e.keyCode` is used if not present 24 | 25 | # v1.3.1 Fire Bug 26 | 27 | - Use `fireEvent` and `createEventObject` when their modern counterparts are missing 28 | 29 | # v1.2.0 Flag The Bug 30 | 31 | - Added ability to use a `capture` parameter in event removal as well 32 | 33 | # v1.1.0 Capture The Flag 34 | 35 | - Added ability to use a `capture` parameter 36 | 37 | # v1.0.0 IPO 38 | 39 | - Initial Public Release 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2014 Nicolas Bevacqua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crossvent 2 | 3 | > Cross-platform browser event handling 4 | 5 | The event handler API used by [dominus][1]. 6 | 7 | # Install 8 | 9 | Using Bower 10 | 11 | ```shell 12 | bower install -S crossvent 13 | ``` 14 | 15 | Using `npm` 16 | 17 | ```shell 18 | npm install -S crossvent 19 | ``` 20 | 21 | # API 22 | 23 | The API exposes a few methods that let you deal with event handling in a consistent manner across browsers. 24 | 25 | ### `crossvent.add(el, type, fn, capturing?)` 26 | 27 | Adds an event listener `fn` of type `type` to DOM element `el`. 28 | 29 | ```js 30 | crossvent.add(document.body, 'click', function (e) { 31 | console.log('clicked document body'); 32 | }); 33 | ``` 34 | 35 | ### `crossvent.remove(el, type, fn, capturing?)` 36 | 37 | Removes an event listener `fn` of type `type` from DOM element `el`. 38 | 39 | ```js 40 | crossvent.add(document.body, 'click', clicked); 41 | crossvent.remove(document.body, 'click', clicked); 42 | 43 | function clicked (e) { 44 | console.log('clicked document body'); 45 | } 46 | ``` 47 | 48 | ### `crossvent.fabricate(el, type, model?)` 49 | 50 | Creates a synthetic custom event of type `type` and dispatches it on `el`. You can provide a custom `model` which will be accessible as `e.detail`. 51 | 52 | ```js 53 | crossvent.add(document.body, 'sugar', sugary); 54 | crossvent.fabricate(document.body, 'sugar', { onTop: true }); 55 | 56 | function sugary (e) { 57 | console.log('synthetic sugar' + e.detail.onTop ? ' on top' : ''); 58 | } 59 | ``` 60 | 61 | # License 62 | 63 | MIT 64 | 65 | [1]: https://github.com/bevacqua/dominus 66 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crossvent", 3 | "description": "Cross-platform browser event handling", 4 | "version": "1.5.4", 5 | "homepage": "https://github.com/bevacqua/crossvent", 6 | "author": { 7 | "name": "Nicolas Bevacqua", 8 | "email": "hello@bevacqua.io", 9 | "url": "http://bevacqua.io" 10 | }, 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/bevacqua/crossvent.git" 15 | }, 16 | "main": "dist/crossvent.js", 17 | "ignore": [ 18 | ".*", 19 | "package.json", 20 | "node_modules", 21 | "src", 22 | "test", 23 | "gulpfile.js" 24 | ], 25 | "dependencies": {} 26 | } 27 | -------------------------------------------------------------------------------- /dist/crossvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * crossvent - Cross-platform browser event handling 3 | * @version v1.5.4 4 | * @link https://github.com/bevacqua/crossvent 5 | * @license MIT 6 | */ 7 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.crossvent=e()}}(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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 9 32 | 'function' === typeof document.createEvent ? function CustomEvent (type, params) { 33 | var e = document.createEvent('CustomEvent'); 34 | if (params) { 35 | e.initCustomEvent(type, params.bubbles, params.cancelable, params.detail); 36 | } else { 37 | e.initCustomEvent(type, false, false, void 0); 38 | } 39 | return e; 40 | } : 41 | 42 | // IE <= 8 43 | function CustomEvent (type, params) { 44 | var e = document.createEventObject(); 45 | e.type = type; 46 | if (params) { 47 | e.bubbles = Boolean(params.bubbles); 48 | e.cancelable = Boolean(params.cancelable); 49 | e.detail = params.detail; 50 | } else { 51 | e.bubbles = false; 52 | e.cancelable = false; 53 | e.detail = void 0; 54 | } 55 | return e; 56 | } 57 | 58 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 59 | },{}],2:[function(_dereq_,module,exports){ 60 | (function (global){ 61 | 'use strict'; 62 | 63 | var customEvent = _dereq_('custom-event'); 64 | var eventmap = _dereq_('./eventmap'); 65 | var doc = global.document; 66 | var addEvent = addEventEasy; 67 | var removeEvent = removeEventEasy; 68 | var hardCache = []; 69 | 70 | if (!global.addEventListener) { 71 | addEvent = addEventHard; 72 | removeEvent = removeEventHard; 73 | } 74 | 75 | module.exports = { 76 | add: addEvent, 77 | remove: removeEvent, 78 | fabricate: fabricateEvent 79 | }; 80 | 81 | function addEventEasy (el, type, fn, capturing) { 82 | return el.addEventListener(type, fn, capturing); 83 | } 84 | 85 | function addEventHard (el, type, fn) { 86 | return el.attachEvent('on' + type, wrap(el, type, fn)); 87 | } 88 | 89 | function removeEventEasy (el, type, fn, capturing) { 90 | return el.removeEventListener(type, fn, capturing); 91 | } 92 | 93 | function removeEventHard (el, type, fn) { 94 | var listener = unwrap(el, type, fn); 95 | if (listener) { 96 | return el.detachEvent('on' + type, listener); 97 | } 98 | } 99 | 100 | function fabricateEvent (el, type, model) { 101 | var e = eventmap.indexOf(type) === -1 ? makeCustomEvent() : makeClassicEvent(); 102 | if (el.dispatchEvent) { 103 | el.dispatchEvent(e); 104 | } else { 105 | el.fireEvent('on' + type, e); 106 | } 107 | function makeClassicEvent () { 108 | var e; 109 | if (doc.createEvent) { 110 | e = doc.createEvent('Event'); 111 | e.initEvent(type, true, true); 112 | } else if (doc.createEventObject) { 113 | e = doc.createEventObject(); 114 | } 115 | return e; 116 | } 117 | function makeCustomEvent () { 118 | return new customEvent(type, { detail: model }); 119 | } 120 | } 121 | 122 | function wrapperFactory (el, type, fn) { 123 | return function wrapper (originalEvent) { 124 | var e = originalEvent || global.event; 125 | e.target = e.target || e.srcElement; 126 | e.preventDefault = e.preventDefault || function preventDefault () { e.returnValue = false; }; 127 | e.stopPropagation = e.stopPropagation || function stopPropagation () { e.cancelBubble = true; }; 128 | e.which = e.which || e.keyCode; 129 | fn.call(el, e); 130 | }; 131 | } 132 | 133 | function wrap (el, type, fn) { 134 | var wrapper = unwrap(el, type, fn) || wrapperFactory(el, type, fn); 135 | hardCache.push({ 136 | wrapper: wrapper, 137 | element: el, 138 | type: type, 139 | fn: fn 140 | }); 141 | return wrapper; 142 | } 143 | 144 | function unwrap (el, type, fn) { 145 | var i = find(el, type, fn); 146 | if (i) { 147 | var wrapper = hardCache[i].wrapper; 148 | hardCache.splice(i, 1); // free up a tad of memory 149 | return wrapper; 150 | } 151 | } 152 | 153 | function find (el, type, fn) { 154 | var i, item; 155 | for (i = 0; i < hardCache.length; i++) { 156 | item = hardCache[i]; 157 | if (item.element === el && item.type === type && item.fn === fn) { 158 | return i; 159 | } 160 | } 161 | } 162 | 163 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 164 | },{"./eventmap":3,"custom-event":1}],3:[function(_dereq_,module,exports){ 165 | (function (global){ 166 | 'use strict'; 167 | 168 | var eventmap = []; 169 | var eventname = ''; 170 | var ron = /^on/; 171 | 172 | for (eventname in global) { 173 | if (ron.test(eventname)) { 174 | eventmap.push(eventname.slice(2)); 175 | } 176 | } 177 | 178 | module.exports = eventmap; 179 | 180 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 181 | },{}]},{},[2]) 182 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaWNvL2Rldi9jcm9zc3ZlbnQvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi9Vc2Vycy9uaWNvL2Rldi9jcm9zc3ZlbnQvbm9kZV9tb2R1bGVzL2N1c3RvbS1ldmVudC9pbmRleC5qcyIsIi9Vc2Vycy9uaWNvL2Rldi9jcm9zc3ZlbnQvc3JjL2Nyb3NzdmVudC5qcyIsIi9Vc2Vycy9uaWNvL2Rldi9jcm9zc3ZlbnQvc3JjL2V2ZW50bWFwLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpfXZhciBmPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChmLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGYsZi5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIoZnVuY3Rpb24gKGdsb2JhbCl7XG5cbnZhciBOYXRpdmVDdXN0b21FdmVudCA9IGdsb2JhbC5DdXN0b21FdmVudDtcblxuZnVuY3Rpb24gdXNlTmF0aXZlICgpIHtcbiAgdHJ5IHtcbiAgICB2YXIgcCA9IG5ldyBOYXRpdmVDdXN0b21FdmVudCgnY2F0JywgeyBkZXRhaWw6IHsgZm9vOiAnYmFyJyB9IH0pO1xuICAgIHJldHVybiAgJ2NhdCcgPT09IHAudHlwZSAmJiAnYmFyJyA9PT0gcC5kZXRhaWwuZm9vO1xuICB9IGNhdGNoIChlKSB7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIENyb3NzLWJyb3dzZXIgYEN1c3RvbUV2ZW50YCBjb25zdHJ1Y3Rvci5cbiAqXG4gKiBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvQ3VzdG9tRXZlbnQuQ3VzdG9tRXZlbnRcbiAqXG4gKiBAcHVibGljXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSB1c2VOYXRpdmUoKSA/IE5hdGl2ZUN1c3RvbUV2ZW50IDpcblxuLy8gSUUgPj0gOVxuJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mIGRvY3VtZW50LmNyZWF0ZUV2ZW50ID8gZnVuY3Rpb24gQ3VzdG9tRXZlbnQgKHR5cGUsIHBhcmFtcykge1xuICB2YXIgZSA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KCdDdXN0b21FdmVudCcpO1xuICBpZiAocGFyYW1zKSB7XG4gICAgZS5pbml0Q3VzdG9tRXZlbnQodHlwZSwgcGFyYW1zLmJ1YmJsZXMsIHBhcmFtcy5jYW5jZWxhYmxlLCBwYXJhbXMuZGV0YWlsKTtcbiAgfSBlbHNlIHtcbiAgICBlLmluaXRDdXN0b21FdmVudCh0eXBlLCBmYWxzZSwgZmFsc2UsIHZvaWQgMCk7XG4gIH1cbiAgcmV0dXJuIGU7XG59IDpcblxuLy8gSUUgPD0gOFxuZnVuY3Rpb24gQ3VzdG9tRXZlbnQgKHR5cGUsIHBhcmFtcykge1xuICB2YXIgZSA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50T2JqZWN0KCk7XG4gIGUudHlwZSA9IHR5cGU7XG4gIGlmIChwYXJhbXMpIHtcbiAgICBlLmJ1YmJsZXMgPSBCb29sZWFuKHBhcmFtcy5idWJibGVzKTtcbiAgICBlLmNhbmNlbGFibGUgPSBCb29sZWFuKHBhcmFtcy5jYW5jZWxhYmxlKTtcbiAgICBlLmRldGFpbCA9IHBhcmFtcy5kZXRhaWw7XG4gIH0gZWxzZSB7XG4gICAgZS5idWJibGVzID0gZmFsc2U7XG4gICAgZS5jYW5jZWxhYmxlID0gZmFsc2U7XG4gICAgZS5kZXRhaWwgPSB2b2lkIDA7XG4gIH1cbiAgcmV0dXJuIGU7XG59XG5cbn0pLmNhbGwodGhpcyx0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYgOiB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93IDoge30pIiwiKGZ1bmN0aW9uIChnbG9iYWwpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgY3VzdG9tRXZlbnQgPSByZXF1aXJlKCdjdXN0b20tZXZlbnQnKTtcbnZhciBldmVudG1hcCA9IHJlcXVpcmUoJy4vZXZlbnRtYXAnKTtcbnZhciBkb2MgPSBnbG9iYWwuZG9jdW1lbnQ7XG52YXIgYWRkRXZlbnQgPSBhZGRFdmVudEVhc3k7XG52YXIgcmVtb3ZlRXZlbnQgPSByZW1vdmVFdmVudEVhc3k7XG52YXIgaGFyZENhY2hlID0gW107XG5cbmlmICghZ2xvYmFsLmFkZEV2ZW50TGlzdGVuZXIpIHtcbiAgYWRkRXZlbnQgPSBhZGRFdmVudEhhcmQ7XG4gIHJlbW92ZUV2ZW50ID0gcmVtb3ZlRXZlbnRIYXJkO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgYWRkOiBhZGRFdmVudCxcbiAgcmVtb3ZlOiByZW1vdmVFdmVudCxcbiAgZmFicmljYXRlOiBmYWJyaWNhdGVFdmVudFxufTtcblxuZnVuY3Rpb24gYWRkRXZlbnRFYXN5IChlbCwgdHlwZSwgZm4sIGNhcHR1cmluZykge1xuICByZXR1cm4gZWwuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBmbiwgY2FwdHVyaW5nKTtcbn1cblxuZnVuY3Rpb24gYWRkRXZlbnRIYXJkIChlbCwgdHlwZSwgZm4pIHtcbiAgcmV0dXJuIGVsLmF0dGFjaEV2ZW50KCdvbicgKyB0eXBlLCB3cmFwKGVsLCB0eXBlLCBmbikpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVFdmVudEVhc3kgKGVsLCB0eXBlLCBmbiwgY2FwdHVyaW5nKSB7XG4gIHJldHVybiBlbC5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGZuLCBjYXB0dXJpbmcpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVFdmVudEhhcmQgKGVsLCB0eXBlLCBmbikge1xuICB2YXIgbGlzdGVuZXIgPSB1bndyYXAoZWwsIHR5cGUsIGZuKTtcbiAgaWYgKGxpc3RlbmVyKSB7XG4gICAgcmV0dXJuIGVsLmRldGFjaEV2ZW50KCdvbicgKyB0eXBlLCBsaXN0ZW5lcik7XG4gIH1cbn1cblxuZnVuY3Rpb24gZmFicmljYXRlRXZlbnQgKGVsLCB0eXBlLCBtb2RlbCkge1xuICB2YXIgZSA9IGV2ZW50bWFwLmluZGV4T2YodHlwZSkgPT09IC0xID8gbWFrZUN1c3RvbUV2ZW50KCkgOiBtYWtlQ2xhc3NpY0V2ZW50KCk7XG4gIGlmIChlbC5kaXNwYXRjaEV2ZW50KSB7XG4gICAgZWwuZGlzcGF0Y2hFdmVudChlKTtcbiAgfSBlbHNlIHtcbiAgICBlbC5maXJlRXZlbnQoJ29uJyArIHR5cGUsIGUpO1xuICB9XG4gIGZ1bmN0aW9uIG1ha2VDbGFzc2ljRXZlbnQgKCkge1xuICAgIHZhciBlO1xuICAgIGlmIChkb2MuY3JlYXRlRXZlbnQpIHtcbiAgICAgIGUgPSBkb2MuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XG4gICAgICBlLmluaXRFdmVudCh0eXBlLCB0cnVlLCB0cnVlKTtcbiAgICB9IGVsc2UgaWYgKGRvYy5jcmVhdGVFdmVudE9iamVjdCkge1xuICAgICAgZSA9IGRvYy5jcmVhdGVFdmVudE9iamVjdCgpO1xuICAgIH1cbiAgICByZXR1cm4gZTtcbiAgfVxuICBmdW5jdGlvbiBtYWtlQ3VzdG9tRXZlbnQgKCkge1xuICAgIHJldHVybiBuZXcgY3VzdG9tRXZlbnQodHlwZSwgeyBkZXRhaWw6IG1vZGVsIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIHdyYXBwZXJGYWN0b3J5IChlbCwgdHlwZSwgZm4pIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIHdyYXBwZXIgKG9yaWdpbmFsRXZlbnQpIHtcbiAgICB2YXIgZSA9IG9yaWdpbmFsRXZlbnQgfHwgZ2xvYmFsLmV2ZW50O1xuICAgIGUudGFyZ2V0ID0gZS50YXJnZXQgfHwgZS5zcmNFbGVtZW50O1xuICAgIGUucHJldmVudERlZmF1bHQgPSBlLnByZXZlbnREZWZhdWx0IHx8IGZ1bmN0aW9uIHByZXZlbnREZWZhdWx0ICgpIHsgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlOyB9O1xuICAgIGUuc3RvcFByb3BhZ2F0aW9uID0gZS5zdG9wUHJvcGFnYXRpb24gfHwgZnVuY3Rpb24gc3RvcFByb3BhZ2F0aW9uICgpIHsgZS5jYW5jZWxCdWJibGUgPSB0cnVlOyB9O1xuICAgIGUud2hpY2ggPSBlLndoaWNoIHx8IGUua2V5Q29kZTtcbiAgICBmbi5jYWxsKGVsLCBlKTtcbiAgfTtcbn1cblxuZnVuY3Rpb24gd3JhcCAoZWwsIHR5cGUsIGZuKSB7XG4gIHZhciB3cmFwcGVyID0gdW53cmFwKGVsLCB0eXBlLCBmbikgfHwgd3JhcHBlckZhY3RvcnkoZWwsIHR5cGUsIGZuKTtcbiAgaGFyZENhY2hlLnB1c2goe1xuICAgIHdyYXBwZXI6IHdyYXBwZXIsXG4gICAgZWxlbWVudDogZWwsXG4gICAgdHlwZTogdHlwZSxcbiAgICBmbjogZm5cbiAgfSk7XG4gIHJldHVybiB3cmFwcGVyO1xufVxuXG5mdW5jdGlvbiB1bndyYXAgKGVsLCB0eXBlLCBmbikge1xuICB2YXIgaSA9IGZpbmQoZWwsIHR5cGUsIGZuKTtcbiAgaWYgKGkpIHtcbiAgICB2YXIgd3JhcHBlciA9IGhhcmRDYWNoZVtpXS53cmFwcGVyO1xuICAgIGhhcmRDYWNoZS5zcGxpY2UoaSwgMSk7IC8vIGZyZWUgdXAgYSB0YWQgb2YgbWVtb3J5XG4gICAgcmV0dXJuIHdyYXBwZXI7XG4gIH1cbn1cblxuZnVuY3Rpb24gZmluZCAoZWwsIHR5cGUsIGZuKSB7XG4gIHZhciBpLCBpdGVtO1xuICBmb3IgKGkgPSAwOyBpIDwgaGFyZENhY2hlLmxlbmd0aDsgaSsrKSB7XG4gICAgaXRlbSA9IGhhcmRDYWNoZVtpXTtcbiAgICBpZiAoaXRlbS5lbGVtZW50ID09PSBlbCAmJiBpdGVtLnR5cGUgPT09IHR5cGUgJiYgaXRlbS5mbiA9PT0gZm4pIHtcbiAgICAgIHJldHVybiBpO1xuICAgIH1cbiAgfVxufVxuXG59KS5jYWxsKHRoaXMsdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCIgPyBzZWxmIDogdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHt9KSIsIihmdW5jdGlvbiAoZ2xvYmFsKXtcbid1c2Ugc3RyaWN0JztcblxudmFyIGV2ZW50bWFwID0gW107XG52YXIgZXZlbnRuYW1lID0gJyc7XG52YXIgcm9uID0gL15vbi87XG5cbmZvciAoZXZlbnRuYW1lIGluIGdsb2JhbCkge1xuICBpZiAocm9uLnRlc3QoZXZlbnRuYW1lKSkge1xuICAgIGV2ZW50bWFwLnB1c2goZXZlbnRuYW1lLnNsaWNlKDIpKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGV2ZW50bWFwO1xuXG59KS5jYWxsKHRoaXMsdHlwZW9mIHNlbGYgIT09IFwidW5kZWZpbmVkXCIgPyBzZWxmIDogdHlwZW9mIHdpbmRvdyAhPT0gXCJ1bmRlZmluZWRcIiA/IHdpbmRvdyA6IHt9KSJdfQ== 183 | (2) 184 | }); 185 | -------------------------------------------------------------------------------- /dist/crossvent.min.js: -------------------------------------------------------------------------------- 1 | // crossvent@v1.5.4, MIT licensed. https://github.com/bevacqua/crossvent 2 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.crossvent=e()}}(function(){return function e(n,t,r){function o(u,f){if(!t[u]){if(!n[u]){var a="function"==typeof require&&require;if(!f&&a)return a(u,!0);if(i)return i(u,!0);throw new Error("Cannot find module '"+u+"'")}var c=t[u]={exports:{}};n[u][0].call(c.exports,function(e){var t=n[u][1][e];return o(t?t:e)},c,c.exports,e,n,t,r)}return t[u].exports}for(var i="function"==typeof require&&require,u=0;u - <%= pkg.description %>', 23 | ' * @version v<%= pkg.version %>', 24 | ' * @link <%= pkg.homepage %>', 25 | ' * @license <%= pkg.license %>', 26 | ' */', 27 | '' 28 | ].join('\n'); 29 | 30 | var succint = '// <%= pkg.name %>@v<%= pkg.version %>, <%= pkg.license %> licensed. <%= pkg.homepage %>\n'; 31 | 32 | function build (done) { 33 | var pkg = require('./package.json'); 34 | 35 | browserify('./src/crossvent.js') 36 | .bundle({ debug: true, standalone: 'crossvent' }) 37 | .pipe(source('crossvent.js')) 38 | .pipe(streamify(header(extended, { pkg : pkg } ))) 39 | .pipe(gulp.dest('./dist')) 40 | .pipe(streamify(rename('crossvent.min.js'))) 41 | .pipe(streamify(uglify())) 42 | .pipe(streamify(header(succint, { pkg : pkg } ))) 43 | .pipe(streamify(size())) 44 | .pipe(gulp.dest('./dist')) 45 | .on('end', done); 46 | } 47 | 48 | function bumpOnly () { 49 | var bumpType = process.env.BUMP || 'patch'; // major.minor.patch 50 | 51 | return gulp.src(['./package.json', './bower.json']) 52 | .pipe(bump({ type: bumpType })) 53 | .pipe(gulp.dest('./')); 54 | } 55 | 56 | function tag () { 57 | var pkg = require('./package.json'); 58 | var v = 'v' + pkg.version; 59 | var message = 'Release ' + v; 60 | 61 | return gulp.src('./') 62 | .pipe(git.commit(message)) 63 | .pipe(git.tag(v, message)) 64 | .pipe(git.push('origin', 'master', '--tags')) 65 | .pipe(gulp.dest('./')); 66 | } 67 | 68 | function publish (done) { 69 | require('child_process').exec('npm publish', { stdio: 'inherit' }, done); 70 | } 71 | 72 | gulp.task('clean', function () { 73 | gulp.src('./dist', { read: false }) 74 | .pipe(clean()); 75 | }); 76 | 77 | gulp.task('build', ['clean'], build); 78 | gulp.task('bump', bumpOnly); 79 | gulp.task('bump-build', ['bump'], build); 80 | gulp.task('tag', ['bump-build'], tag); 81 | gulp.task('npm', publish); 82 | gulp.task('release', ['tag'], function () { 83 | gulp.start('npm'); 84 | }); 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crossvent", 3 | "description": "Cross-platform browser event handling", 4 | "version": "1.5.5", 5 | "homepage": "https://github.com/bevacqua/crossvent", 6 | "author": { 7 | "email": "hello@bevacqua.io", 8 | "name": "Nicolas Bevacqua", 9 | "url": "http://bevacqua.io" 10 | }, 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/bevacqua/crossvent.git" 15 | }, 16 | "main": "src/crossvent.js", 17 | "devDependencies": { 18 | "browserify": "^4.1.3", 19 | "contra": "^1.6.10", 20 | "gulp": "^3.6.2", 21 | "gulp-bump": "~0.1.0", 22 | "gulp-clean": "~0.2.3", 23 | "gulp-git": "~0.2.0", 24 | "gulp-header": "^1.0.2", 25 | "gulp-rename": "~0.2.2", 26 | "gulp-size": "~0.1.1", 27 | "gulp-streamify": "0.0.5", 28 | "gulp-uglify": "~0.1.0", 29 | "gzip-size": "^1.0.0", 30 | "jquery": "^1.11.1", 31 | "pretty-bytes": "^1.0.1", 32 | "vinyl-source-stream": "^0.1.1" 33 | }, 34 | "dependencies": { 35 | "custom-event": "^1.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/crossvent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var customEvent = require('custom-event'); 4 | var eventmap = require('./eventmap'); 5 | var doc = global.document; 6 | var addEvent = addEventEasy; 7 | var removeEvent = removeEventEasy; 8 | var hardCache = []; 9 | 10 | if (!global.addEventListener) { 11 | addEvent = addEventHard; 12 | removeEvent = removeEventHard; 13 | } 14 | 15 | module.exports = { 16 | add: addEvent, 17 | remove: removeEvent, 18 | fabricate: fabricateEvent 19 | }; 20 | 21 | function addEventEasy (el, type, fn, capturing) { 22 | return el.addEventListener(type, fn, capturing); 23 | } 24 | 25 | function addEventHard (el, type, fn) { 26 | return el.attachEvent('on' + type, wrap(el, type, fn)); 27 | } 28 | 29 | function removeEventEasy (el, type, fn, capturing) { 30 | return el.removeEventListener(type, fn, capturing); 31 | } 32 | 33 | function removeEventHard (el, type, fn) { 34 | var listener = unwrap(el, type, fn); 35 | if (listener) { 36 | return el.detachEvent('on' + type, listener); 37 | } 38 | } 39 | 40 | function fabricateEvent (el, type, model) { 41 | var e = eventmap.indexOf(type) === -1 ? makeCustomEvent() : makeClassicEvent(); 42 | if (el.dispatchEvent) { 43 | el.dispatchEvent(e); 44 | } else { 45 | el.fireEvent('on' + type, e); 46 | } 47 | function makeClassicEvent () { 48 | var e; 49 | if (doc.createEvent) { 50 | e = doc.createEvent('Event'); 51 | e.initEvent(type, true, true); 52 | } else if (doc.createEventObject) { 53 | e = doc.createEventObject(); 54 | } 55 | return e; 56 | } 57 | function makeCustomEvent () { 58 | return new customEvent(type, { detail: model }); 59 | } 60 | } 61 | 62 | function wrapperFactory (el, type, fn) { 63 | return function wrapper (originalEvent) { 64 | var e = originalEvent || global.event; 65 | e.target = e.target || e.srcElement; 66 | e.preventDefault = e.preventDefault || function preventDefault () { e.returnValue = false; }; 67 | e.stopPropagation = e.stopPropagation || function stopPropagation () { e.cancelBubble = true; }; 68 | e.which = e.which || e.keyCode; 69 | fn.call(el, e); 70 | }; 71 | } 72 | 73 | function wrap (el, type, fn) { 74 | var wrapper = unwrap(el, type, fn) || wrapperFactory(el, type, fn); 75 | hardCache.push({ 76 | wrapper: wrapper, 77 | element: el, 78 | type: type, 79 | fn: fn 80 | }); 81 | return wrapper; 82 | } 83 | 84 | function unwrap (el, type, fn) { 85 | var i = find(el, type, fn); 86 | if (i) { 87 | var wrapper = hardCache[i].wrapper; 88 | hardCache.splice(i, 1); // free up a tad of memory 89 | return wrapper; 90 | } 91 | } 92 | 93 | function find (el, type, fn) { 94 | var i, item; 95 | for (i = 0; i < hardCache.length; i++) { 96 | item = hardCache[i]; 97 | if (item.element === el && item.type === type && item.fn === fn) { 98 | return i; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/eventmap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var eventmap = []; 4 | var eventname = ''; 5 | var ron = /^on/; 6 | 7 | for (eventname in global) { 8 | if (ron.test(eventname)) { 9 | eventmap.push(eventname.slice(2)); 10 | } 11 | } 12 | 13 | module.exports = eventmap; 14 | --------------------------------------------------------------------------------