Compare commits

...

36 Commits

Author SHA1 Message Date
marcysutton 1f5e42e882 feat(ngAria): add option to disable role=button
Closes #11580
Closes #12234
2015-07-02 14:36:49 +03:00
Jeff Cross d193c3a25c revert: "fix($compile): do not write @-bound properties if attribute is not present"
This reverts commit 8a1eb1625c.

This commit broke the tabs component on the material project,
which caused internal breakages. Will open a separate issue to
look into the issue.
2015-07-01 22:12:03 -07:00
Raphael Jamet 4da1cc3b81 refactor($templateRequest): Remove useless dependencies in tests 2015-07-01 12:15:00 -07:00
Raphael Jamet 6de08216e7 docs($templateRequest): update the description with caching changes
The previous changes to $templateRequest were not documented, they now are.
2015-07-01 12:15:00 -07:00
Raphael Jamet 3c6e8ce044 refactor($templateRequest): move $sce checks and trust the cache
Move all the calls to $sce.getTrustedUrl inside $templateRequest, and
also trust the contents of the cache. This allows prefetching templates
and to bypass the checks on things where they make no sense, like
templates specified in script tags.

Closes #12219
Closes #12220
Closes #12240
2015-07-01 12:14:42 -07:00
Peter Bacon Darwin e51024ed54 docs(ngAnimate): fix typos 2015-06-30 13:19:52 +01:00
Chris Bosco 04f1ebd470 docs(guide/Migrating): $animate.on/off example updated to match docs
Closes #12212
2015-06-30 03:05:05 +01:00
Bart Verkoeijen 2e63ab734a docs(guide/Migrating): add breaking change for 1.4 regarding controller constructors.
If you previously returned a object from a controller constructor function,
it would not be bound to the scope. As of 1.4 it does, and can cause
unexpected objects as the scope.

Closes #12227
2015-06-30 02:59:46 +01:00
Georgios Kalpakas 6333d65b76 fix($compile): throw error when requestng new and isolate scopes (async)
While directives are not allowed to request both a new (normal) and an
isolate scope on the same element, the relevant check was not performed
correctly when the directive requesting the isolate scope had a lower
priority and specified a `templateUrl`.
In that case, the check was deferred until the template was fetched, but
the info about other directives requesting a new (normal) scope was not
properly preserved (in `previousCompileContext`).

This commit fixes this, so now an error is thrown (as expected).

Fixes #12215
Closes #12217
2015-06-28 11:33:06 +03:00
Yichao Wang 1ce5d216c7 docs(ngAnimate): fix typos in JS and CSS selector
Closes #12203
2015-06-25 12:42:17 +03:00
Georgios Kalpakas 28c166939e test($compile): test default value for optional attribute with new scope
Related to #12151
Closes #12194
2015-06-24 10:25:55 +02:00
Peter Bacon Darwin 14638f4a60 fix(ngOptions): only watch numeric properties of an array
It turns out that the options that are displayed are more constrained than
just whether the property starts with a $ character.
If the values collection is array-like then we only display the options that
are identified by numerical properties - it's an array right?

So this commit aligns `getWatchables` with `getOptions`.

See #12010
2015-06-23 17:47:34 -07:00
Peter Bacon Darwin 0c1fbdd242 chore(doc-gen): update to dgeni-packages 0.10.17
Make proper use of the new `git` package in dgeni-packages
2015-06-23 04:41:45 -07:00
Martin Staffa 33f7f26558 docs(ngChecked): note that it shouldn't be used with ngModel
Closes #11106
2015-06-22 23:39:08 +02:00
Martin Staffa e27eed3ca4 docs(ngCookies): improve deprecation notice 2015-06-22 23:37:50 +02:00
Gabriel Monteagudo 6cbbd96647 fix(merge): treat dates as atomic values instead of objects.
Makes angular.merge copy dates correctly.

Closes #11720

Closes #11720
2015-06-22 21:21:09 +02:00
Phil Brown d0cb69348e docs($http): set correct link to XMLHttpRequest.responseType
The link to MDN XMLHttpRequest.responseType was incorrect.

Closes #12183
2015-06-22 18:51:46 +02:00
Jandalf f15f8df2b4 docs($httpProvider): typo fix
fix a typo:
default.cache -> defaults.cache
2015-06-21 14:07:13 +02:00
Peter Bacon Darwin e7662ebc31 docs(directives): add multiElement tag to appropriate directives
Closes #11104
2015-06-21 01:52:01 +01:00
Peter Bacon Darwin 8ceed4faf3 chore(dependencies): update to dgeni-packages 0.10.15
Closes #11104
Closes #11418
2015-06-21 01:51:31 +01:00
Tsuyoshi Yoshizawa 6903b5ec4c fix($location): allow navigating outside the original base URL
Previously, if you navigated outside of the current base URL angular
crashed with a `Cannot call method 'charAt' of undefined` error.

Closes #11302
Closes #4776
2015-06-19 18:40:28 +01:00
Peter Bacon Darwin 48e1f5605e fix(orderBy): ensure correct ordering with arrays of objects and no predicate
By refactoring to use a Schwartzian transform, we can ensure that objects
with no custom `toString` or `toValue` methods are just ordered using
their position in the original collection.

