forked from angular/angular.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshared.js
370 lines (319 loc) · 10.2 KB
/
shared.js
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
'use strict';
/* jshint ignore:start */
var noop = angular.noop;
var copy = angular.copy;
var extend = angular.extend;
var jqLite = angular.element;
var forEach = angular.forEach;
var isArray = angular.isArray;
var isString = angular.isString;
var isObject = angular.isObject;
var isUndefined = angular.isUndefined;
var isDefined = angular.isDefined;
var isFunction = angular.isFunction;
var isElement = angular.isElement;
var ELEMENT_NODE = 1;
var COMMENT_NODE = 8;
var ADD_CLASS_SUFFIX = '-add';
var REMOVE_CLASS_SUFFIX = '-remove';
var EVENT_CLASS_PREFIX = 'ng-';
var ACTIVE_CLASS_SUFFIX = '-active';
var NG_ANIMATE_CLASSNAME = 'ng-animate';
var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
// Detect proper transitionend/animationend event names.
var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
// If unprefixed events are not supported but webkit-prefixed are, use the latter.
// Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
// Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
// but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
// Register both events in case `window.onanimationend` is not supported because of that,
// do the same for `transitionend` as Safari is likely to exhibit similar behavior.
// Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
// therefore there is no reason to test anymore for other vendor prefixes:
// http://caniuse.com/#search=transition
if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) {
CSS_PREFIX = '-webkit-';
TRANSITION_PROP = 'WebkitTransition';
TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
} else {
TRANSITION_PROP = 'transition';
TRANSITIONEND_EVENT = 'transitionend';
}
if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) {
CSS_PREFIX = '-webkit-';
ANIMATION_PROP = 'WebkitAnimation';
ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
} else {
ANIMATION_PROP = 'animation';
ANIMATIONEND_EVENT = 'animationend';
}
var DURATION_KEY = 'Duration';
var PROPERTY_KEY = 'Property';
var DELAY_KEY = 'Delay';
var TIMING_KEY = 'TimingFunction';
var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
var ANIMATION_PLAYSTATE_KEY = 'PlayState';
var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
var isPromiseLike = function(p) {
return p && p.then ? true : false;
};
function assertArg(arg, name, reason) {
if (!arg) {
throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
}
return arg;
}
function mergeClasses(a,b) {
if (!a && !b) return '';
if (!a) return b;
if (!b) return a;
if (isArray(a)) a = a.join(' ');
if (isArray(b)) b = b.join(' ');
return a + ' ' + b;
}
function packageStyles(options) {
var styles = {};
if (options && (options.to || options.from)) {
styles.to = options.to;
styles.from = options.from;
}
return styles;
}
function pendClasses(classes, fix, isPrefix) {
var className = '';
classes = isArray(classes)
? classes
: classes && isString(classes) && classes.length
? classes.split(/\s+/)
: [];
forEach(classes, function(klass, i) {
if (klass && klass.length > 0) {
className += (i > 0) ? ' ' : '';
className += isPrefix ? fix + klass
: klass + fix;
}
});
return className;
}
function removeFromArray(arr, val) {
var index = arr.indexOf(val);
if (val >= 0) {
arr.splice(index, 1);
}
}
function stripCommentsFromElement(element) {
if (element instanceof jqLite) {
switch (element.length) {
case 0:
return [];
break;
case 1:
// there is no point of stripping anything if the element
// is the only element within the jqLite wrapper.
// (it's important that we retain the element instance.)
if (element[0].nodeType === ELEMENT_NODE) {
return element;
}
break;
default:
return jqLite(extractElementNode(element));
break;
}
}
if (element.nodeType === ELEMENT_NODE) {
return jqLite(element);
}
}
function extractElementNode(element) {
if (!element[0]) return element;
for (var i = 0; i < element.length; i++) {
var elm = element[i];
if (elm.nodeType == ELEMENT_NODE) {
return elm;
}
}
}
function $$addClass($$jqLite, element, className) {
forEach(element, function(elm) {
$$jqLite.addClass(elm, className);
});
}
function $$removeClass($$jqLite, element, className) {
forEach(element, function(elm) {
$$jqLite.removeClass(elm, className);
});
}
function applyAnimationClassesFactory($$jqLite) {
return function(element, options) {
if (options.addClass) {
$$addClass($$jqLite, element, options.addClass);
options.addClass = null;
}
if (options.removeClass) {
$$removeClass($$jqLite, element, options.removeClass);
options.removeClass = null;
}
}
}
function prepareAnimationOptions(options) {
options = options || {};
if (!options.$$prepared) {
var domOperation = options.domOperation || noop;
options.domOperation = function() {
options.$$domOperationFired = true;
domOperation();
domOperation = noop;
};
options.$$prepared = true;
}
return options;
}
function applyAnimationStyles(element, options) {
applyAnimationFromStyles(element, options);
applyAnimationToStyles(element, options);
}
function applyAnimationFromStyles(element, options) {
if (options.from) {
element.css(options.from);
options.from = null;
}
}
function applyAnimationToStyles(element, options) {
if (options.to) {
element.css(options.to);
options.to = null;
}
}
function mergeAnimationOptions(element, target, newOptions) {
var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
if (newOptions.preparationClasses) {
target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);
delete newOptions.preparationClasses;
}
// noop is basically when there is no callback; otherwise something has been set
var realDomOperation = target.domOperation !== noop ? target.domOperation : null;
extend(target, newOptions);
// TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.
if (realDomOperation) {
target.domOperation = realDomOperation;
}
if (classes.addClass) {
target.addClass = classes.addClass;
} else {
target.addClass = null;
}
if (classes.removeClass) {
target.removeClass = classes.removeClass;
} else {
target.removeClass = null;
}
return target;
}
function resolveElementClasses(existing, toAdd, toRemove) {
var ADD_CLASS = 1;
var REMOVE_CLASS = -1;
var flags = {};
existing = splitClassesToLookup(existing);
toAdd = splitClassesToLookup(toAdd);
forEach(toAdd, function(value, key) {
flags[key] = ADD_CLASS;
});
toRemove = splitClassesToLookup(toRemove);
forEach(toRemove, function(value, key) {
flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;
});
var classes = {
addClass: '',
removeClass: ''
};
forEach(flags, function(val, klass) {
var prop, allow;
if (val === ADD_CLASS) {
prop = 'addClass';
allow = !existing[klass];
} else if (val === REMOVE_CLASS) {
prop = 'removeClass';
allow = existing[klass];
}
if (allow) {
if (classes[prop].length) {
classes[prop] += ' ';
}
classes[prop] += klass;
}
});
function splitClassesToLookup(classes) {
if (isString(classes)) {
classes = classes.split(' ');
}
var obj = {};
forEach(classes, function(klass) {
// sometimes the split leaves empty string values
// incase extra spaces were applied to the options
if (klass.length) {
obj[klass] = true;
}
});
return obj;
}
return classes;
}
function getDomNode(element) {
return (element instanceof angular.element) ? element[0] : element;
}
function applyGeneratedPreparationClasses(element, event, options) {
var classes = '';
if (event) {
classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
}
if (options.addClass) {
classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));
}
if (options.removeClass) {
classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));
}
if (classes.length) {
options.preparationClasses = classes;
element.addClass(classes);
}
}
function clearGeneratedClasses(element, options) {
if (options.preparationClasses) {
element.removeClass(options.preparationClasses);
options.preparationClasses = null;
}
if (options.activeClasses) {
element.removeClass(options.activeClasses);
options.activeClasses = null;
}
}
function blockTransitions(node, duration) {
// we use a negative delay value since it performs blocking
// yet it doesn't kill any existing transitions running on the
// same element which makes this safe for class-based animations
var value = duration ? '-' + duration + 's' : '';
applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
return [TRANSITION_DELAY_PROP, value];
}
function blockKeyframeAnimations(node, applyBlock) {
var value = applyBlock ? 'paused' : '';
var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
applyInlineStyle(node, [key, value]);
return [key, value];
}
function applyInlineStyle(node, styleTuple) {
var prop = styleTuple[0];
var value = styleTuple[1];
node.style[prop] = value;
}
function concatWithSpace(a,b) {
if (!a) return b;
if (!b) return a;
return a + ' ' + b;
}