Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f5e42e882 | |||
| d193c3a25c | |||
| 4da1cc3b81 | |||
| 6de08216e7 | |||
| 3c6e8ce044 | |||
| e51024ed54 | |||
| 04f1ebd470 | |||
| 2e63ab734a | |||
| 6333d65b76 | |||
| 1ce5d216c7 | |||
| 28c166939e | |||
| 14638f4a60 | |||
| 0c1fbdd242 | |||
| 33f7f26558 | |||
| e27eed3ca4 | |||
| 6cbbd96647 | |||
| d0cb69348e | |||
| f15f8df2b4 | |||
| e7662ebc31 | |||
| 8ceed4faf3 | |||
| 6903b5ec4c | |||
| 48e1f5605e | |||
| c5a3d8fc5f | |||
| c61149213b | |||
| ad7200e2c2 | |||
| bea74c0f56 | |||
| bacc3b7e0e | |||
| 8a1eb1625c | |||
| ed27e0ea6a | |||
| f81ff3beb0 | |||
| 720012eab6 | |||
| 3adfe5bda9 | |||
| dc0467879d | |||
| 528d7f9568 | |||
| 636ce70e47 | |||
| 5f5ee0f880 |
@@ -1,3 +1,74 @@
|
||||
<a name="1.4.1"></a>
|
||||
# 1.4.1 hyperionic-illumination (2015-06-16)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- workaround for IE11 MutationObserver
|
||||
([f3b1d0b7](https://github.com/angular/angular.js/commit/f3b1d0b723298a5f8ea21d0704405649cce1b5fc),
|
||||
[#11781](https://github.com/angular/angular.js/issues/11781))
|
||||
- prevent exception when using `watch` as isolated scope binding property in Firefox
|
||||
([a6339d30](https://github.com/angular/angular.js/commit/a6339d30d1379689da5eec9647a953f64821f8b0),
|
||||
[#11627](https://github.com/angular/angular.js/issues/11627))
|
||||
- assign controller return values correctly for multiple directives
|
||||
([8caf1802](https://github.com/angular/angular.js/commit/8caf1802e0e93389dec626ef35e04a302aa6c39d),
|
||||
[#12029](https://github.com/angular/angular.js/issues/12029), [#12036](https://github.com/angular/angular.js/issues/12036))
|
||||
- **$location:** do not get caught in infinite digest in IE9 when redirecting in `$locationChangeSuccess`
|
||||
([91b60226](https://github.com/angular/angular.js/commit/91b602263b96b6fce1331208462e18eb647f4d60),
|
||||
[#11439](https://github.com/angular/angular.js/issues/11439), [#11675](https://github.com/angular/angular.js/issues/11675), [#11935](https://github.com/angular/angular.js/issues/11935), [#12083](https://github.com/angular/angular.js/issues/12083))
|
||||
- **$parse:** set null reference properties to `undefined`
|
||||
([71fc3f4f](https://github.com/angular/angular.js/commit/71fc3f4fa0cd12eff335d57efed7c033554749f4),
|
||||
[#12099](https://github.com/angular/angular.js/issues/12099))
|
||||
([d19504a1](https://github.com/angular/angular.js/commit/d19504a179355d7801d59a8db0285a1322e04601),
|
||||
[#11959](https://github.com/angular/angular.js/issues/11959))
|
||||
- **$sanitize:** do not remove `tabindex` attribute
|
||||
([799353c7](https://github.com/angular/angular.js/commit/799353c75de28e6fbf52dac6e0721e85b578575a),
|
||||
[#8371](https://github.com/angular/angular.js/issues/8371), [#5853](https://github.com/angular/angular.js/issues/5853))
|
||||
- **copy:** do not copy the same object twice
|
||||
([0e622f7b](https://github.com/angular/angular.js/commit/0e622f7b5bc3d5d0ab0fbc1a1bc69404bd7216d5))
|
||||
- **forms:** parse exponential notation in `numberInputType` directive
|
||||
([ebd0fbba](https://github.com/angular/angular.js/commit/ebd0fbba8ff90bee0cd016d574643d56a7f81ed0),
|
||||
[#12121](https://github.com/angular/angular.js/issues/12121), [#12122](https://github.com/angular/angular.js/issues/12122))
|
||||
- **linky:** allow case insensitive scheme detection
|
||||
([8dc09e6d](https://github.com/angular/angular.js/commit/8dc09e6dabb84c2c611cdc9e40adfac989648200),
|
||||
[#12073](https://github.com/angular/angular.js/issues/12073), [#12073](https://github.com/angular/angular.js/issues/12073))
|
||||
- **ngAria:**
|
||||
- update `aria-valuemin/max` when `min/max` change
|
||||
([ebaa0f59](https://github.com/angular/angular.js/commit/ebaa0f598501702ae64d59ada0ae492eaf0e2db6),
|
||||
[#11770](https://github.com/angular/angular.js/issues/11770), [#11774](https://github.com/angular/angular.js/issues/11774))
|
||||
- ensure boolean values for aria-hidden and aria-disabled
|
||||
([59273354](https://github.com/angular/angular.js/commit/59273354b57dd8d1ad2cd2f4740ffa8923e480f9),
|
||||
[#11365](https://github.com/angular/angular.js/issues/11365))
|
||||
- **ngModel:** ignore Object.prototype properties on the form validation object
|
||||
([0934b76b](https://github.com/angular/angular.js/commit/0934b76b72cec86093414834ac4cb7f0946b651d),
|
||||
[#12066](https://github.com/angular/angular.js/issues/12066))
|
||||
- **ngOptions:**
|
||||
- do not watch properties starting with $
|
||||
([34a6da24](https://github.com/angular/angular.js/commit/34a6da24c17356d4ffc70aec3f621a140a9a61ab),
|
||||
[#11930](https://github.com/angular/angular.js/issues/11930), [#12010](https://github.com/angular/angular.js/issues/12010))
|
||||
- use reference check only when not using trackBy
|
||||
([d7dc14dc](https://github.com/angular/angular.js/commit/d7dc14dc0cdeb9c187d227e19acc8aca7df9d740),
|
||||
[#11936](https://github.com/angular/angular.js/issues/11936), [#11996](https://github.com/angular/angular.js/issues/11996))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** show module name during `multidir` error
|
||||
([351fe4b7](https://github.com/angular/angular.js/commit/351fe4b79c50a45a11af2fcd2aa7b6fd3b70058d),
|
||||
[#11775](https://github.com/angular/angular.js/issues/11775))
|
||||
- **$q:** $q.resolve as an alias for $q.when
|
||||
([3ef52980](https://github.com/angular/angular.js/commit/3ef529806fef28b41ca4af86a330f39a95699cf6),
|
||||
[#11944](https://github.com/angular/angular.js/issues/11944), [#11987](https://github.com/angular/angular.js/issues/11987))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** avoid jquery data calls when there is no data
|
||||
([9efb0d5e](https://github.com/angular/angular.js/commit/9efb0d5ee961b57c8fc144a3138a15955e4010e2))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.16"></a>
|
||||
# 1.3.16 cookie-oatmealification (2015-06-05)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ angular.module('tutorials', [])
|
||||
'step': '@docTutorialReset'
|
||||
},
|
||||
template:
|
||||
'<p><a href="" ng-click="show=!show;$event.stopPropagation()">Workspace Reset Instructions ➤</a></p>\n' +
|
||||
'<p><button class="btn" ng-click="show=!show">Workspace Reset Instructions ➤</button></p>\n' +
|
||||
'<div class="alert alert-info" ng-show="show">\n' +
|
||||
' <p>Reset the workspace to step {{step}}.</p>' +
|
||||
' <p><pre>git checkout -f step-{{step}}</pre></p>\n' +
|
||||
|
||||
@@ -10,14 +10,14 @@ var Package = require('dgeni').Package;
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
require('dgeni-packages/examples')
|
||||
require('dgeni-packages/examples'),
|
||||
require('dgeni-packages/git')
|
||||
])
|
||||
|
||||
|
||||
.factory(require('./services/errorNamespaceMap'))
|
||||
.factory(require('./services/getMinerrInfo'))
|
||||
.factory(require('./services/getVersion'))
|
||||
.factory(require('./services/gitData'))
|
||||
|
||||
.factory(require('./services/deployments/debug'))
|
||||
.factory(require('./services/deployments/default'))
|
||||
@@ -26,7 +26,6 @@ module.exports = new Package('angularjs', [
|
||||
|
||||
.factory(require('./inline-tag-defs/type'))
|
||||
|
||||
|
||||
.processor(require('./processors/error-docs'))
|
||||
.processor(require('./processors/index-page'))
|
||||
.processor(require('./processors/keywords'))
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
var versionInfo = require('../../../lib/versions/version-info');
|
||||
|
||||
/**
|
||||
* @dgService gitData
|
||||
* @description
|
||||
* Information from the local git repository
|
||||
*/
|
||||
module.exports = function gitData() {
|
||||
return {
|
||||
version: versionInfo.currentVersion,
|
||||
versions: versionInfo.previousVersions,
|
||||
info: versionInfo.gitRepoInfo
|
||||
};
|
||||
};
|
||||
@@ -491,9 +491,7 @@ The following example shows how to add two-way data-binding to contentEditable e
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
// view -> model
|
||||
elm.on('blur', function() {
|
||||
scope.$apply(function() {
|
||||
ctrl.$setViewValue(elm.html());
|
||||
});
|
||||
ctrl.$setViewValue(elm.html());
|
||||
});
|
||||
|
||||
// model -> view
|
||||
|
||||
@@ -88,10 +88,10 @@ element.on('$animate:before', function(e, data) {
|
||||
element.off('$animate:before', fn);
|
||||
|
||||
// 1.4+
|
||||
$animate.on(element, 'enter', function(data) {
|
||||
$animate.on('enter', element, function(data) {
|
||||
//...
|
||||
});
|
||||
$animate.off(element, 'enter', fn);
|
||||
$animate.off('enter', element, fn);
|
||||
```
|
||||
|
||||
Due to [c8700f04](https://github.com/angular/angular.js/commit/c8700f04fb6fb5dc21ac24de8665c0476d6db5ef),
|
||||
@@ -246,6 +246,9 @@ Due to [6a38dbfd](https://github.com/angular/angular.js/commit/6a38dbfd3c34c8f9e
|
||||
previously, '&' expressions would always set up a function in the isolate scope. Now, if the binding
|
||||
is marked as optional and the attribute is not specified, no function will be added to the isolate scope.
|
||||
|
||||
Due to [62d514b](https://github.com/angular/angular.js/commit/62d514b06937cc7dd86e973ea11165c88343b42d),
|
||||
returning an object from a controller constructor function will now override the scope. Views that use the
|
||||
controllerAs method will no longer get the this reference, but the returned object.
|
||||
|
||||
|
||||
## Cookies (`ngCookies`)
|
||||
|
||||
@@ -261,8 +261,10 @@ myModule.filter('length', function() {
|
||||
|
||||
describe('length filter', function() {
|
||||
|
||||
var $filter;
|
||||
|
||||
beforeEach(inject(function(_$filter_){
|
||||
$filter= _$filter_;
|
||||
$filter = _$filter_;
|
||||
}));
|
||||
|
||||
it('returns 0 when given null', function() {
|
||||
|
||||
@@ -199,7 +199,7 @@ http://localhost:8000/app/index.html
|
||||
|
||||
<div class="alert alert-info">
|
||||
To serve the web app on a different ip address or port, edit the "start" script within package.json.
|
||||
You can `-a` to set the address and `-p` to set the port.
|
||||
You can use `-a` to set the address and `-p` to set the port.
|
||||
</div>
|
||||
|
||||
### Running Unit Tests
|
||||
|
||||
+22
-16
@@ -2385,10 +2385,10 @@
|
||||
}
|
||||
},
|
||||
"dgeni-packages": {
|
||||
"version": "0.10.13",
|
||||
"version": "0.10.17",
|
||||
"dependencies": {
|
||||
"catharsis": {
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.7",
|
||||
"dependencies": {
|
||||
"underscore-contrib": {
|
||||
"version": "0.3.0",
|
||||
@@ -2404,10 +2404,10 @@
|
||||
"version": "2.3.0",
|
||||
"dependencies": {
|
||||
"camel-case": {
|
||||
"version": "1.1.1"
|
||||
"version": "1.1.2"
|
||||
},
|
||||
"constant-case": {
|
||||
"version": "1.1.0"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"dot-case": {
|
||||
"version": "1.1.1"
|
||||
@@ -2428,7 +2428,7 @@
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"pascal-case": {
|
||||
"version": "1.1.0"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"path-case": {
|
||||
"version": "1.1.1"
|
||||
@@ -2440,10 +2440,10 @@
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"swap-case": {
|
||||
"version": "1.1.0"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"title-case": {
|
||||
"version": "1.1.0"
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"upper-case": {
|
||||
"version": "1.1.2"
|
||||
@@ -2468,7 +2468,7 @@
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.8.2",
|
||||
"version": "3.8.3",
|
||||
"dependencies": {
|
||||
"domhandler": {
|
||||
"version": "2.3.0"
|
||||
@@ -2518,21 +2518,21 @@
|
||||
"version": "0.3.0",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
"version": "2.6.4"
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.0"
|
||||
"version": "1.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nunjucks": {
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.4",
|
||||
"dependencies": {
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2"
|
||||
"version": "0.0.3"
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10"
|
||||
@@ -2552,10 +2552,10 @@
|
||||
"version": "0.2.14",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "2.5.0"
|
||||
"version": "2.6.4"
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.0"
|
||||
"version": "1.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2582,10 +2582,10 @@
|
||||
"version": "0.1.6"
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "0.3.5",
|
||||
"version": "0.3.6",
|
||||
"dependencies": {
|
||||
"nan": {
|
||||
"version": "1.5.3"
|
||||
"version": "1.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2621,6 +2621,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "4.3.6"
|
||||
},
|
||||
"shelljs": {
|
||||
"version": "0.5.1"
|
||||
},
|
||||
"winston": {
|
||||
"version": "0.7.3",
|
||||
"dependencies": {
|
||||
|
||||
Generated
+207
-196
File diff suppressed because it is too large
Load Diff
@@ -55,6 +55,7 @@
|
||||
"isBlob": false,
|
||||
"isBoolean": false,
|
||||
"isPromiseLike": false,
|
||||
"hasCustomToString": false,
|
||||
"trim": false,
|
||||
"escapeForRegexp": false,
|
||||
"isElement": false,
|
||||
|
||||
+11
-2
@@ -352,8 +352,12 @@ function baseExtend(dst, objs, deep) {
|
||||
var src = obj[key];
|
||||
|
||||
if (deep && isObject(src)) {
|
||||
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
|
||||
baseExtend(dst[key], [src], true);
|
||||
if (isDate(src)) {
|
||||
dst[key] = new Date(src.valueOf());
|
||||
} else {
|
||||
if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
|
||||
baseExtend(dst[key], [src], true);
|
||||
}
|
||||
} else {
|
||||
dst[key] = src;
|
||||
}
|
||||
@@ -464,6 +468,11 @@ identity.$inject = [];
|
||||
|
||||
function valueFn(value) {return function() {return value;};}
|
||||
|
||||
function hasCustomToString(obj) {
|
||||
return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.isUndefined
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
function getHash(url) {
|
||||
var index = url.indexOf('#');
|
||||
return index === -1 ? '' : url.substr(index + 1);
|
||||
return index === -1 ? '' : url.substr(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-2
@@ -1654,7 +1654,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
previousCompileContext = previousCompileContext || {};
|
||||
|
||||
var terminalPriority = -Number.MAX_VALUE,
|
||||
newScopeDirective,
|
||||
newScopeDirective = previousCompileContext.newScopeDirective,
|
||||
controllerDirectives = previousCompileContext.controllerDirectives,
|
||||
newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
|
||||
templateDirective = previousCompileContext.templateDirective,
|
||||
@@ -1820,6 +1820,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
|
||||
templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
|
||||
controllerDirectives: controllerDirectives,
|
||||
newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
|
||||
newIsolateScopeDirective: newIsolateScopeDirective,
|
||||
templateDirective: templateDirective,
|
||||
nonTlbTranscludeDirective: nonTlbTranscludeDirective
|
||||
@@ -2204,7 +2205,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
$compileNode.empty();
|
||||
|
||||
$templateRequest($sce.getTrustedResourceUrl(templateUrl))
|
||||
$templateRequest(templateUrl)
|
||||
.then(function(content) {
|
||||
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
|
||||
|
||||
|
||||
@@ -206,6 +206,13 @@
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
|
||||
*
|
||||
* Note that this directive should not be used together with {@link ngModel `ngModel`},
|
||||
* as this can lead to unexpected behavior.
|
||||
*
|
||||
* ### Why do we need `ngChecked`?
|
||||
*
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as checked. (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
@@ -230,7 +237,7 @@
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
|
||||
* then special attribute "checked" will be set on the element
|
||||
* then the `checked` attribute will be set on the element
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -913,12 +913,15 @@ var inputType = {
|
||||
* HTML radio button.
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string} value The value to which the expression should be set when selected.
|
||||
* @param {string} value The value to which the `ngModel` expression should be set when selected.
|
||||
* Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
|
||||
* too. Use `ngValue` if you need complex models (`number`, `object`, ...).
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
* @param {string} ngValue Angular expression which sets the value to which the expression should
|
||||
* be set when selected.
|
||||
* @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
|
||||
* is selected. Should be used instead of the `value` attribute if you need
|
||||
* a non-string `ngModel` (`boolean`, `array`, ...).
|
||||
*
|
||||
* @example
|
||||
<example name="radio-input-directive" module="radioExample">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ngIf
|
||||
* @restrict A
|
||||
* @multiElement
|
||||
*
|
||||
* @description
|
||||
* The `ngIf` directive removes or recreates a portion of the DOM tree based on an
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
* @param {Object} angularEvent Synthetic event object.
|
||||
* @param {String} src URL of content to load.
|
||||
*/
|
||||
var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
|
||||
function($templateRequest, $anchorScroll, $animate, $sce) {
|
||||
var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
function($templateRequest, $anchorScroll, $animate) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: 400,
|
||||
@@ -215,7 +215,7 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce
|
||||
}
|
||||
};
|
||||
|
||||
scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
|
||||
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
|
||||
var afterAnimation = function() {
|
||||
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
|
||||
$anchorScroll();
|
||||
|
||||
@@ -292,20 +292,41 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
function getOptionValuesKeys(optionValues) {
|
||||
var optionValuesKeys;
|
||||
|
||||
if (!keyName && isArrayLike(optionValues)) {
|
||||
optionValuesKeys = optionValues;
|
||||
} else {
|
||||
// if object, extract keys, in enumeration order, unsorted
|
||||
optionValuesKeys = [];
|
||||
for (var itemKey in optionValues) {
|
||||
if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
|
||||
optionValuesKeys.push(itemKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
return optionValuesKeys;
|
||||
}
|
||||
|
||||
return {
|
||||
trackBy: trackBy,
|
||||
getTrackByValue: getTrackByValue,
|
||||
getWatchables: $parse(valuesFn, function(values) {
|
||||
getWatchables: $parse(valuesFn, function(optionValues) {
|
||||
// Create a collection of things that we would like to watch (watchedArray)
|
||||
// so that they can all be watched using a single $watchCollection
|
||||
// that only runs the handler once if anything changes
|
||||
var watchedArray = [];
|
||||
values = values || [];
|
||||
optionValues = optionValues || [];
|
||||
|
||||
Object.keys(values).forEach(function getWatchable(key) {
|
||||
if (key.charAt(0) === '$') return;
|
||||
var locals = getLocals(values[key], key);
|
||||
var selectValue = getTrackByValueFn(values[key], locals);
|
||||
var optionValuesKeys = getOptionValuesKeys(optionValues);
|
||||
var optionValuesLength = optionValuesKeys.length;
|
||||
for (var index = 0; index < optionValuesLength; index++) {
|
||||
var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
|
||||
var value = optionValues[key];
|
||||
|
||||
var locals = getLocals(optionValues[key], key);
|
||||
var selectValue = getTrackByValueFn(optionValues[key], locals);
|
||||
watchedArray.push(selectValue);
|
||||
|
||||
// Only need to watch the displayFn if there is a specific label expression
|
||||
@@ -319,7 +340,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
var disableWhen = disableWhenFn(scope, locals);
|
||||
watchedArray.push(disableWhen);
|
||||
}
|
||||
});
|
||||
}
|
||||
return watchedArray;
|
||||
}),
|
||||
|
||||
@@ -331,21 +352,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
// The option values were already computed in the `getWatchables` fn,
|
||||
// which must have been called to trigger `getOptions`
|
||||
var optionValues = valuesFn(scope) || [];
|
||||
var optionValuesKeys;
|
||||
|
||||
|
||||
if (!keyName && isArrayLike(optionValues)) {
|
||||
optionValuesKeys = optionValues;
|
||||
} else {
|
||||
// if object, extract keys, in enumeration order, unsorted
|
||||
optionValuesKeys = [];
|
||||
for (var itemKey in optionValues) {
|
||||
if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
|
||||
optionValuesKeys.push(itemKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var optionValuesKeys = getOptionValuesKeys(optionValues);
|
||||
var optionValuesLength = optionValuesKeys.length;
|
||||
|
||||
for (var index = 0; index < optionValuesLength; index++) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngRepeat
|
||||
* @multiElement
|
||||
*
|
||||
* @description
|
||||
* The `ngRepeat` directive instantiates a template once per item from a collection. Each template
|
||||
|
||||
@@ -5,6 +5,7 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngShow
|
||||
* @multiElement
|
||||
*
|
||||
* @description
|
||||
* The `ngShow` directive shows or hides the given HTML element based on the expression
|
||||
@@ -180,6 +181,7 @@ var ngShowDirective = ['$animate', function($animate) {
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngHide
|
||||
* @multiElement
|
||||
*
|
||||
* @description
|
||||
* The `ngHide` directive shows or hides the given HTML element based on the expression
|
||||
|
||||
@@ -163,10 +163,6 @@ function filterFilter() {
|
||||
};
|
||||
}
|
||||
|
||||
function hasCustomToString(obj) {
|
||||
return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
|
||||
}
|
||||
|
||||
// Helper functions for `filterFilter`
|
||||
function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
|
||||
var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
|
||||
|
||||
+102
-76
@@ -176,88 +176,114 @@
|
||||
orderByFilter.$inject = ['$parse'];
|
||||
function orderByFilter($parse) {
|
||||
return function(array, sortPredicate, reverseOrder) {
|
||||
|
||||
if (!(isArrayLike(array))) return array;
|
||||
sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
|
||||
|
||||
if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
|
||||
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
|
||||
sortPredicate = sortPredicate.map(function(predicate) {
|
||||
var descending = false, get = predicate || identity;
|
||||
if (isString(predicate)) {
|
||||
if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
|
||||
descending = predicate.charAt(0) == '-';
|
||||
predicate = predicate.substring(1);
|
||||
}
|
||||
if (predicate === '') {
|
||||
// Effectively no predicate was passed so we compare identity
|
||||
return reverseComparator(compare, descending);
|
||||
}
|
||||
get = $parse(predicate);
|
||||
if (get.constant) {
|
||||
var key = get();
|
||||
return reverseComparator(function(a, b) {
|
||||
return compare(a[key], b[key]);
|
||||
}, descending);
|
||||
}
|
||||
}
|
||||
return reverseComparator(function(a, b) {
|
||||
return compare(get(a),get(b));
|
||||
}, descending);
|
||||
});
|
||||
return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
|
||||
|
||||
function comparator(o1, o2) {
|
||||
for (var i = 0; i < sortPredicate.length; i++) {
|
||||
var comp = sortPredicate[i](o1, o2);
|
||||
if (comp !== 0) return comp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function reverseComparator(comp, descending) {
|
||||
return descending
|
||||
? function(a, b) {return comp(b,a);}
|
||||
: comp;
|
||||
var predicates = processPredicates(sortPredicate, reverseOrder);
|
||||
|
||||
// The next three lines are a version of a Swartzian Transform idiom from Perl
|
||||
// (sometimes called the Decorate-Sort-Undecorate idiom)
|
||||
// See https://en.wikipedia.org/wiki/Schwartzian_transform
|
||||
var compareValues = Array.prototype.map.call(array, getComparisonObject);
|
||||
compareValues.sort(doComparison);
|
||||
array = compareValues.map(function(item) { return item.value; });
|
||||
|
||||
return array;
|
||||
|
||||
function getComparisonObject(value, index) {
|
||||
return {
|
||||
value: value,
|
||||
predicateValues: predicates.map(function(predicate) {
|
||||
return getPredicateValue(predicate.get(value), index);
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
function isPrimitive(value) {
|
||||
switch (typeof value) {
|
||||
case 'number': /* falls through */
|
||||
case 'boolean': /* falls through */
|
||||
case 'string':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function objectToString(value) {
|
||||
if (value === null) return 'null';
|
||||
if (typeof value.valueOf === 'function') {
|
||||
value = value.valueOf();
|
||||
if (isPrimitive(value)) return value;
|
||||
}
|
||||
if (typeof value.toString === 'function') {
|
||||
value = value.toString();
|
||||
if (isPrimitive(value)) return value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function compare(v1, v2) {
|
||||
var t1 = typeof v1;
|
||||
var t2 = typeof v2;
|
||||
if (t1 === t2 && t1 === "object") {
|
||||
v1 = objectToString(v1);
|
||||
v2 = objectToString(v2);
|
||||
}
|
||||
if (t1 === t2) {
|
||||
if (t1 === "string") {
|
||||
v1 = v1.toLowerCase();
|
||||
v2 = v2.toLowerCase();
|
||||
}
|
||||
if (v1 === v2) return 0;
|
||||
return v1 < v2 ? -1 : 1;
|
||||
} else {
|
||||
return t1 < t2 ? -1 : 1;
|
||||
function doComparison(v1, v2) {
|
||||
var result = 0;
|
||||
for (var index=0, length = predicates.length; index < length; ++index) {
|
||||
result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
|
||||
if (result) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function processPredicates(sortPredicate, reverseOrder) {
|
||||
reverseOrder = reverseOrder ? -1 : 1;
|
||||
return sortPredicate.map(function(predicate) {
|
||||
var descending = 1, get = identity;
|
||||
|
||||
if (isFunction(predicate)) {
|
||||
get = predicate;
|
||||
} else if (isString(predicate)) {
|
||||
if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
|
||||
descending = predicate.charAt(0) == '-' ? -1 : 1;
|
||||
predicate = predicate.substring(1);
|
||||
}
|
||||
if (predicate !== '') {
|
||||
get = $parse(predicate);
|
||||
if (get.constant) {
|
||||
var key = get();
|
||||
get = function(value) { return value[key]; };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { get: get, descending: descending * reverseOrder };
|
||||
});
|
||||
}
|
||||
|
||||
function isPrimitive(value) {
|
||||
switch (typeof value) {
|
||||
case 'number': /* falls through */
|
||||
case 'boolean': /* falls through */
|
||||
case 'string':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function objectValue(value, index) {
|
||||
// If `valueOf` is a valid function use that
|
||||
if (typeof value.valueOf === 'function') {
|
||||
value = value.valueOf();
|
||||
if (isPrimitive(value)) return value;
|
||||
}
|
||||
// If `toString` is a valid function and not the one from `Object.prototype` use that
|
||||
if (hasCustomToString(value)) {
|
||||
value = value.toString();
|
||||
if (isPrimitive(value)) return value;
|
||||
}
|
||||
// We have a basic object so we use the position of the object in the collection
|
||||
return index;
|
||||
}
|
||||
|
||||
function getPredicateValue(value, index) {
|
||||
var type = typeof value;
|
||||
if (value === null) {
|
||||
type = 'string';
|
||||
value = 'null';
|
||||
} else if (type === 'string') {
|
||||
value = value.toLowerCase();
|
||||
} else if (type === 'object') {
|
||||
value = objectValue(value, index);
|
||||
}
|
||||
return { value: value, type: type };
|
||||
}
|
||||
|
||||
function compare(v1, v2) {
|
||||
var result = 0;
|
||||
if (v1.type === v2.type) {
|
||||
if (v1.value !== v2.value) {
|
||||
result = v1.value < v2.value ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
result = v1.type < v2.type ? -1 : 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -253,7 +253,7 @@ function $HttpProvider() {
|
||||
*
|
||||
* - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
|
||||
* that will provide the cache for all requests who set their `cache` property to `true`.
|
||||
* If you set the `default.cache = false` then only requests that specify their own custom
|
||||
* If you set the `defaults.cache = false` then only requests that specify their own custom
|
||||
* cache object will be cached. See {@link $http#caching $http Caching} for more information.
|
||||
*
|
||||
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
|
||||
@@ -786,7 +786,7 @@ function $HttpProvider() {
|
||||
* XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
|
||||
* for more information.
|
||||
* - **responseType** - `{string}` - see
|
||||
* [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
|
||||
* [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
|
||||
*
|
||||
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
|
||||
* standard `then` method and two http specific methods: `success` and `error`. The `then`
|
||||
|
||||
+10
-2
@@ -185,7 +185,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
|
||||
var withoutHashUrl;
|
||||
|
||||
if (withoutBaseUrl.charAt(0) === '#') {
|
||||
if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
|
||||
|
||||
// The rest of the url starts with a hash so we have
|
||||
// got either a hashbang path or a plain hash fragment
|
||||
@@ -199,7 +199,15 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
// There was no hashbang path nor hash fragment:
|
||||
// If we are in HTML5 mode we use what is left as the path;
|
||||
// Otherwise we ignore what is left
|
||||
withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
|
||||
if (this.$$html5) {
|
||||
withoutHashUrl = withoutBaseUrl;
|
||||
} else {
|
||||
withoutHashUrl = '';
|
||||
if (isUndefined(withoutBaseUrl)) {
|
||||
appBase = url;
|
||||
this.replace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseAppUrl(withoutHashUrl, this);
|
||||
|
||||
@@ -7,12 +7,14 @@ var $compileMinErr = minErr('$compile');
|
||||
* @name $templateRequest
|
||||
*
|
||||
* @description
|
||||
* The `$templateRequest` service downloads the provided template using `$http` and, upon success,
|
||||
* stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
|
||||
* of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
|
||||
* by setting the 2nd parameter of the function to true).
|
||||
* The `$templateRequest` service runs security checks then downloads the provided template using
|
||||
* `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
|
||||
* fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
|
||||
* exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
|
||||
* contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
|
||||
* when `tpl` is of type string and `$templateCache` has the matching entry.
|
||||
*
|
||||
* @param {string} tpl The HTTP request template URL
|
||||
* @param {string|TrustedResourceUrl} tpl The HTTP request template URL
|
||||
* @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
|
||||
*
|
||||
* @return {Promise} a promise for the HTTP response data of the given URL.
|
||||
@@ -20,10 +22,19 @@ var $compileMinErr = minErr('$compile');
|
||||
* @property {number} totalPendingRequests total amount of pending template requests being downloaded.
|
||||
*/
|
||||
function $TemplateRequestProvider() {
|
||||
this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
|
||||
this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
|
||||
function handleRequestFn(tpl, ignoreRequestError) {
|
||||
handleRequestFn.totalPendingRequests++;
|
||||
|
||||
// We consider the template cache holds only trusted templates, so
|
||||
// there's no need to go through whitelisting again for keys that already
|
||||
// are included in there. This also makes Angular accept any script
|
||||
// directive, no matter its name. However, we still need to unwrap trusted
|
||||
// types.
|
||||
if (!isString(tpl) || !$templateCache.get(tpl)) {
|
||||
tpl = $sce.getTrustedResourceUrl(tpl);
|
||||
}
|
||||
|
||||
var transformResponse = $http.defaults && $http.defaults.transformResponse;
|
||||
|
||||
if (isArray(transformResponse)) {
|
||||
|
||||
@@ -327,7 +327,7 @@
|
||||
* ## CSS + JS Animations Together
|
||||
*
|
||||
* AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
|
||||
* defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore example below will only result in **JS animations taking
|
||||
* defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
|
||||
* charge of the animation**:
|
||||
*
|
||||
* ```html
|
||||
@@ -356,8 +356,8 @@
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can suppliment for the
|
||||
* lack of CSS animations by making use of the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
|
||||
* Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the
|
||||
* lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from
|
||||
* our own JS-based animation code:
|
||||
*
|
||||
* ```js
|
||||
@@ -655,7 +655,7 @@
|
||||
* ngModule.directive('greetingBox', ['$animate', function($animate) {
|
||||
* return function(scope, element, attrs) {
|
||||
* attrs.$observe('active', function(value) {
|
||||
* value ? $animate.addClass(element, 'on') ? $animate.removeClass(element, 'on');
|
||||
* value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');
|
||||
* });
|
||||
* });
|
||||
* }]);
|
||||
@@ -666,7 +666,7 @@
|
||||
*
|
||||
* ```css
|
||||
* /* normally we would create a CSS class to reference on the element */
|
||||
* [greeting-box].on { transition:0.5s linear all; background:green; color:white; }
|
||||
* greeting-box.on { transition:0.5s linear all; background:green; color:white; }
|
||||
* ```
|
||||
*
|
||||
* The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's
|
||||
|
||||
+8
-2
@@ -83,7 +83,8 @@ function $AriaProvider() {
|
||||
ariaMultiline: true,
|
||||
ariaValue: true,
|
||||
tabindex: true,
|
||||
bindKeypress: true
|
||||
bindKeypress: true,
|
||||
bindRoleForClick: true
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,6 +103,8 @@ function $AriaProvider() {
|
||||
* - **tabindex** – `{boolean}` – Enables/disables tabindex tags
|
||||
* - **bindKeypress** – `{boolean}` – Enables/disables keypress event binding on `<div>` and
|
||||
* `<li>` elements with ng-click
|
||||
* - **bindRoleForClick** – `{boolean}` – Adds role=button to non-interactive elements like `div`
|
||||
* using ng-click, making them more accessible to users of assistive technologies
|
||||
*
|
||||
* @description
|
||||
* Enables/disables various ARIA attributes
|
||||
@@ -346,7 +349,10 @@ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!elem.attr('role') && !isNodeOneOf(elem, nodeBlackList)) {
|
||||
|
||||
if ($aria.config('bindRoleForClick')
|
||||
&& !elem.attr('role')
|
||||
&& !isNodeOneOf(elem, nodeBlackList)) {
|
||||
elem.attr('role', 'button');
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ angular.module('ngCookies').
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
* <div class="alert alert-danger">
|
||||
* **Note:** The $cookieStore service is deprecated.
|
||||
* **Note:** The $cookieStore service is **deprecated**.
|
||||
* Please use the {@link ngCookies.$cookies `$cookies`} service instead.
|
||||
* </div>
|
||||
*
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
*
|
||||
* <div doc-module-components="ngCookies"></div>
|
||||
*
|
||||
* See {@link ngCookies.$cookies `$cookies`} and
|
||||
* {@link ngCookies.$cookieStore `$cookieStore`} for usage.
|
||||
* See {@link ngCookies.$cookies `$cookies`} for usage.
|
||||
*/
|
||||
|
||||
|
||||
@@ -60,9 +59,11 @@ angular.module('ngCookies', ['ng']).
|
||||
* @description
|
||||
* Provides read/write access to browser's cookies.
|
||||
*
|
||||
* BREAKING CHANGE: `$cookies` no longer exposes properties that represent the
|
||||
* current browser cookie values. Now you must use the get/put/remove/etc. methods
|
||||
* as described below.
|
||||
* <div class="alert alert-info">
|
||||
* Up until Angular 1.3, `$cookies` exposed properties that represented the
|
||||
* current browser cookie values. In version 1.4, this behavior has changed, and
|
||||
* `$cookies` now provides a standard api of getters, setters etc.
|
||||
* </div>
|
||||
*
|
||||
* Requires the {@link ngCookies `ngCookies`} module to be installed.
|
||||
*
|
||||
|
||||
@@ -209,7 +209,8 @@ function shallowClearAndCopy(src, dst) {
|
||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
||||
*
|
||||
*
|
||||
* Success callback is called with (value, responseHeaders) arguments. Error callback is called
|
||||
* Success callback is called with (value, responseHeaders) arguments, where the value is
|
||||
* the populated resource instance or collection object. The error callback is called
|
||||
* with (httpResponse) argument.
|
||||
*
|
||||
* Class actions return empty instance (with additional properties below).
|
||||
|
||||
@@ -591,9 +591,8 @@ function $RouteProvider() {
|
||||
if (angular.isFunction(templateUrl)) {
|
||||
templateUrl = templateUrl(nextRoute.params);
|
||||
}
|
||||
templateUrl = $sce.getTrustedResourceUrl(templateUrl);
|
||||
if (angular.isDefined(templateUrl)) {
|
||||
nextRoute.loadedTemplateUrl = templateUrl;
|
||||
nextRoute.loadedTemplateUrl = $sce.valueOf(templateUrl);
|
||||
template = $templateRequest(templateUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,8 @@ ngTouch.factory('$swipe', [function() {
|
||||
* `$swipe` will listen for `mouse` and `touch` events.
|
||||
*
|
||||
* The four events are `start`, `move`, `end`, and `cancel`. `start`, `move`, and `end`
|
||||
* receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }`.
|
||||
* receive as a parameter a coordinates object of the form `{ x: 150, y: 310 }` and the raw
|
||||
* `event`. `cancel` receives the raw `event` as its single parameter.
|
||||
*
|
||||
* `start` is called on either `mousedown` or `touchstart`. After this event, `$swipe` is
|
||||
* watching for `touchmove` or `mousemove` events. These events are ignored until the total
|
||||
|
||||
@@ -481,6 +481,16 @@ describe('angular', function() {
|
||||
// make sure we retain the old key
|
||||
expect(hashKey(dst)).toEqual(h);
|
||||
});
|
||||
|
||||
|
||||
it('should copy dates by reference', function() {
|
||||
var src = { date: new Date() };
|
||||
var dst = {};
|
||||
|
||||
extend(dst, src);
|
||||
|
||||
expect(dst.date).toBe(src.date);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -548,6 +558,18 @@ describe('angular', function() {
|
||||
});
|
||||
expect(dst.foo).not.toBe(src.foo);
|
||||
});
|
||||
|
||||
|
||||
it('should copy dates by value', function() {
|
||||
var src = { date: new Date() };
|
||||
var dst = {};
|
||||
|
||||
merge(dst, src);
|
||||
|
||||
expect(dst.date).not.toBe(src.date);
|
||||
expect(isDate(dst.date)).toBeTruthy();
|
||||
expect(dst.date.valueOf()).toEqual(src.date.valueOf());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -57,7 +57,9 @@ function MockWindow(options) {
|
||||
return getHash(locationHref);
|
||||
},
|
||||
set hash(value) {
|
||||
locationHref = stripHash(locationHref) + '#' + value;
|
||||
// replace the hash with the new one (stripping off a leading hash if there is one)
|
||||
// See hash setter spec: https://url.spec.whatwg.org/#urlutils-and-urlutilsreadonly-members
|
||||
locationHref = stripHash(locationHref) + '#' + value.replace(/^#/,'');
|
||||
},
|
||||
replace: function(url) {
|
||||
locationHref = url;
|
||||
|
||||
+25
-3
@@ -1296,14 +1296,24 @@ describe('$compile', function() {
|
||||
));
|
||||
|
||||
it('should not load cross domain templates by default', inject(
|
||||
function($compile, $rootScope, $templateCache, $sce) {
|
||||
function($compile, $rootScope) {
|
||||
expect(function() {
|
||||
$templateCache.put('http://example.com/should-not-load.html', 'Should not load even if in cache.');
|
||||
$compile('<div class="crossDomainTemplate"></div>')($rootScope);
|
||||
}).toThrowMinErr('$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: http://example.com/should-not-load.html');
|
||||
}
|
||||
));
|
||||
|
||||
it('should trust what is already in the template cache', inject(
|
||||
function($compile, $httpBackend, $rootScope, $templateCache) {
|
||||
$httpBackend.expect('GET', 'http://example.com/should-not-load.html').respond('<span>example.com/remote-version</span>');
|
||||
$templateCache.put('http://example.com/should-not-load.html', '<span>example.com/cached-version</span>');
|
||||
element = $compile('<div class="crossDomainTemplate"></div>')($rootScope);
|
||||
expect(sortedHtml(element)).toEqual('<div class="crossDomainTemplate"></div>');
|
||||
$rootScope.$digest();
|
||||
expect(sortedHtml(element)).toEqual('<div class="crossDomainTemplate"><span>example.com/cached-version</span></div>');
|
||||
}
|
||||
));
|
||||
|
||||
it('should load cross domain templates when trusted', inject(
|
||||
function($compile, $httpBackend, $rootScope, $sce) {
|
||||
$httpBackend.expect('GET', 'http://example.com/trusted-template.html').respond('<span>example.com/trusted_template_contents</span>');
|
||||
@@ -2370,7 +2380,7 @@ describe('$compile', function() {
|
||||
})
|
||||
);
|
||||
|
||||
it('should not allow more then one isolate scope creation per element', inject(
|
||||
it('should not allow more than one isolate scope creation per element', inject(
|
||||
function($rootScope, $compile) {
|
||||
expect(function() {
|
||||
$compile('<div class="iscope-a; scope-b"></div>');
|
||||
@@ -2379,6 +2389,18 @@ describe('$compile', function() {
|
||||
})
|
||||
);
|
||||
|
||||
it('should not allow more than one isolate/new scope creation per element regardless of `templateUrl`',
|
||||
inject(function($httpBackend) {
|
||||
$httpBackend.expect('GET', 'tiscope.html').respond('<div>Hello, world !</div>');
|
||||
|
||||
expect(function() {
|
||||
compile('<div class="tiscope-a; scope-b"></div>');
|
||||
$httpBackend.flush();
|
||||
}).toThrowMinErr('$compile', 'multidir', 'Multiple directives [scopeB, tiscopeA] ' +
|
||||
'asking for new/isolated scope on: <div class="tiscope-a; scope-b ng-scope">');
|
||||
})
|
||||
);
|
||||
|
||||
it('should not allow more than one isolate scope creation per element regardless of directive priority', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('highPriorityScope', function() {
|
||||
|
||||
@@ -448,7 +448,7 @@ describe('ngOptions', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not watch array properties that start with $ or $$', function() {
|
||||
it('should not watch non-numeric array properties', function() {
|
||||
createSelect({
|
||||
'ng-options': 'value as createLabel(value) for value in array',
|
||||
'ng-model': 'selected'
|
||||
@@ -457,6 +457,8 @@ describe('ngOptions', function() {
|
||||
scope.array = ['a', 'b', 'c'];
|
||||
scope.array.$$private = 'do not watch';
|
||||
scope.array.$property = 'do not watch';
|
||||
scope.array.other = 'do not watch';
|
||||
scope.array.fn = function() {};
|
||||
scope.selected = 'b';
|
||||
scope.$digest();
|
||||
|
||||
@@ -464,6 +466,7 @@ describe('ngOptions', function() {
|
||||
expect(scope.createLabel).toHaveBeenCalledWith('b');
|
||||
expect(scope.createLabel).toHaveBeenCalledWith('c');
|
||||
expect(scope.createLabel).not.toHaveBeenCalledWith('do not watch');
|
||||
expect(scope.createLabel).not.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
|
||||
@@ -482,7 +485,6 @@ describe('ngOptions', function() {
|
||||
expect(scope.createLabel).not.toHaveBeenCalledWith('$property');
|
||||
});
|
||||
|
||||
|
||||
it('should allow expressions over multiple lines', function() {
|
||||
scope.isNotFoo = function(item) {
|
||||
return item.name !== 'Foo';
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('Filter: orderBy', function() {
|
||||
});
|
||||
|
||||
|
||||
it('shouldSortArrayInReverse', function() {
|
||||
it('should reverse collection if `reverseOrder` param is truthy', function() {
|
||||
expect(orderBy([{a:15}, {a:2}], 'a', true)).toEqualData([{a:15}, {a:2}]);
|
||||
expect(orderBy([{a:15}, {a:2}], 'a', "T")).toEqualData([{a:15}, {a:2}]);
|
||||
expect(orderBy([{a:15}, {a:2}], 'a', "reverse")).toEqualData([{a:15}, {a:2}]);
|
||||
@@ -116,7 +116,7 @@ describe('Filter: orderBy', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should not reverse array of objects with no predicate', function() {
|
||||
it('should not reverse array of objects with no predicate and reverse is not `true`', function() {
|
||||
var array = [
|
||||
{ id: 2 },
|
||||
{ id: 1 },
|
||||
@@ -126,6 +126,39 @@ describe('Filter: orderBy', function() {
|
||||
expect(orderBy(array)).toEqualData(array);
|
||||
});
|
||||
|
||||
it('should reverse array of objects with no predicate and reverse is `true`', function() {
|
||||
var array = [
|
||||
{ id: 2 },
|
||||
{ id: 1 },
|
||||
{ id: 4 },
|
||||
{ id: 3 }
|
||||
];
|
||||
var reversedArray = [
|
||||
{ id: 3 },
|
||||
{ id: 4 },
|
||||
{ id: 1 },
|
||||
{ id: 2 }
|
||||
];
|
||||
expect(orderBy(array, '', true)).toEqualData(reversedArray);
|
||||
});
|
||||
|
||||
|
||||
it('should reverse array of objects with predicate of "-"', function() {
|
||||
var array = [
|
||||
{ id: 2 },
|
||||
{ id: 1 },
|
||||
{ id: 4 },
|
||||
{ id: 3 }
|
||||
];
|
||||
var reversedArray = [
|
||||
{ id: 3 },
|
||||
{ id: 4 },
|
||||
{ id: 1 },
|
||||
{ id: 2 }
|
||||
];
|
||||
expect(orderBy(array, '-')).toEqualData(reversedArray);
|
||||
});
|
||||
|
||||
|
||||
it('should not reverse array of objects with null prototype and no predicate', function() {
|
||||
var array = [2,1,4,3].map(function(id) {
|
||||
@@ -151,6 +184,16 @@ describe('Filter: orderBy', function() {
|
||||
null
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should sort array of arrays as Array.prototype.sort', function() {
|
||||
expect(orderBy([['one'], ['two'], ['three']])).toEqualData([['one'], ['three'], ['two']]);
|
||||
});
|
||||
|
||||
|
||||
it('should sort mixed array of objects and values in a stable way', function() {
|
||||
expect(orderBy([{foo: 2}, {foo: {}}, {foo: 3}, {foo: 4}], 'foo')).toEqualData([{foo: 2}, {foo: 3}, {foo: 4}, {foo: {}}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
+23
-6
@@ -989,6 +989,18 @@ describe('$location', function() {
|
||||
expect($browser.url()).toBe('http://new.com/a/b#!/changed');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should not infinitely digest if hash is set when there is no hashPrefix', function() {
|
||||
initService({html5Mode:false, hashPrefix:'', supportHistory:true});
|
||||
mockUpBrowser({initialUrl:'http://new.com/a/b', baseHref:'/a/b'});
|
||||
inject(function($rootScope, $browser, $location) {
|
||||
$location.hash('test');
|
||||
|
||||
$rootScope.$digest();
|
||||
expect($browser.url()).toBe('http://new.com/a/b##test');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('wiring in html5 mode', function() {
|
||||
@@ -2450,6 +2462,14 @@ describe('$location', function() {
|
||||
it('should throw on url(urlString, stateObject)', function() {
|
||||
expectThrowOnStateChange(locationUrl);
|
||||
});
|
||||
|
||||
it('should allow navigating outside the original base URL', function() {
|
||||
locationUrl = new LocationHashbangUrl('http://server/pre/index.html', '#');
|
||||
|
||||
locationUrl.$$parse('http://server/next/index.html');
|
||||
expect(locationUrl.url()).toBe('');
|
||||
expect(locationUrl.absUrl()).toBe('http://server/next/index.html');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2507,17 +2527,11 @@ describe('$location', function() {
|
||||
win.history = {
|
||||
state: options.state || null,
|
||||
replaceState: function(state, title, url) {
|
||||
// console.log('REPLACESTATE');
|
||||
// console.log('CURRENT', win.location.href, win.history.state);
|
||||
// console.log('NEW', url, state);
|
||||
win.history.state = copy(state);
|
||||
if (url) win.location.href = url;
|
||||
jqLite(win).triggerHandler('popstate');
|
||||
},
|
||||
pushState: function(state, title, url) {
|
||||
// console.log('PUSHSTATE');
|
||||
// console.log('CURRENT', win.location.href, win.history.state);
|
||||
// console.log('NEW', url, state);
|
||||
win.history.state = copy(state);
|
||||
if (url) win.location.href = url;
|
||||
jqLite(win).triggerHandler('popstate');
|
||||
@@ -2529,6 +2543,9 @@ describe('$location', function() {
|
||||
get href() { return parser.href; },
|
||||
set href(val) { parser.href = val; },
|
||||
get hash() { return parser.hash; },
|
||||
// The parser correctly strips on a single preceding hash character if necessary
|
||||
// before joining the fragment onto the href by a new hash character
|
||||
// See hash setter spec: https://url.spec.whatwg.org/#urlutils-and-urlutilsreadonly-members
|
||||
set hash(val) { parser.hash = val; },
|
||||
|
||||
replace: function(val) {
|
||||
|
||||
@@ -750,6 +750,18 @@ describe('$aria', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions when bindRoleForClick is set to false', function() {
|
||||
beforeEach(configAriaProvider({
|
||||
bindRoleForClick: false
|
||||
}));
|
||||
beforeEach(injectScopeAndCompiler);
|
||||
|
||||
it('should not add a button role', function() {
|
||||
compileElement('<radio-group ng-click="something"></radio-group>');
|
||||
expect(element.attr('role')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('actions when bindKeypress is set to false', function() {
|
||||
beforeEach(configAriaProvider({
|
||||
bindKeypress: false
|
||||
|
||||
Reference in New Issue
Block a user