Compare commits

..

53 Commits

Author SHA1 Message Date
Matias Niemelä 1622182737 docs(CHANGELOG): add changes for 1.4.3 2015-07-14 18:26:10 -07:00
Matias Niemelä 36efe6c1a2 test($animateCss): avoid unnecessary checking for transition-timing-function
There is no need to check for this in the test and it adds complexity
for linux-based browsers.
2015-07-14 14:07:50 -07:00
Matias Niemelä 5081982e30 test($animateCss): ensure that transitionStyle by itself doesn't trigger anything
Using `transitionStyle` without any other properties does not trigger an
animation so we could have a test to assert that it doesn't do that.
2015-07-14 13:45:11 -07:00
Matias Niemelä 97d79eec80 fix($animateCss): ensure animations execute if only a keyframeStyle is provided
`$animateCss` is a fan of transition animations, but it turns out that
if only a keyframeStyle is provided into the animation upon constrution
then it will quit because it assumes that nothing will be animated
(since no classes or styles are being applied). This patch ensures that
a keyframe style can solely be applied to an animation triggered with
`$animateCss`.

```js
// this will now work as expected
$animateCss(element, { keyframeStyle: '1s rotate' }).start();
```

Closes #12124
Closes #12340
2015-07-14 13:45:03 -07:00
Matias Niemelä e4aeae0c73 fix(ngAnimate): ensure that orphaned elements do not throw errors when animated
This fix ensures that both `$animateCss` and `$animate` swallow the error
when an animation takes place in the sitation that the element is removed
from the parent element sometime before or during the preparation stages of the
animation.

Closes #11975
Closes #12338
2015-07-14 21:06:55 +01:00
Dominic Watson 7202bfafcd docs(ngAnimate) - Correct keyframe to keyframeStyle 2015-07-14 10:42:05 -07:00
Steve Mao 4cef752985 docs(CONTRIBUTING): state what is mandatory or optional
Closes #12032
2015-07-13 13:24:52 +01:00
Steve Mao d38f6ff401 docs(CONTRIBUTING): how to write a breaking change
Closes #12032
2015-07-13 13:24:44 +01:00
Steve Mao 8f6dac9536 docs(CONTRIBUTING): revert is a modifier
EG: https://github.com/angular/angular.js/commit/462f444b06ae5cad3ccb761b1dba7131df01a655

Closes #12032
2015-07-13 13:24:34 +01:00
Peter Bacon Darwin de5b8dc781 docs(guide/controller): add a line about controller as 2015-07-13 13:22:01 +01:00
Peter Bacon Darwin 41834e6f4a docs(guide/controller): add a line about controller as 2015-07-13 13:18:29 +01:00
niteshthakur dbb42b5c85 docs(guide/controller): clarify that controllers are defined **by** a constructor function
A controller is a instantiated object created **from** a constructor function.
It was not accurate to describe a Controller **as** a constructor function.

Closes #11888
2015-07-13 13:18:29 +01:00
Peter Bacon Darwin f012374f12 docs($routeChangeSuccess): note that resolve values are available on current route
Closes #11413
2015-07-13 13:10:47 +01:00
Rouven Weßling 14e0b9c352 refactor(ngCsp): use document.head
The `head` property is available from IE9 onwards.

Closes #11905
2015-07-13 09:37:03 +01:00
Jerry Orta 9ea52d818b fix(loader): define isFunction
Closes: #12299
Closes: #12287
2015-07-10 22:54:58 +02:00
Martin Staffa d518a64d93 docs(CHANGELOG): add changes for 1.4.2 2015-07-06 22:19:53 +02:00
Wesley Cho fe0af2c073 chore(animate): remove dead code
- Remove unused `$$asyncCallback`

