| import EventEmitter from 'events'; |
| import hasLocalStorage from './env/hasLocalStorage'; |
| import pick from './pick'; |
| import nextTick from './nextTick'; |
| |
| export default class Changes extends EventEmitter { |
| constructor() { |
| super(); |
| |
| this._listeners = {}; |
| |
| if (hasLocalStorage()) { |
| addEventListener("storage", (e) => { |
| this.emit(e.key); |
| }); |
| } |
| } |
| |
| addListener(dbName, id, db, opts) { |
| if (this._listeners[id]) { |
| return; |
| } |
| var inprogress = false; |
| var self = this; |
| function eventFunction() { |
| if (!self._listeners[id]) { |
| return; |
| } |
| if (inprogress) { |
| inprogress = 'waiting'; |
| return; |
| } |
| inprogress = true; |
| var changesOpts = pick(opts, [ |
| 'style', 'include_docs', 'attachments', 'conflicts', 'filter', |
| 'doc_ids', 'view', 'since', 'query_params', 'binary', 'return_docs' |
| ]); |
| |
| function onError() { |
| inprogress = false; |
| } |
| |
| db.changes(changesOpts).on('change', function (c) { |
| if (c.seq > opts.since && !opts.cancelled) { |
| opts.since = c.seq; |
| opts.onChange(c); |
| } |
| }).on('complete', function () { |
| if (inprogress === 'waiting') { |
| nextTick(eventFunction); |
| } |
| inprogress = false; |
| }).on('error', onError); |
| } |
| this._listeners[id] = eventFunction; |
| this.on(dbName, eventFunction); |
| } |
| |
| removeListener(dbName, id) { |
| if (!(id in this._listeners)) { |
| return; |
| } |
| super.removeListener(dbName, this._listeners[id]); |
| delete this._listeners[id]; |
| } |
| |
| notifyLocalWindows(dbName) { |
| //do a useless change on a storage thing |
| //in order to get other windows's listeners to activate |
| if (hasLocalStorage()) { |
| localStorage[dbName] = (localStorage[dbName] === "a") ? "b" : "a"; |
| } |
| } |
| |
| notify(dbName) { |
| this.emit(dbName); |
| this.notifyLocalWindows(dbName); |
| } |
| } |