465 lines
24 KiB
Plaintext
465 lines
24 KiB
Plaintext
/*! { "name": "vissense", "version": "0.9.0", "homepage": "https://vissense.github.io/vissense","copyright": "(c) 2016 tbk" } */
|
|
!function(root, name, factory) {
|
|
"use strict";
|
|
var withWindow = function(win) {
|
|
var product = factory(win, win.document);
|
|
return product.noConflict = function() {
|
|
return product;
|
|
}, product;
|
|
};
|
|
if ("function" == typeof define && define.amd) define([], function() {
|
|
return withWindow;
|
|
}); else if ("object" == typeof exports) module.exports = function(win) {
|
|
return withWindow(win);
|
|
}; else {
|
|
var _oldValue = root[name], _newValue = factory(root, root.document);
|
|
root[name] = _newValue, root[name].noConflict = function() {
|
|
return root[name] = _oldValue, _newValue;
|
|
};
|
|
}
|
|
}(this, "VisSense", function(window, document, undefined) {
|
|
"use strict";
|
|
function async(callback, delay) {
|
|
return function() {
|
|
var args = arguments;
|
|
return defer(function() {
|
|
callback.apply(undefined, args);
|
|
}, delay || 0);
|
|
};
|
|
}
|
|
function debounce(callback, delay) {
|
|
var cancel = noop;
|
|
return function() {
|
|
var self = this, args = arguments;
|
|
cancel(), cancel = defer(function() {
|
|
callback.apply(self, args);
|
|
}, delay);
|
|
};
|
|
}
|
|
function defaults(dest, source) {
|
|
var sourceIsObject = isObject(source), destIsObject = isObject(dest);
|
|
return sourceIsObject || destIsObject ? sourceIsObject && destIsObject ? (forEach(Object.keys(source), function(property) {
|
|
dest[property] === undefined && (dest[property] = source[property]);
|
|
}), dest) : sourceIsObject ? source : dest : source;
|
|
}
|
|
function defer(callback, delay) {
|
|
var timer = setTimeout(function() {
|
|
callback();
|
|
}, delay || 0);
|
|
return function() {
|
|
clearTimeout(timer);
|
|
};
|
|
}
|
|
function fireIf(when, callback) {
|
|
return function() {
|
|
return (isFunction(when) ? when() : when) ? callback() : undefined;
|
|
};
|
|
}
|
|
function extend(dest, source, callback) {
|
|
for (var index = -1, props = Object.keys(source), length = props.length, ask = isFunction(callback); ++index < length; ) {
|
|
var key = props[index];
|
|
dest[key] = ask ? callback(dest[key], source[key], key, dest, source) : source[key];
|
|
}
|
|
return dest;
|
|
}
|
|
function forEach(array, callback, thisArg) {
|
|
for (var i = 0, n = array.length; n > i; i++) {
|
|
var result = callback.call(thisArg, array[i], i, array);
|
|
if (result !== undefined) return result;
|
|
}
|
|
}
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
function isDefined(value) {
|
|
return value !== undefined;
|
|
}
|
|
function isArray(value) {
|
|
return value && "object" == typeof value && "number" == typeof value.length && "[object Array]" === Object.prototype.toString.call(value) || !1;
|
|
}
|
|
function isElement(value) {
|
|
return value && 1 === value.nodeType || !1;
|
|
}
|
|
function isFunction(value) {
|
|
return "function" == typeof value || !1;
|
|
}
|
|
function isObject(value) {
|
|
var type = typeof value;
|
|
return "function" === type || value && "object" === type || !1;
|
|
}
|
|
function noop() {}
|
|
function now() {
|
|
return new Date().getTime();
|
|
}
|
|
function once(callback) {
|
|
var cache, called = !1;
|
|
return function() {
|
|
return called || (cache = callback.apply(undefined, arguments), called = !0), cache;
|
|
};
|
|
}
|
|
function throttle(callback, wait, thisArg) {
|
|
var cancel = noop, last = !1;
|
|
return function() {
|
|
var time = now(), args = arguments, func = function() {
|
|
last = time, callback.apply(thisArg, args);
|
|
};
|
|
last && last + wait > time ? (cancel(), cancel = defer(func, wait)) : (last = time,
|
|
defer(func, 0));
|
|
};
|
|
}
|
|
function viewport(referenceWindow) {
|
|
var win = referenceWindow || window;
|
|
return {
|
|
height: win.innerHeight,
|
|
width: win.innerWidth
|
|
};
|
|
}
|
|
function computedStyle(element, referenceWindow) {
|
|
return (referenceWindow || window).getComputedStyle(element, null);
|
|
}
|
|
function styleProperty(style, property) {
|
|
return style.getPropertyValue(property);
|
|
}
|
|
function isDisplayed(element, style) {
|
|
style || (style = computedStyle(element));
|
|
var display = styleProperty(style, "display");
|
|
if ("none" === display) return !1;
|
|
var parent = element.parentNode;
|
|
return isElement(parent) ? isDisplayed(parent) : !0;
|
|
}
|
|
function isVisibleByStyling(element, referenceWindow) {
|
|
if (element === (referenceWindow || window).document) return !0;
|
|
if (!element || !element.parentNode) return !1;
|
|
var style = computedStyle(element, referenceWindow), visibility = styleProperty(style, "visibility");
|
|
return "hidden" === visibility || "collapse" === visibility ? !1 : isDisplayed(element, style);
|
|
}
|
|
function isInViewport(rect, viewport) {
|
|
return !rect || rect.width <= 0 || rect.height <= 0 ? !1 : rect.bottom > 0 && rect.right > 0 && rect.top < viewport.height && rect.left < viewport.width;
|
|
}
|
|
function percentage(element, referenceWindow) {
|
|
var rect = element.getBoundingClientRect(), view = viewport(referenceWindow);
|
|
if (!isInViewport(rect, view) || !isVisibleByStyling(element)) return 0;
|
|
var vh = 0, vw = 0;
|
|
return rect.top >= 0 ? vh = Math.min(rect.height, view.height - rect.top) : rect.bottom > 0 && (vh = Math.min(view.height, rect.bottom)),
|
|
rect.left >= 0 ? vw = Math.min(rect.width, view.width - rect.left) : rect.right > 0 && (vw = Math.min(view.width, rect.right)),
|
|
vh * vw / (rect.height * rect.width);
|
|
}
|
|
function isPageVisible(referenceWindow) {
|
|
return !createVisibilityApi(referenceWindow || window).isHidden();
|
|
}
|
|
function VisSense(element, config) {
|
|
if (!(this instanceof VisSense)) return new VisSense(element, config);
|
|
if (!isElement(element)) throw new Error("not an element node");
|
|
this._element = element, this._config = defaults(config, {
|
|
fullyvisible: 1,
|
|
hidden: 0,
|
|
referenceWindow: window,
|
|
percentageHook: percentage,
|
|
precision: 3,
|
|
visibilityHooks: []
|
|
});
|
|
var roundFactor = this._config.precision <= 0 ? 1 : Math.pow(10, this._config.precision || 3);
|
|
this._round = function(val) {
|
|
return Math.round(val * roundFactor) / roundFactor;
|
|
};
|
|
var visibilityApi = createVisibilityApi(this._config.referenceWindow);
|
|
this._config.visibilityHooks.push(function() {
|
|
return !visibilityApi.isHidden();
|
|
});
|
|
}
|
|
function nextState(visobj, currentState) {
|
|
var newState = visobj.state(), percentage = newState.percentage;
|
|
return currentState && percentage === currentState.percentage && currentState.percentage === currentState.previous.percentage ? currentState : newState.hidden ? VisSense.VisState.hidden(percentage, currentState) : newState.fullyvisible ? VisSense.VisState.fullyvisible(percentage, currentState) : VisSense.VisState.visible(percentage, currentState);
|
|
}
|
|
function VisMon(visobj, config) {
|
|
var _config = defaults(config, {
|
|
strategy: [ new VisMon.Strategy.PollingStrategy(), new VisMon.Strategy.EventStrategy() ],
|
|
async: !1
|
|
});
|
|
this._visobj = visobj, this._state = {}, this._started = !1;
|
|
var anyTopicName = "*#" + now();
|
|
this._pubsub = new PubSub({
|
|
async: _config.async,
|
|
anyTopicName: anyTopicName
|
|
}), this._events = [ anyTopicName, "start", "stop", "update", "hidden", "visible", "fullyvisible", "percentagechange", "visibilitychange" ],
|
|
this._strategy = new VisMon.Strategy.CompositeStrategy(_config.strategy), this._strategy.init(this),
|
|
this._pubsub.on("update", function(monitor) {
|
|
var newValue = monitor._state.percentage, oldValue = monitor._state.previous.percentage;
|
|
newValue !== oldValue && monitor._pubsub.publish("percentagechange", [ monitor, newValue, oldValue ]);
|
|
}), this._pubsub.on("update", function(monitor) {
|
|
monitor._state.code !== monitor._state.previous.code && monitor._pubsub.publish("visibilitychange", [ monitor ]);
|
|
}), this._pubsub.on("visibilitychange", function(monitor) {
|
|
monitor._state.visible && !monitor._state.previous.visible && monitor._pubsub.publish("visible", [ monitor ]);
|
|
}), this._pubsub.on("visibilitychange", function(monitor) {
|
|
monitor._state.fullyvisible && monitor._pubsub.publish("fullyvisible", [ monitor ]);
|
|
}), this._pubsub.on("visibilitychange", function(monitor) {
|
|
monitor._state.hidden && monitor._pubsub.publish("hidden", [ monitor ]);
|
|
}), forEach(this._events, function(event) {
|
|
isFunction(_config[event]) && this.on(event, _config[event]);
|
|
}, this);
|
|
}
|
|
var createVisibilityApi = function(referenceWindow) {
|
|
return function(document, undefined) {
|
|
var entry = function(propertyName, eventName) {
|
|
return {
|
|
property: propertyName,
|
|
event: eventName
|
|
};
|
|
}, event = "visibilitychange", dict = [ entry("webkitHidden", "webkit" + event), entry("msHidden", "ms" + event), entry("mozHidden", "moz" + event), entry("hidden", event) ], api = forEach(dict, function(entry) {
|
|
return document[entry.property] !== undefined ? {
|
|
isHidden: function() {
|
|
return !!document[entry.property] || !1;
|
|
},
|
|
onVisibilityChange: function(callback) {
|
|
return document.addEventListener(entry.event, callback, !1), function() {
|
|
document.removeEventListener(entry.event, callback, !1);
|
|
};
|
|
}
|
|
} : void 0;
|
|
});
|
|
return api || {
|
|
isHidden: function() {
|
|
return !1;
|
|
},
|
|
onVisibilityChange: function() {
|
|
return noop;
|
|
}
|
|
};
|
|
}((referenceWindow || window).document);
|
|
}, PubSub = function(undefined) {
|
|
function PubSub(config) {
|
|
this._cache = {}, this._onAnyCache = [], this._config = defaults(config, {
|
|
async: !1,
|
|
anyTopicName: "*"
|
|
});
|
|
}
|
|
var syncFireListeners = function(consumers, args) {
|
|
forEach(consumers, function(consumer) {
|
|
consumer(args);
|
|
});
|
|
};
|
|
return PubSub.prototype.on = function(topic, callback) {
|
|
if (!isFunction(callback)) return noop;
|
|
var applyCallback = function(args) {
|
|
return callback.apply(undefined, args || []);
|
|
}, listener = this._config.async ? async(applyCallback) : applyCallback, unregister = function(listener, array, topic) {
|
|
return function() {
|
|
var index = array.indexOf(listener);
|
|
return index > -1 ? (array.splice(index, 1), !0) : !1;
|
|
};
|
|
};
|
|
return topic === this._config.anyTopicName ? (this._onAnyCache.push(listener), unregister(listener, this._onAnyCache, "*")) : (this._cache[topic] || (this._cache[topic] = []),
|
|
this._cache[topic].push(listener), unregister(listener, this._cache[topic], topic));
|
|
}, PubSub.prototype.publish = function(topic, args) {
|
|
var listeners = (this._cache[topic] || []).concat(topic === this._config.anyTopicName ? [] : this._onAnyCache), enableAsync = !!this._config.async, syncOrAsyncPublish = enableAsync ? async(syncFireListeners) : function(listeners, args) {
|
|
return syncFireListeners(listeners, args), noop;
|
|
};
|
|
return syncOrAsyncPublish(listeners, args || []);
|
|
}, PubSub;
|
|
}();
|
|
VisSense.prototype.state = function() {
|
|
var hiddenByHook = forEach(this._config.visibilityHooks, function(hook) {
|
|
return hook(this._element) ? void 0 : VisSense.VisState.hidden(0);
|
|
}, this);
|
|
return hiddenByHook || function(visobj, element, config) {
|
|
var perc = visobj._round(config.percentageHook(element, config.referenceWindow));
|
|
return perc <= config.hidden ? VisSense.VisState.hidden(perc) : perc >= config.fullyvisible ? VisSense.VisState.fullyvisible(perc) : VisSense.VisState.visible(perc);
|
|
}(this, this._element, this._config);
|
|
}, VisSense.prototype.percentage = function() {
|
|
return this.state().percentage;
|
|
}, VisSense.prototype.element = function() {
|
|
return this._element;
|
|
}, VisSense.prototype.referenceWindow = function() {
|
|
return this._config.referenceWindow;
|
|
}, VisSense.prototype.isFullyVisible = function() {
|
|
return this.state().fullyvisible;
|
|
}, VisSense.prototype.isVisible = function() {
|
|
return this.state().visible;
|
|
}, VisSense.prototype.isHidden = function() {
|
|
return this.state().hidden;
|
|
}, VisSense.fn = VisSense.prototype, VisSense.of = function(element, config) {
|
|
return new VisSense(element, config);
|
|
};
|
|
var STATES = {
|
|
HIDDEN: [ 0, "hidden" ],
|
|
VISIBLE: [ 1, "visible" ],
|
|
FULLY_VISIBLE: [ 2, "fullyvisible" ]
|
|
};
|
|
return VisSense.VisState = function() {
|
|
function newVisState(state, percentage, previous) {
|
|
return previous && delete previous.previous, {
|
|
code: state[0],
|
|
state: state[1],
|
|
percentage: percentage,
|
|
previous: previous || {},
|
|
fullyvisible: state[0] === STATES.FULLY_VISIBLE[0],
|
|
visible: state[0] === STATES.VISIBLE[0] || state[0] === STATES.FULLY_VISIBLE[0],
|
|
hidden: state[0] === STATES.HIDDEN[0]
|
|
};
|
|
}
|
|
return {
|
|
hidden: function(percentage, previous) {
|
|
return newVisState(STATES.HIDDEN, percentage, previous);
|
|
},
|
|
visible: function(percentage, previous) {
|
|
return newVisState(STATES.VISIBLE, percentage, previous);
|
|
},
|
|
fullyvisible: function(percentage, previous) {
|
|
return newVisState(STATES.FULLY_VISIBLE, percentage, previous);
|
|
}
|
|
};
|
|
}(), VisMon.prototype.visobj = function() {
|
|
return this._visobj;
|
|
}, VisMon.prototype.publish = function(eventName, args) {
|
|
var isInternalEvent = this._events.indexOf(eventName) >= 0;
|
|
if (isInternalEvent) throw new Error('Cannot publish internal event "' + eventName + '" from external scope.');
|
|
return this._pubsub.publish(eventName, args);
|
|
}, VisMon.prototype.state = function() {
|
|
return this._state;
|
|
}, VisMon.prototype.start = function(config) {
|
|
if (this._started) return this;
|
|
var _config = defaults(config, {
|
|
async: !1
|
|
});
|
|
return this._cancelAsyncStart && this._cancelAsyncStart(), _config.async ? this.startAsync() : (this.update(),
|
|
this._pubsub.publish("start", [ this ]), this._strategy.start(this), this._started = !0,
|
|
this);
|
|
}, VisMon.prototype.startAsync = function(config) {
|
|
this._cancelAsyncStart && this._cancelAsyncStart();
|
|
var me = this, cancelAsyncStart = defer(function() {
|
|
me.start(extend(defaults(config, {}), {
|
|
async: !1
|
|
}));
|
|
});
|
|
return this._cancelAsyncStart = function() {
|
|
cancelAsyncStart(), me._cancelAsyncStart = null;
|
|
}, this;
|
|
}, VisMon.prototype.stop = function() {
|
|
this._cancelAsyncStart && this._cancelAsyncStart(), this._started && (this._strategy.stop(this),
|
|
this._pubsub.publish("stop", [ this ])), this._started = !1;
|
|
}, VisMon.prototype.update = function() {
|
|
this._state = nextState(this._visobj, this._state), this._pubsub.publish("update", [ this ]);
|
|
}, VisMon.prototype.on = function(topic, callback) {
|
|
return this._pubsub.on(topic, callback);
|
|
}, VisMon.Builder = function() {
|
|
var combineStrategies = function(config, strategies) {
|
|
var combinedStrategies = null, forceDisableStrategies = config.strategy === !1, enableStrategies = !forceDisableStrategies && (config.strategy || strategies.length > 0);
|
|
if (enableStrategies) {
|
|
var configStrategyIsDefined = !!config.strategy, configStrategyIsArray = isArray(config.strategy), configStrategyAsArray = configStrategyIsDefined ? configStrategyIsArray ? config.strategy : [ config.strategy ] : [];
|
|
combinedStrategies = configStrategyAsArray.concat(strategies);
|
|
} else combinedStrategies = forceDisableStrategies ? [] : config.strategy;
|
|
return combinedStrategies;
|
|
};
|
|
return function(visobj) {
|
|
var config = {}, strategies = [], events = [], productBuilt = !1, product = null;
|
|
return {
|
|
set: function(name, value) {
|
|
return config[name] = value, this;
|
|
},
|
|
strategy: function(strategy) {
|
|
return strategies.push(strategy), this;
|
|
},
|
|
on: function(event, handler) {
|
|
return events.push([ event, handler ]), this;
|
|
},
|
|
build: function(consumer) {
|
|
var manufacture = function() {
|
|
var combinedStrategies = combineStrategies(config, strategies);
|
|
config.strategy = combinedStrategies;
|
|
var monitor = visobj.monitor(config);
|
|
return forEach(events, function(event) {
|
|
monitor.on(event[0], event[1]);
|
|
}), productBuilt = !0, product = monitor;
|
|
}, monitor = productBuilt ? product : manufacture();
|
|
return isFunction(consumer) ? consumer(monitor) : monitor;
|
|
}
|
|
};
|
|
};
|
|
}(), VisMon.Strategy = function() {}, VisMon.Strategy.prototype.init = noop, VisMon.Strategy.prototype.start = noop,
|
|
VisMon.Strategy.prototype.stop = noop, VisMon.Strategy.CompositeStrategy = function(strategies) {
|
|
this._strategies = isArray(strategies) ? strategies : [ strategies ];
|
|
}, VisMon.Strategy.CompositeStrategy.prototype = Object.create(VisMon.Strategy.prototype),
|
|
VisMon.Strategy.CompositeStrategy.prototype.init = function(monitor) {
|
|
forEach(this._strategies, function(strategy) {
|
|
isFunction(strategy.init) && strategy.init(monitor);
|
|
});
|
|
}, VisMon.Strategy.CompositeStrategy.prototype.start = function(monitor) {
|
|
forEach(this._strategies, function(strategy) {
|
|
isFunction(strategy.start) && strategy.start(monitor);
|
|
});
|
|
}, VisMon.Strategy.CompositeStrategy.prototype.stop = function(monitor) {
|
|
forEach(this._strategies, function(strategy) {
|
|
isFunction(strategy.stop) && strategy.stop(monitor);
|
|
});
|
|
}, VisMon.Strategy.PollingStrategy = function(config) {
|
|
this._config = defaults(config, {
|
|
interval: 1e3
|
|
}), this._started = !1;
|
|
}, VisMon.Strategy.PollingStrategy.prototype = Object.create(VisMon.Strategy.prototype),
|
|
VisMon.Strategy.PollingStrategy.prototype.start = function(monitor) {
|
|
return this._started || (this._clearInterval = function(interval) {
|
|
var intervalId = setInterval(function() {
|
|
monitor.update();
|
|
}, interval);
|
|
return function() {
|
|
clearInterval(intervalId);
|
|
};
|
|
}(this._config.interval), this._started = !0), this._started;
|
|
}, VisMon.Strategy.PollingStrategy.prototype.stop = function() {
|
|
return this._started ? (this._clearInterval(), this._started = !1, !0) : !1;
|
|
}, VisMon.Strategy.EventStrategy = function(config) {
|
|
this._config = defaults(config, {
|
|
throttle: 50
|
|
}), this._config.debounce > 0 && (this._config.throttle = +this._config.debounce),
|
|
this._started = !1;
|
|
}, VisMon.Strategy.EventStrategy.prototype = Object.create(VisMon.Strategy.prototype),
|
|
VisMon.Strategy.EventStrategy.prototype.start = function(monitor) {
|
|
return this._started || (this._removeEventListeners = function(update) {
|
|
var referenceWindow = monitor.visobj().referenceWindow(), visibilityApi = createVisibilityApi(referenceWindow), removeOnVisibilityChangeEvent = visibilityApi.onVisibilityChange(update);
|
|
return referenceWindow.addEventListener("scroll", update, !1), referenceWindow.addEventListener("resize", update, !1),
|
|
referenceWindow.addEventListener("touchmove", update, !1), function() {
|
|
referenceWindow.removeEventListener("touchmove", update, !1), referenceWindow.removeEventListener("resize", update, !1),
|
|
referenceWindow.removeEventListener("scroll", update, !1), removeOnVisibilityChangeEvent();
|
|
};
|
|
}(throttle(function() {
|
|
monitor.update();
|
|
}, this._config.throttle)), this._started = !0), this._started;
|
|
}, VisMon.Strategy.EventStrategy.prototype.stop = function() {
|
|
return this._started ? (this._removeEventListeners(), this._started = !1, !0) : !1;
|
|
}, VisSense.VisMon = VisMon, VisSense.PubSub = PubSub, VisSense.fn.monitor = function(config) {
|
|
return new VisMon(this, config);
|
|
}, VisSense.Utils = {
|
|
async: async,
|
|
debounce: debounce,
|
|
defaults: defaults,
|
|
defer: defer,
|
|
extend: extend,
|
|
forEach: forEach,
|
|
fireIf: fireIf,
|
|
identity: identity,
|
|
isArray: isArray,
|
|
isDefined: isDefined,
|
|
isElement: isElement,
|
|
isFunction: isFunction,
|
|
isObject: isObject,
|
|
isPageVisible: isPageVisible,
|
|
isVisibleByStyling: isVisibleByStyling,
|
|
noop: noop,
|
|
now: now,
|
|
once: once,
|
|
throttle: throttle,
|
|
percentage: percentage,
|
|
VisibilityApi: createVisibilityApi(),
|
|
createVisibilityApi: createVisibilityApi,
|
|
_viewport: viewport,
|
|
_isInViewport: isInViewport,
|
|
_isDisplayed: isDisplayed,
|
|
_computedStyle: computedStyle,
|
|
_styleProperty: styleProperty
|
|
}, VisSense;
|
|
});
|
|
|
|
|
|
|
|
!function(a,b){"use strict";b(a,a.VisSense,a.VisSense.Utils)}(this,function(a,b,c,d){"use strict";var e=function(a,d,e){var f=0,g=null,h=e.timeLimit,i=e.percentageLimit,j=e.interval;return b.VisMon.Builder(a.visobj()).strategy(new b.VisMon.Strategy.PollingStrategy({interval:j})).on("update",function(b){var e=b.state().percentage;if(i>e)g=null;else{var j=c.now();g=g||j,f=j-g}f>=h&&(b.stop(),a.stop(),d(b))}).on("stop",function(){g=null}).build()},f=function(a,f,g){var h=c.defaults(g,{percentageLimit:1,timeLimit:1e3,interval:100,strategy:d}),i=Math.max(h.percentageLimit-.001,0),j=null,k=b.VisMon.Builder(new b(a.element(),{hidden:i,referenceWindow:a.referenceWindow()})).set("strategy",h.strategy).on("visible",function(a){null===j&&(j=e(a,f,h)),j.start()}).on("hidden",function(){null!==j&&j.stop()}).on("stop",function(){null!==j&&j.stop()}).build();return k.start(),function(){k.stop(),j=null}};b.fn.onPercentageTimeTestPassed=function(a,b){f(this,a,b)},b.fn.on50_1TestPassed=function(a,b){var d=c.extend(c.defaults(b,{interval:100}),{percentageLimit:.5,timeLimit:1e3});f(this,a,d)},b.VisMon.Strategy.PercentageTimeTestEventStrategy=function(a,b){var d=function(b,d){var e=c.noop,g=b.on("visible",c.once(function(b){e=f(b.visobj(),function(c){var e={monitorState:c.state(),testConfig:d};b.update(),b.publish(a,[b,e])},d),g()}));return function(){g(),e()}},e=c.noop;return{init:function(a){e=d(a,b)},stop:function(){e()}}}});
|