@angular/flex-layout
Version:
Angular 2 Flexbox Layout
190 lines • 8.06 kB
JavaScript
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
import { extendObject } from '../../utils/object-extend';
export var KeyOptions = (function () {
function KeyOptions(baseKey, defaultValue, inputKeys) {
this.baseKey = baseKey;
this.defaultValue = defaultValue;
this.inputKeys = inputKeys;
}
return KeyOptions;
}());
/**
* ResponsiveActivation acts as a proxy between the MonitorMedia service (which emits mediaQuery
* changes) and the fx API directives. The MQA proxies mediaQuery change events and notifies the
* directive via the specified callback.
*
* - The MQA also determines which directive property should be used to determine the
* current change 'value'... BEFORE the original `onMediaQueryChanges()` method is called.
* - The `ngOnDestroy()` method is also head-hooked to enable auto-unsubscribe from the
* MediaQueryServices.
*
* NOTE: these interceptions enables the logic in the fx API directives to remain terse and clean.
*/
export var ResponsiveActivation = (function () {
/**
* Constructor
*/
function ResponsiveActivation(_options, _mediaMonitor, _onMediaChanges) {
this._options = _options;
this._mediaMonitor = _mediaMonitor;
this._onMediaChanges = _onMediaChanges;
this._subscribers = [];
this._subscribers = this._configureChangeObservers();
}
Object.defineProperty(ResponsiveActivation.prototype, "mediaMonitor", {
/**
* Accessor to the DI'ed directive property
* Each directive instance has a reference to the MediaMonitor which is
* used HERE to subscribe to mediaQuery change notifications.
*/
get: function () {
return this._mediaMonitor;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ResponsiveActivation.prototype, "activatedInputKey", {
/**
* Determine which directive @Input() property is currently active (for the viewport size):
* The key must be defined (in use) or fallback to the 'closest' overlapping property key
* that is defined; otherwise the default property key will be used.
* e.g.
* if `<div fxHide fxHide.gt-sm="false">` is used but the current activated mediaQuery alias
* key is `.md` then `.gt-sm` should be used instead
*/
get: function () {
return this._activatedInputKey || this._options.baseKey;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ResponsiveActivation.prototype, "activatedInput", {
/**
* Get the currently activated @Input value or the fallback default @Input value
*/
get: function () {
var key = this.activatedInputKey;
return this.hasKeyValue(key) ? this._lookupKeyValue(key) : this._options.defaultValue;
},
enumerable: true,
configurable: true
});
/**
* Fast validator for presence of attribute on the host element
*/
ResponsiveActivation.prototype.hasKeyValue = function (key) {
var value = this._options.inputKeys[key];
return typeof value !== 'undefined';
};
/**
* Remove interceptors, restore original functions, and forward the onDestroy() call
*/
ResponsiveActivation.prototype.destroy = function () {
this._subscribers.forEach(function (link) {
link.unsubscribe();
});
this._subscribers = [];
};
/**
* For each *defined* API property, register a callback to `_onMonitorEvents( )`
* Cache 1..n subscriptions for internal auto-unsubscribes when the the directive destructs
*/
ResponsiveActivation.prototype._configureChangeObservers = function () {
var _this = this;
var subscriptions = [];
this._buildRegistryMap().forEach(function (bp) {
if (_this._keyInUse(bp.key)) {
// Inject directive default property key name: to let onMediaChange() calls
// know which property is being triggered...
var buildChanges = function (change) {
change.property = _this._options.baseKey;
return change;
};
subscriptions.push(_this.mediaMonitor.observe(bp.alias)
.map(buildChanges)
.subscribe(function (change) {
_this._onMonitorEvents(change);
}));
}
});
return subscriptions;
};
/**
* Build mediaQuery key-hashmap; only for the directive properties that are actually defined/used
* in the HTML markup
*/
ResponsiveActivation.prototype._buildRegistryMap = function () {
var _this = this;
return this.mediaMonitor.breakpoints
.map(function (bp) {
return extendObject({}, bp, {
baseKey: _this._options.baseKey,
key: _this._options.baseKey + bp.suffix // e.g. layoutGtSm, layoutMd, layoutGtLg
});
})
.filter(function (bp) { return _this._keyInUse(bp.key); });
};
/**
* Synchronizes change notifications with the current mq-activated @Input and calculates the
* mq-activated input value or the default value
*/
ResponsiveActivation.prototype._onMonitorEvents = function (change) {
if (change.property == this._options.baseKey) {
change.value = this._calculateActivatedValue(change);
this._onMediaChanges(change);
}
};
/**
* Has the key been specified in the HTML markup and thus is intended
* to participate in activation processes.
*/
ResponsiveActivation.prototype._keyInUse = function (key) {
return this._lookupKeyValue(key) !== undefined;
};
/**
* Map input key associated with mediaQuery activation to closest defined input key
* then return the values associated with the targeted input property
*
* !! change events may arrive out-of-order (activate before deactivate)
* so make sure the deactivate is used ONLY when the keys match
* (since a different activate may be in use)
*/
ResponsiveActivation.prototype._calculateActivatedValue = function (current) {
var currentKey = this._options.baseKey + current.suffix; // e.g. suffix == 'GtSm',
var newKey = this._activatedInputKey; // e.g. newKey == hideGtSm
newKey = current.matches ? currentKey : ((newKey == currentKey) ? null : newKey);
this._activatedInputKey = this._validateInputKey(newKey);
return this.activatedInput;
};
/**
* For the specified input property key, validate it is defined (used in the markup)
* If not see if a overlapping mediaQuery-related input key fallback has been defined
*
* NOTE: scans in the order defined by activeOverLaps (largest viewport ranges -> smallest ranges)
*/
ResponsiveActivation.prototype._validateInputKey = function (inputKey) {
var _this = this;
var items = this.mediaMonitor.activeOverlaps;
var isMissingKey = function (key) { return !_this._keyInUse(key); };
if (isMissingKey(inputKey)) {
items.some(function (bp) {
var key = _this._options.baseKey + bp.suffix;
if (!isMissingKey(key)) {
inputKey = key;
return true; // exit .some()
}
return false;
});
}
return inputKey;
};
/**
* Get the value (if any) for the directive instances @Input property (aka key)
*/
ResponsiveActivation.prototype._lookupKeyValue = function (key) {
return this._options.inputKeys[key];
};
return ResponsiveActivation;
}());
//# sourceMappingURL=/usr/local/google/home/tinagao/WebstormProjects/caretaker/flex-layout/src/lib/flexbox/responsive/responsive-activation.js.map