angularjs-on-rails 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|
|