angularjs-rails 1.0.6.2 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/angularjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/angular-bootstrap-prettify.js +1 -1
- data/vendor/assets/javascripts/angular-bootstrap.js +9 -1
- data/vendor/assets/javascripts/angular-cookies.js +3 -2
- data/vendor/assets/javascripts/angular-loader.js +1 -1
- data/vendor/assets/javascripts/angular-mocks.js +33 -13
- data/vendor/assets/javascripts/angular-resource.js +1 -1
- data/vendor/assets/javascripts/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/angular-scenario.js +276 -189
- data/vendor/assets/javascripts/angular.js +276 -189
- data/vendor/assets/javascripts/unstable/angular-cookies.js +3 -2
- data/vendor/assets/javascripts/unstable/angular-loader.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-mobile.js +207 -14
- data/vendor/assets/javascripts/unstable/angular-mocks.js +61 -21
- data/vendor/assets/javascripts/unstable/angular-resource.js +25 -9
- data/vendor/assets/javascripts/unstable/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-scenario.js +1374 -773
- data/vendor/assets/javascripts/unstable/angular.js +1229 -667
- metadata +2 -6
- data/vendor/assets/javascripts/jstd-scenario-adapter-config.js +0 -6
- data/vendor/assets/javascripts/jstd-scenario-adapter.js +0 -185
- data/vendor/assets/javascripts/unstable/angular-bootstrap-prettify.js +0 -1838
- data/vendor/assets/javascripts/unstable/angular-bootstrap.js +0 -167
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.1.
|
2
|
+
* @license AngularJS v1.1.5
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -87,6 +87,27 @@ function noConflict() {
|
|
87
87
|
return a;
|
88
88
|
}
|
89
89
|
|
90
|
+
/**
|
91
|
+
* @private
|
92
|
+
* @param {*} obj
|
93
|
+
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
94
|
+
*/
|
95
|
+
function isArrayLike(obj) {
|
96
|
+
if (!obj || (typeof obj.length !== 'number')) return false;
|
97
|
+
|
98
|
+
// We have on object which has length property. Should we treat it as array?
|
99
|
+
if (typeof obj.hasOwnProperty != 'function' &&
|
100
|
+
typeof obj.constructor != 'function') {
|
101
|
+
// This is here for IE8: it is a bogus object treat it as array;
|
102
|
+
return true;
|
103
|
+
} else {
|
104
|
+
return obj instanceof JQLite || // JQLite
|
105
|
+
(jQuery && obj instanceof jQuery) || // jQuery
|
106
|
+
toString.call(obj) !== '[object Object]' || // some browser native object
|
107
|
+
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
90
111
|
/**
|
91
112
|
* @ngdoc function
|
92
113
|
* @name angular.forEach
|
@@ -114,30 +135,6 @@ function noConflict() {
|
|
114
135
|
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
115
136
|
* @returns {Object|Array} Reference to `obj`.
|
116
137
|
*/
|
117
|
-
|
118
|
-
|
119
|
-
/**
|
120
|
-
* @private
|
121
|
-
* @param {*} obj
|
122
|
-
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
123
|
-
*/
|
124
|
-
function isArrayLike(obj) {
|
125
|
-
if (!obj || (typeof obj.length !== 'number')) return false;
|
126
|
-
|
127
|
-
// We have on object which has length property. Should we treat it as array?
|
128
|
-
if (typeof obj.hasOwnProperty != 'function' &&
|
129
|
-
typeof obj.constructor != 'function') {
|
130
|
-
// This is here for IE8: it is a bogus object treat it as array;
|
131
|
-
return true;
|
132
|
-
} else {
|
133
|
-
return obj instanceof JQLite || // JQLite
|
134
|
-
(jQuery && obj instanceof jQuery) || // jQuery
|
135
|
-
toString.call(obj) !== '[object Object]' || // some browser native object
|
136
|
-
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
|
141
138
|
function forEach(obj, iterator, context) {
|
142
139
|
var key;
|
143
140
|
if (obj) {
|
@@ -221,6 +218,21 @@ function nextUid() {
|
|
221
218
|
return uid.join('');
|
222
219
|
}
|
223
220
|
|
221
|
+
|
222
|
+
/**
|
223
|
+
* Set or clear the hashkey for an object.
|
224
|
+
* @param obj object
|
225
|
+
* @param h the hashkey (!truthy to delete the hashkey)
|
226
|
+
*/
|
227
|
+
function setHashKey(obj, h) {
|
228
|
+
if (h) {
|
229
|
+
obj.$$hashKey = h;
|
230
|
+
}
|
231
|
+
else {
|
232
|
+
delete obj.$$hashKey;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
224
236
|
/**
|
225
237
|
* @ngdoc function
|
226
238
|
* @name angular.extend
|
@@ -232,8 +244,10 @@ function nextUid() {
|
|
232
244
|
*
|
233
245
|
* @param {Object} dst Destination object.
|
234
246
|
* @param {...Object} src Source object(s).
|
247
|
+
* @returns {Object} Reference to `dst`.
|
235
248
|
*/
|
236
249
|
function extend(dst) {
|
250
|
+
var h = dst.$$hashKey;
|
237
251
|
forEach(arguments, function(obj){
|
238
252
|
if (obj !== dst) {
|
239
253
|
forEach(obj, function(value, key){
|
@@ -241,6 +255,8 @@ function extend(dst) {
|
|
241
255
|
});
|
242
256
|
}
|
243
257
|
});
|
258
|
+
|
259
|
+
setHashKey(dst,h);
|
244
260
|
return dst;
|
245
261
|
}
|
246
262
|
|
@@ -600,12 +616,14 @@ function copy(source, destination){
|
|
600
616
|
destination.push(copy(source[i]));
|
601
617
|
}
|
602
618
|
} else {
|
619
|
+
var h = destination.$$hashKey;
|
603
620
|
forEach(destination, function(value, key){
|
604
621
|
delete destination[key];
|
605
622
|
});
|
606
623
|
for ( var key in source) {
|
607
624
|
destination[key] = copy(source[key]);
|
608
625
|
}
|
626
|
+
setHashKey(destination,h);
|
609
627
|
}
|
610
628
|
}
|
611
629
|
return destination;
|
@@ -645,7 +663,7 @@ function shallowCopy(src, dst) {
|
|
645
663
|
* During a property comparison, properties of `function` type and properties with names
|
646
664
|
* that begin with `$` are ignored.
|
647
665
|
*
|
648
|
-
* Scope and DOMWindow objects are being compared only
|
666
|
+
* Scope and DOMWindow objects are being compared only by identify (`===`).
|
649
667
|
*
|
650
668
|
* @param {*} o1 Object or value to compare.
|
651
669
|
* @param {*} o2 Object or value to compare.
|
@@ -705,7 +723,7 @@ function sliceArgs(args, startIndex) {
|
|
705
723
|
*
|
706
724
|
* @description
|
707
725
|
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
|
708
|
-
* `fn`). You can supply optional `args` that are
|
726
|
+
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
|
709
727
|
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
|
710
728
|
*
|
711
729
|
* @param {Object} self Context which `fn` should be evaluated in.
|
@@ -898,7 +916,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
898
916
|
*
|
899
917
|
* @description
|
900
918
|
*
|
901
|
-
* Use this directive to auto-bootstrap
|
919
|
+
* Use this directive to auto-bootstrap an application. Only
|
902
920
|
* one directive can be used per HTML document. The directive
|
903
921
|
* designates the root of the application and is typically placed
|
904
922
|
* at the root of the page.
|
@@ -981,12 +999,13 @@ function bootstrap(element, modules) {
|
|
981
999
|
}]);
|
982
1000
|
modules.unshift('ng');
|
983
1001
|
var injector = createInjector(modules);
|
984
|
-
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
|
985
|
-
function(scope, element, compile, injector) {
|
1002
|
+
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animator',
|
1003
|
+
function(scope, element, compile, injector, animator) {
|
986
1004
|
scope.$apply(function() {
|
987
1005
|
element.data('$injector', injector);
|
988
1006
|
compile(element)(scope);
|
989
1007
|
});
|
1008
|
+
animator.enabled(true);
|
990
1009
|
}]
|
991
1010
|
);
|
992
1011
|
return injector;
|
@@ -1037,7 +1056,7 @@ function bindJQuery() {
|
|
1037
1056
|
}
|
1038
1057
|
|
1039
1058
|
/**
|
1040
|
-
* throw error
|
1059
|
+
* throw error if the argument is falsy.
|
1041
1060
|
*/
|
1042
1061
|
function assertArg(arg, name, reason) {
|
1043
1062
|
if (!arg) {
|
@@ -1345,11 +1364,11 @@ function setupModuleLoader(window) {
|
|
1345
1364
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
1346
1365
|
*/
|
1347
1366
|
var version = {
|
1348
|
-
full: '1.1.
|
1367
|
+
full: '1.1.5', // all of these placeholder strings will be replaced by grunt's
|
1349
1368
|
major: 1, // package task
|
1350
1369
|
minor: 1,
|
1351
|
-
dot:
|
1352
|
-
codeName: '
|
1370
|
+
dot: 5,
|
1371
|
+
codeName: 'triangle-squarification'
|
1353
1372
|
};
|
1354
1373
|
|
1355
1374
|
|
@@ -1413,6 +1432,7 @@ function publishExternalAPI(angular){
|
|
1413
1432
|
ngController: ngControllerDirective,
|
1414
1433
|
ngForm: ngFormDirective,
|
1415
1434
|
ngHide: ngHideDirective,
|
1435
|
+
ngIf: ngIfDirective,
|
1416
1436
|
ngInclude: ngIncludeDirective,
|
1417
1437
|
ngInit: ngInitDirective,
|
1418
1438
|
ngNonBindable: ngNonBindableDirective,
|
@@ -1497,18 +1517,18 @@ function publishExternalAPI(angular){
|
|
1497
1517
|
* - [after()](http://api.jquery.com/after/)
|
1498
1518
|
* - [append()](http://api.jquery.com/append/)
|
1499
1519
|
* - [attr()](http://api.jquery.com/attr/)
|
1500
|
-
* - [bind()](http://api.jquery.com/bind/)
|
1501
|
-
* - [children()](http://api.jquery.com/children/)
|
1520
|
+
* - [bind()](http://api.jquery.com/bind/) - Does not support namespaces
|
1521
|
+
* - [children()](http://api.jquery.com/children/) - Does not support selectors
|
1502
1522
|
* - [clone()](http://api.jquery.com/clone/)
|
1503
1523
|
* - [contents()](http://api.jquery.com/contents/)
|
1504
1524
|
* - [css()](http://api.jquery.com/css/)
|
1505
1525
|
* - [data()](http://api.jquery.com/data/)
|
1506
1526
|
* - [eq()](http://api.jquery.com/eq/)
|
1507
|
-
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
1527
|
+
* - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
|
1508
1528
|
* - [hasClass()](http://api.jquery.com/hasClass/)
|
1509
1529
|
* - [html()](http://api.jquery.com/html/)
|
1510
|
-
* - [next()](http://api.jquery.com/next/)
|
1511
|
-
* - [parent()](http://api.jquery.com/parent/)
|
1530
|
+
* - [next()](http://api.jquery.com/next/) - Does not support selectors
|
1531
|
+
* - [parent()](http://api.jquery.com/parent/) - Does not support selectors
|
1512
1532
|
* - [prepend()](http://api.jquery.com/prepend/)
|
1513
1533
|
* - [prop()](http://api.jquery.com/prop/)
|
1514
1534
|
* - [ready()](http://api.jquery.com/ready/)
|
@@ -1519,8 +1539,8 @@ function publishExternalAPI(angular){
|
|
1519
1539
|
* - [replaceWith()](http://api.jquery.com/replaceWith/)
|
1520
1540
|
* - [text()](http://api.jquery.com/text/)
|
1521
1541
|
* - [toggleClass()](http://api.jquery.com/toggleClass/)
|
1522
|
-
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) -
|
1523
|
-
* - [unbind()](http://api.jquery.com/unbind/)
|
1542
|
+
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
|
1543
|
+
* - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces
|
1524
1544
|
* - [val()](http://api.jquery.com/val/)
|
1525
1545
|
* - [wrap()](http://api.jquery.com/wrap/)
|
1526
1546
|
*
|
@@ -2025,7 +2045,7 @@ function createEventHandler(element, events) {
|
|
2025
2045
|
}
|
2026
2046
|
|
2027
2047
|
event.isDefaultPrevented = function() {
|
2028
|
-
return event.defaultPrevented;
|
2048
|
+
return event.defaultPrevented || event.returnValue == false;
|
2029
2049
|
};
|
2030
2050
|
|
2031
2051
|
forEach(events[type || event.type], function(fn) {
|
@@ -2072,23 +2092,43 @@ forEach({
|
|
2072
2092
|
|
2073
2093
|
if (!eventFns) {
|
2074
2094
|
if (type == 'mouseenter' || type == 'mouseleave') {
|
2075
|
-
var
|
2095
|
+
var contains = document.body.contains || document.body.compareDocumentPosition ?
|
2096
|
+
function( a, b ) {
|
2097
|
+
var adown = a.nodeType === 9 ? a.documentElement : a,
|
2098
|
+
bup = b && b.parentNode;
|
2099
|
+
return a === bup || !!( bup && bup.nodeType === 1 && (
|
2100
|
+
adown.contains ?
|
2101
|
+
adown.contains( bup ) :
|
2102
|
+
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
|
2103
|
+
));
|
2104
|
+
} :
|
2105
|
+
function( a, b ) {
|
2106
|
+
if ( b ) {
|
2107
|
+
while ( (b = b.parentNode) ) {
|
2108
|
+
if ( b === a ) {
|
2109
|
+
return true;
|
2110
|
+
}
|
2111
|
+
}
|
2112
|
+
}
|
2113
|
+
return false;
|
2114
|
+
};
|
2076
2115
|
|
2077
|
-
events
|
2078
|
-
|
2116
|
+
events[type] = [];
|
2117
|
+
|
2118
|
+
// Refer to jQuery's implementation of mouseenter & mouseleave
|
2119
|
+
// Read about mouseenter and mouseleave:
|
2120
|
+
// http://www.quirksmode.org/js/events_mouse.html#link8
|
2121
|
+
var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"}
|
2122
|
+
bindFn(element, eventmap[type], function(event) {
|
2123
|
+
var ret, target = this, related = event.relatedTarget;
|
2124
|
+
// For mousenter/leave call the handler if related is outside the target.
|
2125
|
+
// NB: No relatedTarget if the mouse left/entered the browser window
|
2126
|
+
if ( !related || (related !== target && !contains(target, related)) ){
|
2127
|
+
handle(event, type);
|
2128
|
+
}
|
2079
2129
|
|
2080
|
-
bindFn(element, 'mouseover', function(event) {
|
2081
|
-
counter++;
|
2082
|
-
if (counter == 1) {
|
2083
|
-
handle(event, 'mouseenter');
|
2084
|
-
}
|
2085
|
-
});
|
2086
|
-
bindFn(element, 'mouseout', function(event) {
|
2087
|
-
counter --;
|
2088
|
-
if (counter == 0) {
|
2089
|
-
handle(event, 'mouseleave');
|
2090
|
-
}
|
2091
2130
|
});
|
2131
|
+
|
2092
2132
|
} else {
|
2093
2133
|
addEventListenerFn(element, type, handle);
|
2094
2134
|
events[type] = [];
|
@@ -2208,9 +2248,10 @@ forEach({
|
|
2208
2248
|
|
2209
2249
|
triggerHandler: function(element, eventName) {
|
2210
2250
|
var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
|
2251
|
+
var event;
|
2211
2252
|
|
2212
2253
|
forEach(eventFns, function(fn) {
|
2213
|
-
fn.call(element,
|
2254
|
+
fn.call(element, {preventDefault: noop});
|
2214
2255
|
});
|
2215
2256
|
}
|
2216
2257
|
}, function(fn, name){
|
@@ -2361,7 +2402,7 @@ function annotate(fn) {
|
|
2361
2402
|
}
|
2362
2403
|
} else if (isArray(fn)) {
|
2363
2404
|
last = fn.length - 1;
|
2364
|
-
assertArgFn(fn[last], 'fn')
|
2405
|
+
assertArgFn(fn[last], 'fn');
|
2365
2406
|
$inject = fn.slice(0, last);
|
2366
2407
|
} else {
|
2367
2408
|
assertArgFn(fn, 'fn', true);
|
@@ -2395,7 +2436,7 @@ function annotate(fn) {
|
|
2395
2436
|
* # Injection Function Annotation
|
2396
2437
|
*
|
2397
2438
|
* JavaScript does not have annotations, and annotations are needed for dependency injection. The
|
2398
|
-
* following
|
2439
|
+
* following are all valid ways of annotating function with injection arguments and are equivalent.
|
2399
2440
|
*
|
2400
2441
|
* <pre>
|
2401
2442
|
* // inferred (only works if code not minified/obfuscated)
|
@@ -2450,6 +2491,18 @@ function annotate(fn) {
|
|
2450
2491
|
* @returns {*} the value returned by the invoked `fn` function.
|
2451
2492
|
*/
|
2452
2493
|
|
2494
|
+
/**
|
2495
|
+
* @ngdoc method
|
2496
|
+
* @name AUTO.$injector#has
|
2497
|
+
* @methodOf AUTO.$injector
|
2498
|
+
*
|
2499
|
+
* @description
|
2500
|
+
* Allows the user to query if the particular service exist.
|
2501
|
+
*
|
2502
|
+
* @param {string} Name of the service to query.
|
2503
|
+
* @returns {boolean} returns true if injector has given service.
|
2504
|
+
*/
|
2505
|
+
|
2453
2506
|
/**
|
2454
2507
|
* @ngdoc method
|
2455
2508
|
* @name AUTO.$injector#instantiate
|
@@ -2524,7 +2577,7 @@ function annotate(fn) {
|
|
2524
2577
|
* // ...
|
2525
2578
|
* };
|
2526
2579
|
* tmpFn.$inject = ['$compile', '$rootScope'];
|
2527
|
-
* injector.invoke(
|
2580
|
+
* injector.invoke(tmpFn);
|
2528
2581
|
*
|
2529
2582
|
* // To better support inline function the inline annotation is supported
|
2530
2583
|
* injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
|
@@ -2577,7 +2630,7 @@ function annotate(fn) {
|
|
2577
2630
|
*
|
2578
2631
|
* beforeEach(module(function($provide) {
|
2579
2632
|
* $provide.provider('greet', GreetProvider);
|
2580
|
-
* });
|
2633
|
+
* }));
|
2581
2634
|
*
|
2582
2635
|
* it('should greet', inject(function(greet) {
|
2583
2636
|
* expect(greet('angular')).toEqual('Hello angular!');
|
@@ -2590,9 +2643,7 @@ function annotate(fn) {
|
|
2590
2643
|
* inject(function(greet) {
|
2591
2644
|
* expect(greet('angular')).toEqual('Ahoj angular!');
|
2592
2645
|
* });
|
2593
|
-
* )
|
2594
|
-
*
|
2595
|
-
* });
|
2646
|
+
* });
|
2596
2647
|
* </pre>
|
2597
2648
|
*/
|
2598
2649
|
|
@@ -2686,7 +2737,7 @@ function annotate(fn) {
|
|
2686
2737
|
*
|
2687
2738
|
* @param {string} name The name of the service to decorate.
|
2688
2739
|
* @param {function()} decorator This function will be invoked when the service needs to be
|
2689
|
-
*
|
2740
|
+
* instantiated. The function is called using the {@link AUTO.$injector#invoke
|
2690
2741
|
* injector.invoke} method and is therefore fully injectable. Local injection arguments:
|
2691
2742
|
*
|
2692
2743
|
* * `$delegate` - The original service instance, which can be monkey patched, configured,
|
@@ -2885,6 +2936,8 @@ function createInjector(modulesToLoad) {
|
|
2885
2936
|
var Constructor = function() {},
|
2886
2937
|
instance, returnedValue;
|
2887
2938
|
|
2939
|
+
// Check if Type is annotated and use just the given function at n-1 as parameter
|
2940
|
+
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
2888
2941
|
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
|
2889
2942
|
instance = new Constructor();
|
2890
2943
|
returnedValue = invoke(Type, instance, locals);
|
@@ -2896,7 +2949,10 @@ function createInjector(modulesToLoad) {
|
|
2896
2949
|
invoke: invoke,
|
2897
2950
|
instantiate: instantiate,
|
2898
2951
|
get: getService,
|
2899
|
-
annotate: annotate
|
2952
|
+
annotate: annotate,
|
2953
|
+
has: function(name) {
|
2954
|
+
return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
|
2955
|
+
}
|
2900
2956
|
};
|
2901
2957
|
}
|
2902
2958
|
}
|
@@ -3022,18 +3078,14 @@ function $AnimationProvider($provide) {
|
|
3022
3078
|
*/
|
3023
3079
|
return function $animation(name) {
|
3024
3080
|
if (name) {
|
3025
|
-
|
3026
|
-
|
3027
|
-
|
3028
|
-
//TODO(misko): this is a hack! we should have a better way to test if the injector has a given key.
|
3029
|
-
// The issue is that the animations are optional, and if not present they should be silently ignored.
|
3030
|
-
// The proper way to fix this is to add API onto the injector so that we can ask to see if a given
|
3031
|
-
// animation is supported.
|
3081
|
+
var animationName = camelCase(name) + suffix;
|
3082
|
+
if ($injector.has(animationName)) {
|
3083
|
+
return $injector.get(animationName);
|
3032
3084
|
}
|
3033
3085
|
}
|
3034
|
-
}
|
3086
|
+
};
|
3035
3087
|
}];
|
3036
|
-
}
|
3088
|
+
}
|
3037
3089
|
|
3038
3090
|
// NOTE: this is a pseudo directive.
|
3039
3091
|
|
@@ -3043,18 +3095,21 @@ function $AnimationProvider($provide) {
|
|
3043
3095
|
*
|
3044
3096
|
* @description
|
3045
3097
|
* The `ngAnimate` directive works as an attribute that is attached alongside pre-existing directives.
|
3046
|
-
* It effects how the directive will perform DOM manipulation. This allows for complex animations to take place
|
3047
|
-
* without
|
3098
|
+
* It effects how the directive will perform DOM manipulation. This allows for complex animations to take place
|
3099
|
+
* without burdening the directive which uses the animation with animation details. The built in directives
|
3048
3100
|
* `ngRepeat`, `ngInclude`, `ngSwitch`, `ngShow`, `ngHide` and `ngView` already accept `ngAnimate` directive.
|
3049
3101
|
* Custom directives can take advantage of animation through {@link ng.$animator $animator service}.
|
3050
3102
|
*
|
3051
3103
|
* Below is a more detailed breakdown of the supported callback events provided by pre-exisitng ng directives:
|
3052
3104
|
*
|
3053
|
-
*
|
3054
|
-
*
|
3055
|
-
*
|
3056
|
-
*
|
3057
|
-
*
|
3105
|
+
* | Directive | Supported Animations |
|
3106
|
+
* |========================================================== |====================================================|
|
3107
|
+
* | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
|
3108
|
+
* | {@link ng.directive:ngView#animations ngView} | enter and leave |
|
3109
|
+
* | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
|
3110
|
+
* | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
|
3111
|
+
* | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
|
3112
|
+
* | {@link ng.directive:ngShow#animations ngShow & ngHide} | show and hide |
|
3058
3113
|
*
|
3059
3114
|
* You can find out more information about animations upon visiting each directive page.
|
3060
3115
|
*
|
@@ -3075,23 +3130,26 @@ function $AnimationProvider($provide) {
|
|
3075
3130
|
*
|
3076
3131
|
* The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned.
|
3077
3132
|
*
|
3133
|
+
* Keep in mind that if an animation is running, no child element of such animation can also be animated.
|
3134
|
+
*
|
3078
3135
|
* <h2>CSS-defined Animations</h2>
|
3079
|
-
* By default, ngAnimate attaches two
|
3080
|
-
*
|
3081
|
-
*
|
3136
|
+
* By default, ngAnimate attaches two CSS classes per animation event to the DOM element to achieve the animation.
|
3137
|
+
* It is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions as
|
3138
|
+
* well as CSS animations.
|
3139
|
+
*
|
3140
|
+
* The following code below demonstrates how to perform animations using **CSS transitions** with ngAnimate:
|
3082
3141
|
*
|
3083
3142
|
* <pre>
|
3084
3143
|
* <style type="text/css">
|
3085
3144
|
* /*
|
3086
|
-
* The animate-enter
|
3145
|
+
* The animate-enter CSS class is the event name that you
|
3087
3146
|
* have provided within the ngAnimate attribute.
|
3088
3147
|
* */
|
3089
|
-
* .animate-enter
|
3148
|
+
* .animate-enter {
|
3090
3149
|
* -webkit-transition: 1s linear all; /* Safari/Chrome */
|
3091
3150
|
* -moz-transition: 1s linear all; /* Firefox */
|
3092
|
-
* -ms-transition: 1s linear all; /* IE10 */
|
3093
3151
|
* -o-transition: 1s linear all; /* Opera */
|
3094
|
-
* transition: 1s linear all; /* Future Browsers */
|
3152
|
+
* transition: 1s linear all; /* IE10+ and Future Browsers */
|
3095
3153
|
*
|
3096
3154
|
* /* The animation preparation code */
|
3097
3155
|
* opacity: 0;
|
@@ -3102,7 +3160,7 @@ function $AnimationProvider($provide) {
|
|
3102
3160
|
* classes together to avoid any CSS-specificity
|
3103
3161
|
* conflicts
|
3104
3162
|
* */
|
3105
|
-
* .animate-enter
|
3163
|
+
* .animate-enter.animate-enter-active {
|
3106
3164
|
* /* The animation code itself */
|
3107
3165
|
* opacity: 1;
|
3108
3166
|
* }
|
@@ -3111,16 +3169,49 @@ function $AnimationProvider($provide) {
|
|
3111
3169
|
* <div ng-directive ng-animate="{enter: 'animate-enter'}"></div>
|
3112
3170
|
* </pre>
|
3113
3171
|
*
|
3114
|
-
*
|
3115
|
-
*
|
3172
|
+
* The following code below demonstrates how to perform animations using **CSS animations** with ngAnimate:
|
3173
|
+
*
|
3174
|
+
* <pre>
|
3175
|
+
* <style type="text/css">
|
3176
|
+
* .animate-enter {
|
3177
|
+
* -webkit-animation: enter_sequence 1s linear; /* Safari/Chrome */
|
3178
|
+
* -moz-animation: enter_sequence 1s linear; /* Firefox */
|
3179
|
+
* -o-animation: enter_sequence 1s linear; /* Opera */
|
3180
|
+
* animation: enter_sequence 1s linear; /* IE10+ and Future Browsers */
|
3181
|
+
* }
|
3182
|
+
* @-webkit-keyframes enter_sequence {
|
3183
|
+
* from { opacity:0; }
|
3184
|
+
* to { opacity:1; }
|
3185
|
+
* }
|
3186
|
+
* @-moz-keyframes enter_sequence {
|
3187
|
+
* from { opacity:0; }
|
3188
|
+
* to { opacity:1; }
|
3189
|
+
* }
|
3190
|
+
* @-o-keyframes enter_sequence {
|
3191
|
+
* from { opacity:0; }
|
3192
|
+
* to { opacity:1; }
|
3193
|
+
* }
|
3194
|
+
* @keyframes enter_sequence {
|
3195
|
+
* from { opacity:0; }
|
3196
|
+
* to { opacity:1; }
|
3197
|
+
* }
|
3198
|
+
* </style>
|
3199
|
+
*
|
3200
|
+
* <div ng-directive ng-animate="{enter: 'animate-enter'}"></div>
|
3201
|
+
* </pre>
|
3202
|
+
*
|
3203
|
+
* ngAnimate will first examine any CSS animation code and then fallback to using CSS transitions.
|
3204
|
+
*
|
3205
|
+
* Upon DOM mutation, the event class is added first, then the browser is allowed to reflow the content and then,
|
3206
|
+
* the active class is added to trigger the animation. The ngAnimate directive will automatically extract the duration
|
3116
3207
|
* of the animation to determine when the animation ends. Once the animation is over then both CSS classes will be
|
3117
|
-
* removed from the DOM. If a browser does not support CSS transitions then the animation will start and end
|
3208
|
+
* removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
|
3118
3209
|
* immediately resulting in a DOM element that is at it's final state. This final state is when the DOM element
|
3119
|
-
* has no CSS animation classes surrounding it.
|
3210
|
+
* has no CSS transition/animation classes surrounding it.
|
3120
3211
|
*
|
3121
3212
|
* <h2>JavaScript-defined Animations</h2>
|
3122
|
-
* In the event that you do not want to use CSS3 animations or if you wish to offer animations to browsers that do not
|
3123
|
-
* yet support them, then you can make use of JavaScript animations defined inside
|
3213
|
+
* In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations to browsers that do not
|
3214
|
+
* yet support them, then you can make use of JavaScript animations defined inside of your AngularJS module.
|
3124
3215
|
*
|
3125
3216
|
* <pre>
|
3126
3217
|
* var ngModule = angular.module('YourApp', []);
|
@@ -3147,8 +3238,8 @@ function $AnimationProvider($provide) {
|
|
3147
3238
|
*
|
3148
3239
|
* As you can see, the JavaScript code follows a similar template to the CSS3 animations. Once defined, the animation
|
3149
3240
|
* can be used in the same way with the ngAnimate attribute. Keep in mind that, when using JavaScript-enabled
|
3150
|
-
* animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're using
|
3151
|
-
*
|
3241
|
+
* animations, ngAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're not using
|
3242
|
+
* CSS animations) to animated the element, but it will not attempt to find any CSS3 transition or animation duration/delay values.
|
3152
3243
|
* It will instead close off the animation once the provided done function is executed. So it's important that you
|
3153
3244
|
* make sure your animations remember to fire off the done function once the animations are complete.
|
3154
3245
|
*
|
@@ -3156,151 +3247,214 @@ function $AnimationProvider($provide) {
|
|
3156
3247
|
*
|
3157
3248
|
*/
|
3158
3249
|
|
3159
|
-
/**
|
3160
|
-
* @ngdoc function
|
3161
|
-
* @name ng.$animator
|
3162
|
-
*
|
3163
|
-
* @description
|
3164
|
-
* The $animator service provides the DOM manipulation API which is decorated with animations.
|
3165
|
-
*
|
3166
|
-
* @param {Scope} scope the scope for the ng-animate.
|
3167
|
-
* @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are
|
3168
|
-
* passed into the linking function of the directive using the `$animator`.)
|
3169
|
-
* @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods.
|
3170
|
-
*/
|
3171
3250
|
var $AnimatorProvider = function() {
|
3172
|
-
|
3173
|
-
|
3174
|
-
var ngAnimateAttr = attrs.ngAnimate;
|
3175
|
-
var animator = {};
|
3251
|
+
var NG_ANIMATE_CONTROLLER = '$ngAnimateController';
|
3252
|
+
var rootAnimateController = {running:true};
|
3176
3253
|
|
3177
|
-
|
3178
|
-
|
3179
|
-
|
3180
|
-
* @methodOf ng.$animator
|
3181
|
-
* @function
|
3182
|
-
*
|
3183
|
-
* @description
|
3184
|
-
* Injects the element object into the DOM (inside of the parent element) and then runs the enter animation.
|
3185
|
-
*
|
3186
|
-
* @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
|
3187
|
-
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation
|
3188
|
-
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the enter animation
|
3189
|
-
*/
|
3190
|
-
animator.enter = animateActionFactory('enter', insert, noop);
|
3191
|
-
|
3192
|
-
/**
|
3193
|
-
* @ngdoc function
|
3194
|
-
* @name ng.animator#leave
|
3195
|
-
* @methodOf ng.$animator
|
3196
|
-
* @function
|
3197
|
-
*
|
3198
|
-
* @description
|
3199
|
-
* Runs the leave animation operation and, upon completion, removes the element from the DOM.
|
3200
|
-
*
|
3201
|
-
* @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
|
3202
|
-
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation
|
3203
|
-
*/
|
3204
|
-
animator.leave = animateActionFactory('leave', noop, remove);
|
3205
|
-
|
3206
|
-
/**
|
3207
|
-
* @ngdoc function
|
3208
|
-
* @name ng.animator#move
|
3209
|
-
* @methodOf ng.$animator
|
3210
|
-
* @function
|
3211
|
-
*
|
3212
|
-
* @description
|
3213
|
-
* Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or
|
3214
|
-
* add the element directly after the after element if present. Then the move animation will be run.
|
3215
|
-
*
|
3216
|
-
* @param {jQuery/jqLite element} element the element that will be the focus of the move animation
|
3217
|
-
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation
|
3218
|
-
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the move animation
|
3219
|
-
*/
|
3220
|
-
animator.move = animateActionFactory('move', move, noop);
|
3254
|
+
this.$get = ['$animation', '$window', '$sniffer', '$rootElement', '$rootScope',
|
3255
|
+
function($animation, $window, $sniffer, $rootElement, $rootScope) {
|
3256
|
+
$rootElement.data(NG_ANIMATE_CONTROLLER, rootAnimateController);
|
3221
3257
|
|
3222
|
-
|
3223
|
-
|
3224
|
-
|
3225
|
-
|
3226
|
-
|
3227
|
-
|
3228
|
-
|
3229
|
-
|
3230
|
-
|
3231
|
-
|
3232
|
-
|
3233
|
-
|
3234
|
-
|
3235
|
-
|
3236
|
-
|
3237
|
-
|
3238
|
-
|
3239
|
-
|
3240
|
-
|
3241
|
-
|
3242
|
-
|
3243
|
-
|
3244
|
-
|
3245
|
-
|
3246
|
-
|
3258
|
+
/**
|
3259
|
+
* @ngdoc function
|
3260
|
+
* @name ng.$animator
|
3261
|
+
* @function
|
3262
|
+
*
|
3263
|
+
* @description
|
3264
|
+
* The $animator.create service provides the DOM manipulation API which is decorated with animations.
|
3265
|
+
*
|
3266
|
+
* @param {Scope} scope the scope for the ng-animate.
|
3267
|
+
* @param {Attributes} attr the attributes object which contains the ngAnimate key / value pair. (The attributes are
|
3268
|
+
* passed into the linking function of the directive using the `$animator`.)
|
3269
|
+
* @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods.
|
3270
|
+
*/
|
3271
|
+
var AnimatorService = function(scope, attrs) {
|
3272
|
+
var animator = {};
|
3273
|
+
|
3274
|
+
/**
|
3275
|
+
* @ngdoc function
|
3276
|
+
* @name ng.animator#enter
|
3277
|
+
* @methodOf ng.$animator
|
3278
|
+
* @function
|
3279
|
+
*
|
3280
|
+
* @description
|
3281
|
+
* Injects the element object into the DOM (inside of the parent element) and then runs the enter animation.
|
3282
|
+
*
|
3283
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
|
3284
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation
|
3285
|
+
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the enter animation
|
3286
|
+
*/
|
3287
|
+
animator.enter = animateActionFactory('enter', insert, noop);
|
3288
|
+
|
3289
|
+
/**
|
3290
|
+
* @ngdoc function
|
3291
|
+
* @name ng.animator#leave
|
3292
|
+
* @methodOf ng.$animator
|
3293
|
+
* @function
|
3294
|
+
*
|
3295
|
+
* @description
|
3296
|
+
* Runs the leave animation operation and, upon completion, removes the element from the DOM.
|
3297
|
+
*
|
3298
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
|
3299
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation
|
3300
|
+
*/
|
3301
|
+
animator.leave = animateActionFactory('leave', noop, remove);
|
3302
|
+
|
3303
|
+
/**
|
3304
|
+
* @ngdoc function
|
3305
|
+
* @name ng.animator#move
|
3306
|
+
* @methodOf ng.$animator
|
3307
|
+
* @function
|
3308
|
+
*
|
3309
|
+
* @description
|
3310
|
+
* Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or
|
3311
|
+
* add the element directly after the after element if present. Then the move animation will be run.
|
3312
|
+
*
|
3313
|
+
* @param {jQuery/jqLite element} element the element that will be the focus of the move animation
|
3314
|
+
* @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation
|
3315
|
+
* @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the move animation
|
3316
|
+
*/
|
3317
|
+
animator.move = animateActionFactory('move', move, noop);
|
3318
|
+
|
3319
|
+
/**
|
3320
|
+
* @ngdoc function
|
3321
|
+
* @name ng.animator#show
|
3322
|
+
* @methodOf ng.$animator
|
3323
|
+
* @function
|
3324
|
+
*
|
3325
|
+
* @description
|
3326
|
+
* Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after.
|
3327
|
+
*
|
3328
|
+
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
|
3329
|
+
*/
|
3330
|
+
animator.show = animateActionFactory('show', show, noop);
|
3331
|
+
|
3332
|
+
/**
|
3333
|
+
* @ngdoc function
|
3334
|
+
* @name ng.animator#hide
|
3335
|
+
* @methodOf ng.$animator
|
3336
|
+
*
|
3337
|
+
* @description
|
3338
|
+
* Starts the hide animation first and sets the CSS `display` property to `none` upon completion.
|
3339
|
+
*
|
3340
|
+
* @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
|
3341
|
+
*/
|
3342
|
+
animator.hide = animateActionFactory('hide', noop, hide);
|
3247
3343
|
|
3248
|
-
|
3249
|
-
|
3250
|
-
|
3251
|
-
|
3252
|
-
|
3253
|
-
|
3344
|
+
/**
|
3345
|
+
* @ngdoc function
|
3346
|
+
* @name ng.animator#animate
|
3347
|
+
* @methodOf ng.$animator
|
3348
|
+
*
|
3349
|
+
* @description
|
3350
|
+
* Triggers a custom animation event to be executed on the given element
|
3351
|
+
*
|
3352
|
+
* @param {jQuery/jqLite element} element that will be animated
|
3353
|
+
*/
|
3354
|
+
animator.animate = function(event, element) {
|
3355
|
+
animateActionFactory(event, noop, noop)(element);
|
3356
|
+
}
|
3357
|
+
return animator;
|
3358
|
+
|
3359
|
+
function animateActionFactory(type, beforeFn, afterFn) {
|
3360
|
+
return function(element, parent, after) {
|
3361
|
+
var ngAnimateValue = scope.$eval(attrs.ngAnimate);
|
3362
|
+
var className = ngAnimateValue
|
3363
|
+
? isObject(ngAnimateValue) ? ngAnimateValue[type] : ngAnimateValue + '-' + type
|
3364
|
+
: '';
|
3365
|
+
var animationPolyfill = $animation(className);
|
3366
|
+
var polyfillSetup = animationPolyfill && animationPolyfill.setup;
|
3367
|
+
var polyfillStart = animationPolyfill && animationPolyfill.start;
|
3368
|
+
var polyfillCancel = animationPolyfill && animationPolyfill.cancel;
|
3369
|
+
|
3370
|
+
if (!className) {
|
3371
|
+
beforeFn(element, parent, after);
|
3372
|
+
afterFn(element, parent, after);
|
3373
|
+
} else {
|
3374
|
+
var activeClassName = className + '-active';
|
3254
3375
|
|
3255
|
-
|
3256
|
-
|
3376
|
+
if (!parent) {
|
3377
|
+
parent = after ? after.parent() : element.parent();
|
3378
|
+
}
|
3379
|
+
if ((!$sniffer.transitions && !polyfillSetup && !polyfillStart) ||
|
3380
|
+
(parent.inheritedData(NG_ANIMATE_CONTROLLER) || noop).running) {
|
3381
|
+
beforeFn(element, parent, after);
|
3382
|
+
afterFn(element, parent, after);
|
3383
|
+
return;
|
3384
|
+
}
|
3257
3385
|
|
3258
|
-
|
3259
|
-
|
3260
|
-
|
3261
|
-
|
3262
|
-
|
3263
|
-
} else {
|
3264
|
-
var setupClass = className + '-setup';
|
3265
|
-
var startClass = className + '-start';
|
3386
|
+
var animationData = element.data(NG_ANIMATE_CONTROLLER) || {};
|
3387
|
+
if(animationData.running) {
|
3388
|
+
(polyfillCancel || noop)(element);
|
3389
|
+
animationData.done();
|
3390
|
+
}
|
3266
3391
|
|
3267
|
-
|
3268
|
-
|
3392
|
+
element.data(NG_ANIMATE_CONTROLLER, {running:true, done:done});
|
3393
|
+
element.addClass(className);
|
3269
3394
|
beforeFn(element, parent, after);
|
3270
|
-
|
3271
|
-
return;
|
3272
|
-
}
|
3395
|
+
if (element.length == 0) return done();
|
3273
3396
|
|
3274
|
-
|
3275
|
-
beforeFn(element, parent, after);
|
3276
|
-
if (element.length == 0) return done();
|
3397
|
+
var memento = (polyfillSetup || noop)(element);
|
3277
3398
|
|
3278
|
-
|
3399
|
+
// $window.setTimeout(beginAnimation, 0); this was causing the element not to animate
|
3400
|
+
// keep at 1 for animation dom rerender
|
3401
|
+
$window.setTimeout(beginAnimation, 1);
|
3402
|
+
}
|
3279
3403
|
|
3280
|
-
|
3281
|
-
|
3282
|
-
|
3404
|
+
function parseMaxTime(str) {
|
3405
|
+
var total = 0, values = isString(str) ? str.split(/\s*,\s*/) : [];
|
3406
|
+
forEach(values, function(value) {
|
3407
|
+
total = Math.max(parseFloat(value) || 0, total);
|
3408
|
+
});
|
3409
|
+
return total;
|
3410
|
+
}
|
3283
3411
|
|
3284
3412
|
function beginAnimation() {
|
3285
|
-
element.addClass(
|
3413
|
+
element.addClass(activeClassName);
|
3286
3414
|
if (polyfillStart) {
|
3287
3415
|
polyfillStart(element, done, memento);
|
3288
3416
|
} else if (isFunction($window.getComputedStyle)) {
|
3417
|
+
//one day all browsers will have these properties
|
3418
|
+
var w3cAnimationProp = 'animation';
|
3419
|
+
var w3cTransitionProp = 'transition';
|
3420
|
+
|
3421
|
+
//but some still use vendor-prefixed styles
|
3422
|
+
var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation';
|
3289
3423
|
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
|
3290
|
-
var w3cTransitionProp = 'transition'; //one day all browsers will have this
|
3291
3424
|
|
3292
|
-
var durationKey = 'Duration'
|
3293
|
-
|
3425
|
+
var durationKey = 'Duration',
|
3426
|
+
delayKey = 'Delay',
|
3427
|
+
animationIterationCountKey = 'IterationCount',
|
3428
|
+
duration = 0;
|
3429
|
+
|
3294
3430
|
//we want all the styles defined before and after
|
3431
|
+
var ELEMENT_NODE = 1;
|
3295
3432
|
forEach(element, function(element) {
|
3296
|
-
|
3297
|
-
|
3298
|
-
|
3299
|
-
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3433
|
+
if (element.nodeType == ELEMENT_NODE) {
|
3434
|
+
var w3cProp = w3cTransitionProp,
|
3435
|
+
vendorProp = vendorTransitionProp,
|
3436
|
+
iterations = 1,
|
3437
|
+
elementStyles = $window.getComputedStyle(element) || {};
|
3438
|
+
|
3439
|
+
//use CSS Animations over CSS Transitions
|
3440
|
+
if(parseFloat(elementStyles[w3cAnimationProp + durationKey]) > 0 ||
|
3441
|
+
parseFloat(elementStyles[vendorAnimationProp + durationKey]) > 0) {
|
3442
|
+
w3cProp = w3cAnimationProp;
|
3443
|
+
vendorProp = vendorAnimationProp;
|
3444
|
+
iterations = Math.max(parseInt(elementStyles[w3cProp + animationIterationCountKey]) || 0,
|
3445
|
+
parseInt(elementStyles[vendorProp + animationIterationCountKey]) || 0,
|
3446
|
+
iterations);
|
3447
|
+
}
|
3303
3448
|
|
3449
|
+
var parsedDelay = Math.max(parseMaxTime(elementStyles[w3cProp + delayKey]),
|
3450
|
+
parseMaxTime(elementStyles[vendorProp + delayKey]));
|
3451
|
+
|
3452
|
+
var parsedDuration = Math.max(parseMaxTime(elementStyles[w3cProp + durationKey]),
|
3453
|
+
parseMaxTime(elementStyles[vendorProp + durationKey]));
|
3454
|
+
|
3455
|
+
duration = Math.max(parsedDelay + (iterations * parsedDuration), duration);
|
3456
|
+
}
|
3457
|
+
});
|
3304
3458
|
$window.setTimeout(done, duration * 1000);
|
3305
3459
|
} else {
|
3306
3460
|
done();
|
@@ -3308,40 +3462,65 @@ var $AnimatorProvider = function() {
|
|
3308
3462
|
}
|
3309
3463
|
|
3310
3464
|
function done() {
|
3311
|
-
|
3312
|
-
|
3313
|
-
|
3465
|
+
if(!done.run) {
|
3466
|
+
done.run = true;
|
3467
|
+
afterFn(element, parent, after);
|
3468
|
+
element.removeClass(className);
|
3469
|
+
element.removeClass(activeClassName);
|
3470
|
+
element.removeData(NG_ANIMATE_CONTROLLER);
|
3471
|
+
}
|
3314
3472
|
}
|
3473
|
+
};
|
3474
|
+
}
|
3475
|
+
|
3476
|
+
function show(element) {
|
3477
|
+
element.css('display', '');
|
3478
|
+
}
|
3479
|
+
|
3480
|
+
function hide(element) {
|
3481
|
+
element.css('display', 'none');
|
3482
|
+
}
|
3483
|
+
|
3484
|
+
function insert(element, parent, after) {
|
3485
|
+
if (after) {
|
3486
|
+
after.after(element);
|
3487
|
+
} else {
|
3488
|
+
parent.append(element);
|
3315
3489
|
}
|
3316
3490
|
}
|
3317
|
-
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3321
|
-
|
3322
|
-
|
3323
|
-
|
3324
|
-
|
3325
|
-
|
3326
|
-
|
3491
|
+
|
3492
|
+
function remove(element) {
|
3493
|
+
element.remove();
|
3494
|
+
}
|
3495
|
+
|
3496
|
+
function move(element, parent, after) {
|
3497
|
+
// Do not remove element before insert. Removing will cause data associated with the
|
3498
|
+
// element to be dropped. Insert will implicitly do the remove.
|
3499
|
+
insert(element, parent, after);
|
3500
|
+
}
|
3501
|
+
};
|
3327
3502
|
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3503
|
+
/**
|
3504
|
+
* @ngdoc function
|
3505
|
+
* @name ng.animator#enabled
|
3506
|
+
* @methodOf ng.$animator
|
3507
|
+
* @function
|
3508
|
+
*
|
3509
|
+
* @param {Boolean=} If provided then set the animation on or off.
|
3510
|
+
* @return {Boolean} Current animation state.
|
3511
|
+
*
|
3512
|
+
* @description
|
3513
|
+
* Globally enables/disables animations.
|
3514
|
+
*
|
3515
|
+
*/
|
3516
|
+
AnimatorService.enabled = function(value) {
|
3517
|
+
if (arguments.length) {
|
3518
|
+
rootAnimateController.running = !value;
|
3333
3519
|
}
|
3334
|
-
|
3335
|
-
|
3336
|
-
function remove(element) {
|
3337
|
-
element.remove();
|
3338
|
-
}
|
3520
|
+
return !rootAnimateController.running;
|
3521
|
+
};
|
3339
3522
|
|
3340
|
-
|
3341
|
-
// Do not remove element before insert. Removing will cause data associated with the
|
3342
|
-
// element to be dropped. Insert will implicitly do the remove.
|
3343
|
-
insert(element, parent, after);
|
3344
|
-
}
|
3523
|
+
return AnimatorService;
|
3345
3524
|
}];
|
3346
3525
|
};
|
3347
3526
|
|
@@ -3642,7 +3821,13 @@ function Browser(window, document, $log, $sniffer) {
|
|
3642
3821
|
cookie = cookieArray[i];
|
3643
3822
|
index = cookie.indexOf('=');
|
3644
3823
|
if (index > 0) { //ignore nameless cookies
|
3645
|
-
|
3824
|
+
var name = unescape(cookie.substring(0, index));
|
3825
|
+
// the first value that is seen for a cookie is the most
|
3826
|
+
// specific one. values for the same cookie name that
|
3827
|
+
// follow are for less specific paths.
|
3828
|
+
if (lastCookies[name] === undefined) {
|
3829
|
+
lastCookies[name] = unescape(cookie.substring(index + 1));
|
3830
|
+
}
|
3646
3831
|
}
|
3647
3832
|
}
|
3648
3833
|
}
|
@@ -4455,9 +4640,9 @@ function $CompileProvider($provide) {
|
|
4455
4640
|
|
4456
4641
|
|
4457
4642
|
/**
|
4458
|
-
* Once the directives have been collected their compile functions
|
4643
|
+
* Once the directives have been collected, their compile functions are executed. This method
|
4459
4644
|
* is responsible for inlining directive templates as well as terminating the application
|
4460
|
-
* of the directives if the terminal directive has been reached
|
4645
|
+
* of the directives if the terminal directive has been reached.
|
4461
4646
|
*
|
4462
4647
|
* @param {Array} directives Array of collected directives to execute their compile function.
|
4463
4648
|
* this needs to be pre-sorted by priority order.
|
@@ -4465,11 +4650,11 @@ function $CompileProvider($provide) {
|
|
4465
4650
|
* @param {Object} templateAttrs The shared attribute function
|
4466
4651
|
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
|
4467
4652
|
* scope argument is auto-generated to the new child of the transcluded parent scope.
|
4468
|
-
* @param {
|
4469
|
-
* argument has the root jqLite array so that we can replace
|
4653
|
+
* @param {JQLite} jqCollection If we are working on the root of the compile tree then this
|
4654
|
+
* argument has the root jqLite array so that we can replace nodes on it.
|
4470
4655
|
* @returns linkFn
|
4471
4656
|
*/
|
4472
|
-
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
|
4657
|
+
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
|
4473
4658
|
var terminalPriority = -Number.MAX_VALUE,
|
4474
4659
|
preLinkFns = [],
|
4475
4660
|
postLinkFns = [],
|
@@ -4523,7 +4708,7 @@ function $CompileProvider($provide) {
|
|
4523
4708
|
$compileNode = templateAttrs.$$element =
|
4524
4709
|
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
|
4525
4710
|
compileNode = $compileNode[0];
|
4526
|
-
replaceWith(
|
4711
|
+
replaceWith(jqCollection, jqLite($template[0]), compileNode);
|
4527
4712
|
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
|
4528
4713
|
} else {
|
4529
4714
|
$template = jqLite(JQLiteClone(compileNode)).contents();
|
@@ -4552,7 +4737,7 @@ function $CompileProvider($provide) {
|
|
4552
4737
|
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
4553
4738
|
}
|
4554
4739
|
|
4555
|
-
replaceWith(
|
4740
|
+
replaceWith(jqCollection, $compileNode, compileNode);
|
4556
4741
|
|
4557
4742
|
var newTemplateAttrs = {$attr: {}};
|
4558
4743
|
|
@@ -4580,7 +4765,7 @@ function $CompileProvider($provide) {
|
|
4580
4765
|
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
4581
4766
|
templateDirective = directive;
|
4582
4767
|
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
|
4583
|
-
nodeLinkFn, $compileNode, templateAttrs,
|
4768
|
+
nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace,
|
4584
4769
|
childTranscludeFn);
|
4585
4770
|
ii = directives.length;
|
4586
4771
|
} else if (directive.compile) {
|
@@ -4721,7 +4906,7 @@ function $CompileProvider($provide) {
|
|
4721
4906
|
parentGet = $parse(attrs[attrName]);
|
4722
4907
|
scope[scopeName] = function(locals) {
|
4723
4908
|
return parentGet(parentScope, locals);
|
4724
|
-
}
|
4909
|
+
};
|
4725
4910
|
break;
|
4726
4911
|
}
|
4727
4912
|
|
@@ -5120,7 +5305,8 @@ function directiveLinkingFn(
|
|
5120
5305
|
* {@link ng.$controllerProvider#register register} method.
|
5121
5306
|
*/
|
5122
5307
|
function $ControllerProvider() {
|
5123
|
-
var controllers = {}
|
5308
|
+
var controllers = {},
|
5309
|
+
CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
5124
5310
|
|
5125
5311
|
|
5126
5312
|
/**
|
@@ -5165,17 +5351,32 @@ function $ControllerProvider() {
|
|
5165
5351
|
* a service, so that one can override this service with {@link https://gist.github.com/1649788
|
5166
5352
|
* BC version}.
|
5167
5353
|
*/
|
5168
|
-
return function(
|
5169
|
-
|
5170
|
-
|
5171
|
-
|
5172
|
-
|
5173
|
-
|
5354
|
+
return function(expression, locals) {
|
5355
|
+
var instance, match, constructor, identifier;
|
5356
|
+
|
5357
|
+
if(isString(expression)) {
|
5358
|
+
match = expression.match(CNTRL_REG),
|
5359
|
+
constructor = match[1],
|
5360
|
+
identifier = match[3];
|
5361
|
+
expression = controllers.hasOwnProperty(constructor)
|
5362
|
+
? controllers[constructor]
|
5363
|
+
: getter(locals.$scope, constructor, true) || getter($window, constructor, true);
|
5364
|
+
|
5365
|
+
assertArgFn(expression, constructor, true);
|
5366
|
+
}
|
5174
5367
|
|
5175
|
-
|
5368
|
+
instance = $injector.instantiate(expression, locals);
|
5369
|
+
|
5370
|
+
if (identifier) {
|
5371
|
+
if (typeof locals.$scope !== 'object') {
|
5372
|
+
throw new Error('Can not export controller as "' + identifier + '". ' +
|
5373
|
+
'No scope object provided!');
|
5374
|
+
}
|
5375
|
+
|
5376
|
+
locals.$scope[identifier] = instance;
|
5176
5377
|
}
|
5177
5378
|
|
5178
|
-
return
|
5379
|
+
return instance;
|
5179
5380
|
};
|
5180
5381
|
}];
|
5181
5382
|
}
|
@@ -5214,7 +5415,7 @@ function $DocumentProvider(){
|
|
5214
5415
|
*
|
5215
5416
|
*/
|
5216
5417
|
function $ExceptionHandlerProvider() {
|
5217
|
-
this.$get = ['$log', function($log){
|
5418
|
+
this.$get = ['$log', function($log) {
|
5218
5419
|
return function(exception, cause) {
|
5219
5420
|
$log.error.apply($log, arguments);
|
5220
5421
|
};
|
@@ -5408,9 +5609,8 @@ function $InterpolateProvider() {
|
|
5408
5609
|
}];
|
5409
5610
|
}
|
5410
5611
|
|
5411
|
-
var
|
5412
|
-
PATH_MATCH = /^([^\?#]*)
|
5413
|
-
HASH_MATCH = PATH_MATCH,
|
5612
|
+
var SERVER_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
|
5613
|
+
PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
|
5414
5614
|
DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
|
5415
5615
|
|
5416
5616
|
|
@@ -5431,30 +5631,23 @@ function encodePath(path) {
|
|
5431
5631
|
return segments.join('/');
|
5432
5632
|
}
|
5433
5633
|
|
5434
|
-
function stripHash(url) {
|
5435
|
-
return url.split('#')[0];
|
5436
|
-
}
|
5437
|
-
|
5438
|
-
|
5439
5634
|
function matchUrl(url, obj) {
|
5440
|
-
var match =
|
5635
|
+
var match = SERVER_MATCH.exec(url);
|
5441
5636
|
|
5442
|
-
|
5443
|
-
|
5444
|
-
|
5445
|
-
|
5446
|
-
path: match[6] || '/',
|
5447
|
-
search: match[8],
|
5448
|
-
hash: match[10]
|
5449
|
-
};
|
5637
|
+
obj.$$protocol = match[1];
|
5638
|
+
obj.$$host = match[3];
|
5639
|
+
obj.$$port = int(match[5]) || DEFAULT_PORTS[match[1]] || null;
|
5640
|
+
}
|
5450
5641
|
|
5451
|
-
|
5452
|
-
|
5453
|
-
obj.$$host = match.host;
|
5454
|
-
obj.$$port = match.port;
|
5455
|
-
}
|
5642
|
+
function matchAppUrl(url, obj) {
|
5643
|
+
var match = PATH_MATCH.exec(url);
|
5456
5644
|
|
5457
|
-
|
5645
|
+
obj.$$path = decodeURIComponent(match[1]);
|
5646
|
+
obj.$$search = parseKeyValue(match[3]);
|
5647
|
+
obj.$$hash = decodeURIComponent(match[5] || '');
|
5648
|
+
|
5649
|
+
// make sure path starts with '/';
|
5650
|
+
if (obj.$$path && obj.$$path.charAt(0) != '/') obj.$$path = '/' + obj.$$path;
|
5458
5651
|
}
|
5459
5652
|
|
5460
5653
|
|
@@ -5462,77 +5655,62 @@ function composeProtocolHostPort(protocol, host, port) {
|
|
5462
5655
|
return protocol + '://' + host + (port == DEFAULT_PORTS[protocol] ? '' : ':' + port);
|
5463
5656
|
}
|
5464
5657
|
|
5465
|
-
|
5466
|
-
|
5467
|
-
|
5658
|
+
/**
|
5659
|
+
*
|
5660
|
+
* @param {string} begin
|
5661
|
+
* @param {string} whole
|
5662
|
+
* @param {string} otherwise
|
5663
|
+
* @returns {string} returns text from whole after begin or otherwise if it does not begin with expected string.
|
5664
|
+
*/
|
5665
|
+
function beginsWith(begin, whole, otherwise) {
|
5666
|
+
return whole.indexOf(begin) == 0 ? whole.substr(begin.length) : otherwise;
|
5468
5667
|
}
|
5469
5668
|
|
5470
5669
|
|
5471
|
-
function
|
5472
|
-
var
|
5473
|
-
|
5474
|
-
// already html5 url
|
5475
|
-
if (decodeURIComponent(match.path) != basePath || isUndefined(match.hash) ||
|
5476
|
-
match.hash.indexOf(hashPrefix) !== 0) {
|
5477
|
-
return url;
|
5478
|
-
// convert hashbang url -> html5 url
|
5479
|
-
} else {
|
5480
|
-
return composeProtocolHostPort(match.protocol, match.host, match.port) +
|
5481
|
-
pathPrefixFromBase(basePath) + match.hash.substr(hashPrefix.length);
|
5482
|
-
}
|
5670
|
+
function stripHash(url) {
|
5671
|
+
var index = url.indexOf('#');
|
5672
|
+
return index == -1 ? url : url.substr(0, index);
|
5483
5673
|
}
|
5484
5674
|
|
5485
5675
|
|
5486
|
-
function
|
5487
|
-
|
5488
|
-
|
5489
|
-
// already hashbang url
|
5490
|
-
if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) &&
|
5491
|
-
match.hash.indexOf(hashPrefix) === 0) {
|
5492
|
-
return url;
|
5493
|
-
// convert html5 url -> hashbang url
|
5494
|
-
} else {
|
5495
|
-
var search = match.search && '?' + match.search || '',
|
5496
|
-
hash = match.hash && '#' + match.hash || '',
|
5497
|
-
pathPrefix = pathPrefixFromBase(basePath),
|
5498
|
-
path = match.path.substr(pathPrefix.length);
|
5499
|
-
|
5500
|
-
if (match.path.indexOf(pathPrefix) !== 0) {
|
5501
|
-
throw Error('Invalid url "' + url + '", missing path prefix "' + pathPrefix + '" !');
|
5502
|
-
}
|
5676
|
+
function stripFile(url) {
|
5677
|
+
return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
|
5678
|
+
}
|
5503
5679
|
|
5504
|
-
|
5505
|
-
|
5506
|
-
|
5680
|
+
/* return the server only */
|
5681
|
+
function serverBase(url) {
|
5682
|
+
return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
|
5507
5683
|
}
|
5508
5684
|
|
5509
5685
|
|
5510
5686
|
/**
|
5511
|
-
*
|
5687
|
+
* LocationHtml5Url represents an url
|
5512
5688
|
* This object is exposed as $location service when HTML5 mode is enabled and supported
|
5513
5689
|
*
|
5514
5690
|
* @constructor
|
5515
|
-
* @param {string}
|
5516
|
-
* @param {string}
|
5691
|
+
* @param {string} appBase application base URL
|
5692
|
+
* @param {string} basePrefix url path prefix
|
5517
5693
|
*/
|
5518
|
-
function
|
5519
|
-
|
5520
|
-
|
5694
|
+
function LocationHtml5Url(appBase, basePrefix) {
|
5695
|
+
basePrefix = basePrefix || '';
|
5696
|
+
var appBaseNoFile = stripFile(appBase);
|
5521
5697
|
/**
|
5522
5698
|
* Parse given html5 (regular) url string into properties
|
5523
5699
|
* @param {string} newAbsoluteUrl HTML5 url
|
5524
5700
|
* @private
|
5525
5701
|
*/
|
5526
|
-
this.$$parse = function(
|
5527
|
-
var
|
5528
|
-
|
5529
|
-
|
5530
|
-
|
5702
|
+
this.$$parse = function(url) {
|
5703
|
+
var parsed = {}
|
5704
|
+
matchUrl(url, parsed);
|
5705
|
+
var pathUrl = beginsWith(appBaseNoFile, url);
|
5706
|
+
if (!isString(pathUrl)) {
|
5707
|
+
throw Error('Invalid url "' + url + '", missing path prefix "' + appBaseNoFile + '".');
|
5708
|
+
}
|
5709
|
+
matchAppUrl(pathUrl, parsed);
|
5710
|
+
extend(this, parsed);
|
5711
|
+
if (!this.$$path) {
|
5712
|
+
this.$$path = '/';
|
5531
5713
|
}
|
5532
|
-
|
5533
|
-
this.$$path = decodeURIComponent(match.path.substr(pathPrefix.length));
|
5534
|
-
this.$$search = parseKeyValue(match.search);
|
5535
|
-
this.$$hash = match.hash && decodeURIComponent(match.hash) || '';
|
5536
5714
|
|
5537
5715
|
this.$$compose();
|
5538
5716
|
};
|
@@ -5546,19 +5724,25 @@ function LocationUrl(url, pathPrefix, appBaseUrl) {
|
|
5546
5724
|
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
|
5547
5725
|
|
5548
5726
|
this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
|
5549
|
-
this.$$absUrl =
|
5550
|
-
pathPrefix + this.$$url;
|
5727
|
+
this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
|
5551
5728
|
};
|
5552
5729
|
|
5730
|
+
this.$$rewrite = function(url) {
|
5731
|
+
var appUrl, prevAppUrl;
|
5553
5732
|
|
5554
|
-
|
5555
|
-
|
5556
|
-
|
5733
|
+
if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
|
5734
|
+
prevAppUrl = appUrl;
|
5735
|
+
if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
|
5736
|
+
return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
|
5737
|
+
} else {
|
5738
|
+
return appBase + prevAppUrl;
|
5739
|
+
}
|
5740
|
+
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
|
5741
|
+
return appBaseNoFile + appUrl;
|
5742
|
+
} else if (appBaseNoFile == url + '/') {
|
5743
|
+
return appBaseNoFile;
|
5557
5744
|
}
|
5558
|
-
}
|
5559
|
-
|
5560
|
-
|
5561
|
-
this.$$parse(url);
|
5745
|
+
}
|
5562
5746
|
}
|
5563
5747
|
|
5564
5748
|
|
@@ -5567,11 +5751,11 @@ function LocationUrl(url, pathPrefix, appBaseUrl) {
|
|
5567
5751
|
* This object is exposed as $location service when html5 history api is disabled or not supported
|
5568
5752
|
*
|
5569
5753
|
* @constructor
|
5570
|
-
* @param {string}
|
5571
|
-
* @param {string} hashPrefix
|
5754
|
+
* @param {string} appBase application base URL
|
5755
|
+
* @param {string} hashPrefix hashbang prefix
|
5572
5756
|
*/
|
5573
|
-
function LocationHashbangUrl(
|
5574
|
-
var
|
5757
|
+
function LocationHashbangUrl(appBase, hashPrefix) {
|
5758
|
+
var appBaseNoFile = stripFile(appBase);
|
5575
5759
|
|
5576
5760
|
/**
|
5577
5761
|
* Parse given hashbang url into properties
|
@@ -5579,24 +5763,16 @@ function LocationHashbangUrl(url, hashPrefix, appBaseUrl) {
|
|
5579
5763
|
* @private
|
5580
5764
|
*/
|
5581
5765
|
this.$$parse = function(url) {
|
5582
|
-
|
5583
|
-
|
5584
|
-
|
5585
|
-
|
5586
|
-
throw Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '" !');
|
5766
|
+
matchUrl(url, this);
|
5767
|
+
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
|
5768
|
+
if (!isString(withoutBaseUrl)) {
|
5769
|
+
throw new Error('Invalid url "' + url + '", does not start with "' + appBase + '".');
|
5587
5770
|
}
|
5588
|
-
|
5589
|
-
|
5590
|
-
|
5591
|
-
if (match[1]) {
|
5592
|
-
this.$$path = (match[1].charAt(0) == '/' ? '' : '/') + decodeURIComponent(match[1]);
|
5593
|
-
} else {
|
5594
|
-
this.$$path = '';
|
5771
|
+
var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' ? beginsWith(hashPrefix, withoutBaseUrl) : withoutBaseUrl;
|
5772
|
+
if (!isString(withoutHashUrl)) {
|
5773
|
+
throw new Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '".');
|
5595
5774
|
}
|
5596
|
-
|
5597
|
-
this.$$search = parseKeyValue(match[3]);
|
5598
|
-
this.$$hash = match[5] && decodeURIComponent(match[5]) || '';
|
5599
|
-
|
5775
|
+
matchAppUrl(withoutHashUrl, this);
|
5600
5776
|
this.$$compose();
|
5601
5777
|
};
|
5602
5778
|
|
@@ -5609,22 +5785,48 @@ function LocationHashbangUrl(url, hashPrefix, appBaseUrl) {
|
|
5609
5785
|
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
|
5610
5786
|
|
5611
5787
|
this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
|
5612
|
-
this.$$absUrl =
|
5613
|
-
basePath + (this.$$url ? '#' + hashPrefix + this.$$url : '');
|
5788
|
+
this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
|
5614
5789
|
};
|
5615
5790
|
|
5616
|
-
this.$$
|
5617
|
-
if(
|
5618
|
-
return
|
5791
|
+
this.$$rewrite = function(url) {
|
5792
|
+
if(stripHash(appBase) == stripHash(url)) {
|
5793
|
+
return url;
|
5619
5794
|
}
|
5620
5795
|
}
|
5796
|
+
}
|
5797
|
+
|
5798
|
+
|
5799
|
+
/**
|
5800
|
+
* LocationHashbangUrl represents url
|
5801
|
+
* This object is exposed as $location service when html5 history api is enabled but the browser
|
5802
|
+
* does not support it.
|
5803
|
+
*
|
5804
|
+
* @constructor
|
5805
|
+
* @param {string} appBase application base URL
|
5806
|
+
* @param {string} hashPrefix hashbang prefix
|
5807
|
+
*/
|
5808
|
+
function LocationHashbangInHtml5Url(appBase, hashPrefix) {
|
5809
|
+
LocationHashbangUrl.apply(this, arguments);
|
5621
5810
|
|
5811
|
+
var appBaseNoFile = stripFile(appBase);
|
5622
5812
|
|
5623
|
-
this.$$
|
5813
|
+
this.$$rewrite = function(url) {
|
5814
|
+
var appUrl;
|
5815
|
+
|
5816
|
+
if ( appBase == stripHash(url) ) {
|
5817
|
+
return url;
|
5818
|
+
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
|
5819
|
+
return appBase + hashPrefix + appUrl;
|
5820
|
+
} else if ( appBaseNoFile === url + '/') {
|
5821
|
+
return appBaseNoFile;
|
5822
|
+
}
|
5823
|
+
}
|
5624
5824
|
}
|
5625
5825
|
|
5626
5826
|
|
5627
|
-
|
5827
|
+
LocationHashbangInHtml5Url.prototype =
|
5828
|
+
LocationHashbangUrl.prototype =
|
5829
|
+
LocationHtml5Url.prototype = {
|
5628
5830
|
|
5629
5831
|
/**
|
5630
5832
|
* Has any change been replacing ?
|
@@ -5806,21 +6008,6 @@ LocationUrl.prototype = {
|
|
5806
6008
|
}
|
5807
6009
|
};
|
5808
6010
|
|
5809
|
-
LocationHashbangUrl.prototype = inherit(LocationUrl.prototype);
|
5810
|
-
|
5811
|
-
function LocationHashbangInHtml5Url(url, hashPrefix, appBaseUrl, baseExtra) {
|
5812
|
-
LocationHashbangUrl.apply(this, arguments);
|
5813
|
-
|
5814
|
-
|
5815
|
-
this.$$rewriteAppUrl = function(absoluteLinkUrl) {
|
5816
|
-
if (absoluteLinkUrl.indexOf(appBaseUrl) == 0) {
|
5817
|
-
return appBaseUrl + baseExtra + '#' + hashPrefix + absoluteLinkUrl.substr(appBaseUrl.length);
|
5818
|
-
}
|
5819
|
-
}
|
5820
|
-
}
|
5821
|
-
|
5822
|
-
LocationHashbangInHtml5Url.prototype = inherit(LocationHashbangUrl.prototype);
|
5823
|
-
|
5824
6011
|
function locationGetter(property) {
|
5825
6012
|
return function() {
|
5826
6013
|
return this[property];
|
@@ -5917,37 +6104,20 @@ function $LocationProvider(){
|
|
5917
6104
|
this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
|
5918
6105
|
function( $rootScope, $browser, $sniffer, $rootElement) {
|
5919
6106
|
var $location,
|
5920
|
-
|
5921
|
-
|
5922
|
-
|
5923
|
-
|
5924
|
-
appBaseUrl;
|
6107
|
+
LocationMode,
|
6108
|
+
baseHref = $browser.baseHref(),
|
6109
|
+
initialUrl = $browser.url(),
|
6110
|
+
appBase;
|
5925
6111
|
|
5926
6112
|
if (html5Mode) {
|
5927
|
-
|
5928
|
-
|
5929
|
-
appBaseUrl =
|
5930
|
-
composeProtocolHostPort(initUrlParts.protocol, initUrlParts.host, initUrlParts.port) +
|
5931
|
-
pathPrefix + '/';
|
5932
|
-
|
5933
|
-
if ($sniffer.history) {
|
5934
|
-
$location = new LocationUrl(
|
5935
|
-
convertToHtml5Url(initUrl, basePath, hashPrefix),
|
5936
|
-
pathPrefix, appBaseUrl);
|
5937
|
-
} else {
|
5938
|
-
$location = new LocationHashbangInHtml5Url(
|
5939
|
-
convertToHashbangUrl(initUrl, basePath, hashPrefix),
|
5940
|
-
hashPrefix, appBaseUrl, basePath.substr(pathPrefix.length + 1));
|
5941
|
-
}
|
6113
|
+
appBase = baseHref ? serverBase(initialUrl) + baseHref : initialUrl;
|
6114
|
+
LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
|
5942
6115
|
} else {
|
5943
|
-
|
5944
|
-
|
5945
|
-
(initUrlParts.path || '') +
|
5946
|
-
(initUrlParts.search ? ('?' + initUrlParts.search) : '') +
|
5947
|
-
'#' + hashPrefix + '/';
|
5948
|
-
|
5949
|
-
$location = new LocationHashbangUrl(initUrl, hashPrefix, appBaseUrl);
|
6116
|
+
appBase = stripHash(initialUrl);
|
6117
|
+
LocationMode = LocationHashbangUrl;
|
5950
6118
|
}
|
6119
|
+
$location = new LocationMode(appBase, '#' + hashPrefix);
|
6120
|
+
$location.$$parse($location.$$rewrite(initialUrl));
|
5951
6121
|
|
5952
6122
|
$rootElement.bind('click', function(event) {
|
5953
6123
|
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
|
@@ -5963,28 +6133,34 @@ function $LocationProvider(){
|
|
5963
6133
|
if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
|
5964
6134
|
}
|
5965
6135
|
|
5966
|
-
var absHref = elm.prop('href')
|
5967
|
-
|
6136
|
+
var absHref = elm.prop('href');
|
6137
|
+
var rewrittenUrl = $location.$$rewrite(absHref);
|
5968
6138
|
|
5969
|
-
if (absHref && !elm.attr('target') && rewrittenUrl) {
|
5970
|
-
// update location manually
|
5971
|
-
$location.$$parse(rewrittenUrl);
|
5972
|
-
$rootScope.$apply();
|
6139
|
+
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
|
5973
6140
|
event.preventDefault();
|
5974
|
-
|
5975
|
-
|
6141
|
+
if (rewrittenUrl != $browser.url()) {
|
6142
|
+
// update location manually
|
6143
|
+
$location.$$parse(rewrittenUrl);
|
6144
|
+
$rootScope.$apply();
|
6145
|
+
// hack to work around FF6 bug 684208 when scenario runner clicks on links
|
6146
|
+
window.angular['ff-684208-preventDefault'] = true;
|
6147
|
+
}
|
5976
6148
|
}
|
5977
6149
|
});
|
5978
6150
|
|
5979
6151
|
|
5980
6152
|
// rewrite hashbang url <> html5 url
|
5981
|
-
if ($location.absUrl() !=
|
6153
|
+
if ($location.absUrl() != initialUrl) {
|
5982
6154
|
$browser.url($location.absUrl(), true);
|
5983
6155
|
}
|
5984
6156
|
|
5985
6157
|
// update $location when $browser url changes
|
5986
6158
|
$browser.onUrlChange(function(newUrl) {
|
5987
6159
|
if ($location.absUrl() != newUrl) {
|
6160
|
+
if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
|
6161
|
+
$browser.url($location.absUrl());
|
6162
|
+
return;
|
6163
|
+
}
|
5988
6164
|
$rootScope.$evalAsync(function() {
|
5989
6165
|
var oldUrl = $location.absUrl();
|
5990
6166
|
|
@@ -6241,7 +6417,7 @@ function lex(text, csp){
|
|
6241
6417
|
(token=tokens[tokens.length-1])) {
|
6242
6418
|
token.json = token.text.indexOf('.') == -1;
|
6243
6419
|
}
|
6244
|
-
} else if (is('(){}[]
|
6420
|
+
} else if (is('(){}[].,;:?')) {
|
6245
6421
|
tokens.push({
|
6246
6422
|
index:index,
|
6247
6423
|
text:ch,
|
@@ -6345,10 +6521,10 @@ function lex(text, csp){
|
|
6345
6521
|
function readIdent() {
|
6346
6522
|
var ident = "",
|
6347
6523
|
start = index,
|
6348
|
-
lastDot, peekIndex, methodName;
|
6524
|
+
lastDot, peekIndex, methodName, ch;
|
6349
6525
|
|
6350
6526
|
while (index < text.length) {
|
6351
|
-
|
6527
|
+
ch = text.charAt(index);
|
6352
6528
|
if (ch == '.' || isIdent(ch) || isNumber(ch)) {
|
6353
6529
|
if (ch == '.') lastDot = index;
|
6354
6530
|
ident += ch;
|
@@ -6362,7 +6538,7 @@ function lex(text, csp){
|
|
6362
6538
|
if (lastDot) {
|
6363
6539
|
peekIndex = index;
|
6364
6540
|
while(peekIndex < text.length) {
|
6365
|
-
|
6541
|
+
ch = text.charAt(peekIndex);
|
6366
6542
|
if (ch == '(') {
|
6367
6543
|
methodName = ident.substr(lastDot - start + 1);
|
6368
6544
|
ident = ident.substr(0, lastDot - start);
|
@@ -6542,6 +6718,14 @@ function parser(text, json, $filter, csp){
|
|
6542
6718
|
});
|
6543
6719
|
}
|
6544
6720
|
|
6721
|
+
function ternaryFn(left, middle, right){
|
6722
|
+
return extend(function(self, locals){
|
6723
|
+
return left(self, locals) ? middle(self, locals) : right(self, locals);
|
6724
|
+
}, {
|
6725
|
+
constant: left.constant && middle.constant && right.constant
|
6726
|
+
});
|
6727
|
+
}
|
6728
|
+
|
6545
6729
|
function binaryFn(left, fn, right) {
|
6546
6730
|
return extend(function(self, locals) {
|
6547
6731
|
return fn(self, locals, left, right);
|
@@ -6612,7 +6796,7 @@ function parser(text, json, $filter, csp){
|
|
6612
6796
|
}
|
6613
6797
|
|
6614
6798
|
function _assignment() {
|
6615
|
-
var left =
|
6799
|
+
var left = ternary();
|
6616
6800
|
var right;
|
6617
6801
|
var token;
|
6618
6802
|
if ((token = expect('='))) {
|
@@ -6620,15 +6804,33 @@ function parser(text, json, $filter, csp){
|
|
6620
6804
|
throwError("implies assignment but [" +
|
6621
6805
|
text.substring(0, token.index) + "] can not be assigned to", token);
|
6622
6806
|
}
|
6623
|
-
right =
|
6624
|
-
return function(
|
6625
|
-
return left.assign(
|
6807
|
+
right = ternary();
|
6808
|
+
return function(scope, locals){
|
6809
|
+
return left.assign(scope, right(scope, locals), locals);
|
6626
6810
|
};
|
6627
6811
|
} else {
|
6628
6812
|
return left;
|
6629
6813
|
}
|
6630
6814
|
}
|
6631
6815
|
|
6816
|
+
function ternary() {
|
6817
|
+
var left = logicalOR();
|
6818
|
+
var middle;
|
6819
|
+
var token;
|
6820
|
+
if((token = expect('?'))){
|
6821
|
+
middle = ternary();
|
6822
|
+
if((token = expect(':'))){
|
6823
|
+
return ternaryFn(left, middle, ternary());
|
6824
|
+
}
|
6825
|
+
else {
|
6826
|
+
throwError('expected :', token);
|
6827
|
+
}
|
6828
|
+
}
|
6829
|
+
else {
|
6830
|
+
return left;
|
6831
|
+
}
|
6832
|
+
}
|
6833
|
+
|
6632
6834
|
function logicalOR() {
|
6633
6835
|
var left = logicalAND();
|
6634
6836
|
var token;
|
@@ -6742,12 +6944,12 @@ function parser(text, json, $filter, csp){
|
|
6742
6944
|
var field = expect().text;
|
6743
6945
|
var getter = getterFn(field, csp);
|
6744
6946
|
return extend(
|
6745
|
-
function(
|
6746
|
-
return getter(object(
|
6947
|
+
function(scope, locals, self) {
|
6948
|
+
return getter(self || object(scope, locals), locals);
|
6747
6949
|
},
|
6748
6950
|
{
|
6749
|
-
assign:function(
|
6750
|
-
return setter(object(
|
6951
|
+
assign:function(scope, value, locals) {
|
6952
|
+
return setter(object(scope, locals), field, value);
|
6751
6953
|
}
|
6752
6954
|
}
|
6753
6955
|
);
|
@@ -6788,14 +6990,14 @@ function parser(text, json, $filter, csp){
|
|
6788
6990
|
} while (expect(','));
|
6789
6991
|
}
|
6790
6992
|
consume(')');
|
6791
|
-
return function(
|
6993
|
+
return function(scope, locals){
|
6792
6994
|
var args = [],
|
6793
|
-
context = contextGetter ? contextGetter(
|
6995
|
+
context = contextGetter ? contextGetter(scope, locals) : scope;
|
6794
6996
|
|
6795
6997
|
for ( var i = 0; i < argsFn.length; i++) {
|
6796
|
-
args.push(argsFn[i](
|
6998
|
+
args.push(argsFn[i](scope, locals));
|
6797
6999
|
}
|
6798
|
-
var fnPtr = fn(
|
7000
|
+
var fnPtr = fn(scope, locals, context) || noop;
|
6799
7001
|
// IE stupidity!
|
6800
7002
|
return fnPtr.apply
|
6801
7003
|
? fnPtr.apply(context, args)
|
@@ -6849,8 +7051,7 @@ function parser(text, json, $filter, csp){
|
|
6849
7051
|
var object = {};
|
6850
7052
|
for ( var i = 0; i < keyValues.length; i++) {
|
6851
7053
|
var keyValue = keyValues[i];
|
6852
|
-
|
6853
|
-
object[keyValue.key] = value;
|
7054
|
+
object[keyValue.key] = keyValue.value(self, locals);
|
6854
7055
|
}
|
6855
7056
|
return object;
|
6856
7057
|
}, {
|
@@ -6975,7 +7176,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) {
|
|
6975
7176
|
}
|
6976
7177
|
return pathVal;
|
6977
7178
|
};
|
6978
|
-
}
|
7179
|
+
}
|
6979
7180
|
|
6980
7181
|
function getterFn(path, csp) {
|
6981
7182
|
if (getterFnCache.hasOwnProperty(path)) {
|
@@ -6990,7 +7191,7 @@ function getterFn(path, csp) {
|
|
6990
7191
|
fn = (pathKeysLength < 6)
|
6991
7192
|
? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
|
6992
7193
|
: function(scope, locals) {
|
6993
|
-
var i = 0, val
|
7194
|
+
var i = 0, val;
|
6994
7195
|
do {
|
6995
7196
|
val = cspSafeGetterFn(
|
6996
7197
|
pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
|
@@ -7178,6 +7379,11 @@ function $ParseProvider() {
|
|
7178
7379
|
* This method *returns a new promise* which is resolved or rejected via the return value of the
|
7179
7380
|
* `successCallback` or `errorCallback`.
|
7180
7381
|
*
|
7382
|
+
* - `always(callback)` – allows you to observe either the fulfillment or rejection of a promise,
|
7383
|
+
* but to do so without modifying the final value. This is useful to release resources or do some
|
7384
|
+
* clean-up that needs to be done whether the promise was rejected or resolved. See the [full
|
7385
|
+
* specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
|
7386
|
+
* more information.
|
7181
7387
|
*
|
7182
7388
|
* # Chaining promises
|
7183
7389
|
*
|
@@ -7208,7 +7414,7 @@ function $ParseProvider() {
|
|
7208
7414
|
* models and avoiding unnecessary browser repaints, which would result in flickering UI.
|
7209
7415
|
* - $q promises are recognized by the templating engine in angular, which means that in templates
|
7210
7416
|
* you can treat promises attached to a scope as if they were the resulting values.
|
7211
|
-
* - Q has many more features
|
7417
|
+
* - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
|
7212
7418
|
* all the important functionality needed for common async tasks.
|
7213
7419
|
*
|
7214
7420
|
* # Testing
|
@@ -7323,6 +7529,42 @@ function qFactory(nextTick, exceptionHandler) {
|
|
7323
7529
|
}
|
7324
7530
|
|
7325
7531
|
return result.promise;
|
7532
|
+
},
|
7533
|
+
always: function(callback) {
|
7534
|
+
|
7535
|
+
function makePromise(value, resolved) {
|
7536
|
+
var result = defer();
|
7537
|
+
if (resolved) {
|
7538
|
+
result.resolve(value);
|
7539
|
+
} else {
|
7540
|
+
result.reject(value);
|
7541
|
+
}
|
7542
|
+
return result.promise;
|
7543
|
+
}
|
7544
|
+
|
7545
|
+
function handleCallback(value, isResolved) {
|
7546
|
+
var callbackOutput = null;
|
7547
|
+
try {
|
7548
|
+
callbackOutput = (callback ||defaultCallback)();
|
7549
|
+
} catch(e) {
|
7550
|
+
return makePromise(e, false);
|
7551
|
+
}
|
7552
|
+
if (callbackOutput && callbackOutput.then) {
|
7553
|
+
return callbackOutput.then(function() {
|
7554
|
+
return makePromise(value, isResolved);
|
7555
|
+
}, function(error) {
|
7556
|
+
return makePromise(error, false);
|
7557
|
+
});
|
7558
|
+
} else {
|
7559
|
+
return makePromise(value, isResolved);
|
7560
|
+
}
|
7561
|
+
}
|
7562
|
+
|
7563
|
+
return this.then(function(value) {
|
7564
|
+
return handleCallback(value, true);
|
7565
|
+
}, function(error) {
|
7566
|
+
return handleCallback(error, false);
|
7567
|
+
});
|
7326
7568
|
}
|
7327
7569
|
}
|
7328
7570
|
};
|
@@ -7403,10 +7645,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
7403
7645
|
* the promise comes from a source that can't be trusted.
|
7404
7646
|
*
|
7405
7647
|
* @param {*} value Value or a promise
|
7406
|
-
* @returns {Promise} Returns a
|
7407
|
-
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
7408
|
-
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
7409
|
-
* same rejection.
|
7648
|
+
* @returns {Promise} Returns a promise of the passed value or promise
|
7410
7649
|
*/
|
7411
7650
|
var when = function(value, callback, errback) {
|
7412
7651
|
var result = defer(),
|
@@ -7545,6 +7784,8 @@ function $RouteProvider(){
|
|
7545
7784
|
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
|
7546
7785
|
* created scope or the name of a {@link angular.Module#controller registered controller}
|
7547
7786
|
* if passed as a string.
|
7787
|
+
* - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
|
7788
|
+
* published to scope under the `controllerAs` name.
|
7548
7789
|
* - `template` – `{string=|function()=}` – html template as a string or function that returns
|
7549
7790
|
* an html template as a string which should be used by {@link ng.directive:ngView ngView} or
|
7550
7791
|
* {@link ng.directive:ngInclude ngInclude} directives.
|
@@ -8039,22 +8280,22 @@ function $RouteParamsProvider() {
|
|
8039
8280
|
/**
|
8040
8281
|
* DESIGN NOTES
|
8041
8282
|
*
|
8042
|
-
* The design decisions behind the scope
|
8283
|
+
* The design decisions behind the scope are heavily favored for speed and memory consumption.
|
8043
8284
|
*
|
8044
8285
|
* The typical use of scope is to watch the expressions, which most of the time return the same
|
8045
8286
|
* value as last time so we optimize the operation.
|
8046
8287
|
*
|
8047
|
-
* Closures construction is expensive
|
8048
|
-
* -
|
8288
|
+
* Closures construction is expensive in terms of speed as well as memory:
|
8289
|
+
* - No closures, instead use prototypical inheritance for API
|
8049
8290
|
* - Internal state needs to be stored on scope directly, which means that private state is
|
8050
8291
|
* exposed as $$____ properties
|
8051
8292
|
*
|
8052
8293
|
* Loop operations are optimized by using while(count--) { ... }
|
8053
8294
|
* - this means that in order to keep the same order of execution as addition we have to add
|
8054
|
-
* items to the array at the
|
8295
|
+
* items to the array at the beginning (shift) instead of at the end (push)
|
8055
8296
|
*
|
8056
8297
|
* Child scopes are created and removed often
|
8057
|
-
* - Using array would be slow since inserts in
|
8298
|
+
* - Using an array would be slow since inserts in middle are expensive so we use linked list
|
8058
8299
|
*
|
8059
8300
|
* There are few watches then a lot of observers. This is why you don't want the observer to be
|
8060
8301
|
* implemented in the same way as watch. Watch requires return of initialization function which
|
@@ -8076,7 +8317,7 @@ function $RouteParamsProvider() {
|
|
8076
8317
|
* @methodOf ng.$rootScopeProvider
|
8077
8318
|
* @description
|
8078
8319
|
*
|
8079
|
-
* Sets the number of digest
|
8320
|
+
* Sets the number of digest iterations the scope should attempt to execute before giving up and
|
8080
8321
|
* assuming that the model is unstable.
|
8081
8322
|
*
|
8082
8323
|
* The current default is 10 iterations.
|
@@ -8412,7 +8653,7 @@ function $RootScopeProvider(){
|
|
8412
8653
|
oldValue = newValue;
|
8413
8654
|
changeDetected++;
|
8414
8655
|
}
|
8415
|
-
} else if (
|
8656
|
+
} else if (isArrayLike(newValue)) {
|
8416
8657
|
if (oldValue !== internalArray) {
|
8417
8658
|
// we are transitioning from something which was not an array into array.
|
8418
8659
|
oldValue = internalArray;
|
@@ -8486,7 +8727,7 @@ function $RootScopeProvider(){
|
|
8486
8727
|
* @function
|
8487
8728
|
*
|
8488
8729
|
* @description
|
8489
|
-
*
|
8730
|
+
* Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
|
8490
8731
|
* Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
|
8491
8732
|
* `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
|
8492
8733
|
* firing. This means that it is possible to get into an infinite loop. This function will throw
|
@@ -8829,7 +9070,7 @@ function $RootScopeProvider(){
|
|
8829
9070
|
* Afterwards, the event traverses upwards toward the root scope and calls all registered
|
8830
9071
|
* listeners along the way. The event will stop propagating if one of the listeners cancels it.
|
8831
9072
|
*
|
8832
|
-
* Any exception
|
9073
|
+
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
8833
9074
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
8834
9075
|
*
|
8835
9076
|
* @param {string} name Event name to emit.
|
@@ -8898,7 +9139,7 @@ function $RootScopeProvider(){
|
|
8898
9139
|
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
8899
9140
|
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
8900
9141
|
*
|
8901
|
-
* @param {string} name Event name to
|
9142
|
+
* @param {string} name Event name to broadcast.
|
8902
9143
|
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
|
8903
9144
|
* @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
|
8904
9145
|
*/
|
@@ -8992,7 +9233,8 @@ function $RootScopeProvider(){
|
|
8992
9233
|
*
|
8993
9234
|
* @property {boolean} history Does the browser support html5 history api ?
|
8994
9235
|
* @property {boolean} hashchange Does the browser support hashchange event ?
|
8995
|
-
* @property {boolean}
|
9236
|
+
* @property {boolean} transitions Does the browser support CSS transition events ?
|
9237
|
+
* @property {boolean} animations Does the browser support CSS animation events ?
|
8996
9238
|
*
|
8997
9239
|
* @description
|
8998
9240
|
* This is very simple implementation of testing browser's features.
|
@@ -9006,6 +9248,7 @@ function $SnifferProvider() {
|
|
9006
9248
|
vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
|
9007
9249
|
bodyStyle = document.body && document.body.style,
|
9008
9250
|
transitions = false,
|
9251
|
+
animations = false,
|
9009
9252
|
match;
|
9010
9253
|
|
9011
9254
|
if (bodyStyle) {
|
@@ -9016,7 +9259,8 @@ function $SnifferProvider() {
|
|
9016
9259
|
break;
|
9017
9260
|
}
|
9018
9261
|
}
|
9019
|
-
transitions = !!(vendorPrefix + 'Transition' in bodyStyle);
|
9262
|
+
transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
|
9263
|
+
animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
|
9020
9264
|
}
|
9021
9265
|
|
9022
9266
|
|
@@ -9044,7 +9288,8 @@ function $SnifferProvider() {
|
|
9044
9288
|
},
|
9045
9289
|
csp: document.securityPolicy ? document.securityPolicy.isActive : false,
|
9046
9290
|
vendorPrefix: vendorPrefix,
|
9047
|
-
|
9291
|
+
transitions : transitions,
|
9292
|
+
animations : animations
|
9048
9293
|
};
|
9049
9294
|
}];
|
9050
9295
|
}
|
@@ -9065,10 +9310,23 @@ function $SnifferProvider() {
|
|
9065
9310
|
* @example
|
9066
9311
|
<doc:example>
|
9067
9312
|
<doc:source>
|
9068
|
-
<
|
9069
|
-
|
9313
|
+
<script>
|
9314
|
+
function Ctrl($scope, $window) {
|
9315
|
+
$scope.$window = $window;
|
9316
|
+
$scope.greeting = 'Hello, World!';
|
9317
|
+
}
|
9318
|
+
</script>
|
9319
|
+
<div ng-controller="Ctrl">
|
9320
|
+
<input type="text" ng-model="greeting" />
|
9321
|
+
<button ng-click="$window.alert(greeting)">ALERT</button>
|
9322
|
+
</div>
|
9070
9323
|
</doc:source>
|
9071
9324
|
<doc:scenario>
|
9325
|
+
it('should display the greeting in the input box', function() {
|
9326
|
+
input('greeting').enter('Hello, E2E Tests');
|
9327
|
+
// If we click the button it will block the test runner
|
9328
|
+
// element(':button').click();
|
9329
|
+
});
|
9072
9330
|
</doc:scenario>
|
9073
9331
|
</doc:example>
|
9074
9332
|
*/
|
@@ -9128,7 +9386,7 @@ function isSameDomain(requestUrl, locationUrl) {
|
|
9128
9386
|
relativeProtocol: match[2] === undefined || match[2] === ''
|
9129
9387
|
};
|
9130
9388
|
|
9131
|
-
match =
|
9389
|
+
match = SERVER_MATCH.exec(locationUrl);
|
9132
9390
|
var domain2 = {
|
9133
9391
|
protocol: match[1],
|
9134
9392
|
host: match[3],
|
@@ -9199,7 +9457,8 @@ function isSuccess(status) {
|
|
9199
9457
|
function $HttpProvider() {
|
9200
9458
|
var JSON_START = /^\s*(\[|\{[^\{])/,
|
9201
9459
|
JSON_END = /[\}\]]\s*$/,
|
9202
|
-
PROTECTION_PREFIX = /^\)\]\}',?\n
|
9460
|
+
PROTECTION_PREFIX = /^\)\]\}',?\n/,
|
9461
|
+
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
|
9203
9462
|
|
9204
9463
|
var defaults = this.defaults = {
|
9205
9464
|
// transform incoming response data
|
@@ -9223,8 +9482,9 @@ function $HttpProvider() {
|
|
9223
9482
|
common: {
|
9224
9483
|
'Accept': 'application/json, text/plain, */*'
|
9225
9484
|
},
|
9226
|
-
post:
|
9227
|
-
put:
|
9485
|
+
post: CONTENT_TYPE_APPLICATION_JSON,
|
9486
|
+
put: CONTENT_TYPE_APPLICATION_JSON,
|
9487
|
+
patch: CONTENT_TYPE_APPLICATION_JSON
|
9228
9488
|
},
|
9229
9489
|
|
9230
9490
|
xsrfCookieName: 'XSRF-TOKEN',
|
@@ -9292,7 +9552,7 @@ function $HttpProvider() {
|
|
9292
9552
|
*
|
9293
9553
|
* @description
|
9294
9554
|
* The `$http` service is a core Angular service that facilitates communication with the remote
|
9295
|
-
* HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
9555
|
+
* HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
|
9296
9556
|
* XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
|
9297
9557
|
*
|
9298
9558
|
* For unit testing applications that use `$http` service, see
|
@@ -9302,13 +9562,13 @@ function $HttpProvider() {
|
|
9302
9562
|
* $resource} service.
|
9303
9563
|
*
|
9304
9564
|
* The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
|
9305
|
-
* the $q service. While for simple usage
|
9306
|
-
* it is important to familiarize yourself with these
|
9565
|
+
* the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
|
9566
|
+
* it is important to familiarize yourself with these APIs and the guarantees they provide.
|
9307
9567
|
*
|
9308
9568
|
*
|
9309
9569
|
* # General usage
|
9310
9570
|
* The `$http` service is a function which takes a single argument — a configuration object —
|
9311
|
-
* that is used to generate an
|
9571
|
+
* that is used to generate an HTTP request and returns a {@link ng.$q promise}
|
9312
9572
|
* with two $http specific methods: `success` and `error`.
|
9313
9573
|
*
|
9314
9574
|
* <pre>
|
@@ -9323,21 +9583,21 @@ function $HttpProvider() {
|
|
9323
9583
|
* });
|
9324
9584
|
* </pre>
|
9325
9585
|
*
|
9326
|
-
* Since the returned value of calling the $http function is a
|
9586
|
+
* Since the returned value of calling the $http function is a `promise`, you can also use
|
9327
9587
|
* the `then` method to register callbacks, and these callbacks will receive a single argument –
|
9328
|
-
* an object representing the response. See the
|
9588
|
+
* an object representing the response. See the API signature and type info below for more
|
9329
9589
|
* details.
|
9330
9590
|
*
|
9331
|
-
* A response status code
|
9591
|
+
* A response status code between 200 and 299 is considered a success status and
|
9332
9592
|
* will result in the success callback being called. Note that if the response is a redirect,
|
9333
9593
|
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
9334
9594
|
* called for such responses.
|
9335
9595
|
*
|
9336
9596
|
* # Shortcut methods
|
9337
9597
|
*
|
9338
|
-
* Since all
|
9339
|
-
* POST
|
9340
|
-
* were created
|
9598
|
+
* Since all invocations of the $http service require passing in an HTTP method and URL, and
|
9599
|
+
* POST/PUT requests require request data to be provided as well, shortcut methods
|
9600
|
+
* were created:
|
9341
9601
|
*
|
9342
9602
|
* <pre>
|
9343
9603
|
* $http.get('/someUrl').success(successCallback);
|
@@ -9356,24 +9616,24 @@ function $HttpProvider() {
|
|
9356
9616
|
*
|
9357
9617
|
* # Setting HTTP Headers
|
9358
9618
|
*
|
9359
|
-
* The $http service will automatically add certain
|
9619
|
+
* The $http service will automatically add certain HTTP headers to all requests. These defaults
|
9360
9620
|
* can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
|
9361
9621
|
* object, which currently contains this default configuration:
|
9362
9622
|
*
|
9363
9623
|
* - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
|
9364
9624
|
* - `Accept: application/json, text/plain, * / *`
|
9365
|
-
* - `$httpProvider.defaults.headers.post`: (header defaults for
|
9625
|
+
* - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
|
9366
9626
|
* - `Content-Type: application/json`
|
9367
|
-
* - `$httpProvider.defaults.headers.put` (header defaults for
|
9627
|
+
* - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
|
9368
9628
|
* - `Content-Type: application/json`
|
9369
9629
|
*
|
9370
|
-
* To add or overwrite these defaults, simply add or remove a property from
|
9630
|
+
* To add or overwrite these defaults, simply add or remove a property from these configuration
|
9371
9631
|
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
|
9372
|
-
* with
|
9632
|
+
* with the lowercased HTTP method name as the key, e.g.
|
9373
9633
|
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
|
9374
9634
|
*
|
9375
|
-
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in
|
9376
|
-
* fashion
|
9635
|
+
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
|
9636
|
+
* fashion.
|
9377
9637
|
*
|
9378
9638
|
*
|
9379
9639
|
* # Transforming Requests and Responses
|
@@ -9383,54 +9643,54 @@ function $HttpProvider() {
|
|
9383
9643
|
*
|
9384
9644
|
* Request transformations:
|
9385
9645
|
*
|
9386
|
-
* -
|
9646
|
+
* - If the `data` property of the request configuration object contains an object, serialize it into
|
9387
9647
|
* JSON format.
|
9388
9648
|
*
|
9389
9649
|
* Response transformations:
|
9390
9650
|
*
|
9391
|
-
* -
|
9392
|
-
* -
|
9651
|
+
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
|
9652
|
+
* - If JSON response is detected, deserialize it using a JSON parser.
|
9393
9653
|
*
|
9394
9654
|
* To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
|
9395
|
-
* `$httpProvider.defaults.transformResponse` properties
|
9655
|
+
* `$httpProvider.defaults.transformResponse` properties. These properties are by default an
|
9396
9656
|
* array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
|
9397
9657
|
* transformation chain. You can also decide to completely override any default transformations by assigning your
|
9398
9658
|
* transformation functions to these properties directly without the array wrapper.
|
9399
9659
|
*
|
9400
9660
|
* Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
|
9401
|
-
* `transformResponse` properties of the
|
9661
|
+
* `transformResponse` properties of the configuration object passed into `$http`.
|
9402
9662
|
*
|
9403
9663
|
*
|
9404
9664
|
* # Caching
|
9405
9665
|
*
|
9406
|
-
* To enable caching set the configuration property `cache` to `true`. When the cache is
|
9666
|
+
* To enable caching, set the configuration property `cache` to `true`. When the cache is
|
9407
9667
|
* enabled, `$http` stores the response from the server in local cache. Next time the
|
9408
9668
|
* response is served from the cache without sending a request to the server.
|
9409
9669
|
*
|
9410
9670
|
* Note that even if the response is served from cache, delivery of the data is asynchronous in
|
9411
9671
|
* the same way that real requests are.
|
9412
9672
|
*
|
9413
|
-
* If there are multiple GET requests for the same
|
9673
|
+
* If there are multiple GET requests for the same URL that should be cached using the same
|
9414
9674
|
* cache, but the cache is not populated yet, only one request to the server will be made and
|
9415
|
-
* the remaining requests will be fulfilled using the response
|
9675
|
+
* the remaining requests will be fulfilled using the response from the first request.
|
9416
9676
|
*
|
9417
9677
|
* A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
|
9418
9678
|
* To skip it, set configuration property `cache` to `false`.
|
9419
|
-
*
|
9679
|
+
*
|
9420
9680
|
*
|
9421
9681
|
* # Interceptors
|
9422
9682
|
*
|
9423
9683
|
* Before you start creating interceptors, be sure to understand the
|
9424
9684
|
* {@link ng.$q $q and deferred/promise APIs}.
|
9425
9685
|
*
|
9426
|
-
* For purposes of global error handling, authentication or any kind of synchronous or
|
9686
|
+
* For purposes of global error handling, authentication, or any kind of synchronous or
|
9427
9687
|
* asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
|
9428
9688
|
* able to intercept requests before they are handed to the server and
|
9429
|
-
* responses
|
9689
|
+
* responses before they are handed over to the application code that
|
9430
9690
|
* initiated these requests. The interceptors leverage the {@link ng.$q
|
9431
|
-
* promise APIs} to
|
9691
|
+
* promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
|
9432
9692
|
*
|
9433
|
-
* The interceptors are service factories that are registered with the
|
9693
|
+
* The interceptors are service factories that are registered with the `$httpProvider` by
|
9434
9694
|
* adding them to the `$httpProvider.interceptors` array. The factory is called and
|
9435
9695
|
* injected with dependencies (if specified) and returns the interceptor.
|
9436
9696
|
*
|
@@ -9550,7 +9810,7 @@ function $HttpProvider() {
|
|
9550
9810
|
* When designing web applications, consider security threats from:
|
9551
9811
|
*
|
9552
9812
|
* - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
9553
|
-
* JSON
|
9813
|
+
* JSON vulnerability}
|
9554
9814
|
* - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
|
9555
9815
|
*
|
9556
9816
|
* Both server and the client must cooperate in order to eliminate these threats. Angular comes
|
@@ -9560,8 +9820,8 @@ function $HttpProvider() {
|
|
9560
9820
|
* ## JSON Vulnerability Protection
|
9561
9821
|
*
|
9562
9822
|
* A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
|
9563
|
-
* JSON
|
9564
|
-
* {@link http://en.wikipedia.org/wiki/
|
9823
|
+
* JSON vulnerability} allows third party website to turn your JSON resource URL into
|
9824
|
+
* {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
|
9565
9825
|
* counter this your server can prefix all JSON requests with following string `")]}',\n"`.
|
9566
9826
|
* Angular will automatically strip the prefix before processing it as JSON.
|
9567
9827
|
*
|
@@ -9582,7 +9842,7 @@ function $HttpProvider() {
|
|
9582
9842
|
* ## Cross Site Request Forgery (XSRF) Protection
|
9583
9843
|
*
|
9584
9844
|
* {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
|
9585
|
-
* an unauthorized site can gain your user's private data. Angular provides
|
9845
|
+
* an unauthorized site can gain your user's private data. Angular provides a mechanism
|
9586
9846
|
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
|
9587
9847
|
* (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
|
9588
9848
|
* JavaScript that runs on your domain could read the cookie, your server can be assured that
|
@@ -9590,12 +9850,12 @@ function $HttpProvider() {
|
|
9590
9850
|
* cross-domain requests.
|
9591
9851
|
*
|
9592
9852
|
* To take advantage of this, your server needs to set a token in a JavaScript readable session
|
9593
|
-
* cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent
|
9853
|
+
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
|
9594
9854
|
* server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
|
9595
|
-
* that only JavaScript running on your domain could have
|
9596
|
-
* unique for each user and must be verifiable by the server (to prevent the JavaScript making
|
9855
|
+
* that only JavaScript running on your domain could have sent the request. The token must be
|
9856
|
+
* unique for each user and must be verifiable by the server (to prevent the JavaScript from making
|
9597
9857
|
* up its own tokens). We recommend that the token is a digest of your site's authentication
|
9598
|
-
* cookie with {@link
|
9858
|
+
* cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
|
9599
9859
|
*
|
9600
9860
|
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
|
9601
9861
|
* properties of either $httpProvider.defaults, or the per-request config object.
|
@@ -9622,7 +9882,8 @@ function $HttpProvider() {
|
|
9622
9882
|
* GET request, otherwise if a cache instance built with
|
9623
9883
|
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
|
9624
9884
|
* caching.
|
9625
|
-
* - **timeout** – `{number}` – timeout in milliseconds
|
9885
|
+
* - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
|
9886
|
+
* that should abort the request when resolved.
|
9626
9887
|
* - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
|
9627
9888
|
* XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
|
9628
9889
|
* requests with credentials} for more information.
|
@@ -9775,7 +10036,7 @@ function $HttpProvider() {
|
|
9775
10036
|
var rejectFn = chain.shift();
|
9776
10037
|
|
9777
10038
|
promise = promise.then(thenFn, rejectFn);
|
9778
|
-
}
|
10039
|
+
}
|
9779
10040
|
|
9780
10041
|
promise.success = function(fn) {
|
9781
10042
|
promise.then(function(response) {
|
@@ -9812,7 +10073,7 @@ function $HttpProvider() {
|
|
9812
10073
|
* @methodOf ng.$http
|
9813
10074
|
*
|
9814
10075
|
* @description
|
9815
|
-
* Shortcut method to perform `GET` request
|
10076
|
+
* Shortcut method to perform `GET` request.
|
9816
10077
|
*
|
9817
10078
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
9818
10079
|
* @param {Object=} config Optional configuration object
|
@@ -9825,7 +10086,7 @@ function $HttpProvider() {
|
|
9825
10086
|
* @methodOf ng.$http
|
9826
10087
|
*
|
9827
10088
|
* @description
|
9828
|
-
* Shortcut method to perform `DELETE` request
|
10089
|
+
* Shortcut method to perform `DELETE` request.
|
9829
10090
|
*
|
9830
10091
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
9831
10092
|
* @param {Object=} config Optional configuration object
|
@@ -9838,7 +10099,7 @@ function $HttpProvider() {
|
|
9838
10099
|
* @methodOf ng.$http
|
9839
10100
|
*
|
9840
10101
|
* @description
|
9841
|
-
* Shortcut method to perform `HEAD` request
|
10102
|
+
* Shortcut method to perform `HEAD` request.
|
9842
10103
|
*
|
9843
10104
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
9844
10105
|
* @param {Object=} config Optional configuration object
|
@@ -9851,7 +10112,7 @@ function $HttpProvider() {
|
|
9851
10112
|
* @methodOf ng.$http
|
9852
10113
|
*
|
9853
10114
|
* @description
|
9854
|
-
* Shortcut method to perform `JSONP` request
|
10115
|
+
* Shortcut method to perform `JSONP` request.
|
9855
10116
|
*
|
9856
10117
|
* @param {string} url Relative or absolute URL specifying the destination of the request.
|
9857
10118
|
* Should contain `JSON_CALLBACK` string.
|
@@ -9866,7 +10127,7 @@ function $HttpProvider() {
|
|
9866
10127
|
* @methodOf ng.$http
|
9867
10128
|
*
|
9868
10129
|
* @description
|
9869
|
-
* Shortcut method to perform `POST` request
|
10130
|
+
* Shortcut method to perform `POST` request.
|
9870
10131
|
*
|
9871
10132
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
9872
10133
|
* @param {*} data Request content
|
@@ -9880,7 +10141,7 @@ function $HttpProvider() {
|
|
9880
10141
|
* @methodOf ng.$http
|
9881
10142
|
*
|
9882
10143
|
* @description
|
9883
|
-
* Shortcut method to perform `PUT` request
|
10144
|
+
* Shortcut method to perform `PUT` request.
|
9884
10145
|
*
|
9885
10146
|
* @param {string} url Relative or absolute URL specifying the destination of the request
|
9886
10147
|
* @param {*} data Request content
|
@@ -9932,7 +10193,7 @@ function $HttpProvider() {
|
|
9932
10193
|
|
9933
10194
|
|
9934
10195
|
/**
|
9935
|
-
* Makes the request
|
10196
|
+
* Makes the request.
|
9936
10197
|
*
|
9937
10198
|
* !!! ACCESSES CLOSURE VARS:
|
9938
10199
|
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
|
@@ -9949,8 +10210,8 @@ function $HttpProvider() {
|
|
9949
10210
|
|
9950
10211
|
|
9951
10212
|
if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
|
9952
|
-
cache = isObject(config.cache) ? config.cache
|
9953
|
-
: isObject(defaults.cache) ? defaults.cache
|
10213
|
+
cache = isObject(config.cache) ? config.cache
|
10214
|
+
: isObject(defaults.cache) ? defaults.cache
|
9954
10215
|
: defaultCache;
|
9955
10216
|
}
|
9956
10217
|
|
@@ -10001,7 +10262,7 @@ function $HttpProvider() {
|
|
10001
10262
|
}
|
10002
10263
|
|
10003
10264
|
resolvePromise(response, status, headersString);
|
10004
|
-
$rootScope.$apply();
|
10265
|
+
if (!$rootScope.$$phase) $rootScope.$apply();
|
10005
10266
|
}
|
10006
10267
|
|
10007
10268
|
|
@@ -10085,6 +10346,7 @@ function $HttpBackendProvider() {
|
|
10085
10346
|
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
|
10086
10347
|
// TODO(vojta): fix the signature
|
10087
10348
|
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
|
10349
|
+
var status;
|
10088
10350
|
$browser.$$incOutstandingRequestCount();
|
10089
10351
|
url = url || $browser.url();
|
10090
10352
|
|
@@ -10094,12 +10356,12 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
10094
10356
|
callbacks[callbackId].data = data;
|
10095
10357
|
};
|
10096
10358
|
|
10097
|
-
jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
|
10359
|
+
var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
|
10098
10360
|
function() {
|
10099
10361
|
if (callbacks[callbackId].data) {
|
10100
10362
|
completeRequest(callback, 200, callbacks[callbackId].data);
|
10101
10363
|
} else {
|
10102
|
-
completeRequest(callback, -2);
|
10364
|
+
completeRequest(callback, status || -2);
|
10103
10365
|
}
|
10104
10366
|
delete callbacks[callbackId];
|
10105
10367
|
});
|
@@ -10110,8 +10372,6 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
10110
10372
|
if (value) xhr.setRequestHeader(key, value);
|
10111
10373
|
});
|
10112
10374
|
|
10113
|
-
var status;
|
10114
|
-
|
10115
10375
|
// In IE6 and 7, this might be called synchronously when xhr.send below is called and the
|
10116
10376
|
// response is in the cache. the promise api will ensure that to the app code the api is
|
10117
10377
|
// always async
|
@@ -10157,19 +10417,28 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
10157
10417
|
}
|
10158
10418
|
|
10159
10419
|
xhr.send(post || '');
|
10420
|
+
}
|
10160
10421
|
|
10161
|
-
|
10162
|
-
|
10163
|
-
|
10164
|
-
|
10165
|
-
}, timeout);
|
10166
|
-
}
|
10422
|
+
if (timeout > 0) {
|
10423
|
+
var timeoutId = $browserDefer(timeoutRequest, timeout);
|
10424
|
+
} else if (timeout && timeout.then) {
|
10425
|
+
timeout.then(timeoutRequest);
|
10167
10426
|
}
|
10168
10427
|
|
10169
10428
|
|
10429
|
+
function timeoutRequest() {
|
10430
|
+
status = -1;
|
10431
|
+
jsonpDone && jsonpDone();
|
10432
|
+
xhr && xhr.abort();
|
10433
|
+
}
|
10434
|
+
|
10170
10435
|
function completeRequest(callback, status, response, headersString) {
|
10171
10436
|
// URL_MATCH is defined in src/service/location.js
|
10172
|
-
var protocol = (url.match(
|
10437
|
+
var protocol = (url.match(SERVER_MATCH) || ['', locationProtocol])[1];
|
10438
|
+
|
10439
|
+
// cancel timeout and subsequent timeout promise resolution
|
10440
|
+
timeoutId && $browserDefer.cancel(timeoutId);
|
10441
|
+
jsonpDone = xhr = null;
|
10173
10442
|
|
10174
10443
|
// fix status code for file protocol (it's always 0)
|
10175
10444
|
status = (protocol == 'file') ? (response ? 200 : 404) : status;
|
@@ -10204,6 +10473,7 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
10204
10473
|
}
|
10205
10474
|
|
10206
10475
|
rawDocument.body.appendChild(script);
|
10476
|
+
return doneWrapper;
|
10207
10477
|
}
|
10208
10478
|
}
|
10209
10479
|
|
@@ -10294,17 +10564,17 @@ function $TimeoutProvider() {
|
|
10294
10564
|
* block and delegates any exceptions to
|
10295
10565
|
* {@link ng.$exceptionHandler $exceptionHandler} service.
|
10296
10566
|
*
|
10297
|
-
* The return value of registering a timeout function is a promise which will be resolved when
|
10567
|
+
* The return value of registering a timeout function is a promise, which will be resolved when
|
10298
10568
|
* the timeout is reached and the timeout function is executed.
|
10299
10569
|
*
|
10300
|
-
* To cancel a
|
10570
|
+
* To cancel a timeout request, call `$timeout.cancel(promise)`.
|
10301
10571
|
*
|
10302
10572
|
* In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
|
10303
10573
|
* synchronously flush the queue of deferred functions.
|
10304
10574
|
*
|
10305
|
-
* @param {function()} fn A function,
|
10575
|
+
* @param {function()} fn A function, whose execution should be delayed.
|
10306
10576
|
* @param {number=} [delay=0] Delay in milliseconds.
|
10307
|
-
* @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
|
10577
|
+
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
10308
10578
|
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
|
10309
10579
|
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
10310
10580
|
* promise will be resolved with is the return value of the `fn` function.
|
@@ -10344,7 +10614,7 @@ function $TimeoutProvider() {
|
|
10344
10614
|
* @methodOf ng.$timeout
|
10345
10615
|
*
|
10346
10616
|
* @description
|
10347
|
-
* Cancels a task associated with the `promise`. As a result of this the promise will be
|
10617
|
+
* Cancels a task associated with the `promise`. As a result of this, the promise will be
|
10348
10618
|
* resolved with a rejection.
|
10349
10619
|
*
|
10350
10620
|
* @param {Promise=} promise Promise returned by the `$timeout` function.
|
@@ -10432,7 +10702,7 @@ function $TimeoutProvider() {
|
|
10432
10702
|
*
|
10433
10703
|
* The general syntax in templates is as follows:
|
10434
10704
|
*
|
10435
|
-
* {{ expression | [
|
10705
|
+
* {{ expression [| filter_name[:parameter_value] ... ] }}
|
10436
10706
|
*
|
10437
10707
|
* @param {String} name Name of the filter function to retrieve
|
10438
10708
|
* @return {Function} the filter function
|
@@ -10534,7 +10804,7 @@ function $FilterProvider($provide) {
|
|
10534
10804
|
<hr>
|
10535
10805
|
Any: <input ng-model="search.$"> <br>
|
10536
10806
|
Name only <input ng-model="search.name"><br>
|
10537
|
-
Phone only <input ng-model="search.phone"
|
10807
|
+
Phone only <input ng-model="search.phone"><br>
|
10538
10808
|
Equality <input type="checkbox" ng-model="strict"><br>
|
10539
10809
|
<table id="searchObjResults">
|
10540
10810
|
<tr><th>Name</th><th>Phone</th></tr>
|
@@ -10866,6 +11136,7 @@ function padNumber(num, digits, trim) {
|
|
10866
11136
|
|
10867
11137
|
|
10868
11138
|
function dateGetter(name, size, offset, trim) {
|
11139
|
+
offset = offset || 0;
|
10869
11140
|
return function(date) {
|
10870
11141
|
var value = date['get' + name]();
|
10871
11142
|
if (offset > 0 || value > -offset)
|
@@ -10980,7 +11251,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10980
11251
|
* (e.g. `"h o''clock"`).
|
10981
11252
|
*
|
10982
11253
|
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
|
10983
|
-
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and
|
11254
|
+
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
|
10984
11255
|
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
|
10985
11256
|
* specified in the string input, the time is considered to be in the local timezone.
|
10986
11257
|
* @param {string=} format Formatting rules (see Description). If not specified,
|
@@ -11029,7 +11300,11 @@ function dateFilter($locale) {
|
|
11029
11300
|
tzMin = int(match[9] + match[11]);
|
11030
11301
|
}
|
11031
11302
|
dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
|
11032
|
-
|
11303
|
+
var h = int(match[4]||0) - tzHour;
|
11304
|
+
var m = int(match[5]||0) - tzMin
|
11305
|
+
var s = int(match[6]||0);
|
11306
|
+
var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
|
11307
|
+
timeSetter.call(date, h, m, s, ms);
|
11033
11308
|
return date;
|
11034
11309
|
}
|
11035
11310
|
return string;
|
@@ -11534,6 +11809,31 @@ var htmlAnchorDirective = valueFn({
|
|
11534
11809
|
* @param {template} ngSrc any string which can contain `{{}}` markup.
|
11535
11810
|
*/
|
11536
11811
|
|
11812
|
+
/**
|
11813
|
+
* @ngdoc directive
|
11814
|
+
* @name ng.directive:ngSrcset
|
11815
|
+
* @restrict A
|
11816
|
+
*
|
11817
|
+
* @description
|
11818
|
+
* Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
|
11819
|
+
* work right: The browser will fetch from the URL with the literal
|
11820
|
+
* text `{{hash}}` until Angular replaces the expression inside
|
11821
|
+
* `{{hash}}`. The `ngSrcset` directive solves this problem.
|
11822
|
+
*
|
11823
|
+
* The buggy way to write it:
|
11824
|
+
* <pre>
|
11825
|
+
* <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
|
11826
|
+
* </pre>
|
11827
|
+
*
|
11828
|
+
* The correct way to write it:
|
11829
|
+
* <pre>
|
11830
|
+
* <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
|
11831
|
+
* </pre>
|
11832
|
+
*
|
11833
|
+
* @element IMG
|
11834
|
+
* @param {template} ngSrcset any string which can contain `{{}}` markup.
|
11835
|
+
*/
|
11836
|
+
|
11537
11837
|
/**
|
11538
11838
|
* @ngdoc directive
|
11539
11839
|
* @name ng.directive:ngDisabled
|
@@ -11754,8 +12054,8 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
|
11754
12054
|
});
|
11755
12055
|
|
11756
12056
|
|
11757
|
-
// ng-src, ng-href are interpolated
|
11758
|
-
forEach(['src', 'href'], function(attrName) {
|
12057
|
+
// ng-src, ng-srcset, ng-href are interpolated
|
12058
|
+
forEach(['src', 'srcset', 'href'], function(attrName) {
|
11759
12059
|
var normalized = directiveNormalize('ng-' + attrName);
|
11760
12060
|
ngAttributeAliasDirectives[normalized] = function() {
|
11761
12061
|
return {
|
@@ -12187,8 +12487,8 @@ var inputType = {
|
|
12187
12487
|
*
|
12188
12488
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
12189
12489
|
* @param {string=} name Property name of the form under which the control is published.
|
12190
|
-
* @param {string=} min Sets the `min` validation error key if the value entered is less
|
12191
|
-
* @param {string=} max Sets the `max` validation error key if the value entered is greater
|
12490
|
+
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
|
12491
|
+
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
|
12192
12492
|
* @param {string=} required Sets `required` validation error key if the value is not entered.
|
12193
12493
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
12194
12494
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
@@ -12507,6 +12807,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
12507
12807
|
} else {
|
12508
12808
|
var timeout;
|
12509
12809
|
|
12810
|
+
var deferListener = function() {
|
12811
|
+
if (!timeout) {
|
12812
|
+
timeout = $browser.defer(function() {
|
12813
|
+
listener();
|
12814
|
+
timeout = null;
|
12815
|
+
});
|
12816
|
+
}
|
12817
|
+
};
|
12818
|
+
|
12510
12819
|
element.bind('keydown', function(event) {
|
12511
12820
|
var key = event.keyCode;
|
12512
12821
|
|
@@ -12514,16 +12823,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
12514
12823
|
// command modifiers arrows
|
12515
12824
|
if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
|
12516
12825
|
|
12517
|
-
|
12518
|
-
timeout = $browser.defer(function() {
|
12519
|
-
listener();
|
12520
|
-
timeout = null;
|
12521
|
-
});
|
12522
|
-
}
|
12826
|
+
deferListener();
|
12523
12827
|
});
|
12524
12828
|
|
12525
12829
|
// if user paste into input using mouse, we need "change" event to catch it
|
12526
12830
|
element.bind('change', listener);
|
12831
|
+
|
12832
|
+
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
|
12833
|
+
if ($sniffer.hasEvent('paste')) {
|
12834
|
+
element.bind('paste cut', deferListener);
|
12835
|
+
}
|
12527
12836
|
}
|
12528
12837
|
|
12529
12838
|
|
@@ -12533,7 +12842,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
12533
12842
|
|
12534
12843
|
// pattern validator
|
12535
12844
|
var pattern = attr.ngPattern,
|
12536
|
-
patternValidator
|
12845
|
+
patternValidator,
|
12846
|
+
match;
|
12537
12847
|
|
12538
12848
|
var validate = function(regexp, value) {
|
12539
12849
|
if (isEmpty(value) || regexp.test(value)) {
|
@@ -12546,8 +12856,9 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
12546
12856
|
};
|
12547
12857
|
|
12548
12858
|
if (pattern) {
|
12549
|
-
|
12550
|
-
|
12859
|
+
match = pattern.match(/^\/(.*)\/([gim]*)$/);
|
12860
|
+
if (match) {
|
12861
|
+
pattern = new RegExp(match[1], match[2]);
|
12551
12862
|
patternValidator = function(value) {
|
12552
12863
|
return validate(pattern, value)
|
12553
12864
|
};
|
@@ -12822,7 +13133,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
|
12822
13133
|
<tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
|
12823
13134
|
<tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
|
12824
13135
|
<tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
|
12825
|
-
<tt>myForm.
|
13136
|
+
<tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
|
12826
13137
|
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
12827
13138
|
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
12828
13139
|
<tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
|
@@ -13101,7 +13412,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
13101
13412
|
* For example {@link ng.directive:input input} or
|
13102
13413
|
* {@link ng.directive:select select} directives call it.
|
13103
13414
|
*
|
13104
|
-
* It internally calls all `
|
13415
|
+
* It internally calls all `parsers` and if resulted value is valid, updates the model and
|
13105
13416
|
* calls all registered change listeners.
|
13106
13417
|
*
|
13107
13418
|
* @param {string} value Value from the view.
|
@@ -13407,7 +13718,7 @@ var ngValueDirective = function() {
|
|
13407
13718
|
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
13408
13719
|
* `{{ expression }}` which is similar but less verbose.
|
13409
13720
|
*
|
13410
|
-
*
|
13721
|
+
* One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when
|
13411
13722
|
* it's desirable to put bindings into template that is momentarily displayed by the browser in its
|
13412
13723
|
* raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
|
13413
13724
|
* bindings invisible to the user while the page is loading.
|
@@ -13548,9 +13859,9 @@ function classDirective(name, selector) {
|
|
13548
13859
|
|
13549
13860
|
if (name !== 'ngClass') {
|
13550
13861
|
scope.$watch('$index', function($index, old$index) {
|
13551
|
-
var mod = $index
|
13552
|
-
if (mod !== old$index
|
13553
|
-
if (mod
|
13862
|
+
var mod = $index & 1;
|
13863
|
+
if (mod !== old$index & 1) {
|
13864
|
+
if (mod === selector) {
|
13554
13865
|
addClass(scope.$eval(attr[name]));
|
13555
13866
|
} else {
|
13556
13867
|
removeClass(scope.$eval(attr[name]));
|
@@ -13562,12 +13873,12 @@ function classDirective(name, selector) {
|
|
13562
13873
|
|
13563
13874
|
function ngClassWatchAction(newVal) {
|
13564
13875
|
if (selector === true || scope.$index % 2 === selector) {
|
13565
|
-
if (oldVal && (newVal
|
13876
|
+
if (oldVal && !equals(newVal,oldVal)) {
|
13566
13877
|
removeClass(oldVal);
|
13567
13878
|
}
|
13568
13879
|
addClass(newVal);
|
13569
13880
|
}
|
13570
|
-
oldVal = newVal;
|
13881
|
+
oldVal = copy(newVal);
|
13571
13882
|
}
|
13572
13883
|
|
13573
13884
|
|
@@ -13693,7 +14004,7 @@ var ngClassOddDirective = classDirective('Odd', 0);
|
|
13693
14004
|
* @name ng.directive:ngClassEven
|
13694
14005
|
*
|
13695
14006
|
* @description
|
13696
|
-
* The `ngClassOdd` and `ngClassEven`
|
14007
|
+
* The `ngClassOdd` and `ngClassEven` directives work exactly as
|
13697
14008
|
* {@link ng.directive:ngClass ngClass}, except it works in
|
13698
14009
|
* conjunction with `ngRepeat` and takes affect only on odd (even) rows.
|
13699
14010
|
*
|
@@ -13810,14 +14121,14 @@ var ngCloakDirective = ngDirective({
|
|
13810
14121
|
* * Controller — The `ngController` directive specifies a Controller class; the class has
|
13811
14122
|
* methods that typically express the business logic behind the application.
|
13812
14123
|
*
|
13813
|
-
* Note that an alternative way to define controllers is via the
|
13814
|
-
* service.
|
14124
|
+
* Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
|
13815
14125
|
*
|
13816
14126
|
* @element ANY
|
13817
14127
|
* @scope
|
13818
14128
|
* @param {expression} ngController Name of a globally accessible constructor function or an
|
13819
14129
|
* {@link guide/expression expression} that on the current scope evaluates to a
|
13820
|
-
* constructor function.
|
14130
|
+
* constructor function. The controller instance can further be published into the scope
|
14131
|
+
* by adding `as localName` the controller name attribute.
|
13821
14132
|
*
|
13822
14133
|
* @example
|
13823
14134
|
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
|
@@ -13825,8 +14136,75 @@ var ngCloakDirective = ngDirective({
|
|
13825
14136
|
* easily be called from the angular markup. Notice that the scope becomes the `this` for the
|
13826
14137
|
* controller's instance. This allows for easy access to the view data from the controller. Also
|
13827
14138
|
* notice that any changes to the data are automatically reflected in the View without the need
|
13828
|
-
* for a manual update.
|
14139
|
+
* for a manual update. The example is included in two different declaration styles based on
|
14140
|
+
* your style preferences.
|
13829
14141
|
<doc:example>
|
14142
|
+
<doc:source>
|
14143
|
+
<script>
|
14144
|
+
function SettingsController() {
|
14145
|
+
this.name = "John Smith";
|
14146
|
+
this.contacts = [
|
14147
|
+
{type: 'phone', value: '408 555 1212'},
|
14148
|
+
{type: 'email', value: 'john.smith@example.org'} ];
|
14149
|
+
};
|
14150
|
+
|
14151
|
+
SettingsController.prototype.greet = function() {
|
14152
|
+
alert(this.name);
|
14153
|
+
};
|
14154
|
+
|
14155
|
+
SettingsController.prototype.addContact = function() {
|
14156
|
+
this.contacts.push({type: 'email', value: 'yourname@example.org'});
|
14157
|
+
};
|
14158
|
+
|
14159
|
+
SettingsController.prototype.removeContact = function(contactToRemove) {
|
14160
|
+
var index = this.contacts.indexOf(contactToRemove);
|
14161
|
+
this.contacts.splice(index, 1);
|
14162
|
+
};
|
14163
|
+
|
14164
|
+
SettingsController.prototype.clearContact = function(contact) {
|
14165
|
+
contact.type = 'phone';
|
14166
|
+
contact.value = '';
|
14167
|
+
};
|
14168
|
+
</script>
|
14169
|
+
<div ng-controller="SettingsController as settings">
|
14170
|
+
Name: <input type="text" ng-model="settings.name"/>
|
14171
|
+
[ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
|
14172
|
+
Contact:
|
14173
|
+
<ul>
|
14174
|
+
<li ng-repeat="contact in settings.contacts">
|
14175
|
+
<select ng-model="contact.type">
|
14176
|
+
<option>phone</option>
|
14177
|
+
<option>email</option>
|
14178
|
+
</select>
|
14179
|
+
<input type="text" ng-model="contact.value"/>
|
14180
|
+
[ <a href="" ng-click="settings.clearContact(contact)">clear</a>
|
14181
|
+
| <a href="" ng-click="settings.removeContact(contact)">X</a> ]
|
14182
|
+
</li>
|
14183
|
+
<li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
|
14184
|
+
</ul>
|
14185
|
+
</div>
|
14186
|
+
</doc:source>
|
14187
|
+
<doc:scenario>
|
14188
|
+
it('should check controller', function() {
|
14189
|
+
expect(element('.doc-example-live div>:input').val()).toBe('John Smith');
|
14190
|
+
expect(element('.doc-example-live li:nth-child(1) input').val())
|
14191
|
+
.toBe('408 555 1212');
|
14192
|
+
expect(element('.doc-example-live li:nth-child(2) input').val())
|
14193
|
+
.toBe('john.smith@example.org');
|
14194
|
+
|
14195
|
+
element('.doc-example-live li:first a:contains("clear")').click();
|
14196
|
+
expect(element('.doc-example-live li:first input').val()).toBe('');
|
14197
|
+
|
14198
|
+
element('.doc-example-live li:last a:contains("add")').click();
|
14199
|
+
expect(element('.doc-example-live li:nth-child(3) input').val())
|
14200
|
+
.toBe('yourname@example.org');
|
14201
|
+
});
|
14202
|
+
</doc:scenario>
|
14203
|
+
</doc:example>
|
14204
|
+
|
14205
|
+
|
14206
|
+
|
14207
|
+
<doc:example>
|
13830
14208
|
<doc:source>
|
13831
14209
|
<script>
|
13832
14210
|
function SettingsController($scope) {
|
@@ -13889,6 +14267,7 @@ var ngCloakDirective = ngDirective({
|
|
13889
14267
|
});
|
13890
14268
|
</doc:scenario>
|
13891
14269
|
</doc:example>
|
14270
|
+
|
13892
14271
|
*/
|
13893
14272
|
var ngControllerDirective = [function() {
|
13894
14273
|
return {
|
@@ -13902,16 +14281,32 @@ var ngControllerDirective = [function() {
|
|
13902
14281
|
* @name ng.directive:ngCsp
|
13903
14282
|
* @priority 1000
|
13904
14283
|
*
|
14284
|
+
* @element html
|
13905
14285
|
* @description
|
13906
14286
|
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
|
13907
|
-
*
|
13908
|
-
*
|
13909
|
-
*
|
13910
|
-
*
|
13911
|
-
*
|
13912
|
-
*
|
13913
|
-
*
|
13914
|
-
*
|
14287
|
+
*
|
14288
|
+
* This is necessary when developing things like Google Chrome Extensions.
|
14289
|
+
*
|
14290
|
+
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
|
14291
|
+
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
|
14292
|
+
* any of these restrictions.
|
14293
|
+
*
|
14294
|
+
* AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
|
14295
|
+
* it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
|
14296
|
+
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
|
14297
|
+
* be raised.
|
14298
|
+
*
|
14299
|
+
* In order to use this feature put `ngCsp` directive on the root element of the application.
|
14300
|
+
*
|
14301
|
+
* @example
|
14302
|
+
* This example shows how to apply the `ngCsp` directive to the `html` tag.
|
14303
|
+
<pre>
|
14304
|
+
<!doctype html>
|
14305
|
+
<html ng-app ng-csp>
|
14306
|
+
...
|
14307
|
+
...
|
14308
|
+
</html>
|
14309
|
+
</pre>
|
13915
14310
|
*/
|
13916
14311
|
|
13917
14312
|
var ngCspDirective = ['$sniffer', function($sniffer) {
|
@@ -14192,6 +14587,114 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
14192
14587
|
});
|
14193
14588
|
});
|
14194
14589
|
|
14590
|
+
/**
|
14591
|
+
* @ngdoc directive
|
14592
|
+
* @name ng.directive:ngIf
|
14593
|
+
* @restrict A
|
14594
|
+
*
|
14595
|
+
* @description
|
14596
|
+
* The `ngIf` directive removes and recreates a portion of the DOM tree (HTML)
|
14597
|
+
* conditionally based on **"falsy"** and **"truthy"** values, respectively, evaluated within
|
14598
|
+
* an {expression}. In other words, if the expression assigned to **ngIf evaluates to a false
|
14599
|
+
* value** then **the element is removed from the DOM** and **if true** then **a clone of the
|
14600
|
+
* element is reinserted into the DOM**.
|
14601
|
+
*
|
14602
|
+
* `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
|
14603
|
+
* element in the DOM rather than changing its visibility via the `display` css property. A common
|
14604
|
+
* case when this difference is significant is when using css selectors that rely on an element's
|
14605
|
+
* position within the DOM (HTML), such as the `:first-child` or `:last-child` pseudo-classes.
|
14606
|
+
*
|
14607
|
+
* Note that **when an element is removed using ngIf its scope is destroyed** and **a new scope
|
14608
|
+
* is created when the element is restored**. The scope created within `ngIf` inherits from
|
14609
|
+
* its parent scope using
|
14610
|
+
* {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
|
14611
|
+
* An important implication of this is if `ngModel` is used within `ngIf` to bind to
|
14612
|
+
* a javascript primitive defined in the parent scope. In this case any modifications made to the
|
14613
|
+
* variable within the child scope will override (hide) the value in the parent scope.
|
14614
|
+
*
|
14615
|
+
* Also, `ngIf` recreates elements using their compiled state. An example scenario of this behavior
|
14616
|
+
* is if an element's class attribute is directly modified after it's compiled, using something like
|
14617
|
+
* jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
|
14618
|
+
* the added class will be lost because the original compiled state is used to regenerate the element.
|
14619
|
+
*
|
14620
|
+
* Additionally, you can provide animations via the ngAnimate attribute to animate the **enter**
|
14621
|
+
* and **leave** effects.
|
14622
|
+
*
|
14623
|
+
* @animations
|
14624
|
+
* enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
|
14625
|
+
* leave - happens just before the ngIf contents are removed from the DOM
|
14626
|
+
*
|
14627
|
+
* @element ANY
|
14628
|
+
* @scope
|
14629
|
+
* @param {expression} ngIf If the {@link guide/expression expression} is falsy then
|
14630
|
+
* the element is removed from the DOM tree (HTML).
|
14631
|
+
*
|
14632
|
+
* @example
|
14633
|
+
<example animations="true">
|
14634
|
+
<file name="index.html">
|
14635
|
+
Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
|
14636
|
+
Show when checked:
|
14637
|
+
<span ng-if="checked" ng-animate="'example'">
|
14638
|
+
I'm removed when the checkbox is unchecked.
|
14639
|
+
</span>
|
14640
|
+
</file>
|
14641
|
+
<file name="animations.css">
|
14642
|
+
.example-leave, .example-enter {
|
14643
|
+
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14644
|
+
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14645
|
+
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14646
|
+
-o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14647
|
+
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14648
|
+
}
|
14649
|
+
|
14650
|
+
.example-enter {
|
14651
|
+
opacity:0;
|
14652
|
+
}
|
14653
|
+
.example-enter.example-enter-active {
|
14654
|
+
opacity:1;
|
14655
|
+
}
|
14656
|
+
|
14657
|
+
.example-leave {
|
14658
|
+
opacity:1;
|
14659
|
+
}
|
14660
|
+
.example-leave.example-leave-active {
|
14661
|
+
opacity:0;
|
14662
|
+
}
|
14663
|
+
</file>
|
14664
|
+
</example>
|
14665
|
+
*/
|
14666
|
+
var ngIfDirective = ['$animator', function($animator) {
|
14667
|
+
return {
|
14668
|
+
transclude: 'element',
|
14669
|
+
priority: 1000,
|
14670
|
+
terminal: true,
|
14671
|
+
restrict: 'A',
|
14672
|
+
compile: function (element, attr, transclude) {
|
14673
|
+
return function ($scope, $element, $attr) {
|
14674
|
+
var animate = $animator($scope, $attr);
|
14675
|
+
var childElement, childScope;
|
14676
|
+
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
|
14677
|
+
if (childElement) {
|
14678
|
+
animate.leave(childElement);
|
14679
|
+
childElement = undefined;
|
14680
|
+
}
|
14681
|
+
if (childScope) {
|
14682
|
+
childScope.$destroy();
|
14683
|
+
childScope = undefined;
|
14684
|
+
}
|
14685
|
+
if (toBoolean(value)) {
|
14686
|
+
childScope = $scope.$new();
|
14687
|
+
transclude(childScope, function (clone) {
|
14688
|
+
childElement = clone;
|
14689
|
+
animate.enter(clone, $element.parent(), $element);
|
14690
|
+
});
|
14691
|
+
}
|
14692
|
+
});
|
14693
|
+
}
|
14694
|
+
}
|
14695
|
+
}
|
14696
|
+
}];
|
14697
|
+
|
14195
14698
|
/**
|
14196
14699
|
* @ngdoc directive
|
14197
14700
|
* @name ng.directive:ngInclude
|
@@ -14225,7 +14728,7 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
14225
14728
|
* - Otherwise enable scrolling only if the expression evaluates to truthy value.
|
14226
14729
|
*
|
14227
14730
|
* @example
|
14228
|
-
<example>
|
14731
|
+
<example animations="true">
|
14229
14732
|
<file name="index.html">
|
14230
14733
|
<div ng-controller="Ctrl">
|
14231
14734
|
<select ng-model="template" ng-options="t.name for t in templates">
|
@@ -14253,8 +14756,8 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
14253
14756
|
<div>Content of template2.html</div>
|
14254
14757
|
</file>
|
14255
14758
|
<file name="animations.css">
|
14256
|
-
.example-leave
|
14257
|
-
.example-enter
|
14759
|
+
.example-leave,
|
14760
|
+
.example-enter {
|
14258
14761
|
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14259
14762
|
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
14260
14763
|
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
@@ -14273,17 +14776,17 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
14273
14776
|
padding:10px;
|
14274
14777
|
}
|
14275
14778
|
|
14276
|
-
.example-enter
|
14779
|
+
.example-enter {
|
14277
14780
|
top:-50px;
|
14278
14781
|
}
|
14279
|
-
.example-enter
|
14782
|
+
.example-enter.example-enter-active {
|
14280
14783
|
top:0;
|
14281
14784
|
}
|
14282
14785
|
|
14283
|
-
.example-leave
|
14786
|
+
.example-leave {
|
14284
14787
|
top:0;
|
14285
14788
|
}
|
14286
|
-
.example-leave
|
14789
|
+
.example-leave.example-leave-active {
|
14287
14790
|
top:50px;
|
14288
14791
|
}
|
14289
14792
|
</file>
|
@@ -14306,6 +14809,16 @@ var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
|
|
14306
14809
|
*/
|
14307
14810
|
|
14308
14811
|
|
14812
|
+
/**
|
14813
|
+
* @ngdoc event
|
14814
|
+
* @name ng.directive:ngInclude#$includeContentRequested
|
14815
|
+
* @eventOf ng.directive:ngInclude
|
14816
|
+
* @eventType emit on the scope ngInclude was declared in
|
14817
|
+
* @description
|
14818
|
+
* Emitted every time the ngInclude content is requested.
|
14819
|
+
*/
|
14820
|
+
|
14821
|
+
|
14309
14822
|
/**
|
14310
14823
|
* @ngdoc event
|
14311
14824
|
* @name ng.directive:ngInclude#$includeContentLoaded
|
@@ -14362,6 +14875,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|
14362
14875
|
}).error(function() {
|
14363
14876
|
if (thisChangeId === changeCounter) clearContent();
|
14364
14877
|
});
|
14878
|
+
scope.$emit('$includeContentRequested');
|
14365
14879
|
} else {
|
14366
14880
|
clearContent();
|
14367
14881
|
}
|
@@ -14633,7 +15147,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
14633
15147
|
if (!isNaN(value)) {
|
14634
15148
|
//if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
|
14635
15149
|
//check it against pluralization rules in $locale service
|
14636
|
-
if (!whens
|
15150
|
+
if (!(value in whens)) value = $locale.pluralCat(value - offset);
|
14637
15151
|
return whensExpFns[value](scope, element, true);
|
14638
15152
|
} else {
|
14639
15153
|
return '';
|
@@ -14733,9 +15247,9 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
14733
15247
|
</div>
|
14734
15248
|
</file>
|
14735
15249
|
<file name="animations.css">
|
14736
|
-
.example-repeat-enter
|
14737
|
-
.example-repeat-leave
|
14738
|
-
.example-repeat-move
|
15250
|
+
.example-repeat-enter,
|
15251
|
+
.example-repeat-leave,
|
15252
|
+
.example-repeat-move {
|
14739
15253
|
-webkit-transition:all linear 0.5s;
|
14740
15254
|
-moz-transition:all linear 0.5s;
|
14741
15255
|
-ms-transition:all linear 0.5s;
|
@@ -14743,26 +15257,26 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
|
14743
15257
|
transition:all linear 0.5s;
|
14744
15258
|
}
|
14745
15259
|
|
14746
|
-
.example-repeat-enter
|
15260
|
+
.example-repeat-enter {
|
14747
15261
|
line-height:0;
|
14748
15262
|
opacity:0;
|
14749
15263
|
}
|
14750
|
-
.example-repeat-enter
|
15264
|
+
.example-repeat-enter.example-repeat-enter-active {
|
14751
15265
|
line-height:20px;
|
14752
15266
|
opacity:1;
|
14753
15267
|
}
|
14754
15268
|
|
14755
|
-
.example-repeat-leave
|
15269
|
+
.example-repeat-leave {
|
14756
15270
|
opacity:1;
|
14757
15271
|
line-height:20px;
|
14758
15272
|
}
|
14759
|
-
.example-repeat-leave
|
15273
|
+
.example-repeat-leave.example-repeat-leave-active {
|
14760
15274
|
opacity:0;
|
14761
15275
|
line-height:0;
|
14762
15276
|
}
|
14763
15277
|
|
14764
|
-
.example-repeat-move
|
14765
|
-
.example-repeat-move
|
15278
|
+
.example-repeat-move { }
|
15279
|
+
.example-repeat-move.example-repeat-move-active { }
|
14766
15280
|
</file>
|
14767
15281
|
<file name="scenario.js">
|
14768
15282
|
it('should render initial data set', function() {
|
@@ -14798,7 +15312,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
14798
15312
|
var animate = $animator($scope, $attr);
|
14799
15313
|
var expression = $attr.ngRepeat;
|
14800
15314
|
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
14801
|
-
trackByExp,
|
15315
|
+
trackByExp, trackByExpGetter, trackByIdFn, lhs, rhs, valueIdentifier, keyIdentifier,
|
14802
15316
|
hashFnLocals = {$id: hashKey};
|
14803
15317
|
|
14804
15318
|
if (!match) {
|
@@ -14811,13 +15325,13 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
14811
15325
|
trackByExp = match[4];
|
14812
15326
|
|
14813
15327
|
if (trackByExp) {
|
14814
|
-
|
15328
|
+
trackByExpGetter = $parse(trackByExp);
|
14815
15329
|
trackByIdFn = function(key, value, index) {
|
14816
15330
|
// assign key, value, and $index to the locals so that they can be used in hash functions
|
14817
15331
|
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
|
14818
15332
|
hashFnLocals[valueIdentifier] = value;
|
14819
15333
|
hashFnLocals.$index = index;
|
14820
|
-
return
|
15334
|
+
return trackByExpGetter($scope, hashFnLocals);
|
14821
15335
|
};
|
14822
15336
|
} else {
|
14823
15337
|
trackByIdFn = function(key, value) {
|
@@ -14857,7 +15371,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
14857
15371
|
nextBlockOrder = [];
|
14858
15372
|
|
14859
15373
|
|
14860
|
-
if (
|
15374
|
+
if (isArrayLike(collection)) {
|
14861
15375
|
collectionKeys = collection;
|
14862
15376
|
} else {
|
14863
15377
|
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
@@ -14878,7 +15392,8 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
14878
15392
|
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
14879
15393
|
value = collection[key];
|
14880
15394
|
trackById = trackByIdFn(key, value, index);
|
14881
|
-
if((
|
15395
|
+
if(lastBlockMap.hasOwnProperty(trackById)) {
|
15396
|
+
block = lastBlockMap[trackById]
|
14882
15397
|
delete lastBlockMap[trackById];
|
14883
15398
|
nextBlockMap[trackById] = block;
|
14884
15399
|
nextBlockOrder[index] = block;
|
@@ -14888,10 +15403,12 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
14888
15403
|
if (block && block.element) lastBlockMap[block.id] = block;
|
14889
15404
|
});
|
14890
15405
|
// This is a duplicate and we need to throw an error
|
14891
|
-
throw new Error('Duplicates in a repeater are not allowed. Repeater: ' + expression
|
15406
|
+
throw new Error('Duplicates in a repeater are not allowed. Repeater: ' + expression +
|
15407
|
+
' key: ' + trackById);
|
14892
15408
|
} else {
|
14893
15409
|
// new never before seen block
|
14894
15410
|
nextBlockOrder[index] = { id: trackById };
|
15411
|
+
nextBlockMap[trackById] = false;
|
14895
15412
|
}
|
14896
15413
|
}
|
14897
15414
|
|
@@ -15003,7 +15520,7 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
15003
15520
|
</div>
|
15004
15521
|
</file>
|
15005
15522
|
<file name="animations.css">
|
15006
|
-
.example-show
|
15523
|
+
.example-show, .example-hide {
|
15007
15524
|
-webkit-transition:all linear 0.5s;
|
15008
15525
|
-moz-transition:all linear 0.5s;
|
15009
15526
|
-ms-transition:all linear 0.5s;
|
@@ -15011,12 +15528,12 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
15011
15528
|
transition:all linear 0.5s;
|
15012
15529
|
}
|
15013
15530
|
|
15014
|
-
.example-show
|
15531
|
+
.example-show {
|
15015
15532
|
line-height:0;
|
15016
15533
|
opacity:0;
|
15017
15534
|
padding:0 10px;
|
15018
15535
|
}
|
15019
|
-
.example-show-
|
15536
|
+
.example-show-active.example-show-active {
|
15020
15537
|
line-height:20px;
|
15021
15538
|
opacity:1;
|
15022
15539
|
padding:10px;
|
@@ -15024,14 +15541,14 @@ var ngRepeatDirective = ['$parse', '$animator', function($parse, $animator) {
|
|
15024
15541
|
background:white;
|
15025
15542
|
}
|
15026
15543
|
|
15027
|
-
.example-hide
|
15544
|
+
.example-hide {
|
15028
15545
|
line-height:20px;
|
15029
15546
|
opacity:1;
|
15030
15547
|
padding:10px;
|
15031
15548
|
border:1px solid black;
|
15032
15549
|
background:white;
|
15033
15550
|
}
|
15034
|
-
.example-hide-
|
15551
|
+
.example-hide-active.example-hide-active {
|
15035
15552
|
line-height:0;
|
15036
15553
|
opacity:0;
|
15037
15554
|
padding:0 10px;
|
@@ -15112,7 +15629,7 @@ var ngShowDirective = ['$animator', function($animator) {
|
|
15112
15629
|
</div>
|
15113
15630
|
</file>
|
15114
15631
|
<file name="animations.css">
|
15115
|
-
.example-show
|
15632
|
+
.example-show, .example-hide {
|
15116
15633
|
-webkit-transition:all linear 0.5s;
|
15117
15634
|
-moz-transition:all linear 0.5s;
|
15118
15635
|
-ms-transition:all linear 0.5s;
|
@@ -15120,12 +15637,12 @@ var ngShowDirective = ['$animator', function($animator) {
|
|
15120
15637
|
transition:all linear 0.5s;
|
15121
15638
|
}
|
15122
15639
|
|
15123
|
-
.example-show
|
15640
|
+
.example-show {
|
15124
15641
|
line-height:0;
|
15125
15642
|
opacity:0;
|
15126
15643
|
padding:0 10px;
|
15127
15644
|
}
|
15128
|
-
.example-show
|
15645
|
+
.example-show.example-show-active {
|
15129
15646
|
line-height:20px;
|
15130
15647
|
opacity:1;
|
15131
15648
|
padding:10px;
|
@@ -15133,14 +15650,14 @@ var ngShowDirective = ['$animator', function($animator) {
|
|
15133
15650
|
background:white;
|
15134
15651
|
}
|
15135
15652
|
|
15136
|
-
.example-hide
|
15653
|
+
.example-hide {
|
15137
15654
|
line-height:20px;
|
15138
15655
|
opacity:1;
|
15139
15656
|
padding:10px;
|
15140
15657
|
border:1px solid black;
|
15141
15658
|
background:white;
|
15142
15659
|
}
|
15143
|
-
.example-hide
|
15660
|
+
.example-hide.example-hide-active {
|
15144
15661
|
line-height:0;
|
15145
15662
|
opacity:0;
|
15146
15663
|
padding:0 10px;
|
@@ -15292,7 +15809,7 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
15292
15809
|
}
|
15293
15810
|
</file>
|
15294
15811
|
<file name="animations.css">
|
15295
|
-
.example-leave
|
15812
|
+
.example-leave, .example-enter {
|
15296
15813
|
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15297
15814
|
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
15298
15815
|
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
@@ -15311,17 +15828,17 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
15311
15828
|
padding:10px;
|
15312
15829
|
}
|
15313
15830
|
|
15314
|
-
.example-enter
|
15831
|
+
.example-enter {
|
15315
15832
|
top:-50px;
|
15316
15833
|
}
|
15317
|
-
.example-enter
|
15834
|
+
.example-enter.example-enter-active {
|
15318
15835
|
top:0;
|
15319
15836
|
}
|
15320
15837
|
|
15321
|
-
.example-leave
|
15838
|
+
.example-leave {
|
15322
15839
|
top:0;
|
15323
15840
|
}
|
15324
|
-
.example-leave
|
15841
|
+
.example-leave.example-leave-active {
|
15325
15842
|
top:50px;
|
15326
15843
|
}
|
15327
15844
|
</file>
|
@@ -15487,7 +16004,7 @@ var ngTranscludeDirective = ngDirective({
|
|
15487
16004
|
* @example
|
15488
16005
|
<example module="ngView" animations="true">
|
15489
16006
|
<file name="index.html">
|
15490
|
-
<div ng-controller="MainCntl">
|
16007
|
+
<div ng-controller="MainCntl as main">
|
15491
16008
|
Choose:
|
15492
16009
|
<a href="Book/Moby">Moby</a> |
|
15493
16010
|
<a href="Book/Moby/ch/1">Moby: Ch1</a> |
|
@@ -15501,31 +16018,31 @@ var ngTranscludeDirective = ngDirective({
|
|
15501
16018
|
ng-animate="{enter: 'example-enter', leave: 'example-leave'}"></div>
|
15502
16019
|
<hr />
|
15503
16020
|
|
15504
|
-
<pre>$location.path() = {{
|
15505
|
-
<pre>$route.current.templateUrl = {{
|
15506
|
-
<pre>$route.current.params = {{
|
15507
|
-
<pre>$route.current.scope.name = {{
|
15508
|
-
<pre>$routeParams = {{
|
16021
|
+
<pre>$location.path() = {{main.$location.path()}}</pre>
|
16022
|
+
<pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
|
16023
|
+
<pre>$route.current.params = {{main.$route.current.params}}</pre>
|
16024
|
+
<pre>$route.current.scope.name = {{main.$route.current.scope.name}}</pre>
|
16025
|
+
<pre>$routeParams = {{main.$routeParams}}</pre>
|
15509
16026
|
</div>
|
15510
16027
|
</file>
|
15511
16028
|
|
15512
16029
|
<file name="book.html">
|
15513
16030
|
<div>
|
15514
|
-
controller: {{name}}<br />
|
15515
|
-
Book Id: {{params.bookId}}<br />
|
16031
|
+
controller: {{book.name}}<br />
|
16032
|
+
Book Id: {{book.params.bookId}}<br />
|
15516
16033
|
</div>
|
15517
16034
|
</file>
|
15518
16035
|
|
15519
16036
|
<file name="chapter.html">
|
15520
16037
|
<div>
|
15521
|
-
controller: {{name}}<br />
|
15522
|
-
Book Id: {{params.bookId}}<br />
|
15523
|
-
Chapter Id: {{params.chapterId}}
|
16038
|
+
controller: {{chapter.name}}<br />
|
16039
|
+
Book Id: {{chapter.params.bookId}}<br />
|
16040
|
+
Chapter Id: {{chapter.params.chapterId}}
|
15524
16041
|
</div>
|
15525
16042
|
</file>
|
15526
16043
|
|
15527
16044
|
<file name="animations.css">
|
15528
|
-
.example-leave
|
16045
|
+
.example-leave, .example-enter {
|
15529
16046
|
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15530
16047
|
-moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
15531
16048
|
-ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
|
@@ -15551,15 +16068,15 @@ var ngTranscludeDirective = ngDirective({
|
|
15551
16068
|
padding:10px;
|
15552
16069
|
}
|
15553
16070
|
|
15554
|
-
.example-enter
|
16071
|
+
.example-enter {
|
15555
16072
|
left:100%;
|
15556
16073
|
}
|
15557
|
-
.example-enter
|
16074
|
+
.example-enter.example-enter-active {
|
15558
16075
|
left:0;
|
15559
16076
|
}
|
15560
16077
|
|
15561
|
-
.example-leave
|
15562
|
-
.example-leave
|
16078
|
+
.example-leave { }
|
16079
|
+
.example-leave.example-leave-active {
|
15563
16080
|
left:-100%;
|
15564
16081
|
}
|
15565
16082
|
</file>
|
@@ -15568,31 +16085,33 @@ var ngTranscludeDirective = ngDirective({
|
|
15568
16085
|
angular.module('ngView', [], function($routeProvider, $locationProvider) {
|
15569
16086
|
$routeProvider.when('/Book/:bookId', {
|
15570
16087
|
templateUrl: 'book.html',
|
15571
|
-
controller: BookCntl
|
16088
|
+
controller: BookCntl,
|
16089
|
+
controllerAs: 'book'
|
15572
16090
|
});
|
15573
16091
|
$routeProvider.when('/Book/:bookId/ch/:chapterId', {
|
15574
16092
|
templateUrl: 'chapter.html',
|
15575
|
-
controller: ChapterCntl
|
16093
|
+
controller: ChapterCntl,
|
16094
|
+
controllerAs: 'chapter'
|
15576
16095
|
});
|
15577
16096
|
|
15578
16097
|
// configure html5 to get links working on jsfiddle
|
15579
16098
|
$locationProvider.html5Mode(true);
|
15580
16099
|
});
|
15581
16100
|
|
15582
|
-
function MainCntl($
|
15583
|
-
|
15584
|
-
|
15585
|
-
|
16101
|
+
function MainCntl($route, $routeParams, $location) {
|
16102
|
+
this.$route = $route;
|
16103
|
+
this.$location = $location;
|
16104
|
+
this.$routeParams = $routeParams;
|
15586
16105
|
}
|
15587
16106
|
|
15588
|
-
function BookCntl($
|
15589
|
-
|
15590
|
-
|
16107
|
+
function BookCntl($routeParams) {
|
16108
|
+
this.name = "BookCntl";
|
16109
|
+
this.params = $routeParams;
|
15591
16110
|
}
|
15592
16111
|
|
15593
|
-
function ChapterCntl($
|
15594
|
-
|
15595
|
-
|
16112
|
+
function ChapterCntl($routeParams) {
|
16113
|
+
this.name = "ChapterCntl";
|
16114
|
+
this.params = $routeParams;
|
15596
16115
|
}
|
15597
16116
|
</file>
|
15598
16117
|
|
@@ -15656,9 +16175,10 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
15656
16175
|
|
15657
16176
|
if (template) {
|
15658
16177
|
clearContent();
|
15659
|
-
|
16178
|
+
var enterElements = jqLite('<div></div>').html(template).contents();
|
16179
|
+
animate.enter(enterElements, element);
|
15660
16180
|
|
15661
|
-
var link = $compile(
|
16181
|
+
var link = $compile(enterElements),
|
15662
16182
|
current = $route.current,
|
15663
16183
|
controller;
|
15664
16184
|
|
@@ -15666,6 +16186,9 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
15666
16186
|
if (current.controller) {
|
15667
16187
|
locals.$scope = lastScope;
|
15668
16188
|
controller = $controller(current.controller, locals);
|
16189
|
+
if (current.controllerAs) {
|
16190
|
+
lastScope[current.controllerAs] = controller;
|
16191
|
+
}
|
15669
16192
|
element.children().data('$ngControllerController', controller);
|
15670
16193
|
}
|
15671
16194
|
|
@@ -15755,7 +16278,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
15755
16278
|
* `select` model to be bound to a non-string value. This is because an option element can currently
|
15756
16279
|
* be bound to string values only.
|
15757
16280
|
*
|
15758
|
-
* @param {string}
|
16281
|
+
* @param {string} ngModel Assignable angular expression to data-bind to.
|
16282
|
+
* @param {string=} name Property name of the form under which the control is published.
|
15759
16283
|
* @param {string=} required The control is considered valid only if value is entered.
|
15760
16284
|
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
15761
16285
|
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
@@ -15766,7 +16290,7 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
15766
16290
|
* * `label` **`for`** `value` **`in`** `array`
|
15767
16291
|
* * `select` **`as`** `label` **`for`** `value` **`in`** `array`
|
15768
16292
|
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
|
15769
|
-
* * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
|
16293
|
+
* * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
|
15770
16294
|
* * for object data sources:
|
15771
16295
|
* * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
|
15772
16296
|
* * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
|
@@ -15786,6 +16310,9 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
15786
16310
|
* element. If not specified, `select` expression will default to `value`.
|
15787
16311
|
* * `group`: The result of this expression will be used to group options using the `<optgroup>`
|
15788
16312
|
* DOM element.
|
16313
|
+
* * `trackexpr`: Used when working with an array of objects. The result of this expression will be
|
16314
|
+
* used to identify the objects in the array. The `trackexpr` will most likely refer to the
|
16315
|
+
* `value` variable (e.g. `value.propertyName`).
|
15789
16316
|
*
|
15790
16317
|
* @example
|
15791
16318
|
<doc:example>
|
@@ -15850,8 +16377,8 @@ var scriptDirective = ['$templateCache', function($templateCache) {
|
|
15850
16377
|
|
15851
16378
|
var ngOptionsDirective = valueFn({ terminal: true });
|
15852
16379
|
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
15853
|
-
//
|
15854
|
-
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(
|
16380
|
+
//0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000007777000000000000000000088888
|
16381
|
+
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
|
15855
16382
|
nullModelCtrl = {$setViewValue: noop};
|
15856
16383
|
|
15857
16384
|
return {
|
@@ -16025,7 +16552,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16025
16552
|
|
16026
16553
|
if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
|
16027
16554
|
throw Error(
|
16028
|
-
"Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
|
16555
|
+
"Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_ (track by _expr_)?'" +
|
16029
16556
|
" but got '" + optionsExp + "'.");
|
16030
16557
|
}
|
16031
16558
|
|
@@ -16035,6 +16562,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16035
16562
|
groupByFn = $parse(match[3] || ''),
|
16036
16563
|
valueFn = $parse(match[2] ? match[1] : valueName),
|
16037
16564
|
valuesFn = $parse(match[7]),
|
16565
|
+
track = match[8],
|
16566
|
+
trackFn = track ? $parse(match[8]) : null,
|
16038
16567
|
// This is an array of array of existing option groups in DOM. We try to reuse these if possible
|
16039
16568
|
// optionGroupsCache[0] is the options with no option group
|
16040
16569
|
// optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
|
@@ -16075,7 +16604,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16075
16604
|
if ((optionElement = optionGroup[index].element)[0].selected) {
|
16076
16605
|
key = optionElement.val();
|
16077
16606
|
if (keyName) locals[keyName] = key;
|
16078
|
-
|
16607
|
+
if (trackFn) {
|
16608
|
+
for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
16609
|
+
locals[valueName] = collection[trackIndex];
|
16610
|
+
if (trackFn(scope, locals) == key) break;
|
16611
|
+
}
|
16612
|
+
} else {
|
16613
|
+
locals[valueName] = collection[key];
|
16614
|
+
}
|
16079
16615
|
value.push(valueFn(scope, locals));
|
16080
16616
|
}
|
16081
16617
|
}
|
@@ -16087,9 +16623,19 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16087
16623
|
} else if (key == ''){
|
16088
16624
|
value = null;
|
16089
16625
|
} else {
|
16090
|
-
|
16091
|
-
|
16092
|
-
|
16626
|
+
if (trackFn) {
|
16627
|
+
for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
16628
|
+
locals[valueName] = collection[trackIndex];
|
16629
|
+
if (trackFn(scope, locals) == key) {
|
16630
|
+
value = valueFn(scope, locals);
|
16631
|
+
break;
|
16632
|
+
}
|
16633
|
+
}
|
16634
|
+
} else {
|
16635
|
+
locals[valueName] = collection[key];
|
16636
|
+
if (keyName) locals[keyName] = key;
|
16637
|
+
value = valueFn(scope, locals);
|
16638
|
+
}
|
16093
16639
|
}
|
16094
16640
|
}
|
16095
16641
|
ctrl.$setViewValue(value);
|
@@ -16121,11 +16667,15 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16121
16667
|
label;
|
16122
16668
|
|
16123
16669
|
if (multiple) {
|
16124
|
-
|
16125
|
-
|
16126
|
-
|
16127
|
-
|
16128
|
-
|
16670
|
+
if (trackFn && isArray(modelValue)) {
|
16671
|
+
selectedSet = new HashMap([]);
|
16672
|
+
for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
|
16673
|
+
locals[valueName] = modelValue[trackIndex];
|
16674
|
+
selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
|
16675
|
+
}
|
16676
|
+
} else {
|
16677
|
+
selectedSet = new HashMap(modelValue);
|
16678
|
+
}
|
16129
16679
|
}
|
16130
16680
|
|
16131
16681
|
// We now build up the list of options we need (we merge later)
|
@@ -16137,22 +16687,33 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16137
16687
|
optionGroupNames.push(optionGroupName);
|
16138
16688
|
}
|
16139
16689
|
if (multiple) {
|
16140
|
-
selected = selectedSet.remove(valueFn(scope, locals)) != undefined;
|
16690
|
+
selected = selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) != undefined;
|
16141
16691
|
} else {
|
16142
|
-
|
16692
|
+
if (trackFn) {
|
16693
|
+
var modelCast = {};
|
16694
|
+
modelCast[valueName] = modelValue;
|
16695
|
+
selected = trackFn(scope, modelCast) === trackFn(scope, locals);
|
16696
|
+
} else {
|
16697
|
+
selected = modelValue === valueFn(scope, locals);
|
16698
|
+
}
|
16143
16699
|
selectedSet = selectedSet || selected; // see if at least one item is selected
|
16144
16700
|
}
|
16145
16701
|
label = displayFn(scope, locals); // what will be seen by the user
|
16146
16702
|
label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
|
16147
16703
|
optionGroup.push({
|
16148
|
-
id: keyName ? keys[index] : index, // either the index into array or key from object
|
16704
|
+
id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index), // either the index into array or key from object
|
16149
16705
|
label: label,
|
16150
16706
|
selected: selected // determine if we should be selected
|
16151
16707
|
});
|
16152
16708
|
}
|
16153
|
-
if (!multiple
|
16154
|
-
|
16155
|
-
|
16709
|
+
if (!multiple) {
|
16710
|
+
if (nullOption || modelValue === null) {
|
16711
|
+
// insert null option if we have a placeholder, or the model is null
|
16712
|
+
optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
|
16713
|
+
} else if (!selectedSet) {
|
16714
|
+
// option could not be found, we have to insert the undefined item
|
16715
|
+
optionGroups[''].unshift({id:'?', label:'', selected:true});
|
16716
|
+
}
|
16156
16717
|
}
|
16157
16718
|
|
16158
16719
|
// Now we need to update the list of DOM nodes to match the optionGroups we computed above
|
@@ -16196,7 +16757,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
16196
16757
|
if (existingOption.id !== option.id) {
|
16197
16758
|
lastElement.val(existingOption.id = option.id);
|
16198
16759
|
}
|
16199
|
-
|
16760
|
+
// lastElement.prop('selected') provided by jQuery has side-effects
|
16761
|
+
if (lastElement[0].selected !== option.selected) {
|
16200
16762
|
lastElement.prop('selected', (existingOption.selected = option.selected));
|
16201
16763
|
}
|
16202
16764
|
} else {
|