angular-gem 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|