├── .babelrc.js ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .storybook ├── addons.js ├── config.js └── webpack.config.js ├── LICENSE ├── README.md ├── build ├── build.js └── release.js ├── dist ├── vue-event-manager.common.js ├── vue-event-manager.esm.js ├── vue-event-manager.js └── vue-event-manager.min.js ├── package.json ├── src ├── EventManager.js ├── index.js ├── plugin.js └── util.js ├── stories ├── components │ └── DefaultStory.vue └── index.js ├── test ├── event.js ├── eventAsync.js ├── index.html ├── index.js └── karma.conf.js ├── webpack.config.js └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | presets: [ 4 | ['@babel/preset-env', { 5 | loose: true, 6 | modules: false 7 | }] 8 | ] 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: circleci/node:10-browsers 6 | environment: 7 | CHROME_BIN: /usr/bin/google-chrome 8 | working_directory: ~/vue-event-manager 9 | 10 | jobs: 11 | build: 12 | <<: *defaults 13 | steps: 14 | - checkout 15 | - restore_cache: 16 | key: yarn-{{ checksum "yarn.lock" }} 17 | - run: 18 | name: Install Dependencies 19 | command: yarn --pure-lockfile 20 | - save_cache: 21 | key: yarn-{{ checksum "yarn.lock" }} 22 | paths: 23 | - ./node_modules 24 | - run: 25 | name: Run ESLint 26 | command: yarn eslint 27 | - run: 28 | name: Run Tests 29 | command: | 30 | yarn karma --browsers Chrome 31 | - run: 32 | name: Build Release 33 | command: yarn build -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /test 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "root": true, 3 | "env": { 4 | "es6": true, 5 | "browser": true, 6 | "commonjs": true, 7 | }, 8 | "extends": [ 9 | "eslint:recommended" 10 | ], 11 | "parserOptions": { 12 | "sourceType": "module" 13 | }, 14 | "rules": { 15 | "brace-style": ["error", "1tbs", {"allowSingleLine": true}], 16 | "comma-style": "error", 17 | "comma-spacing": "error", 18 | "eqeqeq": ["off", "smart"], 19 | "indent": "off", 20 | "indent-legacy": ["error", 4, {"SwitchCase": 1}], 21 | "key-spacing": "error", 22 | "keyword-spacing": "error", 23 | "linebreak-style": ["error", "unix"], 24 | "no-var": "error", 25 | "no-multi-spaces": "error", 26 | "no-trailing-spaces": "error", 27 | "no-lone-blocks": "error", 28 | "no-extend-native": "error", 29 | "no-unused-vars": ["error", {"vars": "local", "args": "none"}], 30 | "no-empty": ["error", {"allowEmptyCatch": true}], 31 | "no-duplicate-imports": "error", 32 | "no-array-constructor": "error", 33 | "no-multiple-empty-lines": "error", 34 | "no-template-curly-in-string": "error", 35 | "no-console": "off", 36 | "object-curly-spacing": "error", 37 | "prefer-const": "error", 38 | "quotes": ["error", "single", {"avoidEscape": true}], 39 | "semi": ["error", "always"], 40 | "space-infix-ops": "error", 41 | "space-unary-ops": "error", 42 | "space-in-parens": "error", 43 | "space-before-blocks": "error", 44 | "template-curly-spacing": "error" 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /test/specs.js 3 | /yarn-error.log 4 | .pnp* 5 | .history 6 | .DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | build 2 | docs -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import {configure} from '@storybook/vue'; 2 | 3 | configure(() => { 4 | 5 | require('../stories'); 6 | 7 | }, module); -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = (baseConfig, configType, config) => { 4 | 5 | // add alias 6 | config.resolve.alias['vue-event-manager'] = path.resolve(__dirname, '../src') 7 | 8 | return config; 9 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 steffans 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-event-manager [![Build](https://circleci.com/gh/pagekit/vue-event-manager.svg?style=shield)](https://circleci.com/gh/pagekit/vue-event-manager) [![Downloads](https://img.shields.io/npm/dm/vue-event-manager.svg)](https://www.npmjs.com/package/vue-event-manager) [![jsdelivr](https://data.jsdelivr.com/v1/package/npm/vue-event-manager/badge?style=rounded)](https://www.jsdelivr.com/package/npm/vue-event-manager) [![Version](https://img.shields.io/npm/v/vue-event-manager.svg)](https://www.npmjs.com/package/vue-event-manager) [![License](https://img.shields.io/npm/l/vue-event-manager.svg)](https://www.npmjs.com/package/vue-event-manager) 2 | 3 | The plugin for [Vue.js](http://vuejs.org) provides a declarative way to bind events to a global event manager. It uses the Vue lifecycle to automatically bind and unbind all events. 4 | 5 | ## Features 6 | 7 | - Supports event priorities and [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) based asynchronous events 8 | - Supports latest Firefox, Chrome, Safari, Opera and IE9+ 9 | - Supports Vue 2.0 10 | - Compact size 3KB (1,5KB gzipped) 11 | 12 | ## Installation 13 | You can install it via [yarn](https://yarnpkg.com) or [NPM](https://npmjs.org). 14 | ``` 15 | $ yarn add vue-event-manager 16 | $ npm install vue-event-manager 17 | ``` 18 | 19 | ### CDN 20 | Available on [jsdelivr](https://cdn.jsdelivr.net/npm/vue-event-manager@2.1.3) or [unpkg](https://unpkg.com/vue-event-manager@2.1.3). 21 | ```html 22 | 23 | ``` 24 | 25 | ## Example 26 | Try the example on [jsfiddle](https://jsfiddle.net/gh/get/library/pure/pagekit/vue-event-manager/tree/master/examples/demo/). 27 | ```js 28 | new Vue({ 29 | 30 | created() { 31 | 32 | // trigger event 33 | this.$trigger('someEvent', {foo: 'bar'}); 34 | 35 | }, 36 | 37 | events: { 38 | 39 | // event handler (priority 0) 40 | someEvent(event, param) { ... }, 41 | 42 | // event handler (priority 10) 43 | earlyEvent: { 44 | 45 | // handler callback 46 | handler(event, param) { ... }, 47 | 48 | // a higher priority, means earlier execution 49 | priority: 10 50 | 51 | }, 52 | 53 | // event handler (priority -10) 54 | lateEvent: { 55 | 56 | // handler callback 57 | handler(event, param) { ... }, 58 | 59 | // a lower priority, means late execution 60 | priority: -10 61 | 62 | } 63 | 64 | } 65 | 66 | }); 67 | ``` 68 | 69 | Lets see how **easy** you can **watch global events** like reactive properties! (Like in this [example](https://vuejs.org/v2/examples/commits.html)). 70 | Let's assume you have a logout button in any component template and want it to be handled *somewhere else* without these nasty `$on(...)` and `$off(...)` lines in the created and destroy hooks. 71 | 72 | ```html 73 | 74 | 75 | ``` 76 | 77 | ```js 78 | // userManager.vue 79 | export default { 80 | 81 | name: 'any-other-component', 82 | 83 | events: { 84 | // the event name string binds the method name string 85 | 'logout:the-user': 'logout' 86 | }, 87 | 88 | methods: { 89 | // this method will be called everytime the event occurs 90 | logout (event, param) { 91 | this.$http.post('/logout') 92 | } 93 | } 94 | 95 | } 96 | ``` 97 | 98 | ## Changelog 99 | 100 | Details changes for each release are documented in the [release notes](https://github.com/pagekit/vue-event-manager/releases). 101 | 102 | ## Contribution 103 | 104 | If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/pagekit/vue-event-manager/issues) or a [pull request](https://github.com/pagekit/vue-event-manager/pulls). 105 | 106 | ## License 107 | 108 | [MIT](http://opensource.org/licenses/MIT) 109 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const fs = require('fs'); 4 | const zlib = require('zlib'); 5 | const rollup = require('rollup'); 6 | const uglify = require('uglify-js'); 7 | const babel = require('rollup-plugin-babel'); 8 | const replace = require('rollup-plugin-replace'); 9 | const {name, version, homepage} = require('../package.json'); 10 | const banner = 11 | '/*!\n' + 12 | ' * ' + name + ' v' + version + '\n' + 13 | ' * ' + homepage + '\n' + 14 | ' * Released under the MIT License.\n' + 15 | ' */\n'; 16 | 17 | rollup.rollup({ 18 | input: 'src/index.js', 19 | plugins: [babel(), replace({__VERSION__: version})] 20 | }) 21 | .then(bundle => 22 | bundle.generate({ 23 | format: 'umd', 24 | banner: banner, 25 | name: 'VueEventManager', 26 | }).then(({code}) => write(`dist/${name}.js`, code, bundle)) 27 | ) 28 | .then(bundle => 29 | write(`dist/${name}.min.js`, banner + '\n' + 30 | uglify.minify(read(`dist/${name}.js`)).code, bundle, true) 31 | ) 32 | .then(bundle => 33 | bundle.generate({ 34 | format: 'es', 35 | banner: banner, 36 | }).then(({code}) => write(`dist/${name}.esm.js`, code, bundle)) 37 | ) 38 | .then(bundle => 39 | bundle.generate({ 40 | format: 'cjs', 41 | banner: banner 42 | }).then(({code}) => write(`dist/${name}.common.js`, code, bundle)) 43 | ) 44 | .catch(logError); 45 | 46 | function read(path) { 47 | return fs.readFileSync(path, 'utf8'); 48 | } 49 | 50 | function write(dest, code, bundle, zip) { 51 | return new Promise((resolve, reject) => { 52 | fs.writeFile(dest, code, err => { 53 | if (err) return reject(err); 54 | 55 | if (zip) { 56 | zlib.gzip(code, (err, zipped) => { 57 | if (err) return reject(err); 58 | console.log(blue(dest) + ' ' + getSize(code) + ' (' + getSize(zipped) + ' gzipped)'); 59 | }); 60 | } else { 61 | console.log(blue(dest) + ' ' + getSize(code)); 62 | } 63 | 64 | resolve(bundle); 65 | }); 66 | }); 67 | } 68 | 69 | function getSize(code) { 70 | return (code.length / 1024).toFixed(2) + 'kb'; 71 | } 72 | 73 | function logError(e) { 74 | console.log(e); 75 | } 76 | 77 | function blue(str) { 78 | return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'; 79 | } 80 | -------------------------------------------------------------------------------- /build/release.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const replace = require('replace-in-file'); 4 | const version = process.argv[2]; 5 | 6 | replace({ 7 | files: 'package.json', 8 | from: /("version"\s*:\s*")\d+\.\d+\.\d+("\s*,)/g, 9 | to: '$1' + version + '$2' 10 | }); 11 | 12 | replace({ 13 | files: 'README.md', 14 | from: /(\/|@)\d+\.\d+\.\d+/g, 15 | to: '$1' + version 16 | }); 17 | -------------------------------------------------------------------------------- /dist/vue-event-manager.common.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-event-manager v2.1.3 3 | * https://github.com/pagekit/vue-event-manager 4 | * Released under the MIT License. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Utility functions. 11 | */ 12 | var _config = {}; 13 | var assign = Object.assign || _assign; 14 | var isArray = Array.isArray; 15 | function Util (_ref) { 16 | var config = _ref.config; 17 | _config = config; 18 | } 19 | function log(message, color) { 20 | if (color === void 0) { 21 | color = '#41B883'; 22 | } 23 | 24 | if (typeof console !== 'undefined' && _config.devtools) { 25 | console.log("%c vue-event-manager %c " + message + " ", 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', "color: #fff; background: " + color + "; padding: 1px; border-radius: 0 3px 3px 0;"); 26 | } 27 | } 28 | function isObject(val) { 29 | return val !== null && typeof val === 'object'; 30 | } 31 | function isUndefined(val) { 32 | return typeof val === 'undefined'; 33 | } 34 | function forEach(collection, callback) { 35 | Object.keys(collection || {}).forEach(function (key) { 36 | return callback.call(null, collection[key], key); 37 | }); 38 | } 39 | function array(array) { 40 | if (array === void 0) { 41 | array = []; 42 | } 43 | 44 | if (!array.findIndex) { 45 | array.findIndex = _findIndex; 46 | } 47 | 48 | return array; 49 | } 50 | /** 51 | * Object.assign() polyfill. 52 | */ 53 | 54 | function _assign(target) { 55 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 56 | sources[_key - 1] = arguments[_key]; 57 | } 58 | 59 | sources.forEach(function (source) { 60 | Object.keys(source || {}).forEach(function (key) { 61 | return target[key] = source[key]; 62 | }); 63 | }); 64 | return target; 65 | } 66 | /** 67 | * Array.findIndex() polyfill. 68 | */ 69 | 70 | 71 | function _findIndex(predicate) { 72 | if (this == null) { 73 | throw new TypeError('"this" is null or not defined'); 74 | } 75 | 76 | if (typeof predicate !== 'function') { 77 | throw new TypeError('predicate must be a function'); 78 | } 79 | 80 | var o = Object(this); 81 | var len = o.length >>> 0; 82 | var thisArg = arguments[1]; 83 | var k = 0; 84 | 85 | while (k < len) { 86 | var kValue = o[k]; 87 | 88 | if (predicate.call(thisArg, kValue, k, o)) { 89 | return k; 90 | } 91 | 92 | k++; 93 | } 94 | 95 | return -1; 96 | } 97 | 98 | /** 99 | * Event manager class. 100 | */ 101 | 102 | var EventManager = /*#__PURE__*/function () { 103 | function EventManager() { 104 | this.log = null; 105 | this.listeners = {}; 106 | } 107 | 108 | var _proto = EventManager.prototype; 109 | 110 | _proto.on = function on(event, callback, priority) { 111 | var _this = this; 112 | 113 | if (priority === void 0) { 114 | priority = 0; 115 | } 116 | 117 | var listeners = array(this.listeners[event]); 118 | var index = listeners.findIndex(function (listener) { 119 | return listener.priority < priority; 120 | }); 121 | 122 | if (~index) { 123 | listeners.splice(index, 0, { 124 | callback: callback, 125 | priority: priority 126 | }); 127 | } else { 128 | listeners.push({ 129 | callback: callback, 130 | priority: priority 131 | }); 132 | } 133 | 134 | this.listeners[event] = listeners; 135 | return function () { 136 | return _this.off(event, callback); 137 | }; 138 | }; 139 | 140 | _proto.off = function off(event, callback) { 141 | if (!callback) { 142 | delete this.listeners[event]; 143 | } 144 | 145 | var listeners = this.listeners[event]; 146 | 147 | if (listeners && callback) { 148 | var index = listeners.findIndex(function (listener) { 149 | return listener.callback === callback; 150 | }); 151 | 152 | if (~index) { 153 | listeners.splice(index, 1); 154 | } 155 | } 156 | }; 157 | 158 | _proto.trigger = function trigger(event, params, asynch) { 159 | if (params === void 0) { 160 | params = []; 161 | } 162 | 163 | if (asynch === void 0) { 164 | asynch = false; 165 | } 166 | 167 | var _event = new Event(event, params); 168 | 169 | var reject = function reject(result) { 170 | return Promise.reject(result); 171 | }; 172 | 173 | var resolve = function resolve(result) { 174 | return !isUndefined(result) ? result : _event.result; 175 | }; 176 | 177 | var reducer = function reducer(result, _ref) { 178 | var callback = _ref.callback; 179 | 180 | var next = function next(result) { 181 | if (!isUndefined(result)) { 182 | _event.result = result; 183 | } 184 | 185 | if (result === false) { 186 | _event.stopPropagation(); 187 | } 188 | 189 | if (_event.isPropagationStopped()) { 190 | return _event.result; 191 | } 192 | 193 | return callback.apply(callback, [_event].concat(_event.params)); 194 | }; 195 | 196 | return asynch ? result.then(next, reject) : next(result); 197 | }; 198 | 199 | if (this.log) { 200 | this.log.call(this, _event); 201 | } 202 | 203 | var listeners = (this.listeners[_event.name] || []).concat(); 204 | var result = listeners.reduce(reducer, asynch ? Promise.resolve() : undefined); 205 | return asynch ? result.then(resolve, reject) : resolve(result); 206 | }; 207 | 208 | return EventManager; 209 | }(); 210 | var Event = /*#__PURE__*/function () { 211 | function Event(event, params) { 212 | if (!isObject(event)) { 213 | event = { 214 | name: event 215 | }; 216 | } 217 | 218 | if (!isArray(params)) { 219 | params = [params]; 220 | } 221 | 222 | assign(this, event, { 223 | params: params, 224 | result: undefined 225 | }); 226 | } 227 | 228 | var _proto2 = Event.prototype; 229 | 230 | _proto2.stopPropagation = function stopPropagation() { 231 | this.stop = true; 232 | }; 233 | 234 | _proto2.isPropagationStopped = function isPropagationStopped() { 235 | return this.stop === true; 236 | }; 237 | 238 | return Event; 239 | }(); 240 | 241 | /** 242 | * Plugin class. 243 | */ 244 | var Events = new EventManager(); 245 | var Plugin = { 246 | version: '2.1.3', 247 | install: function install(Vue, options) { 248 | if (options === void 0) { 249 | options = {}; 250 | } 251 | 252 | if (this.installed) { 253 | return; 254 | } 255 | 256 | Util(Vue); 257 | log(this.version); // add global instance/methods 258 | 259 | Vue.prototype.$events = Vue.events = assign(Events, options); 260 | 261 | Vue.prototype.$trigger = function (event, params, asynch) { 262 | if (params === void 0) { 263 | params = []; 264 | } 265 | 266 | if (asynch === void 0) { 267 | asynch = false; 268 | } 269 | 270 | if (!isObject(event)) { 271 | event = { 272 | name: event, 273 | origin: this 274 | }; 275 | } 276 | 277 | return Events.trigger(event, params, asynch); 278 | }; // add merge strategy for "events" 279 | 280 | 281 | Vue.config.optionMergeStrategies.events = mergeEvents; // add mixin to parse "events" from component options 282 | 283 | Vue.mixin({ 284 | beforeCreate: initEvents 285 | }); 286 | }, 287 | EventManager: EventManager 288 | }; 289 | function mergeEvents(parentVal, childVal) { 290 | if (!childVal) { 291 | return parentVal; 292 | } 293 | 294 | if (!parentVal) { 295 | return childVal; 296 | } 297 | 298 | var events = assign({}, parentVal); 299 | 300 | for (var event in childVal) { 301 | var parent = events[event]; 302 | var child = childVal[event]; 303 | 304 | if (parent && !isArray(parent)) { 305 | parent = [parent]; 306 | } 307 | 308 | events[event] = parent ? parent.concat(child) : isArray(child) ? child : [child]; 309 | } 310 | 311 | return events; 312 | } 313 | function initEvents() { 314 | var _this = this; 315 | 316 | var _events = []; 317 | var events = this.$options.events; 318 | 319 | if (events) { 320 | forEach(events, function (listeners, event) { 321 | forEach(isArray(listeners) ? listeners : [listeners], function (listener) { 322 | var priority = 0; 323 | 324 | if (isObject(listener)) { 325 | priority = listener.priority; 326 | listener = listener.handler; 327 | } 328 | 329 | _events.push(_this.$events.on(event, bindListener(listener, _this), priority)); 330 | }); 331 | }); 332 | this.$on('hook:beforeDestroy', function () { 333 | return _events.forEach(function (off) { 334 | return off(); 335 | }); 336 | }); 337 | } 338 | } 339 | function bindListener(fn, vm) { 340 | if (typeof fn === 'string') { 341 | return function () { 342 | return vm[fn].apply(vm, arguments); 343 | }; 344 | } 345 | 346 | return fn.bind(vm); 347 | } 348 | 349 | /** 350 | * Install plugin. 351 | */ 352 | 353 | if (typeof window !== 'undefined' && window.Vue) { 354 | window.Vue.use(Plugin); 355 | } 356 | 357 | module.exports = Plugin; 358 | -------------------------------------------------------------------------------- /dist/vue-event-manager.esm.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-event-manager v2.1.3 3 | * https://github.com/pagekit/vue-event-manager 4 | * Released under the MIT License. 5 | */ 6 | 7 | /** 8 | * Utility functions. 9 | */ 10 | var _config = {}; 11 | var assign = Object.assign || _assign; 12 | var isArray = Array.isArray; 13 | function Util (_ref) { 14 | var config = _ref.config; 15 | _config = config; 16 | } 17 | function log(message, color) { 18 | if (color === void 0) { 19 | color = '#41B883'; 20 | } 21 | 22 | if (typeof console !== 'undefined' && _config.devtools) { 23 | console.log("%c vue-event-manager %c " + message + " ", 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', "color: #fff; background: " + color + "; padding: 1px; border-radius: 0 3px 3px 0;"); 24 | } 25 | } 26 | function isObject(val) { 27 | return val !== null && typeof val === 'object'; 28 | } 29 | function isUndefined(val) { 30 | return typeof val === 'undefined'; 31 | } 32 | function forEach(collection, callback) { 33 | Object.keys(collection || {}).forEach(function (key) { 34 | return callback.call(null, collection[key], key); 35 | }); 36 | } 37 | function array(array) { 38 | if (array === void 0) { 39 | array = []; 40 | } 41 | 42 | if (!array.findIndex) { 43 | array.findIndex = _findIndex; 44 | } 45 | 46 | return array; 47 | } 48 | /** 49 | * Object.assign() polyfill. 50 | */ 51 | 52 | function _assign(target) { 53 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 54 | sources[_key - 1] = arguments[_key]; 55 | } 56 | 57 | sources.forEach(function (source) { 58 | Object.keys(source || {}).forEach(function (key) { 59 | return target[key] = source[key]; 60 | }); 61 | }); 62 | return target; 63 | } 64 | /** 65 | * Array.findIndex() polyfill. 66 | */ 67 | 68 | 69 | function _findIndex(predicate) { 70 | if (this == null) { 71 | throw new TypeError('"this" is null or not defined'); 72 | } 73 | 74 | if (typeof predicate !== 'function') { 75 | throw new TypeError('predicate must be a function'); 76 | } 77 | 78 | var o = Object(this); 79 | var len = o.length >>> 0; 80 | var thisArg = arguments[1]; 81 | var k = 0; 82 | 83 | while (k < len) { 84 | var kValue = o[k]; 85 | 86 | if (predicate.call(thisArg, kValue, k, o)) { 87 | return k; 88 | } 89 | 90 | k++; 91 | } 92 | 93 | return -1; 94 | } 95 | 96 | /** 97 | * Event manager class. 98 | */ 99 | 100 | var EventManager = /*#__PURE__*/function () { 101 | function EventManager() { 102 | this.log = null; 103 | this.listeners = {}; 104 | } 105 | 106 | var _proto = EventManager.prototype; 107 | 108 | _proto.on = function on(event, callback, priority) { 109 | var _this = this; 110 | 111 | if (priority === void 0) { 112 | priority = 0; 113 | } 114 | 115 | var listeners = array(this.listeners[event]); 116 | var index = listeners.findIndex(function (listener) { 117 | return listener.priority < priority; 118 | }); 119 | 120 | if (~index) { 121 | listeners.splice(index, 0, { 122 | callback: callback, 123 | priority: priority 124 | }); 125 | } else { 126 | listeners.push({ 127 | callback: callback, 128 | priority: priority 129 | }); 130 | } 131 | 132 | this.listeners[event] = listeners; 133 | return function () { 134 | return _this.off(event, callback); 135 | }; 136 | }; 137 | 138 | _proto.off = function off(event, callback) { 139 | if (!callback) { 140 | delete this.listeners[event]; 141 | } 142 | 143 | var listeners = this.listeners[event]; 144 | 145 | if (listeners && callback) { 146 | var index = listeners.findIndex(function (listener) { 147 | return listener.callback === callback; 148 | }); 149 | 150 | if (~index) { 151 | listeners.splice(index, 1); 152 | } 153 | } 154 | }; 155 | 156 | _proto.trigger = function trigger(event, params, asynch) { 157 | if (params === void 0) { 158 | params = []; 159 | } 160 | 161 | if (asynch === void 0) { 162 | asynch = false; 163 | } 164 | 165 | var _event = new Event(event, params); 166 | 167 | var reject = function reject(result) { 168 | return Promise.reject(result); 169 | }; 170 | 171 | var resolve = function resolve(result) { 172 | return !isUndefined(result) ? result : _event.result; 173 | }; 174 | 175 | var reducer = function reducer(result, _ref) { 176 | var callback = _ref.callback; 177 | 178 | var next = function next(result) { 179 | if (!isUndefined(result)) { 180 | _event.result = result; 181 | } 182 | 183 | if (result === false) { 184 | _event.stopPropagation(); 185 | } 186 | 187 | if (_event.isPropagationStopped()) { 188 | return _event.result; 189 | } 190 | 191 | return callback.apply(callback, [_event].concat(_event.params)); 192 | }; 193 | 194 | return asynch ? result.then(next, reject) : next(result); 195 | }; 196 | 197 | if (this.log) { 198 | this.log.call(this, _event); 199 | } 200 | 201 | var listeners = (this.listeners[_event.name] || []).concat(); 202 | var result = listeners.reduce(reducer, asynch ? Promise.resolve() : undefined); 203 | return asynch ? result.then(resolve, reject) : resolve(result); 204 | }; 205 | 206 | return EventManager; 207 | }(); 208 | var Event = /*#__PURE__*/function () { 209 | function Event(event, params) { 210 | if (!isObject(event)) { 211 | event = { 212 | name: event 213 | }; 214 | } 215 | 216 | if (!isArray(params)) { 217 | params = [params]; 218 | } 219 | 220 | assign(this, event, { 221 | params: params, 222 | result: undefined 223 | }); 224 | } 225 | 226 | var _proto2 = Event.prototype; 227 | 228 | _proto2.stopPropagation = function stopPropagation() { 229 | this.stop = true; 230 | }; 231 | 232 | _proto2.isPropagationStopped = function isPropagationStopped() { 233 | return this.stop === true; 234 | }; 235 | 236 | return Event; 237 | }(); 238 | 239 | /** 240 | * Plugin class. 241 | */ 242 | var Events = new EventManager(); 243 | var Plugin = { 244 | version: '2.1.3', 245 | install: function install(Vue, options) { 246 | if (options === void 0) { 247 | options = {}; 248 | } 249 | 250 | if (this.installed) { 251 | return; 252 | } 253 | 254 | Util(Vue); 255 | log(this.version); // add global instance/methods 256 | 257 | Vue.prototype.$events = Vue.events = assign(Events, options); 258 | 259 | Vue.prototype.$trigger = function (event, params, asynch) { 260 | if (params === void 0) { 261 | params = []; 262 | } 263 | 264 | if (asynch === void 0) { 265 | asynch = false; 266 | } 267 | 268 | if (!isObject(event)) { 269 | event = { 270 | name: event, 271 | origin: this 272 | }; 273 | } 274 | 275 | return Events.trigger(event, params, asynch); 276 | }; // add merge strategy for "events" 277 | 278 | 279 | Vue.config.optionMergeStrategies.events = mergeEvents; // add mixin to parse "events" from component options 280 | 281 | Vue.mixin({ 282 | beforeCreate: initEvents 283 | }); 284 | }, 285 | EventManager: EventManager 286 | }; 287 | function mergeEvents(parentVal, childVal) { 288 | if (!childVal) { 289 | return parentVal; 290 | } 291 | 292 | if (!parentVal) { 293 | return childVal; 294 | } 295 | 296 | var events = assign({}, parentVal); 297 | 298 | for (var event in childVal) { 299 | var parent = events[event]; 300 | var child = childVal[event]; 301 | 302 | if (parent && !isArray(parent)) { 303 | parent = [parent]; 304 | } 305 | 306 | events[event] = parent ? parent.concat(child) : isArray(child) ? child : [child]; 307 | } 308 | 309 | return events; 310 | } 311 | function initEvents() { 312 | var _this = this; 313 | 314 | var _events = []; 315 | var events = this.$options.events; 316 | 317 | if (events) { 318 | forEach(events, function (listeners, event) { 319 | forEach(isArray(listeners) ? listeners : [listeners], function (listener) { 320 | var priority = 0; 321 | 322 | if (isObject(listener)) { 323 | priority = listener.priority; 324 | listener = listener.handler; 325 | } 326 | 327 | _events.push(_this.$events.on(event, bindListener(listener, _this), priority)); 328 | }); 329 | }); 330 | this.$on('hook:beforeDestroy', function () { 331 | return _events.forEach(function (off) { 332 | return off(); 333 | }); 334 | }); 335 | } 336 | } 337 | function bindListener(fn, vm) { 338 | if (typeof fn === 'string') { 339 | return function () { 340 | return vm[fn].apply(vm, arguments); 341 | }; 342 | } 343 | 344 | return fn.bind(vm); 345 | } 346 | 347 | /** 348 | * Install plugin. 349 | */ 350 | 351 | if (typeof window !== 'undefined' && window.Vue) { 352 | window.Vue.use(Plugin); 353 | } 354 | 355 | export default Plugin; 356 | -------------------------------------------------------------------------------- /dist/vue-event-manager.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-event-manager v2.1.3 3 | * https://github.com/pagekit/vue-event-manager 4 | * Released under the MIT License. 5 | */ 6 | 7 | (function (global, factory) { 8 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 9 | typeof define === 'function' && define.amd ? define(factory) : 10 | (global = global || self, global.VueEventManager = factory()); 11 | }(this, function () { 'use strict'; 12 | 13 | /** 14 | * Utility functions. 15 | */ 16 | var _config = {}; 17 | var assign = Object.assign || _assign; 18 | var isArray = Array.isArray; 19 | function Util (_ref) { 20 | var config = _ref.config; 21 | _config = config; 22 | } 23 | function log(message, color) { 24 | if (color === void 0) { 25 | color = '#41B883'; 26 | } 27 | 28 | if (typeof console !== 'undefined' && _config.devtools) { 29 | console.log("%c vue-event-manager %c " + message + " ", 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', "color: #fff; background: " + color + "; padding: 1px; border-radius: 0 3px 3px 0;"); 30 | } 31 | } 32 | function isObject(val) { 33 | return val !== null && typeof val === 'object'; 34 | } 35 | function isUndefined(val) { 36 | return typeof val === 'undefined'; 37 | } 38 | function forEach(collection, callback) { 39 | Object.keys(collection || {}).forEach(function (key) { 40 | return callback.call(null, collection[key], key); 41 | }); 42 | } 43 | function array(array) { 44 | if (array === void 0) { 45 | array = []; 46 | } 47 | 48 | if (!array.findIndex) { 49 | array.findIndex = _findIndex; 50 | } 51 | 52 | return array; 53 | } 54 | /** 55 | * Object.assign() polyfill. 56 | */ 57 | 58 | function _assign(target) { 59 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 60 | sources[_key - 1] = arguments[_key]; 61 | } 62 | 63 | sources.forEach(function (source) { 64 | Object.keys(source || {}).forEach(function (key) { 65 | return target[key] = source[key]; 66 | }); 67 | }); 68 | return target; 69 | } 70 | /** 71 | * Array.findIndex() polyfill. 72 | */ 73 | 74 | 75 | function _findIndex(predicate) { 76 | if (this == null) { 77 | throw new TypeError('"this" is null or not defined'); 78 | } 79 | 80 | if (typeof predicate !== 'function') { 81 | throw new TypeError('predicate must be a function'); 82 | } 83 | 84 | var o = Object(this); 85 | var len = o.length >>> 0; 86 | var thisArg = arguments[1]; 87 | var k = 0; 88 | 89 | while (k < len) { 90 | var kValue = o[k]; 91 | 92 | if (predicate.call(thisArg, kValue, k, o)) { 93 | return k; 94 | } 95 | 96 | k++; 97 | } 98 | 99 | return -1; 100 | } 101 | 102 | /** 103 | * Event manager class. 104 | */ 105 | 106 | var EventManager = /*#__PURE__*/function () { 107 | function EventManager() { 108 | this.log = null; 109 | this.listeners = {}; 110 | } 111 | 112 | var _proto = EventManager.prototype; 113 | 114 | _proto.on = function on(event, callback, priority) { 115 | var _this = this; 116 | 117 | if (priority === void 0) { 118 | priority = 0; 119 | } 120 | 121 | var listeners = array(this.listeners[event]); 122 | var index = listeners.findIndex(function (listener) { 123 | return listener.priority < priority; 124 | }); 125 | 126 | if (~index) { 127 | listeners.splice(index, 0, { 128 | callback: callback, 129 | priority: priority 130 | }); 131 | } else { 132 | listeners.push({ 133 | callback: callback, 134 | priority: priority 135 | }); 136 | } 137 | 138 | this.listeners[event] = listeners; 139 | return function () { 140 | return _this.off(event, callback); 141 | }; 142 | }; 143 | 144 | _proto.off = function off(event, callback) { 145 | if (!callback) { 146 | delete this.listeners[event]; 147 | } 148 | 149 | var listeners = this.listeners[event]; 150 | 151 | if (listeners && callback) { 152 | var index = listeners.findIndex(function (listener) { 153 | return listener.callback === callback; 154 | }); 155 | 156 | if (~index) { 157 | listeners.splice(index, 1); 158 | } 159 | } 160 | }; 161 | 162 | _proto.trigger = function trigger(event, params, asynch) { 163 | if (params === void 0) { 164 | params = []; 165 | } 166 | 167 | if (asynch === void 0) { 168 | asynch = false; 169 | } 170 | 171 | var _event = new Event(event, params); 172 | 173 | var reject = function reject(result) { 174 | return Promise.reject(result); 175 | }; 176 | 177 | var resolve = function resolve(result) { 178 | return !isUndefined(result) ? result : _event.result; 179 | }; 180 | 181 | var reducer = function reducer(result, _ref) { 182 | var callback = _ref.callback; 183 | 184 | var next = function next(result) { 185 | if (!isUndefined(result)) { 186 | _event.result = result; 187 | } 188 | 189 | if (result === false) { 190 | _event.stopPropagation(); 191 | } 192 | 193 | if (_event.isPropagationStopped()) { 194 | return _event.result; 195 | } 196 | 197 | return callback.apply(callback, [_event].concat(_event.params)); 198 | }; 199 | 200 | return asynch ? result.then(next, reject) : next(result); 201 | }; 202 | 203 | if (this.log) { 204 | this.log.call(this, _event); 205 | } 206 | 207 | var listeners = (this.listeners[_event.name] || []).concat(); 208 | var result = listeners.reduce(reducer, asynch ? Promise.resolve() : undefined); 209 | return asynch ? result.then(resolve, reject) : resolve(result); 210 | }; 211 | 212 | return EventManager; 213 | }(); 214 | var Event = /*#__PURE__*/function () { 215 | function Event(event, params) { 216 | if (!isObject(event)) { 217 | event = { 218 | name: event 219 | }; 220 | } 221 | 222 | if (!isArray(params)) { 223 | params = [params]; 224 | } 225 | 226 | assign(this, event, { 227 | params: params, 228 | result: undefined 229 | }); 230 | } 231 | 232 | var _proto2 = Event.prototype; 233 | 234 | _proto2.stopPropagation = function stopPropagation() { 235 | this.stop = true; 236 | }; 237 | 238 | _proto2.isPropagationStopped = function isPropagationStopped() { 239 | return this.stop === true; 240 | }; 241 | 242 | return Event; 243 | }(); 244 | 245 | /** 246 | * Plugin class. 247 | */ 248 | var Events = new EventManager(); 249 | var Plugin = { 250 | version: '2.1.3', 251 | install: function install(Vue, options) { 252 | if (options === void 0) { 253 | options = {}; 254 | } 255 | 256 | if (this.installed) { 257 | return; 258 | } 259 | 260 | Util(Vue); 261 | log(this.version); // add global instance/methods 262 | 263 | Vue.prototype.$events = Vue.events = assign(Events, options); 264 | 265 | Vue.prototype.$trigger = function (event, params, asynch) { 266 | if (params === void 0) { 267 | params = []; 268 | } 269 | 270 | if (asynch === void 0) { 271 | asynch = false; 272 | } 273 | 274 | if (!isObject(event)) { 275 | event = { 276 | name: event, 277 | origin: this 278 | }; 279 | } 280 | 281 | return Events.trigger(event, params, asynch); 282 | }; // add merge strategy for "events" 283 | 284 | 285 | Vue.config.optionMergeStrategies.events = mergeEvents; // add mixin to parse "events" from component options 286 | 287 | Vue.mixin({ 288 | beforeCreate: initEvents 289 | }); 290 | }, 291 | EventManager: EventManager 292 | }; 293 | function mergeEvents(parentVal, childVal) { 294 | if (!childVal) { 295 | return parentVal; 296 | } 297 | 298 | if (!parentVal) { 299 | return childVal; 300 | } 301 | 302 | var events = assign({}, parentVal); 303 | 304 | for (var event in childVal) { 305 | var parent = events[event]; 306 | var child = childVal[event]; 307 | 308 | if (parent && !isArray(parent)) { 309 | parent = [parent]; 310 | } 311 | 312 | events[event] = parent ? parent.concat(child) : isArray(child) ? child : [child]; 313 | } 314 | 315 | return events; 316 | } 317 | function initEvents() { 318 | var _this = this; 319 | 320 | var _events = []; 321 | var events = this.$options.events; 322 | 323 | if (events) { 324 | forEach(events, function (listeners, event) { 325 | forEach(isArray(listeners) ? listeners : [listeners], function (listener) { 326 | var priority = 0; 327 | 328 | if (isObject(listener)) { 329 | priority = listener.priority; 330 | listener = listener.handler; 331 | } 332 | 333 | _events.push(_this.$events.on(event, bindListener(listener, _this), priority)); 334 | }); 335 | }); 336 | this.$on('hook:beforeDestroy', function () { 337 | return _events.forEach(function (off) { 338 | return off(); 339 | }); 340 | }); 341 | } 342 | } 343 | function bindListener(fn, vm) { 344 | if (typeof fn === 'string') { 345 | return function () { 346 | return vm[fn].apply(vm, arguments); 347 | }; 348 | } 349 | 350 | return fn.bind(vm); 351 | } 352 | 353 | /** 354 | * Install plugin. 355 | */ 356 | 357 | if (typeof window !== 'undefined' && window.Vue) { 358 | window.Vue.use(Plugin); 359 | } 360 | 361 | return Plugin; 362 | 363 | })); 364 | -------------------------------------------------------------------------------- /dist/vue-event-manager.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-event-manager v2.1.3 3 | * https://github.com/pagekit/vue-event-manager 4 | * Released under the MIT License. 5 | */ 6 | 7 | !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n=n||self).VueEventManager=t()}(this,function(){"use strict";var i={},u=Object.assign||function(e){for(var n=arguments.length,t=new Array(1>>0,r=arguments[1],o=0;o listener.priority < priority); 18 | 19 | if (~index) { 20 | listeners.splice(index, 0, {callback, priority}); 21 | } else { 22 | listeners.push({callback, priority}); 23 | } 24 | 25 | this.listeners[event] = listeners; 26 | 27 | return () => this.off(event, callback); 28 | } 29 | 30 | off(event, callback) { 31 | 32 | if (!callback) { 33 | delete this.listeners[event]; 34 | } 35 | 36 | const listeners = this.listeners[event]; 37 | 38 | if (listeners && callback) { 39 | 40 | const index = listeners.findIndex(listener => listener.callback === callback); 41 | 42 | if (~index) { 43 | listeners.splice(index, 1); 44 | } 45 | } 46 | } 47 | 48 | trigger(event, params = [], asynch = false) { 49 | 50 | const _event = new Event(event, params); 51 | const reject = result => Promise.reject(result); 52 | const resolve = result => !isUndefined(result) ? result : _event.result; 53 | const reducer = (result, {callback}) => { 54 | 55 | const next = result => { 56 | 57 | if (!isUndefined(result)) { 58 | _event.result = result; 59 | } 60 | 61 | if (result === false) { 62 | _event.stopPropagation(); 63 | } 64 | 65 | if (_event.isPropagationStopped()) { 66 | return _event.result; 67 | } 68 | 69 | return callback.apply(callback, [_event].concat(_event.params)); 70 | }; 71 | 72 | return asynch ? result.then(next, reject) : next(result); 73 | }; 74 | 75 | if (this.log) { 76 | this.log.call(this, _event); 77 | } 78 | 79 | const listeners = (this.listeners[_event.name] || []).concat(); 80 | const result = listeners.reduce(reducer, asynch ? Promise.resolve() : undefined); 81 | 82 | return asynch ? result.then(resolve, reject) : resolve(result); 83 | } 84 | 85 | } 86 | 87 | export class Event { 88 | 89 | constructor(event, params) { 90 | 91 | if (!isObject(event)) { 92 | event = {name: event}; 93 | } 94 | 95 | if (!isArray(params)) { 96 | params = [params]; 97 | } 98 | 99 | assign(this, event, {params, result: undefined}); 100 | } 101 | 102 | stopPropagation() { 103 | this.stop = true; 104 | } 105 | 106 | isPropagationStopped() { 107 | return this.stop === true; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Install plugin. 3 | */ 4 | 5 | import Plugin from './plugin'; 6 | 7 | if (typeof window !== 'undefined' && window.Vue) { 8 | window.Vue.use(Plugin); 9 | } 10 | 11 | export default Plugin; -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Plugin class. 3 | */ 4 | 5 | import EventManager from './EventManager'; 6 | import Util, {log, assign, forEach, isArray, isObject} from './util'; 7 | 8 | const Events = new EventManager(); 9 | 10 | export default { 11 | 12 | version: '__VERSION__', 13 | 14 | install(Vue, options = {}) { 15 | 16 | if (this.installed) { 17 | return; 18 | } 19 | 20 | Util(Vue); log(this.version); 21 | 22 | // add global instance/methods 23 | Vue.prototype.$events = Vue.events = assign(Events, options); 24 | Vue.prototype.$trigger = function (event, params = [], asynch = false) { 25 | 26 | if (!isObject(event)) { 27 | event = {name: event, origin: this}; 28 | } 29 | 30 | return Events.trigger(event, params, asynch); 31 | }; 32 | 33 | // add merge strategy for "events" 34 | Vue.config.optionMergeStrategies.events = mergeEvents; 35 | 36 | // add mixin to parse "events" from component options 37 | Vue.mixin({beforeCreate: initEvents}); 38 | }, 39 | 40 | EventManager 41 | 42 | }; 43 | 44 | export function mergeEvents(parentVal, childVal) { 45 | 46 | if (!childVal) { 47 | return parentVal; 48 | } 49 | 50 | if (!parentVal) { 51 | return childVal; 52 | } 53 | 54 | const events = assign({}, parentVal); 55 | 56 | for (const event in childVal) { 57 | 58 | let parent = events[event]; 59 | const child = childVal[event]; 60 | 61 | if (parent && !isArray(parent)) { 62 | parent = [parent]; 63 | } 64 | 65 | events[event] = parent 66 | ? parent.concat(child) 67 | : isArray(child) ? child : [child]; 68 | } 69 | 70 | return events; 71 | } 72 | 73 | export function initEvents() { 74 | 75 | const _events = []; 76 | const {events} = this.$options; 77 | 78 | if (events) { 79 | 80 | forEach(events, (listeners, event) => { 81 | forEach(isArray(listeners) ? listeners : [listeners], listener => { 82 | 83 | let priority = 0; 84 | 85 | if (isObject(listener)) { 86 | priority = listener.priority; 87 | listener = listener.handler; 88 | } 89 | 90 | _events.push(this.$events.on(event, bindListener(listener, this), priority)); 91 | }); 92 | }); 93 | 94 | this.$on('hook:beforeDestroy', () => _events.forEach(off => off())); 95 | } 96 | } 97 | 98 | export function bindListener(fn, vm) { 99 | 100 | if (typeof fn === 'string') { 101 | return function () { 102 | return vm[fn].apply(vm, arguments); 103 | }; 104 | } 105 | 106 | return fn.bind(vm); 107 | } 108 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility functions. 3 | */ 4 | 5 | let _config = {}; 6 | 7 | export const assign = Object.assign || _assign; 8 | 9 | export const isArray = Array.isArray; 10 | 11 | export default function ({config}) { 12 | _config = config; 13 | } 14 | 15 | export function log(message, color = '#41B883') { 16 | if (typeof console !== 'undefined' && _config.devtools) { 17 | console.log(`%c vue-event-manager %c ${message} `, 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', `color: #fff; background: ${color}; padding: 1px; border-radius: 0 3px 3px 0;`); 18 | } 19 | } 20 | 21 | export function warn(message, color = '#DB6B00') { 22 | log(message, color); 23 | } 24 | 25 | export function isObject(val) { 26 | return val !== null && typeof val === 'object'; 27 | } 28 | 29 | export function isUndefined(val) { 30 | return typeof val === 'undefined'; 31 | } 32 | 33 | export function forEach(collection, callback) { 34 | Object.keys(collection || {}).forEach( 35 | key => callback.call(null, collection[key], key) 36 | ); 37 | } 38 | 39 | export function array(array = []) { 40 | 41 | if (!array.findIndex) { 42 | array.findIndex = _findIndex; 43 | } 44 | 45 | return array; 46 | } 47 | 48 | /** 49 | * Object.assign() polyfill. 50 | */ 51 | function _assign(target, ...sources) { 52 | 53 | sources.forEach(source => { 54 | Object.keys(source || {}).forEach( 55 | key => target[key] = source[key] 56 | ); 57 | }); 58 | 59 | return target; 60 | } 61 | 62 | /** 63 | * Array.findIndex() polyfill. 64 | */ 65 | function _findIndex(predicate) { 66 | 67 | if (this == null) { 68 | throw new TypeError('"this" is null or not defined'); 69 | } 70 | 71 | if (typeof predicate !== 'function') { 72 | throw new TypeError('predicate must be a function'); 73 | } 74 | 75 | const o = Object(this); 76 | const len = o.length >>> 0; 77 | const thisArg = arguments[1]; 78 | 79 | let k = 0; 80 | 81 | while (k < len) { 82 | 83 | const kValue = o[k]; 84 | 85 | if (predicate.call(thisArg, kValue, k, o)) { 86 | return k; 87 | } 88 | 89 | k++; 90 | } 91 | 92 | return -1; 93 | } 94 | -------------------------------------------------------------------------------- /stories/components/DefaultStory.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | 42 | 47 | -------------------------------------------------------------------------------- /stories/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueEventManager from 'vue-event-manager'; 3 | import DefaultStory from './components/DefaultStory.vue'; 4 | import {storiesOf} from '@storybook/vue'; 5 | import {action} from '@storybook/addon-actions'; 6 | 7 | // load plugin 8 | Vue.use(VueEventManager, { 9 | 10 | // log event action 11 | log({name, params}) { 12 | action(name)(...params); 13 | } 14 | 15 | }); 16 | 17 | storiesOf('Event Manager', module) 18 | .add('Default', () => ({extends: DefaultStory})); 19 | -------------------------------------------------------------------------------- /test/event.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | describe('Vue.events', () => { 4 | 5 | it('Trigger Method with one param', () => { 6 | new Vue({ 7 | created() { 8 | this.$trigger('someEvent', 'foo'); 9 | }, 10 | events: { 11 | someEvent(event, param) { 12 | expect(param).toBe('foo'); 13 | expect(event.name).toBe('someEvent'); 14 | } 15 | } 16 | }); 17 | }); 18 | 19 | it('Trigger Method with Array', () => { 20 | new Vue({ 21 | created() { 22 | this.$trigger('paramArray', ['foo', 'bar']); 23 | }, 24 | events: { 25 | paramArray(event, param, param2) { 26 | expect(param).toBe('foo'); 27 | expect(param2).toBe('bar'); 28 | } 29 | } 30 | }); 31 | }); 32 | 33 | it('Trigger Method with Object', () => { 34 | new Vue({ 35 | created() { 36 | this.$trigger('paramObject', { foo : 'bar' }); 37 | }, 38 | events: { 39 | paramObject(event, param) { 40 | expect(param.foo).toBe('bar'); 41 | } 42 | } 43 | }); 44 | }); 45 | 46 | it('Trigger Method with Priority', () => { 47 | var vm = new Vue({ 48 | data() { 49 | return { 50 | lastPrio : null 51 | } 52 | }, 53 | events: { 54 | // event handler (priority 10) 55 | prioHandler: [ 56 | { 57 | // handler callback 58 | handler(event, param) { 59 | this.lastPrio = 10; 60 | }, 61 | // a higher priority, means earlier execution 62 | priority: 10 63 | }, 64 | { 65 | // handler callback 66 | handler(event, param) { 67 | expect(this.lastPrio).toBe(10); 68 | this.lastPrio = -10; 69 | }, 70 | // a higher priority, means earlier execution 71 | priority: -10 72 | } 73 | ] 74 | } 75 | }); 76 | vm.$trigger('prioHandler'); 77 | }); 78 | 79 | 80 | it('Trigger Method with Different Instances and Priority', () => { 81 | 82 | var vm1 = new Vue({ 83 | data() { 84 | return { 85 | isLoaded : false 86 | } 87 | }, 88 | events: { 89 | testEvent(event, param) { 90 | this.isLoaded = true; 91 | expect(this.isLoaded).toBe(true); 92 | } 93 | } 94 | }); 95 | 96 | var vm2 = new Vue({ 97 | events: { 98 | testEvent:{ 99 | handler(event, param) { 100 | expect(param).toBe('foo'); 101 | }, 102 | priority: 10 103 | } 104 | } 105 | }); 106 | vm1.$trigger('testEvent', 'foo'); 107 | }); 108 | 109 | it('Trigger Method with Cancel Event', () => { 110 | 111 | var vm1 = new Vue({ 112 | data() { 113 | return { 114 | isLoaded: false 115 | } 116 | }, 117 | events: { 118 | actionCancel(event, param) { 119 | this.isLoaded = true; 120 | return "lastAction"; 121 | } 122 | } 123 | }); 124 | 125 | var vm2 = new Vue({ 126 | events: { 127 | actionCancel:{ 128 | handler(event, param) { 129 | expect(param).toBe('foo'); 130 | return false; 131 | }, 132 | priority: 10 133 | } 134 | } 135 | }); 136 | 137 | vm1.$trigger('actionCancel', 'foo'); 138 | expect(vm1.isLoaded).toBe(false); 139 | 140 | }); 141 | 142 | it('Use string names of methods in event list', () => { 143 | new Vue({ 144 | data() { 145 | return { 146 | isRun : false 147 | } 148 | }, 149 | created() { 150 | this.$trigger('test'); 151 | expect(this.isRun).toBe(true); 152 | }, 153 | methods: { 154 | test() { 155 | this.isRun = true; 156 | } 157 | }, 158 | events: { 159 | test: 'test' 160 | } 161 | }); 162 | }); 163 | 164 | }); -------------------------------------------------------------------------------- /test/eventAsync.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | describe('Vue.events Async', () => { 4 | it('Trigger Method asynchronous', () => { 5 | new Vue({ 6 | data() { 7 | return { 8 | isRun : false 9 | } 10 | }, 11 | created() { 12 | this.$trigger('setRun', [], true); 13 | this.$trigger('sendParam', 'foo'); 14 | }, 15 | events: { 16 | setRun() { 17 | this.isRun = true; 18 | expect(this.isRun).toBe(true); 19 | }, 20 | sendParam(event, param) { 21 | expect(this.isRun).toBe(false); 22 | } 23 | } 24 | }); 25 | }); 26 | 27 | it('Trigger Method asynchronous with Different Instances', (done) => { 28 | 29 | var vm1 = new Vue({ 30 | data() { 31 | return { 32 | isLoaded : false 33 | } 34 | }, 35 | events: { 36 | testEvent(event, param) { 37 | this.isLoaded = true; 38 | expect(this.isLoaded).toBe(true); 39 | done(); 40 | } 41 | } 42 | }); 43 | 44 | var vm2 = new Vue({ 45 | events: { 46 | testEvent:{ 47 | handler(event, param) { 48 | expect(param).toBe('foo'); 49 | return new Promise((resolve) => { 50 | setTimeout(resolve, 300); 51 | }); 52 | }, 53 | priority: 10 54 | } 55 | } 56 | }); 57 | vm1.$trigger('testEvent', 'foo', true); 58 | }); 59 | 60 | }); -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue EventManager - Jasmine 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueEventManager from 'vue-event-manager'; 3 | 4 | Vue.use(VueEventManager); 5 | 6 | require('./event'); 7 | require('./eventAsync'); -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | const webpack = require('../webpack.config'); 2 | 3 | module.exports = config => { 4 | 5 | config.set({ 6 | basePath: __dirname, 7 | frameworks: ['jasmine'], 8 | browsers: ['Chrome', 'Safari', 'Firefox'], 9 | files: ['index.js'], 10 | preprocessors: { 11 | 'index.js': ['webpack'] 12 | }, 13 | webpack 14 | }); 15 | 16 | }; -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | module.exports = { 4 | 5 | mode: 'production', 6 | 7 | entry: { 8 | 'test/specs': './test/index', 9 | }, 10 | 11 | output: { 12 | filename: './[name].js' 13 | }, 14 | 15 | resolve: { 16 | alias: { 17 | 'vue-event-manager': __dirname + '/src' 18 | } 19 | }, 20 | 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.js$/, 25 | exclude: /node_modules/, 26 | use: 'babel-loader' 27 | } 28 | ] 29 | } 30 | 31 | }; 32 | --------------------------------------------------------------------------------