@angular/flex-layout
Version:
Angular 2 Flexbox Layout
1,263 lines (1,234 loc) • 165 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/platform-browser'), require('rxjs/add/operator/map'), require('rxjs/add/operator/filter'), require('@angular/core'), require('rxjs/BehaviorSubject'), require('@angular/common')) :
typeof define === 'function' && define.amd ? define(['exports', '@angular/platform-browser', 'rxjs/add/operator/map', 'rxjs/add/operator/filter', '@angular/core', 'rxjs/BehaviorSubject', '@angular/common'], factory) :
(factory((global.ng = global.ng || {}, global.ng.flexLayout = global.ng.flexLayout || {}),global.ng.platformBrowser,global.Rx.Observable.prototype,global.Rx.Observable.prototype,global.ng.core,global.Rx,global.ng.common));
}(this, (function (exports,_angular_platformBrowser,rxjs_add_operator_map,rxjs_add_operator_filter,_angular_core,rxjs_BehaviorSubject,_angular_common) { 'use strict';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/** Applies CSS prefixes to appropriate style keys.*/
function applyCssPrefixes(target) {
for (var key in target) {
var value = target[key];
switch (key) {
case 'display':
target['display'] = value;
// also need 'display : -webkit-box' and 'display : -ms-flexbox;'
break;
case 'flex':
target['-ms-flex'] = value;
target['-webkit-box-flex'] = value.split(" ")[0];
break;
case 'flex-direction':
value = value || "row";
target['flex-direction'] = value;
target['-ms-flex-direction'] = value;
target['-webkit-box-orient'] = toBoxOrient(value);
target['-webkit-box-direction'] = toBoxDirection(value);
break;
case 'flex-wrap':
target['-ms-flex-wrap'] = value;
break;
case 'order':
if (isNaN(value)) {
value = "0";
}
target['order'] = value;
target['-ms-flex-order'] = value;
target['-webkit-box-ordinal-group'] = toBoxOrdinal(value);
break;
case 'justify-content':
target['-ms-flex-pack'] = toBoxValue(value);
target['-webkit-box-pack'] = toBoxValue(value);
break;
case 'align-items':
target['-ms-flex-align'] = toBoxValue(value);
target['-webkit-box-align'] = toBoxValue(value);
break;
case 'align-self':
target['-ms-flex-item-align'] = toBoxValue(value);
break;
case 'align-content':
target['-ms-align-content'] = toAlignContentValue(value);
target['-ms-flex-line-pack'] = toAlignContentValue(value);
break;
}
}
return target;
}
function toAlignContentValue(value) {
switch (value) {
case "space-between":
return "justify";
case "space-around":
return "distribute";
default:
return toBoxValue(value);
}
}
/** Convert flex values flex-start, flex-end to start, end. */
function toBoxValue(value) {
if (value === void 0) { value = ""; }
return (value == 'flex-start') ? 'start' : ((value == 'flex-end') ? 'end' : value);
}
/** Convert flex Direction to Box orientation */
function toBoxOrient(flexDirection) {
if (flexDirection === void 0) { flexDirection = 'row'; }
return flexDirection.indexOf('column') === -1 ? 'horizontal' : 'vertical';
}
/** Convert flex Direction to Box direction type */
function toBoxDirection(flexDirection) {
if (flexDirection === void 0) { flexDirection = 'row'; }
return flexDirection.indexOf('reverse') !== -1 ? 'reverse' : 'normal';
}
/** Convert flex order to Box ordinal group */
function toBoxOrdinal(order) {
if (order === void 0) { order = '0'; }
var value = order ? parseInt(order) + 1 : 1;
return isNaN(value) ? "0" : value.toString();
}
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* Extends an object with the *enumerable* and *own* properties of one or more source objects,
* similar to Object.assign.
*
* @param dest The object which will have properties copied to it.
* @param sources The source objects from which properties will be copied.
*/
function extendObject(dest) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
if (dest == null) {
throw TypeError('Cannot convert undefined or null to object');
}
for (var _a = 0, sources_1 = sources; _a < sources_1.length; _a++) {
var source = sources_1[_a];
if (source != null) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
dest[key] = source[key];
}
}
}
}
return dest;
}
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.
*/
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;
}());
var getDOM = _angular_platformBrowser.__platform_browser_private__.getDOM;
/** Abstract base class for the Layout API styling directives. */
var BaseFxDirective = (function () {
/**
*
*/
function BaseFxDirective(_mediaMonitor, _elementRef, _renderer) {
this._mediaMonitor = _mediaMonitor;
this._elementRef = _elementRef;
this._renderer = _renderer;
/**
* Dictionary of input keys with associated values
*/
this._inputMap = {};
this._display = this._getDisplayStyle();
}
// *********************************************
// Accessor Methods
// *********************************************
/**
* Access the current value (if any) of the @Input property.
*/
BaseFxDirective.prototype._queryInput = function (key) {
return this._inputMap[key];
};
// *********************************************
// Lifecycle Methods
// *********************************************
BaseFxDirective.prototype.ngOnDestroy = function () {
if (this._mqActivation) {
this._mqActivation.destroy();
}
this._mediaMonitor = null;
};
// *********************************************
// Protected Methods
// *********************************************
/**
* Was the directive's default selector used ?
* If not, use the fallback value!
*/
BaseFxDirective.prototype._getDefaultVal = function (key, fallbackVal) {
var val = this._queryInput(key);
var hasDefaultVal = (val !== undefined && val !== null);
return (hasDefaultVal && val !== '') ? val : fallbackVal;
};
/**
* Quick accessor to the current HTMLElement's `display` style
* Note: this allows use to preserve the original style
* and optional restore it when the mediaQueries deactivate
*/
BaseFxDirective.prototype._getDisplayStyle = function (source) {
var element = source || this._elementRef.nativeElement;
var value = element.style['display'] || getDOM().getComputedStyle(element)['display'];
return value.trim();
};
/**
* Applies styles given via string pair or object map to the directive element.
*/
BaseFxDirective.prototype._applyStyleToElement = function (style, value, nativeElement) {
var styles = {};
var element = nativeElement || this._elementRef.nativeElement;
if (typeof style === 'string') {
styles[style] = value;
style = styles;
}
styles = applyCssPrefixes(style);
// Iterate all properties in hashMap and set styles
for (var key in styles) {
this._renderer.setElementStyle(element, key, styles[key]);
}
};
/**
* Applies styles given via string pair or object map to the directive element.
*/
BaseFxDirective.prototype._applyStyleToElements = function (style, elements) {
var _this = this;
var styles = applyCssPrefixes(style);
elements.forEach(function (el) {
// Iterate all properties in hashMap and set styles
for (var key in styles) {
_this._renderer.setElementStyle(el, key, styles[key]);
}
});
};
/**
* Save the property value; which may be a complex object.
* Complex objects support property chains
*/
BaseFxDirective.prototype._cacheInput = function (key, source) {
if (typeof source === 'object') {
for (var prop in source) {
this._inputMap[prop] = source[prop];
}
}
else {
this._inputMap[key] = source;
}
};
/**
* Build a ResponsiveActivation object used to manage subscriptions to mediaChange notifications
* and intelligent lookup of the directive's property value that corresponds to that mediaQuery
* (or closest match).
*/
BaseFxDirective.prototype._listenForMediaQueryChanges = function (key, defaultValue, onMediaQueryChange) {
var _this = this;
var keyOptions = new KeyOptions(key, defaultValue, this._inputMap);
return this._mqActivation = new ResponsiveActivation(keyOptions, this._mediaMonitor, function (change) { return onMediaQueryChange.call(_this, change); });
};
Object.defineProperty(BaseFxDirective.prototype, "childrenNodes", {
/**
* Special accessor to query for all child 'element' nodes regardless of type, class, etc.
*/
get: function () {
var obj = this._elementRef.nativeElement.childNodes;
var buffer = [];
// iterate backwards ensuring that length is an UInt32
for (var i = obj.length; i--;) {
buffer[i] = obj[i];
}
return buffer;
},
enumerable: true,
configurable: true
});
/**
* Fast validator for presence of attribute on the host element
*/
BaseFxDirective.prototype.hasKeyValue = function (key) {
return this._mqActivation.hasKeyValue(key);
};
return BaseFxDirective;
}());
var RESPONSIVE_ALIASES = [
'xs', 'gt-xs', 'sm', 'gt-sm', 'md', 'gt-md', 'lg', 'gt-lg', 'xl'
];
var RAW_DEFAULTS = [
{
alias: 'xs',
suffix: 'Xs',
overlapping: false,
mediaQuery: 'screen and (max-width: 599px)'
},
{
alias: 'gt-xs',
suffix: 'GtXs',
overlapping: true,
mediaQuery: 'screen and (min-width: 600px)'
},
{
alias: 'sm',
suffix: 'Sm',
overlapping: false,
mediaQuery: 'screen and (min-width: 600px) and (max-width: 959px)'
},
{
alias: 'gt-sm',
suffix: 'GtSm',
overlapping: true,
mediaQuery: 'screen and (min-width: 960px)'
},
{
alias: 'md',
suffix: 'Md',
overlapping: false,
mediaQuery: 'screen and (min-width: 960px) and (max-width: 1279px)'
},
{
alias: 'gt-md',
suffix: 'GtMd',
overlapping: true,
mediaQuery: 'screen and (min-width: 1280px)'
},
{
alias: 'lg',
suffix: 'Lg',
overlapping: false,
mediaQuery: 'screen and (min-width: 1280px) and (max-width: 1919px)'
},
{
alias: 'gt-lg',
suffix: 'GtLg',
overlapping: true,
mediaQuery: 'screen and (min-width: 1920px)'
},
{
alias: 'xl',
suffix: 'Xl',
overlapping: false,
mediaQuery: 'screen and (min-width: 1920px) and (max-width: 5000px)'
}
];
/**
* Opaque Token unique to the flex-layout library.
* Use this token when build a custom provider (see below).
*/
var BREAKPOINTS = new _angular_core.OpaqueToken('fxRawBreakpoints');
/**
* Provider to return observable to ALL known BreakPoint(s)
* Developers should build custom providers to override
* this default BreakPointRegistry dataset provider
* NOTE: !! custom breakpoints lists MUST contain the following aliases & suffixes:
* [xs, gt-xs, sm, gt-sm, md, gt-md, lg, gt-lg, xl]
*/
var BreakPointsProvider = {
provide: BREAKPOINTS,
useValue: RAW_DEFAULTS
};
var __decorate$2 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$2 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
/**
* Registry of 1..n MediaQuery breakpoint ranges
* This is published as a provider and may be overriden from custom, application-specific ranges
*
*/
var BreakPointRegistry = (function () {
function BreakPointRegistry(_registry) {
this._registry = _registry;
}
Object.defineProperty(BreakPointRegistry.prototype, "items", {
/**
* Accessor to raw list
*/
get: function () {
return this._registry.slice();
},
enumerable: true,
configurable: true
});
/**
* Search breakpoints by alias (e.g. gt-xs)
*/
BreakPointRegistry.prototype.findByAlias = function (alias) {
return this._registry.find(function (bp) { return bp.alias == alias; });
};
BreakPointRegistry.prototype.findByQuery = function (query) {
return this._registry.find(function (bp) { return bp.mediaQuery == query; });
};
Object.defineProperty(BreakPointRegistry.prototype, "overlappings", {
/**
* Get all the breakpoints whose ranges could overlapping `normal` ranges;
* e.g. gt-sm overlaps md, lg, and xl
*/
get: function () {
return this._registry.filter(function (it) { return it.overlapping == true; });
},
enumerable: true,
configurable: true
});
Object.defineProperty(BreakPointRegistry.prototype, "aliases", {
/**
* Get list of all registered (non-empty) breakpoint aliases
*/
get: function () {
return this._registry.map(function (it) { return it.alias; });
},
enumerable: true,
configurable: true
});
Object.defineProperty(BreakPointRegistry.prototype, "suffixes", {
/**
* Aliases are mapped to properties using suffixes
* e.g. 'gt-sm' for property 'layout' uses suffix 'GtSm'
* for property layoutGtSM.
*/
get: function () {
return this._registry.map(function (it) { return it.suffix; });
},
enumerable: true,
configurable: true
});
BreakPointRegistry = __decorate$2([
_angular_core.Injectable(),
__param(0, _angular_core.Inject(BREAKPOINTS)),
__metadata$2('design:paramtypes', [Array])
], BreakPointRegistry);
return BreakPointRegistry;
}());
/**
* Class instances emitted [to observers] for each mql notification
*/
var MediaChange = (function () {
function MediaChange(matches, // Is the mq currently activated
mediaQuery, // e.g. (min-width: 600px) and (max-width: 959px)
mqAlias, // e.g. gt-sm, md, gt-lg
suffix // e.g. GtSM, Md, GtLg
) {
if (matches === void 0) { matches = false; }
if (mediaQuery === void 0) { mediaQuery = 'all'; }
if (mqAlias === void 0) { mqAlias = ''; }
if (suffix === void 0) { suffix = ''; }
this.matches = matches;
this.mediaQuery = mediaQuery;
this.mqAlias = mqAlias;
this.suffix = suffix;
}
return MediaChange;
}());
var __decorate$3 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$3 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
/**
* MediaMonitor configures listeners to mediaQuery changes and publishes an Observable facade to
* convert mediaQuery change callbacks to subscriber notifications. These notifications will be
* performed within the ng Zone to trigger change detections and component updates.
*
* NOTE: both mediaQuery activations and de-activations are announced in notifications
*/
var MatchMedia = (function () {
function MatchMedia(_zone) {
this._zone = _zone;
this._registry = new Map();
this._source = new rxjs_BehaviorSubject.BehaviorSubject(new MediaChange(true));
this._observable$ = this._source.asObservable();
}
/**
* For the specified mediaQuery?
*/
MatchMedia.prototype.isActive = function (mediaQuery) {
if (this._registry.has(mediaQuery)) {
var mql = this._registry.get(mediaQuery);
return mql.matches;
}
return false;
};
/**
* External observers can watch for all (or a specific) mql changes.
* Typically used by the MediaQueryAdaptor; optionally available to components
* who wish to use the MediaMonitor as mediaMonitor$ observable service.
*
* NOTE: if a mediaQuery is not specified, then ALL mediaQuery activations will
* be announced.
*/
MatchMedia.prototype.observe = function (mediaQuery) {
this.registerQuery(mediaQuery);
return this._observable$.filter(function (change) {
return mediaQuery ? (change.mediaQuery === mediaQuery) : true;
});
};
/**
* Based on the BreakPointRegistry provider, register internal listeners for each unique
* mediaQuery. Each listener emits specific MediaChange data to observers
*/
MatchMedia.prototype.registerQuery = function (mediaQuery) {
var _this = this;
if (mediaQuery) {
var mql = this._registry.get(mediaQuery);
var onMQLEvent = function (e) {
_this._zone.run(function () {
var change = new MediaChange(e.matches, mediaQuery);
_this._source.next(change);
});
};
if (!mql) {
mql = this._buildMQL(mediaQuery);
mql.addListener(onMQLEvent);
this._registry.set(mediaQuery, mql);
}
if (mql.matches) {
onMQLEvent(mql); // Announce activate range for initial subscribers
}
}
};
/**
* Call window.matchMedia() to build a MediaQueryList; which
* supports 0..n listeners for activation/deactivation
*/
MatchMedia.prototype._buildMQL = function (query) {
prepareQueryCSS(query);
var canListen = !!window.matchMedia('all').addListener;
return canListen ? window.matchMedia(query) : {
matches: query === 'all' || query === '',
media: query,
addListener: function () {
},
removeListener: function () {
}
};
};
MatchMedia = __decorate$3([
_angular_core.Injectable(),
__metadata$3('design:paramtypes', [_angular_core.NgZone])
], MatchMedia);
return MatchMedia;
}());
/**
* Private global registry for all dynamically-created, injected style tags
* @see prepare(query)
*/
var ALL_STYLES = {};
/**
* For Webkit engines that only trigger the MediaQueryListListener
* when there is at least one CSS selector for the respective media query.
*
* @param query string The mediaQuery used to create a faux CSS selector
*
*/
function prepareQueryCSS(query) {
if (!ALL_STYLES[query]) {
try {
var style = document.createElement('style');
style.setAttribute('type', 'text/css');
if (!style['styleSheet']) {
var cssText = "@media " + query + " {.fx-query-test{ }}";
style.appendChild(document.createTextNode(cssText));
}
document.getElementsByTagName('head')[0].appendChild(style);
// Store in private global registry
ALL_STYLES[query] = style;
}
catch (e) {
console.error(e);
}
}
}
/**
* For the specified MediaChange, make sure it contains the breakpoint alias
* and suffix (if available).
*/
function mergeAlias(dest, source) {
return extendObject(dest, source ? {
mqAlias: source.alias,
suffix: source.suffix
} : {});
}
var __decorate$1 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$1 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
/**
* MediaMonitor uses the MatchMedia service to observe mediaQuery changes (both activations and
* deactivations). These changes are are published as MediaChange notifications.
*
* Note: all notifications will be performed within the
* ng Zone to trigger change detections and component updates.
*
* It is the MediaMonitor that:
* - auto registers all known breakpoints
* - injects alias information into each raw MediaChange event
* - provides accessor to the currently active BreakPoint
* - publish list of overlapping BreakPoint(s); used by ResponsiveActivation
*/
var MediaMonitor = (function () {
function MediaMonitor(_breakpoints, _matchMedia) {
this._breakpoints = _breakpoints;
this._matchMedia = _matchMedia;
this._registerBreakpoints();
}
Object.defineProperty(MediaMonitor.prototype, "breakpoints", {
/**
* Read-only accessor to the list of breakpoints configured in the BreakPointRegistry provider
*/
get: function () {
return this._breakpoints.items.slice();
},
enumerable: true,
configurable: true
});
Object.defineProperty(MediaMonitor.prototype, "activeOverlaps", {
get: function () {
var _this = this;
var items = this._breakpoints.overlappings.reverse();
return items.filter(function (bp) {
return _this._matchMedia.isActive(bp.mediaQuery);
});
},
enumerable: true,
configurable: true
});
Object.defineProperty(MediaMonitor.prototype, "active", {
get: function () {
var _this = this;
var found = null, items = this.breakpoints.reverse();
items.forEach(function (bp) {
if (bp.alias !== '') {
if (!found && _this._matchMedia.isActive(bp.mediaQuery)) {
found = bp;
}
}
});
var first = this.breakpoints[0];
return found || (this._matchMedia.isActive(first.mediaQuery) ? first : null);
},
enumerable: true,
configurable: true
});
/**
* For the specified mediaQuery alias, is the mediaQuery range active?
*/
MediaMonitor.prototype.isActive = function (alias) {
var bp = this._breakpoints.findByAlias(alias) || this._breakpoints.findByQuery(alias);
return this._matchMedia.isActive(bp ? bp.mediaQuery : alias);
};
/**
* External observers can watch for all (or a specific) mql changes.
* If specific breakpoint is observed, only return *activated* events
* otherwise return all events for BOTH activated + deactivated changes.
*/
MediaMonitor.prototype.observe = function (alias) {
var bp = this._breakpoints.findByAlias(alias) || this._breakpoints.findByQuery(alias);
var hasAlias = function (change) { return (bp ? change.mqAlias !== "" : true); };
// Note: the raw MediaChange events [from MatchMedia] do not contain important alias information
return this._matchMedia
.observe(bp ? bp.mediaQuery : alias)
.map(function (change) { return mergeAlias(change, bp); })
.filter(hasAlias);
};
/**
* Immediate calls to matchMedia() to establish listeners
* and prepare for immediate subscription notifications
*/
MediaMonitor.prototype._registerBreakpoints = function () {
var _this = this;
this._breakpoints.items.forEach(function (bp) {
_this._matchMedia.registerQuery(bp.mediaQuery);
});
};
MediaMonitor = __decorate$1([
_angular_core.Injectable(),
__metadata$1('design:paramtypes', [BreakPointRegistry, MatchMedia])
], MediaMonitor);
return MediaMonitor;
}());
var __decorate$5 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$5 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
/**
* Base class for MediaService and pseudo-token for
*/
var ObservableMedia = (function () {
function ObservableMedia() {
}
return ObservableMedia;
}());
/**
* Class internalizes a MatchMedia service and exposes an Subscribable and Observable interface.
* This an Observable with that exposes a feature to subscribe to mediaQuery
* changes and a validator method (`isActive(<alias>)`) to test if a mediaQuery (or alias) is
* currently active.
*
* !! Only mediaChange activations (not de-activations) are announced by the ObservableMedia
*
* This class uses the BreakPoint Registry to inject alias information into the raw MediaChange
* notification. For custom mediaQuery notifications, alias information will not be injected and
* those fields will be ''.
*
* !! This is not an actual Observable. It is a wrapper of an Observable used to publish additional
* methods like `isActive(<alias>). To access the Observable and use RxJS operators, use
* `.asObservable()` with syntax like media.asObservable().map(....).
*
* @usage
*
* // RxJS
* import 'rxjs/add/operator/filter';
* import { ObservableMedia } from '@angular/flex-layout';
*
* @Component({ ... })
* export class AppComponent {
* status : string = '';
*
* constructor( media:ObservableMedia ) {
* let onChange = (change:MediaChange) => {
* this.status = change ? `'${change.mqAlias}' = (${change.mediaQuery})` : "";
* };
*
* // Subscribe directly or access observable to use filter/map operators
* // e.g.
* // media.subscribe(onChange);
*
* media.asObservable()
* .filter((change:MediaChange) => true) // silly noop filter
* .subscribe(onChange);
* }
* }
*/
var MediaService = (function () {
function MediaService(mediaWatcher, breakpoints) {
this.mediaWatcher = mediaWatcher;
this.breakpoints = breakpoints;
this._registerBreakPoints();
this.observable$ = this._buildObservable();
}
/**
* Test if specified query/alias is active.
*/
MediaService.prototype.isActive = function (alias) {
var query = this._toMediaQuery(alias);
return this.mediaWatcher.isActive(query);
};
/**
* Proxy to the Observable subscribe method
*/
MediaService.prototype.subscribe = function (next, error, complete) {
return this.observable$.subscribe(next, error, complete);
};
/**
* Access to observable for use with operators like
* .filter(), .map(), etc.
*/
MediaService.prototype.asObservable = function () {
return this.observable$;
};
// ************************************************
// Internal Methods
// ************************************************
/**
* Register all the mediaQueries registered in the BreakPointRegistry
* This is needed so subscribers can be auto-notified of all standard, registered
* mediaQuery activations
*/
MediaService.prototype._registerBreakPoints = function () {
var _this = this;
this.breakpoints.items.forEach(function (bp) {
_this.mediaWatcher.registerQuery(bp.mediaQuery);
return bp;
});
};
/**
* Prepare internal observable
* NOTE: the raw MediaChange events [from MatchMedia] do not contain important alias information
* these must be injected into the MediaChange
*/
MediaService.prototype._buildObservable = function () {
var _this = this;
return this.mediaWatcher.observe()
.filter(function (change) {
// Only pass/announce activations (not de-activations)
return change.matches === true;
})
.map(function (change) {
// Inject associated (if any) alias information into the MediaChange event
return mergeAlias(change, _this._findByQuery(change.mediaQuery));
});
};
/**
* Breakpoint locator by alias
*/
MediaService.prototype._findByAlias = function (alias) {
return this.breakpoints.findByAlias(alias);
};
/**
* Breakpoint locator by mediaQuery
*/
MediaService.prototype._findByQuery = function (query) {
return this.breakpoints.findByQuery(query);
};
/**
* Find associated breakpoint (if any)
*/
MediaService.prototype._toMediaQuery = function (query) {
var bp = this._findByAlias(query) || this._findByQuery(query);
return bp ? bp.mediaQuery : query;
};
MediaService = __decorate$5([
_angular_core.Injectable(),
__metadata$5('design:paramtypes', [MatchMedia, BreakPointRegistry])
], MediaService);
return MediaService;
}());
/**
* Provider to return observable to ALL MediaQuery events
* Developers should build custom providers to override this default MediaQuery Observable
*/
var ObservableMediaProvider = {
provide: ObservableMedia,
useClass: MediaService,
deps: [MatchMedia, BreakPointRegistry]
};
var __decorate$4 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$4 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
/**
* *****************************************************************
* Define module for the MediaQuery API
* *****************************************************************
*/
var MediaQueriesModule = (function () {
function MediaQueriesModule() {
}
MediaQueriesModule = __decorate$4([
_angular_core.NgModule({
providers: [
MatchMedia,
BreakPointsProvider,
BreakPointRegistry,
MediaMonitor,
ObservableMediaProvider // easy subscription injectable `media$` matchMedia observable
]
}),
__metadata$4('design:paramtypes', [])
], MediaQueriesModule);
return MediaQueriesModule;
}());
var __extends$1 = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __decorate$7 = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata$7 = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var LAYOUT_VALUES = ['row', 'column', 'row-reverse', 'column-reverse'];
/**
* 'layout' flexbox styling directive
* Defines the positioning flow direction for the child elements: row or column
* Optional values: column or row (default)
* @see https://css-tricks.com/almanac/properties/f/flex-direction/
*
*/
var LayoutDirective = (function (_super) {
__extends$1(LayoutDirective, _super);
/**
*
*/
function LayoutDirective(monitor, elRef, renderer) {
_super.call(this, monitor, elRef, renderer);
this._announcer = new rxjs_BehaviorSubject.BehaviorSubject("row");
this.layout$ = this._announcer.asObservable();
}
Object.defineProperty(LayoutDirective.prototype, "layout", {
set: function (val) { this._cacheInput("layout", val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutXs", {
set: function (val) { this._cacheInput('layoutXs', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutGtXs", {
set: function (val) { this._cacheInput('layoutGtXs', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutSm", {
set: function (val) { this._cacheInput('layoutSm', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutGtSm", {
set: function (val) { this._cacheInput('layoutGtSm', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutMd", {
set: function (val) { this._cacheInput('layoutMd', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutGtMd", {
set: function (val) { this._cacheInput('layoutGtMd', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutLg", {
set: function (val) { this._cacheInput('layoutLg', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutGtLg", {
set: function (val) { this._cacheInput('layoutGtLg', val); },
enumerable: true,
configurable: true
});
Object.defineProperty(LayoutDirective.prototype, "layoutXl", {
set: function (val) { this._cacheInput('layoutXl', val); },
enumerable: true,
configurable: true
});
// *********************************************
// Lifecycle Methods
// *********************************************
/**
* On changes to any @Input properties...
* Default to use the non-responsive Input value ('fxLayout')
* Then conditionally override with the mq-activated Input's current value
*/
LayoutDirective.prototype.ngOnChanges = function (changes) {
if (changes['layout'] != null || this._mqActivation) {
this._updateWithDirection();
}
};
/**
* After the initial onChanges, build an mqActivation object that bridges
* mql change events to onMediaQueryChange handlers
*/
LayoutDirective.prototype.ngOnInit = function () {
var _this = this;
this._listenForMediaQueryChanges('layout', 'row', function (changes) {
_this._updateWithDirection(changes.value);
});
this._updateWithDirection();
};
// *********************************************
// Protected methods
// *********************************************
/**
* Validate the direction value and then update the host's inline flexbox styles
*/
LayoutDirective.prototype._updateWithDirection = function (direction) {
direction = direction || this._queryInput("layout") || 'row';
if (this._mqActivation) {
direction = this._mqActivation.activatedInput;
}
direction = this._validateValue(direction);
// Update styles and announce to subscribers the *new* direction
this._applyStyleToElement(this._buildCSS(direction));
this._announcer.next(direction);
};
/**
* Build the CSS that should be assigned to the element instance
* BUG:
*
* 1) min-height on a column flex container won’t apply to its flex item children in IE 10-11.
* Use height instead if possible; height : <xxx>vh;
*
* @todo - update all child containers to have "box-sizing: border-box"
* This way any padding or border specified on the child elements are
* laid out and drawn inside that element's specified width and height.
*
*/
LayoutDirective.prototype._buildCSS = function (value) {
return { 'display': 'flex', 'box-sizing': 'border-box', 'flex-direction': value };
};
/**
* Validate the value to be one of the acceptable value options
* Use default fallback of "row"
*/
LayoutDirective.prototype._validateValue = function (value) {
value = value ? value.toLowerCase() : '';
return LAYOUT_VALUES.find(function (x) { return x === value; }) ? value : LAYOUT_VALUES[0]; // "row"
};
__decorate$7([
_angular_core.Input('fxLayout'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layout", null);
__decorate$7([
_angular_core.Input('fxLayout.xs'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutXs", null);
__decorate$7([
_angular_core.Input('fxLayout.gt-xs'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutGtXs", null);
__decorate$7([
_angular_core.Input('fxLayout.sm'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutSm", null);
__decorate$7([
_angular_core.Input('fxLayout.gt-sm'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutGtSm", null);
__decorate$7([
_angular_core.Input('fxLayout.md'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutMd", null);
__decorate$7([
_angular_core.Input('fxLayout.gt-md'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutGtMd", null);
__decorate$7([
_angular_core.Input('fxLayout.lg'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutLg", null);
__decorate$7([
_angular_core.Input('fxLayout.gt-lg'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDirective.prototype, "layoutGtLg", null);
__decorate$7([
_angular_core.Input('fxLayout.xl'),
__metadata$7('design:type', Object),
__metadata$7('design:paramtypes', [Object])
], LayoutDi