angular-gem 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +9 -2
- data/Rakefile +86 -19
- data/lib/angular-gem/version.rb +1 -1
- data/lib/generators/angular/resource_helpers.rb +13 -13
- data/test/dummy/log/test.log +1 -3
- data/test/dummy/tmp/cache/assets/{DF8/FD0/sprockets%2F87b01decd5c7fd3c6f174b8cba0d810f → D65/250/sprockets%2F54a960d46bb0b354e8bd46fa03f5e0e4} +0 -0
- data/test/dummy/tmp/cache/assets/{D73/C00/sprockets%2Fa3620dc4bbd0562669b546e9c58eede4 → D6A/FB0/sprockets%2F92721e9941b77adcfdfba3d060622de2} +0 -0
- data/test/dummy/tmp/cache/assets/E07/040/sprockets%2Ff55b8ce9d0f28ce36b768a1c7aeb2ef3 +0 -0
- data/test/test_helper.rb +3 -0
- data/vendor/assets/javascripts/1.0.5/angular-1.0.5.js +14733 -0
- data/vendor/assets/javascripts/1.0.5/angular-resource-1.0.5.js +445 -0
- data/vendor/assets/javascripts/1.0.5/angular-sanitize-1.0.5.js +535 -0
- data/{test/dummy/tmp/cache/assets/CF7/120/sprockets%2Fd6adf41113c67a57c4a1330845ba0d08 → vendor/assets/javascripts/1.1.2/angular-1.1.2.js} +0 -0
- data/vendor/assets/javascripts/1.1.2/angular-resource-1.1.2.js +472 -0
- data/vendor/assets/javascripts/1.1.2/angular-sanitize-1.1.2.js +556 -0
- data/{test/dummy/tmp/cache/assets/CD5/C60/sprockets%2F4348b099c4aadda10262e757261e0f81 → vendor/assets/javascripts/1.1.3/angular-1.1.3.js} +0 -0
- data/vendor/assets/javascripts/1.1.3/angular-resource-1.1.3.js +507 -0
- data/vendor/assets/javascripts/1.1.3/angular-sanitize-1.1.3.js +556 -0
- data/vendor/assets/javascripts/angular-resource-unstable.js +507 -0
- data/vendor/assets/javascripts/angular-resource.js +23 -50
- data/vendor/assets/javascripts/angular-sanitize-unstable.js +556 -0
- data/vendor/assets/javascripts/angular-sanitize.js +4 -25
- data/{test/dummy/tmp/cache/assets/CE3/300/sprockets%2Fc11999ba09d72e745355212e48bc72dd → vendor/assets/javascripts/angular-unstable.js} +0 -0
- data/vendor/assets/javascripts/angular.js +305 -454
- metadata +53 -21
- data/test/dummy/tmp/cache/assets/D71/060/sprockets%2Fc434a3f93ecb87049eb12e766005fede +0 -0
- data/test/dummy/tmp/cache/assets/D79/F40/sprockets%2F9088cfe323d1b81dd526e6a9e3ed358c +0 -0
- data/test/dummy/tmp/cache/assets/D9E/830/sprockets%2Fbb7eb0f50f1afed5705594e9d812b8d0 +0 -0
- data/test/dummy/tmp/cache/assets/DD4/250/sprockets%2Feaa70f0d0954a5edffe77c9ca1e93860 +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
2
|
+
* @license AngularJS v1.0.5
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -129,7 +129,7 @@ var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:
|
|
129
129
|
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
130
130
|
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
131
131
|
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
132
|
-
URI_REGEXP = /^((ftp|https?):\/\/|mailto
|
132
|
+
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/,
|
133
133
|
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
|
134
134
|
|
135
135
|
|
@@ -432,7 +432,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
432
432
|
* plain email address links.
|
433
433
|
*
|
434
434
|
* @param {string} text Input text.
|
435
|
-
* @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in.
|
436
435
|
* @returns {string} Html-linkified text.
|
437
436
|
*
|
438
437
|
* @usage
|
@@ -449,7 +448,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
449
448
|
'mailto:us@somewhere.org,\n'+
|
450
449
|
'another@somewhere.org,\n'+
|
451
450
|
'and one more: ftp://127.0.0.1/.';
|
452
|
-
$scope.snippetWithTarget = 'http://angularjs.org/';
|
453
451
|
}
|
454
452
|
</script>
|
455
453
|
<div ng-controller="Ctrl">
|
@@ -469,15 +467,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
469
467
|
<div ng-bind-html="snippet | linky"></div>
|
470
468
|
</td>
|
471
469
|
</tr>
|
472
|
-
<tr id="linky-target">
|
473
|
-
<td>linky target</td>
|
474
|
-
<td>
|
475
|
-
<pre><div ng-bind-html="snippetWithTarget | linky:'_blank'"><br></div></pre>
|
476
|
-
</td>
|
477
|
-
<td>
|
478
|
-
<div ng-bind-html="snippetWithTarget | linky:'_blank'"></div>
|
479
|
-
</td>
|
480
|
-
</tr>
|
481
470
|
<tr id="escaped-html">
|
482
471
|
<td>no filter</td>
|
483
472
|
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
@@ -510,11 +499,6 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
|
|
510
499
|
toBe('new <a href="http://link">http://link</a>.');
|
511
500
|
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
512
501
|
});
|
513
|
-
|
514
|
-
it('should work with the target property', function() {
|
515
|
-
expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")).
|
516
|
-
toBe('<a target="_blank" href="http://angularjs.org/">http://angularjs.org/</a>');
|
517
|
-
});
|
518
502
|
</doc:scenario>
|
519
503
|
</doc:example>
|
520
504
|
*/
|
@@ -522,7 +506,7 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
522
506
|
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
|
523
507
|
MAILTO_REGEXP = /^mailto:/;
|
524
508
|
|
525
|
-
return function(text
|
509
|
+
return function(text) {
|
526
510
|
if (!text) return text;
|
527
511
|
var match;
|
528
512
|
var raw = text;
|
@@ -531,10 +515,6 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
531
515
|
var writer = htmlSanitizeWriter(html);
|
532
516
|
var url;
|
533
517
|
var i;
|
534
|
-
var properties = {};
|
535
|
-
if (angular.isDefined(target)) {
|
536
|
-
properties.target = target;
|
537
|
-
}
|
538
518
|
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
539
519
|
// We can not end in these as they are sometimes found at the end of the sentence
|
540
520
|
url = match[0];
|
@@ -542,8 +522,7 @@ angular.module('ngSanitize').filter('linky', function() {
|
|
542
522
|
if (match[2] == match[3]) url = 'mailto:' + url;
|
543
523
|
i = match.index;
|
544
524
|
writer.chars(raw.substr(0, i));
|
545
|
-
|
546
|
-
writer.start('a', properties);
|
525
|
+
writer.start('a', {href:url});
|
547
526
|
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
548
527
|
writer.end('a');
|
549
528
|
raw = raw.substring(i + match[0].length);
|
Binary file
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license AngularJS v1.
|
2
|
+
* @license AngularJS v1.0.5
|
3
3
|
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
4
4
|
* License: MIT
|
5
5
|
*/
|
@@ -55,8 +55,7 @@ if ('i' !== 'I'.toLowerCase()) {
|
|
55
55
|
function fromCharCode(code) {return String.fromCharCode(code);}
|
56
56
|
|
57
57
|
|
58
|
-
var
|
59
|
-
/** holds major version number for IE or NaN for real browsers */
|
58
|
+
var /** holds major version number for IE or NaN for real browsers */
|
60
59
|
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
|
61
60
|
jqLite, // delay binding since jQuery could be loaded after us.
|
62
61
|
jQuery, // delay binding
|
@@ -97,6 +96,30 @@ var Error = window.Error,
|
|
97
96
|
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
98
97
|
* @returns {Object|Array} Reference to `obj`.
|
99
98
|
*/
|
99
|
+
|
100
|
+
|
101
|
+
/**
|
102
|
+
* @private
|
103
|
+
* @param {*} obj
|
104
|
+
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
105
|
+
*/
|
106
|
+
function isArrayLike(obj) {
|
107
|
+
if (!obj || (typeof obj.length !== 'number')) return false;
|
108
|
+
|
109
|
+
// We have on object which has length property. Should we treat it as array?
|
110
|
+
if (typeof obj.hasOwnProperty != 'function' &&
|
111
|
+
typeof obj.constructor != 'function') {
|
112
|
+
// This is here for IE8: it is a bogus object treat it as array;
|
113
|
+
return true;
|
114
|
+
} else {
|
115
|
+
return obj instanceof JQLite || // JQLite
|
116
|
+
(jQuery && obj instanceof jQuery) || // jQuery
|
117
|
+
toString.call(obj) !== '[object Object]' || // some browser native object
|
118
|
+
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
|
100
123
|
function forEach(obj, iterator, context) {
|
101
124
|
var key;
|
102
125
|
if (obj) {
|
@@ -108,7 +131,7 @@ function forEach(obj, iterator, context) {
|
|
108
131
|
}
|
109
132
|
} else if (obj.forEach && obj.forEach !== forEach) {
|
110
133
|
obj.forEach(iterator, context);
|
111
|
-
} else if (
|
134
|
+
} else if (isArrayLike(obj)) {
|
112
135
|
for (key = 0; key < obj.length; key++)
|
113
136
|
iterator.call(context, obj[key], key);
|
114
137
|
} else {
|
@@ -153,7 +176,7 @@ function reverseParams(iteratorFn) {
|
|
153
176
|
/**
|
154
177
|
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
155
178
|
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
156
|
-
* the number string gets longer over time, and it can also overflow, where as the
|
179
|
+
* the number string gets longer over time, and it can also overflow, where as the nextId
|
157
180
|
* will grow much slower, it is a string, and it will never overflow.
|
158
181
|
*
|
159
182
|
* @returns an unique alpha-numeric string
|
@@ -549,9 +572,7 @@ function copy(source, destination){
|
|
549
572
|
} else {
|
550
573
|
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
|
551
574
|
if (isArray(source)) {
|
552
|
-
|
553
|
-
destination.pop();
|
554
|
-
}
|
575
|
+
destination.length = 0;
|
555
576
|
for ( var i = 0; i < source.length; i++) {
|
556
577
|
destination.push(copy(source[i]));
|
557
578
|
}
|
@@ -762,9 +783,18 @@ function startingTag(element) {
|
|
762
783
|
// are not allowed to have children. So we just ignore it.
|
763
784
|
element.html('');
|
764
785
|
} catch(e) {}
|
765
|
-
|
766
|
-
|
767
|
-
|
786
|
+
// As Per DOM Standards
|
787
|
+
var TEXT_NODE = 3;
|
788
|
+
var elemHtml = jqLite('<div>').append(element).html();
|
789
|
+
try {
|
790
|
+
return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
|
791
|
+
elemHtml.
|
792
|
+
match(/^(<[^>]+>)/)[1].
|
793
|
+
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
794
|
+
} catch(e) {
|
795
|
+
return lowercase(elemHtml);
|
796
|
+
}
|
797
|
+
|
768
798
|
}
|
769
799
|
|
770
800
|
|
@@ -848,7 +878,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
|
848
878
|
* Use this directive to auto-bootstrap on application. Only
|
849
879
|
* one directive can be used per HTML document. The directive
|
850
880
|
* designates the root of the application and is typically placed
|
851
|
-
*
|
881
|
+
* at the root of the page.
|
852
882
|
*
|
853
883
|
* In the example below if the `ngApp` directive would not be placed
|
854
884
|
* on the `html` element then the document would not be compiled
|
@@ -1249,11 +1279,11 @@ function setupModuleLoader(window) {
|
|
1249
1279
|
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
|
1250
1280
|
*/
|
1251
1281
|
var version = {
|
1252
|
-
full: '1.
|
1282
|
+
full: '1.0.5', // all of these placeholder strings will be replaced by rake's
|
1253
1283
|
major: 1, // compile task
|
1254
|
-
minor:
|
1255
|
-
dot:
|
1256
|
-
codeName: '
|
1284
|
+
minor: 0,
|
1285
|
+
dot: 5,
|
1286
|
+
codeName: 'flatulent-propulsion'
|
1257
1287
|
};
|
1258
1288
|
|
1259
1289
|
|
@@ -1719,11 +1749,11 @@ var JQLitePrototype = JQLite.prototype = {
|
|
1719
1749
|
// value on get.
|
1720
1750
|
//////////////////////////////////////////
|
1721
1751
|
var BOOLEAN_ATTR = {};
|
1722
|
-
forEach('multiple,selected,checked,disabled,readOnly,required
|
1752
|
+
forEach('multiple,selected,checked,disabled,readOnly,required'.split(','), function(value) {
|
1723
1753
|
BOOLEAN_ATTR[lowercase(value)] = value;
|
1724
1754
|
});
|
1725
1755
|
var BOOLEAN_ELEMENTS = {};
|
1726
|
-
forEach('input,select,option,textarea,button,form
|
1756
|
+
forEach('input,select,option,textarea,button,form'.split(','), function(value) {
|
1727
1757
|
BOOLEAN_ELEMENTS[uppercase(value)] = true;
|
1728
1758
|
});
|
1729
1759
|
|
@@ -2025,9 +2055,8 @@ forEach({
|
|
2025
2055
|
|
2026
2056
|
append: function(element, node) {
|
2027
2057
|
forEach(new JQLite(node), function(child){
|
2028
|
-
if (element.nodeType === 1
|
2058
|
+
if (element.nodeType === 1)
|
2029
2059
|
element.appendChild(child);
|
2030
|
-
}
|
2031
2060
|
});
|
2032
2061
|
},
|
2033
2062
|
|
@@ -2431,7 +2460,7 @@ function annotate(fn) {
|
|
2431
2460
|
* This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
|
2432
2461
|
* are supported.
|
2433
2462
|
*
|
2434
|
-
* # The `$
|
2463
|
+
* # The `$inject` property
|
2435
2464
|
*
|
2436
2465
|
* If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
|
2437
2466
|
* services to be injected into the function.
|
@@ -2649,10 +2678,9 @@ function createInjector(modulesToLoad) {
|
|
2649
2678
|
decorator: decorator
|
2650
2679
|
}
|
2651
2680
|
},
|
2652
|
-
providerInjector = (providerCache
|
2653
|
-
|
2654
|
-
|
2655
|
-
})),
|
2681
|
+
providerInjector = createInternalInjector(providerCache, function() {
|
2682
|
+
throw Error("Unknown provider: " + path.join(' <- '));
|
2683
|
+
}),
|
2656
2684
|
instanceCache = {},
|
2657
2685
|
instanceInjector = (instanceCache.$injector =
|
2658
2686
|
createInternalInjector(instanceCache, function(servicename) {
|
@@ -2729,7 +2757,9 @@ function createInjector(modulesToLoad) {
|
|
2729
2757
|
try {
|
2730
2758
|
for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
|
2731
2759
|
var invokeArgs = invokeQueue[i],
|
2732
|
-
provider =
|
2760
|
+
provider = invokeArgs[0] == '$injector'
|
2761
|
+
? providerInjector
|
2762
|
+
: providerInjector.get(invokeArgs[0]);
|
2733
2763
|
|
2734
2764
|
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
|
2735
2765
|
}
|
@@ -3144,7 +3174,7 @@ function Browser(window, document, $log, $sniffer) {
|
|
3144
3174
|
*/
|
3145
3175
|
self.baseHref = function() {
|
3146
3176
|
var href = baseElement.attr('href');
|
3147
|
-
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') :
|
3177
|
+
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
|
3148
3178
|
};
|
3149
3179
|
|
3150
3180
|
//////////////////////////////////////////////////////////////
|
@@ -3284,7 +3314,7 @@ function $BrowserProvider(){
|
|
3284
3314
|
* @returns {object} Newly created cache object with the following set of methods:
|
3285
3315
|
*
|
3286
3316
|
* - `{object}` `info()` — Returns id, size, and options of cache.
|
3287
|
-
* - `{
|
3317
|
+
* - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
|
3288
3318
|
* - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
|
3289
3319
|
* - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
|
3290
3320
|
* - `{void}` `removeAll()` — Removes all cached values.
|
@@ -3323,8 +3353,6 @@ function $CacheFactoryProvider() {
|
|
3323
3353
|
if (size > capacity) {
|
3324
3354
|
this.remove(staleEnd.key);
|
3325
3355
|
}
|
3326
|
-
|
3327
|
-
return value;
|
3328
3356
|
},
|
3329
3357
|
|
3330
3358
|
|
@@ -3596,7 +3624,8 @@ function $CompileProvider($provide) {
|
|
3596
3624
|
Suffix = 'Directive',
|
3597
3625
|
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
3598
3626
|
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
3599
|
-
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: '
|
3627
|
+
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
|
3628
|
+
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
|
3600
3629
|
|
3601
3630
|
|
3602
3631
|
/**
|
@@ -3650,11 +3679,41 @@ function $CompileProvider($provide) {
|
|
3650
3679
|
};
|
3651
3680
|
|
3652
3681
|
|
3682
|
+
/**
|
3683
|
+
* @ngdoc function
|
3684
|
+
* @name ng.$compileProvider#urlSanitizationWhitelist
|
3685
|
+
* @methodOf ng.$compileProvider
|
3686
|
+
* @function
|
3687
|
+
*
|
3688
|
+
* @description
|
3689
|
+
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
3690
|
+
* urls during a[href] sanitization.
|
3691
|
+
*
|
3692
|
+
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
3693
|
+
*
|
3694
|
+
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
|
3695
|
+
* absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
|
3696
|
+
* expression. If a match is found the original url is written into the dom. Otherwise the
|
3697
|
+
* absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
|
3698
|
+
*
|
3699
|
+
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
3700
|
+
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
3701
|
+
* chaining otherwise.
|
3702
|
+
*/
|
3703
|
+
this.urlSanitizationWhitelist = function(regexp) {
|
3704
|
+
if (isDefined(regexp)) {
|
3705
|
+
urlSanitizationWhitelist = regexp;
|
3706
|
+
return this;
|
3707
|
+
}
|
3708
|
+
return urlSanitizationWhitelist;
|
3709
|
+
};
|
3710
|
+
|
3711
|
+
|
3653
3712
|
this.$get = [
|
3654
3713
|
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
|
3655
|
-
'$controller', '$rootScope',
|
3714
|
+
'$controller', '$rootScope', '$document',
|
3656
3715
|
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
|
3657
|
-
$controller, $rootScope) {
|
3716
|
+
$controller, $rootScope, $document) {
|
3658
3717
|
|
3659
3718
|
var Attributes = function(element, attr) {
|
3660
3719
|
this.$$element = element;
|
@@ -3676,7 +3735,8 @@ function $CompileProvider($provide) {
|
|
3676
3735
|
*/
|
3677
3736
|
$set: function(key, value, writeAttr, attrName) {
|
3678
3737
|
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
3679
|
-
$$observers = this.$$observers
|
3738
|
+
$$observers = this.$$observers,
|
3739
|
+
normalizedVal;
|
3680
3740
|
|
3681
3741
|
if (booleanKey) {
|
3682
3742
|
this.$$element.prop(key, value);
|
@@ -3695,6 +3755,19 @@ function $CompileProvider($provide) {
|
|
3695
3755
|
}
|
3696
3756
|
}
|
3697
3757
|
|
3758
|
+
|
3759
|
+
// sanitize a[href] values
|
3760
|
+
if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
|
3761
|
+
urlSanitizationNode.setAttribute('href', value);
|
3762
|
+
|
3763
|
+
// href property always returns normalized absolute url, so we can match against that
|
3764
|
+
normalizedVal = urlSanitizationNode.href;
|
3765
|
+
if (!normalizedVal.match(urlSanitizationWhitelist)) {
|
3766
|
+
this[key] = value = 'unsafe:' + normalizedVal;
|
3767
|
+
}
|
3768
|
+
}
|
3769
|
+
|
3770
|
+
|
3698
3771
|
if (writeAttr !== false) {
|
3699
3772
|
if (value === null || value === undefined) {
|
3700
3773
|
this.$$element.removeAttr(attrName);
|
@@ -3738,7 +3811,8 @@ function $CompileProvider($provide) {
|
|
3738
3811
|
}
|
3739
3812
|
};
|
3740
3813
|
|
3741
|
-
var
|
3814
|
+
var urlSanitizationNode = $document[0].createElement('a'),
|
3815
|
+
startSymbol = $interpolate.startSymbol(),
|
3742
3816
|
endSymbol = $interpolate.endSymbol(),
|
3743
3817
|
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
|
3744
3818
|
? identity
|
@@ -3771,7 +3845,14 @@ function $CompileProvider($provide) {
|
|
3771
3845
|
var $linkNode = cloneConnectFn
|
3772
3846
|
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
|
3773
3847
|
: $compileNodes;
|
3774
|
-
|
3848
|
+
|
3849
|
+
// Attach scope only to non-text nodes.
|
3850
|
+
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
3851
|
+
var node = $linkNode[i];
|
3852
|
+
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
3853
|
+
$linkNode.eq(i).data('$scope', scope);
|
3854
|
+
}
|
3855
|
+
}
|
3775
3856
|
safeAddClass($linkNode, 'ng-scope');
|
3776
3857
|
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
3777
3858
|
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
@@ -3861,6 +3942,7 @@ function $CompileProvider($provide) {
|
|
3861
3942
|
(function(transcludeFn) {
|
3862
3943
|
return function(cloneFn) {
|
3863
3944
|
var transcludeScope = scope.$new();
|
3945
|
+
transcludeScope.$$transcluded = true;
|
3864
3946
|
|
3865
3947
|
return transcludeFn(transcludeScope, cloneFn).
|
3866
3948
|
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
|
@@ -4166,6 +4248,8 @@ function $CompileProvider($provide) {
|
|
4166
4248
|
lastValue,
|
4167
4249
|
parentGet, parentSet;
|
4168
4250
|
|
4251
|
+
scope.$$isolateBindings[scopeName] = mode + attrName;
|
4252
|
+
|
4169
4253
|
switch (mode) {
|
4170
4254
|
|
4171
4255
|
case '@': {
|
@@ -4376,7 +4460,7 @@ function $CompileProvider($provide) {
|
|
4376
4460
|
}
|
4377
4461
|
|
4378
4462
|
directives.unshift(derivedSyncDirective);
|
4379
|
-
afterTemplateNodeLinkFn = applyDirectivesToNode(directives,
|
4463
|
+
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
|
4380
4464
|
afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
|
4381
4465
|
|
4382
4466
|
|
@@ -4456,10 +4540,10 @@ function $CompileProvider($provide) {
|
|
4456
4540
|
function addAttrInterpolateDirective(node, directives, value, name) {
|
4457
4541
|
var interpolateFn = $interpolate(value, true);
|
4458
4542
|
|
4459
|
-
|
4460
4543
|
// no interpolation found -> ignore
|
4461
4544
|
if (!interpolateFn) return;
|
4462
4545
|
|
4546
|
+
|
4463
4547
|
directives.push({
|
4464
4548
|
priority: 100,
|
4465
4549
|
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
|
@@ -4754,7 +4838,7 @@ function $InterpolateProvider() {
|
|
4754
4838
|
};
|
4755
4839
|
|
4756
4840
|
|
4757
|
-
this.$get = ['$parse',
|
4841
|
+
this.$get = ['$parse', function($parse) {
|
4758
4842
|
var startSymbolLength = startSymbol.length,
|
4759
4843
|
endSymbolLength = endSymbol.length;
|
4760
4844
|
|
@@ -4826,24 +4910,18 @@ function $InterpolateProvider() {
|
|
4826
4910
|
if (!mustHaveExpression || hasInterpolation) {
|
4827
4911
|
concat.length = length;
|
4828
4912
|
fn = function(context) {
|
4829
|
-
|
4830
|
-
|
4831
|
-
|
4832
|
-
|
4833
|
-
|
4834
|
-
|
4835
|
-
|
4836
|
-
part = toJson(part);
|
4837
|
-
}
|
4913
|
+
for(var i = 0, ii = length, part; i<ii; i++) {
|
4914
|
+
if (typeof (part = parts[i]) == 'function') {
|
4915
|
+
part = part(context);
|
4916
|
+
if (part == null || part == undefined) {
|
4917
|
+
part = '';
|
4918
|
+
} else if (typeof part != 'string') {
|
4919
|
+
part = toJson(part);
|
4838
4920
|
}
|
4839
|
-
concat[i] = part;
|
4840
4921
|
}
|
4841
|
-
|
4842
|
-
}
|
4843
|
-
catch(err) {
|
4844
|
-
var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString());
|
4845
|
-
$exceptionHandler(newErr);
|
4922
|
+
concat[i] = part;
|
4846
4923
|
}
|
4924
|
+
return concat.join('');
|
4847
4925
|
};
|
4848
4926
|
fn.exp = text;
|
4849
4927
|
fn.parts = parts;
|
@@ -5539,33 +5617,7 @@ function $LocationProvider(){
|
|
5539
5617
|
</example>
|
5540
5618
|
*/
|
5541
5619
|
|
5542
|
-
/**
|
5543
|
-
* @ngdoc object
|
5544
|
-
* @name ng.$logProvider
|
5545
|
-
* @description
|
5546
|
-
* Use the `$logProvider` to configure how the application logs messages
|
5547
|
-
*/
|
5548
5620
|
function $LogProvider(){
|
5549
|
-
var debug = true,
|
5550
|
-
self = this;
|
5551
|
-
|
5552
|
-
/**
|
5553
|
-
* @ngdoc property
|
5554
|
-
* @name ng.$logProvider#debugEnabled
|
5555
|
-
* @methodOf ng.$logProvider
|
5556
|
-
* @description
|
5557
|
-
* @param {string=} flag enable or disable debug level messages
|
5558
|
-
* @returns {*} current value if used as getter or itself (chaining) if used as setter
|
5559
|
-
*/
|
5560
|
-
this.debugEnabled = function(flag) {
|
5561
|
-
if (isDefined(flag)) {
|
5562
|
-
debug = flag;
|
5563
|
-
return this;
|
5564
|
-
} else {
|
5565
|
-
return debug;
|
5566
|
-
}
|
5567
|
-
};
|
5568
|
-
|
5569
5621
|
this.$get = ['$window', function($window){
|
5570
5622
|
return {
|
5571
5623
|
/**
|
@@ -5606,25 +5658,7 @@ function $LogProvider(){
|
|
5606
5658
|
* @description
|
5607
5659
|
* Write an error message
|
5608
5660
|
*/
|
5609
|
-
error: consoleLog('error')
|
5610
|
-
|
5611
|
-
/**
|
5612
|
-
* @ngdoc method
|
5613
|
-
* @name ng.$log#debug
|
5614
|
-
* @methodOf ng.$log
|
5615
|
-
*
|
5616
|
-
* @description
|
5617
|
-
* Write a debug message
|
5618
|
-
*/
|
5619
|
-
debug: (function () {
|
5620
|
-
var fn = consoleLog('debug');
|
5621
|
-
|
5622
|
-
return function() {
|
5623
|
-
if (debug) {
|
5624
|
-
fn.apply(self, arguments);
|
5625
|
-
}
|
5626
|
-
}
|
5627
|
-
}())
|
5661
|
+
error: consoleLog('error')
|
5628
5662
|
};
|
5629
5663
|
|
5630
5664
|
function formatError(arg) {
|
@@ -5683,8 +5717,6 @@ var OPERATORS = {
|
|
5683
5717
|
'%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
|
5684
5718
|
'^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
|
5685
5719
|
'=':noop,
|
5686
|
-
'===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
|
5687
|
-
'!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
|
5688
5720
|
'==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
|
5689
5721
|
'!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
|
5690
5722
|
'<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
|
@@ -5735,14 +5767,9 @@ function lex(text, csp){
|
|
5735
5767
|
continue;
|
5736
5768
|
} else {
|
5737
5769
|
var ch2 = ch + peek(),
|
5738
|
-
ch3 = ch2 + peek(2),
|
5739
5770
|
fn = OPERATORS[ch],
|
5740
|
-
fn2 = OPERATORS[ch2]
|
5741
|
-
|
5742
|
-
if (fn3) {
|
5743
|
-
tokens.push({index:index, text:ch3, fn:fn3});
|
5744
|
-
index += 3;
|
5745
|
-
} else if (fn2) {
|
5771
|
+
fn2 = OPERATORS[ch2];
|
5772
|
+
if (fn2) {
|
5746
5773
|
tokens.push({index:index, text:ch2, fn:fn2});
|
5747
5774
|
index += 2;
|
5748
5775
|
} else if (fn) {
|
@@ -5764,9 +5791,8 @@ function lex(text, csp){
|
|
5764
5791
|
return chars.indexOf(lastCh) != -1;
|
5765
5792
|
}
|
5766
5793
|
|
5767
|
-
function peek(
|
5768
|
-
|
5769
|
-
return index + num < text.length ? text.charAt(index + num) : false;
|
5794
|
+
function peek() {
|
5795
|
+
return index + 1 < text.length ? text.charAt(index + 1) : false;
|
5770
5796
|
}
|
5771
5797
|
function isNumber(ch) {
|
5772
5798
|
return '0' <= ch && ch <= '9';
|
@@ -6127,7 +6153,7 @@ function parser(text, json, $filter, csp){
|
|
6127
6153
|
function equality() {
|
6128
6154
|
var left = relational();
|
6129
6155
|
var token;
|
6130
|
-
if ((token = expect('==','!='
|
6156
|
+
if ((token = expect('==','!='))) {
|
6131
6157
|
left = binaryFn(left, token.fn, equality());
|
6132
6158
|
}
|
6133
6159
|
return left;
|
@@ -6511,9 +6537,10 @@ function getterFn(path, csp) {
|
|
6511
6537
|
* @param {string} expression String expression to compile.
|
6512
6538
|
* @returns {function(context, locals)} a function which represents the compiled expression:
|
6513
6539
|
*
|
6514
|
-
* * `context
|
6515
|
-
* against (
|
6516
|
-
* * `locals
|
6540
|
+
* * `context` – `{object}` – an object against which any expressions embedded in the strings
|
6541
|
+
* are evaluated against (tipically a scope object).
|
6542
|
+
* * `locals` – `{object=}` – local variables context object, useful for overriding values in
|
6543
|
+
* `context`.
|
6517
6544
|
*
|
6518
6545
|
* The return function also has an `assign` property, if the expression is assignable, which
|
6519
6546
|
* allows one to set values to expressions.
|
@@ -6549,7 +6576,7 @@ function $ParseProvider() {
|
|
6549
6576
|
* interface for interacting with an object that represents the result of an action that is
|
6550
6577
|
* performed asynchronously, and may or may not be finished at any given point in time.
|
6551
6578
|
*
|
6552
|
-
* From the perspective of dealing with error handling, deferred and promise
|
6579
|
+
* From the perspective of dealing with error handling, deferred and promise APIs are to
|
6553
6580
|
* asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
|
6554
6581
|
*
|
6555
6582
|
* <pre>
|
@@ -6584,7 +6611,7 @@ function $ParseProvider() {
|
|
6584
6611
|
*
|
6585
6612
|
* At first it might not be obvious why this extra complexity is worth the trouble. The payoff
|
6586
6613
|
* comes in the way of
|
6587
|
-
* [guarantees that promise and deferred
|
6614
|
+
* [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
|
6588
6615
|
*
|
6589
6616
|
* Additionally the promise api allows for composition that is very hard to do with the
|
6590
6617
|
* traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
|
@@ -6596,7 +6623,7 @@ function $ParseProvider() {
|
|
6596
6623
|
*
|
6597
6624
|
* A new instance of deferred is constructed by calling `$q.defer()`.
|
6598
6625
|
*
|
6599
|
-
* The purpose of the deferred object is to expose the associated Promise instance as well as
|
6626
|
+
* The purpose of the deferred object is to expose the associated Promise instance as well as APIs
|
6600
6627
|
* that can be used for signaling the successful or unsuccessful completion of the task.
|
6601
6628
|
*
|
6602
6629
|
* **Methods**
|
@@ -6639,7 +6666,7 @@ function $ParseProvider() {
|
|
6639
6666
|
* return result + 1;
|
6640
6667
|
* });
|
6641
6668
|
*
|
6642
|
-
* // promiseB will be resolved immediately after promiseA is resolved and
|
6669
|
+
* // promiseB will be resolved immediately after promiseA is resolved and its value will be
|
6643
6670
|
* // the result of promiseA incremented by 1
|
6644
6671
|
* </pre>
|
6645
6672
|
*
|
@@ -6664,7 +6691,7 @@ function $ParseProvider() {
|
|
6664
6691
|
* # Testing
|
6665
6692
|
*
|
6666
6693
|
* <pre>
|
6667
|
-
* it('should simulate promise', inject(function($q, $
|
6694
|
+
* it('should simulate promise', inject(function($q, $rootScope) {
|
6668
6695
|
* var deferred = $q.defer();
|
6669
6696
|
* var promise = deferred.promise;
|
6670
6697
|
* var resolvedValue;
|
@@ -6673,7 +6700,7 @@ function $ParseProvider() {
|
|
6673
6700
|
* expect(resolvedValue).toBeUndefined();
|
6674
6701
|
*
|
6675
6702
|
* // Simulate resolving of promise
|
6676
|
-
*
|
6703
|
+
* deferred.resolve(123);
|
6677
6704
|
* // Note that the 'then' function does not get called synchronously.
|
6678
6705
|
* // This is because we want the promise API to always be async, whether or not
|
6679
6706
|
* // it got called synchronously or asynchronously.
|
@@ -6849,12 +6876,12 @@ function qFactory(nextTick, exceptionHandler) {
|
|
6849
6876
|
* @methodOf ng.$q
|
6850
6877
|
* @description
|
6851
6878
|
* Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
|
6852
|
-
* This is useful when you are dealing with
|
6879
|
+
* This is useful when you are dealing with an object that might or might not be a promise, or if
|
6853
6880
|
* the promise comes from a source that can't be trusted.
|
6854
6881
|
*
|
6855
6882
|
* @param {*} value Value or a promise
|
6856
6883
|
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
|
6857
|
-
* each value
|
6884
|
+
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
6858
6885
|
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
6859
6886
|
* same rejection.
|
6860
6887
|
*/
|
@@ -6916,7 +6943,7 @@ function qFactory(nextTick, exceptionHandler) {
|
|
6916
6943
|
*
|
6917
6944
|
* @param {Array.<Promise>} promises An array of promises.
|
6918
6945
|
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
|
6919
|
-
* each value
|
6946
|
+
* each value corresponding to the promise at the same index in the `promises` array. If any of
|
6920
6947
|
* the promises is resolved with a rejection, this resulting promise will be resolved with the
|
6921
6948
|
* same rejection.
|
6922
6949
|
*/
|
@@ -6985,24 +7012,12 @@ function $RouteProvider(){
|
|
6985
7012
|
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
|
6986
7013
|
* created scope or the name of a {@link angular.Module#controller registered controller}
|
6987
7014
|
* if passed as a string.
|
6988
|
-
* - `template` – `{string
|
6989
|
-
*
|
7015
|
+
* - `template` – `{string=}` – html template as a string that should be used by
|
7016
|
+
* {@link ng.directive:ngView ngView} or
|
6990
7017
|
* {@link ng.directive:ngInclude ngInclude} directives.
|
6991
|
-
*
|
6992
|
-
*
|
6993
|
-
*
|
6994
|
-
*
|
6995
|
-
* - `{Array.<Object>}` - route parameters extracted from the current
|
6996
|
-
* `$location.path()` by applying the current route
|
6997
|
-
*
|
6998
|
-
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
6999
|
-
* template that should be used by {@link ng.directive:ngView ngView}.
|
7000
|
-
*
|
7001
|
-
* If `templateUrl` is a function, it will be called with the following parameters:
|
7002
|
-
*
|
7003
|
-
* - `{Array.<Object>}` - route parameters extracted from the current
|
7004
|
-
* `$location.path()` by applying the current route
|
7005
|
-
*
|
7018
|
+
* this property takes precedence over `templateUrl`.
|
7019
|
+
* - `templateUrl` – `{string=}` – path to an html template that should be used by
|
7020
|
+
* {@link ng.directive:ngView ngView}.
|
7006
7021
|
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
7007
7022
|
* be injected into the controller. If any of these dependencies are promises, they will be
|
7008
7023
|
* resolved and converted to a value before the controller is instantiated and the
|
@@ -7357,18 +7372,9 @@ function $RouteProvider(){
|
|
7357
7372
|
values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
|
7358
7373
|
});
|
7359
7374
|
if (isDefined(template = next.template)) {
|
7360
|
-
if (isFunction(template)) {
|
7361
|
-
template = template(next.params);
|
7362
|
-
}
|
7363
7375
|
} else if (isDefined(template = next.templateUrl)) {
|
7364
|
-
|
7365
|
-
|
7366
|
-
}
|
7367
|
-
if (isDefined(template)) {
|
7368
|
-
next.loadedTemplateUrl = template;
|
7369
|
-
template = $http.get(template, {cache: $templateCache}).
|
7370
|
-
then(function(response) { return response.data; });
|
7371
|
-
}
|
7376
|
+
template = $http.get(template, {cache: $templateCache}).
|
7377
|
+
then(function(response) { return response.data; });
|
7372
7378
|
}
|
7373
7379
|
if (isDefined(template)) {
|
7374
7380
|
keys.push('$template');
|
@@ -7606,6 +7612,7 @@ function $RootScopeProvider(){
|
|
7606
7612
|
this.$$destroyed = false;
|
7607
7613
|
this.$$asyncQueue = [];
|
7608
7614
|
this.$$listeners = {};
|
7615
|
+
this.$$isolateBindings = {};
|
7609
7616
|
}
|
7610
7617
|
|
7611
7618
|
/**
|
@@ -7665,6 +7672,7 @@ function $RootScopeProvider(){
|
|
7665
7672
|
child['this'] = child;
|
7666
7673
|
child.$$listeners = {};
|
7667
7674
|
child.$parent = this;
|
7675
|
+
child.$$asyncQueue = [];
|
7668
7676
|
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
|
7669
7677
|
child.$$prevSibling = this.$$childTail;
|
7670
7678
|
if (this.$$childHead) {
|
@@ -7831,7 +7839,7 @@ function $RootScopeProvider(){
|
|
7831
7839
|
$digest: function() {
|
7832
7840
|
var watch, value, last,
|
7833
7841
|
watchers,
|
7834
|
-
asyncQueue
|
7842
|
+
asyncQueue,
|
7835
7843
|
length,
|
7836
7844
|
dirty, ttl = TTL,
|
7837
7845
|
next, current, target = this,
|
@@ -7840,19 +7848,18 @@ function $RootScopeProvider(){
|
|
7840
7848
|
|
7841
7849
|
beginPhase('$digest');
|
7842
7850
|
|
7843
|
-
do {
|
7851
|
+
do {
|
7844
7852
|
dirty = false;
|
7845
7853
|
current = target;
|
7846
|
-
|
7847
|
-
|
7848
|
-
|
7849
|
-
|
7850
|
-
|
7851
|
-
|
7854
|
+
do {
|
7855
|
+
asyncQueue = current.$$asyncQueue;
|
7856
|
+
while(asyncQueue.length) {
|
7857
|
+
try {
|
7858
|
+
current.$eval(asyncQueue.shift());
|
7859
|
+
} catch (e) {
|
7860
|
+
$exceptionHandler(e);
|
7861
|
+
}
|
7852
7862
|
}
|
7853
|
-
}
|
7854
|
-
|
7855
|
-
do { // "traverse the scopes" loop
|
7856
7863
|
if ((watchers = current.$$watchers)) {
|
7857
7864
|
// process our watches
|
7858
7865
|
length = watchers.length;
|
@@ -8087,10 +8094,6 @@ function $RootScopeProvider(){
|
|
8087
8094
|
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
|
8088
8095
|
* event life cycle.
|
8089
8096
|
*
|
8090
|
-
* @param {string} name Event name to listen on.
|
8091
|
-
* @param {function(event)} listener Function to call when the event is emitted.
|
8092
|
-
* @returns {function()} Returns a deregistration function for this listener.
|
8093
|
-
*
|
8094
8097
|
* The event listener function format is: `function(event, args...)`. The `event` object
|
8095
8098
|
* passed into the listener has the following attributes:
|
8096
8099
|
*
|
@@ -8101,6 +8104,10 @@ function $RootScopeProvider(){
|
|
8101
8104
|
* propagation (available only for events that were `$emit`-ed).
|
8102
8105
|
* - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
|
8103
8106
|
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
|
8107
|
+
*
|
8108
|
+
* @param {string} name Event name to listen on.
|
8109
|
+
* @param {function(event, args...)} listener Function to call when the event is emitted.
|
8110
|
+
* @returns {function()} Returns a deregistration function for this listener.
|
8104
8111
|
*/
|
8105
8112
|
$on: function(name, listener) {
|
8106
8113
|
var namedListeners = this.$$listeners[name];
|
@@ -8278,7 +8285,7 @@ function $RootScopeProvider(){
|
|
8278
8285
|
|
8279
8286
|
/**
|
8280
8287
|
* function used as an initial value for watchers.
|
8281
|
-
* because it's
|
8288
|
+
* because it's unique we can easily tell it apart from other values
|
8282
8289
|
*/
|
8283
8290
|
function initWatchVal() {}
|
8284
8291
|
}];
|
@@ -8289,7 +8296,6 @@ function $RootScopeProvider(){
|
|
8289
8296
|
*
|
8290
8297
|
* @name ng.$sniffer
|
8291
8298
|
* @requires $window
|
8292
|
-
* @requires $document
|
8293
8299
|
*
|
8294
8300
|
* @property {boolean} history Does the browser support html5 history api ?
|
8295
8301
|
* @property {boolean} hashchange Does the browser support hashchange event ?
|
@@ -8298,10 +8304,9 @@ function $RootScopeProvider(){
|
|
8298
8304
|
* This is very simple implementation of testing browser's features.
|
8299
8305
|
*/
|
8300
8306
|
function $SnifferProvider() {
|
8301
|
-
this.$get = ['$window',
|
8307
|
+
this.$get = ['$window', function($window) {
|
8302
8308
|
var eventSupport = {},
|
8303
|
-
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1])
|
8304
|
-
document = $document[0];
|
8309
|
+
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
|
8305
8310
|
|
8306
8311
|
return {
|
8307
8312
|
// Android has history.pushState, but it does not update location correctly
|
@@ -8311,7 +8316,7 @@ function $SnifferProvider() {
|
|
8311
8316
|
history: !!($window.history && $window.history.pushState && !(android < 4)),
|
8312
8317
|
hashchange: 'onhashchange' in $window &&
|
8313
8318
|
// IE8 compatible mode lies
|
8314
|
-
(
|
8319
|
+
(!$window.document.documentMode || $window.document.documentMode > 7),
|
8315
8320
|
hasEvent: function(event) {
|
8316
8321
|
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
|
8317
8322
|
// it. In particular the event is not fired when backspace or delete key are pressed or
|
@@ -8319,13 +8324,14 @@ function $SnifferProvider() {
|
|
8319
8324
|
if (event == 'input' && msie == 9) return false;
|
8320
8325
|
|
8321
8326
|
if (isUndefined(eventSupport[event])) {
|
8322
|
-
var divElm = document.createElement('div');
|
8327
|
+
var divElm = $window.document.createElement('div');
|
8323
8328
|
eventSupport[event] = 'on' + event in divElm;
|
8324
8329
|
}
|
8325
8330
|
|
8326
8331
|
return eventSupport[event];
|
8327
8332
|
},
|
8328
|
-
|
8333
|
+
// TODO(i): currently there is no way to feature detect CSP without triggering alerts
|
8334
|
+
csp: false
|
8329
8335
|
};
|
8330
8336
|
}];
|
8331
8337
|
}
|
@@ -8386,43 +8392,6 @@ function parseHeaders(headers) {
|
|
8386
8392
|
}
|
8387
8393
|
|
8388
8394
|
|
8389
|
-
var IS_SAME_DOMAIN_URL_MATCH = /^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/;
|
8390
|
-
|
8391
|
-
|
8392
|
-
/**
|
8393
|
-
* Parse a request and location URL and determine whether this is a same-domain request.
|
8394
|
-
*
|
8395
|
-
* @param {string} requestUrl The url of the request.
|
8396
|
-
* @param {string} locationUrl The current browser location url.
|
8397
|
-
* @returns {boolean} Whether the request is for the same domain.
|
8398
|
-
*/
|
8399
|
-
function isSameDomain(requestUrl, locationUrl) {
|
8400
|
-
var match = IS_SAME_DOMAIN_URL_MATCH.exec(requestUrl);
|
8401
|
-
// if requestUrl is relative, the regex does not match.
|
8402
|
-
if (match == null) return true;
|
8403
|
-
|
8404
|
-
var domain1 = {
|
8405
|
-
protocol: match[2],
|
8406
|
-
host: match[4],
|
8407
|
-
port: int(match[6]) || DEFAULT_PORTS[match[2]] || null,
|
8408
|
-
// IE8 sets unmatched groups to '' instead of undefined.
|
8409
|
-
relativeProtocol: match[2] === undefined || match[2] === ''
|
8410
|
-
};
|
8411
|
-
|
8412
|
-
match = URL_MATCH.exec(locationUrl);
|
8413
|
-
var domain2 = {
|
8414
|
-
protocol: match[1],
|
8415
|
-
host: match[3],
|
8416
|
-
port: int(match[5]) || DEFAULT_PORTS[match[1]] || null
|
8417
|
-
};
|
8418
|
-
|
8419
|
-
return (domain1.protocol == domain2.protocol || domain1.relativeProtocol) &&
|
8420
|
-
domain1.host == domain2.host &&
|
8421
|
-
(domain1.port == domain2.port || (domain1.relativeProtocol &&
|
8422
|
-
domain2.port == DEFAULT_PORTS[domain2.protocol]));
|
8423
|
-
}
|
8424
|
-
|
8425
|
-
|
8426
8395
|
/**
|
8427
8396
|
* Returns a function that provides access to parsed headers.
|
8428
8397
|
*
|
@@ -8482,7 +8451,7 @@ function $HttpProvider() {
|
|
8482
8451
|
JSON_END = /[\}\]]\s*$/,
|
8483
8452
|
PROTECTION_PREFIX = /^\)\]\}',?\n/;
|
8484
8453
|
|
8485
|
-
var
|
8454
|
+
var $config = this.defaults = {
|
8486
8455
|
// transform incoming response data
|
8487
8456
|
transformResponse: [function(data) {
|
8488
8457
|
if (isString(data)) {
|
@@ -8502,7 +8471,8 @@ function $HttpProvider() {
|
|
8502
8471
|
// default headers
|
8503
8472
|
headers: {
|
8504
8473
|
common: {
|
8505
|
-
'Accept': 'application/json, text/plain, */*'
|
8474
|
+
'Accept': 'application/json, text/plain, */*',
|
8475
|
+
'X-Requested-With': 'XMLHttpRequest'
|
8506
8476
|
},
|
8507
8477
|
post: {'Content-Type': 'application/json;charset=utf-8'},
|
8508
8478
|
put: {'Content-Type': 'application/json;charset=utf-8'}
|
@@ -8608,6 +8578,7 @@ function $HttpProvider() {
|
|
8608
8578
|
*
|
8609
8579
|
* - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
|
8610
8580
|
* - `Accept: application/json, text/plain, * / *`
|
8581
|
+
* - `X-Requested-With: XMLHttpRequest`
|
8611
8582
|
* - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
|
8612
8583
|
* - `Content-Type: application/json`
|
8613
8584
|
* - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
|
@@ -8742,7 +8713,7 @@ function $HttpProvider() {
|
|
8742
8713
|
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
|
8743
8714
|
* called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
|
8744
8715
|
* runs on your domain could read the cookie, your server can be assured that the XHR came from
|
8745
|
-
* JavaScript running on your domain.
|
8716
|
+
* JavaScript running on your domain.
|
8746
8717
|
*
|
8747
8718
|
* To take advantage of this, your server needs to set a token in a JavaScript readable session
|
8748
8719
|
* cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
|
@@ -8776,8 +8747,6 @@ function $HttpProvider() {
|
|
8776
8747
|
* - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
|
8777
8748
|
* XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
|
8778
8749
|
* requests with credentials} for more information.
|
8779
|
-
* - **responseType** - `{string}` - see {@link
|
8780
|
-
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
|
8781
8750
|
*
|
8782
8751
|
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
|
8783
8752
|
* standard `then` method and two http specific methods: `success` and `error`. The `then`
|
@@ -8870,12 +8839,10 @@ function $HttpProvider() {
|
|
8870
8839
|
function $http(config) {
|
8871
8840
|
config.method = uppercase(config.method);
|
8872
8841
|
|
8873
|
-
var reqTransformFn = config.transformRequest ||
|
8874
|
-
respTransformFn = config.transformResponse ||
|
8875
|
-
defHeaders =
|
8876
|
-
|
8877
|
-
$browser.cookies()['XSRF-TOKEN'] : undefined,
|
8878
|
-
reqHeaders = extend({'X-XSRF-TOKEN': xsrfToken},
|
8842
|
+
var reqTransformFn = config.transformRequest || $config.transformRequest,
|
8843
|
+
respTransformFn = config.transformResponse || $config.transformResponse,
|
8844
|
+
defHeaders = $config.headers,
|
8845
|
+
reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
|
8879
8846
|
defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
|
8880
8847
|
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
|
8881
8848
|
promise;
|
@@ -8885,10 +8852,6 @@ function $HttpProvider() {
|
|
8885
8852
|
delete reqHeaders['Content-Type'];
|
8886
8853
|
}
|
8887
8854
|
|
8888
|
-
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
|
8889
|
-
config.withCredentials = defaults.withCredentials;
|
8890
|
-
}
|
8891
|
-
|
8892
8855
|
// send request
|
8893
8856
|
promise = sendReq(config, reqData, reqHeaders);
|
8894
8857
|
|
@@ -9020,11 +8983,11 @@ function $HttpProvider() {
|
|
9020
8983
|
*
|
9021
8984
|
* @description
|
9022
8985
|
* Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
|
9023
|
-
* default headers
|
8986
|
+
* default headers as well as request and response transformations.
|
9024
8987
|
*
|
9025
8988
|
* See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
|
9026
8989
|
*/
|
9027
|
-
$http.defaults =
|
8990
|
+
$http.defaults = $config;
|
9028
8991
|
|
9029
8992
|
|
9030
8993
|
return $http;
|
@@ -9059,7 +9022,7 @@ function $HttpProvider() {
|
|
9059
9022
|
* Makes the request
|
9060
9023
|
*
|
9061
9024
|
* !!! ACCESSES CLOSURE VARS:
|
9062
|
-
* $httpBackend,
|
9025
|
+
* $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
|
9063
9026
|
*/
|
9064
9027
|
function sendReq(config, reqData, reqHeaders) {
|
9065
9028
|
var deferred = $q.defer(),
|
@@ -9100,7 +9063,7 @@ function $HttpProvider() {
|
|
9100
9063
|
// if we won't have the response in cache, send the request to the backend
|
9101
9064
|
if (!cachedResp) {
|
9102
9065
|
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
|
9103
|
-
config.withCredentials
|
9066
|
+
config.withCredentials);
|
9104
9067
|
}
|
9105
9068
|
|
9106
9069
|
return promise;
|
@@ -9155,15 +9118,10 @@ function $HttpProvider() {
|
|
9155
9118
|
var parts = [];
|
9156
9119
|
forEachSorted(params, function(value, key) {
|
9157
9120
|
if (value == null || value == undefined) return;
|
9158
|
-
if (
|
9159
|
-
|
9160
|
-
|
9161
|
-
|
9162
|
-
v = toJson(v);
|
9163
|
-
}
|
9164
|
-
parts.push(encodeURIComponent(key) + '=' +
|
9165
|
-
encodeURIComponent(v));
|
9166
|
-
});
|
9121
|
+
if (isObject(value)) {
|
9122
|
+
value = toJson(value);
|
9123
|
+
}
|
9124
|
+
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
|
9167
9125
|
});
|
9168
9126
|
return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
|
9169
9127
|
}
|
@@ -9205,7 +9163,7 @@ function $HttpBackendProvider() {
|
|
9205
9163
|
|
9206
9164
|
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
|
9207
9165
|
// TODO(vojta): fix the signature
|
9208
|
-
return function(method, url, post, callback, headers, timeout, withCredentials
|
9166
|
+
return function(method, url, post, callback, headers, timeout, withCredentials) {
|
9209
9167
|
$browser.$$incOutstandingRequestCount();
|
9210
9168
|
url = url || $browser.url();
|
9211
9169
|
|
@@ -9238,8 +9196,30 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
9238
9196
|
// always async
|
9239
9197
|
xhr.onreadystatechange = function() {
|
9240
9198
|
if (xhr.readyState == 4) {
|
9241
|
-
|
9242
|
-
|
9199
|
+
var responseHeaders = xhr.getAllResponseHeaders();
|
9200
|
+
|
9201
|
+
// TODO(vojta): remove once Firefox 21 gets released.
|
9202
|
+
// begin: workaround to overcome Firefox CORS http response headers bug
|
9203
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=608735
|
9204
|
+
// Firefox already patched in nightly. Should land in Firefox 21.
|
9205
|
+
|
9206
|
+
// CORS "simple response headers" http://www.w3.org/TR/cors/
|
9207
|
+
var value,
|
9208
|
+
simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
|
9209
|
+
"Expires", "Last-Modified", "Pragma"];
|
9210
|
+
if (!responseHeaders) {
|
9211
|
+
responseHeaders = "";
|
9212
|
+
forEach(simpleHeaders, function (header) {
|
9213
|
+
var value = xhr.getResponseHeader(header);
|
9214
|
+
if (value) {
|
9215
|
+
responseHeaders += header + ": " + value + "\n";
|
9216
|
+
}
|
9217
|
+
});
|
9218
|
+
}
|
9219
|
+
// end of the workaround.
|
9220
|
+
|
9221
|
+
completeRequest(callback, status || xhr.status, xhr.responseText,
|
9222
|
+
responseHeaders);
|
9243
9223
|
}
|
9244
9224
|
};
|
9245
9225
|
|
@@ -9247,10 +9227,6 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
|
9247
9227
|
xhr.withCredentials = true;
|
9248
9228
|
}
|
9249
9229
|
|
9250
|
-
if (responseType) {
|
9251
|
-
xhr.responseType = responseType;
|
9252
|
-
}
|
9253
|
-
|
9254
9230
|
xhr.send(post || '');
|
9255
9231
|
|
9256
9232
|
if (timeout > 0) {
|
@@ -9642,7 +9618,7 @@ function $FilterProvider($provide) {
|
|
9642
9618
|
*/
|
9643
9619
|
function filterFilter() {
|
9644
9620
|
return function(array, expression) {
|
9645
|
-
if (!(array
|
9621
|
+
if (!isArray(array)) return array;
|
9646
9622
|
var predicates = [];
|
9647
9623
|
predicates.check = function(value) {
|
9648
9624
|
for (var j = 0; j < predicates.length; j++) {
|
@@ -9891,7 +9867,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
|
9891
9867
|
fraction += '0';
|
9892
9868
|
}
|
9893
9869
|
|
9894
|
-
if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
|
9870
|
+
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
|
9895
9871
|
}
|
9896
9872
|
|
9897
9873
|
parts.push(isNegative ? pattern.negPre : pattern.posPre);
|
@@ -9934,8 +9910,12 @@ function dateStrGetter(name, shortForm) {
|
|
9934
9910
|
}
|
9935
9911
|
|
9936
9912
|
function timeZoneGetter(date) {
|
9937
|
-
var
|
9938
|
-
|
9913
|
+
var zone = -1 * date.getTimezoneOffset();
|
9914
|
+
var paddedZone = (zone >= 0) ? "+" : "";
|
9915
|
+
|
9916
|
+
paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2);
|
9917
|
+
|
9918
|
+
return paddedZone;
|
9939
9919
|
}
|
9940
9920
|
|
9941
9921
|
function ampmGetter(date, formats) {
|
@@ -10021,7 +10001,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10021
10001
|
*
|
10022
10002
|
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
|
10023
10003
|
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
|
10024
|
-
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
|
10004
|
+
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
|
10005
|
+
* specified in the string input, the time is considered to be in the local timezone.
|
10025
10006
|
* @param {string=} format Formatting rules (see Description). If not specified,
|
10026
10007
|
* `mediumDate` is used.
|
10027
10008
|
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
|
@@ -10041,7 +10022,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
|
10041
10022
|
expect(binding("1288323623006 | date:'medium'")).
|
10042
10023
|
toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
|
10043
10024
|
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
|
10044
|
-
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2}
|
10025
|
+
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
|
10045
10026
|
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
|
10046
10027
|
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
|
10047
10028
|
});
|
@@ -10053,22 +10034,18 @@ function dateFilter($locale) {
|
|
10053
10034
|
|
10054
10035
|
|
10055
10036
|
var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
|
10056
|
-
|
10057
|
-
function jsonStringToDate(string) {
|
10037
|
+
function jsonStringToDate(string){
|
10058
10038
|
var match;
|
10059
10039
|
if (match = string.match(R_ISO8601_STR)) {
|
10060
10040
|
var date = new Date(0),
|
10061
10041
|
tzHour = 0,
|
10062
|
-
tzMin = 0
|
10063
|
-
dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
|
10064
|
-
timeSetter = match[8] ? date.setUTCHours : date.setHours;
|
10065
|
-
|
10042
|
+
tzMin = 0;
|
10066
10043
|
if (match[9]) {
|
10067
10044
|
tzHour = int(match[9] + match[10]);
|
10068
10045
|
tzMin = int(match[9] + match[11]);
|
10069
10046
|
}
|
10070
|
-
|
10071
|
-
|
10047
|
+
date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
|
10048
|
+
date.setUTCHours(int(match[4]||0) - tzHour, int(match[5]||0) - tzMin, int(match[6]||0), int(match[7]||0));
|
10072
10049
|
return date;
|
10073
10050
|
}
|
10074
10051
|
return string;
|
@@ -10182,20 +10159,20 @@ var uppercaseFilter = valueFn(uppercase);
|
|
10182
10159
|
* @function
|
10183
10160
|
*
|
10184
10161
|
* @description
|
10185
|
-
* Creates a new array
|
10186
|
-
* are taken from either the beginning or the end of the source array
|
10187
|
-
*
|
10162
|
+
* Creates a new array containing only a specified number of elements in an array. The elements
|
10163
|
+
* are taken from either the beginning or the end of the source array, as specified by the
|
10164
|
+
* value and sign (positive or negative) of `limit`.
|
10188
10165
|
*
|
10189
10166
|
* Note: This function is used to augment the `Array` type in Angular expressions. See
|
10190
10167
|
* {@link ng.$filter} for more information about Angular arrays.
|
10191
10168
|
*
|
10192
|
-
* @param {Array
|
10193
|
-
* @param {string|
|
10194
|
-
*
|
10195
|
-
* If the number is negative, `limit` number of items from the end of the source array
|
10196
|
-
*
|
10197
|
-
* @returns {Array
|
10198
|
-
*
|
10169
|
+
* @param {Array} array Source array to be limited.
|
10170
|
+
* @param {string|Number} limit The length of the returned array. If the `limit` number is
|
10171
|
+
* positive, `limit` number of items from the beginning of the source array are copied.
|
10172
|
+
* If the number is negative, `limit` number of items from the end of the source array are
|
10173
|
+
* copied. The `limit` will be trimmed if it exceeds `array.length`
|
10174
|
+
* @returns {Array} A new sub-array of length `limit` or less if input array had less than `limit`
|
10175
|
+
* elements.
|
10199
10176
|
*
|
10200
10177
|
* @example
|
10201
10178
|
<doc:example>
|
@@ -10203,76 +10180,59 @@ var uppercaseFilter = valueFn(uppercase);
|
|
10203
10180
|
<script>
|
10204
10181
|
function Ctrl($scope) {
|
10205
10182
|
$scope.numbers = [1,2,3,4,5,6,7,8,9];
|
10206
|
-
$scope.
|
10207
|
-
$scope.numLimit = 3;
|
10208
|
-
$scope.letterLimit = 3;
|
10183
|
+
$scope.limit = 3;
|
10209
10184
|
}
|
10210
10185
|
</script>
|
10211
10186
|
<div ng-controller="Ctrl">
|
10212
|
-
Limit {{numbers}} to: <input type="integer" ng-model="
|
10213
|
-
<p>Output
|
10214
|
-
Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
|
10215
|
-
<p>Output letters: {{ letters | limitTo:letterLimit }}</p>
|
10187
|
+
Limit {{numbers}} to: <input type="integer" ng-model="limit">
|
10188
|
+
<p>Output: {{ numbers | limitTo:limit }}</p>
|
10216
10189
|
</div>
|
10217
10190
|
</doc:source>
|
10218
10191
|
<doc:scenario>
|
10219
|
-
it('should limit the
|
10220
|
-
expect(element('.doc-example-live input[ng-model=
|
10221
|
-
expect(
|
10222
|
-
expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
|
10223
|
-
expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
|
10192
|
+
it('should limit the numer array to first three items', function() {
|
10193
|
+
expect(element('.doc-example-live input[ng-model=limit]').val()).toBe('3');
|
10194
|
+
expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3]');
|
10224
10195
|
});
|
10225
10196
|
|
10226
10197
|
it('should update the output when -3 is entered', function() {
|
10227
|
-
input('
|
10228
|
-
|
10229
|
-
expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
|
10230
|
-
expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
|
10198
|
+
input('limit').enter(-3);
|
10199
|
+
expect(binding('numbers | limitTo:limit')).toEqual('[7,8,9]');
|
10231
10200
|
});
|
10232
10201
|
|
10233
10202
|
it('should not exceed the maximum size of input array', function() {
|
10234
|
-
input('
|
10235
|
-
|
10236
|
-
expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
|
10237
|
-
expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
|
10203
|
+
input('limit').enter(100);
|
10204
|
+
expect(binding('numbers | limitTo:limit')).toEqual('[1,2,3,4,5,6,7,8,9]');
|
10238
10205
|
});
|
10239
10206
|
</doc:scenario>
|
10240
10207
|
</doc:example>
|
10241
10208
|
*/
|
10242
10209
|
function limitToFilter(){
|
10243
|
-
return function(
|
10244
|
-
if (!
|
10245
|
-
|
10210
|
+
return function(array, limit) {
|
10211
|
+
if (!(array instanceof Array)) return array;
|
10246
10212
|
limit = int(limit);
|
10247
|
-
|
10248
|
-
if (isString(input)) {
|
10249
|
-
//NaN check on limit
|
10250
|
-
if (limit) {
|
10251
|
-
return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
|
10252
|
-
} else {
|
10253
|
-
return "";
|
10254
|
-
}
|
10255
|
-
}
|
10256
|
-
|
10257
10213
|
var out = [],
|
10258
10214
|
i, n;
|
10259
10215
|
|
10216
|
+
// check that array is iterable
|
10217
|
+
if (!array || !(array instanceof Array))
|
10218
|
+
return out;
|
10219
|
+
|
10260
10220
|
// if abs(limit) exceeds maximum length, trim it
|
10261
|
-
if (limit >
|
10262
|
-
limit =
|
10263
|
-
else if (limit < -
|
10264
|
-
limit = -
|
10221
|
+
if (limit > array.length)
|
10222
|
+
limit = array.length;
|
10223
|
+
else if (limit < -array.length)
|
10224
|
+
limit = -array.length;
|
10265
10225
|
|
10266
10226
|
if (limit > 0) {
|
10267
10227
|
i = 0;
|
10268
10228
|
n = limit;
|
10269
10229
|
} else {
|
10270
|
-
i =
|
10271
|
-
n =
|
10230
|
+
i = array.length + limit;
|
10231
|
+
n = array.length;
|
10272
10232
|
}
|
10273
10233
|
|
10274
10234
|
for (; i<n; i++) {
|
10275
|
-
out.push(
|
10235
|
+
out.push(array[i]);
|
10276
10236
|
}
|
10277
10237
|
|
10278
10238
|
return out;
|
@@ -10368,7 +10328,7 @@ function limitToFilter(){
|
|
10368
10328
|
orderByFilter.$inject = ['$parse'];
|
10369
10329
|
function orderByFilter($parse){
|
10370
10330
|
return function(array, sortPredicate, reverseOrder) {
|
10371
|
-
if (!(array
|
10331
|
+
if (!isArray(array)) return array;
|
10372
10332
|
if (!sortPredicate) return array;
|
10373
10333
|
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
|
10374
10334
|
sortPredicate = map(sortPredicate, function(predicate){
|
@@ -10436,15 +10396,25 @@ function ngDirective(directive) {
|
|
10436
10396
|
*
|
10437
10397
|
* The reasoning for this change is to allow easy creation of action links with `ngClick` directive
|
10438
10398
|
* without changing the location or causing page reloads, e.g.:
|
10439
|
-
*
|
10399
|
+
* `<a href="" ng-click="model.$save()">Save</a>`
|
10440
10400
|
*/
|
10441
10401
|
var htmlAnchorDirective = valueFn({
|
10442
10402
|
restrict: 'E',
|
10443
10403
|
compile: function(element, attr) {
|
10444
|
-
|
10445
|
-
|
10446
|
-
|
10447
|
-
|
10404
|
+
|
10405
|
+
if (msie <= 8) {
|
10406
|
+
|
10407
|
+
// turn <a href ng-click="..">link</a> into a stylable link in IE
|
10408
|
+
// but only if it doesn't have name attribute, in which case it's an anchor
|
10409
|
+
if (!attr.href && !attr.name) {
|
10410
|
+
attr.$set('href', '');
|
10411
|
+
}
|
10412
|
+
|
10413
|
+
// add a comment node to anchors to workaround IE bug that causes element content to be reset
|
10414
|
+
// to new attribute content if attribute is updated with value containing @ and element also
|
10415
|
+
// contains value with @
|
10416
|
+
// see issue #1949
|
10417
|
+
element.append(document.createComment('IE fix'));
|
10448
10418
|
}
|
10449
10419
|
|
10450
10420
|
return function(scope, element) {
|
@@ -10524,7 +10494,7 @@ var htmlAnchorDirective = valueFn({
|
|
10524
10494
|
it('should execute ng-click but not reload when no href but name specified', function() {
|
10525
10495
|
element('#link-5').click();
|
10526
10496
|
expect(input('value').val()).toEqual('5');
|
10527
|
-
expect(element('#link-5').attr('href')).toBe(
|
10497
|
+
expect(element('#link-5').attr('href')).toBe(undefined);
|
10528
10498
|
});
|
10529
10499
|
|
10530
10500
|
it('should only change url when only ng-href', function() {
|
@@ -10730,37 +10700,6 @@ var htmlAnchorDirective = valueFn({
|
|
10730
10700
|
* @param {string} expression Angular expression that will be evaluated.
|
10731
10701
|
*/
|
10732
10702
|
|
10733
|
-
/**
|
10734
|
-
* @ngdoc directive
|
10735
|
-
* @name ng.directive:ngOpen
|
10736
|
-
* @restrict A
|
10737
|
-
*
|
10738
|
-
* @description
|
10739
|
-
* The HTML specs do not require browsers to preserve the special attributes such as open.
|
10740
|
-
* (The presence of them means true and absence means false)
|
10741
|
-
* This prevents the angular compiler from correctly retrieving the binding expression.
|
10742
|
-
* To solve this problem, we introduce the `ngOpen` directive.
|
10743
|
-
*
|
10744
|
-
* @example
|
10745
|
-
<doc:example>
|
10746
|
-
<doc:source>
|
10747
|
-
Check me check multiple: <input type="checkbox" ng-model="open"><br/>
|
10748
|
-
<details id="details" ng-open="open">
|
10749
|
-
<summary>Show/Hide me</summary>
|
10750
|
-
</details>
|
10751
|
-
</doc:source>
|
10752
|
-
<doc:scenario>
|
10753
|
-
it('should toggle open', function() {
|
10754
|
-
expect(element('#details').prop('open')).toBeFalsy();
|
10755
|
-
input('open').check();
|
10756
|
-
expect(element('#details').prop('open')).toBeTruthy();
|
10757
|
-
});
|
10758
|
-
</doc:scenario>
|
10759
|
-
</doc:example>
|
10760
|
-
*
|
10761
|
-
* @element DETAILS
|
10762
|
-
* @param {string} expression Angular expression that will be evaluated.
|
10763
|
-
*/
|
10764
10703
|
|
10765
10704
|
var ngAttributeAliasDirectives = {};
|
10766
10705
|
|
@@ -10798,8 +10737,9 @@ forEach(['src', 'href'], function(attrName) {
|
|
10798
10737
|
|
10799
10738
|
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
10800
10739
|
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
|
10801
|
-
// to set the property as well to achieve the desired effect
|
10802
|
-
|
10740
|
+
// to set the property as well to achieve the desired effect.
|
10741
|
+
// we use attr[attrName] value since $set can sanitize the url.
|
10742
|
+
if (msie) element.prop(attrName, attr[attrName]);
|
10803
10743
|
});
|
10804
10744
|
}
|
10805
10745
|
};
|
@@ -10810,8 +10750,7 @@ var nullFormCtrl = {
|
|
10810
10750
|
$addControl: noop,
|
10811
10751
|
$removeControl: noop,
|
10812
10752
|
$setValidity: noop,
|
10813
|
-
$setDirty: noop
|
10814
|
-
$setPristine: noop
|
10753
|
+
$setDirty: noop
|
10815
10754
|
};
|
10816
10755
|
|
10817
10756
|
/**
|
@@ -10843,8 +10782,7 @@ function FormController(element, attrs) {
|
|
10843
10782
|
var form = this,
|
10844
10783
|
parentForm = element.parent().controller('form') || nullFormCtrl,
|
10845
10784
|
invalidCount = 0, // used to easily determine if we are valid
|
10846
|
-
errors = form.$error = {}
|
10847
|
-
controls = [];
|
10785
|
+
errors = form.$error = {};
|
10848
10786
|
|
10849
10787
|
// init state
|
10850
10788
|
form.$name = attrs.name;
|
@@ -10868,8 +10806,6 @@ function FormController(element, attrs) {
|
|
10868
10806
|
}
|
10869
10807
|
|
10870
10808
|
form.$addControl = function(control) {
|
10871
|
-
controls.push(control);
|
10872
|
-
|
10873
10809
|
if (control.$name && !form.hasOwnProperty(control.$name)) {
|
10874
10810
|
form[control.$name] = control;
|
10875
10811
|
}
|
@@ -10882,8 +10818,6 @@ function FormController(element, attrs) {
|
|
10882
10818
|
forEach(errors, function(queue, validationToken) {
|
10883
10819
|
form.$setValidity(validationToken, true, control);
|
10884
10820
|
});
|
10885
|
-
|
10886
|
-
arrayRemove(controls, control);
|
10887
10821
|
};
|
10888
10822
|
|
10889
10823
|
form.$setValidity = function(validationToken, isValid, control) {
|
@@ -10931,29 +10865,6 @@ function FormController(element, attrs) {
|
|
10931
10865
|
parentForm.$setDirty();
|
10932
10866
|
};
|
10933
10867
|
|
10934
|
-
/**
|
10935
|
-
* @ngdoc function
|
10936
|
-
* @name ng.directive:form.FormController#$setPristine
|
10937
|
-
* @methodOf ng.directive:form.FormController
|
10938
|
-
*
|
10939
|
-
* @description
|
10940
|
-
* Sets the form to its pristine state.
|
10941
|
-
*
|
10942
|
-
* This method can be called to remove the 'ng-dirty' class and set the form to its pristine
|
10943
|
-
* state (ng-pristine class). This method will also propagate to all the controls contained
|
10944
|
-
* in this form.
|
10945
|
-
*
|
10946
|
-
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
|
10947
|
-
* saving or resetting it.
|
10948
|
-
*/
|
10949
|
-
form.$setPristine = function () {
|
10950
|
-
element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
|
10951
|
-
form.$dirty = false;
|
10952
|
-
form.$pristine = true;
|
10953
|
-
forEach(controls, function(control) {
|
10954
|
-
control.$setPristine();
|
10955
|
-
});
|
10956
|
-
};
|
10957
10868
|
}
|
10958
10869
|
|
10959
10870
|
|
@@ -11150,8 +11061,6 @@ var inputType = {
|
|
11150
11061
|
* patterns defined as scope expressions.
|
11151
11062
|
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
11152
11063
|
* interaction with the input element.
|
11153
|
-
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trimming the
|
11154
|
-
* input.
|
11155
11064
|
*
|
11156
11065
|
* @example
|
11157
11066
|
<doc:example>
|
@@ -11159,12 +11068,12 @@ var inputType = {
|
|
11159
11068
|
<script>
|
11160
11069
|
function Ctrl($scope) {
|
11161
11070
|
$scope.text = 'guest';
|
11162
|
-
$scope.word = /^\
|
11071
|
+
$scope.word = /^\w*$/;
|
11163
11072
|
}
|
11164
11073
|
</script>
|
11165
11074
|
<form name="myForm" ng-controller="Ctrl">
|
11166
11075
|
Single word: <input type="text" name="input" ng-model="text"
|
11167
|
-
ng-pattern="word" required
|
11076
|
+
ng-pattern="word" required>
|
11168
11077
|
<span class="error" ng-show="myForm.input.$error.required">
|
11169
11078
|
Required!</span>
|
11170
11079
|
<span class="error" ng-show="myForm.input.$error.pattern">
|
@@ -11193,12 +11102,6 @@ var inputType = {
|
|
11193
11102
|
input('text').enter('hello world');
|
11194
11103
|
expect(binding('myForm.input.$valid')).toEqual('false');
|
11195
11104
|
});
|
11196
|
-
|
11197
|
-
it('should not be trimmed', function() {
|
11198
|
-
input('text').enter('untrimmed ');
|
11199
|
-
expect(binding('text')).toEqual('untrimmed ');
|
11200
|
-
expect(binding('myForm.input.$valid')).toEqual('true');
|
11201
|
-
});
|
11202
11105
|
</doc:scenario>
|
11203
11106
|
</doc:example>
|
11204
11107
|
*/
|
@@ -11512,14 +11415,7 @@ function isEmpty(value) {
|
|
11512
11415
|
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
11513
11416
|
|
11514
11417
|
var listener = function() {
|
11515
|
-
var value = element.val();
|
11516
|
-
|
11517
|
-
// By default we will trim the value
|
11518
|
-
// If the attribute ng-trim exists we will avoid trimming
|
11519
|
-
// e.g. <input ng-model="foo" ng-trim="false">
|
11520
|
-
if (toBoolean(attr.ngTrim || 'T')) {
|
11521
|
-
value = trim(value);
|
11522
|
-
}
|
11418
|
+
var value = trim(element.val());
|
11523
11419
|
|
11524
11420
|
if (ctrl.$viewValue !== value) {
|
11525
11421
|
scope.$apply(function() {
|
@@ -12100,22 +11996,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
|
12100
11996
|
parentForm.$setValidity(validationErrorKey, isValid, this);
|
12101
11997
|
};
|
12102
11998
|
|
12103
|
-
/**
|
12104
|
-
* @ngdoc function
|
12105
|
-
* @name ng.directive:ngModel.NgModelController#$setPristine
|
12106
|
-
* @methodOf ng.directive:ngModel.NgModelController
|
12107
|
-
*
|
12108
|
-
* @description
|
12109
|
-
* Sets the control to its pristine state.
|
12110
|
-
*
|
12111
|
-
* This method can be called to remove the 'ng-dirty' class and set the control to its pristine
|
12112
|
-
* state (ng-pristine class).
|
12113
|
-
*/
|
12114
|
-
this.$setPristine = function () {
|
12115
|
-
this.$dirty = false;
|
12116
|
-
this.$pristine = true;
|
12117
|
-
$element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
|
12118
|
-
};
|
12119
11999
|
|
12120
12000
|
/**
|
12121
12001
|
* @ngdoc function
|
@@ -12564,6 +12444,7 @@ var ngBindHtmlUnsafeDirective = [function() {
|
|
12564
12444
|
function classDirective(name, selector) {
|
12565
12445
|
name = 'ngClass' + name;
|
12566
12446
|
return ngDirective(function(scope, element, attr) {
|
12447
|
+
var oldVal = undefined;
|
12567
12448
|
|
12568
12449
|
scope.$watch(attr[name], ngClassWatchAction, true);
|
12569
12450
|
|
@@ -12587,13 +12468,14 @@ function classDirective(name, selector) {
|
|
12587
12468
|
}
|
12588
12469
|
|
12589
12470
|
|
12590
|
-
function ngClassWatchAction(newVal
|
12471
|
+
function ngClassWatchAction(newVal) {
|
12591
12472
|
if (selector === true || scope.$index % 2 === selector) {
|
12592
12473
|
if (oldVal && (newVal !== oldVal)) {
|
12593
12474
|
removeClass(oldVal);
|
12594
12475
|
}
|
12595
12476
|
addClass(newVal);
|
12596
12477
|
}
|
12478
|
+
oldVal = newVal;
|
12597
12479
|
}
|
12598
12480
|
|
12599
12481
|
|
@@ -12626,7 +12508,7 @@ function classDirective(name, selector) {
|
|
12626
12508
|
*
|
12627
12509
|
* The directive won't add duplicate classes if a particular class was already set.
|
12628
12510
|
*
|
12629
|
-
* When the expression changes, the previously added classes are removed and only then the
|
12511
|
+
* When the expression changes, the previously added classes are removed and only then the
|
12630
12512
|
* new classes are added.
|
12631
12513
|
*
|
12632
12514
|
* @element ANY
|
@@ -12986,7 +12868,7 @@ var ngCspDirective = ['$sniffer', function($sniffer) {
|
|
12986
12868
|
*/
|
12987
12869
|
var ngEventDirectives = {};
|
12988
12870
|
forEach(
|
12989
|
-
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave
|
12871
|
+
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
|
12990
12872
|
function(name) {
|
12991
12873
|
var directiveName = directiveNormalize('ng-' + name);
|
12992
12874
|
ngEventDirectives[directiveName] = ['$parse', function($parse) {
|
@@ -13113,38 +12995,6 @@ forEach(
|
|
13113
12995
|
*/
|
13114
12996
|
|
13115
12997
|
|
13116
|
-
/**
|
13117
|
-
* @ngdoc directive
|
13118
|
-
* @name ng.directive:ngKeydown
|
13119
|
-
*
|
13120
|
-
* @description
|
13121
|
-
* Specify custom behavior on keydown event.
|
13122
|
-
*
|
13123
|
-
* @element ANY
|
13124
|
-
* @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
|
13125
|
-
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
13126
|
-
*
|
13127
|
-
* @example
|
13128
|
-
* See {@link ng.directive:ngClick ngClick}
|
13129
|
-
*/
|
13130
|
-
|
13131
|
-
|
13132
|
-
/**
|
13133
|
-
* @ngdoc directive
|
13134
|
-
* @name ng.directive:ngKeyup
|
13135
|
-
*
|
13136
|
-
* @description
|
13137
|
-
* Specify custom behavior on keyup event.
|
13138
|
-
*
|
13139
|
-
* @element ANY
|
13140
|
-
* @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
|
13141
|
-
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
13142
|
-
*
|
13143
|
-
* @example
|
13144
|
-
* See {@link ng.directive:ngClick ngClick}
|
13145
|
-
*/
|
13146
|
-
|
13147
|
-
|
13148
12998
|
/**
|
13149
12999
|
* @ngdoc directive
|
13150
13000
|
* @name ng.directive:ngSubmit
|
@@ -13982,9 +13832,10 @@ var NG_SWITCH = 'ng-switch';
|
|
13982
13832
|
var ngSwitchDirective = valueFn({
|
13983
13833
|
restrict: 'EA',
|
13984
13834
|
require: 'ngSwitch',
|
13985
|
-
|
13835
|
+
// asks for $scope to fool the BC controller module
|
13836
|
+
controller: ['$scope', function ngSwitchController() {
|
13986
13837
|
this.cases = {};
|
13987
|
-
},
|
13838
|
+
}],
|
13988
13839
|
link: function(scope, element, attr, ctrl) {
|
13989
13840
|
var watchExpr = attr.ngSwitch || attr.on,
|
13990
13841
|
selectedTransclude,
|
@@ -14235,7 +14086,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|
14235
14086
|
if (current.controller) {
|
14236
14087
|
locals.$scope = lastScope;
|
14237
14088
|
controller = $controller(current.controller, locals);
|
14238
|
-
element.
|
14089
|
+
element.children().data('$ngControllerController', controller);
|
14239
14090
|
}
|
14240
14091
|
|
14241
14092
|
link(lastScope);
|