angularjs-rails 1.2.25 → 1.2.26
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.
- checksums.yaml +4 -4
- data/lib/angularjs-rails/version.rb +2 -2
- data/vendor/assets/javascripts/angular-animate.js +1 -1
- data/vendor/assets/javascripts/angular-cookies.js +1 -1
- data/vendor/assets/javascripts/angular-loader.js +2 -2
- data/vendor/assets/javascripts/angular-mocks.js +1 -1
- data/vendor/assets/javascripts/angular-resource.js +1 -1
- data/vendor/assets/javascripts/angular-route.js +1 -4
- data/vendor/assets/javascripts/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/angular-scenario.js +30 -24
- data/vendor/assets/javascripts/angular-touch.js +1 -1
- data/vendor/assets/javascripts/angular.js +30 -24
- data/vendor/assets/javascripts/unstable/angular-animate.js +109 -46
- data/vendor/assets/javascripts/unstable/angular-aria.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-loader.js +2 -2
- data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-mocks.js +15 -4
- data/vendor/assets/javascripts/unstable/angular-resource.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-route.js +69 -43
- data/vendor/assets/javascripts/unstable/angular-sanitize.js +1 -1
- data/vendor/assets/javascripts/unstable/angular-scenario.js +1152 -591
- data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
- data/vendor/assets/javascripts/unstable/angular.js +1092 -509
- metadata +14 -14
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0-rc.
|
2
|
+
* @license AngularJS v1.3.0-rc.5
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -72,7 +72,7 @@ function minErr(module, ErrorConstructor) {
|
|
72
72
|
return match;
|
73
73
|
});
|
74
74
|
|
75
|
-
message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.
|
75
|
+
message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.5/' +
|
76
76
|
(module ? module + '/' : '') + code;
|
77
77
|
for (i = 2; i < arguments.length; i++) {
|
78
78
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0-rc.
|
2
|
+
* @license AngularJS v1.3.0-rc.5
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -53,9 +53,10 @@ angular.mock.$Browser = function() {
|
|
53
53
|
self.onUrlChange = function(listener) {
|
54
54
|
self.pollFns.push(
|
55
55
|
function() {
|
56
|
-
if (self.$$lastUrl
|
56
|
+
if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
|
57
57
|
self.$$lastUrl = self.$$url;
|
58
|
-
|
58
|
+
self.$$lastState = self.$$state;
|
59
|
+
listener(self.$$url, self.$$state);
|
59
60
|
}
|
60
61
|
}
|
61
62
|
);
|
@@ -151,15 +152,24 @@ angular.mock.$Browser.prototype = {
|
|
151
152
|
return pollFn;
|
152
153
|
},
|
153
154
|
|
154
|
-
url: function(url, replace) {
|
155
|
+
url: function(url, replace, state) {
|
156
|
+
if (angular.isUndefined(state)) {
|
157
|
+
state = null;
|
158
|
+
}
|
155
159
|
if (url) {
|
156
160
|
this.$$url = url;
|
161
|
+
// Native pushState serializes & copies the object; simulate it.
|
162
|
+
this.$$state = angular.copy(state);
|
157
163
|
return this;
|
158
164
|
}
|
159
165
|
|
160
166
|
return this.$$url;
|
161
167
|
},
|
162
168
|
|
169
|
+
state: function() {
|
170
|
+
return this.$$state;
|
171
|
+
},
|
172
|
+
|
163
173
|
cookies: function(name, value) {
|
164
174
|
if (name) {
|
165
175
|
if (angular.isUndefined(value)) {
|
@@ -806,6 +816,7 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
|
|
806
816
|
animate.queue.push({
|
807
817
|
event : method,
|
808
818
|
element : arguments[0],
|
819
|
+
options : arguments[arguments.length-1],
|
809
820
|
args : arguments
|
810
821
|
});
|
811
822
|
return $delegate[method].apply($delegate, arguments);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.3.0-rc.
|
2
|
+
* @license AngularJS v1.3.0-rc.5
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -380,6 +380,10 @@ function $RouteProvider(){
|
|
380
380
|
* defined in `resolve` route property. Once all of the dependencies are resolved
|
381
381
|
* `$routeChangeSuccess` is fired.
|
382
382
|
*
|
383
|
+
* The route change (and the `$location` change that triggered it) can be prevented
|
384
|
+
* by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on}
|
385
|
+
* for more details about event object.
|
386
|
+
*
|
383
387
|
* @param {Object} angularEvent Synthetic event object.
|
384
388
|
* @param {Route} next Future route information.
|
385
389
|
* @param {Route} current Current route information.
|
@@ -424,6 +428,8 @@ function $RouteProvider(){
|
|
424
428
|
*/
|
425
429
|
|
426
430
|
var forceReload = false,
|
431
|
+
preparedRoute,
|
432
|
+
preparedRouteIsUpdateOnly,
|
427
433
|
$route = {
|
428
434
|
routes: routes,
|
429
435
|
|
@@ -440,7 +446,11 @@ function $RouteProvider(){
|
|
440
446
|
*/
|
441
447
|
reload: function() {
|
442
448
|
forceReload = true;
|
443
|
-
$rootScope.$evalAsync(
|
449
|
+
$rootScope.$evalAsync(function() {
|
450
|
+
// Don't support cancellation of a reload for now...
|
451
|
+
prepareRoute();
|
452
|
+
commitRoute();
|
453
|
+
});
|
444
454
|
},
|
445
455
|
|
446
456
|
/**
|
@@ -474,7 +484,8 @@ function $RouteProvider(){
|
|
474
484
|
}
|
475
485
|
};
|
476
486
|
|
477
|
-
$rootScope.$on('$
|
487
|
+
$rootScope.$on('$locationChangeStart', prepareRoute);
|
488
|
+
$rootScope.$on('$locationChangeSuccess', commitRoute);
|
478
489
|
|
479
490
|
return $route;
|
480
491
|
|
@@ -512,36 +523,50 @@ function $RouteProvider(){
|
|
512
523
|
return params;
|
513
524
|
}
|
514
525
|
|
515
|
-
function
|
516
|
-
var
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
&& angular.equals(
|
521
|
-
&& !
|
522
|
-
|
523
|
-
|
524
|
-
$rootScope.$broadcast('$
|
525
|
-
|
526
|
+
function prepareRoute($locationEvent) {
|
527
|
+
var lastRoute = $route.current;
|
528
|
+
|
529
|
+
preparedRoute = parseRoute();
|
530
|
+
preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
|
531
|
+
&& angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
|
532
|
+
&& !preparedRoute.reloadOnSearch && !forceReload;
|
533
|
+
|
534
|
+
if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
|
535
|
+
if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
|
536
|
+
if ($locationEvent) {
|
537
|
+
$locationEvent.preventDefault();
|
538
|
+
}
|
539
|
+
}
|
540
|
+
}
|
541
|
+
}
|
542
|
+
|
543
|
+
function commitRoute() {
|
544
|
+
var lastRoute = $route.current;
|
545
|
+
var nextRoute = preparedRoute;
|
546
|
+
|
547
|
+
if (preparedRouteIsUpdateOnly) {
|
548
|
+
lastRoute.params = nextRoute.params;
|
549
|
+
angular.copy(lastRoute.params, $routeParams);
|
550
|
+
$rootScope.$broadcast('$routeUpdate', lastRoute);
|
551
|
+
} else if (nextRoute || lastRoute) {
|
526
552
|
forceReload = false;
|
527
|
-
$
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
$location.path(interpolate(next.redirectTo, next.params)).search(next.params)
|
553
|
+
$route.current = nextRoute;
|
554
|
+
if (nextRoute) {
|
555
|
+
if (nextRoute.redirectTo) {
|
556
|
+
if (angular.isString(nextRoute.redirectTo)) {
|
557
|
+
$location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
|
533
558
|
.replace();
|
534
559
|
} else {
|
535
|
-
$location.url(
|
560
|
+
$location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
|
536
561
|
.replace();
|
537
562
|
}
|
538
563
|
}
|
539
564
|
}
|
540
565
|
|
541
|
-
$q.when(
|
566
|
+
$q.when(nextRoute).
|
542
567
|
then(function() {
|
543
|
-
if (
|
544
|
-
var locals = angular.extend({},
|
568
|
+
if (nextRoute) {
|
569
|
+
var locals = angular.extend({}, nextRoute.resolve),
|
545
570
|
template, templateUrl;
|
546
571
|
|
547
572
|
angular.forEach(locals, function(value, key) {
|
@@ -549,17 +574,17 @@ function $RouteProvider(){
|
|
549
574
|
$injector.get(value) : $injector.invoke(value, null, null, key);
|
550
575
|
});
|
551
576
|
|
552
|
-
if (angular.isDefined(template =
|
577
|
+
if (angular.isDefined(template = nextRoute.template)) {
|
553
578
|
if (angular.isFunction(template)) {
|
554
|
-
template = template(
|
579
|
+
template = template(nextRoute.params);
|
555
580
|
}
|
556
|
-
} else if (angular.isDefined(templateUrl =
|
581
|
+
} else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
|
557
582
|
if (angular.isFunction(templateUrl)) {
|
558
|
-
templateUrl = templateUrl(
|
583
|
+
templateUrl = templateUrl(nextRoute.params);
|
559
584
|
}
|
560
585
|
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
561
586
|
if (angular.isDefined(templateUrl)) {
|
562
|
-
|
587
|
+
nextRoute.loadedTemplateUrl = templateUrl;
|
563
588
|
template = $templateRequest(templateUrl);
|
564
589
|
}
|
565
590
|
}
|
@@ -571,16 +596,16 @@ function $RouteProvider(){
|
|
571
596
|
}).
|
572
597
|
// after route change
|
573
598
|
then(function(locals) {
|
574
|
-
if (
|
575
|
-
if (
|
576
|
-
|
577
|
-
angular.copy(
|
599
|
+
if (nextRoute == $route.current) {
|
600
|
+
if (nextRoute) {
|
601
|
+
nextRoute.locals = locals;
|
602
|
+
angular.copy(nextRoute.params, $routeParams);
|
578
603
|
}
|
579
|
-
$rootScope.$broadcast('$routeChangeSuccess',
|
604
|
+
$rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
|
580
605
|
}
|
581
606
|
}, function(error) {
|
582
|
-
if (
|
583
|
-
$rootScope.$broadcast('$routeChangeError',
|
607
|
+
if (nextRoute == $route.current) {
|
608
|
+
$rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
|
584
609
|
}
|
585
610
|
});
|
586
611
|
}
|
@@ -854,7 +879,7 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
|
|
854
879
|
link: function(scope, $element, attr, ctrl, $transclude) {
|
855
880
|
var currentScope,
|
856
881
|
currentElement,
|
857
|
-
|
882
|
+
previousLeaveAnimation,
|
858
883
|
autoScrollExp = attr.autoscroll,
|
859
884
|
onloadExp = attr.onload || '';
|
860
885
|
|
@@ -862,19 +887,20 @@ function ngViewFactory( $route, $anchorScroll, $animate) {
|
|
862
887
|
update();
|
863
888
|
|
864
889
|
function cleanupLastView() {
|
865
|
-
if(
|
866
|
-
|
867
|
-
|
890
|
+
if(previousLeaveAnimation) {
|
891
|
+
$animate.cancel(previousLeaveAnimation);
|
892
|
+
previousLeaveAnimation = null;
|
868
893
|
}
|
894
|
+
|
869
895
|
if(currentScope) {
|
870
896
|
currentScope.$destroy();
|
871
897
|
currentScope = null;
|
872
898
|
}
|
873
899
|
if(currentElement) {
|
874
|
-
$animate.leave(currentElement)
|
875
|
-
|
900
|
+
previousLeaveAnimation = $animate.leave(currentElement);
|
901
|
+
previousLeaveAnimation.then(function() {
|
902
|
+
previousLeaveAnimation = null;
|
876
903
|
});
|
877
|
-
previousElement = currentElement;
|
878
904
|
currentElement = null;
|
879
905
|
}
|
880
906
|
}
|
@@ -9190,7 +9190,7 @@ return jQuery;
|
|
9190
9190
|
}));
|
9191
9191
|
|
9192
9192
|
/**
|
9193
|
-
* @license AngularJS v1.3.0-rc.
|
9193
|
+
* @license AngularJS v1.3.0-rc.5
|
9194
9194
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
9195
9195
|
* License: MIT
|
9196
9196
|
*/
|
@@ -9263,7 +9263,7 @@ function minErr(module, ErrorConstructor) {
|
|
9263
9263
|
return match;
|
9264
9264
|
});
|
9265
9265
|
|
9266
|
-
message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.
|
9266
|
+
message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.5/' +
|
9267
9267
|
(module ? module + '/' : '') + code;
|
9268
9268
|
for (i = 2; i < arguments.length; i++) {
|
9269
9269
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -9279,6 +9279,7 @@ function minErr(module, ErrorConstructor) {
|
|
9279
9279
|
jqLite: true,
|
9280
9280
|
jQuery: true,
|
9281
9281
|
slice: true,
|
9282
|
+
splice: true,
|
9282
9283
|
push: true,
|
9283
9284
|
toString: true,
|
9284
9285
|
ngMinErr: true,
|
@@ -9355,6 +9356,12 @@ function minErr(module, ErrorConstructor) {
|
|
9355
9356
|
getBlockNodes: true,
|
9356
9357
|
hasOwnProperty: true,
|
9357
9358
|
createMap: true,
|
9359
|
+
|
9360
|
+
NODE_TYPE_ELEMENT: true,
|
9361
|
+
NODE_TYPE_TEXT: true,
|
9362
|
+
NODE_TYPE_COMMENT: true,
|
9363
|
+
NODE_TYPE_DOCUMENT: true,
|
9364
|
+
NODE_TYPE_DOCUMENT_FRAGMENT: true,
|
9358
9365
|
*/
|
9359
9366
|
|
9360
9367
|
////////////////////////////////////
|
@@ -9434,6 +9441,7 @@ var /** holds major version number for IE or NaN for real browsers */
|
|
9434
9441
|
jqLite, // delay binding since jQuery could be loaded after us.
|
9435
9442
|
jQuery, // delay binding
|
9436
9443
|
slice = [].slice,
|
9444
|
+
splice = [].splice,
|
9437
9445
|
push = [].push,
|
9438
9446
|
toString = Object.prototype.toString,
|
9439
9447
|
ngMinErr = minErr('ng'),
|
@@ -9444,13 +9452,10 @@ var /** holds major version number for IE or NaN for real browsers */
|
|
9444
9452
|
uid = 0;
|
9445
9453
|
|
9446
9454
|
/**
|
9447
|
-
*
|
9448
|
-
*
|
9455
|
+
* documentMode is an IE-only property
|
9456
|
+
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
|
9449
9457
|
*/
|
9450
|
-
msie =
|
9451
|
-
if (isNaN(msie)) {
|
9452
|
-
msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
|
9453
|
-
}
|
9458
|
+
msie = document.documentMode;
|
9454
9459
|
|
9455
9460
|
|
9456
9461
|
/**
|
@@ -9466,7 +9471,7 @@ function isArrayLike(obj) {
|
|
9466
9471
|
|
9467
9472
|
var length = obj.length;
|
9468
9473
|
|
9469
|
-
if (obj.nodeType ===
|
9474
|
+
if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
|
9470
9475
|
return true;
|
9471
9476
|
}
|
9472
9477
|
|
@@ -10302,11 +10307,9 @@ function startingTag(element) {
|
|
10302
10307
|
// are not allowed to have children. So we just ignore it.
|
10303
10308
|
element.empty();
|
10304
10309
|
} catch(e) {}
|
10305
|
-
// As Per DOM Standards
|
10306
|
-
var TEXT_NODE = 3;
|
10307
10310
|
var elemHtml = jqLite('<div>').append(element).html();
|
10308
10311
|
try {
|
10309
|
-
return element[0].nodeType ===
|
10312
|
+
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
|
10310
10313
|
elemHtml.
|
10311
10314
|
match(/^(<[^>]+>)/)[1].
|
10312
10315
|
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
@@ -10885,6 +10888,12 @@ function createMap() {
|
|
10885
10888
|
return Object.create(null);
|
10886
10889
|
}
|
10887
10890
|
|
10891
|
+
var NODE_TYPE_ELEMENT = 1;
|
10892
|
+
var NODE_TYPE_TEXT = 3;
|
10893
|
+
var NODE_TYPE_COMMENT = 8;
|
10894
|
+
var NODE_TYPE_DOCUMENT = 9;
|
10895
|
+
var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
|
10896
|
+
|
10888
10897
|
/**
|
10889
10898
|
* @ngdoc type
|
10890
10899
|
* @name angular.Module
|
@@ -11304,11 +11313,11 @@ function setupModuleLoader(window) {
|
|
11304
11313
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
11305
11314
|
*/
|
11306
11315
|
var version = {
|
11307
|
-
full: '1.3.0-rc.
|
11316
|
+
full: '1.3.0-rc.5', // all of these placeholder strings will be replaced by grunt's
|
11308
11317
|
major: 1, // package task
|
11309
11318
|
minor: 3,
|
11310
11319
|
dot: 0,
|
11311
|
-
codeName: '
|
11320
|
+
codeName: 'impossible-choreography'
|
11312
11321
|
};
|
11313
11322
|
|
11314
11323
|
|
@@ -11342,8 +11351,7 @@ function publishExternalAPI(angular){
|
|
11342
11351
|
'getTestability': getTestability,
|
11343
11352
|
'$$minErr': minErr,
|
11344
11353
|
'$$csp': csp,
|
11345
|
-
'reloadWithDebugInfo': reloadWithDebugInfo
|
11346
|
-
'$$hasClass': jqLiteHasClass
|
11354
|
+
'reloadWithDebugInfo': reloadWithDebugInfo
|
11347
11355
|
});
|
11348
11356
|
|
11349
11357
|
angularModule = setupModuleLoader(window);
|
@@ -11489,7 +11497,7 @@ function publishExternalAPI(angular){
|
|
11489
11497
|
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
11490
11498
|
* - [`clone()`](http://api.jquery.com/clone/)
|
11491
11499
|
* - [`contents()`](http://api.jquery.com/contents/)
|
11492
|
-
* - [`css()`](http://api.jquery.com/css/)
|
11500
|
+
* - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
|
11493
11501
|
* - [`data()`](http://api.jquery.com/data/)
|
11494
11502
|
* - [`detach()`](http://api.jquery.com/detach/)
|
11495
11503
|
* - [`empty()`](http://api.jquery.com/empty/)
|
@@ -11611,7 +11619,7 @@ function jqLiteAcceptsData(node) {
|
|
11611
11619
|
// The window object can accept data but has no nodeType
|
11612
11620
|
// Otherwise we are only interested in elements (1) and documents (9)
|
11613
11621
|
var nodeType = node.nodeType;
|
11614
|
-
return nodeType ===
|
11622
|
+
return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
|
11615
11623
|
}
|
11616
11624
|
|
11617
11625
|
function jqLiteBuildFragment(html, context) {
|
@@ -11864,7 +11872,7 @@ function jqLiteController(element, name) {
|
|
11864
11872
|
function jqLiteInheritedData(element, name, value) {
|
11865
11873
|
// if element is the document object work with the html element instead
|
11866
11874
|
// this makes $(document).scope() possible
|
11867
|
-
if(element.nodeType ==
|
11875
|
+
if(element.nodeType == NODE_TYPE_DOCUMENT) {
|
11868
11876
|
element = element.documentElement;
|
11869
11877
|
}
|
11870
11878
|
var names = isArray(name) ? name : [name];
|
@@ -11877,7 +11885,7 @@ function jqLiteInheritedData(element, name, value) {
|
|
11877
11885
|
// If dealing with a document fragment node with a host element, and no parent, use the host
|
11878
11886
|
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
|
11879
11887
|
// to lookup parent controllers.
|
11880
|
-
element = element.parentNode || (element.nodeType ===
|
11888
|
+
element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
|
11881
11889
|
}
|
11882
11890
|
}
|
11883
11891
|
|
@@ -12055,7 +12063,7 @@ forEach({
|
|
12055
12063
|
function getText(element, value) {
|
12056
12064
|
if (isUndefined(value)) {
|
12057
12065
|
var nodeType = element.nodeType;
|
12058
|
-
return (nodeType ===
|
12066
|
+
return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
|
12059
12067
|
}
|
12060
12068
|
element.textContent = value;
|
12061
12069
|
}
|
@@ -12277,7 +12285,7 @@ forEach({
|
|
12277
12285
|
children: function(element) {
|
12278
12286
|
var children = [];
|
12279
12287
|
forEach(element.childNodes, function(element){
|
12280
|
-
if (element.nodeType ===
|
12288
|
+
if (element.nodeType === NODE_TYPE_ELEMENT)
|
12281
12289
|
children.push(element);
|
12282
12290
|
});
|
12283
12291
|
return children;
|
@@ -12289,7 +12297,7 @@ forEach({
|
|
12289
12297
|
|
12290
12298
|
append: function(element, node) {
|
12291
12299
|
var nodeType = element.nodeType;
|
12292
|
-
if (nodeType !==
|
12300
|
+
if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
|
12293
12301
|
|
12294
12302
|
node = new JQLite(node);
|
12295
12303
|
|
@@ -12300,7 +12308,7 @@ forEach({
|
|
12300
12308
|
},
|
12301
12309
|
|
12302
12310
|
prepend: function(element, node) {
|
12303
|
-
if (element.nodeType ===
|
12311
|
+
if (element.nodeType === NODE_TYPE_ELEMENT) {
|
12304
12312
|
var index = element.firstChild;
|
12305
12313
|
forEach(new JQLite(node), function(child){
|
12306
12314
|
element.insertBefore(child, index);
|
@@ -12351,7 +12359,7 @@ forEach({
|
|
12351
12359
|
|
12352
12360
|
parent: function(element) {
|
12353
12361
|
var parent = element.parentNode;
|
12354
|
-
return parent && parent.nodeType !==
|
12362
|
+
return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
|
12355
12363
|
},
|
12356
12364
|
|
12357
12365
|
next: function(element) {
|
@@ -12510,13 +12518,13 @@ HashMap.prototype = {
|
|
12510
12518
|
* @kind function
|
12511
12519
|
*
|
12512
12520
|
* @description
|
12513
|
-
* Creates an injector
|
12521
|
+
* Creates an injector object that can be used for retrieving services as well as for
|
12514
12522
|
* dependency injection (see {@link guide/di dependency injection}).
|
12515
12523
|
*
|
12516
12524
|
|
12517
12525
|
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
|
12518
12526
|
* {@link angular.module}. The `ng` module must be explicitly added.
|
12519
|
-
* @returns {function()} Injector
|
12527
|
+
* @returns {function()} Injector object. See {@link auto.$injector $injector}.
|
12520
12528
|
*
|
12521
12529
|
* @example
|
12522
12530
|
* Typical usage
|
@@ -12623,7 +12631,6 @@ function annotate(fn, strictDi, name) {
|
|
12623
12631
|
/**
|
12624
12632
|
* @ngdoc service
|
12625
12633
|
* @name $injector
|
12626
|
-
* @kind function
|
12627
12634
|
*
|
12628
12635
|
* @description
|
12629
12636
|
*
|
@@ -12638,7 +12645,7 @@ function annotate(fn, strictDi, name) {
|
|
12638
12645
|
* expect($injector.get('$injector')).toBe($injector);
|
12639
12646
|
* expect($injector.invoke(function($injector) {
|
12640
12647
|
* return $injector;
|
12641
|
-
* }).toBe($injector);
|
12648
|
+
* })).toBe($injector);
|
12642
12649
|
* ```
|
12643
12650
|
*
|
12644
12651
|
* # Injection Function Annotation
|
@@ -12705,8 +12712,8 @@ function annotate(fn, strictDi, name) {
|
|
12705
12712
|
* @description
|
12706
12713
|
* Allows the user to query if the particular service exists.
|
12707
12714
|
*
|
12708
|
-
* @param {string} Name of the service to query.
|
12709
|
-
* @returns {boolean}
|
12715
|
+
* @param {string} name Name of the service to query.
|
12716
|
+
* @returns {boolean} `true` if injector has given service.
|
12710
12717
|
*/
|
12711
12718
|
|
12712
12719
|
/**
|
@@ -13166,7 +13173,21 @@ function createInjector(modulesToLoad, strictDi) {
|
|
13166
13173
|
return providerCache[name + providerSuffix] = provider_;
|
13167
13174
|
}
|
13168
13175
|
|
13169
|
-
function
|
13176
|
+
function enforceReturnValue(name, factory) {
|
13177
|
+
return function enforcedReturnValue() {
|
13178
|
+
var result = instanceInjector.invoke(factory);
|
13179
|
+
if (isUndefined(result)) {
|
13180
|
+
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
|
13181
|
+
}
|
13182
|
+
return result;
|
13183
|
+
};
|
13184
|
+
}
|
13185
|
+
|
13186
|
+
function factory(name, factoryFn, enforce) {
|
13187
|
+
return provider(name, {
|
13188
|
+
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
|
13189
|
+
});
|
13190
|
+
}
|
13170
13191
|
|
13171
13192
|
function service(name, constructor) {
|
13172
13193
|
return factory(name, ['$injector', function($injector) {
|
@@ -13174,7 +13195,7 @@ function createInjector(modulesToLoad, strictDi) {
|
|
13174
13195
|
}]);
|
13175
13196
|
}
|
13176
13197
|
|
13177
|
-
function value(name, val) { return factory(name, valueFn(val)); }
|
13198
|
+
function value(name, val) { return factory(name, valueFn(val), false); }
|
13178
13199
|
|
13179
13200
|
function constant(name, value) {
|
13180
13201
|
assertNotHasOwnProperty(name, 'constant');
|
@@ -13425,7 +13446,10 @@ function $AnchorScrollProvider() {
|
|
13425
13446
|
// (no url change, no $location.hash() change), browser native does scroll
|
13426
13447
|
if (autoScrollingEnabled) {
|
13427
13448
|
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
|
13428
|
-
function autoScrollWatchAction() {
|
13449
|
+
function autoScrollWatchAction(newVal, oldVal) {
|
13450
|
+
// skip the initial scroll if $location.hash is empty
|
13451
|
+
if (newVal === oldVal && newVal === '') return;
|
13452
|
+
|
13429
13453
|
$rootScope.$evalAsync(scroll);
|
13430
13454
|
});
|
13431
13455
|
}
|
@@ -13515,9 +13539,57 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13515
13539
|
return this.$$classNameFilter;
|
13516
13540
|
};
|
13517
13541
|
|
13518
|
-
this.$get = ['$$q', '$$asyncCallback', function($$q, $$asyncCallback) {
|
13542
|
+
this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) {
|
13519
13543
|
|
13520
13544
|
var currentDefer;
|
13545
|
+
|
13546
|
+
function runAnimationPostDigest(fn) {
|
13547
|
+
var cancelFn, defer = $$q.defer();
|
13548
|
+
defer.promise.$$cancelFn = function ngAnimateMaybeCancel() {
|
13549
|
+
cancelFn && cancelFn();
|
13550
|
+
};
|
13551
|
+
|
13552
|
+
$rootScope.$$postDigest(function ngAnimatePostDigest() {
|
13553
|
+
cancelFn = fn(function ngAnimateNotifyComplete() {
|
13554
|
+
defer.resolve();
|
13555
|
+
});
|
13556
|
+
});
|
13557
|
+
|
13558
|
+
return defer.promise;
|
13559
|
+
}
|
13560
|
+
|
13561
|
+
function resolveElementClasses(element, cache) {
|
13562
|
+
var toAdd = [], toRemove = [];
|
13563
|
+
|
13564
|
+
var hasClasses = createMap();
|
13565
|
+
forEach((element.attr('class') || '').split(/\s+/), function(className) {
|
13566
|
+
hasClasses[className] = true;
|
13567
|
+
});
|
13568
|
+
|
13569
|
+
forEach(cache.classes, function(status, className) {
|
13570
|
+
var hasClass = hasClasses[className];
|
13571
|
+
|
13572
|
+
// If the most recent class manipulation (via $animate) was to remove the class, and the
|
13573
|
+
// element currently has the class, the class is scheduled for removal. Otherwise, if
|
13574
|
+
// the most recent class manipulation (via $animate) was to add the class, and the
|
13575
|
+
// element does not currently have the class, the class is scheduled to be added.
|
13576
|
+
if (status === false && hasClass) {
|
13577
|
+
toRemove.push(className);
|
13578
|
+
} else if (status === true && !hasClass) {
|
13579
|
+
toAdd.push(className);
|
13580
|
+
}
|
13581
|
+
});
|
13582
|
+
|
13583
|
+
return (toAdd.length + toRemove.length) > 0 && [toAdd.length && toAdd, toRemove.length && toRemove];
|
13584
|
+
}
|
13585
|
+
|
13586
|
+
function cachedClassManipulation(cache, classes, op) {
|
13587
|
+
for (var i=0, ii = classes.length; i < ii; ++i) {
|
13588
|
+
var className = classes[i];
|
13589
|
+
cache[className] = op;
|
13590
|
+
}
|
13591
|
+
}
|
13592
|
+
|
13521
13593
|
function asyncPromise() {
|
13522
13594
|
// only serve one instance of a promise in order to save CPU cycles
|
13523
13595
|
if (!currentDefer) {
|
@@ -13621,13 +13693,17 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13621
13693
|
* @return {Promise} the animation callback promise
|
13622
13694
|
*/
|
13623
13695
|
addClass : function(element, className) {
|
13696
|
+
return this.setClass(element, className, []);
|
13697
|
+
},
|
13698
|
+
|
13699
|
+
$$addClassImmediately : function addClassImmediately(element, className) {
|
13700
|
+
element = jqLite(element);
|
13624
13701
|
className = !isString(className)
|
13625
13702
|
? (isArray(className) ? className.join(' ') : '')
|
13626
13703
|
: className;
|
13627
13704
|
forEach(element, function (element) {
|
13628
13705
|
jqLiteAddClass(element, className);
|
13629
13706
|
});
|
13630
|
-
return asyncPromise();
|
13631
13707
|
},
|
13632
13708
|
|
13633
13709
|
/**
|
@@ -13643,6 +13719,11 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13643
13719
|
* @return {Promise} the animation callback promise
|
13644
13720
|
*/
|
13645
13721
|
removeClass : function(element, className) {
|
13722
|
+
return this.setClass(element, [], className);
|
13723
|
+
},
|
13724
|
+
|
13725
|
+
$$removeClassImmediately : function removeClassImmediately(element, className) {
|
13726
|
+
element = jqLite(element);
|
13646
13727
|
className = !isString(className)
|
13647
13728
|
? (isArray(className) ? className.join(' ') : '')
|
13648
13729
|
: className;
|
@@ -13665,10 +13746,53 @@ var $AnimateProvider = ['$provide', function($provide) {
|
|
13665
13746
|
* @param {string} remove the CSS class which will be removed from the element
|
13666
13747
|
* @return {Promise} the animation callback promise
|
13667
13748
|
*/
|
13668
|
-
setClass : function(element, add, remove) {
|
13669
|
-
this
|
13670
|
-
|
13671
|
-
|
13749
|
+
setClass : function(element, add, remove, runSynchronously) {
|
13750
|
+
var self = this;
|
13751
|
+
var STORAGE_KEY = '$$animateClasses';
|
13752
|
+
var createdCache = false;
|
13753
|
+
element = jqLite(element);
|
13754
|
+
|
13755
|
+
if (runSynchronously) {
|
13756
|
+
// TODO(@caitp/@matsko): Remove undocumented `runSynchronously` parameter, and always
|
13757
|
+
// perform DOM manipulation asynchronously or in postDigest.
|
13758
|
+
self.$$addClassImmediately(element, add);
|
13759
|
+
self.$$removeClassImmediately(element, remove);
|
13760
|
+
return asyncPromise();
|
13761
|
+
}
|
13762
|
+
|
13763
|
+
var cache = element.data(STORAGE_KEY);
|
13764
|
+
if (!cache) {
|
13765
|
+
cache = {
|
13766
|
+
classes: {}
|
13767
|
+
};
|
13768
|
+
createdCache = true;
|
13769
|
+
}
|
13770
|
+
|
13771
|
+
var classes = cache.classes;
|
13772
|
+
|
13773
|
+
add = isArray(add) ? add : add.split(' ');
|
13774
|
+
remove = isArray(remove) ? remove : remove.split(' ');
|
13775
|
+
cachedClassManipulation(classes, add, true);
|
13776
|
+
cachedClassManipulation(classes, remove, false);
|
13777
|
+
|
13778
|
+
if (createdCache) {
|
13779
|
+
cache.promise = runAnimationPostDigest(function(done) {
|
13780
|
+
var cache = element.data(STORAGE_KEY);
|
13781
|
+
element.removeData(STORAGE_KEY);
|
13782
|
+
|
13783
|
+
var classes = cache && resolveElementClasses(element, cache);
|
13784
|
+
|
13785
|
+
if (classes) {
|
13786
|
+
if (classes[0]) self.$$addClassImmediately(element, classes[0]);
|
13787
|
+
if (classes[1]) self.$$removeClassImmediately(element, classes[1]);
|
13788
|
+
}
|
13789
|
+
|
13790
|
+
done();
|
13791
|
+
});
|
13792
|
+
element.data(STORAGE_KEY, cache);
|
13793
|
+
}
|
13794
|
+
|
13795
|
+
return cache.promise;
|
13672
13796
|
},
|
13673
13797
|
|
13674
13798
|
enabled : noop,
|
@@ -13687,6 +13811,8 @@ function $$AsyncCallbackProvider(){
|
|
13687
13811
|
}];
|
13688
13812
|
}
|
13689
13813
|
|
13814
|
+
/* global stripHash: true */
|
13815
|
+
|
13690
13816
|
/**
|
13691
13817
|
* ! This is a private undocumented service !
|
13692
13818
|
*
|
@@ -13810,8 +13936,9 @@ function Browser(window, document, $log, $sniffer) {
|
|
13810
13936
|
//////////////////////////////////////////////////////////////
|
13811
13937
|
|
13812
13938
|
var lastBrowserUrl = location.href,
|
13939
|
+
lastHistoryState = history.state,
|
13813
13940
|
baseElement = document.find('base'),
|
13814
|
-
|
13941
|
+
reloadLocation = null;
|
13815
13942
|
|
13816
13943
|
/**
|
13817
13944
|
* @name $browser#url
|
@@ -13830,26 +13957,42 @@ function Browser(window, document, $log, $sniffer) {
|
|
13830
13957
|
* {@link ng.$location $location service} to change url.
|
13831
13958
|
*
|
13832
13959
|
* @param {string} url New url (when used as setter)
|
13833
|
-
* @param {boolean=} replace Should new url replace current history record
|
13960
|
+
* @param {boolean=} replace Should new url replace current history record?
|
13961
|
+
* @param {object=} state object to use with pushState/replaceState
|
13834
13962
|
*/
|
13835
|
-
self.url = function(url, replace) {
|
13963
|
+
self.url = function(url, replace, state) {
|
13964
|
+
// In modern browsers `history.state` is `null` by default; treating it separately
|
13965
|
+
// from `undefined` would cause `$browser.url('/foo')` to change `history.state`
|
13966
|
+
// to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
|
13967
|
+
if (isUndefined(state)) {
|
13968
|
+
state = null;
|
13969
|
+
}
|
13970
|
+
|
13836
13971
|
// Android Browser BFCache causes location, history reference to become stale.
|
13837
13972
|
if (location !== window.location) location = window.location;
|
13838
13973
|
if (history !== window.history) history = window.history;
|
13839
13974
|
|
13840
13975
|
// setter
|
13841
13976
|
if (url) {
|
13842
|
-
if
|
13977
|
+
// Don't change anything if previous and current URLs and states match. This also prevents
|
13978
|
+
// IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
|
13979
|
+
// See https://github.com/angular/angular.js/commit/ffb2701
|
13980
|
+
if (lastBrowserUrl === url && (!$sniffer.history || history.state === state)) {
|
13981
|
+
return;
|
13982
|
+
}
|
13983
|
+
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
|
13843
13984
|
lastBrowserUrl = url;
|
13844
|
-
|
13845
|
-
|
13846
|
-
|
13847
|
-
|
13848
|
-
|
13849
|
-
|
13850
|
-
|
13985
|
+
// Don't use history API if only the hash changed
|
13986
|
+
// due to a bug in IE10/IE11 which leads
|
13987
|
+
// to not firing a `hashchange` nor `popstate` event
|
13988
|
+
// in some cases (see #9143).
|
13989
|
+
if ($sniffer.history && (!sameBase || history.state !== state)) {
|
13990
|
+
history[replace ? 'replaceState' : 'pushState'](state, '', url);
|
13991
|
+
lastHistoryState = history.state;
|
13851
13992
|
} else {
|
13852
|
-
|
13993
|
+
if (!sameBase) {
|
13994
|
+
reloadLocation = url;
|
13995
|
+
}
|
13853
13996
|
if (replace) {
|
13854
13997
|
location.replace(url);
|
13855
13998
|
} else {
|
@@ -13859,23 +14002,38 @@ function Browser(window, document, $log, $sniffer) {
|
|
13859
14002
|
return self;
|
13860
14003
|
// getter
|
13861
14004
|
} else {
|
13862
|
-
// -
|
13863
|
-
//
|
14005
|
+
// - reloadLocation is needed as browsers don't allow to read out
|
14006
|
+
// the new location.href if a reload happened.
|
13864
14007
|
// - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
|
13865
|
-
return
|
14008
|
+
return reloadLocation || location.href.replace(/%27/g,"'");
|
13866
14009
|
}
|
13867
14010
|
};
|
13868
14011
|
|
14012
|
+
/**
|
14013
|
+
* @name $browser#state
|
14014
|
+
*
|
14015
|
+
* @description
|
14016
|
+
* This method is a getter.
|
14017
|
+
*
|
14018
|
+
* Return history.state or null if history.state is undefined.
|
14019
|
+
*
|
14020
|
+
* @returns {object} state
|
14021
|
+
*/
|
14022
|
+
self.state = function() {
|
14023
|
+
return isUndefined(history.state) ? null : history.state;
|
14024
|
+
};
|
14025
|
+
|
13869
14026
|
var urlChangeListeners = [],
|
13870
14027
|
urlChangeInit = false;
|
13871
14028
|
|
13872
14029
|
function fireUrlChange() {
|
13873
|
-
|
13874
|
-
|
14030
|
+
if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
|
14031
|
+
return;
|
14032
|
+
}
|
13875
14033
|
|
13876
14034
|
lastBrowserUrl = self.url();
|
13877
14035
|
forEach(urlChangeListeners, function(listener) {
|
13878
|
-
listener(self.url());
|
14036
|
+
listener(self.url(), history.state);
|
13879
14037
|
});
|
13880
14038
|
}
|
13881
14039
|
|
@@ -13910,9 +14068,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
13910
14068
|
// html5 history api - popstate event
|
13911
14069
|
if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
|
13912
14070
|
// hashchange event
|
13913
|
-
|
13914
|
-
// polling
|
13915
|
-
else self.addPollFn(fireUrlChange);
|
14071
|
+
jqLite(window).on('hashchange', fireUrlChange);
|
13916
14072
|
|
13917
14073
|
urlChangeInit = true;
|
13918
14074
|
}
|
@@ -14687,8 +14843,11 @@ function $TemplateCacheProvider() {
|
|
14687
14843
|
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
|
14688
14844
|
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
|
14689
14845
|
* * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
|
14846
|
+
* * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
|
14690
14847
|
* * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
|
14691
14848
|
* `null` to the `link` fn if not found.
|
14849
|
+
* * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
|
14850
|
+
* `null` to the `link` fn if not found.
|
14692
14851
|
*
|
14693
14852
|
*
|
14694
14853
|
* #### `controllerAs`
|
@@ -14766,22 +14925,18 @@ function $TemplateCacheProvider() {
|
|
14766
14925
|
* (because SVG doesn't work with custom elements in the DOM tree).
|
14767
14926
|
*
|
14768
14927
|
* #### `transclude`
|
14769
|
-
*
|
14770
|
-
*
|
14771
|
-
*
|
14772
|
-
* transclusion function which is pre-bound to the correct scope. In a typical setup the widget
|
14773
|
-
* creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
|
14774
|
-
* scope. This makes it possible for the widget to have private state, and the transclusion to
|
14775
|
-
* be bound to the parent (pre-`isolate`) scope.
|
14928
|
+
* Extract the contents of the element where the directive appears and make it available to the directive.
|
14929
|
+
* The contents are compiled and provided to the directive as a **transclusion function**. See the
|
14930
|
+
* {@link $compile#transclusion Transclusion} section below.
|
14776
14931
|
*
|
14777
|
-
*
|
14778
|
-
*
|
14932
|
+
* There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
|
14933
|
+
* directive's element or the entire element:
|
14934
|
+
*
|
14935
|
+
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
|
14936
|
+
* * `'element'` - transclude the whole of the directive's element including any directives on this
|
14937
|
+
* element that defined at a lower priority than this directive. When used, the `template`
|
14938
|
+
* property is ignored.
|
14779
14939
|
*
|
14780
|
-
* <div class="alert alert-warning">
|
14781
|
-
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
|
14782
|
-
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
|
14783
|
-
* Testing Transclusion Directives}.
|
14784
|
-
* </div>
|
14785
14940
|
*
|
14786
14941
|
* #### `compile`
|
14787
14942
|
*
|
@@ -14879,7 +15034,121 @@ function $TemplateCacheProvider() {
|
|
14879
15034
|
* It is safe to do DOM transformation in the post-linking function on elements that are not waiting
|
14880
15035
|
* for their async templates to be resolved.
|
14881
15036
|
*
|
14882
|
-
*
|
15037
|
+
*
|
15038
|
+
* ### Transclusion
|
15039
|
+
*
|
15040
|
+
* Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
|
15041
|
+
* copying them to another part of the DOM, while maintaining their connection to the original AngularJS
|
15042
|
+
* scope from where they were taken.
|
15043
|
+
*
|
15044
|
+
* Transclusion is used (often with {@link ngTransclude}) to insert the
|
15045
|
+
* original contents of a directive's element into a specified place in the template of the directive.
|
15046
|
+
* The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
|
15047
|
+
* content has access to the properties on the scope from which it was taken, even if the directive
|
15048
|
+
* has isolated scope.
|
15049
|
+
* See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
|
15050
|
+
*
|
15051
|
+
* This makes it possible for the widget to have private state for its template, while the transcluded
|
15052
|
+
* content has access to its originating scope.
|
15053
|
+
*
|
15054
|
+
* <div class="alert alert-warning">
|
15055
|
+
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
|
15056
|
+
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
|
15057
|
+
* Testing Transclusion Directives}.
|
15058
|
+
* </div>
|
15059
|
+
*
|
15060
|
+
* #### Transclusion Functions
|
15061
|
+
*
|
15062
|
+
* When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
|
15063
|
+
* function** to the directive's `link` function and `controller`. This transclusion function is a special
|
15064
|
+
* **linking function** that will return the compiled contents linked to a new transclusion scope.
|
15065
|
+
*
|
15066
|
+
* <div class="alert alert-info">
|
15067
|
+
* If you are just using {@link ngTransclude} then you don't need to worry about this function, since
|
15068
|
+
* ngTransclude will deal with it for us.
|
15069
|
+
* </div>
|
15070
|
+
*
|
15071
|
+
* If you want to manually control the insertion and removal of the transcluded content in your directive
|
15072
|
+
* then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
|
15073
|
+
* object that contains the compiled DOM, which is linked to the correct transclusion scope.
|
15074
|
+
*
|
15075
|
+
* When you call a transclusion function you can pass in a **clone attach function**. This function is accepts
|
15076
|
+
* two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
|
15077
|
+
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
|
15078
|
+
*
|
15079
|
+
* <div class="alert alert-info">
|
15080
|
+
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
|
15081
|
+
* since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
|
15082
|
+
* </div>
|
15083
|
+
*
|
15084
|
+
* It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
|
15085
|
+
* attach function**:
|
15086
|
+
*
|
15087
|
+
* ```js
|
15088
|
+
* var transcludedContent, transclusionScope;
|
15089
|
+
*
|
15090
|
+
* $transclude(function(clone, scope) {
|
15091
|
+
* element.append(clone);
|
15092
|
+
* transcludedContent = clone;
|
15093
|
+
* transclusionScope = scope;
|
15094
|
+
* });
|
15095
|
+
* ```
|
15096
|
+
*
|
15097
|
+
* Later, if you want to remove the transcluded content from your DOM then you should also destroy the
|
15098
|
+
* associated transclusion scope:
|
15099
|
+
*
|
15100
|
+
* ```js
|
15101
|
+
* transcludedContent.remove();
|
15102
|
+
* transclusionScope.$destroy();
|
15103
|
+
* ```
|
15104
|
+
*
|
15105
|
+
* <div class="alert alert-info">
|
15106
|
+
* **Best Practice**: if you intend to add and remove transcluded content manually in your directive
|
15107
|
+
* (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
|
15108
|
+
* then you are also responsible for calling `$destroy` on the transclusion scope.
|
15109
|
+
* </div>
|
15110
|
+
*
|
15111
|
+
* The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
|
15112
|
+
* automatically destroy their transluded clones as necessary so you do not need to worry about this if
|
15113
|
+
* you are simply using {@link ngTransclude} to inject the transclusion into your directive.
|
15114
|
+
*
|
15115
|
+
*
|
15116
|
+
* #### Transclusion Scopes
|
15117
|
+
*
|
15118
|
+
* When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
|
15119
|
+
* scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
|
15120
|
+
* when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
|
15121
|
+
* was taken.
|
15122
|
+
*
|
15123
|
+
* For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
|
15124
|
+
* like this:
|
15125
|
+
*
|
15126
|
+
* ```html
|
15127
|
+
* <div ng-app>
|
15128
|
+
* <div isolate>
|
15129
|
+
* <div transclusion>
|
15130
|
+
* </div>
|
15131
|
+
* </div>
|
15132
|
+
* </div>
|
15133
|
+
* ```
|
15134
|
+
*
|
15135
|
+
* The `$parent` scope hierarchy will look like this:
|
15136
|
+
*
|
15137
|
+
* ```
|
15138
|
+
* - $rootScope
|
15139
|
+
* - isolate
|
15140
|
+
* - transclusion
|
15141
|
+
* ```
|
15142
|
+
*
|
15143
|
+
* but the scopes will inherit prototypically from different scopes to their `$parent`.
|
15144
|
+
*
|
15145
|
+
* ```
|
15146
|
+
* - $rootScope
|
15147
|
+
* - transclusion
|
15148
|
+
* - isolate
|
15149
|
+
* ```
|
15150
|
+
*
|
15151
|
+
*
|
14883
15152
|
* ### Attributes
|
14884
15153
|
*
|
14885
15154
|
* The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
@@ -14917,7 +15186,7 @@ function $TemplateCacheProvider() {
|
|
14917
15186
|
* }
|
14918
15187
|
* ```
|
14919
15188
|
*
|
14920
|
-
*
|
15189
|
+
* ## Example
|
14921
15190
|
*
|
14922
15191
|
* <div class="alert alert-warning">
|
14923
15192
|
* **Note**: Typically directives are registered with `module.directive`. The example below is
|
@@ -15042,7 +15311,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15042
15311
|
Suffix = 'Directive',
|
15043
15312
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
|
15044
15313
|
CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
|
15045
|
-
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset')
|
15314
|
+
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
|
15315
|
+
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
|
15046
15316
|
|
15047
15317
|
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
|
15048
15318
|
// The assumption is that future DOM event attribute names will begin with
|
@@ -15347,10 +15617,44 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15347
15617
|
|
15348
15618
|
nodeName = nodeName_(this.$$element);
|
15349
15619
|
|
15350
|
-
// sanitize a[href] and img[src] values
|
15351
15620
|
if ((nodeName === 'a' && key === 'href') ||
|
15352
15621
|
(nodeName === 'img' && key === 'src')) {
|
15622
|
+
// sanitize a[href] and img[src] values
|
15353
15623
|
this[key] = value = $$sanitizeUri(value, key === 'src');
|
15624
|
+
} else if (nodeName === 'img' && key === 'srcset') {
|
15625
|
+
// sanitize img[srcset] values
|
15626
|
+
var result = "";
|
15627
|
+
|
15628
|
+
// first check if there are spaces because it's not the same pattern
|
15629
|
+
var trimmedSrcset = trim(value);
|
15630
|
+
// ( 999x ,| 999w ,| ,|, )
|
15631
|
+
var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
|
15632
|
+
var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
|
15633
|
+
|
15634
|
+
// split srcset into tuple of uri and descriptor except for the last item
|
15635
|
+
var rawUris = trimmedSrcset.split(pattern);
|
15636
|
+
|
15637
|
+
// for each tuples
|
15638
|
+
var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
|
15639
|
+
for (var i=0; i<nbrUrisWith2parts; i++) {
|
15640
|
+
var innerIdx = i*2;
|
15641
|
+
// sanitize the uri
|
15642
|
+
result += $$sanitizeUri(trim( rawUris[innerIdx]), true);
|
15643
|
+
// add the descriptor
|
15644
|
+
result += ( " " + trim(rawUris[innerIdx+1]));
|
15645
|
+
}
|
15646
|
+
|
15647
|
+
// split the last item into uri and descriptor
|
15648
|
+
var lastTuple = trim(rawUris[i*2]).split(/\s/);
|
15649
|
+
|
15650
|
+
// sanitize the last uri
|
15651
|
+
result += $$sanitizeUri(trim(lastTuple[0]), true);
|
15652
|
+
|
15653
|
+
// and add the last descriptor if any
|
15654
|
+
if( lastTuple.length === 2) {
|
15655
|
+
result += (" " + trim(lastTuple[1]));
|
15656
|
+
}
|
15657
|
+
this[key] = value = result;
|
15354
15658
|
}
|
15355
15659
|
|
15356
15660
|
if (writeAttr !== false) {
|
@@ -15388,12 +15692,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15388
15692
|
* @param {string} key Normalized key. (ie ngAttribute) .
|
15389
15693
|
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
15390
15694
|
the interpolated value of the attribute changes.
|
15391
|
-
* See
|
15695
|
+
* See {@link ng.$compile#attributes $compile} for more info.
|
15392
15696
|
* @returns {function()} Returns a deregistration function for this observer.
|
15393
15697
|
*/
|
15394
15698
|
$observe: function(key, fn) {
|
15395
15699
|
var attrs = this,
|
15396
|
-
$$observers = (attrs.$$observers || (attrs.$$observers =
|
15700
|
+
$$observers = (attrs.$$observers || (attrs.$$observers = Object.create(null))),
|
15397
15701
|
listeners = ($$observers[key] || ($$observers[key] = []));
|
15398
15702
|
|
15399
15703
|
listeners.push(fn);
|
@@ -15469,7 +15773,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15469
15773
|
// We can not compile top level text elements since text nodes can be merged and we will
|
15470
15774
|
// not be able to attach scope data to them, so we will wrap them in <span>
|
15471
15775
|
forEach($compileNodes, function(node, index){
|
15472
|
-
if (node.nodeType ==
|
15776
|
+
if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
|
15473
15777
|
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
15474
15778
|
}
|
15475
15779
|
});
|
@@ -15478,27 +15782,28 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15478
15782
|
maxPriority, ignoreDirective, previousCompileContext);
|
15479
15783
|
compile.$$addScopeClass($compileNodes);
|
15480
15784
|
var namespace = null;
|
15481
|
-
var namespaceAdaptedCompileNodes = $compileNodes;
|
15482
|
-
var lastCompileNode;
|
15483
15785
|
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
|
15484
15786
|
assertArg(scope, 'scope');
|
15485
15787
|
if (!namespace) {
|
15486
15788
|
namespace = detectNamespaceForChildElements(futureParentElement);
|
15487
15789
|
}
|
15488
|
-
|
15489
|
-
|
15790
|
+
var $linkNode;
|
15791
|
+
if (namespace !== 'html') {
|
15792
|
+
// When using a directive with replace:true and templateUrl the $compileNodes
|
15793
|
+
// (or a child element inside of them)
|
15794
|
+
// might change, so we need to recreate the namespace adapted compileNodes
|
15795
|
+
// for call to the link function.
|
15796
|
+
// Note: This will already clone the nodes...
|
15797
|
+
$linkNode = jqLite(
|
15490
15798
|
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
|
15491
15799
|
);
|
15800
|
+
} else if (cloneConnectFn) {
|
15801
|
+
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
15802
|
+
// and sometimes changes the structure of the DOM.
|
15803
|
+
$linkNode = JQLitePrototype.clone.call($compileNodes);
|
15804
|
+
} else {
|
15805
|
+
$linkNode = $compileNodes;
|
15492
15806
|
}
|
15493
|
-
// When using a directive with replace:true and templateUrl the $compileNodes
|
15494
|
-
// might change, so we need to recreate the namespace adapted compileNodes.
|
15495
|
-
lastCompileNode = $compileNodes[0];
|
15496
|
-
|
15497
|
-
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
15498
|
-
// and sometimes changes the structure of the DOM.
|
15499
|
-
var $linkNode = cloneConnectFn
|
15500
|
-
? JQLitePrototype.clone.call(namespaceAdaptedCompileNodes) // IMPORTANT!!!
|
15501
|
-
: namespaceAdaptedCompileNodes;
|
15502
15807
|
|
15503
15808
|
if (transcludeControllers) {
|
15504
15809
|
for (var controllerName in transcludeControllers) {
|
@@ -15641,20 +15946,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15641
15946
|
|
15642
15947
|
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
|
15643
15948
|
|
15644
|
-
var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement) {
|
15645
|
-
var scopeCreated = false;
|
15949
|
+
var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
|
15646
15950
|
|
15647
15951
|
if (!transcludedScope) {
|
15648
|
-
transcludedScope = scope.$new();
|
15952
|
+
transcludedScope = scope.$new(false, containingScope);
|
15649
15953
|
transcludedScope.$$transcluded = true;
|
15650
|
-
scopeCreated = true;
|
15651
15954
|
}
|
15652
15955
|
|
15653
|
-
|
15654
|
-
if (scopeCreated && !elementTransclusion) {
|
15655
|
-
clone.on('$destroy', function() { transcludedScope.$destroy(); });
|
15656
|
-
}
|
15657
|
-
return clone;
|
15956
|
+
return transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn, futureParentElement);
|
15658
15957
|
};
|
15659
15958
|
|
15660
15959
|
return boundTranscludeFn;
|
@@ -15677,7 +15976,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15677
15976
|
className;
|
15678
15977
|
|
15679
15978
|
switch(nodeType) {
|
15680
|
-
case
|
15979
|
+
case NODE_TYPE_ELEMENT: /* Element */
|
15681
15980
|
// use the node name: <directive>
|
15682
15981
|
addDirective(directives,
|
15683
15982
|
directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
|
@@ -15689,37 +15988,35 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15689
15988
|
var attrEndName = false;
|
15690
15989
|
|
15691
15990
|
attr = nAttrs[j];
|
15692
|
-
|
15693
|
-
|
15694
|
-
value = trim(attr.value);
|
15695
|
-
|
15696
|
-
// support ngAttr attribute binding
|
15697
|
-
ngAttrName = directiveNormalize(name);
|
15698
|
-
if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
|
15699
|
-
name = snake_case(ngAttrName.substr(6), '-');
|
15700
|
-
}
|
15991
|
+
name = attr.name;
|
15992
|
+
value = trim(attr.value);
|
15701
15993
|
|
15702
|
-
|
15703
|
-
|
15704
|
-
|
15705
|
-
|
15706
|
-
|
15707
|
-
name = name.substr(0, name.length - 6);
|
15708
|
-
}
|
15709
|
-
}
|
15994
|
+
// support ngAttr attribute binding
|
15995
|
+
ngAttrName = directiveNormalize(name);
|
15996
|
+
if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
|
15997
|
+
name = snake_case(ngAttrName.substr(6), '-');
|
15998
|
+
}
|
15710
15999
|
|
15711
|
-
|
15712
|
-
|
15713
|
-
if (
|
15714
|
-
|
15715
|
-
|
15716
|
-
|
15717
|
-
}
|
16000
|
+
var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
|
16001
|
+
if (directiveIsMultiElement(directiveNName)) {
|
16002
|
+
if (ngAttrName === directiveNName + 'Start') {
|
16003
|
+
attrStartName = name;
|
16004
|
+
attrEndName = name.substr(0, name.length - 5) + 'end';
|
16005
|
+
name = name.substr(0, name.length - 6);
|
15718
16006
|
}
|
15719
|
-
addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
|
15720
|
-
addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
|
15721
|
-
attrEndName);
|
15722
16007
|
}
|
16008
|
+
|
16009
|
+
nName = directiveNormalize(name.toLowerCase());
|
16010
|
+
attrsMap[nName] = name;
|
16011
|
+
if (isNgAttr || !attrs.hasOwnProperty(nName)) {
|
16012
|
+
attrs[nName] = value;
|
16013
|
+
if (getBooleanAttrName(node, nName)) {
|
16014
|
+
attrs[nName] = true; // presence means true
|
16015
|
+
}
|
16016
|
+
}
|
16017
|
+
addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
|
16018
|
+
addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
|
16019
|
+
attrEndName);
|
15723
16020
|
}
|
15724
16021
|
|
15725
16022
|
// use class as directive
|
@@ -15734,10 +16031,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15734
16031
|
}
|
15735
16032
|
}
|
15736
16033
|
break;
|
15737
|
-
case
|
16034
|
+
case NODE_TYPE_TEXT: /* Text Node */
|
15738
16035
|
addTextInterpolateDirective(directives, node.nodeValue);
|
15739
16036
|
break;
|
15740
|
-
case
|
16037
|
+
case NODE_TYPE_COMMENT: /* Comment */
|
15741
16038
|
try {
|
15742
16039
|
match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
|
15743
16040
|
if (match) {
|
@@ -15777,7 +16074,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15777
16074
|
"Unterminated attribute, found '{0}' but no matching '{1}' found.",
|
15778
16075
|
attrStart, attrEnd);
|
15779
16076
|
}
|
15780
|
-
if (node.nodeType ==
|
16077
|
+
if (node.nodeType == NODE_TYPE_ELEMENT) {
|
15781
16078
|
if (node.hasAttribute(attrStart)) depth++;
|
15782
16079
|
if (node.hasAttribute(attrEnd)) depth--;
|
15783
16080
|
}
|
@@ -15956,11 +16253,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
15956
16253
|
if (jqLiteIsTextNode(directiveValue)) {
|
15957
16254
|
$template = [];
|
15958
16255
|
} else {
|
15959
|
-
$template =
|
16256
|
+
$template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
|
15960
16257
|
}
|
15961
16258
|
compileNode = $template[0];
|
15962
16259
|
|
15963
|
-
if ($template.length != 1 || compileNode.nodeType !==
|
16260
|
+
if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
|
15964
16261
|
throw $compileMinErr('tplrt',
|
15965
16262
|
"Template for directive '{0}' must have exactly one root element. {1}",
|
15966
16263
|
directiveName, '');
|
@@ -16064,14 +16361,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16064
16361
|
|
16065
16362
|
function getControllers(directiveName, require, $element, elementControllers) {
|
16066
16363
|
var value, retrievalMethod = 'data', optional = false;
|
16364
|
+
var $searchElement = $element;
|
16365
|
+
var match;
|
16067
16366
|
if (isString(require)) {
|
16068
|
-
|
16069
|
-
|
16070
|
-
|
16071
|
-
|
16072
|
-
|
16073
|
-
|
16367
|
+
match = require.match(REQUIRE_PREFIX_REGEXP);
|
16368
|
+
require = require.substring(match[0].length);
|
16369
|
+
|
16370
|
+
if (match[3]) {
|
16371
|
+
if (match[1]) match[3] = null;
|
16372
|
+
else match[1] = match[3];
|
16074
16373
|
}
|
16374
|
+
if (match[1] === '^') {
|
16375
|
+
retrievalMethod = 'inheritedData';
|
16376
|
+
} else if (match[1] === '^^') {
|
16377
|
+
retrievalMethod = 'inheritedData';
|
16378
|
+
$searchElement = $element.parent();
|
16379
|
+
}
|
16380
|
+
if (match[2] === '?') {
|
16381
|
+
optional = true;
|
16382
|
+
}
|
16383
|
+
|
16075
16384
|
value = null;
|
16076
16385
|
|
16077
16386
|
if (elementControllers && retrievalMethod === 'data') {
|
@@ -16079,7 +16388,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16079
16388
|
value = value.instance;
|
16080
16389
|
}
|
16081
16390
|
}
|
16082
|
-
value = value || $
|
16391
|
+
value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
|
16083
16392
|
|
16084
16393
|
if (!value && !optional) {
|
16085
16394
|
throw $compileMinErr('ctreq',
|
@@ -16285,7 +16594,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16285
16594
|
if (!futureParentElement) {
|
16286
16595
|
futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
|
16287
16596
|
}
|
16288
|
-
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement);
|
16597
|
+
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
|
16289
16598
|
}
|
16290
16599
|
}
|
16291
16600
|
}
|
@@ -16426,11 +16735,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16426
16735
|
if (jqLiteIsTextNode(content)) {
|
16427
16736
|
$template = [];
|
16428
16737
|
} else {
|
16429
|
-
$template =
|
16738
|
+
$template = removeComments(wrapTemplate(templateNamespace, trim(content)));
|
16430
16739
|
}
|
16431
16740
|
compileNode = $template[0];
|
16432
16741
|
|
16433
|
-
if ($template.length != 1 || compileNode.nodeType !==
|
16742
|
+
if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
|
16434
16743
|
throw $compileMinErr('tplrt',
|
16435
16744
|
"Template for directive '{0}' must have exactly one root element. {1}",
|
16436
16745
|
origAsyncDirective.name, templateUrl);
|
@@ -16469,6 +16778,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16469
16778
|
boundTranscludeFn = linkQueue.shift(),
|
16470
16779
|
linkNode = $compileNode[0];
|
16471
16780
|
|
16781
|
+
if (scope.$$destroyed) continue;
|
16782
|
+
|
16472
16783
|
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
|
16473
16784
|
var oldClasses = beforeTemplateLinkNode.className;
|
16474
16785
|
|
@@ -16495,6 +16806,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16495
16806
|
|
16496
16807
|
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
|
16497
16808
|
var childBoundTranscludeFn = boundTranscludeFn;
|
16809
|
+
if (scope.$$destroyed) return;
|
16498
16810
|
if (linkQueue) {
|
16499
16811
|
linkQueue.push(scope);
|
16500
16812
|
linkQueue.push(node);
|
@@ -16611,6 +16923,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
16611
16923
|
"ng- versions (such as ng-click instead of onclick) instead.");
|
16612
16924
|
}
|
16613
16925
|
|
16926
|
+
// If the attribute was removed, then we are done
|
16927
|
+
if (!attr[name]) {
|
16928
|
+
return;
|
16929
|
+
}
|
16930
|
+
|
16614
16931
|
// we need to interpolate again, in case the attribute value has been updated
|
16615
16932
|
// (e.g. by another directive's compile function)
|
16616
16933
|
interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name),
|
@@ -16838,6 +17155,23 @@ function tokenDifference(str1, str2) {
|
|
16838
17155
|
return values;
|
16839
17156
|
}
|
16840
17157
|
|
17158
|
+
function removeComments(jqNodes) {
|
17159
|
+
jqNodes = jqLite(jqNodes);
|
17160
|
+
var i = jqNodes.length;
|
17161
|
+
|
17162
|
+
if (i <= 1) {
|
17163
|
+
return jqNodes;
|
17164
|
+
}
|
17165
|
+
|
17166
|
+
while (i--) {
|
17167
|
+
var node = jqNodes[i];
|
17168
|
+
if (node.nodeType === NODE_TYPE_COMMENT) {
|
17169
|
+
splice.call(jqNodes, i, 1);
|
17170
|
+
}
|
17171
|
+
}
|
17172
|
+
return jqNodes;
|
17173
|
+
}
|
17174
|
+
|
16841
17175
|
/**
|
16842
17176
|
* @ngdoc provider
|
16843
17177
|
* @name $controllerProvider
|
@@ -17141,7 +17475,8 @@ function $HttpProvider() {
|
|
17141
17475
|
var JSON_START = /^\s*(\[|\{[^\{])/,
|
17142
17476
|
JSON_END = /[\}\]]\s*$/,
|
17143
17477
|
PROTECTION_PREFIX = /^\)\]\}',?\n/,
|
17144
|
-
|
17478
|
+
APPLICATION_JSON = 'application/json',
|
17479
|
+
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
|
17145
17480
|
|
17146
17481
|
/**
|
17147
17482
|
* @ngdoc property
|
@@ -17166,12 +17501,15 @@ function $HttpProvider() {
|
|
17166
17501
|
**/
|
17167
17502
|
var defaults = this.defaults = {
|
17168
17503
|
// transform incoming response data
|
17169
|
-
transformResponse: [function(data) {
|
17504
|
+
transformResponse: [function defaultHttpResponseTransform(data, headers) {
|
17170
17505
|
if (isString(data)) {
|
17171
17506
|
// strip json vulnerability protection prefix
|
17172
17507
|
data = data.replace(PROTECTION_PREFIX, '');
|
17173
|
-
|
17508
|
+
var contentType = headers('Content-Type');
|
17509
|
+
if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
|
17510
|
+
(JSON_START.test(data) && JSON_END.test(data))) {
|
17174
17511
|
data = fromJson(data);
|
17512
|
+
}
|
17175
17513
|
}
|
17176
17514
|
return data;
|
17177
17515
|
}],
|
@@ -18129,18 +18467,8 @@ function $HttpProvider() {
|
|
18129
18467
|
}];
|
18130
18468
|
}
|
18131
18469
|
|
18132
|
-
function createXhr(
|
18133
|
-
|
18134
|
-
//is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
|
18135
|
-
//if it is available
|
18136
|
-
if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
|
18137
|
-
!window.XMLHttpRequest)) {
|
18138
|
-
return new window.ActiveXObject("Microsoft.XMLHTTP");
|
18139
|
-
} else if (window.XMLHttpRequest) {
|
18140
|
-
return new window.XMLHttpRequest();
|
18141
|
-
}
|
18142
|
-
|
18143
|
-
throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
|
18470
|
+
function createXhr() {
|
18471
|
+
return new window.XMLHttpRequest();
|
18144
18472
|
}
|
18145
18473
|
|
18146
18474
|
/**
|
@@ -18166,11 +18494,8 @@ function $HttpBackendProvider() {
|
|
18166
18494
|
}
|
18167
18495
|
|
18168
18496
|
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
|
18169
|
-
var ABORTED = -1;
|
18170
|
-
|
18171
18497
|
// TODO(vojta): fix the signature
|
18172
18498
|
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
|
18173
|
-
var status;
|
18174
18499
|
$browser.$$incOutstandingRequestCount();
|
18175
18500
|
url = url || $browser.url();
|
18176
18501
|
|
@@ -18188,7 +18513,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
18188
18513
|
});
|
18189
18514
|
} else {
|
18190
18515
|
|
18191
|
-
var xhr = createXhr(
|
18516
|
+
var xhr = createXhr();
|
18192
18517
|
|
18193
18518
|
xhr.open(method, url, true);
|
18194
18519
|
forEach(headers, function(value, key) {
|
@@ -18197,44 +18522,39 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
18197
18522
|
}
|
18198
18523
|
});
|
18199
18524
|
|
18200
|
-
|
18201
|
-
|
18202
|
-
// always async
|
18203
|
-
xhr.onreadystatechange = function() {
|
18204
|
-
// onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
|
18205
|
-
// xhrs that are resolved while the app is in the background (see #5426).
|
18206
|
-
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
|
18207
|
-
// continuing
|
18208
|
-
//
|
18209
|
-
// we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
|
18210
|
-
// Safari respectively.
|
18211
|
-
if (xhr && xhr.readyState == 4) {
|
18212
|
-
var responseHeaders = null,
|
18213
|
-
response = null,
|
18214
|
-
statusText = '';
|
18215
|
-
|
18216
|
-
if(status !== ABORTED) {
|
18217
|
-
responseHeaders = xhr.getAllResponseHeaders();
|
18218
|
-
|
18219
|
-
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
18220
|
-
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
18221
|
-
response = ('response' in xhr) ? xhr.response : xhr.responseText;
|
18222
|
-
}
|
18525
|
+
xhr.onload = function requestLoaded() {
|
18526
|
+
var statusText = xhr.statusText || '';
|
18223
18527
|
|
18224
|
-
|
18225
|
-
|
18226
|
-
|
18227
|
-
|
18228
|
-
|
18528
|
+
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
18529
|
+
// response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
|
18530
|
+
var response = ('response' in xhr) ? xhr.response : xhr.responseText;
|
18531
|
+
|
18532
|
+
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
|
18533
|
+
var status = xhr.status === 1223 ? 204 : xhr.status;
|
18229
18534
|
|
18230
|
-
|
18231
|
-
|
18232
|
-
|
18233
|
-
|
18234
|
-
|
18535
|
+
// fix status code when it is 0 (0 status is undocumented).
|
18536
|
+
// Occurs when accessing file resources or on Android 4.1 stock browser
|
18537
|
+
// while retrieving files from application cache.
|
18538
|
+
if (status === 0) {
|
18539
|
+
status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
|
18235
18540
|
}
|
18541
|
+
|
18542
|
+
completeRequest(callback,
|
18543
|
+
status,
|
18544
|
+
response,
|
18545
|
+
xhr.getAllResponseHeaders(),
|
18546
|
+
statusText);
|
18547
|
+
};
|
18548
|
+
|
18549
|
+
var requestError = function () {
|
18550
|
+
// The response is always empty
|
18551
|
+
// See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
|
18552
|
+
completeRequest(callback, -1, null, null, '');
|
18236
18553
|
};
|
18237
18554
|
|
18555
|
+
xhr.onerror = requestError;
|
18556
|
+
xhr.onabort = requestError;
|
18557
|
+
|
18238
18558
|
if (withCredentials) {
|
18239
18559
|
xhr.withCredentials = true;
|
18240
18560
|
}
|
@@ -18267,7 +18587,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
18267
18587
|
|
18268
18588
|
|
18269
18589
|
function timeoutRequest() {
|
18270
|
-
status = ABORTED;
|
18271
18590
|
jsonpDone && jsonpDone();
|
18272
18591
|
xhr && xhr.abort();
|
18273
18592
|
}
|
@@ -18277,17 +18596,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
18277
18596
|
timeoutId && $browserDefer.cancel(timeoutId);
|
18278
18597
|
jsonpDone = xhr = null;
|
18279
18598
|
|
18280
|
-
// fix status code when it is 0 (0 status is undocumented).
|
18281
|
-
// Occurs when accessing file resources or on Android 4.1 stock browser
|
18282
|
-
// while retrieving files from application cache.
|
18283
|
-
if (status === 0) {
|
18284
|
-
status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
|
18285
|
-
}
|
18286
|
-
|
18287
|
-
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
|
18288
|
-
status = status === 1223 ? 204 : status;
|
18289
|
-
statusText = statusText || '';
|
18290
|
-
|
18291
18599
|
callback(status, response, headersString, statusText);
|
18292
18600
|
$browser.$$completeOutstandingRequest(noop);
|
18293
18601
|
}
|
@@ -19239,9 +19547,7 @@ function LocationHashbangInHtml5Url(appBase, hashPrefix) {
|
|
19239
19547
|
}
|
19240
19548
|
|
19241
19549
|
|
19242
|
-
|
19243
|
-
LocationHashbangUrl.prototype =
|
19244
|
-
LocationHtml5Url.prototype = {
|
19550
|
+
var locationPrototype = {
|
19245
19551
|
|
19246
19552
|
/**
|
19247
19553
|
* Are we in html5 mode?
|
@@ -19250,7 +19556,7 @@ LocationHashbangInHtml5Url.prototype =
|
|
19250
19556
|
$$html5: false,
|
19251
19557
|
|
19252
19558
|
/**
|
19253
|
-
* Has any change been replacing
|
19559
|
+
* Has any change been replacing?
|
19254
19560
|
* @private
|
19255
19561
|
*/
|
19256
19562
|
$$replace: false,
|
@@ -19352,7 +19658,7 @@ LocationHashbangInHtml5Url.prototype =
|
|
19352
19658
|
* @return {string} path
|
19353
19659
|
*/
|
19354
19660
|
path: locationGetterSetter('$$path', function(path) {
|
19355
|
-
path = path ? path.toString() : '';
|
19661
|
+
path = path !== null ? path.toString() : '';
|
19356
19662
|
return path.charAt(0) == '/' ? path : '/' + path;
|
19357
19663
|
}),
|
19358
19664
|
|
@@ -19449,7 +19755,7 @@ LocationHashbangInHtml5Url.prototype =
|
|
19449
19755
|
* @return {string} hash
|
19450
19756
|
*/
|
19451
19757
|
hash: locationGetterSetter('$$hash', function(hash) {
|
19452
|
-
return hash ? hash.toString() : '';
|
19758
|
+
return hash !== null ? hash.toString() : '';
|
19453
19759
|
}),
|
19454
19760
|
|
19455
19761
|
/**
|
@@ -19466,6 +19772,46 @@ LocationHashbangInHtml5Url.prototype =
|
|
19466
19772
|
}
|
19467
19773
|
};
|
19468
19774
|
|
19775
|
+
forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function (Location) {
|
19776
|
+
Location.prototype = Object.create(locationPrototype);
|
19777
|
+
|
19778
|
+
/**
|
19779
|
+
* @ngdoc method
|
19780
|
+
* @name $location#state
|
19781
|
+
*
|
19782
|
+
* @description
|
19783
|
+
* This method is getter / setter.
|
19784
|
+
*
|
19785
|
+
* Return the history state object when called without any parameter.
|
19786
|
+
*
|
19787
|
+
* Change the history state object when called with one parameter and return `$location`.
|
19788
|
+
* The state object is later passed to `pushState` or `replaceState`.
|
19789
|
+
*
|
19790
|
+
* NOTE: This method is supported only in HTML5 mode and only in browsers supporting
|
19791
|
+
* the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
|
19792
|
+
* older browsers (like IE9 or Android < 4.0), don't use this method.
|
19793
|
+
*
|
19794
|
+
* @param {object=} state State object for pushState or replaceState
|
19795
|
+
* @return {object} state
|
19796
|
+
*/
|
19797
|
+
Location.prototype.state = function(state) {
|
19798
|
+
if (!arguments.length)
|
19799
|
+
return this.$$state;
|
19800
|
+
|
19801
|
+
if (Location !== LocationHtml5Url || !this.$$html5) {
|
19802
|
+
throw $locationMinErr('nostate', 'History API state support is available only ' +
|
19803
|
+
'in HTML5 mode and only in browsers supporting HTML5 History API');
|
19804
|
+
}
|
19805
|
+
// The user might modify `stateObject` after invoking `$location.state(stateObject)`
|
19806
|
+
// but we're changing the $$state reference to $browser.state() during the $digest
|
19807
|
+
// so the modification window is narrow.
|
19808
|
+
this.$$state = isUndefined(state) ? null : state;
|
19809
|
+
|
19810
|
+
return this;
|
19811
|
+
};
|
19812
|
+
});
|
19813
|
+
|
19814
|
+
|
19469
19815
|
function locationGetter(property) {
|
19470
19816
|
return function() {
|
19471
19817
|
return this[property];
|
@@ -19522,7 +19868,8 @@ function $LocationProvider(){
|
|
19522
19868
|
var hashPrefix = '',
|
19523
19869
|
html5Mode = {
|
19524
19870
|
enabled: false,
|
19525
|
-
requireBase: true
|
19871
|
+
requireBase: true,
|
19872
|
+
rewriteLinks: true
|
19526
19873
|
};
|
19527
19874
|
|
19528
19875
|
/**
|
@@ -19546,15 +19893,17 @@ function $LocationProvider(){
|
|
19546
19893
|
* @name $locationProvider#html5Mode
|
19547
19894
|
* @description
|
19548
19895
|
* @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
|
19549
|
-
* If object, sets `enabled` and `
|
19550
|
-
*
|
19551
|
-
*
|
19552
|
-
* in browsers that do not
|
19553
|
-
*
|
19554
|
-
*
|
19555
|
-
*
|
19556
|
-
* thrown when `$location` is injected.
|
19557
|
-
* {@link guide/$location $location guide for more information}
|
19896
|
+
* If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
|
19897
|
+
* properties:
|
19898
|
+
* - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
|
19899
|
+
* change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
|
19900
|
+
* support `pushState`.
|
19901
|
+
* - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
|
19902
|
+
* whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
|
19903
|
+
* true, and a base tag is not present, an error will be thrown when `$location` is injected.
|
19904
|
+
* See the {@link guide/$location $location guide for more information}
|
19905
|
+
* - **rewriteLinks** - `{boolean}` - (default: `false`) When html5Mode is enabled, disables
|
19906
|
+
* url rewriting for relative linksTurns off url rewriting for relative links.
|
19558
19907
|
*
|
19559
19908
|
* @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
|
19560
19909
|
*/
|
@@ -19563,12 +19912,19 @@ function $LocationProvider(){
|
|
19563
19912
|
html5Mode.enabled = mode;
|
19564
19913
|
return this;
|
19565
19914
|
} else if (isObject(mode)) {
|
19566
|
-
|
19567
|
-
|
19568
|
-
|
19569
|
-
|
19570
|
-
|
19571
|
-
|
19915
|
+
|
19916
|
+
if (isBoolean(mode.enabled)) {
|
19917
|
+
html5Mode.enabled = mode.enabled;
|
19918
|
+
}
|
19919
|
+
|
19920
|
+
if (isBoolean(mode.requireBase)) {
|
19921
|
+
html5Mode.requireBase = mode.requireBase;
|
19922
|
+
}
|
19923
|
+
|
19924
|
+
if (isBoolean(mode.rewriteLinks)) {
|
19925
|
+
html5Mode.rewriteLinks = mode.rewriteLinks;
|
19926
|
+
}
|
19927
|
+
|
19572
19928
|
return this;
|
19573
19929
|
} else {
|
19574
19930
|
return html5Mode;
|
@@ -19580,14 +19936,21 @@ function $LocationProvider(){
|
|
19580
19936
|
* @name $location#$locationChangeStart
|
19581
19937
|
* @eventType broadcast on root scope
|
19582
19938
|
* @description
|
19583
|
-
* Broadcasted before a URL will change.
|
19939
|
+
* Broadcasted before a URL will change.
|
19940
|
+
*
|
19941
|
+
* This change can be prevented by calling
|
19584
19942
|
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
|
19585
19943
|
* details about event object. Upon successful change
|
19586
19944
|
* {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
|
19587
19945
|
*
|
19946
|
+
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
|
19947
|
+
* the browser supports the HTML5 History API.
|
19948
|
+
*
|
19588
19949
|
* @param {Object} angularEvent Synthetic event object.
|
19589
19950
|
* @param {string} newUrl New URL
|
19590
19951
|
* @param {string=} oldUrl URL that was before it was changed.
|
19952
|
+
* @param {string=} newState New history state object
|
19953
|
+
* @param {string=} oldState History state object that was before it was changed.
|
19591
19954
|
*/
|
19592
19955
|
|
19593
19956
|
/**
|
@@ -19597,9 +19960,14 @@ function $LocationProvider(){
|
|
19597
19960
|
* @description
|
19598
19961
|
* Broadcasted after a URL was changed.
|
19599
19962
|
*
|
19963
|
+
* The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
|
19964
|
+
* the browser supports the HTML5 History API.
|
19965
|
+
*
|
19600
19966
|
* @param {Object} angularEvent Synthetic event object.
|
19601
19967
|
* @param {string} newUrl New URL
|
19602
19968
|
* @param {string=} oldUrl URL that was before it was changed.
|
19969
|
+
* @param {string=} newState New history state object
|
19970
|
+
* @param {string=} oldState History state object that was before it was changed.
|
19603
19971
|
*/
|
19604
19972
|
|
19605
19973
|
this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
|
@@ -19624,13 +19992,34 @@ function $LocationProvider(){
|
|
19624
19992
|
$location = new LocationMode(appBase, '#' + hashPrefix);
|
19625
19993
|
$location.$$parseLinkUrl(initialUrl, initialUrl);
|
19626
19994
|
|
19995
|
+
$location.$$state = $browser.state();
|
19996
|
+
|
19627
19997
|
var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
|
19628
19998
|
|
19999
|
+
function setBrowserUrlWithFallback(url, replace, state) {
|
20000
|
+
var oldUrl = $location.url();
|
20001
|
+
var oldState = $location.$$state;
|
20002
|
+
try {
|
20003
|
+
$browser.url(url, replace, state);
|
20004
|
+
|
20005
|
+
// Make sure $location.state() returns referentially identical (not just deeply equal)
|
20006
|
+
// state object; this makes possible quick checking if the state changed in the digest
|
20007
|
+
// loop. Checking deep equality would be too expensive.
|
20008
|
+
$location.$$state = $browser.state();
|
20009
|
+
} catch (e) {
|
20010
|
+
// Restore old values if pushState fails
|
20011
|
+
$location.url(oldUrl);
|
20012
|
+
$location.$$state = oldState;
|
20013
|
+
|
20014
|
+
throw e;
|
20015
|
+
}
|
20016
|
+
}
|
20017
|
+
|
19629
20018
|
$rootElement.on('click', function(event) {
|
19630
20019
|
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
|
19631
20020
|
// currently we open nice url link and redirect then
|
19632
20021
|
|
19633
|
-
if (event.ctrlKey || event.metaKey || event.which == 2) return;
|
20022
|
+
if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.which == 2) return;
|
19634
20023
|
|
19635
20024
|
var elm = jqLite(event.target);
|
19636
20025
|
|
@@ -19656,6 +20045,9 @@ function $LocationProvider(){
|
|
19656
20045
|
|
19657
20046
|
if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
|
19658
20047
|
if ($location.$$parseLinkUrl(absHref, relHref)) {
|
20048
|
+
// We do a preventDefault for all urls that are part of the angular application,
|
20049
|
+
// in html5mode and also without, so that we are able to abort navigation without
|
20050
|
+
// getting double entries in the location history.
|
19659
20051
|
event.preventDefault();
|
19660
20052
|
// update location manually
|
19661
20053
|
if ($location.absUrl() != $browser.url()) {
|
@@ -19673,52 +20065,63 @@ function $LocationProvider(){
|
|
19673
20065
|
$browser.url($location.absUrl(), true);
|
19674
20066
|
}
|
19675
20067
|
|
19676
|
-
|
19677
|
-
$browser.onUrlChange(function(newUrl) {
|
19678
|
-
if ($location.absUrl() != newUrl) {
|
19679
|
-
$rootScope.$evalAsync(function() {
|
19680
|
-
var oldUrl = $location.absUrl();
|
20068
|
+
var initializing = true;
|
19681
20069
|
|
19682
|
-
|
19683
|
-
|
19684
|
-
|
19685
|
-
|
19686
|
-
|
19687
|
-
|
19688
|
-
|
19689
|
-
|
19690
|
-
|
19691
|
-
|
19692
|
-
|
20070
|
+
// update $location when $browser url changes
|
20071
|
+
$browser.onUrlChange(function(newUrl, newState) {
|
20072
|
+
$rootScope.$evalAsync(function() {
|
20073
|
+
var oldUrl = $location.absUrl();
|
20074
|
+
var oldState = $location.$$state;
|
20075
|
+
|
20076
|
+
$location.$$parse(newUrl);
|
20077
|
+
$location.$$state = newState;
|
20078
|
+
if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
|
20079
|
+
newState, oldState).defaultPrevented) {
|
20080
|
+
$location.$$parse(oldUrl);
|
20081
|
+
$location.$$state = oldState;
|
20082
|
+
setBrowserUrlWithFallback(oldUrl, false, oldState);
|
20083
|
+
} else {
|
20084
|
+
initializing = false;
|
20085
|
+
afterLocationChange(oldUrl, oldState);
|
20086
|
+
}
|
20087
|
+
});
|
20088
|
+
if (!$rootScope.$$phase) $rootScope.$digest();
|
19693
20089
|
});
|
19694
20090
|
|
19695
20091
|
// update browser
|
19696
|
-
var changeCounter = 0;
|
19697
20092
|
$rootScope.$watch(function $locationWatch() {
|
19698
20093
|
var oldUrl = $browser.url();
|
20094
|
+
var oldState = $browser.state();
|
19699
20095
|
var currentReplace = $location.$$replace;
|
19700
20096
|
|
19701
|
-
if (
|
19702
|
-
|
20097
|
+
if (initializing || oldUrl !== $location.absUrl() ||
|
20098
|
+
($location.$$html5 && $sniffer.history && oldState !== $location.$$state)) {
|
20099
|
+
initializing = false;
|
20100
|
+
|
19703
20101
|
$rootScope.$evalAsync(function() {
|
19704
|
-
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl
|
19705
|
-
defaultPrevented) {
|
20102
|
+
if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl,
|
20103
|
+
$location.$$state, oldState).defaultPrevented) {
|
19706
20104
|
$location.$$parse(oldUrl);
|
20105
|
+
$location.$$state = oldState;
|
19707
20106
|
} else {
|
19708
|
-
|
19709
|
-
|
20107
|
+
setBrowserUrlWithFallback($location.absUrl(), currentReplace,
|
20108
|
+
oldState === $location.$$state ? null : $location.$$state);
|
20109
|
+
afterLocationChange(oldUrl, oldState);
|
19710
20110
|
}
|
19711
20111
|
});
|
19712
20112
|
}
|
20113
|
+
|
19713
20114
|
$location.$$replace = false;
|
19714
20115
|
|
19715
|
-
return
|
20116
|
+
// we don't need to return anything because $evalAsync will make the digest loop dirty when
|
20117
|
+
// there is a change
|
19716
20118
|
});
|
19717
20119
|
|
19718
20120
|
return $location;
|
19719
20121
|
|
19720
|
-
function afterLocationChange(oldUrl) {
|
19721
|
-
$rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl
|
20122
|
+
function afterLocationChange(oldUrl, oldState) {
|
20123
|
+
$rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
|
20124
|
+
$location.$$state, oldState);
|
19722
20125
|
}
|
19723
20126
|
}];
|
19724
20127
|
}
|
@@ -19977,6 +20380,11 @@ forEach({
|
|
19977
20380
|
CONSTANTS[name] = constantGetter;
|
19978
20381
|
});
|
19979
20382
|
|
20383
|
+
//Not quite a constant, but can be lex/parsed the same
|
20384
|
+
CONSTANTS['this'] = function(self) { return self; };
|
20385
|
+
CONSTANTS['this'].sharedGetter = true;
|
20386
|
+
|
20387
|
+
|
19980
20388
|
//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
|
19981
20389
|
var OPERATORS = extend(createMap(), {
|
19982
20390
|
/* jshint bitwise : false */
|
@@ -21840,14 +22248,11 @@ function $RootScopeProvider(){
|
|
21840
22248
|
this.$$phase = this.$parent = this.$$watchers =
|
21841
22249
|
this.$$nextSibling = this.$$prevSibling =
|
21842
22250
|
this.$$childHead = this.$$childTail = null;
|
21843
|
-
this
|
22251
|
+
this.$root = this;
|
21844
22252
|
this.$$destroyed = false;
|
21845
|
-
this.$$asyncQueue = [];
|
21846
|
-
this.$$postDigestQueue = [];
|
21847
22253
|
this.$$listeners = {};
|
21848
22254
|
this.$$listenerCount = {};
|
21849
22255
|
this.$$isolateBindings = null;
|
21850
|
-
this.$$applyAsyncQueue = [];
|
21851
22256
|
}
|
21852
22257
|
|
21853
22258
|
/**
|
@@ -21896,18 +22301,23 @@ function $RootScopeProvider(){
|
|
21896
22301
|
* When creating widgets, it is useful for the widget to not accidentally read parent
|
21897
22302
|
* state.
|
21898
22303
|
*
|
22304
|
+
* @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
|
22305
|
+
* of the newly created scope. Defaults to `this` scope if not provided.
|
22306
|
+
* This is used when creating a transclude scope to correctly place it
|
22307
|
+
* in the scope hierarchy while maintaining the correct prototypical
|
22308
|
+
* inheritance.
|
22309
|
+
*
|
21899
22310
|
* @returns {Object} The newly created child scope.
|
21900
22311
|
*
|
21901
22312
|
*/
|
21902
|
-
$new: function(isolate) {
|
22313
|
+
$new: function(isolate, parent) {
|
21903
22314
|
var child;
|
21904
22315
|
|
22316
|
+
parent = parent || this;
|
22317
|
+
|
21905
22318
|
if (isolate) {
|
21906
22319
|
child = new Scope();
|
21907
22320
|
child.$root = this.$root;
|
21908
|
-
// ensure that there is just one async queue per $rootScope and its children
|
21909
|
-
child.$$asyncQueue = this.$$asyncQueue;
|
21910
|
-
child.$$postDigestQueue = this.$$postDigestQueue;
|
21911
22321
|
} else {
|
21912
22322
|
// Only create a child scope class if somebody asks for one,
|
21913
22323
|
// but cache it to allow the VM to optimize lookups.
|
@@ -21924,16 +22334,27 @@ function $RootScopeProvider(){
|
|
21924
22334
|
}
|
21925
22335
|
child = new this.$$ChildScope();
|
21926
22336
|
}
|
21927
|
-
child
|
21928
|
-
child
|
21929
|
-
|
21930
|
-
|
21931
|
-
|
21932
|
-
this.$$childTail = child;
|
22337
|
+
child.$parent = parent;
|
22338
|
+
child.$$prevSibling = parent.$$childTail;
|
22339
|
+
if (parent.$$childHead) {
|
22340
|
+
parent.$$childTail.$$nextSibling = child;
|
22341
|
+
parent.$$childTail = child;
|
21933
22342
|
} else {
|
21934
|
-
|
22343
|
+
parent.$$childHead = parent.$$childTail = child;
|
21935
22344
|
}
|
22345
|
+
|
22346
|
+
// When the new scope is not isolated or we inherit from `this`, and
|
22347
|
+
// the parent scope is destroyed, the property `$$destroyed` is inherited
|
22348
|
+
// prototypically. In all other cases, this property needs to be set
|
22349
|
+
// when the parent scope is destroyed.
|
22350
|
+
// The listener needs to be added after the parent is set
|
22351
|
+
if (isolate || parent != this) child.$on('$destroy', destroyChild);
|
22352
|
+
|
21936
22353
|
return child;
|
22354
|
+
|
22355
|
+
function destroyChild() {
|
22356
|
+
child.$$destroyed = true;
|
22357
|
+
}
|
21937
22358
|
},
|
21938
22359
|
|
21939
22360
|
/**
|
@@ -22409,8 +22830,6 @@ function $RootScopeProvider(){
|
|
22409
22830
|
$digest: function() {
|
22410
22831
|
var watch, value, last,
|
22411
22832
|
watchers,
|
22412
|
-
asyncQueue = this.$$asyncQueue,
|
22413
|
-
postDigestQueue = this.$$postDigestQueue,
|
22414
22833
|
length,
|
22415
22834
|
dirty, ttl = TTL,
|
22416
22835
|
next, current, target = this,
|
@@ -22575,6 +22994,10 @@ function $RootScopeProvider(){
|
|
22575
22994
|
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
|
22576
22995
|
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
|
22577
22996
|
|
22997
|
+
// Disable listeners, watchers and apply/digest methods
|
22998
|
+
this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
|
22999
|
+
this.$on = this.$watch = this.$watchGroup = function() { return noop; };
|
23000
|
+
this.$$listeners = {};
|
22578
23001
|
|
22579
23002
|
// All of the code below is bogus code that works around V8's memory leak via optimized code
|
22580
23003
|
// and inline caches.
|
@@ -22585,15 +23008,7 @@ function $RootScopeProvider(){
|
|
22585
23008
|
// - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
|
22586
23009
|
|
22587
23010
|
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
|
22588
|
-
this.$$childTail = this.$root = null;
|
22589
|
-
|
22590
|
-
// don't reset these to null in case some async task tries to register a listener/watch/task
|
22591
|
-
this.$$listeners = {};
|
22592
|
-
this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
|
22593
|
-
|
22594
|
-
// prevent NPEs since these methods have references to properties we nulled out
|
22595
|
-
this.$destroy = this.$digest = this.$apply = noop;
|
22596
|
-
this.$on = this.$watch = this.$watchGroup = function() { return noop; };
|
23011
|
+
this.$$childTail = this.$root = this.$$watchers = null;
|
22597
23012
|
},
|
22598
23013
|
|
22599
23014
|
/**
|
@@ -22660,19 +23075,19 @@ function $RootScopeProvider(){
|
|
22660
23075
|
$evalAsync: function(expr) {
|
22661
23076
|
// if we are outside of an $digest loop and this is the first time we are scheduling async
|
22662
23077
|
// task also schedule async auto-flush
|
22663
|
-
if (!$rootScope.$$phase &&
|
23078
|
+
if (!$rootScope.$$phase && !asyncQueue.length) {
|
22664
23079
|
$browser.defer(function() {
|
22665
|
-
if (
|
23080
|
+
if (asyncQueue.length) {
|
22666
23081
|
$rootScope.$digest();
|
22667
23082
|
}
|
22668
23083
|
});
|
22669
23084
|
}
|
22670
23085
|
|
22671
|
-
|
23086
|
+
asyncQueue.push({scope: this, expression: expr});
|
22672
23087
|
},
|
22673
23088
|
|
22674
23089
|
$$postDigest : function(fn) {
|
22675
|
-
|
23090
|
+
postDigestQueue.push(fn);
|
22676
23091
|
},
|
22677
23092
|
|
22678
23093
|
/**
|
@@ -22756,7 +23171,7 @@ function $RootScopeProvider(){
|
|
22756
23171
|
*/
|
22757
23172
|
$applyAsync: function(expr) {
|
22758
23173
|
var scope = this;
|
22759
|
-
expr &&
|
23174
|
+
expr && applyAsyncQueue.push($applyAsyncExpression);
|
22760
23175
|
scheduleApplyAsync();
|
22761
23176
|
|
22762
23177
|
function $applyAsyncExpression() {
|
@@ -22965,6 +23380,11 @@ function $RootScopeProvider(){
|
|
22965
23380
|
|
22966
23381
|
var $rootScope = new Scope();
|
22967
23382
|
|
23383
|
+
//The internal queues. Expose them on the $rootScope for debugging/testing purposes.
|
23384
|
+
var asyncQueue = $rootScope.$$asyncQueue = [];
|
23385
|
+
var postDigestQueue = $rootScope.$$postDigestQueue = [];
|
23386
|
+
var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
|
23387
|
+
|
22968
23388
|
return $rootScope;
|
22969
23389
|
|
22970
23390
|
|
@@ -22998,10 +23418,9 @@ function $RootScopeProvider(){
|
|
22998
23418
|
function initWatchVal() {}
|
22999
23419
|
|
23000
23420
|
function flushApplyAsync() {
|
23001
|
-
|
23002
|
-
while (queue.length) {
|
23421
|
+
while (applyAsyncQueue.length) {
|
23003
23422
|
try {
|
23004
|
-
|
23423
|
+
applyAsyncQueue.shift()();
|
23005
23424
|
} catch(e) {
|
23006
23425
|
$exceptionHandler(e);
|
23007
23426
|
}
|
@@ -23080,12 +23499,9 @@ function $$SanitizeUriProvider() {
|
|
23080
23499
|
return function sanitizeUri(uri, isImage) {
|
23081
23500
|
var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
|
23082
23501
|
var normalizedVal;
|
23083
|
-
|
23084
|
-
if (
|
23085
|
-
normalizedVal
|
23086
|
-
if (normalizedVal !== '' && !normalizedVal.match(regex)) {
|
23087
|
-
return 'unsafe:'+normalizedVal;
|
23088
|
-
}
|
23502
|
+
normalizedVal = urlResolve(uri).href;
|
23503
|
+
if (normalizedVal !== '' && !normalizedVal.match(regex)) {
|
23504
|
+
return 'unsafe:'+normalizedVal;
|
23089
23505
|
}
|
23090
23506
|
return uri;
|
23091
23507
|
};
|
@@ -24157,7 +24573,6 @@ function $SceProvider() {
|
|
24157
24573
|
* @requires $document
|
24158
24574
|
*
|
24159
24575
|
* @property {boolean} history Does the browser support html5 history api ?
|
24160
|
-
* @property {boolean} hashchange Does the browser support hashchange event ?
|
24161
24576
|
* @property {boolean} transitions Does the browser support CSS transition events ?
|
24162
24577
|
* @property {boolean} animations Does the browser support CSS animation events ?
|
24163
24578
|
*
|
@@ -24214,9 +24629,6 @@ function $SnifferProvider() {
|
|
24214
24629
|
// jshint -W018
|
24215
24630
|
history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
|
24216
24631
|
// jshint +W018
|
24217
|
-
hashchange: 'onhashchange' in $window &&
|
24218
|
-
// IE8 compatible mode lies
|
24219
|
-
(!documentMode || documentMode > 7),
|
24220
24632
|
hasEvent: function(event) {
|
24221
24633
|
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
24222
24634
|
// it. In particular the event is not fired when backspace or delete key are pressed or
|
@@ -25686,7 +26098,7 @@ function limitToFilter(){
|
|
25686
26098
|
* correctly, make sure they are actually being saved as numbers and not strings.
|
25687
26099
|
*
|
25688
26100
|
* @param {Array} array The array to sort.
|
25689
|
-
* @param {function(*)|string|Array.<(function(*)|string)
|
26101
|
+
* @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
|
25690
26102
|
* used by the comparator to determine the order of elements.
|
25691
26103
|
*
|
25692
26104
|
* Can be one of:
|
@@ -25699,10 +26111,13 @@ function limitToFilter(){
|
|
25699
26111
|
* is interpreted as a property name to be used in comparisons (for example `"special name"`
|
25700
26112
|
* to sort object by the value of their `special name` property). An expression can be
|
25701
26113
|
* optionally prefixed with `+` or `-` to control ascending or descending sort order
|
25702
|
-
* (for example, `+name` or `-name`).
|
26114
|
+
* (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
|
26115
|
+
* element itself is used to compare where sorting.
|
25703
26116
|
* - `Array`: An array of function or string predicates. The first predicate in the array
|
25704
26117
|
* is used for sorting, but when two items are equivalent, the next predicate is used.
|
25705
26118
|
*
|
26119
|
+
* If the predicate is missing or empty then it defaults to `'+'`.
|
26120
|
+
*
|
25706
26121
|
* @param {boolean=} reverse Reverse the order of the array.
|
25707
26122
|
* @returns {Array} Sorted copy of the source array.
|
25708
26123
|
*
|
@@ -25791,8 +26206,8 @@ orderByFilter.$inject = ['$parse'];
|
|
25791
26206
|
function orderByFilter($parse){
|
25792
26207
|
return function(array, sortPredicate, reverseOrder) {
|
25793
26208
|
if (!(isArrayLike(array))) return array;
|
25794
|
-
if (!sortPredicate) return array;
|
25795
26209
|
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
|
26210
|
+
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
|
25796
26211
|
sortPredicate = sortPredicate.map(function(predicate){
|
25797
26212
|
var descending = false, get = predicate || identity;
|
25798
26213
|
if (isString(predicate)) {
|
@@ -25800,6 +26215,12 @@ function orderByFilter($parse){
|
|
25800
26215
|
descending = predicate.charAt(0) == '-';
|
25801
26216
|
predicate = predicate.substring(1);
|
25802
26217
|
}
|
26218
|
+
if ( predicate === '' ) {
|
26219
|
+
// Effectively no predicate was passed so we compare identity
|
26220
|
+
return reverseComparator(function(a,b) {
|
26221
|
+
return compare(a, b);
|
26222
|
+
}, descending);
|
26223
|
+
}
|
25803
26224
|
get = $parse(predicate);
|
25804
26225
|
if (get.constant) {
|
25805
26226
|
var key = get();
|
@@ -25875,22 +26296,6 @@ function ngDirective(directive) {
|
|
25875
26296
|
var htmlAnchorDirective = valueFn({
|
25876
26297
|
restrict: 'E',
|
25877
26298
|
compile: function(element, attr) {
|
25878
|
-
|
25879
|
-
if (msie <= 8) {
|
25880
|
-
|
25881
|
-
// turn <a href ng-click="..">link</a> into a stylable link in IE
|
25882
|
-
// but only if it doesn't have name attribute, in which case it's an anchor
|
25883
|
-
if (!attr.href && !attr.name) {
|
25884
|
-
attr.$set('href', '');
|
25885
|
-
}
|
25886
|
-
|
25887
|
-
// add a comment node to anchors to workaround IE bug that causes element content to be reset
|
25888
|
-
// to new attribute content if attribute is updated with value containing @ and element also
|
25889
|
-
// contains value with @
|
25890
|
-
// see issue #1949
|
25891
|
-
element.append(document.createComment('IE fix'));
|
25892
|
-
}
|
25893
|
-
|
25894
26299
|
if (!attr.href && !attr.xlinkHref && !attr.name) {
|
25895
26300
|
return function(scope, element) {
|
25896
26301
|
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
@@ -26338,11 +26743,9 @@ var nullFormCtrl = {
|
|
26338
26743
|
$$renameControl: nullFormRenameControl,
|
26339
26744
|
$removeControl: noop,
|
26340
26745
|
$setValidity: noop,
|
26341
|
-
$$setPending: noop,
|
26342
26746
|
$setDirty: noop,
|
26343
26747
|
$setPristine: noop,
|
26344
|
-
$setSubmitted: noop
|
26345
|
-
$$clearControlValidity: noop
|
26748
|
+
$setSubmitted: noop
|
26346
26749
|
},
|
26347
26750
|
SUBMITTED_CLASS = 'ng-submitted';
|
26348
26751
|
|
@@ -26407,9 +26810,6 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
|
26407
26810
|
|
26408
26811
|
parentForm.$addControl(form);
|
26409
26812
|
|
26410
|
-
// Setup initial state of the control
|
26411
|
-
element.addClass(PRISTINE_CLASS);
|
26412
|
-
|
26413
26813
|
/**
|
26414
26814
|
* @ngdoc method
|
26415
26815
|
* @name form.FormController#$rollbackViewValue
|
@@ -26782,10 +27182,14 @@ var formDirectiveFactory = function(isNgForm) {
|
|
26782
27182
|
name: 'form',
|
26783
27183
|
restrict: isNgForm ? 'EAC' : 'E',
|
26784
27184
|
controller: FormController,
|
26785
|
-
compile: function() {
|
27185
|
+
compile: function ngFormCompile(formElement) {
|
27186
|
+
// Setup initial state of the control
|
27187
|
+
formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
|
27188
|
+
|
26786
27189
|
return {
|
26787
|
-
pre: function(scope, formElement, attr, controller) {
|
26788
|
-
if
|
27190
|
+
pre: function ngFormPreLink(scope, formElement, attr, controller) {
|
27191
|
+
// if `action` attr is not present on the form, prevent the default action (submission)
|
27192
|
+
if (!('action' in attr)) {
|
26789
27193
|
// we can't use jq events because if a form is destroyed during submission the default
|
26790
27194
|
// action is not prevented. see #1238
|
26791
27195
|
//
|
@@ -27939,16 +28343,15 @@ function createDateInputType(type, regexp, parseDate, format) {
|
|
27939
28343
|
badInputChecker(scope, element, attr, ctrl);
|
27940
28344
|
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
27941
28345
|
var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
|
28346
|
+
var previousDate;
|
27942
28347
|
|
27943
28348
|
ctrl.$$parserName = type;
|
27944
28349
|
ctrl.$parsers.push(function(value) {
|
27945
28350
|
if (ctrl.$isEmpty(value)) return null;
|
27946
28351
|
if (regexp.test(value)) {
|
27947
|
-
|
27948
|
-
|
27949
|
-
|
27950
|
-
previousDate = new Date(previousDate.getTime() + timezoneOffset);
|
27951
|
-
}
|
28352
|
+
// Note: We cannot read ctrl.$modelValue, as there might be a different
|
28353
|
+
// parser/formatter in the processing chain so that the model
|
28354
|
+
// contains some different data format!
|
27952
28355
|
var parsedDate = parseDate(value, previousDate);
|
27953
28356
|
if (timezone === 'UTC') {
|
27954
28357
|
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
|
@@ -27959,8 +28362,18 @@ function createDateInputType(type, regexp, parseDate, format) {
|
|
27959
28362
|
});
|
27960
28363
|
|
27961
28364
|
ctrl.$formatters.push(function(value) {
|
27962
|
-
if (
|
28365
|
+
if (!ctrl.$isEmpty(value)) {
|
28366
|
+
if (!isDate(value)) {
|
28367
|
+
throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
28368
|
+
}
|
28369
|
+
previousDate = value;
|
28370
|
+
if (previousDate && timezone === 'UTC') {
|
28371
|
+
var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
|
28372
|
+
previousDate = new Date(previousDate.getTime() + timezoneOffset);
|
28373
|
+
}
|
27963
28374
|
return $filter('date')(value, format, timezone);
|
28375
|
+
} else {
|
28376
|
+
previousDate = null;
|
27964
28377
|
}
|
27965
28378
|
return '';
|
27966
28379
|
});
|
@@ -27986,6 +28399,11 @@ function createDateInputType(type, regexp, parseDate, format) {
|
|
27986
28399
|
ctrl.$validate();
|
27987
28400
|
});
|
27988
28401
|
}
|
28402
|
+
// Override the standard $isEmpty to detect invalid dates as well
|
28403
|
+
ctrl.$isEmpty = function(value) {
|
28404
|
+
// Invalid Date: getTime() returns NaN
|
28405
|
+
return !value || (value.getTime && value.getTime() !== value.getTime());
|
28406
|
+
};
|
27989
28407
|
|
27990
28408
|
function parseObservedDateValue(val) {
|
27991
28409
|
return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
|
@@ -28300,10 +28718,12 @@ var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
|
|
28300
28718
|
return {
|
28301
28719
|
restrict: 'E',
|
28302
28720
|
require: ['?ngModel'],
|
28303
|
-
link:
|
28304
|
-
|
28305
|
-
|
28306
|
-
|
28721
|
+
link: {
|
28722
|
+
pre: function(scope, element, attr, ctrls) {
|
28723
|
+
if (ctrls[0]) {
|
28724
|
+
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
|
28725
|
+
$browser, $filter, $parse);
|
28726
|
+
}
|
28307
28727
|
}
|
28308
28728
|
}
|
28309
28729
|
};
|
@@ -28604,11 +29024,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
28604
29024
|
var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
|
28605
29025
|
currentValidationRunId = 0;
|
28606
29026
|
|
28607
|
-
// Setup initial state of the control
|
28608
|
-
$element
|
28609
|
-
.addClass(PRISTINE_CLASS)
|
28610
|
-
.addClass(UNTOUCHED_CLASS);
|
28611
|
-
|
28612
29027
|
/**
|
28613
29028
|
* @ngdoc method
|
28614
29029
|
* @name ngModel.NgModelController#$setValidity
|
@@ -28901,14 +29316,17 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
28901
29316
|
};
|
28902
29317
|
|
28903
29318
|
this.$$parseAndValidate = function() {
|
28904
|
-
var
|
28905
|
-
|
28906
|
-
|
28907
|
-
|
28908
|
-
|
28909
|
-
|
28910
|
-
|
28911
|
-
|
29319
|
+
var viewValue = ctrl.$$lastCommittedViewValue;
|
29320
|
+
var modelValue = viewValue;
|
29321
|
+
var parserValid = isUndefined(modelValue) ? undefined : true;
|
29322
|
+
|
29323
|
+
if (parserValid) {
|
29324
|
+
for(var i = 0; i < ctrl.$parsers.length; i++) {
|
29325
|
+
modelValue = ctrl.$parsers[i](modelValue);
|
29326
|
+
if (isUndefined(modelValue)) {
|
29327
|
+
parserValid = false;
|
29328
|
+
break;
|
29329
|
+
}
|
28912
29330
|
}
|
28913
29331
|
}
|
28914
29332
|
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
|
@@ -29225,42 +29643,51 @@ var ngModelDirective = function() {
|
|
29225
29643
|
restrict: 'A',
|
29226
29644
|
require: ['ngModel', '^?form', '^?ngModelOptions'],
|
29227
29645
|
controller: NgModelController,
|
29228
|
-
|
29229
|
-
|
29230
|
-
|
29231
|
-
|
29646
|
+
// Prelink needs to run before any input directive
|
29647
|
+
// so that we can set the NgModelOptions in NgModelController
|
29648
|
+
// before anyone else uses it.
|
29649
|
+
priority: 1,
|
29650
|
+
compile: function ngModelCompile(element) {
|
29651
|
+
// Setup initial state of the control
|
29652
|
+
element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
|
29232
29653
|
|
29233
|
-
|
29654
|
+
return {
|
29655
|
+
pre: function ngModelPreLink(scope, element, attr, ctrls) {
|
29656
|
+
var modelCtrl = ctrls[0],
|
29657
|
+
formCtrl = ctrls[1] || nullFormCtrl;
|
29234
29658
|
|
29235
|
-
|
29236
|
-
formCtrl.$addControl(modelCtrl);
|
29659
|
+
modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
|
29237
29660
|
|
29238
|
-
|
29239
|
-
|
29240
|
-
formCtrl.$$renameControl(modelCtrl, newValue);
|
29241
|
-
}
|
29242
|
-
});
|
29661
|
+
// notify others, especially parent forms
|
29662
|
+
formCtrl.$addControl(modelCtrl);
|
29243
29663
|
|
29244
|
-
|
29245
|
-
|
29246
|
-
|
29247
|
-
|
29248
|
-
post: function(scope, element, attr, ctrls) {
|
29249
|
-
var modelCtrl = ctrls[0];
|
29250
|
-
if (modelCtrl.$options && modelCtrl.$options.updateOn) {
|
29251
|
-
element.on(modelCtrl.$options.updateOn, function(ev) {
|
29252
|
-
modelCtrl.$$debounceViewValueCommit(ev && ev.type);
|
29664
|
+
attr.$observe('name', function(newValue) {
|
29665
|
+
if (modelCtrl.$name !== newValue) {
|
29666
|
+
formCtrl.$$renameControl(modelCtrl, newValue);
|
29667
|
+
}
|
29253
29668
|
});
|
29254
|
-
}
|
29255
29669
|
|
29256
|
-
|
29257
|
-
|
29670
|
+
scope.$on('$destroy', function() {
|
29671
|
+
formCtrl.$removeControl(modelCtrl);
|
29672
|
+
});
|
29673
|
+
},
|
29674
|
+
post: function ngModelPostLink(scope, element, attr, ctrls) {
|
29675
|
+
var modelCtrl = ctrls[0];
|
29676
|
+
if (modelCtrl.$options && modelCtrl.$options.updateOn) {
|
29677
|
+
element.on(modelCtrl.$options.updateOn, function(ev) {
|
29678
|
+
modelCtrl.$$debounceViewValueCommit(ev && ev.type);
|
29679
|
+
});
|
29680
|
+
}
|
29681
|
+
|
29682
|
+
element.on('blur', function(ev) {
|
29683
|
+
if (modelCtrl.$touched) return;
|
29258
29684
|
|
29259
|
-
|
29260
|
-
|
29685
|
+
scope.$apply(function() {
|
29686
|
+
modelCtrl.$setTouched();
|
29687
|
+
});
|
29261
29688
|
});
|
29262
|
-
}
|
29263
|
-
}
|
29689
|
+
}
|
29690
|
+
};
|
29264
29691
|
}
|
29265
29692
|
};
|
29266
29693
|
};
|
@@ -29815,8 +30242,9 @@ function addSetValidityMethod(context) {
|
|
29815
30242
|
parentForm = context.parentForm,
|
29816
30243
|
$animate = context.$animate;
|
29817
30244
|
|
30245
|
+
classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
|
30246
|
+
|
29818
30247
|
ctrl.$setValidity = setValidity;
|
29819
|
-
toggleValidationCss('', true);
|
29820
30248
|
|
29821
30249
|
function setValidity(validationErrorKey, state, options) {
|
29822
30250
|
if (state === undefined) {
|
@@ -29966,11 +30394,9 @@ var ngBindDirective = ['$compile', function($compile) {
|
|
29966
30394
|
$compile.$$addBindingClass(templateElement);
|
29967
30395
|
return function ngBindLink(scope, element, attr) {
|
29968
30396
|
$compile.$$addBindingInfo(element, attr.ngBind);
|
30397
|
+
element = element[0];
|
29969
30398
|
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
|
29970
|
-
|
29971
|
-
// catch when value is "null or undefined"
|
29972
|
-
// jshint -W041
|
29973
|
-
element.text(value == undefined ? '' : value);
|
30399
|
+
element.textContent = value === undefined ? '' : value;
|
29974
30400
|
});
|
29975
30401
|
};
|
29976
30402
|
}
|
@@ -30036,8 +30462,9 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
|
|
30036
30462
|
return function ngBindTemplateLink(scope, element, attr) {
|
30037
30463
|
var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
|
30038
30464
|
$compile.$$addBindingInfo(element, interpolateFn.expressions);
|
30465
|
+
element = element[0];
|
30039
30466
|
attr.$observe('ngBindTemplate', function(value) {
|
30040
|
-
element.
|
30467
|
+
element.textContent = value === undefined ? '' : value;
|
30041
30468
|
});
|
30042
30469
|
};
|
30043
30470
|
}
|
@@ -30054,7 +30481,10 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
|
|
30054
30481
|
* element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
|
30055
30482
|
* ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
|
30056
30483
|
* is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
|
30057
|
-
* core Angular.
|
30484
|
+
* core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
|
30485
|
+
* include "angular-sanitize.js" in your application.
|
30486
|
+
*
|
30487
|
+
* You may also bypass sanitization for values you know are safe. To do so, bind to
|
30058
30488
|
* an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
|
30059
30489
|
* under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
|
30060
30490
|
*
|
@@ -30816,7 +31246,125 @@ var ngControllerDirective = [function() {
|
|
30816
31246
|
...
|
30817
31247
|
</html>
|
30818
31248
|
```
|
30819
|
-
|
31249
|
+
* @example
|
31250
|
+
// Note: the suffix `.csp` in the example name triggers
|
31251
|
+
// csp mode in our http server!
|
31252
|
+
<example name="example.csp" module="cspExample" ng-csp="true">
|
31253
|
+
<file name="index.html">
|
31254
|
+
<div ng-controller="MainController as ctrl">
|
31255
|
+
<div>
|
31256
|
+
<button ng-click="ctrl.inc()" id="inc">Increment</button>
|
31257
|
+
<span id="counter">
|
31258
|
+
{{ctrl.counter}}
|
31259
|
+
</span>
|
31260
|
+
</div>
|
31261
|
+
|
31262
|
+
<div>
|
31263
|
+
<button ng-click="ctrl.evil()" id="evil">Evil</button>
|
31264
|
+
<span id="evilError">
|
31265
|
+
{{ctrl.evilError}}
|
31266
|
+
</span>
|
31267
|
+
</div>
|
31268
|
+
</div>
|
31269
|
+
</file>
|
31270
|
+
<file name="script.js">
|
31271
|
+
angular.module('cspExample', [])
|
31272
|
+
.controller('MainController', function() {
|
31273
|
+
this.counter = 0;
|
31274
|
+
this.inc = function() {
|
31275
|
+
this.counter++;
|
31276
|
+
};
|
31277
|
+
this.evil = function() {
|
31278
|
+
// jshint evil:true
|
31279
|
+
try {
|
31280
|
+
eval('1+2');
|
31281
|
+
} catch (e) {
|
31282
|
+
this.evilError = e.message;
|
31283
|
+
}
|
31284
|
+
};
|
31285
|
+
});
|
31286
|
+
</file>
|
31287
|
+
<file name="protractor.js" type="protractor">
|
31288
|
+
var util, webdriver;
|
31289
|
+
|
31290
|
+
var incBtn = element(by.id('inc'));
|
31291
|
+
var counter = element(by.id('counter'));
|
31292
|
+
var evilBtn = element(by.id('evil'));
|
31293
|
+
var evilError = element(by.id('evilError'));
|
31294
|
+
|
31295
|
+
function getAndClearSevereErrors() {
|
31296
|
+
return browser.manage().logs().get('browser').then(function(browserLog) {
|
31297
|
+
return browserLog.filter(function(logEntry) {
|
31298
|
+
return logEntry.level.value > webdriver.logging.Level.WARNING.value;
|
31299
|
+
});
|
31300
|
+
});
|
31301
|
+
}
|
31302
|
+
|
31303
|
+
function clearErrors() {
|
31304
|
+
getAndClearSevereErrors();
|
31305
|
+
}
|
31306
|
+
|
31307
|
+
function expectNoErrors() {
|
31308
|
+
getAndClearSevereErrors().then(function(filteredLog) {
|
31309
|
+
expect(filteredLog.length).toEqual(0);
|
31310
|
+
if (filteredLog.length) {
|
31311
|
+
console.log('browser console errors: ' + util.inspect(filteredLog));
|
31312
|
+
}
|
31313
|
+
});
|
31314
|
+
}
|
31315
|
+
|
31316
|
+
function expectError(regex) {
|
31317
|
+
getAndClearSevereErrors().then(function(filteredLog) {
|
31318
|
+
var found = false;
|
31319
|
+
filteredLog.forEach(function(log) {
|
31320
|
+
if (log.message.match(regex)) {
|
31321
|
+
found = true;
|
31322
|
+
}
|
31323
|
+
});
|
31324
|
+
if (!found) {
|
31325
|
+
throw new Error('expected an error that matches ' + regex);
|
31326
|
+
}
|
31327
|
+
});
|
31328
|
+
}
|
31329
|
+
|
31330
|
+
beforeEach(function() {
|
31331
|
+
util = require('util');
|
31332
|
+
webdriver = require('protractor/node_modules/selenium-webdriver');
|
31333
|
+
});
|
31334
|
+
|
31335
|
+
// For now, we only test on Chrome,
|
31336
|
+
// as Safari does not load the page with Protractor's injected scripts,
|
31337
|
+
// and Firefox webdriver always disables content security policy (#6358)
|
31338
|
+
if (browser.params.browser !== 'chrome') {
|
31339
|
+
return;
|
31340
|
+
}
|
31341
|
+
|
31342
|
+
it('should not report errors when the page is loaded', function() {
|
31343
|
+
// clear errors so we are not dependent on previous tests
|
31344
|
+
clearErrors();
|
31345
|
+
// Need to reload the page as the page is already loaded when
|
31346
|
+
// we come here
|
31347
|
+
browser.driver.getCurrentUrl().then(function(url) {
|
31348
|
+
browser.get(url);
|
31349
|
+
});
|
31350
|
+
expectNoErrors();
|
31351
|
+
});
|
31352
|
+
|
31353
|
+
it('should evaluate expressions', function() {
|
31354
|
+
expect(counter.getText()).toEqual('0');
|
31355
|
+
incBtn.click();
|
31356
|
+
expect(counter.getText()).toEqual('1');
|
31357
|
+
expectNoErrors();
|
31358
|
+
});
|
31359
|
+
|
31360
|
+
it('should throw and report an error when using "eval"', function() {
|
31361
|
+
evilBtn.click();
|
31362
|
+
expect(evilError.getText()).toMatch(/Content Security Policy/);
|
31363
|
+
expectError(/Content Security Policy/);
|
31364
|
+
});
|
31365
|
+
</file>
|
31366
|
+
</example>
|
31367
|
+
*/
|
30820
31368
|
|
30821
31369
|
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
|
30822
31370
|
// bootstrap the system (before $parse is instantiated), for this reason we just have
|
@@ -31323,7 +31871,7 @@ forEach(
|
|
31323
31871
|
* Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
|
31324
31872
|
* is created when the element is restored. The scope created within `ngIf` inherits from
|
31325
31873
|
* its parent scope using
|
31326
|
-
* [prototypal inheritance](https://github.com/angular/angular.js/wiki/
|
31874
|
+
* [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
|
31327
31875
|
* An important implication of this is if `ngModel` is used within `ngIf` to bind to
|
31328
31876
|
* a javascript primitive defined in the parent scope. In this case any modifications made to the
|
31329
31877
|
* variable within the child scope will override (hide) the value in the parent scope.
|
@@ -31337,8 +31885,8 @@ forEach(
|
|
31337
31885
|
* and `leave` effects.
|
31338
31886
|
*
|
31339
31887
|
* @animations
|
31340
|
-
* enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
|
31341
|
-
* leave - happens just before the ngIf contents are removed from the DOM
|
31888
|
+
* enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
|
31889
|
+
* leave - happens just before the `ngIf` contents are removed from the DOM
|
31342
31890
|
*
|
31343
31891
|
* @element ANY
|
31344
31892
|
* @scope
|
@@ -32478,6 +33026,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
|
32478
33026
|
};
|
32479
33027
|
}];
|
32480
33028
|
|
33029
|
+
var NG_HIDE_CLASS = 'ng-hide';
|
33030
|
+
var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
32481
33031
|
/**
|
32482
33032
|
* @ngdoc directive
|
32483
33033
|
* @name ngShow
|
@@ -32639,7 +33189,11 @@ var ngShowDirective = ['$animate', function($animate) {
|
|
32639
33189
|
multiElement: true,
|
32640
33190
|
link: function(scope, element, attr) {
|
32641
33191
|
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
|
32642
|
-
|
33192
|
+
// we're adding a temporary, animation-specific class for ng-hide since this way
|
33193
|
+
// we can control when the element is actually displayed on screen without having
|
33194
|
+
// to have a global/greedy CSS selector that breaks when other animations are run.
|
33195
|
+
// Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
|
33196
|
+
$animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
|
32643
33197
|
});
|
32644
33198
|
}
|
32645
33199
|
};
|
@@ -32794,7 +33348,9 @@ var ngHideDirective = ['$animate', function($animate) {
|
|
32794
33348
|
multiElement: true,
|
32795
33349
|
link: function(scope, element, attr) {
|
32796
33350
|
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
|
32797
|
-
|
33351
|
+
// The comment inside of the ngShowDirective explains why we add and
|
33352
|
+
// remove a temporary class for the show/hide animation
|
33353
|
+
$animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
|
32798
33354
|
});
|
32799
33355
|
}
|
32800
33356
|
};
|
@@ -33216,6 +33772,12 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
33216
33772
|
* be bound to string values at present.
|
33217
33773
|
* </div>
|
33218
33774
|
*
|
33775
|
+
* <div class="alert alert-info">
|
33776
|
+
* **Note:** Using `select as` will bind the result of the `select as` expression to the model, but
|
33777
|
+
* the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
|
33778
|
+
* or property name (for object data sources) of the value within the collection.
|
33779
|
+
* </div>
|
33780
|
+
*
|
33219
33781
|
* @param {string} ngModel Assignable angular expression to data-bind to.
|
33220
33782
|
* @param {string=} name Property name of the form under which the control is published.
|
33221
33783
|
* @param {string=} required The control is considered valid only if value is entered.
|
@@ -33250,7 +33812,25 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
33250
33812
|
* DOM element.
|
33251
33813
|
* * `trackexpr`: Used when working with an array of objects. The result of this expression will be
|
33252
33814
|
* used to identify the objects in the array. The `trackexpr` will most likely refer to the
|
33253
|
-
* `value` variable (e.g. `value.propertyName`).
|
33815
|
+
* `value` variable (e.g. `value.propertyName`). With this the selection is preserved
|
33816
|
+
* even when the options are recreated (e.g. reloaded from the server).
|
33817
|
+
|
33818
|
+
* <div class="alert alert-info">
|
33819
|
+
* **Note:** Using `select as` together with `trackexpr` is not possible (and will throw).
|
33820
|
+
* Reasoning:
|
33821
|
+
* - Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
|
33822
|
+
* values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItemß'}}],
|
33823
|
+
* $scope.selected = {name: 'aSubItem'};
|
33824
|
+
* - track by is always applied to `value`, with purpose to preserve the selection,
|
33825
|
+
* (to `item` in this case)
|
33826
|
+
* - to calculate whether an item is selected we do the following:
|
33827
|
+
* 1. apply `track by` to the values in the array, e.g.
|
33828
|
+
* In the example: [1,2]
|
33829
|
+
* 2. apply `track by` to the already selected value in `ngModel`:
|
33830
|
+
* In the example: this is not possible, as `track by` refers to `item.id`, but the selected
|
33831
|
+
* value from `ngModel` is `{name: aSubItem}`.
|
33832
|
+
*
|
33833
|
+
* </div>
|
33254
33834
|
*
|
33255
33835
|
* @example
|
33256
33836
|
<example module="selectExample">
|
@@ -33507,6 +34087,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33507
34087
|
|
33508
34088
|
var displayFn = $parse(match[2] || match[1]),
|
33509
34089
|
valueName = match[4] || match[6],
|
34090
|
+
selectAs = / as /.test(match[0]) && match[1],
|
34091
|
+
selectAsFn = selectAs ? $parse(selectAs) : null,
|
33510
34092
|
keyName = match[5],
|
33511
34093
|
groupByFn = $parse(match[3] || ''),
|
33512
34094
|
valueFn = $parse(match[2] ? match[1] : valueName),
|
@@ -33517,7 +34099,16 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33517
34099
|
// We try to reuse these if possible
|
33518
34100
|
// - optionGroupsCache[0] is the options with no option group
|
33519
34101
|
// - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
|
33520
|
-
optionGroupsCache = [[{element: selectElement, label:''}]]
|
34102
|
+
optionGroupsCache = [[{element: selectElement, label:''}]],
|
34103
|
+
//re-usable object to represent option's locals
|
34104
|
+
locals = {};
|
34105
|
+
|
34106
|
+
if (trackFn && selectAsFn) {
|
34107
|
+
throw ngOptionsMinErr('trkslct',
|
34108
|
+
"Comprehension expression cannot contain both selectAs '{0}' " +
|
34109
|
+
"and trackBy '{1}' expressions.",
|
34110
|
+
selectAs, track);
|
34111
|
+
}
|
33521
34112
|
|
33522
34113
|
if (nullOption) {
|
33523
34114
|
// compile the element since there might be bindings in it
|
@@ -33535,103 +34126,110 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33535
34126
|
// clear contents, we'll add what's needed based on the model
|
33536
34127
|
selectElement.empty();
|
33537
34128
|
|
33538
|
-
selectElement.on('change',
|
34129
|
+
selectElement.on('change', selectionChanged);
|
34130
|
+
|
34131
|
+
ctrl.$render = render;
|
34132
|
+
|
34133
|
+
scope.$watchCollection(valuesFn, scheduleRendering);
|
34134
|
+
scope.$watchCollection(getLabels, scheduleRendering);
|
34135
|
+
|
34136
|
+
if (multiple) {
|
34137
|
+
scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
|
34138
|
+
}
|
34139
|
+
|
34140
|
+
// ------------------------------------------------------------------ //
|
34141
|
+
|
34142
|
+
function callExpression(exprFn, key, value) {
|
34143
|
+
locals[valueName] = value;
|
34144
|
+
if (keyName) locals[keyName] = key;
|
34145
|
+
return exprFn(scope, locals);
|
34146
|
+
}
|
34147
|
+
|
34148
|
+
function selectionChanged() {
|
33539
34149
|
scope.$apply(function() {
|
33540
34150
|
var optionGroup,
|
33541
34151
|
collection = valuesFn(scope) || [],
|
33542
|
-
locals = {},
|
33543
34152
|
key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
|
33544
|
-
|
34153
|
+
var viewValue;
|
33545
34154
|
if (multiple) {
|
33546
|
-
|
33547
|
-
|
33548
|
-
|
33549
|
-
|
33550
|
-
// list of options for that group. (first item has the parent)
|
33551
|
-
optionGroup = optionGroupsCache[groupIndex];
|
33552
|
-
|
33553
|
-
for(index = 1, length = optionGroup.length; index < length; index++) {
|
33554
|
-
if ((optionElement = optionGroup[index].element)[0].selected) {
|
33555
|
-
key = optionElement.val();
|
33556
|
-
if (keyName) locals[keyName] = key;
|
33557
|
-
if (trackFn) {
|
33558
|
-
for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
33559
|
-
locals[valueName] = collection[trackIndex];
|
33560
|
-
if (trackFn(scope, locals) == key) break;
|
33561
|
-
}
|
33562
|
-
} else {
|
33563
|
-
locals[valueName] = collection[key];
|
33564
|
-
}
|
33565
|
-
value.push(valueFn(scope, locals));
|
33566
|
-
}
|
33567
|
-
}
|
33568
|
-
}
|
34155
|
+
viewValue = [];
|
34156
|
+
forEach(selectElement.val(), function(selectedKey) {
|
34157
|
+
viewValue.push(getViewValue(selectedKey, collection[selectedKey]));
|
34158
|
+
});
|
33569
34159
|
} else {
|
33570
|
-
|
33571
|
-
|
33572
|
-
value = undefined;
|
33573
|
-
} else if (key === ''){
|
33574
|
-
value = null;
|
33575
|
-
} else {
|
33576
|
-
if (trackFn) {
|
33577
|
-
for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
|
33578
|
-
locals[valueName] = collection[trackIndex];
|
33579
|
-
if (trackFn(scope, locals) == key) {
|
33580
|
-
value = valueFn(scope, locals);
|
33581
|
-
break;
|
33582
|
-
}
|
33583
|
-
}
|
33584
|
-
} else {
|
33585
|
-
locals[valueName] = collection[key];
|
33586
|
-
if (keyName) locals[keyName] = key;
|
33587
|
-
value = valueFn(scope, locals);
|
33588
|
-
}
|
33589
|
-
}
|
34160
|
+
var selectedKey = selectElement.val();
|
34161
|
+
viewValue = getViewValue(selectedKey, collection[selectedKey]);
|
33590
34162
|
}
|
33591
|
-
ctrl.$setViewValue(
|
34163
|
+
ctrl.$setViewValue(viewValue);
|
33592
34164
|
render();
|
33593
34165
|
});
|
33594
|
-
}
|
34166
|
+
}
|
33595
34167
|
|
33596
|
-
|
34168
|
+
function getViewValue(key, value) {
|
34169
|
+
if (key === '?') {
|
34170
|
+
return undefined;
|
34171
|
+
} else if (key === '') {
|
34172
|
+
return null;
|
34173
|
+
} else {
|
34174
|
+
var viewValueFn = selectAsFn ? selectAsFn : valueFn;
|
34175
|
+
return callExpression(viewValueFn, key, value);
|
34176
|
+
}
|
34177
|
+
}
|
33597
34178
|
|
33598
|
-
|
33599
|
-
|
33600
|
-
var
|
33601
|
-
|
33602
|
-
|
33603
|
-
var toDisplay = new Array(values.length);
|
34179
|
+
function getLabels() {
|
34180
|
+
var values = valuesFn(scope);
|
34181
|
+
var toDisplay;
|
34182
|
+
if (values && isArray(values)) {
|
34183
|
+
toDisplay = new Array(values.length);
|
33604
34184
|
for (var i = 0, ii = values.length; i < ii; i++) {
|
33605
|
-
|
33606
|
-
toDisplay[i] = displayFn(scope, locals);
|
34185
|
+
toDisplay[i] = callExpression(displayFn, i, values[i]);
|
33607
34186
|
}
|
33608
34187
|
return toDisplay;
|
34188
|
+
} else if (values) {
|
34189
|
+
// TODO: Add a test for this case
|
34190
|
+
toDisplay = {};
|
34191
|
+
for (var prop in values) {
|
34192
|
+
if (values.hasOwnProperty(prop)) {
|
34193
|
+
toDisplay[prop] = callExpression(displayFn, prop, values[prop]);
|
34194
|
+
}
|
34195
|
+
}
|
33609
34196
|
}
|
33610
|
-
|
33611
|
-
|
33612
|
-
if (multiple) {
|
33613
|
-
scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
|
34197
|
+
return toDisplay;
|
33614
34198
|
}
|
33615
34199
|
|
33616
|
-
|
33617
|
-
|
33618
|
-
var selectedSet = false;
|
34200
|
+
function createIsSelectedFn(viewValue) {
|
34201
|
+
var selectedSet;
|
33619
34202
|
if (multiple) {
|
33620
|
-
|
33621
|
-
|
34203
|
+
if (!selectAs && trackFn && isArray(viewValue)) {
|
34204
|
+
|
33622
34205
|
selectedSet = new HashMap([]);
|
33623
|
-
var
|
33624
|
-
|
33625
|
-
|
33626
|
-
selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
|
34206
|
+
for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
|
34207
|
+
// tracking by key
|
34208
|
+
selectedSet.put(callExpression(trackFn, null, viewValue[trackIndex]), true);
|
33627
34209
|
}
|
33628
34210
|
} else {
|
33629
|
-
selectedSet = new HashMap(
|
34211
|
+
selectedSet = new HashMap(viewValue);
|
33630
34212
|
}
|
34213
|
+
} else if (!selectAsFn && trackFn) {
|
34214
|
+
viewValue = callExpression(trackFn, null, viewValue);
|
33631
34215
|
}
|
33632
|
-
return
|
33633
|
-
|
34216
|
+
return function isSelected(key, value) {
|
34217
|
+
var compareValueFn;
|
34218
|
+
if (selectAsFn) {
|
34219
|
+
compareValueFn = selectAsFn;
|
34220
|
+
} else if (trackFn) {
|
34221
|
+
compareValueFn = trackFn;
|
34222
|
+
} else {
|
34223
|
+
compareValueFn = valueFn;
|
34224
|
+
}
|
33634
34225
|
|
34226
|
+
if (multiple) {
|
34227
|
+
return isDefined(selectedSet.remove(callExpression(compareValueFn, key, value)));
|
34228
|
+
} else {
|
34229
|
+
return viewValue == callExpression(compareValueFn, key, value);
|
34230
|
+
}
|
34231
|
+
};
|
34232
|
+
}
|
33635
34233
|
|
33636
34234
|
function scheduleRendering() {
|
33637
34235
|
if (!renderScheduled) {
|
@@ -33640,78 +34238,64 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33640
34238
|
}
|
33641
34239
|
}
|
33642
34240
|
|
33643
|
-
|
33644
34241
|
function render() {
|
33645
34242
|
renderScheduled = false;
|
33646
34243
|
|
33647
|
-
|
34244
|
+
// Temporary location for the option groups before we render them
|
33648
34245
|
var optionGroups = {'':[]},
|
33649
34246
|
optionGroupNames = [''],
|
33650
34247
|
optionGroupName,
|
33651
34248
|
optionGroup,
|
33652
34249
|
option,
|
33653
34250
|
existingParent, existingOptions, existingOption,
|
33654
|
-
|
34251
|
+
viewValue = ctrl.$viewValue,
|
33655
34252
|
values = valuesFn(scope) || [],
|
33656
34253
|
keys = keyName ? sortedKeys(values) : values,
|
33657
34254
|
key,
|
34255
|
+
value,
|
33658
34256
|
groupLength, length,
|
33659
34257
|
groupIndex, index,
|
33660
|
-
locals = {},
|
33661
34258
|
selected,
|
33662
|
-
|
34259
|
+
isSelected = createIsSelectedFn(viewValue),
|
34260
|
+
anySelected = false,
|
33663
34261
|
lastElement,
|
33664
34262
|
element,
|
33665
34263
|
label;
|
33666
34264
|
|
33667
|
-
|
33668
34265
|
// We now build up the list of options we need (we merge later)
|
33669
34266
|
for (index = 0; length = keys.length, index < length; index++) {
|
33670
|
-
|
33671
34267
|
key = index;
|
33672
34268
|
if (keyName) {
|
33673
34269
|
key = keys[index];
|
33674
34270
|
if ( key.charAt(0) === '$' ) continue;
|
33675
|
-
locals[keyName] = key;
|
33676
34271
|
}
|
34272
|
+
value = values[key];
|
33677
34273
|
|
33678
|
-
|
33679
|
-
|
33680
|
-
optionGroupName = groupByFn(scope, locals) || '';
|
34274
|
+
optionGroupName = callExpression(groupByFn, key, value) || '';
|
33681
34275
|
if (!(optionGroup = optionGroups[optionGroupName])) {
|
33682
34276
|
optionGroup = optionGroups[optionGroupName] = [];
|
33683
34277
|
optionGroupNames.push(optionGroupName);
|
33684
34278
|
}
|
33685
|
-
|
33686
|
-
|
33687
|
-
|
33688
|
-
|
33689
|
-
|
33690
|
-
if (trackFn) {
|
33691
|
-
var modelCast = {};
|
33692
|
-
modelCast[valueName] = modelValue;
|
33693
|
-
selected = trackFn(scope, modelCast) === trackFn(scope, locals);
|
33694
|
-
} else {
|
33695
|
-
selected = modelValue === valueFn(scope, locals);
|
33696
|
-
}
|
33697
|
-
selectedSet = selectedSet || selected; // see if at least one item is selected
|
33698
|
-
}
|
33699
|
-
label = displayFn(scope, locals); // what will be seen by the user
|
34279
|
+
|
34280
|
+
selected = isSelected(key, value);
|
34281
|
+
anySelected = anySelected || selected;
|
34282
|
+
|
34283
|
+
label = callExpression(displayFn, key, value); // what will be seen by the user
|
33700
34284
|
|
33701
34285
|
// doing displayFn(scope, locals) || '' overwrites zero values
|
33702
34286
|
label = isDefined(label) ? label : '';
|
33703
34287
|
optionGroup.push({
|
33704
34288
|
// either the index into array or key from object
|
33705
|
-
id:
|
34289
|
+
id: (keyName ? keys[index] : index),
|
33706
34290
|
label: label,
|
33707
34291
|
selected: selected // determine if we should be selected
|
33708
34292
|
});
|
33709
34293
|
}
|
33710
34294
|
if (!multiple) {
|
33711
|
-
if (nullOption ||
|
34295
|
+
if (nullOption || viewValue === null) {
|
33712
34296
|
// insert null option if we have a placeholder, or the model is null
|
33713
|
-
optionGroups[''].unshift({id:'', label:'', selected:!
|
33714
|
-
} else if (!
|
34297
|
+
optionGroups[''].unshift({id:'', label:'', selected:!anySelected});
|
34298
|
+
} else if (!anySelected) {
|
33715
34299
|
// option could not be found, we have to insert the undefined item
|
33716
34300
|
optionGroups[''].unshift({id:'?', label:'', selected:true});
|
33717
34301
|
}
|
@@ -33792,6 +34376,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33792
34376
|
id: option.id,
|
33793
34377
|
selected: option.selected
|
33794
34378
|
});
|
34379
|
+
selectCtrl.addOption(option.label, element);
|
33795
34380
|
if (lastElement) {
|
33796
34381
|
lastElement.after(element);
|
33797
34382
|
} else {
|
@@ -33803,7 +34388,9 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
33803
34388
|
// remove any excessive OPTIONs in a group
|
33804
34389
|
index++; // increment since the existingOptions[0] is parent element not OPTION
|
33805
34390
|
while(existingOptions.length > index) {
|
33806
|
-
existingOptions.pop()
|
34391
|
+
option = existingOptions.pop();
|
34392
|
+
selectCtrl.removeOption(option.label);
|
34393
|
+
option.element.remove();
|
33807
34394
|
}
|
33808
34395
|
}
|
33809
34396
|
// remove any excessive OPTGROUPs from select
|
@@ -33839,11 +34426,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
|
33839
34426
|
selectCtrl = parent.data(selectCtrlName) ||
|
33840
34427
|
parent.parent().data(selectCtrlName); // in case we are in optgroup
|
33841
34428
|
|
33842
|
-
if (selectCtrl
|
33843
|
-
// For some reason Opera defaults to true and if not overridden this messes up the repeater.
|
33844
|
-
// We don't want the view to drive the initialization of the model anyway.
|
33845
|
-
element.prop('selected', false);
|
33846
|
-
} else {
|
34429
|
+
if (!selectCtrl || !selectCtrl.databound) {
|
33847
34430
|
selectCtrl = nullSelectCtrl;
|
33848
34431
|
}
|
33849
34432
|
|
@@ -34197,7 +34780,11 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) {
|
|
34197
34780
|
};
|
34198
34781
|
|
34199
34782
|
(function() {
|
34200
|
-
|
34783
|
+
/**
|
34784
|
+
* documentMode is an IE-only property
|
34785
|
+
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
|
34786
|
+
*/
|
34787
|
+
var msie = document.documentMode;
|
34201
34788
|
|
34202
34789
|
/**
|
34203
34790
|
* Triggers a browser event. Attempts to choose the right event if one is
|
@@ -34248,97 +34835,71 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) {
|
|
34248
34835
|
return keys.indexOf(key) !== -1;
|
34249
34836
|
}
|
34250
34837
|
|
34251
|
-
|
34252
|
-
|
34253
|
-
|
34838
|
+
var evnt;
|
34839
|
+
if(/transitionend/.test(eventType)) {
|
34840
|
+
if(window.WebKitTransitionEvent) {
|
34841
|
+
evnt = new WebKitTransitionEvent(eventType, eventData);
|
34842
|
+
evnt.initEvent(eventType, false, true);
|
34254
34843
|
}
|
34255
|
-
|
34256
|
-
|
34257
|
-
|
34258
|
-
// calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
|
34259
|
-
// forcing the browser to compute the element position (by reading its CSS)
|
34260
|
-
// puts the element in consistent state.
|
34261
|
-
element.style.posLeft;
|
34262
|
-
|
34263
|
-
// TODO(vojta): create event objects with pressed keys to get it working on IE<9
|
34264
|
-
var ret = element.fireEvent('on' + eventType);
|
34265
|
-
if (inputType == 'submit') {
|
34266
|
-
while(element) {
|
34267
|
-
if (element.nodeName.toLowerCase() == 'form') {
|
34268
|
-
element.fireEvent('onsubmit');
|
34269
|
-
break;
|
34270
|
-
}
|
34271
|
-
element = element.parentNode;
|
34272
|
-
}
|
34273
|
-
}
|
34274
|
-
return ret;
|
34275
|
-
} else {
|
34276
|
-
var evnt;
|
34277
|
-
if(/transitionend/.test(eventType)) {
|
34278
|
-
if(window.WebKitTransitionEvent) {
|
34279
|
-
evnt = new WebKitTransitionEvent(eventType, eventData);
|
34280
|
-
evnt.initEvent(eventType, false, true);
|
34844
|
+
else {
|
34845
|
+
try {
|
34846
|
+
evnt = new TransitionEvent(eventType, eventData);
|
34281
34847
|
}
|
34282
|
-
|
34283
|
-
|
34284
|
-
|
34285
|
-
}
|
34286
|
-
catch(e) {
|
34287
|
-
evnt = document.createEvent('TransitionEvent');
|
34288
|
-
evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
34289
|
-
}
|
34848
|
+
catch(e) {
|
34849
|
+
evnt = document.createEvent('TransitionEvent');
|
34850
|
+
evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
34290
34851
|
}
|
34291
34852
|
}
|
34292
|
-
|
34293
|
-
|
34294
|
-
|
34295
|
-
|
34853
|
+
}
|
34854
|
+
else if(/animationend/.test(eventType)) {
|
34855
|
+
if(window.WebKitAnimationEvent) {
|
34856
|
+
evnt = new WebKitAnimationEvent(eventType, eventData);
|
34857
|
+
evnt.initEvent(eventType, false, true);
|
34858
|
+
}
|
34859
|
+
else {
|
34860
|
+
try {
|
34861
|
+
evnt = new AnimationEvent(eventType, eventData);
|
34296
34862
|
}
|
34297
|
-
|
34298
|
-
|
34299
|
-
|
34300
|
-
}
|
34301
|
-
catch(e) {
|
34302
|
-
evnt = document.createEvent('AnimationEvent');
|
34303
|
-
evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
34304
|
-
}
|
34863
|
+
catch(e) {
|
34864
|
+
evnt = document.createEvent('AnimationEvent');
|
34865
|
+
evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
|
34305
34866
|
}
|
34306
34867
|
}
|
34307
|
-
|
34308
|
-
|
34309
|
-
|
34310
|
-
|
34311
|
-
|
34312
|
-
|
34313
|
-
|
34314
|
-
|
34315
|
-
/* we're unable to change the timeStamp value directly so this
|
34316
|
-
* is only here to allow for testing where the timeStamp value is
|
34317
|
-
* read */
|
34318
|
-
evnt.$manualTimeStamp = eventData.timeStamp;
|
34319
|
-
|
34320
|
-
if(!evnt) return;
|
34321
|
-
|
34322
|
-
var originalPreventDefault = evnt.preventDefault,
|
34323
|
-
appWindow = element.ownerDocument.defaultView,
|
34324
|
-
fakeProcessDefault = true,
|
34325
|
-
finalProcessDefault,
|
34326
|
-
angular = appWindow.angular || {};
|
34327
|
-
|
34328
|
-
// igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
|
34329
|
-
angular['ff-684208-preventDefault'] = false;
|
34330
|
-
evnt.preventDefault = function() {
|
34331
|
-
fakeProcessDefault = false;
|
34332
|
-
return originalPreventDefault.apply(evnt, arguments);
|
34333
|
-
};
|
34868
|
+
}
|
34869
|
+
else {
|
34870
|
+
evnt = document.createEvent('MouseEvents');
|
34871
|
+
x = x || 0;
|
34872
|
+
y = y || 0;
|
34873
|
+
evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
|
34874
|
+
pressed('alt'), pressed('shift'), pressed('meta'), 0, element);
|
34875
|
+
}
|
34334
34876
|
|
34335
|
-
|
34336
|
-
|
34877
|
+
/* we're unable to change the timeStamp value directly so this
|
34878
|
+
* is only here to allow for testing where the timeStamp value is
|
34879
|
+
* read */
|
34880
|
+
evnt.$manualTimeStamp = eventData.timeStamp;
|
34337
34881
|
|
34338
|
-
|
34882
|
+
if(!evnt) return;
|
34339
34883
|
|
34340
|
-
|
34341
|
-
|
34884
|
+
var originalPreventDefault = evnt.preventDefault,
|
34885
|
+
appWindow = element.ownerDocument.defaultView,
|
34886
|
+
fakeProcessDefault = true,
|
34887
|
+
finalProcessDefault,
|
34888
|
+
angular = appWindow.angular || {};
|
34889
|
+
|
34890
|
+
// igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
|
34891
|
+
angular['ff-684208-preventDefault'] = false;
|
34892
|
+
evnt.preventDefault = function() {
|
34893
|
+
fakeProcessDefault = false;
|
34894
|
+
return originalPreventDefault.apply(evnt, arguments);
|
34895
|
+
};
|
34896
|
+
|
34897
|
+
element.dispatchEvent(evnt);
|
34898
|
+
finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
|
34899
|
+
|
34900
|
+
delete angular['ff-684208-preventDefault'];
|
34901
|
+
|
34902
|
+
return finalProcessDefault;
|
34342
34903
|
};
|
34343
34904
|
}());
|
34344
34905
|
|
@@ -36079,5 +36640,5 @@ if (config.autotest) {
|
|
36079
36640
|
})(window, document);
|
36080
36641
|
|
36081
36642
|
|
36082
|
-
!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide:not(.ng-animate) {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
|
36643
|
+
!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide:not(.ng-hide-animate) {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
|
36083
36644
|
!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');
|