Fixes #12251
Closes #12254
2015-07-02 22:57:00 +02:00
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
52 changed files with 991 additions and 463 deletions
+231
View File
@@ -1,3 +1,234 @@
<a name="1.4.3"></a>
# 1.4.3 foam-acceleration (2015-07-06)
## Bug Fixes
- **$animateCss:** ensure animations execute if only a keyframeStyle is provided
([97d79eec](https://github.com/angular/angular.js/commit/97d79eec80092f5fae3336c23aa881a72436de55),
[#12124](https://github.com/angular/angular.js/issues/12124), [#12340](https://github.com/angular/angular.js/issues/12340))
- **$browser:** prevent infinite digest if changing hash when there is no hashPrefix
([f81ff3be](https://github.com/angular/angular.js/commit/f81ff3beb0c9d19d494c5878086fb57476442b8b),
[#10423](https://github.com/angular/angular.js/issues/10423), [#12145](https://github.com/angular/angular.js/issues/12145))
- **$compile:**
- throw error when requestng new and isolate scopes (async)
([6333d65b](https://github.com/angular/angular.js/commit/6333d65b76e0796cfbab8a2953af0c8014dba2e1),
[#12215](https://github.com/angular/angular.js/issues/12215), [#12217](https://github.com/angular/angular.js/issues/12217))
- do not write @-bound properties if attribute is not present
([8a1eb162](https://github.com/angular/angular.js/commit/8a1eb1625c080445ce1e519762e1f2d4fd842b72),
[#12151](https://github.com/angular/angular.js/issues/12151), [#12144](https://github.com/angular/angular.js/issues/12144))
- workaround for IE11 MutationObserver
([f3b1d0b7](https://github.com/angular/angular.js/commit/f3b1d0b723298a5f8ea21d0704405649cce1b5fc),
[#11781](https://github.com/angular/angular.js/issues/11781))
- exception when using "watch" as isolated scope binding variable in Firefox
([a6339d30](https://github.com/angular/angular.js/commit/a6339d30d1379689da5eec9647a953f64821f8b0),
[#11627](https://github.com/angular/angular.js/issues/11627))
- **$location:**
- allow navigating outside the original base URL
([6903b5ec](https://github.com/angular/angular.js/commit/6903b5ec4c04ed6b7c80ef7d638c48639ccdc4bb),
[#11302](https://github.com/angular/angular.js/issues/11302), [#4776](https://github.com/angular/angular.js/issues/4776))
- do not get caught in infinite digest in IE9
([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))
- set null reference properties to `undefined`
([d19504a1](https://github.com/angular/angular.js/commit/d19504a179355d7801d59a8db0285a1322e04601),
[#11959](https://github.com/angular/angular.js/issues/11959))
- **$sanitize:** dont not remove tab index property
([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))
- **compile:** assign ctrl 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))
- **copy:** do not copy the same object twice
([0e622f7b](https://github.com/angular/angular.js/commit/0e622f7b5bc3d5d0ab0fbc1a1bc69404bd7216d5))
- **forms:** parse exponential notation in numberInputType parser
([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))
- **loader:** define isFunction
([9ea52d81](https://github.com/angular/angular.js/commit/9ea52d818bcd2fb3ea8ccc85bf47f9fd5af68843))
- **merge:** treat dates as atomic values instead of objects.
([6cbbd966](https://github.com/angular/angular.js/commit/6cbbd966479448591f819cbf904e0a3b757613dc),
[#11720](https://github.com/angular/angular.js/issues/11720), [#11720](https://github.com/angular/angular.js/issues/11720))
- **ngAnimate:** ensure that orphaned elements do not throw errors when animated
([e4aeae0c](https://github.com/angular/angular.js/commit/e4aeae0c7303b94135e6df20e6c5e25f2aa0f586),
[#11975](https://github.com/angular/angular.js/issues/11975), [#12338](https://github.com/angular/angular.js/issues/12338))
- **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:** form validation when there is an Object.prototype enumerable value
([0934b76b](https://github.com/angular/angular.js/commit/0934b76b72cec86093414834ac4cb7f0946b651d),
[#12066](https://github.com/angular/angular.js/issues/12066))
- **ngOptions:**
- only watch numeric properties of an array
([14638f4a](https://github.com/angular/angular.js/commit/14638f4a60053b085565e597fc74bd31cf0d372b))
- 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))
- **orderBy:** ensure correct ordering with arrays of objects and no predicate
([48e1f560](https://github.com/angular/angular.js/commit/48e1f5605edd32a63318fd78f5165c7d1f1a20f9),
[#11866](https://github.com/angular/angular.js/issues/11866), [#11312](https://github.com/angular/angular.js/issues/11312), [#4282](https://github.com/angular/angular.js/issues/4282))
## 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))
- **ngAria:** add option to disable role=button
([1f5e42e8](https://github.com/angular/angular.js/commit/1f5e42e8821217026ef36a46d36f84d7cd32830a),
[#11580](https://github.com/angular/angular.js/issues/11580), [#12234](https://github.com/angular/angular.js/issues/12234))
## Performance Improvements
- **$compile:** avoid jquery data calls when there is no data
([9efb0d5e](https://github.com/angular/angular.js/commit/9efb0d5ee961b57c8fc144a3138a15955e4010e2))
<a name="1.4.2"></a>
# 1.4.2 nebular-readjustment (2015-07-06)
## Bug Fixes
- **$browser:** prevent infinite digest if changing hash when there is no hashPrefix
([f81ff3be](https://github.com/angular/angular.js/commit/f81ff3beb0c9d19d494c5878086fb57476442b8b),
[#10423](https://github.com/angular/angular.js/issues/10423), [#12145](https://github.com/angular/angular.js/issues/12145))
- **$compile:**
- throw error when requestng new and isolate scopes (async)
([6333d65b](https://github.com/angular/angular.js/commit/6333d65b76e0796cfbab8a2953af0c8014dba2e1),
[#12215](https://github.com/angular/angular.js/issues/12215), [#12217](https://github.com/angular/angular.js/issues/12217))
- **$location:** allow navigating outside the original base URL
([6903b5ec](https://github.com/angular/angular.js/commit/6903b5ec4c04ed6b7c80ef7d638c48639ccdc4bb),
[#11302](https://github.com/angular/angular.js/issues/11302), [#4776](https://github.com/angular/angular.js/issues/4776))
- **merge:** treat dates as atomic values instead of objects.
([6cbbd966](https://github.com/angular/angular.js/commit/6cbbd966479448591f819cbf904e0a3b757613dc),
[#11720](https://github.com/angular/angular.js/issues/11720), [#11720](https://github.com/angular/angular.js/issues/11720))
- **ngOptions:** only watch numeric properties of an array
([14638f4a](https://github.com/angular/angular.js/commit/14638f4a60053b085565e597fc74bd31cf0d372b))
- **orderBy:** ensure correct ordering with arrays of objects and no predicate
([48e1f560](https://github.com/angular/angular.js/commit/48e1f5605edd32a63318fd78f5165c7d1f1a20f9),
[#11866](https://github.com/angular/angular.js/issues/11866), [#11312](https://github.com/angular/angular.js/issues/11312), [#4282](https://github.com/angular/angular.js/issues/4282))
## Features
- **ngAria:** add option to disable role=button
([1f5e42e8](https://github.com/angular/angular.js/commit/1f5e42e8821217026ef36a46d36f84d7cd32830a),
[#11580](https://github.com/angular/angular.js/issues/11580), [#12234](https://github.com/angular/angular.js/issues/12234))
<a name="1.3.17"></a>
# 1.3.17 tsktskskly-euouae (2015-07-06)
## Bug Fixes
- **$browser:** prevent infinite digest if changing hash when there is no hashPrefix
([61a3fb67](https://github.com/angular/angular.js/commit/61a3fb676a186e22564fb0181c17647b35ca4e5e),
[#10423](https://github.com/angular/angular.js/issues/10423), [#12145](https://github.com/angular/angular.js/issues/12145))
- **$location:**
- allow navigating outside the original base URL
([0bb57d53](https://github.com/angular/angular.js/commit/0bb57d538f25a1b6f20025d87a451c39671b59aa),
[#11302](https://github.com/angular/angular.js/issues/11302), [#4776](https://github.com/angular/angular.js/issues/4776))
- do not get caught in infinite digest in IE9
([f486ebe8](https://github.com/angular/angular.js/commit/f486ebe80b6d7854d3eb9029f14d94299cf493cb),
[#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))
- **linky:** allow case insensitive scheme detection
([6b28aef1](https://github.com/angular/angular.js/commit/6b28aef1c537bfb2da21820d6ca154344efe266e),
[#12073](https://github.com/angular/angular.js/issues/12073), [#12074](https://github.com/angular/angular.js/issues/12074))
<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)
+6
View File
@@ -199,9 +199,14 @@ format that includes a **type**, a **scope** and a **subject**:
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
to read on github as well as in various git tools.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
@@ -235,6 +240,7 @@ The body should include the motivation for the change and contrast this with pre
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
A detailed explanation can be found in this [document][commit-message-format].
+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
};
};
+6 -3
View File
@@ -5,13 +5,16 @@
# Understanding Controllers
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
In Angular, a Controller is defined by a JavaScript **constructor function** that is used to augment the
{@link scope Angular Scope}.
When a Controller is attached to the DOM via the {@link ng.directive:ngController ng-controller}
directive, Angular will instantiate a new Controller object, using the specified Controller's
**constructor function**. A new **child scope** will be available as an injectable parameter to the
Controller's constructor function as `$scope`.
**constructor function**. A new **child scope** will be created and made available as an injectable
parameter to the Controller's constructor function as `$scope`.
If the controller has been attached using the `controller as` syntax then the controller instance will
be assigned to a property on the new scope.
Use controllers to:
+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
+1 -1
View File
@@ -116,7 +116,7 @@ module.exports = {
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/\r?\n/g, '\\n');
js = "!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type=\"text/css\">" + css + "</style>');";
js = "!window.angular.$$csp() && window.angular.element(document.head).prepend('<style type=\"text/css\">" + css + "</style>');";
state.js.push(js);
return state;
+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
-2
View File
@@ -87,7 +87,6 @@
$$TestabilityProvider,
$TimeoutProvider,
$$RAFProvider,
$$AsyncCallbackProvider,
$WindowProvider,
$$jqLiteProvider,
$$CookieReaderProvider
@@ -248,7 +247,6 @@ function publishExternalAPI(angular) {
$timeout: $TimeoutProvider,
$window: $WindowProvider,
$$rAF: $$RAFProvider,
$$asyncCallback: $$AsyncCallbackProvider,
$$jqLite: $$jqLiteProvider,
$$HashMap: $$HashMapProvider,
$$cookieReader: $$CookieReaderProvider
+1
View File
@@ -5,3 +5,4 @@
*/
'use strict';
(function() {
function isFunction(value) {return typeof value === 'function';};
+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)) {
+16 -4
View File
@@ -186,7 +186,7 @@
* to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)
* * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).
* * `transition` - The raw CSS transition style that will be used (e.g. `1s linear all`).
* * `keyframe` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
* * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).
* * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.
* * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.
* * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.
@@ -497,6 +497,10 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
function init(element, options) {
var node = getDomNode(element);
if (!node || !node.parentNode) {
return closeAndReturnNoopAnimator();
}
options = prepareAnimationOptions(options);
var temporaryStyles = [];
@@ -556,10 +560,14 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
var fullClassName = classes + ' ' + setupClasses;
var activeClasses = pendClasses(setupClasses, '-active');
var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
// there is no way we can trigger an animation since no styles and
// no classes are being applied which would then trigger a transition
if (!hasToStyles && !setupClasses) {
// there is no way we can trigger an animation if no styles and
// no classes are being applied which would then trigger a transition,
// unless there a is raw keyframe value that is applied to the element.
if (!containsKeyframeAnimation
&& !hasToStyles
&& !setupClasses) {
return closeAndReturnNoopAnimator();
}
@@ -782,6 +790,10 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
function start() {
if (animationClosed) return;
if (!node.parentNode) {
close();
return;
}
var startTime, events = [];
+1 -1
View File
@@ -138,7 +138,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
? (animationEntry.from.element || animationEntry.to.element)
: animationEntry.element;
if (getRunner(targetElement)) {
if (getRunner(targetElement) && getDomNode(targetElement).parentNode) {
var operation = invokeFirstDriver(animationEntry);
if (operation) {
startAnimationFn = operation.start;
+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 -18
View File
@@ -764,15 +764,14 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
};
});
$provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser', '$$rAF',
function($delegate, $$asyncCallback, $timeout, $browser, $$rAF) {
$provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF',
function($delegate, $timeout, $browser, $$rAF) {
var animate = {
queue: [],
cancel: $delegate.cancel,
enabled: $delegate.enabled,
triggerCallbackEvents: function() {
$$rAF.flush();
$$asyncCallback.flush();
},
triggerCallbackPromise: function() {
$timeout.flush(0);
@@ -1764,20 +1763,6 @@ angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
return rafFn;
}];
angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
var callbacks = [];
var addFn = function(fn) {
callbacks.push(fn);
};
addFn.flush = function() {
angular.forEach(callbacks, function(fn) {
fn();
});
callbacks = [];
};
return addFn;
}];
/**
*
*/
@@ -1884,7 +1869,6 @@ angular.module('ngMock', ['ng']).provider({
}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
$provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
$provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
$provide.decorator('$controller', angular.mock.$ControllerDecorator);
}]);
+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).
+4 -3
View File
@@ -407,7 +407,9 @@ function $RouteProvider() {
* @name $route#$routeChangeSuccess
* @eventType broadcast on root scope
* @description
* Broadcasted after a route dependencies are resolved.
* Broadcasted after a route change has happened successfully.
* The `resolve` dependencies are now available in the `current.locals` property.
*
* {@link ngRoute.directive:ngView ngView} listens for the directive
* to instantiate the controller and render the view.
*
@@ -591,9 +593,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());
});
});
-33
View File
@@ -1,33 +0,0 @@
'use strict';
describe('$$asyncCallback', function() {
it('should perform a callback asynchronously', inject(function($$asyncCallback) {
var message = 'hello there ';
$$asyncCallback(function() {
message += 'Angular';
});
expect(message).toBe('hello there ');
$$asyncCallback.flush();
expect(message).toBe('hello there Angular');
}));
describe('mocks', function() {
it('should queue up all async callbacks', inject(function($$asyncCallback) {
var callback = jasmine.createSpy('callback');
$$asyncCallback(callback);
$$asyncCallback(callback);
$$asyncCallback(callback);
expect(callback.callCount).toBe(0);
$$asyncCallback.flush();
expect(callback.callCount).toBe(3);
$$asyncCallback(callback);
$$asyncCallback(callback);
expect(callback.callCount).toBe(3);
$$asyncCallback.flush();
expect(callback.callCount).toBe(5);
}));
});
});
+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) {
+76 -1
View File
@@ -51,6 +51,43 @@ describe("ngAnimate $animateCss", function() {
describe('when active', function() {
if (!browserSupportsCssAnimations()) return;
it("should silently quit the animation and not throw when an element has no parent during preparation",
inject(function($animateCss, $$rAF, $rootScope, $document, $rootElement) {
var element = jqLite('<div></div>');
expect(function() {
$animateCss(element, {
duration: 1000,
event: 'fake',
to: fakeStyle
}).start();
}).not.toThrow();
expect(element).not.toHaveClass('fake');
triggerAnimationStartFrame();
expect(element).not.toHaveClass('fake-active');
}));
it("should silently quit the animation and not throw when an element has no parent before starting",
inject(function($animateCss, $$rAF, $rootScope, $document, $rootElement) {
var element = jqLite('<div></div>');
jqLite($document[0].body).append($rootElement);
$rootElement.append(element);
$animateCss(element, {
duration: 1000,
addClass: 'wait-for-it',
to: fakeStyle
}).start();
element.remove();
expect(function() {
triggerAnimationStartFrame();
}).not.toThrow();
}));
describe("rAF usage", function() {
it("should buffer all requests into a single requestAnimationFrame call",
inject(function($animateCss, $$rAF, $rootScope, $document, $rootElement) {
@@ -2017,7 +2054,7 @@ describe("ngAnimate $animateCss", function() {
});
});
describe("[transtionStyle]", function() {
describe("[transitionStyle]", function() {
it("should apply the transition directly onto the element and animate accordingly",
inject(function($animateCss, $rootElement) {
@@ -2092,6 +2129,27 @@ describe("ngAnimate $animateCss", function() {
expect(element.css('transition-property')).toMatch('color');
expect(style).toContain('ease-in');
}));
it("should execute the animation only if there is any provided CSS styling to go with the transition",
inject(function($animateCss, $rootElement) {
var options = {
transitionStyle: '6s 4s ease-out all'
};
$animateCss(element, options).start();
triggerAnimationStartFrame();
expect(element.css(prefix + 'transition-delay')).not.toEqual('4s');
expect(element.css(prefix + 'transition-duration')).not.toEqual('6s');
options.to = { color: 'brown' };
$animateCss(element, options).start();
triggerAnimationStartFrame();
expect(element.css(prefix + 'transition-delay')).toEqual('4s');
expect(element.css(prefix + 'transition-duration')).toEqual('6s');
}));
});
describe("[keyframeStyle]", function() {
@@ -2167,6 +2225,23 @@ describe("ngAnimate $animateCss", function() {
expect(element.css(prefix + 'animation-duration')).toEqual('5.5s');
expect(element.css(prefix + 'animation-name')).toEqual('my_animation');
}));
it("should be able to execute the animation if it is the only provided value",
inject(function($animateCss, $rootElement) {
var options = {
keyframeStyle: 'my_animation 5.5s 10s'
};
var animator = $animateCss(element, options);
animator.start();
triggerAnimationStartFrame();
expect(element.css(prefix + 'animation-delay')).toEqual('10s');
expect(element.css(prefix + 'animation-duration')).toEqual('5.5s');
expect(element.css(prefix + 'animation-name')).toEqual('my_animation');
}));
});
describe("[from] and [to]", function() {
+23 -5
View File
@@ -80,8 +80,10 @@ describe('$$animation', function() {
};
});
inject(function($$animation, $rootScope) {
inject(function($$animation, $rootScope, $rootElement) {
element = jqLite('<div></div>');
$rootElement.append(element);
$$animation(element, 'enter');
$rootScope.$digest();
@@ -109,7 +111,8 @@ describe('$$animation', function() {
}));
it("should obtain the element, event, the provided options and the domOperation",
inject(function($$animation, $rootScope) {
inject(function($$animation, $rootScope, $rootElement) {
$rootElement.append(element);
var options = {};
options.foo = 'bar';
@@ -132,9 +135,11 @@ describe('$$animation', function() {
}));
it("should obtain the classes string which is a combination of className, addClass and removeClass",
inject(function($$animation, $rootScope) {
inject(function($$animation, $rootScope, $rootElement) {
element.addClass('blue red');
$rootElement.append(element);
$$animation(element, 'enter', {
addClass: 'green',
removeClass: 'orange',
@@ -165,8 +170,9 @@ describe('$$animation', function() {
});
});
inject(function($$animation, $rootScope) {
inject(function($$animation, $rootScope, $rootElement) {
element = jqLite('<div></div>');
$rootElement.append(element);
$$animation(element, 'enter');
$rootScope.$digest();
expect(log).toEqual(['second', 'first']);
@@ -237,8 +243,10 @@ describe('$$animation', function() {
});
});
inject(function($$animation, $rootScope) {
inject(function($$animation, $rootScope, $rootElement) {
element = jqLite('<div></div>');
$rootElement.append(element);
var runner = $$animation(element, 'enter');
$rootScope.$digest();
@@ -791,6 +799,8 @@ describe('$$animation', function() {
it('should temporarily assign the provided CSS class for the duration of the animation',
inject(function($rootScope, $$animation) {
parent.append(element);
$$animation(element, 'enter', {
tempClasses: 'temporary fudge'
});
@@ -809,6 +819,8 @@ describe('$$animation', function() {
it('should add and remove the ng-animate CSS class when the animation is active',
inject(function($$animation, $rootScope) {
parent.append(element);
$$animation(element, 'enter');
$rootScope.$digest();
expect(element).toHaveClass('ng-animate');
@@ -823,6 +835,8 @@ describe('$$animation', function() {
it('should apply the `ng-animate` and temporary CSS classes before the driver is invoked', function() {
var capturedElementClasses;
parent.append(element);
module(function($provide) {
$provide.factory('mockedTestDriver', function() {
return function(details) {
@@ -832,6 +846,8 @@ describe('$$animation', function() {
});
inject(function($$animation, $rootScope) {
parent.append(element);
$$animation(element, 'enter', {
tempClasses: 'temp-class-name'
});
@@ -845,6 +861,8 @@ describe('$$animation', function() {
it('should perform the DOM operation at the end of the animation if the driver doesn\'t run it already',
inject(function($$animation, $rootScope) {
parent.append(element);
var domOperationFired = false;
$$animation(element, 'enter', {
domOperation: function() {
+27
View File
@@ -105,6 +105,33 @@ describe('ngAnimate integration tests', function() {
expect(animationCompleted).toBe(true);
});
});
it('should not throw an error if the element is orphaned before the CSS animation starts',
inject(function($rootScope, $rootElement, $animate, $$rAF) {
ss.addRule('.animate-me', 'transition:2s linear all;');
var parent = jqLite('<div></div>');
html(parent);
var element = jqLite('<div class="animate-me">DOING</div>');
parent.append(element);
$animate.addClass(parent, 'on');
$animate.addClass(element, 'on');
$rootScope.$digest();
// this will run the first class-based animation
$$rAF.flush();
element.remove();
expect(function() {
$$rAF.flush();
}).not.toThrow();
dealoc(element);
}));
});
describe('JS animations', function() {
+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