angularjs-on-rails 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/angular-animate.js +77 -21
- data/app/assets/javascripts/angular-cookies.js +17 -15
- data/app/assets/javascripts/angular-loader.js +2 -2
- data/app/assets/javascripts/angular-mocks.js +11 -3
- data/app/assets/javascripts/angular-resource.js +12 -12
- data/app/assets/javascripts/angular-route.js +2 -4
- data/app/assets/javascripts/angular-sanitize.js +40 -30
- data/app/assets/javascripts/angular-scenario.js +909 -744
- data/app/assets/javascripts/angular-touch.js +1 -1
- data/app/assets/javascripts/angular.js +908 -743
- data/lib/angularjs-on-rails/version.rb +1 -1
- data/lib/generators/angular/install/templates/index.html +0 -1
- metadata +4 -4
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.2.
|
2
|
+
* @license AngularJS v1.2.21
|
3
3
|
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -68,7 +68,7 @@ function minErr(module) {
|
|
68
68
|
return match;
|
69
69
|
});
|
70
70
|
|
71
|
-
message = message + '\nhttp://errors.angularjs.org/1.2.
|
71
|
+
message = message + '\nhttp://errors.angularjs.org/1.2.21/' +
|
72
72
|
(module ? module + '/' : '') + code;
|
73
73
|
for (i = 2; i < arguments.length; i++) {
|
74
74
|
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
|
@@ -80,88 +80,88 @@ function minErr(module) {
|
|
80
80
|
}
|
81
81
|
|
82
82
|
/* We need to tell jshint what variables are being exported */
|
83
|
-
/* global
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
83
|
+
/* global angular: true,
|
84
|
+
msie: true,
|
85
|
+
jqLite: true,
|
86
|
+
jQuery: true,
|
87
|
+
slice: true,
|
88
|
+
push: true,
|
89
|
+
toString: true,
|
90
|
+
ngMinErr: true,
|
91
|
+
angularModule: true,
|
92
|
+
nodeName_: true,
|
93
|
+
uid: true,
|
94
|
+
VALIDITY_STATE_PROPERTY: true,
|
95
|
+
|
96
|
+
lowercase: true,
|
97
|
+
uppercase: true,
|
98
|
+
manualLowercase: true,
|
99
|
+
manualUppercase: true,
|
100
|
+
nodeName_: true,
|
101
|
+
isArrayLike: true,
|
102
|
+
forEach: true,
|
103
|
+
sortedKeys: true,
|
104
|
+
forEachSorted: true,
|
105
|
+
reverseParams: true,
|
106
|
+
nextUid: true,
|
107
|
+
setHashKey: true,
|
108
|
+
extend: true,
|
109
|
+
int: true,
|
110
|
+
inherit: true,
|
111
|
+
noop: true,
|
112
|
+
identity: true,
|
113
|
+
valueFn: true,
|
114
|
+
isUndefined: true,
|
115
|
+
isDefined: true,
|
116
|
+
isObject: true,
|
117
|
+
isString: true,
|
118
|
+
isNumber: true,
|
119
|
+
isDate: true,
|
120
|
+
isArray: true,
|
121
|
+
isFunction: true,
|
122
|
+
isRegExp: true,
|
123
|
+
isWindow: true,
|
124
|
+
isScope: true,
|
125
|
+
isFile: true,
|
126
|
+
isBlob: true,
|
127
|
+
isBoolean: true,
|
128
|
+
isPromiseLike: true,
|
129
|
+
trim: true,
|
130
|
+
isElement: true,
|
131
|
+
makeMap: true,
|
132
|
+
map: true,
|
133
|
+
size: true,
|
134
|
+
includes: true,
|
135
|
+
indexOf: true,
|
136
|
+
arrayRemove: true,
|
137
|
+
isLeafNode: true,
|
138
|
+
copy: true,
|
139
|
+
shallowCopy: true,
|
140
|
+
equals: true,
|
141
|
+
csp: true,
|
142
|
+
concat: true,
|
143
|
+
sliceArgs: true,
|
144
|
+
bind: true,
|
145
|
+
toJsonReplacer: true,
|
146
|
+
toJson: true,
|
147
|
+
fromJson: true,
|
148
|
+
toBoolean: true,
|
149
|
+
startingTag: true,
|
150
|
+
tryDecodeURIComponent: true,
|
151
|
+
parseKeyValue: true,
|
152
|
+
toKeyValue: true,
|
153
|
+
encodeUriSegment: true,
|
154
|
+
encodeUriQuery: true,
|
155
|
+
angularInit: true,
|
156
|
+
bootstrap: true,
|
157
|
+
snake_case: true,
|
158
|
+
bindJQuery: true,
|
159
|
+
assertArg: true,
|
160
|
+
assertArgFn: true,
|
161
|
+
assertNotHasOwnProperty: true,
|
162
|
+
getter: true,
|
163
|
+
getBlockElements: true,
|
164
|
+
hasOwnProperty: true,
|
165
165
|
*/
|
166
166
|
|
167
167
|
////////////////////////////////////
|
@@ -181,6 +181,10 @@ function minErr(module) {
|
|
181
181
|
* <div doc-module-components="ng"></div>
|
182
182
|
*/
|
183
183
|
|
184
|
+
// The name of a form control's ValidityState property.
|
185
|
+
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
186
|
+
var VALIDITY_STATE_PROPERTY = 'validity';
|
187
|
+
|
184
188
|
/**
|
185
189
|
* @ngdoc function
|
186
190
|
* @name angular.lowercase
|
@@ -316,11 +320,12 @@ function forEach(obj, iterator, context) {
|
|
316
320
|
iterator.call(context, obj[key], key);
|
317
321
|
}
|
318
322
|
}
|
319
|
-
} else if (obj
|
320
|
-
obj.
|
321
|
-
} else if (isArrayLike(obj)) {
|
322
|
-
for (key = 0; key < obj.length; key++)
|
323
|
+
} else if (isArray(obj) || isArrayLike(obj)) {
|
324
|
+
for (key = 0; key < obj.length; key++) {
|
323
325
|
iterator.call(context, obj[key], key);
|
326
|
+
}
|
327
|
+
} else if (obj.forEach && obj.forEach !== forEach) {
|
328
|
+
obj.forEach(iterator, context);
|
324
329
|
} else {
|
325
330
|
for (key in obj) {
|
326
331
|
if (obj.hasOwnProperty(key)) {
|
@@ -657,6 +662,11 @@ function isBoolean(value) {
|
|
657
662
|
}
|
658
663
|
|
659
664
|
|
665
|
+
function isPromiseLike(obj) {
|
666
|
+
return obj && isFunction(obj.then);
|
667
|
+
}
|
668
|
+
|
669
|
+
|
660
670
|
var trim = (function() {
|
661
671
|
// native trim is way faster: http://jsperf.com/angular-trim-test
|
662
672
|
// but IE doesn't have it... :-(
|
@@ -805,9 +815,9 @@ function isLeafNode (node) {
|
|
805
815
|
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
806
816
|
*
|
807
817
|
* @example
|
808
|
-
<example>
|
818
|
+
<example module="copyExample">
|
809
819
|
<file name="index.html">
|
810
|
-
<div ng-controller="
|
820
|
+
<div ng-controller="ExampleController">
|
811
821
|
<form novalidate class="simple-form">
|
812
822
|
Name: <input type="text" ng-model="user.name" /><br />
|
813
823
|
E-mail: <input type="email" ng-model="user.email" /><br />
|
@@ -821,21 +831,22 @@ function isLeafNode (node) {
|
|
821
831
|
</div>
|
822
832
|
|
823
833
|
<script>
|
824
|
-
|
825
|
-
$scope
|
834
|
+
angular.module('copyExample', [])
|
835
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
836
|
+
$scope.master= {};
|
826
837
|
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
838
|
+
$scope.update = function(user) {
|
839
|
+
// Example with 1 argument
|
840
|
+
$scope.master= angular.copy(user);
|
841
|
+
};
|
831
842
|
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
843
|
+
$scope.reset = function() {
|
844
|
+
// Example with 2 arguments
|
845
|
+
angular.copy($scope.master, $scope.user);
|
846
|
+
};
|
836
847
|
|
837
|
-
|
838
|
-
|
848
|
+
$scope.reset();
|
849
|
+
}]);
|
839
850
|
</script>
|
840
851
|
</file>
|
841
852
|
</example>
|
@@ -854,7 +865,8 @@ function copy(source, destination, stackSource, stackDest) {
|
|
854
865
|
} else if (isDate(source)) {
|
855
866
|
destination = new Date(source.getTime());
|
856
867
|
} else if (isRegExp(source)) {
|
857
|
-
destination = new RegExp(source.source);
|
868
|
+
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
869
|
+
destination.lastIndex = source.lastIndex;
|
858
870
|
} else if (isObject(source)) {
|
859
871
|
destination = copy(source, {}, stackSource, stackDest);
|
860
872
|
}
|
@@ -998,12 +1010,25 @@ function equals(o1, o2) {
|
|
998
1010
|
return false;
|
999
1011
|
}
|
1000
1012
|
|
1013
|
+
var csp = function() {
|
1014
|
+
if (isDefined(csp.isActive_)) return csp.isActive_;
|
1015
|
+
|
1016
|
+
var active = !!(document.querySelector('[ng-csp]') ||
|
1017
|
+
document.querySelector('[data-ng-csp]'));
|
1018
|
+
|
1019
|
+
if (!active) {
|
1020
|
+
try {
|
1021
|
+
/* jshint -W031, -W054 */
|
1022
|
+
new Function('');
|
1023
|
+
/* jshint +W031, +W054 */
|
1024
|
+
} catch (e) {
|
1025
|
+
active = true;
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
return (csp.isActive_ = active);
|
1030
|
+
};
|
1001
1031
|
|
1002
|
-
function csp() {
|
1003
|
-
return (document.securityPolicy && document.securityPolicy.isActive) ||
|
1004
|
-
(document.querySelector &&
|
1005
|
-
!!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
|
1006
|
-
}
|
1007
1032
|
|
1008
1033
|
|
1009
1034
|
function concat(array1, array2, index) {
|
@@ -1175,11 +1200,11 @@ function parseKeyValue(/**string*/keyValue) {
|
|
1175
1200
|
var obj = {}, key_value, key;
|
1176
1201
|
forEach((keyValue || "").split('&'), function(keyValue) {
|
1177
1202
|
if ( keyValue ) {
|
1178
|
-
key_value = keyValue.split('=');
|
1203
|
+
key_value = keyValue.replace(/\+/g,'%20').split('=');
|
1179
1204
|
key = tryDecodeURIComponent(key_value[0]);
|
1180
1205
|
if ( isDefined(key) ) {
|
1181
1206
|
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
|
1182
|
-
if (!obj
|
1207
|
+
if (!hasOwnProperty.call(obj, key)) {
|
1183
1208
|
obj[key] = val;
|
1184
1209
|
} else if(isArray(obj[key])) {
|
1185
1210
|
obj[key].push(val);
|
@@ -1353,7 +1378,7 @@ function angularInit(element, bootstrap) {
|
|
1353
1378
|
*
|
1354
1379
|
* Angular will detect if it has been loaded into the browser more than once and only allow the
|
1355
1380
|
* first loaded script to be bootstrapped and will report a warning to the browser console for
|
1356
|
-
* each of the subsequent scripts.
|
1381
|
+
* each of the subsequent scripts. This prevents strange results in applications, where otherwise
|
1357
1382
|
* multiple instances of Angular try to work on the DOM.
|
1358
1383
|
*
|
1359
1384
|
* <example name="multi-bootstrap" module="multi-bootstrap">
|
@@ -1483,7 +1508,7 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
|
|
1483
1508
|
}
|
1484
1509
|
|
1485
1510
|
assertArg(isFunction(arg), name, 'not a function, got ' +
|
1486
|
-
(arg && typeof arg
|
1511
|
+
(arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
1487
1512
|
return arg;
|
1488
1513
|
}
|
1489
1514
|
|
@@ -1860,12 +1885,11 @@ function setupModuleLoader(window) {
|
|
1860
1885
|
|
1861
1886
|
}
|
1862
1887
|
|
1863
|
-
/* global
|
1864
|
-
|
1865
|
-
version: true,
|
1888
|
+
/* global angularModule: true,
|
1889
|
+
version: true,
|
1866
1890
|
|
1867
|
-
|
1868
|
-
|
1891
|
+
$LocaleProvider,
|
1892
|
+
$CompileProvider,
|
1869
1893
|
|
1870
1894
|
htmlAnchorDirective,
|
1871
1895
|
inputDirective,
|
@@ -1953,11 +1977,11 @@ function setupModuleLoader(window) {
|
|
1953
1977
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
1954
1978
|
*/
|
1955
1979
|
var version = {
|
1956
|
-
full: '1.2.
|
1980
|
+
full: '1.2.21', // all of these placeholder strings will be replaced by grunt's
|
1957
1981
|
major: 1, // package task
|
1958
1982
|
minor: 2,
|
1959
|
-
dot:
|
1960
|
-
codeName: '
|
1983
|
+
dot: 21,
|
1984
|
+
codeName: 'wizard-props'
|
1961
1985
|
};
|
1962
1986
|
|
1963
1987
|
|
@@ -2081,12 +2105,10 @@ function publishExternalAPI(angular){
|
|
2081
2105
|
]);
|
2082
2106
|
}
|
2083
2107
|
|
2084
|
-
/* global
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
-removeEventListenerFn,
|
2089
|
-
-BOOLEAN_ATTR
|
2108
|
+
/* global JQLitePrototype: true,
|
2109
|
+
addEventListenerFn: true,
|
2110
|
+
removeEventListenerFn: true,
|
2111
|
+
BOOLEAN_ATTR: true
|
2090
2112
|
*/
|
2091
2113
|
|
2092
2114
|
//////////////////////////////////
|
@@ -2179,8 +2201,9 @@ function publishExternalAPI(angular){
|
|
2179
2201
|
* @returns {Object} jQuery object.
|
2180
2202
|
*/
|
2181
2203
|
|
2204
|
+
JQLite.expando = 'ng339';
|
2205
|
+
|
2182
2206
|
var jqCache = JQLite.cache = {},
|
2183
|
-
jqName = JQLite.expando = 'ng' + new Date().getTime(),
|
2184
2207
|
jqId = 1,
|
2185
2208
|
addEventListenerFn = (window.document.addEventListener
|
2186
2209
|
? function(element, type, fn) {element.addEventListener(type, fn, false);}
|
@@ -2390,7 +2413,7 @@ function jqLiteOff(element, type, fn, unsupported) {
|
|
2390
2413
|
}
|
2391
2414
|
|
2392
2415
|
function jqLiteRemoveData(element, name) {
|
2393
|
-
var expandoId = element
|
2416
|
+
var expandoId = element.ng339,
|
2394
2417
|
expandoStore = jqCache[expandoId];
|
2395
2418
|
|
2396
2419
|
if (expandoStore) {
|
@@ -2404,17 +2427,17 @@ function jqLiteRemoveData(element, name) {
|
|
2404
2427
|
jqLiteOff(element);
|
2405
2428
|
}
|
2406
2429
|
delete jqCache[expandoId];
|
2407
|
-
element
|
2430
|
+
element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
|
2408
2431
|
}
|
2409
2432
|
}
|
2410
2433
|
|
2411
2434
|
function jqLiteExpandoStore(element, key, value) {
|
2412
|
-
var expandoId = element
|
2435
|
+
var expandoId = element.ng339,
|
2413
2436
|
expandoStore = jqCache[expandoId || -1];
|
2414
2437
|
|
2415
2438
|
if (isDefined(value)) {
|
2416
2439
|
if (!expandoStore) {
|
2417
|
-
element
|
2440
|
+
element.ng339 = expandoId = jqNextId();
|
2418
2441
|
expandoStore = jqCache[expandoId] = {};
|
2419
2442
|
}
|
2420
2443
|
expandoStore[key] = value;
|
@@ -2499,25 +2522,22 @@ function jqLiteController(element, name) {
|
|
2499
2522
|
}
|
2500
2523
|
|
2501
2524
|
function jqLiteInheritedData(element, name, value) {
|
2502
|
-
element = jqLite(element);
|
2503
|
-
|
2504
2525
|
// if element is the document object work with the html element instead
|
2505
2526
|
// this makes $(document).scope() possible
|
2506
|
-
if(element
|
2507
|
-
element = element.
|
2527
|
+
if(element.nodeType == 9) {
|
2528
|
+
element = element.documentElement;
|
2508
2529
|
}
|
2509
2530
|
var names = isArray(name) ? name : [name];
|
2510
2531
|
|
2511
|
-
while (element
|
2512
|
-
var node = element[0];
|
2532
|
+
while (element) {
|
2513
2533
|
for (var i = 0, ii = names.length; i < ii; i++) {
|
2514
|
-
if ((value =
|
2534
|
+
if ((value = jqLite.data(element, names[i])) !== undefined) return value;
|
2515
2535
|
}
|
2516
2536
|
|
2517
2537
|
// If dealing with a document fragment node with a host element, and no parent, use the host
|
2518
2538
|
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
|
2519
2539
|
// to lookup parent controllers.
|
2520
|
-
element =
|
2540
|
+
element = element.parentNode || (element.nodeType === 11 && element.host);
|
2521
2541
|
}
|
2522
2542
|
}
|
2523
2543
|
|
@@ -2592,18 +2612,25 @@ function getBooleanAttrName(element, name) {
|
|
2592
2612
|
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
|
2593
2613
|
}
|
2594
2614
|
|
2615
|
+
forEach({
|
2616
|
+
data: jqLiteData,
|
2617
|
+
removeData: jqLiteRemoveData
|
2618
|
+
}, function(fn, name) {
|
2619
|
+
JQLite[name] = fn;
|
2620
|
+
});
|
2621
|
+
|
2595
2622
|
forEach({
|
2596
2623
|
data: jqLiteData,
|
2597
2624
|
inheritedData: jqLiteInheritedData,
|
2598
2625
|
|
2599
2626
|
scope: function(element) {
|
2600
2627
|
// Can't use jqLiteData here directly so we stay compatible with jQuery!
|
2601
|
-
return jqLite
|
2628
|
+
return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
|
2602
2629
|
},
|
2603
2630
|
|
2604
2631
|
isolateScope: function(element) {
|
2605
2632
|
// Can't use jqLiteData here directly so we stay compatible with jQuery!
|
2606
|
-
return jqLite
|
2633
|
+
return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
|
2607
2634
|
},
|
2608
2635
|
|
2609
2636
|
controller: jqLiteController,
|
@@ -3031,7 +3058,9 @@ forEach({
|
|
3031
3058
|
clone: jqLiteClone,
|
3032
3059
|
|
3033
3060
|
triggerHandler: function(element, eventName, eventData) {
|
3034
|
-
|
3061
|
+
// Copy event handlers in case event handlers array is modified during execution.
|
3062
|
+
var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName],
|
3063
|
+
eventFnsCopy = shallowCopy(eventFns || []);
|
3035
3064
|
|
3036
3065
|
eventData = eventData || [];
|
3037
3066
|
|
@@ -3040,7 +3069,7 @@ forEach({
|
|
3040
3069
|
stopPropagation: noop
|
3041
3070
|
}];
|
3042
3071
|
|
3043
|
-
forEach(
|
3072
|
+
forEach(eventFnsCopy, function(fn) {
|
3044
3073
|
fn.apply(element, event.concat(eventData));
|
3045
3074
|
});
|
3046
3075
|
}
|
@@ -3081,16 +3110,16 @@ forEach({
|
|
3081
3110
|
* @returns {string} hash string such that the same input will have the same hash string.
|
3082
3111
|
* The resulting string key is in 'type:hashKey' format.
|
3083
3112
|
*/
|
3084
|
-
function hashKey(obj) {
|
3113
|
+
function hashKey(obj, nextUidFn) {
|
3085
3114
|
var objType = typeof obj,
|
3086
3115
|
key;
|
3087
3116
|
|
3088
|
-
if (objType == 'object' && obj !== null) {
|
3117
|
+
if (objType == 'function' || (objType == 'object' && obj !== null)) {
|
3089
3118
|
if (typeof (key = obj.$$hashKey) == 'function') {
|
3090
3119
|
// must invoke on object to keep the right this
|
3091
3120
|
key = obj.$$hashKey();
|
3092
3121
|
} else if (key === undefined) {
|
3093
|
-
key = obj.$$hashKey = nextUid();
|
3122
|
+
key = obj.$$hashKey = (nextUidFn || nextUid)();
|
3094
3123
|
}
|
3095
3124
|
} else {
|
3096
3125
|
key = obj;
|
@@ -3102,7 +3131,13 @@ function hashKey(obj) {
|
|
3102
3131
|
/**
|
3103
3132
|
* HashMap which can use objects as keys
|
3104
3133
|
*/
|
3105
|
-
function HashMap(array){
|
3134
|
+
function HashMap(array, isolatedUid) {
|
3135
|
+
if (isolatedUid) {
|
3136
|
+
var uid = 0;
|
3137
|
+
this.nextUid = function() {
|
3138
|
+
return ++uid;
|
3139
|
+
};
|
3140
|
+
}
|
3106
3141
|
forEach(array, this.put, this);
|
3107
3142
|
}
|
3108
3143
|
HashMap.prototype = {
|
@@ -3112,7 +3147,7 @@ HashMap.prototype = {
|
|
3112
3147
|
* @param value value to store can be any type
|
3113
3148
|
*/
|
3114
3149
|
put: function(key, value) {
|
3115
|
-
this[hashKey(key)] = value;
|
3150
|
+
this[hashKey(key, this.nextUid)] = value;
|
3116
3151
|
},
|
3117
3152
|
|
3118
3153
|
/**
|
@@ -3120,7 +3155,7 @@ HashMap.prototype = {
|
|
3120
3155
|
* @returns {Object} the value for the key
|
3121
3156
|
*/
|
3122
3157
|
get: function(key) {
|
3123
|
-
return this[hashKey(key)];
|
3158
|
+
return this[hashKey(key, this.nextUid)];
|
3124
3159
|
},
|
3125
3160
|
|
3126
3161
|
/**
|
@@ -3128,7 +3163,7 @@ HashMap.prototype = {
|
|
3128
3163
|
* @param key
|
3129
3164
|
*/
|
3130
3165
|
remove: function(key) {
|
3131
|
-
var value = this[key = hashKey(key)];
|
3166
|
+
var value = this[key = hashKey(key, this.nextUid)];
|
3132
3167
|
delete this[key];
|
3133
3168
|
return value;
|
3134
3169
|
}
|
@@ -3206,7 +3241,7 @@ function annotate(fn) {
|
|
3206
3241
|
argDecl,
|
3207
3242
|
last;
|
3208
3243
|
|
3209
|
-
if (typeof fn
|
3244
|
+
if (typeof fn === 'function') {
|
3210
3245
|
if (!($inject = fn.$inject)) {
|
3211
3246
|
$inject = [];
|
3212
3247
|
if (fn.length) {
|
@@ -3419,7 +3454,7 @@ function annotate(fn) {
|
|
3419
3454
|
|
3420
3455
|
|
3421
3456
|
/**
|
3422
|
-
* @ngdoc
|
3457
|
+
* @ngdoc service
|
3423
3458
|
* @name $provide
|
3424
3459
|
*
|
3425
3460
|
* @description
|
@@ -3725,7 +3760,7 @@ function createInjector(modulesToLoad) {
|
|
3725
3760
|
var INSTANTIATING = {},
|
3726
3761
|
providerSuffix = 'Provider',
|
3727
3762
|
path = [],
|
3728
|
-
loadedModules = new HashMap(),
|
3763
|
+
loadedModules = new HashMap([], true),
|
3729
3764
|
providerCache = {
|
3730
3765
|
$provide: {
|
3731
3766
|
provider: supportObject(provider),
|
@@ -3896,8 +3931,7 @@ function createInjector(modulesToLoad) {
|
|
3896
3931
|
: getService(key)
|
3897
3932
|
);
|
3898
3933
|
}
|
3899
|
-
if (
|
3900
|
-
// this means that we must be an array.
|
3934
|
+
if (isArray(fn)) {
|
3901
3935
|
fn = fn[length];
|
3902
3936
|
}
|
3903
3937
|
|
@@ -5230,7 +5264,7 @@ function $TemplateCacheProvider() {
|
|
5230
5264
|
* local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
5231
5265
|
* `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
|
5232
5266
|
* a function wrapper for the `count = count + value` expression. Often it's desirable to
|
5233
|
-
* pass data from the isolated scope via an expression
|
5267
|
+
* pass data from the isolated scope via an expression to the parent scope, this can be
|
5234
5268
|
* done by passing a map of local variable names and values into the expression wrapper fn.
|
5235
5269
|
* For example, if the expression is `increment(amount)` then we can specify the amount value
|
5236
5270
|
* by calling the `localFn` as `localFn({amount: 22})`.
|
@@ -5281,14 +5315,16 @@ function $TemplateCacheProvider() {
|
|
5281
5315
|
*
|
5282
5316
|
*
|
5283
5317
|
* #### `template`
|
5284
|
-
*
|
5285
|
-
*
|
5286
|
-
*
|
5287
|
-
*
|
5318
|
+
* HTML markup that may:
|
5319
|
+
* * Replace the contents of the directive's element (defualt).
|
5320
|
+
* * Replace the directive's element itself (if `replace` is true - DEPRECATED).
|
5321
|
+
* * Wrap the contents of the directive's element (if `transclude` is true).
|
5288
5322
|
*
|
5289
|
-
*
|
5290
|
-
*
|
5291
|
-
*
|
5323
|
+
* Value may be:
|
5324
|
+
*
|
5325
|
+
* * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
|
5326
|
+
* * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
|
5327
|
+
* function api below) and returns a string value.
|
5292
5328
|
*
|
5293
5329
|
*
|
5294
5330
|
* #### `templateUrl`
|
@@ -5303,11 +5339,14 @@ function $TemplateCacheProvider() {
|
|
5303
5339
|
*
|
5304
5340
|
*
|
5305
5341
|
* #### `replace` ([*DEPRECATED*!], will be removed in next major release)
|
5306
|
-
* specify
|
5342
|
+
* specify what the template should replace. Defaults to `false`.
|
5307
5343
|
*
|
5308
|
-
* * `true` - the template will replace the
|
5309
|
-
* * `false` - the template will replace the contents of the
|
5344
|
+
* * `true` - the template will replace the directive's element.
|
5345
|
+
* * `false` - the template will replace the contents of the directive's element.
|
5310
5346
|
*
|
5347
|
+
* The replacement process migrates all of the attributes / classes from the old element to the new
|
5348
|
+
* one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
|
5349
|
+
* Directives Guide} for an example.
|
5311
5350
|
*
|
5312
5351
|
* #### `transclude`
|
5313
5352
|
* compile the content of the element and make it available to the directive.
|
@@ -5321,6 +5360,11 @@ function $TemplateCacheProvider() {
|
|
5321
5360
|
* * `true` - transclude the content of the directive.
|
5322
5361
|
* * `'element'` - transclude the whole element including any directives defined at lower priority.
|
5323
5362
|
*
|
5363
|
+
* <div class="alert alert-warning">
|
5364
|
+
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
|
5365
|
+
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
|
5366
|
+
* Testing Transclusion Directives}.
|
5367
|
+
* </div>
|
5324
5368
|
*
|
5325
5369
|
* #### `compile`
|
5326
5370
|
*
|
@@ -5457,10 +5501,10 @@ function $TemplateCacheProvider() {
|
|
5457
5501
|
* to illustrate how `$compile` works.
|
5458
5502
|
* </div>
|
5459
5503
|
*
|
5460
|
-
<example module="
|
5504
|
+
<example module="compileExample">
|
5461
5505
|
<file name="index.html">
|
5462
5506
|
<script>
|
5463
|
-
angular.module('
|
5507
|
+
angular.module('compileExample', [], function($compileProvider) {
|
5464
5508
|
// configure new 'compile' directive by passing a directive
|
5465
5509
|
// factory function. The factory function injects the '$compile'
|
5466
5510
|
$compileProvider.directive('compile', function($compile) {
|
@@ -5484,15 +5528,14 @@ function $TemplateCacheProvider() {
|
|
5484
5528
|
}
|
5485
5529
|
);
|
5486
5530
|
};
|
5487
|
-
})
|
5488
|
-
})
|
5489
|
-
|
5490
|
-
function Ctrl($scope) {
|
5531
|
+
});
|
5532
|
+
})
|
5533
|
+
.controller('GreeterController', ['$scope', function($scope) {
|
5491
5534
|
$scope.name = 'Angular';
|
5492
5535
|
$scope.html = 'Hello {{name}}';
|
5493
|
-
}
|
5536
|
+
}]);
|
5494
5537
|
</script>
|
5495
|
-
<div ng-controller="
|
5538
|
+
<div ng-controller="GreeterController">
|
5496
5539
|
<input ng-model="name"> <br>
|
5497
5540
|
<textarea ng-model="html"></textarea> <br>
|
5498
5541
|
<div compile="html"></div>
|
@@ -5967,7 +6010,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
5967
6010
|
: null;
|
5968
6011
|
|
5969
6012
|
if (nodeLinkFn && nodeLinkFn.scope) {
|
5970
|
-
safeAddClass(
|
6013
|
+
safeAddClass(attrs.$$element, 'ng-scope');
|
5971
6014
|
}
|
5972
6015
|
|
5973
6016
|
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
|
@@ -5989,7 +6032,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
5989
6032
|
return linkFnFound ? compositeLinkFn : null;
|
5990
6033
|
|
5991
6034
|
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
|
5992
|
-
var nodeLinkFn, childLinkFn, node,
|
6035
|
+
var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
|
5993
6036
|
|
5994
6037
|
// copy nodeList so that linking doesn't break due to live list updates.
|
5995
6038
|
var nodeListLength = nodeList.length,
|
@@ -6002,12 +6045,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6002
6045
|
node = stableNodeList[n];
|
6003
6046
|
nodeLinkFn = linkFns[i++];
|
6004
6047
|
childLinkFn = linkFns[i++];
|
6005
|
-
$node = jqLite(node);
|
6006
6048
|
|
6007
6049
|
if (nodeLinkFn) {
|
6008
6050
|
if (nodeLinkFn.scope) {
|
6009
6051
|
childScope = scope.$new();
|
6010
|
-
|
6052
|
+
jqLite.data(node, '$scope', childScope);
|
6011
6053
|
} else {
|
6012
6054
|
childScope = scope;
|
6013
6055
|
}
|
@@ -6078,7 +6120,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6078
6120
|
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
|
6079
6121
|
|
6080
6122
|
// iterate over the attributes
|
6081
|
-
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
|
6123
|
+
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
|
6082
6124
|
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
|
6083
6125
|
var attrStartName = false;
|
6084
6126
|
var attrEndName = false;
|
@@ -6086,9 +6128,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6086
6128
|
attr = nAttrs[j];
|
6087
6129
|
if (!msie || msie >= 8 || attr.specified) {
|
6088
6130
|
name = attr.name;
|
6131
|
+
value = trim(attr.value);
|
6132
|
+
|
6089
6133
|
// support ngAttr attribute binding
|
6090
6134
|
ngAttrName = directiveNormalize(name);
|
6091
|
-
if (NG_ATTR_BINDING.test(ngAttrName)) {
|
6135
|
+
if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
|
6092
6136
|
name = snake_case(ngAttrName.substr(6), '-');
|
6093
6137
|
}
|
6094
6138
|
|
@@ -6101,9 +6145,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6101
6145
|
|
6102
6146
|
nName = directiveNormalize(name.toLowerCase());
|
6103
6147
|
attrsMap[nName] = name;
|
6104
|
-
|
6105
|
-
|
6106
|
-
|
6148
|
+
if (isNgAttr || !attrs.hasOwnProperty(nName)) {
|
6149
|
+
attrs[nName] = value;
|
6150
|
+
if (getBooleanAttrName(node, nName)) {
|
6151
|
+
attrs[nName] = true; // presence means true
|
6152
|
+
}
|
6107
6153
|
}
|
6108
6154
|
addAttrInterpolateDirective(node, directives, value, nName);
|
6109
6155
|
addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
|
@@ -6295,12 +6341,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6295
6341
|
if (directiveValue == 'element') {
|
6296
6342
|
hasElementTranscludeDirective = true;
|
6297
6343
|
terminalPriority = directive.priority;
|
6298
|
-
$template =
|
6344
|
+
$template = $compileNode;
|
6299
6345
|
$compileNode = templateAttrs.$$element =
|
6300
6346
|
jqLite(document.createComment(' ' + directiveName + ': ' +
|
6301
6347
|
templateAttrs[directiveName] + ' '));
|
6302
6348
|
compileNode = $compileNode[0];
|
6303
|
-
replaceWith(jqCollection,
|
6349
|
+
replaceWith(jqCollection, sliceArgs($template), compileNode);
|
6304
6350
|
|
6305
6351
|
childTranscludeFn = compile($template, transcludeFn, terminalPriority,
|
6306
6352
|
replaceDirective && replaceDirective.name, {
|
@@ -6477,29 +6523,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
|
6477
6523
|
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
|
6478
6524
|
var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
|
6479
6525
|
|
6480
|
-
|
6481
|
-
|
6482
|
-
|
6483
|
-
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
|
6484
|
-
}
|
6526
|
+
attrs = (compileNode === linkNode)
|
6527
|
+
? templateAttrs
|
6528
|
+
: shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
|
6485
6529
|
$element = attrs.$$element;
|
6486
6530
|
|
6487
6531
|
if (newIsolateScopeDirective) {
|
6488
6532
|
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
|
6489
|
-
var $linkNode = jqLite(linkNode);
|
6490
6533
|
|
6491
6534
|
isolateScope = scope.$new(true);
|
6492
6535
|
|
6493
6536
|
if (templateDirective && (templateDirective === newIsolateScopeDirective ||
|
6494
6537
|
templateDirective === newIsolateScopeDirective.$$originalDirective)) {
|
6495
|
-
$
|
6538
|
+
$element.data('$isolateScope', isolateScope);
|
6496
6539
|
} else {
|
6497
|
-
$
|
6540
|
+
$element.data('$isolateScopeNoTemplate', isolateScope);
|
6498
6541
|
}
|
6499
6542
|
|
6500
6543
|
|
6501
6544
|
|
6502
|
-
safeAddClass($
|
6545
|
+
safeAddClass($element, 'ng-isolate-scope');
|
6503
6546
|
|
6504
6547
|
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
|
6505
6548
|
var match = definition.match(LOCAL_REGEXP) || [],
|
@@ -7201,7 +7244,7 @@ function $ControllerProvider() {
|
|
7201
7244
|
instance = $injector.instantiate(expression, locals);
|
7202
7245
|
|
7203
7246
|
if (identifier) {
|
7204
|
-
if (!(locals && typeof locals.$scope
|
7247
|
+
if (!(locals && typeof locals.$scope === 'object')) {
|
7205
7248
|
throw minErr('$controller')('noscp',
|
7206
7249
|
"Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
|
7207
7250
|
constructor || expression.name, identifier);
|
@@ -7224,18 +7267,19 @@ function $ControllerProvider() {
|
|
7224
7267
|
* A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
|
7225
7268
|
*
|
7226
7269
|
* @example
|
7227
|
-
<example>
|
7270
|
+
<example module="documentExample">
|
7228
7271
|
<file name="index.html">
|
7229
|
-
<div ng-controller="
|
7272
|
+
<div ng-controller="ExampleController">
|
7230
7273
|
<p>$document title: <b ng-bind="title"></b></p>
|
7231
7274
|
<p>window.document title: <b ng-bind="windowTitle"></b></p>
|
7232
7275
|
</div>
|
7233
7276
|
</file>
|
7234
7277
|
<file name="script.js">
|
7235
|
-
|
7236
|
-
$scope
|
7237
|
-
|
7238
|
-
|
7278
|
+
angular.module('documentExample', [])
|
7279
|
+
.controller('ExampleController', ['$scope', '$document', function($scope, $document) {
|
7280
|
+
$scope.title = $document[0].title;
|
7281
|
+
$scope.windowTitle = angular.element(window.document)[0].title;
|
7282
|
+
}]);
|
7239
7283
|
</file>
|
7240
7284
|
</example>
|
7241
7285
|
*/
|
@@ -7302,11 +7346,7 @@ function parseHeaders(headers) {
|
|
7302
7346
|
val = trim(line.substr(i + 1));
|
7303
7347
|
|
7304
7348
|
if (key) {
|
7305
|
-
|
7306
|
-
parsed[key] += ', ' + val;
|
7307
|
-
} else {
|
7308
|
-
parsed[key] = val;
|
7309
|
-
}
|
7349
|
+
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
|
7310
7350
|
}
|
7311
7351
|
});
|
7312
7352
|
|
@@ -7368,12 +7408,39 @@ function isSuccess(status) {
|
|
7368
7408
|
}
|
7369
7409
|
|
7370
7410
|
|
7411
|
+
/**
|
7412
|
+
* @ngdoc provider
|
7413
|
+
* @name $httpProvider
|
7414
|
+
* @description
|
7415
|
+
* Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
|
7416
|
+
* */
|
7371
7417
|
function $HttpProvider() {
|
7372
7418
|
var JSON_START = /^\s*(\[|\{[^\{])/,
|
7373
7419
|
JSON_END = /[\}\]]\s*$/,
|
7374
7420
|
PROTECTION_PREFIX = /^\)\]\}',?\n/,
|
7375
7421
|
CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
|
7376
7422
|
|
7423
|
+
/**
|
7424
|
+
* @ngdoc property
|
7425
|
+
* @name $httpProvider#defaults
|
7426
|
+
* @description
|
7427
|
+
*
|
7428
|
+
* Object containing default values for all {@link ng.$http $http} requests.
|
7429
|
+
*
|
7430
|
+
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
|
7431
|
+
* Defaults value is `'XSRF-TOKEN'`.
|
7432
|
+
*
|
7433
|
+
* - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
|
7434
|
+
* XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
|
7435
|
+
*
|
7436
|
+
* - **`defaults.headers`** - {Object} - Default headers for all $http requests.
|
7437
|
+
* Refer to {@link ng.$http#setting-http-headers $http} for documentation on
|
7438
|
+
* setting default headers.
|
7439
|
+
* - **`defaults.headers.common`**
|
7440
|
+
* - **`defaults.headers.post`**
|
7441
|
+
* - **`defaults.headers.put`**
|
7442
|
+
* - **`defaults.headers.patch`**
|
7443
|
+
**/
|
7377
7444
|
var defaults = this.defaults = {
|
7378
7445
|
// transform incoming response data
|
7379
7446
|
transformResponse: [function(data) {
|
@@ -7863,9 +7930,9 @@ function $HttpProvider() {
|
|
7863
7930
|
*
|
7864
7931
|
*
|
7865
7932
|
* @example
|
7866
|
-
<example>
|
7933
|
+
<example module="httpExample">
|
7867
7934
|
<file name="index.html">
|
7868
|
-
<div ng-controller="
|
7935
|
+
<div ng-controller="FetchController">
|
7869
7936
|
<select ng-model="method">
|
7870
7937
|
<option>GET</option>
|
7871
7938
|
<option>JSONP</option>
|
@@ -7887,30 +7954,32 @@ function $HttpProvider() {
|
|
7887
7954
|
</div>
|
7888
7955
|
</file>
|
7889
7956
|
<file name="script.js">
|
7890
|
-
|
7891
|
-
$scope
|
7892
|
-
|
7893
|
-
|
7894
|
-
|
7895
|
-
|
7896
|
-
|
7897
|
-
|
7898
|
-
|
7899
|
-
|
7900
|
-
$scope.
|
7901
|
-
|
7902
|
-
|
7903
|
-
|
7904
|
-
|
7905
|
-
|
7906
|
-
|
7907
|
-
|
7957
|
+
angular.module('httpExample', [])
|
7958
|
+
.controller('FetchController', ['$scope', '$http', '$templateCache',
|
7959
|
+
function($scope, $http, $templateCache) {
|
7960
|
+
$scope.method = 'GET';
|
7961
|
+
$scope.url = 'http-hello.html';
|
7962
|
+
|
7963
|
+
$scope.fetch = function() {
|
7964
|
+
$scope.code = null;
|
7965
|
+
$scope.response = null;
|
7966
|
+
|
7967
|
+
$http({method: $scope.method, url: $scope.url, cache: $templateCache}).
|
7968
|
+
success(function(data, status) {
|
7969
|
+
$scope.status = status;
|
7970
|
+
$scope.data = data;
|
7971
|
+
}).
|
7972
|
+
error(function(data, status) {
|
7973
|
+
$scope.data = data || "Request failed";
|
7974
|
+
$scope.status = status;
|
7975
|
+
});
|
7976
|
+
};
|
7908
7977
|
|
7909
|
-
|
7910
|
-
|
7911
|
-
|
7912
|
-
|
7913
|
-
|
7978
|
+
$scope.updateModel = function(method, url) {
|
7979
|
+
$scope.method = method;
|
7980
|
+
$scope.url = url;
|
7981
|
+
};
|
7982
|
+
}]);
|
7914
7983
|
</file>
|
7915
7984
|
<file name="http-hello.html">
|
7916
7985
|
Hello, $http!
|
@@ -7964,7 +8033,7 @@ function $HttpProvider() {
|
|
7964
8033
|
var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
|
7965
8034
|
|
7966
8035
|
// strip content-type if data is undefined
|
7967
|
-
if (isUndefined(
|
8036
|
+
if (isUndefined(reqData)) {
|
7968
8037
|
forEach(headers, function(value, header) {
|
7969
8038
|
if (lowercase(header) === 'content-type') {
|
7970
8039
|
delete headers[header];
|
@@ -8033,10 +8102,6 @@ function $HttpProvider() {
|
|
8033
8102
|
|
8034
8103
|
defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
|
8035
8104
|
|
8036
|
-
// execute if header value is function
|
8037
|
-
execHeaders(defHeaders);
|
8038
|
-
execHeaders(reqHeaders);
|
8039
|
-
|
8040
8105
|
// using for-in instead of forEach to avoid unecessary iteration after header has been found
|
8041
8106
|
defaultHeadersIteration:
|
8042
8107
|
for (defHeaderName in defHeaders) {
|
@@ -8051,6 +8116,8 @@ function $HttpProvider() {
|
|
8051
8116
|
reqHeaders[defHeaderName] = defHeaders[defHeaderName];
|
8052
8117
|
}
|
8053
8118
|
|
8119
|
+
// execute if header value is a function for merged headers
|
8120
|
+
execHeaders(reqHeaders);
|
8054
8121
|
return reqHeaders;
|
8055
8122
|
|
8056
8123
|
function execHeaders(headers) {
|
@@ -8116,7 +8183,7 @@ function $HttpProvider() {
|
|
8116
8183
|
* Shortcut method to perform `JSONP` request.
|
8117
8184
|
*
|
8118
8185
|
* @param {string} url Relative or absolute URL specifying the destination of the request.
|
8119
|
-
*
|
8186
|
+
* The name of the callback should be the string `JSON_CALLBACK`.
|
8120
8187
|
* @param {Object=} config Optional configuration object
|
8121
8188
|
* @returns {HttpPromise} Future object
|
8122
8189
|
*/
|
@@ -8216,7 +8283,7 @@ function $HttpProvider() {
|
|
8216
8283
|
if (cache) {
|
8217
8284
|
cachedResp = cache.get(url);
|
8218
8285
|
if (isDefined(cachedResp)) {
|
8219
|
-
if (cachedResp
|
8286
|
+
if (isPromiseLike(cachedResp)) {
|
8220
8287
|
// cached request has already been sent, but there is no response yet
|
8221
8288
|
cachedResp.then(removePendingReq, removePendingReq);
|
8222
8289
|
return cachedResp;
|
@@ -8298,27 +8365,29 @@ function $HttpProvider() {
|
|
8298
8365
|
|
8299
8366
|
|
8300
8367
|
function buildUrl(url, params) {
|
8301
|
-
|
8302
|
-
|
8303
|
-
|
8304
|
-
|
8305
|
-
|
8306
|
-
|
8307
|
-
|
8308
|
-
|
8309
|
-
|
8310
|
-
|
8311
|
-
|
8312
|
-
|
8313
|
-
}
|
8314
|
-
});
|
8315
|
-
if(parts.length > 0) {
|
8316
|
-
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
|
8368
|
+
if (!params) return url;
|
8369
|
+
var parts = [];
|
8370
|
+
forEachSorted(params, function(value, key) {
|
8371
|
+
if (value === null || isUndefined(value)) return;
|
8372
|
+
if (!isArray(value)) value = [value];
|
8373
|
+
|
8374
|
+
forEach(value, function(v) {
|
8375
|
+
if (isObject(v)) {
|
8376
|
+
if (isDate(v)){
|
8377
|
+
v = v.toISOString();
|
8378
|
+
} else if (isObject(v)) {
|
8379
|
+
v = toJson(v);
|
8380
|
+
}
|
8317
8381
|
}
|
8318
|
-
|
8319
|
-
|
8320
|
-
|
8321
|
-
|
8382
|
+
parts.push(encodeUriQuery(key) + '=' +
|
8383
|
+
encodeUriQuery(v));
|
8384
|
+
});
|
8385
|
+
});
|
8386
|
+
if(parts.length > 0) {
|
8387
|
+
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
|
8388
|
+
}
|
8389
|
+
return url;
|
8390
|
+
}
|
8322
8391
|
}];
|
8323
8392
|
}
|
8324
8393
|
|
@@ -8403,7 +8472,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
8403
8472
|
// Safari respectively.
|
8404
8473
|
if (xhr && xhr.readyState == 4) {
|
8405
8474
|
var responseHeaders = null,
|
8406
|
-
response = null
|
8475
|
+
response = null,
|
8476
|
+
statusText = '';
|
8407
8477
|
|
8408
8478
|
if(status !== ABORTED) {
|
8409
8479
|
responseHeaders = xhr.getAllResponseHeaders();
|
@@ -8413,11 +8483,17 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
8413
8483
|
response = ('response' in xhr) ? xhr.response : xhr.responseText;
|
8414
8484
|
}
|
8415
8485
|
|
8486
|
+
// Accessing statusText on an aborted xhr object will
|
8487
|
+
// throw an 'c00c023f error' in IE9 and lower, don't touch it.
|
8488
|
+
if (!(status === ABORTED && msie < 10)) {
|
8489
|
+
statusText = xhr.statusText;
|
8490
|
+
}
|
8491
|
+
|
8416
8492
|
completeRequest(callback,
|
8417
8493
|
status || xhr.status,
|
8418
8494
|
response,
|
8419
8495
|
responseHeaders,
|
8420
|
-
|
8496
|
+
statusText);
|
8421
8497
|
}
|
8422
8498
|
};
|
8423
8499
|
|
@@ -8447,7 +8523,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
|
|
8447
8523
|
|
8448
8524
|
if (timeout > 0) {
|
8449
8525
|
var timeoutId = $browserDefer(timeoutRequest, timeout);
|
8450
|
-
} else if (timeout
|
8526
|
+
} else if (isPromiseLike(timeout)) {
|
8451
8527
|
timeout.then(timeoutRequest);
|
8452
8528
|
}
|
8453
8529
|
|
@@ -8819,25 +8895,27 @@ function $IntervalProvider() {
|
|
8819
8895
|
* @returns {promise} A promise which will be notified on each iteration.
|
8820
8896
|
*
|
8821
8897
|
* @example
|
8822
|
-
* <example module="
|
8823
|
-
*
|
8824
|
-
*
|
8825
|
-
*
|
8826
|
-
*
|
8827
|
-
* $scope
|
8828
|
-
*
|
8898
|
+
* <example module="intervalExample">
|
8899
|
+
* <file name="index.html">
|
8900
|
+
* <script>
|
8901
|
+
* angular.module('intervalExample', [])
|
8902
|
+
* .controller('ExampleController', ['$scope', '$interval',
|
8903
|
+
* function($scope, $interval) {
|
8904
|
+
* $scope.format = 'M/d/yy h:mm:ss a';
|
8905
|
+
* $scope.blood_1 = 100;
|
8906
|
+
* $scope.blood_2 = 120;
|
8829
8907
|
*
|
8830
|
-
*
|
8831
|
-
*
|
8832
|
-
*
|
8833
|
-
*
|
8908
|
+
* var stop;
|
8909
|
+
* $scope.fight = function() {
|
8910
|
+
* // Don't start a new fight if we are already fighting
|
8911
|
+
* if ( angular.isDefined(stop) ) return;
|
8834
8912
|
*
|
8835
8913
|
* stop = $interval(function() {
|
8836
8914
|
* if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
8837
|
-
*
|
8838
|
-
*
|
8915
|
+
* $scope.blood_1 = $scope.blood_1 - 3;
|
8916
|
+
* $scope.blood_2 = $scope.blood_2 - 4;
|
8839
8917
|
* } else {
|
8840
|
-
*
|
8918
|
+
* $scope.stopFight();
|
8841
8919
|
* }
|
8842
8920
|
* }, 100);
|
8843
8921
|
* };
|
@@ -8852,22 +8930,21 @@ function $IntervalProvider() {
|
|
8852
8930
|
* $scope.resetFight = function() {
|
8853
8931
|
* $scope.blood_1 = 100;
|
8854
8932
|
* $scope.blood_2 = 120;
|
8855
|
-
* }
|
8933
|
+
* };
|
8856
8934
|
*
|
8857
8935
|
* $scope.$on('$destroy', function() {
|
8858
|
-
* // Make sure that the interval
|
8936
|
+
* // Make sure that the interval nis destroyed too
|
8859
8937
|
* $scope.stopFight();
|
8860
8938
|
* });
|
8861
|
-
* }
|
8862
|
-
*
|
8863
|
-
*
|
8864
|
-
*
|
8865
|
-
*
|
8866
|
-
* .directive('myCurrentTime', function($interval, dateFilter) {
|
8939
|
+
* }])
|
8940
|
+
* // Register the 'myCurrentTime' directive factory method.
|
8941
|
+
* // We inject $interval and dateFilter service since the factory method is DI.
|
8942
|
+
* .directive('myCurrentTime', ['$interval', 'dateFilter',
|
8943
|
+
* function($interval, dateFilter) {
|
8867
8944
|
* // return the directive link function. (compile function not needed)
|
8868
8945
|
* return function(scope, element, attrs) {
|
8869
8946
|
* var format, // date format
|
8870
|
-
*
|
8947
|
+
* stopTime; // so that we can cancel the time updates
|
8871
8948
|
*
|
8872
8949
|
* // used to update the UI
|
8873
8950
|
* function updateTime() {
|
@@ -8883,28 +8960,28 @@ function $IntervalProvider() {
|
|
8883
8960
|
* stopTime = $interval(updateTime, 1000);
|
8884
8961
|
*
|
8885
8962
|
* // listen on DOM destroy (removal) event, and cancel the next UI update
|
8886
|
-
* // to prevent updating time
|
8963
|
+
* // to prevent updating time after the DOM element was removed.
|
8887
8964
|
* element.bind('$destroy', function() {
|
8888
8965
|
* $interval.cancel(stopTime);
|
8889
8966
|
* });
|
8890
8967
|
* }
|
8891
|
-
* });
|
8892
|
-
*
|
8968
|
+
* }]);
|
8969
|
+
* </script>
|
8893
8970
|
*
|
8894
|
-
*
|
8895
|
-
*
|
8896
|
-
*
|
8897
|
-
*
|
8898
|
-
*
|
8899
|
-
*
|
8900
|
-
*
|
8901
|
-
*
|
8902
|
-
*
|
8903
|
-
*
|
8904
|
-
* </div>
|
8971
|
+
* <div>
|
8972
|
+
* <div ng-controller="ExampleController">
|
8973
|
+
* Date format: <input ng-model="format"> <hr/>
|
8974
|
+
* Current time is: <span my-current-time="format"></span>
|
8975
|
+
* <hr/>
|
8976
|
+
* Blood 1 : <font color='red'>{{blood_1}}</font>
|
8977
|
+
* Blood 2 : <font color='red'>{{blood_2}}</font>
|
8978
|
+
* <button type="button" data-ng-click="fight()">Fight</button>
|
8979
|
+
* <button type="button" data-ng-click="stopFight()">StopFight</button>
|
8980
|
+
* <button type="button" data-ng-click="resetFight()">resetFight</button>
|
8905
8981
|
* </div>
|
8982
|
+
* </div>
|
8906
8983
|
*
|
8907
|
-
*
|
8984
|
+
* </file>
|
8908
8985
|
* </example>
|
8909
8986
|
*/
|
8910
8987
|
function interval(fn, delay, count, invokeApply) {
|
@@ -8951,7 +9028,7 @@ function $IntervalProvider() {
|
|
8951
9028
|
interval.cancel = function(promise) {
|
8952
9029
|
if (promise && promise.$$intervalId in intervals) {
|
8953
9030
|
intervals[promise.$$intervalId].reject('canceled');
|
8954
|
-
clearInterval(promise.$$intervalId);
|
9031
|
+
$window.clearInterval(promise.$$intervalId);
|
8955
9032
|
delete intervals[promise.$$intervalId];
|
8956
9033
|
return true;
|
8957
9034
|
}
|
@@ -9461,14 +9538,17 @@ LocationHashbangInHtml5Url.prototype =
|
|
9461
9538
|
* If the argument is a hash object containing an array of values, these values will be encoded
|
9462
9539
|
* as duplicate search parameters in the url.
|
9463
9540
|
*
|
9464
|
-
* @param {(string|Array<string
|
9465
|
-
* override only a single search property.
|
9541
|
+
* @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
|
9542
|
+
* will override only a single search property.
|
9466
9543
|
*
|
9467
9544
|
* If `paramValue` is an array, it will override the property of the `search` component of
|
9468
9545
|
* `$location` specified via the first argument.
|
9469
9546
|
*
|
9470
9547
|
* If `paramValue` is `null`, the property specified via the first argument will be deleted.
|
9471
9548
|
*
|
9549
|
+
* If `paramValue` is `true`, the property specified via the first argument will be added with no
|
9550
|
+
* value nor trailing equal sign.
|
9551
|
+
*
|
9472
9552
|
* @return {Object} If called with no arguments returns the parsed `search` object. If called with
|
9473
9553
|
* one or more arguments returns `$location` object itself.
|
9474
9554
|
*/
|
@@ -9480,6 +9560,11 @@ LocationHashbangInHtml5Url.prototype =
|
|
9480
9560
|
if (isString(search)) {
|
9481
9561
|
this.$$search = parseKeyValue(search);
|
9482
9562
|
} else if (isObject(search)) {
|
9563
|
+
// remove object undefined or null properties
|
9564
|
+
forEach(search, function(value, key) {
|
9565
|
+
if (value == null) delete search[key];
|
9566
|
+
});
|
9567
|
+
|
9483
9568
|
this.$$search = search;
|
9484
9569
|
} else {
|
9485
9570
|
throw $locationMinErr('isrcharg',
|
@@ -9585,7 +9670,7 @@ function $LocationProvider(){
|
|
9585
9670
|
html5Mode = false;
|
9586
9671
|
|
9587
9672
|
/**
|
9588
|
-
* @ngdoc
|
9673
|
+
* @ngdoc method
|
9589
9674
|
* @name $locationProvider#hashPrefix
|
9590
9675
|
* @description
|
9591
9676
|
* @param {string=} prefix Prefix for hash part (containing path and search)
|
@@ -9601,7 +9686,7 @@ function $LocationProvider(){
|
|
9601
9686
|
};
|
9602
9687
|
|
9603
9688
|
/**
|
9604
|
-
* @ngdoc
|
9689
|
+
* @ngdoc method
|
9605
9690
|
* @name $locationProvider#html5Mode
|
9606
9691
|
* @description
|
9607
9692
|
* @param {boolean=} mode Use HTML5 strategy if available.
|
@@ -9801,15 +9886,16 @@ function $LocationProvider(){
|
|
9801
9886
|
* {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
|
9802
9887
|
*
|
9803
9888
|
* @example
|
9804
|
-
<example>
|
9889
|
+
<example module="logExample">
|
9805
9890
|
<file name="script.js">
|
9806
|
-
|
9807
|
-
$scope
|
9808
|
-
|
9809
|
-
|
9891
|
+
angular.module('logExample', [])
|
9892
|
+
.controller('LogController', ['$scope', '$log', function($scope, $log) {
|
9893
|
+
$scope.$log = $log;
|
9894
|
+
$scope.message = 'Hello World!';
|
9895
|
+
}]);
|
9810
9896
|
</file>
|
9811
9897
|
<file name="index.html">
|
9812
|
-
<div ng-controller="
|
9898
|
+
<div ng-controller="LogController">
|
9813
9899
|
<p>Reload this page with open console, enter text and hit the log button...</p>
|
9814
9900
|
Message:
|
9815
9901
|
<input type="text" ng-model="message"/>
|
@@ -9833,7 +9919,7 @@ function $LogProvider(){
|
|
9833
9919
|
self = this;
|
9834
9920
|
|
9835
9921
|
/**
|
9836
|
-
* @ngdoc
|
9922
|
+
* @ngdoc method
|
9837
9923
|
* @name $logProvider#debugEnabled
|
9838
9924
|
* @description
|
9839
9925
|
* @param {boolean=} flag enable or disable debug level messages
|
@@ -9959,14 +10045,7 @@ var promiseWarning;
|
|
9959
10045
|
//
|
9960
10046
|
// As an example, consider the following Angular expression:
|
9961
10047
|
//
|
9962
|
-
// {}.toString.constructor(alert("evil JS code"))
|
9963
|
-
//
|
9964
|
-
// We want to prevent this type of access. For the sake of performance, during the lexing phase we
|
9965
|
-
// disallow any "dotted" access to any member named "constructor".
|
9966
|
-
//
|
9967
|
-
// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
|
9968
|
-
// while evaluating the expression, which is a stronger but more expensive test. Since reflective
|
9969
|
-
// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
|
10048
|
+
// {}.toString.constructor('alert("evil JS code")')
|
9970
10049
|
//
|
9971
10050
|
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
|
9972
10051
|
// against the expression language, but not to prevent exploits that were enabled by exposing
|
@@ -9974,17 +10053,19 @@ var promiseWarning;
|
|
9974
10053
|
// practice and therefore we are not even trying to protect against interaction with an object
|
9975
10054
|
// explicitly exposed in this way.
|
9976
10055
|
//
|
9977
|
-
// A developer could foil the name check by aliasing the Function constructor under a different
|
9978
|
-
// name on the scope.
|
9979
|
-
//
|
9980
10056
|
// In general, it is not possible to access a Window object from an angular expression unless a
|
9981
10057
|
// window or some DOM object that has a reference to window is published onto a Scope.
|
10058
|
+
// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
|
10059
|
+
// native objects.
|
10060
|
+
|
9982
10061
|
|
9983
10062
|
function ensureSafeMemberName(name, fullExpression) {
|
9984
|
-
if (name === "
|
10063
|
+
if (name === "__defineGetter__" || name === "__defineSetter__"
|
10064
|
+
|| name === "__lookupGetter__" || name === "__lookupSetter__"
|
10065
|
+
|| name === "__proto__") {
|
9985
10066
|
throw $parseMinErr('isecfld',
|
9986
|
-
'
|
9987
|
-
fullExpression);
|
10067
|
+
'Attempting to access a disallowed field in Angular expressions! '
|
10068
|
+
+'Expression: {0}', fullExpression);
|
9988
10069
|
}
|
9989
10070
|
return name;
|
9990
10071
|
}
|
@@ -10006,11 +10087,34 @@ function ensureSafeObject(obj, fullExpression) {
|
|
10006
10087
|
throw $parseMinErr('isecdom',
|
10007
10088
|
'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
|
10008
10089
|
fullExpression);
|
10090
|
+
} else if (// block Object so that we can't get hold of dangerous Object.* methods
|
10091
|
+
obj === Object) {
|
10092
|
+
throw $parseMinErr('isecobj',
|
10093
|
+
'Referencing Object in Angular expressions is disallowed! Expression: {0}',
|
10094
|
+
fullExpression);
|
10009
10095
|
}
|
10010
10096
|
}
|
10011
10097
|
return obj;
|
10012
10098
|
}
|
10013
10099
|
|
10100
|
+
var CALL = Function.prototype.call;
|
10101
|
+
var APPLY = Function.prototype.apply;
|
10102
|
+
var BIND = Function.prototype.bind;
|
10103
|
+
|
10104
|
+
function ensureSafeFunction(obj, fullExpression) {
|
10105
|
+
if (obj) {
|
10106
|
+
if (obj.constructor === obj) {
|
10107
|
+
throw $parseMinErr('isecfn',
|
10108
|
+
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
10109
|
+
fullExpression);
|
10110
|
+
} else if (obj === CALL || obj === APPLY || (BIND && obj === BIND)) {
|
10111
|
+
throw $parseMinErr('isecff',
|
10112
|
+
'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
|
10113
|
+
fullExpression);
|
10114
|
+
}
|
10115
|
+
}
|
10116
|
+
}
|
10117
|
+
|
10014
10118
|
var OPERATORS = {
|
10015
10119
|
/* jshint bitwise : false */
|
10016
10120
|
'null':function(){return null;},
|
@@ -10290,11 +10394,7 @@ Lexer.prototype = {
|
|
10290
10394
|
string += String.fromCharCode(parseInt(hex, 16));
|
10291
10395
|
} else {
|
10292
10396
|
var rep = ESCAPE[ch];
|
10293
|
-
|
10294
|
-
string += rep;
|
10295
|
-
} else {
|
10296
|
-
string += ch;
|
10297
|
-
}
|
10397
|
+
string = string + (rep || ch);
|
10298
10398
|
}
|
10299
10399
|
escape = false;
|
10300
10400
|
} else if (ch === '\\') {
|
@@ -10645,6 +10745,7 @@ Parser.prototype = {
|
|
10645
10745
|
i = indexFn(self, locals),
|
10646
10746
|
v, p;
|
10647
10747
|
|
10748
|
+
ensureSafeMemberName(i, parser.text);
|
10648
10749
|
if (!o) return undefined;
|
10649
10750
|
v = ensureSafeObject(o[i], parser.text);
|
10650
10751
|
if (v && v.then && parser.options.unwrapPromises) {
|
@@ -10687,7 +10788,7 @@ Parser.prototype = {
|
|
10687
10788
|
var fnPtr = fn(scope, locals, context) || noop;
|
10688
10789
|
|
10689
10790
|
ensureSafeObject(context, parser.text);
|
10690
|
-
|
10791
|
+
ensureSafeFunction(fnPtr, parser.text);
|
10691
10792
|
|
10692
10793
|
// IE stupidity! (IE doesn't have apply for some native functions)
|
10693
10794
|
var v = fnPtr.apply
|
@@ -10796,6 +10897,8 @@ function setter(obj, path, setValue, fullExp, options) {
|
|
10796
10897
|
}
|
10797
10898
|
}
|
10798
10899
|
key = ensureSafeMemberName(element.shift(), fullExp);
|
10900
|
+
ensureSafeObject(obj, fullExp);
|
10901
|
+
ensureSafeObject(obj[key], fullExp);
|
10799
10902
|
obj[key] = setValue;
|
10800
10903
|
return setValue;
|
10801
10904
|
}
|
@@ -10911,26 +11014,6 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
|
10911
11014
|
};
|
10912
11015
|
}
|
10913
11016
|
|
10914
|
-
function simpleGetterFn1(key0, fullExp) {
|
10915
|
-
ensureSafeMemberName(key0, fullExp);
|
10916
|
-
|
10917
|
-
return function simpleGetterFn1(scope, locals) {
|
10918
|
-
if (scope == null) return undefined;
|
10919
|
-
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
10920
|
-
};
|
10921
|
-
}
|
10922
|
-
|
10923
|
-
function simpleGetterFn2(key0, key1, fullExp) {
|
10924
|
-
ensureSafeMemberName(key0, fullExp);
|
10925
|
-
ensureSafeMemberName(key1, fullExp);
|
10926
|
-
|
10927
|
-
return function simpleGetterFn2(scope, locals) {
|
10928
|
-
if (scope == null) return undefined;
|
10929
|
-
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
10930
|
-
return scope == null ? undefined : scope[key1];
|
10931
|
-
};
|
10932
|
-
}
|
10933
|
-
|
10934
11017
|
function getterFn(path, options, fullExp) {
|
10935
11018
|
// Check whether the cache has this getter already.
|
10936
11019
|
// We can use hasOwnProperty directly on the cache because we ensure,
|
@@ -10943,13 +11026,8 @@ function getterFn(path, options, fullExp) {
|
|
10943
11026
|
pathKeysLength = pathKeys.length,
|
10944
11027
|
fn;
|
10945
11028
|
|
10946
|
-
// When we have only 1 or 2 tokens, use optimized special case closures.
|
10947
11029
|
// http://jsperf.com/angularjs-parse-getter/6
|
10948
|
-
if (
|
10949
|
-
fn = simpleGetterFn1(pathKeys[0], fullExp);
|
10950
|
-
} else if (!options.unwrapPromises && pathKeysLength === 2) {
|
10951
|
-
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
|
10952
|
-
} else if (options.csp) {
|
11030
|
+
if (options.csp) {
|
10953
11031
|
if (pathKeysLength < 6) {
|
10954
11032
|
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
10955
11033
|
options);
|
@@ -11215,17 +11293,13 @@ function $ParseProvider() {
|
|
11215
11293
|
* var deferred = $q.defer();
|
11216
11294
|
*
|
11217
11295
|
* setTimeout(function() {
|
11218
|
-
*
|
11219
|
-
*
|
11220
|
-
*
|
11221
|
-
* deferred.
|
11222
|
-
*
|
11223
|
-
*
|
11224
|
-
*
|
11225
|
-
* } else {
|
11226
|
-
* deferred.reject('Greeting ' + name + ' is not allowed.');
|
11227
|
-
* }
|
11228
|
-
* });
|
11296
|
+
* deferred.notify('About to greet ' + name + '.');
|
11297
|
+
*
|
11298
|
+
* if (okToGreet(name)) {
|
11299
|
+
* deferred.resolve('Hello, ' + name + '!');
|
11300
|
+
* } else {
|
11301
|
+
* deferred.reject('Greeting ' + name + ' is not allowed.');
|
11302
|
+
* }
|
11229
11303
|
* }, 1000);
|
11230
11304
|
*
|
11231
11305
|
* return deferred.promise;
|
@@ -11499,7 +11573,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
11499
11573
|
} catch(e) {
|
11500
11574
|
return makePromise(e, false);
|
11501
11575
|
}
|
11502
|
-
if (
|
11576
|
+
if (isPromiseLike(callbackOutput)) {
|
11503
11577
|
return callbackOutput.then(function() {
|
11504
11578
|
return makePromise(value, isResolved);
|
11505
11579
|
}, function(error) {
|
@@ -11524,7 +11598,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
11524
11598
|
|
11525
11599
|
|
11526
11600
|
var ref = function(value) {
|
11527
|
-
if (
|
11601
|
+
if (isPromiseLike(value)) return value;
|
11528
11602
|
return {
|
11529
11603
|
then: function(callback) {
|
11530
11604
|
var result = defer();
|
@@ -12191,7 +12265,7 @@ function $RootScopeProvider(){
|
|
12191
12265
|
|
12192
12266
|
function $watchCollectionWatch() {
|
12193
12267
|
newValue = objGetter(self);
|
12194
|
-
var newLength, key;
|
12268
|
+
var newLength, key, bothNaN;
|
12195
12269
|
|
12196
12270
|
if (!isObject(newValue)) { // if primitive
|
12197
12271
|
if (oldValue !== newValue) {
|
@@ -12215,7 +12289,7 @@ function $RootScopeProvider(){
|
|
12215
12289
|
}
|
12216
12290
|
// copy the items to oldValue and look for changes.
|
12217
12291
|
for (var i = 0; i < newLength; i++) {
|
12218
|
-
|
12292
|
+
bothNaN = (oldValue[i] !== oldValue[i]) &&
|
12219
12293
|
(newValue[i] !== newValue[i]);
|
12220
12294
|
if (!bothNaN && (oldValue[i] !== newValue[i])) {
|
12221
12295
|
changeDetected++;
|
@@ -12235,7 +12309,9 @@ function $RootScopeProvider(){
|
|
12235
12309
|
if (newValue.hasOwnProperty(key)) {
|
12236
12310
|
newLength++;
|
12237
12311
|
if (oldValue.hasOwnProperty(key)) {
|
12238
|
-
|
12312
|
+
bothNaN = (oldValue[key] !== oldValue[key]) &&
|
12313
|
+
(newValue[key] !== newValue[key]);
|
12314
|
+
if (!bothNaN && (oldValue[key] !== newValue[key])) {
|
12239
12315
|
changeDetected++;
|
12240
12316
|
oldValue[key] = newValue[key];
|
12241
12317
|
}
|
@@ -12387,7 +12463,7 @@ function $RootScopeProvider(){
|
|
12387
12463
|
if ((value = watch.get(current)) !== (last = watch.last) &&
|
12388
12464
|
!(watch.eq
|
12389
12465
|
? equals(value, last)
|
12390
|
-
: (typeof value
|
12466
|
+
: (typeof value === 'number' && typeof last === 'number'
|
12391
12467
|
&& isNaN(value) && isNaN(last)))) {
|
12392
12468
|
dirty = true;
|
12393
12469
|
lastDirtyWatch = watch;
|
@@ -13080,19 +13156,21 @@ function adjustMatchers(matchers) {
|
|
13080
13156
|
*
|
13081
13157
|
* Here is what a secure configuration for this scenario might look like:
|
13082
13158
|
*
|
13083
|
-
*
|
13084
|
-
*
|
13085
|
-
*
|
13086
|
-
*
|
13087
|
-
*
|
13088
|
-
*
|
13089
|
-
*
|
13090
|
-
*
|
13091
|
-
*
|
13092
|
-
*
|
13093
|
-
*
|
13094
|
-
*
|
13095
|
-
*
|
13159
|
+
* ```
|
13160
|
+
* angular.module('myApp', []).config(function($sceDelegateProvider) {
|
13161
|
+
* $sceDelegateProvider.resourceUrlWhitelist([
|
13162
|
+
* // Allow same origin resource loads.
|
13163
|
+
* 'self',
|
13164
|
+
* // Allow loading from our assets domain. Notice the difference between * and **.
|
13165
|
+
* 'http://srv*.assets.example.com/**'
|
13166
|
+
* ]);
|
13167
|
+
*
|
13168
|
+
* // The blacklist overrides the whitelist so the open redirect here is blocked.
|
13169
|
+
* $sceDelegateProvider.resourceUrlBlacklist([
|
13170
|
+
* 'http://myapp.example.com/clickThru**'
|
13171
|
+
* ]);
|
13172
|
+
* });
|
13173
|
+
* ```
|
13096
13174
|
*/
|
13097
13175
|
|
13098
13176
|
function $SceDelegateProvider() {
|
@@ -13387,10 +13465,10 @@ function $SceDelegateProvider() {
|
|
13387
13465
|
*
|
13388
13466
|
* Here's an example of a binding in a privileged context:
|
13389
13467
|
*
|
13390
|
-
*
|
13391
|
-
*
|
13392
|
-
*
|
13393
|
-
*
|
13468
|
+
* ```
|
13469
|
+
* <input ng-model="userHtml">
|
13470
|
+
* <div ng-bind-html="userHtml"></div>
|
13471
|
+
* ```
|
13394
13472
|
*
|
13395
13473
|
* Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
|
13396
13474
|
* disabled, this application allows the user to render arbitrary HTML into the DIV.
|
@@ -13430,15 +13508,15 @@ function $SceDelegateProvider() {
|
|
13430
13508
|
* ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
|
13431
13509
|
* simplified):
|
13432
13510
|
*
|
13433
|
-
*
|
13434
|
-
*
|
13435
|
-
*
|
13436
|
-
*
|
13437
|
-
*
|
13438
|
-
*
|
13439
|
-
*
|
13440
|
-
*
|
13441
|
-
*
|
13511
|
+
* ```
|
13512
|
+
* var ngBindHtmlDirective = ['$sce', function($sce) {
|
13513
|
+
* return function(scope, element, attr) {
|
13514
|
+
* scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
|
13515
|
+
* element.html(value || '');
|
13516
|
+
* });
|
13517
|
+
* };
|
13518
|
+
* }];
|
13519
|
+
* ```
|
13442
13520
|
*
|
13443
13521
|
* ## Impact on loading templates
|
13444
13522
|
*
|
@@ -13542,66 +13620,65 @@ function $SceDelegateProvider() {
|
|
13542
13620
|
*
|
13543
13621
|
* ## Show me an example using SCE.
|
13544
13622
|
*
|
13545
|
-
*
|
13546
|
-
<
|
13547
|
-
<
|
13548
|
-
|
13549
|
-
|
13550
|
-
|
13551
|
-
|
13552
|
-
|
13553
|
-
|
13554
|
-
|
13555
|
-
|
13556
|
-
|
13557
|
-
|
13558
|
-
|
13559
|
-
|
13560
|
-
|
13561
|
-
|
13562
|
-
|
13563
|
-
|
13564
|
-
|
13565
|
-
|
13566
|
-
|
13567
|
-
|
13568
|
-
|
13569
|
-
|
13570
|
-
|
13571
|
-
|
13572
|
-
|
13573
|
-
|
13574
|
-
|
13575
|
-
|
13576
|
-
|
13577
|
-
|
13578
|
-
|
13579
|
-
|
13580
|
-
|
13581
|
-
|
13582
|
-
|
13583
|
-
|
13584
|
-
|
13585
|
-
|
13586
|
-
|
13587
|
-
|
13588
|
-
|
13589
|
-
|
13590
|
-
|
13591
|
-
|
13592
|
-
|
13593
|
-
|
13594
|
-
|
13595
|
-
|
13596
|
-
|
13597
|
-
|
13598
|
-
|
13599
|
-
|
13600
|
-
|
13601
|
-
|
13602
|
-
|
13603
|
-
</
|
13604
|
-
</example>
|
13623
|
+
* <example module="mySceApp" deps="angular-sanitize.js">
|
13624
|
+
* <file name="index.html">
|
13625
|
+
* <div ng-controller="myAppController as myCtrl">
|
13626
|
+
* <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
|
13627
|
+
* <b>User comments</b><br>
|
13628
|
+
* By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
|
13629
|
+
* $sanitize is available. If $sanitize isn't available, this results in an error instead of an
|
13630
|
+
* exploit.
|
13631
|
+
* <div class="well">
|
13632
|
+
* <div ng-repeat="userComment in myCtrl.userComments">
|
13633
|
+
* <b>{{userComment.name}}</b>:
|
13634
|
+
* <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
|
13635
|
+
* <br>
|
13636
|
+
* </div>
|
13637
|
+
* </div>
|
13638
|
+
* </div>
|
13639
|
+
* </file>
|
13640
|
+
*
|
13641
|
+
* <file name="script.js">
|
13642
|
+
* var mySceApp = angular.module('mySceApp', ['ngSanitize']);
|
13643
|
+
*
|
13644
|
+
* mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
|
13645
|
+
* var self = this;
|
13646
|
+
* $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
|
13647
|
+
* self.userComments = userComments;
|
13648
|
+
* });
|
13649
|
+
* self.explicitlyTrustedHtml = $sce.trustAsHtml(
|
13650
|
+
* '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
|
13651
|
+
* 'sanitization."">Hover over this text.</span>');
|
13652
|
+
* });
|
13653
|
+
* </file>
|
13654
|
+
*
|
13655
|
+
* <file name="test_data.json">
|
13656
|
+
* [
|
13657
|
+
* { "name": "Alice",
|
13658
|
+
* "htmlComment":
|
13659
|
+
* "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
|
13660
|
+
* },
|
13661
|
+
* { "name": "Bob",
|
13662
|
+
* "htmlComment": "<i>Yes!</i> Am I the only other one?"
|
13663
|
+
* }
|
13664
|
+
* ]
|
13665
|
+
* </file>
|
13666
|
+
*
|
13667
|
+
* <file name="protractor.js" type="protractor">
|
13668
|
+
* describe('SCE doc demo', function() {
|
13669
|
+
* it('should sanitize untrusted values', function() {
|
13670
|
+
* expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
|
13671
|
+
* .toBe('<span>Is <i>anyone</i> reading this?</span>');
|
13672
|
+
* });
|
13673
|
+
*
|
13674
|
+
* it('should NOT sanitize explicitly trusted values', function() {
|
13675
|
+
* expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
|
13676
|
+
* '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
|
13677
|
+
* 'sanitization."">Hover over this text.</span>');
|
13678
|
+
* });
|
13679
|
+
* });
|
13680
|
+
* </file>
|
13681
|
+
* </example>
|
13605
13682
|
*
|
13606
13683
|
*
|
13607
13684
|
*
|
@@ -13615,13 +13692,13 @@ function $SceDelegateProvider() {
|
|
13615
13692
|
*
|
13616
13693
|
* That said, here's how you can completely disable SCE:
|
13617
13694
|
*
|
13618
|
-
*
|
13619
|
-
*
|
13620
|
-
*
|
13621
|
-
*
|
13622
|
-
*
|
13623
|
-
*
|
13624
|
-
*
|
13695
|
+
* ```
|
13696
|
+
* angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
|
13697
|
+
* // Completely disable SCE. For demonstration purposes only!
|
13698
|
+
* // Do not use in new projects.
|
13699
|
+
* $sceProvider.enabled(false);
|
13700
|
+
* });
|
13701
|
+
* ```
|
13625
13702
|
*
|
13626
13703
|
*/
|
13627
13704
|
/* jshint maxlen: 100 */
|
@@ -13732,7 +13809,7 @@ function $SceProvider() {
|
|
13732
13809
|
|
13733
13810
|
/**
|
13734
13811
|
* @ngdoc method
|
13735
|
-
* @name $sce#
|
13812
|
+
* @name $sce#parseAs
|
13736
13813
|
*
|
13737
13814
|
* @description
|
13738
13815
|
* Converts Angular {@link guide/expression expression} into a function. This is like {@link
|
@@ -14318,17 +14395,18 @@ function urlIsSameOrigin(requestUrl) {
|
|
14318
14395
|
* expression.
|
14319
14396
|
*
|
14320
14397
|
* @example
|
14321
|
-
<example>
|
14398
|
+
<example module="windowExample">
|
14322
14399
|
<file name="index.html">
|
14323
14400
|
<script>
|
14324
|
-
|
14325
|
-
$scope
|
14326
|
-
|
14401
|
+
angular.module('windowExample', [])
|
14402
|
+
.controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
|
14403
|
+
$scope.greeting = 'Hello, World!';
|
14404
|
+
$scope.doGreeting = function(greeting) {
|
14327
14405
|
$window.alert(greeting);
|
14328
|
-
|
14329
|
-
|
14406
|
+
};
|
14407
|
+
}]);
|
14330
14408
|
</script>
|
14331
|
-
<div ng-controller="
|
14409
|
+
<div ng-controller="ExampleController">
|
14332
14410
|
<input type="text" ng-model="greeting" />
|
14333
14411
|
<button ng-click="doGreeting(greeting)">ALERT</button>
|
14334
14412
|
</div>
|
@@ -14346,6 +14424,17 @@ function $WindowProvider(){
|
|
14346
14424
|
this.$get = valueFn(window);
|
14347
14425
|
}
|
14348
14426
|
|
14427
|
+
/* global currencyFilter: true,
|
14428
|
+
dateFilter: true,
|
14429
|
+
filterFilter: true,
|
14430
|
+
jsonFilter: true,
|
14431
|
+
limitToFilter: true,
|
14432
|
+
lowercaseFilter: true,
|
14433
|
+
numberFilter: true,
|
14434
|
+
orderByFilter: true,
|
14435
|
+
uppercaseFilter: true,
|
14436
|
+
*/
|
14437
|
+
|
14349
14438
|
/**
|
14350
14439
|
* @ngdoc provider
|
14351
14440
|
* @name $filterProvider
|
@@ -14688,7 +14777,7 @@ function filterFilter() {
|
|
14688
14777
|
// jshint +W086
|
14689
14778
|
for (var key in expression) {
|
14690
14779
|
(function(path) {
|
14691
|
-
if (typeof expression[path]
|
14780
|
+
if (typeof expression[path] === 'undefined') return;
|
14692
14781
|
predicates.push(function(value) {
|
14693
14782
|
return search(path == '$' ? value : (value && value[path]), expression[path]);
|
14694
14783
|
});
|
@@ -14727,14 +14816,15 @@ function filterFilter() {
|
|
14727
14816
|
*
|
14728
14817
|
*
|
14729
14818
|
* @example
|
14730
|
-
<example>
|
14819
|
+
<example module="currencyExample">
|
14731
14820
|
<file name="index.html">
|
14732
14821
|
<script>
|
14733
|
-
|
14734
|
-
$scope
|
14735
|
-
|
14822
|
+
angular.module('currencyExample', [])
|
14823
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
14824
|
+
$scope.amount = 1234.56;
|
14825
|
+
}]);
|
14736
14826
|
</script>
|
14737
|
-
<div ng-controller="
|
14827
|
+
<div ng-controller="ExampleController">
|
14738
14828
|
<input type="number" ng-model="amount"> <br>
|
14739
14829
|
default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
|
14740
14830
|
custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
|
@@ -14786,14 +14876,15 @@ function currencyFilter($locale) {
|
|
14786
14876
|
* @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
|
14787
14877
|
*
|
14788
14878
|
* @example
|
14789
|
-
<example>
|
14879
|
+
<example module="numberFilterExample">
|
14790
14880
|
<file name="index.html">
|
14791
14881
|
<script>
|
14792
|
-
|
14793
|
-
$scope
|
14794
|
-
|
14882
|
+
angular.module('numberFilterExample', [])
|
14883
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
14884
|
+
$scope.val = 1234.56789;
|
14885
|
+
}]);
|
14795
14886
|
</script>
|
14796
|
-
<div ng-controller="
|
14887
|
+
<div ng-controller="ExampleController">
|
14797
14888
|
Enter number: <input ng-model='val'><br>
|
14798
14889
|
Default formatting: <span id='number-default'>{{val | number}}</span><br>
|
14799
14890
|
No fractions: <span>{{val | number:0}}</span><br>
|
@@ -14843,6 +14934,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
|
14843
14934
|
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
|
14844
14935
|
if (match && match[2] == '-' && match[3] > fractionSize + 1) {
|
14845
14936
|
numStr = '0';
|
14937
|
+
number = 0;
|
14846
14938
|
} else {
|
14847
14939
|
formatedText = numStr;
|
14848
14940
|
hasExponent = true;
|
@@ -14857,8 +14949,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
|
14857
14949
|
fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
|
14858
14950
|
}
|
14859
14951
|
|
14860
|
-
|
14861
|
-
|
14952
|
+
// safely round numbers in JS without hitting imprecisions of floating-point arithmetics
|
14953
|
+
// inspired by:
|
14954
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
|
14955
|
+
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
|
14956
|
+
|
14862
14957
|
var fraction = ('' + number).split(DECIMAL_SEP);
|
14863
14958
|
var whole = fraction[0];
|
14864
14959
|
fraction = fraction[1] || '';
|
@@ -15101,11 +15196,7 @@ function dateFilter($locale) {
|
|
15101
15196
|
format = format || 'mediumDate';
|
15102
15197
|
format = $locale.DATETIME_FORMATS[format] || format;
|
15103
15198
|
if (isString(date)) {
|
15104
|
-
|
15105
|
-
date = int(date);
|
15106
|
-
} else {
|
15107
|
-
date = jsonStringToDate(date);
|
15108
|
-
}
|
15199
|
+
date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
|
15109
15200
|
}
|
15110
15201
|
|
15111
15202
|
if (isNumber(date)) {
|
@@ -15213,17 +15304,18 @@ var uppercaseFilter = valueFn(uppercase);
|
|
15213
15304
|
* had less than `limit` elements.
|
15214
15305
|
*
|
15215
15306
|
* @example
|
15216
|
-
<example>
|
15307
|
+
<example module="limitToExample">
|
15217
15308
|
<file name="index.html">
|
15218
15309
|
<script>
|
15219
|
-
|
15220
|
-
$scope
|
15221
|
-
|
15222
|
-
|
15223
|
-
|
15224
|
-
|
15310
|
+
angular.module('limitToExample', [])
|
15311
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
15312
|
+
$scope.numbers = [1,2,3,4,5,6,7,8,9];
|
15313
|
+
$scope.letters = "abcdefghi";
|
15314
|
+
$scope.numLimit = 3;
|
15315
|
+
$scope.letterLimit = 3;
|
15316
|
+
}]);
|
15225
15317
|
</script>
|
15226
|
-
<div ng-controller="
|
15318
|
+
<div ng-controller="ExampleController">
|
15227
15319
|
Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
|
15228
15320
|
<p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
|
15229
15321
|
Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
|
@@ -15335,20 +15427,21 @@ function limitToFilter(){
|
|
15335
15427
|
* @returns {Array} Sorted copy of the source array.
|
15336
15428
|
*
|
15337
15429
|
* @example
|
15338
|
-
<example>
|
15430
|
+
<example module="orderByExample">
|
15339
15431
|
<file name="index.html">
|
15340
15432
|
<script>
|
15341
|
-
|
15342
|
-
$scope
|
15343
|
-
|
15344
|
-
|
15345
|
-
|
15346
|
-
|
15347
|
-
|
15348
|
-
|
15349
|
-
|
15433
|
+
angular.module('orderByExample', [])
|
15434
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
15435
|
+
$scope.friends =
|
15436
|
+
[{name:'John', phone:'555-1212', age:10},
|
15437
|
+
{name:'Mary', phone:'555-9876', age:19},
|
15438
|
+
{name:'Mike', phone:'555-4321', age:21},
|
15439
|
+
{name:'Adam', phone:'555-5678', age:35},
|
15440
|
+
{name:'Julie', phone:'555-8765', age:29}];
|
15441
|
+
$scope.predicate = '-age';
|
15442
|
+
}]);
|
15350
15443
|
</script>
|
15351
|
-
<div ng-controller="
|
15444
|
+
<div ng-controller="ExampleController">
|
15352
15445
|
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
|
15353
15446
|
<hr/>
|
15354
15447
|
[ <a href="" ng-click="predicate=''">unsorted</a> ]
|
@@ -15376,9 +15469,9 @@ function limitToFilter(){
|
|
15376
15469
|
* Example:
|
15377
15470
|
*
|
15378
15471
|
* @example
|
15379
|
-
<example>
|
15472
|
+
<example module="orderByExample">
|
15380
15473
|
<file name="index.html">
|
15381
|
-
<div ng-controller="
|
15474
|
+
<div ng-controller="ExampleController">
|
15382
15475
|
<table class="friend">
|
15383
15476
|
<tr>
|
15384
15477
|
<th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
|
@@ -15396,21 +15489,21 @@ function limitToFilter(){
|
|
15396
15489
|
</file>
|
15397
15490
|
|
15398
15491
|
<file name="script.js">
|
15399
|
-
|
15400
|
-
|
15401
|
-
|
15402
|
-
|
15403
|
-
|
15404
|
-
|
15405
|
-
|
15406
|
-
|
15407
|
-
|
15408
|
-
|
15409
|
-
|
15410
|
-
|
15411
|
-
|
15412
|
-
|
15413
|
-
|
15492
|
+
angular.module('orderByExample', [])
|
15493
|
+
.controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
|
15494
|
+
var orderBy = $filter('orderBy');
|
15495
|
+
$scope.friends = [
|
15496
|
+
{ name: 'John', phone: '555-1212', age: 10 },
|
15497
|
+
{ name: 'Mary', phone: '555-9876', age: 19 },
|
15498
|
+
{ name: 'Mike', phone: '555-4321', age: 21 },
|
15499
|
+
{ name: 'Adam', phone: '555-5678', age: 35 },
|
15500
|
+
{ name: 'Julie', phone: '555-8765', age: 29 }
|
15501
|
+
];
|
15502
|
+
$scope.order = function(predicate, reverse) {
|
15503
|
+
$scope.friends = orderBy($scope.friends, predicate, reverse);
|
15504
|
+
};
|
15505
|
+
$scope.order('-age',false);
|
15506
|
+
}]);
|
15414
15507
|
</file>
|
15415
15508
|
</example>
|
15416
15509
|
*/
|
@@ -15459,6 +15552,10 @@ function orderByFilter($parse){
|
|
15459
15552
|
var t1 = typeof v1;
|
15460
15553
|
var t2 = typeof v2;
|
15461
15554
|
if (t1 == t2) {
|
15555
|
+
if (isDate(v1) && isDate(v2)) {
|
15556
|
+
v1 = v1.valueOf();
|
15557
|
+
v2 = v2.valueOf();
|
15558
|
+
}
|
15462
15559
|
if (t1 == "string") {
|
15463
15560
|
v1 = v1.toLowerCase();
|
15464
15561
|
v2 = v2.toLowerCase();
|
@@ -15596,7 +15693,7 @@ var htmlAnchorDirective = valueFn({
|
|
15596
15693
|
return browser.driver.getCurrentUrl().then(function(url) {
|
15597
15694
|
return url.match(/\/123$/);
|
15598
15695
|
});
|
15599
|
-
},
|
15696
|
+
}, 5000, 'page should navigate to /123');
|
15600
15697
|
});
|
15601
15698
|
|
15602
15699
|
xit('should execute ng-click but not reload when href empty string and name specified', function() {
|
@@ -15624,7 +15721,7 @@ var htmlAnchorDirective = valueFn({
|
|
15624
15721
|
return browser.driver.getCurrentUrl().then(function(url) {
|
15625
15722
|
return url.match(/\/6$/);
|
15626
15723
|
});
|
15627
|
-
},
|
15724
|
+
}, 5000, 'page should navigate to /6');
|
15628
15725
|
});
|
15629
15726
|
</file>
|
15630
15727
|
</example>
|
@@ -16240,12 +16337,13 @@ function FormController(element, attrs, $scope, $animate) {
|
|
16240
16337
|
* </pre>
|
16241
16338
|
*
|
16242
16339
|
* @example
|
16243
|
-
<example deps="angular-animate.js" animations="true" fixBase="true">
|
16340
|
+
<example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
|
16244
16341
|
<file name="index.html">
|
16245
16342
|
<script>
|
16246
|
-
|
16247
|
-
$scope
|
16248
|
-
|
16343
|
+
angular.module('formExample', [])
|
16344
|
+
.controller('FormController', ['$scope', function($scope) {
|
16345
|
+
$scope.userType = 'guest';
|
16346
|
+
}]);
|
16249
16347
|
</script>
|
16250
16348
|
<style>
|
16251
16349
|
.my-form {
|
@@ -16257,7 +16355,7 @@ function FormController(element, attrs, $scope, $animate) {
|
|
16257
16355
|
background: red;
|
16258
16356
|
}
|
16259
16357
|
</style>
|
16260
|
-
<form name="myForm" ng-controller="
|
16358
|
+
<form name="myForm" ng-controller="FormController" class="my-form">
|
16261
16359
|
userType: <input name="input" ng-model="userType" required>
|
16262
16360
|
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
|
16263
16361
|
<tt>userType = {{userType}}</tt><br>
|
@@ -16351,16 +16449,14 @@ var formDirectiveFactory = function(isNgForm) {
|
|
16351
16449
|
var formDirective = formDirectiveFactory();
|
16352
16450
|
var ngFormDirective = formDirectiveFactory(true);
|
16353
16451
|
|
16354
|
-
/* global
|
16355
|
-
|
16356
|
-
|
16357
|
-
|
16358
|
-
-PRISTINE_CLASS,
|
16359
|
-
-DIRTY_CLASS
|
16452
|
+
/* global VALID_CLASS: true,
|
16453
|
+
INVALID_CLASS: true,
|
16454
|
+
PRISTINE_CLASS: true,
|
16455
|
+
DIRTY_CLASS: true
|
16360
16456
|
*/
|
16361
16457
|
|
16362
16458
|
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
|
16363
|
-
var EMAIL_REGEXP = /^[a-z0-9!#$%&'
|
16459
|
+
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
16364
16460
|
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
|
16365
16461
|
|
16366
16462
|
var inputType = {
|
@@ -16390,15 +16486,16 @@ var inputType = {
|
|
16390
16486
|
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
|
16391
16487
|
*
|
16392
16488
|
* @example
|
16393
|
-
<example name="text-input-directive">
|
16489
|
+
<example name="text-input-directive" module="textInputExample">
|
16394
16490
|
<file name="index.html">
|
16395
16491
|
<script>
|
16396
|
-
|
16397
|
-
$scope
|
16398
|
-
|
16399
|
-
|
16492
|
+
angular.module('textInputExample', [])
|
16493
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16494
|
+
$scope.text = 'guest';
|
16495
|
+
$scope.word = /^\s*\w*\s*$/;
|
16496
|
+
}]);
|
16400
16497
|
</script>
|
16401
|
-
<form name="myForm" ng-controller="
|
16498
|
+
<form name="myForm" ng-controller="ExampleController">
|
16402
16499
|
Single word: <input type="text" name="input" ng-model="text"
|
16403
16500
|
ng-pattern="word" required ng-trim="false">
|
16404
16501
|
<span class="error" ng-show="myForm.input.$error.required">
|
@@ -16470,14 +16567,15 @@ var inputType = {
|
|
16470
16567
|
* interaction with the input element.
|
16471
16568
|
*
|
16472
16569
|
* @example
|
16473
|
-
<example name="number-input-directive">
|
16570
|
+
<example name="number-input-directive" module="numberExample">
|
16474
16571
|
<file name="index.html">
|
16475
16572
|
<script>
|
16476
|
-
|
16477
|
-
$scope
|
16478
|
-
|
16573
|
+
angular.module('numberExample', [])
|
16574
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16575
|
+
$scope.value = 12;
|
16576
|
+
}]);
|
16479
16577
|
</script>
|
16480
|
-
<form name="myForm" ng-controller="
|
16578
|
+
<form name="myForm" ng-controller="ExampleController">
|
16481
16579
|
Number: <input type="number" name="input" ng-model="value"
|
16482
16580
|
min="0" max="99" required>
|
16483
16581
|
<span class="error" ng-show="myForm.input.$error.required">
|
@@ -16545,14 +16643,15 @@ var inputType = {
|
|
16545
16643
|
* interaction with the input element.
|
16546
16644
|
*
|
16547
16645
|
* @example
|
16548
|
-
<example name="url-input-directive">
|
16646
|
+
<example name="url-input-directive" module="urlExample">
|
16549
16647
|
<file name="index.html">
|
16550
16648
|
<script>
|
16551
|
-
|
16552
|
-
$scope
|
16553
|
-
|
16649
|
+
angular.module('urlExample', [])
|
16650
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16651
|
+
$scope.text = 'http://google.com';
|
16652
|
+
}]);
|
16554
16653
|
</script>
|
16555
|
-
<form name="myForm" ng-controller="
|
16654
|
+
<form name="myForm" ng-controller="ExampleController">
|
16556
16655
|
URL: <input type="url" name="input" ng-model="text" required>
|
16557
16656
|
<span class="error" ng-show="myForm.input.$error.required">
|
16558
16657
|
Required!</span>
|
@@ -16621,14 +16720,15 @@ var inputType = {
|
|
16621
16720
|
* interaction with the input element.
|
16622
16721
|
*
|
16623
16722
|
* @example
|
16624
|
-
<example name="email-input-directive">
|
16723
|
+
<example name="email-input-directive" module="emailExample">
|
16625
16724
|
<file name="index.html">
|
16626
16725
|
<script>
|
16627
|
-
|
16628
|
-
$scope
|
16629
|
-
|
16726
|
+
angular.module('emailExample', [])
|
16727
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16728
|
+
$scope.text = 'me@example.com';
|
16729
|
+
}]);
|
16630
16730
|
</script>
|
16631
|
-
<form name="myForm" ng-controller="
|
16731
|
+
<form name="myForm" ng-controller="ExampleController">
|
16632
16732
|
Email: <input type="email" name="input" ng-model="text" required>
|
16633
16733
|
<span class="error" ng-show="myForm.input.$error.required">
|
16634
16734
|
Required!</span>
|
@@ -16687,18 +16787,19 @@ var inputType = {
|
|
16687
16787
|
* be set when selected.
|
16688
16788
|
*
|
16689
16789
|
* @example
|
16690
|
-
<example name="radio-input-directive">
|
16790
|
+
<example name="radio-input-directive" module="radioExample">
|
16691
16791
|
<file name="index.html">
|
16692
16792
|
<script>
|
16693
|
-
|
16694
|
-
$scope
|
16695
|
-
|
16696
|
-
|
16697
|
-
|
16698
|
-
|
16699
|
-
|
16793
|
+
angular.module('radioExample', [])
|
16794
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16795
|
+
$scope.color = 'blue';
|
16796
|
+
$scope.specialValue = {
|
16797
|
+
"id": "12345",
|
16798
|
+
"value": "green"
|
16799
|
+
};
|
16800
|
+
}]);
|
16700
16801
|
</script>
|
16701
|
-
<form name="myForm" ng-controller="
|
16802
|
+
<form name="myForm" ng-controller="ExampleController">
|
16702
16803
|
<input type="radio" ng-model="color" value="red"> Red <br/>
|
16703
16804
|
<input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
|
16704
16805
|
<input type="radio" ng-model="color" value="blue"> Blue <br/>
|
@@ -16737,15 +16838,16 @@ var inputType = {
|
|
16737
16838
|
* interaction with the input element.
|
16738
16839
|
*
|
16739
16840
|
* @example
|
16740
|
-
<example name="checkbox-input-directive">
|
16841
|
+
<example name="checkbox-input-directive" module="checkboxExample">
|
16741
16842
|
<file name="index.html">
|
16742
16843
|
<script>
|
16743
|
-
|
16744
|
-
$scope
|
16745
|
-
|
16746
|
-
|
16844
|
+
angular.module('checkboxExample', [])
|
16845
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
16846
|
+
$scope.value1 = true;
|
16847
|
+
$scope.value2 = 'YES'
|
16848
|
+
}]);
|
16747
16849
|
</script>
|
16748
|
-
<form name="myForm" ng-controller="
|
16850
|
+
<form name="myForm" ng-controller="ExampleController">
|
16749
16851
|
Value1: <input type="checkbox" ng-model="value1"> <br/>
|
16750
16852
|
Value2: <input type="checkbox" ng-model="value2"
|
16751
16853
|
ng-true-value="YES" ng-false-value="NO"> <br/>
|
@@ -16786,15 +16888,29 @@ function validate(ctrl, validatorName, validity, value){
|
|
16786
16888
|
return validity ? value : undefined;
|
16787
16889
|
}
|
16788
16890
|
|
16891
|
+
function testFlags(validity, flags) {
|
16892
|
+
var i, flag;
|
16893
|
+
if (flags) {
|
16894
|
+
for (i=0; i<flags.length; ++i) {
|
16895
|
+
flag = flags[i];
|
16896
|
+
if (validity[flag]) {
|
16897
|
+
return true;
|
16898
|
+
}
|
16899
|
+
}
|
16900
|
+
}
|
16901
|
+
return false;
|
16902
|
+
}
|
16789
16903
|
|
16790
|
-
|
16791
|
-
|
16904
|
+
// Pass validity so that behaviour can be mocked easier.
|
16905
|
+
function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
|
16792
16906
|
if (isObject(validity)) {
|
16907
|
+
ctrl.$$hasNativeValidators = true;
|
16793
16908
|
var validator = function(value) {
|
16794
16909
|
// Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
|
16795
16910
|
// perform the required validation)
|
16796
|
-
if (!ctrl.$error[validatorName] &&
|
16797
|
-
validity
|
16911
|
+
if (!ctrl.$error[validatorName] &&
|
16912
|
+
!testFlags(validity, ignoreFlags) &&
|
16913
|
+
testFlags(validity, badFlags)) {
|
16798
16914
|
ctrl.$setValidity(validatorName, false);
|
16799
16915
|
return;
|
16800
16916
|
}
|
@@ -16805,8 +16921,9 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
|
|
16805
16921
|
}
|
16806
16922
|
|
16807
16923
|
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
16808
|
-
var validity = element.prop(
|
16924
|
+
var validity = element.prop(VALIDITY_STATE_PROPERTY);
|
16809
16925
|
var placeholder = element[0].placeholder, noevent = {};
|
16926
|
+
ctrl.$$validityState = validity;
|
16810
16927
|
|
16811
16928
|
// In composition mode, users are still inputing intermediate text buffer,
|
16812
16929
|
// hold the listener until composition is done.
|
@@ -16844,11 +16961,11 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
16844
16961
|
value = trim(value);
|
16845
16962
|
}
|
16846
16963
|
|
16847
|
-
|
16848
|
-
|
16849
|
-
|
16850
|
-
|
16851
|
-
|
16964
|
+
// If a control is suffering from bad input, browsers discard its value, so it may be
|
16965
|
+
// necessary to revalidate even if the control's value is the same empty value twice in
|
16966
|
+
// a row.
|
16967
|
+
var revalidate = validity && ctrl.$$hasNativeValidators;
|
16968
|
+
if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
|
16852
16969
|
if (scope.$$phase) {
|
16853
16970
|
ctrl.$setViewValue(value);
|
16854
16971
|
} else {
|
@@ -16954,6 +17071,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
16954
17071
|
}
|
16955
17072
|
}
|
16956
17073
|
|
17074
|
+
var numberBadFlags = ['badInput'];
|
17075
|
+
|
16957
17076
|
function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
16958
17077
|
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
16959
17078
|
|
@@ -16968,7 +17087,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
|
16968
17087
|
}
|
16969
17088
|
});
|
16970
17089
|
|
16971
|
-
addNativeHtml5Validators(ctrl, 'number',
|
17090
|
+
addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
|
16972
17091
|
|
16973
17092
|
ctrl.$formatters.push(function(value) {
|
16974
17093
|
return ctrl.$isEmpty(value) ? '' : '' + value;
|
@@ -17128,14 +17247,15 @@ function checkboxInputType(scope, element, attr, ctrl) {
|
|
17128
17247
|
* interaction with the input element.
|
17129
17248
|
*
|
17130
17249
|
* @example
|
17131
|
-
<example name="input-directive">
|
17250
|
+
<example name="input-directive" module="inputExample">
|
17132
17251
|
<file name="index.html">
|
17133
17252
|
<script>
|
17134
|
-
|
17135
|
-
|
17136
|
-
|
17253
|
+
angular.module('inputExample', [])
|
17254
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
17255
|
+
$scope.user = {name: 'guest', last: 'visitor'};
|
17256
|
+
}]);
|
17137
17257
|
</script>
|
17138
|
-
<div ng-controller="
|
17258
|
+
<div ng-controller="ExampleController">
|
17139
17259
|
<form name="myForm">
|
17140
17260
|
User name: <input type="text" name="userName" ng-model="user.name" required>
|
17141
17261
|
<span class="error" ng-show="myForm.userName.$error.required">
|
@@ -17450,7 +17570,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
17450
17570
|
* This method should be called by validators - i.e. the parser or formatter functions.
|
17451
17571
|
*
|
17452
17572
|
* @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
|
17453
|
-
* to `$error[validationErrorKey]
|
17573
|
+
* to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
|
17454
17574
|
* The `validationErrorKey` should be in camelCase and will get converted into dash-case
|
17455
17575
|
* for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
|
17456
17576
|
* class and can be bound to as `{{someForm.someControl.$error.myError}}` .
|
@@ -17653,12 +17773,13 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
17653
17773
|
* </pre>
|
17654
17774
|
*
|
17655
17775
|
* @example
|
17656
|
-
* <example deps="angular-animate.js" animations="true" fixBase="true">
|
17776
|
+
* <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
|
17657
17777
|
<file name="index.html">
|
17658
17778
|
<script>
|
17659
|
-
|
17660
|
-
$scope
|
17661
|
-
|
17779
|
+
angular.module('inputExample', [])
|
17780
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
17781
|
+
$scope.val = '1';
|
17782
|
+
}]);
|
17662
17783
|
</script>
|
17663
17784
|
<style>
|
17664
17785
|
.my-input {
|
@@ -17673,7 +17794,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
17673
17794
|
</style>
|
17674
17795
|
Update input to see transitions when valid/invalid.
|
17675
17796
|
Integer is a valid value.
|
17676
|
-
<form name="testForm" ng-controller="
|
17797
|
+
<form name="testForm" ng-controller="ExampleController">
|
17677
17798
|
<input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
|
17678
17799
|
</form>
|
17679
17800
|
</file>
|
@@ -17717,17 +17838,18 @@ var ngModelDirective = function() {
|
|
17717
17838
|
* in input value.
|
17718
17839
|
*
|
17719
17840
|
* @example
|
17720
|
-
* <example name="ngChange-directive">
|
17841
|
+
* <example name="ngChange-directive" module="changeExample">
|
17721
17842
|
* <file name="index.html">
|
17722
17843
|
* <script>
|
17723
|
-
*
|
17724
|
-
* $scope
|
17725
|
-
*
|
17726
|
-
* $scope.
|
17727
|
-
*
|
17728
|
-
*
|
17844
|
+
* angular.module('changeExample', [])
|
17845
|
+
* .controller('ExampleController', ['$scope', function($scope) {
|
17846
|
+
* $scope.counter = 0;
|
17847
|
+
* $scope.change = function() {
|
17848
|
+
* $scope.counter++;
|
17849
|
+
* };
|
17850
|
+
* }]);
|
17729
17851
|
* </script>
|
17730
|
-
* <div ng-controller="
|
17852
|
+
* <div ng-controller="ExampleController">
|
17731
17853
|
* <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
|
17732
17854
|
* <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
|
17733
17855
|
* <label for="ng-change-example2">Confirmed</label><br />
|
@@ -17808,14 +17930,15 @@ var requiredDirective = function() {
|
|
17808
17930
|
* specified in form `/something/` then the value will be converted into a regular expression.
|
17809
17931
|
*
|
17810
17932
|
* @example
|
17811
|
-
<example name="ngList-directive">
|
17933
|
+
<example name="ngList-directive" module="listExample">
|
17812
17934
|
<file name="index.html">
|
17813
17935
|
<script>
|
17814
|
-
|
17815
|
-
|
17816
|
-
|
17936
|
+
angular.module('listExample', [])
|
17937
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
17938
|
+
$scope.names = ['igor', 'misko', 'vojta'];
|
17939
|
+
}]);
|
17817
17940
|
</script>
|
17818
|
-
<form name="myForm" ng-controller="
|
17941
|
+
<form name="myForm" ng-controller="ExampleController">
|
17819
17942
|
List: <input name="namesInput" ng-model="names" ng-list required>
|
17820
17943
|
<span class="error" ng-show="myForm.namesInput.$error.required">
|
17821
17944
|
Required!</span>
|
@@ -17907,15 +18030,16 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
|
17907
18030
|
* of the `input` element
|
17908
18031
|
*
|
17909
18032
|
* @example
|
17910
|
-
<example name="ngValue-directive">
|
18033
|
+
<example name="ngValue-directive" module="valueExample">
|
17911
18034
|
<file name="index.html">
|
17912
18035
|
<script>
|
17913
|
-
|
17914
|
-
|
17915
|
-
|
17916
|
-
|
18036
|
+
angular.module('valueExample', [])
|
18037
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
18038
|
+
$scope.names = ['pizza', 'unicorns', 'robots'];
|
18039
|
+
$scope.my = { favorite: 'unicorns' };
|
18040
|
+
}]);
|
17917
18041
|
</script>
|
17918
|
-
<form ng-controller="
|
18042
|
+
<form ng-controller="ExampleController">
|
17919
18043
|
<h2>Which is your favorite?</h2>
|
17920
18044
|
<label ng-repeat="name in names" for="{{name}}">
|
17921
18045
|
{{name}}
|
@@ -17973,7 +18097,7 @@ var ngValueDirective = function() {
|
|
17973
18097
|
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
|
17974
18098
|
* `{{ expression }}` which is similar but less verbose.
|
17975
18099
|
*
|
17976
|
-
* It is preferable to use `ngBind` instead of `{{ expression }}`
|
18100
|
+
* It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
|
17977
18101
|
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
|
17978
18102
|
* element attribute, it makes the bindings invisible to the user while the page is loading.
|
17979
18103
|
*
|
@@ -17986,14 +18110,15 @@ var ngValueDirective = function() {
|
|
17986
18110
|
*
|
17987
18111
|
* @example
|
17988
18112
|
* Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
|
17989
|
-
<example>
|
18113
|
+
<example module="bindExample">
|
17990
18114
|
<file name="index.html">
|
17991
18115
|
<script>
|
17992
|
-
|
17993
|
-
$scope
|
17994
|
-
|
18116
|
+
angular.module('bindExample', [])
|
18117
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
18118
|
+
$scope.name = 'Whirled';
|
18119
|
+
}]);
|
17995
18120
|
</script>
|
17996
|
-
<div ng-controller="
|
18121
|
+
<div ng-controller="ExampleController">
|
17997
18122
|
Enter name: <input type="text" ng-model="name"><br>
|
17998
18123
|
Hello <span ng-bind="name"></span>!
|
17999
18124
|
</div>
|
@@ -18044,15 +18169,16 @@ var ngBindDirective = ngDirective({
|
|
18044
18169
|
*
|
18045
18170
|
* @example
|
18046
18171
|
* Try it here: enter text in text box and watch the greeting change.
|
18047
|
-
<example>
|
18172
|
+
<example module="bindExample">
|
18048
18173
|
<file name="index.html">
|
18049
18174
|
<script>
|
18050
|
-
|
18051
|
-
$scope
|
18052
|
-
|
18053
|
-
|
18175
|
+
angular.module('bindExample', [])
|
18176
|
+
.controller('ExampleController', ['$scope', function ($scope) {
|
18177
|
+
$scope.salutation = 'Hello';
|
18178
|
+
$scope.name = 'World';
|
18179
|
+
}]);
|
18054
18180
|
</script>
|
18055
|
-
<div ng-controller="
|
18181
|
+
<div ng-controller="ExampleController">
|
18056
18182
|
Salutation: <input type="text" ng-model="salutation"><br>
|
18057
18183
|
Name: <input type="text" ng-model="name"><br>
|
18058
18184
|
<pre ng-bind-template="{{salutation}} {{name}}!"></pre>
|
@@ -18110,20 +18236,20 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|
18110
18236
|
* @example
|
18111
18237
|
Try it here: enter text in text box and watch the greeting change.
|
18112
18238
|
|
18113
|
-
<example module="
|
18239
|
+
<example module="bindHtmlExample" deps="angular-sanitize.js">
|
18114
18240
|
<file name="index.html">
|
18115
|
-
<div ng-controller="
|
18241
|
+
<div ng-controller="ExampleController">
|
18116
18242
|
<p ng-bind-html="myHTML"></p>
|
18117
18243
|
</div>
|
18118
18244
|
</file>
|
18119
18245
|
|
18120
18246
|
<file name="script.js">
|
18121
|
-
angular.module('
|
18122
|
-
|
18123
|
-
|
18124
|
-
|
18125
|
-
|
18126
|
-
|
18247
|
+
angular.module('bindHtmlExample', ['ngSanitize'])
|
18248
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
18249
|
+
$scope.myHTML =
|
18250
|
+
'I am an <code>HTML</code>string with ' +
|
18251
|
+
'<a href="#">links!</a> and other <em>stuff</em>';
|
18252
|
+
}]);
|
18127
18253
|
</file>
|
18128
18254
|
|
18129
18255
|
<file name="protractor.js" type="protractor">
|
@@ -18135,15 +18261,24 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|
18135
18261
|
</example>
|
18136
18262
|
*/
|
18137
18263
|
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
|
18138
|
-
return
|
18139
|
-
|
18264
|
+
return {
|
18265
|
+
compile: function (tElement) {
|
18266
|
+
tElement.addClass('ng-binding');
|
18140
18267
|
|
18141
|
-
|
18142
|
-
|
18268
|
+
return function (scope, element, attr) {
|
18269
|
+
element.data('$binding', attr.ngBindHtml);
|
18143
18270
|
|
18144
|
-
|
18145
|
-
|
18146
|
-
|
18271
|
+
var parsed = $parse(attr.ngBindHtml);
|
18272
|
+
|
18273
|
+
function getStringValue() {
|
18274
|
+
return (parsed(scope) || '').toString();
|
18275
|
+
}
|
18276
|
+
|
18277
|
+
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
|
18278
|
+
element.html($sce.getTrustedHtml(parsed(scope)) || '');
|
18279
|
+
});
|
18280
|
+
};
|
18281
|
+
}
|
18147
18282
|
};
|
18148
18283
|
}];
|
18149
18284
|
|
@@ -18622,7 +18757,7 @@ var ngCloakDirective = ngDirective({
|
|
18622
18757
|
*
|
18623
18758
|
* This example demonstrates the `controller as` syntax.
|
18624
18759
|
*
|
18625
|
-
* <example name="ngControllerAs">
|
18760
|
+
* <example name="ngControllerAs" module="controllerAsExample">
|
18626
18761
|
* <file name="index.html">
|
18627
18762
|
* <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
|
18628
18763
|
* Name: <input type="text" ng-model="settings.name"/>
|
@@ -18643,6 +18778,9 @@ var ngCloakDirective = ngDirective({
|
|
18643
18778
|
* </div>
|
18644
18779
|
* </file>
|
18645
18780
|
* <file name="app.js">
|
18781
|
+
* angular.module('controllerAsExample', [])
|
18782
|
+
* .controller('SettingsController1', SettingsController1);
|
18783
|
+
*
|
18646
18784
|
* function SettingsController1() {
|
18647
18785
|
* this.name = "John Smith";
|
18648
18786
|
* this.contacts = [
|
@@ -18671,29 +18809,29 @@ var ngCloakDirective = ngDirective({
|
|
18671
18809
|
* <file name="protractor.js" type="protractor">
|
18672
18810
|
* it('should check controller as', function() {
|
18673
18811
|
* var container = element(by.id('ctrl-as-exmpl'));
|
18674
|
-
* expect(container.
|
18812
|
+
* expect(container.element(by.model('settings.name'))
|
18675
18813
|
* .getAttribute('value')).toBe('John Smith');
|
18676
18814
|
*
|
18677
18815
|
* var firstRepeat =
|
18678
|
-
* container.
|
18816
|
+
* container.element(by.repeater('contact in settings.contacts').row(0));
|
18679
18817
|
* var secondRepeat =
|
18680
|
-
* container.
|
18818
|
+
* container.element(by.repeater('contact in settings.contacts').row(1));
|
18681
18819
|
*
|
18682
|
-
* expect(firstRepeat.
|
18820
|
+
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18683
18821
|
* .toBe('408 555 1212');
|
18684
18822
|
*
|
18685
|
-
* expect(secondRepeat.
|
18823
|
+
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18686
18824
|
* .toBe('john.smith@example.org');
|
18687
18825
|
*
|
18688
|
-
* firstRepeat.
|
18826
|
+
* firstRepeat.element(by.linkText('clear')).click();
|
18689
18827
|
*
|
18690
|
-
* expect(firstRepeat.
|
18828
|
+
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18691
18829
|
* .toBe('');
|
18692
18830
|
*
|
18693
|
-
* container.
|
18831
|
+
* container.element(by.linkText('add')).click();
|
18694
18832
|
*
|
18695
|
-
* expect(container.
|
18696
|
-
* .
|
18833
|
+
* expect(container.element(by.repeater('contact in settings.contacts').row(2))
|
18834
|
+
* .element(by.model('contact.value'))
|
18697
18835
|
* .getAttribute('value'))
|
18698
18836
|
* .toBe('yourname@example.org');
|
18699
18837
|
* });
|
@@ -18702,7 +18840,7 @@ var ngCloakDirective = ngDirective({
|
|
18702
18840
|
*
|
18703
18841
|
* This example demonstrates the "attach to `$scope`" style of controller.
|
18704
18842
|
*
|
18705
|
-
* <example name="ngController">
|
18843
|
+
* <example name="ngController" module="controllerExample">
|
18706
18844
|
* <file name="index.html">
|
18707
18845
|
* <div id="ctrl-exmpl" ng-controller="SettingsController2">
|
18708
18846
|
* Name: <input type="text" ng-model="name"/>
|
@@ -18723,6 +18861,9 @@ var ngCloakDirective = ngDirective({
|
|
18723
18861
|
* </div>
|
18724
18862
|
* </file>
|
18725
18863
|
* <file name="app.js">
|
18864
|
+
* angular.module('controllerExample', [])
|
18865
|
+
* .controller('SettingsController2', ['$scope', SettingsController2]);
|
18866
|
+
*
|
18726
18867
|
* function SettingsController2($scope) {
|
18727
18868
|
* $scope.name = "John Smith";
|
18728
18869
|
* $scope.contacts = [
|
@@ -18752,28 +18893,28 @@ var ngCloakDirective = ngDirective({
|
|
18752
18893
|
* it('should check controller', function() {
|
18753
18894
|
* var container = element(by.id('ctrl-exmpl'));
|
18754
18895
|
*
|
18755
|
-
* expect(container.
|
18896
|
+
* expect(container.element(by.model('name'))
|
18756
18897
|
* .getAttribute('value')).toBe('John Smith');
|
18757
18898
|
*
|
18758
18899
|
* var firstRepeat =
|
18759
|
-
* container.
|
18900
|
+
* container.element(by.repeater('contact in contacts').row(0));
|
18760
18901
|
* var secondRepeat =
|
18761
|
-
* container.
|
18902
|
+
* container.element(by.repeater('contact in contacts').row(1));
|
18762
18903
|
*
|
18763
|
-
* expect(firstRepeat.
|
18904
|
+
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18764
18905
|
* .toBe('408 555 1212');
|
18765
|
-
* expect(secondRepeat.
|
18906
|
+
* expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18766
18907
|
* .toBe('john.smith@example.org');
|
18767
18908
|
*
|
18768
|
-
* firstRepeat.
|
18909
|
+
* firstRepeat.element(by.linkText('clear')).click();
|
18769
18910
|
*
|
18770
|
-
* expect(firstRepeat.
|
18911
|
+
* expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
|
18771
18912
|
* .toBe('');
|
18772
18913
|
*
|
18773
|
-
* container.
|
18914
|
+
* container.element(by.linkText('add')).click();
|
18774
18915
|
*
|
18775
|
-
* expect(container.
|
18776
|
-
* .
|
18916
|
+
* expect(container.element(by.repeater('contact in contacts').row(2))
|
18917
|
+
* .element(by.model('contact.value'))
|
18777
18918
|
* .getAttribute('value'))
|
18778
18919
|
* .toBe('yourname@example.org');
|
18779
18920
|
* });
|
@@ -18800,8 +18941,10 @@ var ngControllerDirective = [function() {
|
|
18800
18941
|
* This is necessary when developing things like Google Chrome Extensions.
|
18801
18942
|
*
|
18802
18943
|
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
|
18803
|
-
* For
|
18804
|
-
*
|
18944
|
+
* For Angular to be CSP compatible there are only two things that we need to do differently:
|
18945
|
+
*
|
18946
|
+
* - don't use `Function` constructor to generate optimized value getters
|
18947
|
+
* - don't inject custom stylesheet into the document
|
18805
18948
|
*
|
18806
18949
|
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
|
18807
18950
|
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
|
@@ -18812,7 +18955,18 @@ var ngControllerDirective = [function() {
|
|
18812
18955
|
* includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
|
18813
18956
|
* To make those directives work in CSP mode, include the `angular-csp.css` manually.
|
18814
18957
|
*
|
18815
|
-
*
|
18958
|
+
* Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
|
18959
|
+
* autodetection however triggers a CSP error to be logged in the console:
|
18960
|
+
*
|
18961
|
+
* ```
|
18962
|
+
* Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
|
18963
|
+
* script in the following Content Security Policy directive: "default-src 'self'". Note that
|
18964
|
+
* 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
|
18965
|
+
* ```
|
18966
|
+
*
|
18967
|
+
* This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
|
18968
|
+
* directive on the root element of the application or on the `angular.js` script tag, whichever
|
18969
|
+
* appears first in the html document.
|
18816
18970
|
*
|
18817
18971
|
* *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
|
18818
18972
|
*
|
@@ -18827,9 +18981,9 @@ var ngControllerDirective = [function() {
|
|
18827
18981
|
```
|
18828
18982
|
*/
|
18829
18983
|
|
18830
|
-
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
|
18831
|
-
// the system (before $parse is instantiated), for this reason we just have
|
18832
|
-
// anywhere in the current doc
|
18984
|
+
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
|
18985
|
+
// bootstrap the system (before $parse is instantiated), for this reason we just have
|
18986
|
+
// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
|
18833
18987
|
|
18834
18988
|
/**
|
18835
18989
|
* @ngdoc directive
|
@@ -19144,21 +19298,22 @@ forEach(
|
|
19144
19298
|
* ({@link guide/expression#-event- Event object is available as `$event`})
|
19145
19299
|
*
|
19146
19300
|
* @example
|
19147
|
-
<example>
|
19301
|
+
<example module="submitExample">
|
19148
19302
|
<file name="index.html">
|
19149
19303
|
<script>
|
19150
|
-
|
19151
|
-
$scope
|
19152
|
-
|
19153
|
-
|
19154
|
-
|
19155
|
-
$scope.
|
19156
|
-
|
19157
|
-
|
19158
|
-
|
19159
|
-
|
19304
|
+
angular.module('submitExample', [])
|
19305
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
19306
|
+
$scope.list = [];
|
19307
|
+
$scope.text = 'hello';
|
19308
|
+
$scope.submit = function() {
|
19309
|
+
if ($scope.text) {
|
19310
|
+
$scope.list.push(this.text);
|
19311
|
+
$scope.text = '';
|
19312
|
+
}
|
19313
|
+
};
|
19314
|
+
}]);
|
19160
19315
|
</script>
|
19161
|
-
<form ng-submit="submit()" ng-controller="
|
19316
|
+
<form ng-submit="submit()" ng-controller="ExampleController">
|
19162
19317
|
Enter text and hit enter:
|
19163
19318
|
<input type="text" ng-model="text" name="text" />
|
19164
19319
|
<input type="submit" id="submit" value="Submit" />
|
@@ -19170,7 +19325,7 @@ forEach(
|
|
19170
19325
|
expect(element(by.binding('list')).getText()).toBe('list=[]');
|
19171
19326
|
element(by.css('#submit')).click();
|
19172
19327
|
expect(element(by.binding('list')).getText()).toContain('hello');
|
19173
|
-
expect(element(by.
|
19328
|
+
expect(element(by.model('text')).getAttribute('value')).toBe('');
|
19174
19329
|
});
|
19175
19330
|
it('should ignore empty strings', function() {
|
19176
19331
|
expect(element(by.binding('list')).getText()).toBe('list=[]');
|
@@ -19443,9 +19598,9 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
19443
19598
|
* - Otherwise enable scrolling only if the expression evaluates to truthy value.
|
19444
19599
|
*
|
19445
19600
|
* @example
|
19446
|
-
<example module="
|
19601
|
+
<example module="includeExample" deps="angular-animate.js" animations="true">
|
19447
19602
|
<file name="index.html">
|
19448
|
-
<div ng-controller="
|
19603
|
+
<div ng-controller="ExampleController">
|
19449
19604
|
<select ng-model="template" ng-options="t.name for t in templates">
|
19450
19605
|
<option value="">(blank)</option>
|
19451
19606
|
</select>
|
@@ -19457,12 +19612,13 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
19457
19612
|
</div>
|
19458
19613
|
</file>
|
19459
19614
|
<file name="script.js">
|
19460
|
-
|
19461
|
-
$scope
|
19462
|
-
|
19463
|
-
{ name: '
|
19464
|
-
|
19465
|
-
|
19615
|
+
angular.module('includeExample', ['ngAnimate'])
|
19616
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
19617
|
+
$scope.templates =
|
19618
|
+
[ { name: 'template1.html', url: 'template1.html'},
|
19619
|
+
{ name: 'template2.html', url: 'template2.html'} ];
|
19620
|
+
$scope.template = $scope.templates[0];
|
19621
|
+
}]);
|
19466
19622
|
</file>
|
19467
19623
|
<file name="template1.html">
|
19468
19624
|
Content of template1.html
|
@@ -19525,7 +19681,7 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
19525
19681
|
return;
|
19526
19682
|
}
|
19527
19683
|
templateSelect.click();
|
19528
|
-
templateSelect.
|
19684
|
+
templateSelect.all(by.css('option')).get(2).click();
|
19529
19685
|
expect(includeElem.getText()).toMatch(/Content of template2.html/);
|
19530
19686
|
});
|
19531
19687
|
|
@@ -19535,7 +19691,7 @@ var ngIfDirective = ['$animate', function($animate) {
|
|
19535
19691
|
return;
|
19536
19692
|
}
|
19537
19693
|
templateSelect.click();
|
19538
|
-
templateSelect.
|
19694
|
+
templateSelect.all(by.css('option')).get(0).click();
|
19539
19695
|
expect(includeElem.isPresent()).toBe(false);
|
19540
19696
|
});
|
19541
19697
|
</file>
|
@@ -19687,14 +19843,15 @@ var ngIncludeFillContentDirective = ['$compile',
|
|
19687
19843
|
* @param {expression} ngInit {@link guide/expression Expression} to eval.
|
19688
19844
|
*
|
19689
19845
|
* @example
|
19690
|
-
<example>
|
19846
|
+
<example module="initExample">
|
19691
19847
|
<file name="index.html">
|
19692
19848
|
<script>
|
19693
|
-
|
19694
|
-
|
19695
|
-
|
19849
|
+
angular.module('initExample', [])
|
19850
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
19851
|
+
$scope.list = [['a', 'b'], ['c', 'd']];
|
19852
|
+
}]);
|
19696
19853
|
</script>
|
19697
|
-
<div ng-controller="
|
19854
|
+
<div ng-controller="ExampleController">
|
19698
19855
|
<div ng-repeat="innerList in list" ng-init="outerIndex = $index">
|
19699
19856
|
<div ng-repeat="value in innerList" ng-init="innerIndex = $index">
|
19700
19857
|
<span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
|
@@ -19834,7 +19991,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
19834
19991
|
* When one person, perhaps John, views the document, "John is viewing" will be shown.
|
19835
19992
|
* When three people view the document, no explicit number rule is found, so
|
19836
19993
|
* an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
|
19837
|
-
* In this case, plural category 'one' is matched and "John,
|
19994
|
+
* In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
|
19838
19995
|
* is shown.
|
19839
19996
|
*
|
19840
19997
|
* Note that when you specify offsets, you must provide explicit number rules for
|
@@ -19847,16 +20004,17 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
|
|
19847
20004
|
* @param {number=} offset Offset to deduct from the total number.
|
19848
20005
|
*
|
19849
20006
|
* @example
|
19850
|
-
<example>
|
20007
|
+
<example module="pluralizeExample">
|
19851
20008
|
<file name="index.html">
|
19852
20009
|
<script>
|
19853
|
-
|
19854
|
-
$scope
|
19855
|
-
|
19856
|
-
|
19857
|
-
|
20010
|
+
angular.module('pluralizeExample', [])
|
20011
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
20012
|
+
$scope.person1 = 'Igor';
|
20013
|
+
$scope.person2 = 'Misko';
|
20014
|
+
$scope.personCount = 1;
|
20015
|
+
}]);
|
19858
20016
|
</script>
|
19859
|
-
<div ng-controller="
|
20017
|
+
<div ng-controller="ExampleController">
|
19860
20018
|
Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
|
19861
20019
|
Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
|
19862
20020
|
Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
|
@@ -20716,7 +20874,7 @@ var ngHideDirective = ['$animate', function($animate) {
|
|
20716
20874
|
<file name="protractor.js" type="protractor">
|
20717
20875
|
var colorSpan = element(by.css('span'));
|
20718
20876
|
|
20719
|
-
|
20877
|
+
it('should check ng-style', function() {
|
20720
20878
|
expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
|
20721
20879
|
element(by.css('input[value=\'set color\']')).click();
|
20722
20880
|
expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
|
@@ -20790,9 +20948,9 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
20790
20948
|
*
|
20791
20949
|
*
|
20792
20950
|
* @example
|
20793
|
-
<example module="
|
20951
|
+
<example module="switchExample" deps="angular-animate.js" animations="true">
|
20794
20952
|
<file name="index.html">
|
20795
|
-
<div ng-controller="
|
20953
|
+
<div ng-controller="ExampleController">
|
20796
20954
|
<select ng-model="selection" ng-options="item for item in items">
|
20797
20955
|
</select>
|
20798
20956
|
<tt>selection={{selection}}</tt>
|
@@ -20806,10 +20964,11 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
20806
20964
|
</div>
|
20807
20965
|
</file>
|
20808
20966
|
<file name="script.js">
|
20809
|
-
|
20810
|
-
|
20811
|
-
|
20812
|
-
|
20967
|
+
angular.module('switchExample', ['ngAnimate'])
|
20968
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
20969
|
+
$scope.items = ['settings', 'home', 'other'];
|
20970
|
+
$scope.selection = $scope.items[0];
|
20971
|
+
}]);
|
20813
20972
|
</file>
|
20814
20973
|
<file name="animations.css">
|
20815
20974
|
.animate-switch-container {
|
@@ -20852,11 +21011,11 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) {
|
|
20852
21011
|
expect(switchElem.getText()).toMatch(/Settings Div/);
|
20853
21012
|
});
|
20854
21013
|
it('should change to home', function() {
|
20855
|
-
select.
|
21014
|
+
select.all(by.css('option')).get(1).click();
|
20856
21015
|
expect(switchElem.getText()).toMatch(/Home Span/);
|
20857
21016
|
});
|
20858
21017
|
it('should select default', function() {
|
20859
|
-
select.
|
21018
|
+
select.all(by.css('option')).get(2).click();
|
20860
21019
|
expect(switchElem.getText()).toMatch(/default/);
|
20861
21020
|
});
|
20862
21021
|
</file>
|
@@ -20948,15 +21107,10 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
20948
21107
|
* @element ANY
|
20949
21108
|
*
|
20950
21109
|
* @example
|
20951
|
-
<example module="
|
21110
|
+
<example module="transcludeExample">
|
20952
21111
|
<file name="index.html">
|
20953
21112
|
<script>
|
20954
|
-
|
20955
|
-
$scope.title = 'Lorem Ipsum';
|
20956
|
-
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
|
20957
|
-
}
|
20958
|
-
|
20959
|
-
angular.module('transclude', [])
|
21113
|
+
angular.module('transcludeExample', [])
|
20960
21114
|
.directive('pane', function(){
|
20961
21115
|
return {
|
20962
21116
|
restrict: 'E',
|
@@ -20967,9 +21121,13 @@ var ngSwitchDefaultDirective = ngDirective({
|
|
20967
21121
|
'<div ng-transclude></div>' +
|
20968
21122
|
'</div>'
|
20969
21123
|
};
|
20970
|
-
})
|
21124
|
+
})
|
21125
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
21126
|
+
$scope.title = 'Lorem Ipsum';
|
21127
|
+
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
|
21128
|
+
}]);
|
20971
21129
|
</script>
|
20972
|
-
<div ng-controller="
|
21130
|
+
<div ng-controller="ExampleController">
|
20973
21131
|
<input ng-model="title"><br>
|
20974
21132
|
<textarea ng-model="text"></textarea> <br/>
|
20975
21133
|
<pane title="{{title}}">{{text}}</pane>
|
@@ -21128,21 +21286,22 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
21128
21286
|
* `value` variable (e.g. `value.propertyName`).
|
21129
21287
|
*
|
21130
21288
|
* @example
|
21131
|
-
<example>
|
21289
|
+
<example module="selectExample">
|
21132
21290
|
<file name="index.html">
|
21133
21291
|
<script>
|
21134
|
-
|
21135
|
-
$scope
|
21136
|
-
|
21137
|
-
|
21138
|
-
|
21139
|
-
|
21140
|
-
|
21141
|
-
|
21142
|
-
|
21143
|
-
|
21292
|
+
angular.module('selectExample', [])
|
21293
|
+
.controller('ExampleController', ['$scope', function($scope) {
|
21294
|
+
$scope.colors = [
|
21295
|
+
{name:'black', shade:'dark'},
|
21296
|
+
{name:'white', shade:'light'},
|
21297
|
+
{name:'red', shade:'dark'},
|
21298
|
+
{name:'blue', shade:'dark'},
|
21299
|
+
{name:'yellow', shade:'light'}
|
21300
|
+
];
|
21301
|
+
$scope.myColor = $scope.colors[2]; // red
|
21302
|
+
}]);
|
21144
21303
|
</script>
|
21145
|
-
<div ng-controller="
|
21304
|
+
<div ng-controller="ExampleController">
|
21146
21305
|
<ul>
|
21147
21306
|
<li ng-repeat="color in colors">
|
21148
21307
|
Name: <input ng-model="color.name">
|
@@ -21179,7 +21338,7 @@ var ngOptionsMinErr = minErr('ngOptions');
|
|
21179
21338
|
<file name="protractor.js" type="protractor">
|
21180
21339
|
it('should check ng-options', function() {
|
21181
21340
|
expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
|
21182
|
-
element.all(by.
|
21341
|
+
element.all(by.model('myColor')).first().click();
|
21183
21342
|
element.all(by.css('select[ng-model="myColor"] option')).first().click();
|
21184
21343
|
expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
|
21185
21344
|
element(by.css('.nullable select[ng-model="myColor"]')).click();
|
@@ -21595,6 +21754,12 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
21595
21754
|
// lastElement.prop('selected') provided by jQuery has side-effects
|
21596
21755
|
if (existingOption.selected !== option.selected) {
|
21597
21756
|
lastElement.prop('selected', (existingOption.selected = option.selected));
|
21757
|
+
if (msie) {
|
21758
|
+
// See #7692
|
21759
|
+
// The selected item wouldn't visually update on IE without this.
|
21760
|
+
// Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
|
21761
|
+
lastElement.prop('selected', existingOption.selected);
|
21762
|
+
}
|
21598
21763
|
}
|
21599
21764
|
} else {
|
21600
21765
|
// grow elements
|
@@ -21609,7 +21774,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
|
21609
21774
|
// rather then the element.
|
21610
21775
|
(element = optionTemplate.clone())
|
21611
21776
|
.val(option.id)
|
21612
|
-
.
|
21777
|
+
.prop('selected', option.selected)
|
21613
21778
|
.text(option.label);
|
21614
21779
|
}
|
21615
21780
|
|