Closes #11866
Closes #11312
Closes #4282
2015-06-18 08:36:16 +01:00
Peter Bacon Darwin c5a3d8fc5f refact(filter): move hasCustomToString into shared namespace to be reused 2015-06-18 08:33:28 +01:00
Martin Staffa c61149213b docs(CHANGELOG): fix position for some entries in 1.4.1 2015-06-17 23:57:54 +02:00
Stéphane Campinas ad7200e2c2 docs(tutorial/Tutorial): add missing word
Closes #12147
2015-06-17 21:19:02 +02:00
Alfonso Presa bea74c0f56 docs(ngTouch): Document event parameter for $swipe handlers
Document that the event handlers provided by $swipe do receive the raw
event as their last parameter.

Closes #11983

Closes #12149
2015-06-17 21:17:33 +02:00
Martin Staffa bacc3b7e0e docs(tutorial): make docTutorialReset use a button
It's confusing to have it look like a link that goes to the homepage

Closes #1473
2015-06-17 21:14:39 +02:00
Caitlin Potter 8a1eb1625c fix($compile): do not write @-bound properties if attribute is not present
Shadows only when attributes are non-optional and not own properties,
only stores the observed '@' values when they are indeed strings.

Partial revert of 6339d30d1379689da5eec9647a953f64821f8b0

Closes #12151
Closes #12144
2015-06-17 17:40:12 +01:00
Peter Bacon Darwin ed27e0ea6a docs(CHANGELOG): fix typo 2015-06-17 14:35:25 +01:00
Peter Bacon Darwin f81ff3beb0 fix($browser): prevent infinite digest if changing hash when there is no hashPrefix
The `window.location.hash' setter will strip of a single leading hash character
if it exists from the fragment  before joining the fragment value to the href
with a new hash character.

This meant that if we want the fragment to lead with a hash character, we
must do `window.location.hash = '##test'` to ensure that the first hash
character in the fragment is not lost.

The `$location.hash` setter works differently and assumes that the value
passed is the the full fragment, i.e. it does not attempt to strip off a
single leading hash character.

Previously, if you called, `$location.hash('#test')`, the leading hash was
being stripped and the resulting url fragment did not contain this hash:
`$location.hash()`, then became 'test' rather than `#test`, which led to
an infinite digest.

Closes #10423
Closes #12145
2015-06-17 14:01:20 +01:00
Martin Staffa 720012eab6 docs(resource): clarify success callback arguments
Closes #7730
2015-06-16 19:50:42 +02:00
Kent C. Dodds 3adfe5bda9 docs(guide/Unit Testing): add variable declaration to $filter test
The $filter example never declares `$filter` and therefore would add
`$filter` to the global namespace. Add variable declaration.

Closes #12129
2015-06-16 19:12:10 +02:00
Martin Staffa dc0467879d docs(input[radio]): clarify difference between value and ngValue
Closes #7971
2015-06-16 19:11:11 +02:00
Peter Bacon Darwin 528d7f9568 docs(CHANGELOG): add 1.4.1 changes 2015-06-16 14:52:17 +01:00
Georgios Kalpakas 636ce70e47 style(forms): fix indentation in example 2015-06-16 15:34:02 +03:00
Nir Noy 5f5ee0f880 docs(forms): remove redundant call to $scope.$apply()
As of Angular 1.3 `$setViewValue` already calls `$apply` and triggers a
digest cycle, so now there is no need wrapping the `$setViewValue`
function call with `$apply`, which will just trigger an additional digest
cycle.
2015-06-16 13:20:57 +03:00
40 changed files with 669 additions and 394 deletions
+71
View File
@@ -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)
+1 -1
View File
@@ -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' +
+2 -3
View File
@@ -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'))
-16
View File
@@ -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
};
};
+1 -3
View File
@@ -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
+5 -2
View File
@@ -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`)
+3 -1
View File
@@ -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() {
+1 -1
View File
@@ -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
View File
@@ -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": {
+207 -196
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -55,6 +55,7 @@
"isBlob": false,
"isBoolean": false,
"isPromiseLike": false,
"hasCustomToString": false,
"trim": false,
"escapeForRegexp": false,
"isElement": false,
+11 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+8 -1
View File
@@ -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
*/
+6 -3
View File
@@ -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">
+1
View File
@@ -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
+3 -3
View File
@@ -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();
+29 -22
View File
@@ -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++) {
+1
View File
@@ -3,6 +3,7 @@
/**
* @ngdoc directive
* @name ngRepeat
* @multiElement
*
* @description
* The `ngRepeat` directive instantiates a template once per item from a collection. Each template
+2
View File
@@ -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
-4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+17 -6
View File
@@ -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)) {
+5 -5
View File
@@ -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
* /&#42; normally we would create a CSS class to reference on the element &#42;/
* [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
View File
@@ -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 `&lt;div&gt;` and
* `&lt;li&gt;` 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');
}
+1 -1
View File
@@ -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>
*
+6 -5
View File
@@ -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.
*
+2 -1
View File
@@ -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).
+1 -2
View File
@@ -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);
}
}
+2 -1
View File
@@ -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
+22
View File
@@ -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());
});
});
+3 -1
View File
@@ -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
View File
@@ -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() {
+4 -2
View File
@@ -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';
+45 -2
View File
@@ -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
View File
@@ -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) {
+12
View File
@@ -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