UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

200 lines (191 loc) 6.81 kB
import { E as ENV } from './env-DXxsTFkM.js'; import { peekMeta } from '../@ember/-internals/meta/lib/meta.js'; import { registerDestructor } from '../@glimmer/destroyable/index.js'; import { d as valueForTag, v as validateTag, i as CURRENT_TAG } from './cache-BIlOoPA7.js'; import { a as tagMetaFor } from './meta-B9mldqPL.js'; import { g as getChainTagsForKey } from './chain-tags-C9rFtQ_x.js'; import { a as addListener, r as removeListener, s as sendEvent } from './events-DYrYz3V8.js'; const AFTER_OBSERVERS = ':change'; function changeEvent(keyName) { return keyName + AFTER_OBSERVERS; } const SYNC_DEFAULT = !ENV._DEFAULT_ASYNC_OBSERVERS; const SYNC_OBSERVERS = new Map(); const ASYNC_OBSERVERS = new Map(); /** @module @ember/object */ /** @method addObserver @static @for @ember/object/observers @param obj @param {String} path @param {Object|Function} target @param {Function|String} [method] @public */ function addObserver(obj, path, target, method, sync = SYNC_DEFAULT) { let eventName = changeEvent(path); addListener(obj, eventName, target, method, false, sync); let meta = peekMeta(obj); if (meta === null || !(meta.isPrototypeMeta(obj) || meta.isInitializing())) { activateObserver(obj, eventName, sync); } } /** @method removeObserver @static @for @ember/object/observers @param obj @param {String} path @param {Object|Function} target @param {Function|String} [method] @public */ function removeObserver(obj, path, target, method, sync = SYNC_DEFAULT) { let eventName = changeEvent(path); let meta = peekMeta(obj); if (meta === null || !(meta.isPrototypeMeta(obj) || meta.isInitializing())) { deactivateObserver(obj, eventName, sync); } removeListener(obj, eventName, target, method); } function getOrCreateActiveObserversFor(target, sync) { let observerMap = sync === true ? SYNC_OBSERVERS : ASYNC_OBSERVERS; if (!observerMap.has(target)) { observerMap.set(target, new Map()); registerDestructor(target, () => destroyObservers(target), true); } return observerMap.get(target); } function activateObserver(target, eventName, sync = false) { let activeObservers = getOrCreateActiveObserversFor(target, sync); if (activeObservers.has(eventName)) { activeObservers.get(eventName).count++; } else { let path = eventName.substring(0, eventName.lastIndexOf(':')); let tag = getChainTagsForKey(target, path, tagMetaFor(target), peekMeta(target)); activeObservers.set(eventName, { count: 1, path, tag, lastRevision: valueForTag(tag), suspended: false }); } } let DEACTIVATE_SUSPENDED = false; let SCHEDULED_DEACTIVATE = []; function deactivateObserver(target, eventName, sync = false) { if (DEACTIVATE_SUSPENDED === true) { SCHEDULED_DEACTIVATE.push([target, eventName, sync]); return; } let observerMap = sync === true ? SYNC_OBSERVERS : ASYNC_OBSERVERS; let activeObservers = observerMap.get(target); if (activeObservers !== undefined) { let observer = activeObservers.get(eventName); observer.count--; if (observer.count === 0) { activeObservers.delete(eventName); if (activeObservers.size === 0) { observerMap.delete(target); } } } } function suspendedObserverDeactivation() { DEACTIVATE_SUSPENDED = true; } function resumeObserverDeactivation() { DEACTIVATE_SUSPENDED = false; for (let [target, eventName, sync] of SCHEDULED_DEACTIVATE) { deactivateObserver(target, eventName, sync); } SCHEDULED_DEACTIVATE = []; } /** * Primarily used for cases where we are redefining a class, e.g. mixins/reopen * being applied later. Revalidates all the observers, resetting their tags. * * @private * @param target */ function revalidateObservers(target) { if (ASYNC_OBSERVERS.has(target)) { ASYNC_OBSERVERS.get(target).forEach(observer => { observer.tag = getChainTagsForKey(target, observer.path, tagMetaFor(target), peekMeta(target)); observer.lastRevision = valueForTag(observer.tag); }); } if (SYNC_OBSERVERS.has(target)) { SYNC_OBSERVERS.get(target).forEach(observer => { observer.tag = getChainTagsForKey(target, observer.path, tagMetaFor(target), peekMeta(target)); observer.lastRevision = valueForTag(observer.tag); }); } } let lastKnownRevision = 0; function flushAsyncObservers(_schedule) { let currentRevision = valueForTag(CURRENT_TAG); if (lastKnownRevision === currentRevision) { return; } lastKnownRevision = currentRevision; ASYNC_OBSERVERS.forEach((activeObservers, target) => { let meta = peekMeta(target); activeObservers.forEach((observer, eventName) => { if (!validateTag(observer.tag, observer.lastRevision)) { let sendObserver = () => { try { sendEvent(target, eventName, [target, observer.path], undefined, meta); } finally { observer.tag = getChainTagsForKey(target, observer.path, tagMetaFor(target), peekMeta(target)); observer.lastRevision = valueForTag(observer.tag); } }; if (_schedule) { _schedule('actions', sendObserver); } else { sendObserver(); } } }); }); } function flushSyncObservers() { // When flushing synchronous observers, we know that something has changed (we // only do this during a notifyPropertyChange), so there's no reason to check // a global revision. SYNC_OBSERVERS.forEach((activeObservers, target) => { let meta = peekMeta(target); activeObservers.forEach((observer, eventName) => { if (!observer.suspended && !validateTag(observer.tag, observer.lastRevision)) { try { observer.suspended = true; sendEvent(target, eventName, [target, observer.path], undefined, meta); } finally { observer.tag = getChainTagsForKey(target, observer.path, tagMetaFor(target), peekMeta(target)); observer.lastRevision = valueForTag(observer.tag); observer.suspended = false; } } }); }); } function setObserverSuspended(target, property, suspended) { let activeObservers = SYNC_OBSERVERS.get(target); if (!activeObservers) { return; } let observer = activeObservers.get(changeEvent(property)); if (observer) { observer.suspended = suspended; } } function destroyObservers(target) { if (SYNC_OBSERVERS.size > 0) SYNC_OBSERVERS.delete(target); if (ASYNC_OBSERVERS.size > 0) ASYNC_OBSERVERS.delete(target); } export { ASYNC_OBSERVERS as A, SYNC_OBSERVERS as S, activateObserver as a, addObserver as b, revalidateObservers as c, flushSyncObservers as d, resumeObserverDeactivation as e, flushAsyncObservers as f, setObserverSuspended as g, removeObserver as r, suspendedObserverDeactivation as s };