This repository was archived by the owner on Jan 6, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 768
/
Copy pathbase.ts
210 lines (177 loc) · 6.32 KB
/
base.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* @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
*/
import {ElementRef, Renderer, OnDestroy} from '@angular/core';
import {applyCssPrefixes} from '../../utils/auto-prefixer';
import {buildLayoutCSS} from '../../utils/layout-validator';
import {ResponsiveActivation, KeyOptions} from '../responsive/responsive-activation';
import {MediaMonitor} from '../../media-query/media-monitor';
import {MediaQuerySubscriber} from '../../media-query/media-change';
/**
* Definition of a css style. Either a property name (e.g. "flex-basis") or an object
* map of property name and value (e.g. {display: 'none', flex-order: 5}).
*/
export type StyleDefinition = string|{[property: string]: string|number};
/** Abstract base class for the Layout API styling directives. */
export abstract class BaseFxDirective implements OnDestroy {
get hasMediaQueryListener() {
return !!this._mqActivation;
}
/**
*
*/
constructor(protected _mediaMonitor: MediaMonitor,
protected _elementRef: ElementRef,
protected _renderer: Renderer) {
this._display = this._getDisplayStyle();
}
// *********************************************
// Accessor Methods
// *********************************************
/**
* Access the current value (if any) of the @Input property.
*/
protected _queryInput(key) {
return this._inputMap[key];
}
// *********************************************
// Lifecycle Methods
// *********************************************
ngOnDestroy() {
if (this._mqActivation) {
this._mqActivation.destroy();
}
this._mediaMonitor = null;
}
// *********************************************
// Protected Methods
// *********************************************
/**
* Was the directive's default selector used ?
* If not, use the fallback value!
*/
protected _getDefaultVal(key: string, fallbackVal: any): string|boolean {
let val = this._queryInput(key);
let 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
*/
protected _getDisplayStyle(source?: HTMLElement): string {
let element: HTMLElement = source || this._elementRef.nativeElement;
let value = (element.style as any)['display'] || getComputedStyle(element)['display'];
return value.trim();
}
protected _getFlowDirection(target: any, addIfMissing = false): string {
let value = "";
if ( target ) {
let directionKeys = Object.keys(applyCssPrefixes({'flex-direction': ''}));
let findDirection = (styles) => directionKeys.reduce((direction, key) => {
return direction || styles[key];
}, null);
let immediateValue = findDirection(target['style']);
value = immediateValue || findDirection(getComputedStyle(target as Element));
if ( !immediateValue && addIfMissing ) {
value = value || 'row';
this._applyStyleToElements(buildLayoutCSS(value), [target]);
}
}
return value ? value.trim() : "row";
}
/**
* Applies styles given via string pair or object map to the directive element.
*/
protected _applyStyleToElement(style: StyleDefinition,
value?: string|number,
nativeElement?: any) {
let styles = {};
let 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 (let key in styles) {
this._renderer.setElementStyle(element, key, styles[key] as string);
}
}
/**
* Applies styles given via string pair or object map to the directive element.
*/
protected _applyStyleToElements(style: StyleDefinition, elements: HTMLElement[ ]) {
let styles = applyCssPrefixes(style);
elements.forEach(el => {
// Iterate all properties in hashMap and set styles
for (let key in styles) {
this._renderer.setElementStyle(el, key, styles[key] as string);
}
});
}
/**
* Save the property value; which may be a complex object.
* Complex objects support property chains
*/
protected _cacheInput(key?: string, source?: any) {
if (typeof source === 'object') {
for (let 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).
*/
protected _listenForMediaQueryChanges(key: string,
defaultValue: any,
onMediaQueryChange: MediaQuerySubscriber): ResponsiveActivation { // tslint:disable-line:max-line-length
if ( !this._mqActivation ) {
let keyOptions = new KeyOptions(key, defaultValue, this._inputMap);
this._mqActivation = new ResponsiveActivation(
keyOptions,
this._mediaMonitor,
(change) => onMediaQueryChange(change)
);
}
return this._mqActivation;
}
/**
* Special accessor to query for all child 'element' nodes regardless of type, class, etc.
*/
protected get childrenNodes() {
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;
}
/**
* Fast validator for presence of attribute on the host element
*/
protected hasKeyValue(key) {
return this._mqActivation.hasKeyValue(key);
}
/** Original dom Elements CSS display style */
protected _display;
/**
* MediaQuery Activation Tracker
*/
protected _mqActivation: ResponsiveActivation;
/**
* Dictionary of input keys with associated values
*/
protected _inputMap = {};
}