Compare commits
156 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a3504abdc | |||
| 0dfc1dfebf | |||
| e9c406b246 | |||
| 79b6d55792 | |||
| 8f94b5b277 | |||
| b11120be0a | |||
| bfba95ce46 | |||
| 310f80e78e | |||
| acfda1022d | |||
| 04d4d93e5b | |||
| 8348365df9 | |||
| 16bcdcb61d | |||
| adcfa74327 | |||
| d641901be6 | |||
| eae0a1121f | |||
| 173c9063e7 | |||
| b461551b81 | |||
| 63492a0261 | |||
| adb0e1746b | |||
| 3be79cd6a1 | |||
| e4c6e01791 | |||
| fb76d96009 | |||
| f322c4f3c3 | |||
| 081f6ec7f2 | |||
| 9bb6a30417 | |||
| 97e97d1eb7 | |||
| 1ab4e44443 | |||
| 99eeec358c | |||
| ce8a7525cc | |||
| 5df2e5ce29 | |||
| ef03dfc4a4 | |||
| 4ff9c027b0 | |||
| 20b8ece444 | |||
| 6406e3b01d | |||
| 234053fc9a | |||
| a277bcf0f7 | |||
| 7985416d39 | |||
| dc3013e848 | |||
| 0f2926db38 | |||
| bd59335eba | |||
| 6aa111b333 | |||
| 42b5ce99fb | |||
| 2cb1989d12 | |||
| 1137d91abd | |||
| 288e4e33c3 | |||
| d98c5f03a4 | |||
| 8d20b04f1c | |||
| 56c3666fe5 | |||
| cd21216ff7 | |||
| 3ffdf380c5 | |||
| db5e0ffe12 | |||
| 92e4801d88 | |||
| 6a92e9111f | |||
| ba6d37756e | |||
| 683bd92f56 | |||
| 7700e2df09 | |||
| 3fb809e412 | |||
| 52ea4110d3 | |||
| a3a7afd3aa | |||
| 20bc37fbc8 | |||
| 7761b6c3b0 | |||
| b77e14beea | |||
| a1f461e429 | |||
| 13587193a5 | |||
| a1ff35850c | |||
| 95b3e1ce6c | |||
| b78b12976a | |||
| a31c082de6 | |||
| 5afd54514d | |||
| 72b96ef57a | |||
| 90975db5f9 | |||
| 25bc531802 | |||
| 4e1b36c216 | |||
| d4fa331308 | |||
| a801df719e | |||
| cb74999b17 | |||
| 2764536e8f | |||
| 8ccc0547a8 | |||
| dd14e0c44d | |||
| 7e24590fa3 | |||
| 8b6360338d | |||
| d91cf16796 | |||
| f31c5a3924 | |||
| 16ccac91d0 | |||
| 91b080e6e6 | |||
| feeb19787c | |||
| 98c2db7f9c | |||
| 06aa52efff | |||
| fabc6ab5b0 | |||
| 93c7251f5f | |||
| e1def1b8fe | |||
| e5cab951f4 | |||
| f7eab8d8fe | |||
| 495d40d802 | |||
| d28ae2126e | |||
| 8955cfb646 | |||
| 776972ed9c | |||
| 1358b3ca9b | |||
| e020b8993e | |||
| b2b896f949 | |||
| 3c5827b6f5 | |||
| 0e03644dad | |||
| 112024271b | |||
| bca0a1f786 | |||
| 959f2bbb2d | |||
| 6a47c0d75d | |||
| b0248b7894 | |||
| 6fd41e7f59 | |||
| 3297bbd188 | |||
| 8863836cd4 | |||
| b8fb0c4573 | |||
| 17b700a339 | |||
| 811b20e3b9 | |||
| 5ded3d3e73 | |||
| 986647a968 | |||
| 7b51243be5 | |||
| 798fb18542 | |||
| 99d601a048 | |||
| a6e9174a27 | |||
| dec8a0eb72 | |||
| 98776487a0 | |||
| b3ef5e0852 | |||
| 04efdd5bfa | |||
| 9f5d76e16b | |||
| 525be5b7d4 | |||
| 042e0f1f0a | |||
| 03872983a4 | |||
| 62f79e820f | |||
| e5c26e92cc | |||
| 4bcb307abc | |||
| 0e729e1dd5 | |||
| 9bb184d181 | |||
| a7a053f5be | |||
| 9630159444 | |||
| e3be5d6efa | |||
| c2173c1298 | |||
| 0b94e8a8bf | |||
| 983374c574 | |||
| 05d3ed0d9b | |||
| 1b25f80cd2 | |||
| 6cdbda7cf1 | |||
| c9e6cf9be0 | |||
| c7ed8a33af | |||
| 6988667e5e | |||
| e57cf13d5d | |||
| e4e5677fbd | |||
| 8b6b428271 | |||
| 8f0b482596 | |||
| 6428ed5bb5 | |||
| bc41ad8aa8 | |||
| 6858caf251 | |||
| 20604e7fc4 | |||
| b7b06d8477 | |||
| de9777d819 | |||
| 1b06f33f30 | |||
| ca6e266869 |
+17
-22
@@ -1,7 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '4.2'
|
||||
|
||||
cache:
|
||||
directories:
|
||||
@@ -15,28 +15,26 @@ branches:
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- JOB=ci-checks
|
||||
- JOB=unit BROWSER_PROVIDER=saucelabs
|
||||
- JOB=docs-e2e BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=saucelabs
|
||||
- JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=saucelabs
|
||||
# - JOB=unit BROWSER_PROVIDER=browserstack
|
||||
# - JOB=docs-e2e BROWSER_PROVIDER=browserstack
|
||||
# - JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack
|
||||
# - JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack
|
||||
global:
|
||||
- CXX=g++-4.8 # node 4 likes the G++ v4.8 compiler
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- BROWSER_STACK_USERNAME=VojtaJina
|
||||
- BROWSER_STACK_ACCESS_KEY=QCQJ1ZpWXpBkSwEdD8ev
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/browsersprovider-tunnel-ready
|
||||
|
||||
#matrix:
|
||||
# allow_failures:
|
||||
# - env: "JOB=unit BROWSER_PROVIDER=browserstack"
|
||||
# - env: "JOB=docs-e2e BROWSER_PROVIDER=browserstack"
|
||||
# - env: "JOB=e2e TEST_TARGET=jqlite BROWSER_PROVIDER=browserstack"
|
||||
# - env: "JOB=e2e TEST_TARGET=jquery BROWSER_PROVIDER=browserstack"
|
||||
# node 4 likes the G++ v4.8 compiler
|
||||
# see https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
|
||||
install:
|
||||
# Check the size of caches
|
||||
@@ -46,16 +44,12 @@ install:
|
||||
- npm config set spin false
|
||||
# Log HTTP requests
|
||||
- npm config set loglevel http
|
||||
- npm install -g npm@2.5
|
||||
# Instal npm dependecies and ensure that npm cache is not stale
|
||||
#- npm install -g npm@2.5
|
||||
# Install npm dependencies and ensure that npm cache is not stale
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
- ./scripts/travis/start_browser_provider.sh
|
||||
- npm install -g grunt-cli
|
||||
- grunt package
|
||||
- ./scripts/travis/wait_for_browser_provider.sh
|
||||
- ./scripts/travis/before_build.sh
|
||||
|
||||
script:
|
||||
- ./scripts/travis/build.sh
|
||||
@@ -68,6 +62,7 @@ notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/d2120f3f2bb39a4531b2
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
- http://104.197.9.155:8484/hubot/travis/activity #hubot-server
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
on_start: always # default: false
|
||||
|
||||
+448
-150
@@ -1,3 +1,382 @@
|
||||
<a name="1.5.0-rc.2"></a>
|
||||
# 1.5.0-rc.2 controller-requisition (2016-01-28)
|
||||
|
||||
## Deprecation Warning
|
||||
|
||||
- The `ngTouch` module's `ngClick` directive has been deprecated and disabled by default. See the breaking
|
||||
changes section for more information
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- properly denormalize templates when only one of the start/end symbols is different
|
||||
([8348365d](https://github.com/angular/angular.js/commit/8348365df9b9e2d4c9c8d5211e3424d4b9a29767),
|
||||
[#13848](https://github.com/angular/angular.js/issues/13848))
|
||||
- handle boolean attributes in `@` bindings
|
||||
([db5e0ffe](https://github.com/angular/angular.js/commit/db5e0ffe124ac588f01ef0fe79efebfa72f5eec7),
|
||||
[#13767](https://github.com/angular/angular.js/issues/13767), [#13769](https://github.com/angular/angular.js/issues/13769))
|
||||
- **$parse:** Preserve expensive checks when runnning $eval inside an expression
|
||||
([acfda102](https://github.com/angular/angular.js/commit/acfda1022d23ecaea34bbc8931588a0715b3ab03))
|
||||
- **dateFilter:** follow the CLDR on pattern escape sequences
|
||||
([1ab4e444](https://github.com/angular/angular.js/commit/1ab4e44443716c33cd857dcb1098d20580dbb0cc),
|
||||
[#12839](https://github.com/angular/angular.js/issues/12839))
|
||||
- **ngAnimate:**
|
||||
- cancel fallback timeout when animation ends normally
|
||||
([e9c406b2](https://github.com/angular/angular.js/commit/e9c406b2464614c9784f7324d8910180c81c38a7),
|
||||
[#13787](https://github.com/angular/angular.js/issues/13787))
|
||||
- correctly handle `$animate.pin()` host elements
|
||||
([7700e2df](https://github.com/angular/angular.js/commit/7700e2df096cf50dfdf84841cab7e2d24d2eb96d),
|
||||
[#13783](https://github.com/angular/angular.js/issues/13783))
|
||||
- properly cancel-out previously running class-based animations
|
||||
([20b8ece4](https://github.com/angular/angular.js/commit/20b8ece444408a64ac69f7b5d45ddb3af0c418a0),
|
||||
[#10156](https://github.com/angular/angular.js/issues/10156), [#13822](https://github.com/angular/angular.js/issues/13822))
|
||||
- ensure that animate promises resolve when the document is hidden
|
||||
([52ea4110](https://github.com/angular/angular.js/commit/52ea4110d33b7de2845a698913682a03365aa074))
|
||||
- do not trigger animations if the document is hidden
|
||||
([a3a7afd3](https://github.com/angular/angular.js/commit/a3a7afd3aa70d981b0210088df53fa2cf68d3a3d),
|
||||
[#12842](https://github.com/angular/angular.js/issues/12842), [#13776](https://github.com/angular/angular.js/issues/13776))
|
||||
- **ngSanitize:** Blacklist the attribute `usemap`
|
||||
([234053fc](https://github.com/angular/angular.js/commit/234053fc9ad90e0d05be7e8359c6af66be94c094))
|
||||
- **ngTouch:** deprecate ngClick and disable it by default
|
||||
([0dfc1dfe](https://github.com/angular/angular.js/commit/0dfc1dfebf26af7f951f301c4e3848ac46f05d7f),
|
||||
[#4030](https://github.com/angular/angular.js/issues/4030), [#5307](https://github.com/angular/angular.js/issues/5307), [#6001](https://github.com/angular/angular.js/issues/6001), [#6432](https://github.com/angular/angular.js/issues/6432), [#7231](https://github.com/angular/angular.js/issues/7231), [#11358](https://github.com/angular/angular.js/issues/11358), [#12082](https://github.com/angular/angular.js/issues/12082), [#12153](https://github.com/angular/angular.js/issues/12153), [#12392](https://github.com/angular/angular.js/issues/12392), [#12545](https://github.com/angular/angular.js/issues/12545), [#12867](https://github.com/angular/angular.js/issues/12867), [#13213](https://github.com/angular/angular.js/issues/13213), [#13558](https://github.com/angular/angular.js/issues/13558), [#3296](https://github.com/angular/angular.js/issues/3296), [#3347](https://github.com/angular/angular.js/issues/3347), [#3447](https://github.com/angular/angular.js/issues/3447), [#3999](https://github.com/angular/angular.js/issues/3999), [#4428](https://github.com/angular/angular.js/issues/4428), [#6251](https://github.com/angular/angular.js/issues/6251), [#6330](https://github.com/angular/angular.js/issues/6330), [#7134](https://github.com/angular/angular.js/issues/7134), [#7935](https://github.com/angular/angular.js/issues/7935), [#9724](https://github.com/angular/angular.js/issues/9724), [#9744](https://github.com/angular/angular.js/issues/9744), [#9872](https://github.com/angular/angular.js/issues/9872), [#10211](https://github.com/angular/angular.js/issues/10211), [#10366](https://github.com/angular/angular.js/issues/10366), [#10918](https://github.com/angular/angular.js/issues/10918), [#11197](https://github.com/angular/angular.js/issues/11197), [#11261](https://github.com/angular/angular.js/issues/11261), [#11342](https://github.com/angular/angular.js/issues/11342), [#11577](https://github.com/angular/angular.js/issues/11577), [#12150](https://github.com/angular/angular.js/issues/12150), [#12317](https://github.com/angular/angular.js/issues/12317), [#12455](https://github.com/angular/angular.js/issues/12455), [#12734](https://github.com/angular/angular.js/issues/12734), [#13122](https://github.com/angular/angular.js/issues/13122), [#13272](https://github.com/angular/angular.js/issues/13272), [#13447](https://github.com/angular/angular.js/issues/13447))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:**
|
||||
- allow required controllers to be bound to the directive controller
|
||||
([56c3666f](https://github.com/angular/angular.js/commit/56c3666fe50955aa7d1c1b6159626f1c1cb34637),
|
||||
[#6040](https://github.com/angular/angular.js/issues/6040), [#5893](https://github.com/angular/angular.js/issues/5893), [#13763](https://github.com/angular/angular.js/issues/13763))
|
||||
- allow directive definition property `require` to be an object
|
||||
([cd21216f](https://github.com/angular/angular.js/commit/cd21216ff7eb6d81fc9aa1d1ef994c3d8e046394),
|
||||
[#8401](https://github.com/angular/angular.js/issues/8401), [#13763](https://github.com/angular/angular.js/issues/13763))
|
||||
- call `$ngOnInit` on directive controllers after all sibling controllers have been constructed
|
||||
([3ffdf380](https://github.com/angular/angular.js/commit/3ffdf380c522cbf15a4ce5a8b08d21d40d5f8859),
|
||||
[#13763](https://github.com/angular/angular.js/issues/13763))
|
||||
- **$locale:** include original locale ID in `$locale`
|
||||
([63492a02](https://github.com/angular/angular.js/commit/63492a02614a33a50cc28f9fdd73bae731352dd5),
|
||||
[#13390](https://github.com/angular/angular.js/issues/13390))
|
||||
- **$resource:** add support for timeout in cancellable actions
|
||||
([d641901b](https://github.com/angular/angular.js/commit/d641901be6887cdd93dc678eb514366eb759d21e),
|
||||
[#13824](https://github.com/angular/angular.js/issues/13824))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** avoid needless overhead when wrapping text nodes
|
||||
([92e4801d](https://github.com/angular/angular.js/commit/92e4801d88fbe9b7ef719fd3d0175d85420e1cc4))
|
||||
- **ngAnimate:** speed up `areAnimationsAllowed` check
|
||||
([683bd92f](https://github.com/angular/angular.js/commit/683bd92f56990bf1bfeabf619d997716909ebf6b))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngTouch:** due to [0dfc1dfe](https://github.com/angular/angular.js/commit/0dfc1dfebf26af7f951f301c4e3848ac46f05d7f),
|
||||
|
||||
|
||||
The `ngClick` override directive from the `ngTouch` module is **deprecated and disabled by default**.
|
||||
This means that on touch-based devices, users might now experience a 300ms delay before a click event is fired.
|
||||
|
||||
If you rely on this directive, you can still enable it with the `$touchProvider.ngClickOverrideEnabled()`method:
|
||||
|
||||
```js
|
||||
angular.module('myApp').config(function($touchProvider) {
|
||||
$touchProvider.ngClickOverrideEnabled(true);
|
||||
});
|
||||
```
|
||||
|
||||
Going forward, we recommend using [FastClick](https://github.com/ftlabs/fastclick) or perhaps one of the [Angular
|
||||
3rd party touch-related modules](http://ngmodules.org/tags/touch) that provide similar functionality.
|
||||
|
||||
Also note that modern browsers already remove the 300ms delay under some circumstances:
|
||||
- Chrome and Firefox for Android remove the 300ms delay when the well-known `<meta name="viewport" content="width=device-width">` is set
|
||||
- Internet Explorer removes the delay when `touch-action` css property is set to `none` or `manipulation`
|
||||
- Since iOs 8, Safari removes the delay on so-called "slow taps"
|
||||
|
||||
See this [article by Telerik](http://developer.telerik.com/featured/300-ms-click-delay-ios-8/) for more info on the topic.
|
||||
|
||||
**Note that this change does not affect the `ngSwipe` directive.**
|
||||
|
||||
|
||||
<a name="1.4.9"></a>
|
||||
# 1.4.9 implicit-superannuation (2016-01-21)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Animation**
|
||||
- ensure that animate promises resolve when the document is hidden
|
||||
([9a60408c](https://github.com/angular/angular.js/commit/9a60408c804a62a9517857bdb9a42182ab6769e3))
|
||||
- do not trigger animations if the document is hidden
|
||||
([09f6061a](https://github.com/angular/angular.js/commit/09f6061a8ee41cae4268e8d44d727d3bf52e22a9),
|
||||
[#12842](https://github.com/angular/angular.js/issues/12842), [#13776](https://github.com/angular/angular.js/issues/13776))
|
||||
- only copy over the animation options once
|
||||
([2fc954d3](https://github.com/angular/angular.js/commit/2fc954d33a3a4c5d4f355be1e15a381664e02f1b),
|
||||
[#13722](https://github.com/angular/angular.js/issues/13722), [#13578](https://github.com/angular/angular.js/issues/13578))
|
||||
- allow event listeners on document in IE
|
||||
([5ba4419e](https://github.com/angular/angular.js/commit/5ba4419e265ff34c6c23bf3533a3332c99c5f014),
|
||||
[#13548](https://github.com/angular/angular.js/issues/13548), [#13696](https://github.com/angular/angular.js/issues/13696))
|
||||
- allow removing classes that are added by a running animation
|
||||
([6c4581fc](https://github.com/angular/angular.js/commit/6c4581fcb692b17295a41b8918c6038333e7bc3d),
|
||||
[#13339](https://github.com/angular/angular.js/issues/13339), [#13380](https://github.com/angular/angular.js/issues/13380), [#13414](https://github.com/angular/angular.js/issues/13414), [#13472](https://github.com/angular/angular.js/issues/13472), [#13678](https://github.com/angular/angular.js/issues/13678))
|
||||
- do not use `event.timeStamp` anymore for time tracking
|
||||
([620a20d1](https://github.com/angular/angular.js/commit/620a20d1b3376d95f85004ffa494e36bb19a2e4d),
|
||||
[#13494](https://github.com/angular/angular.js/issues/13494), [#13495](https://github.com/angular/angular.js/issues/13495))
|
||||
- ignore children without animation data when closing them
|
||||
([be01cebf](https://github.com/angular/angular.js/commit/be01cebfae9ca2383105e535820442b39a96b240),
|
||||
[#11992](https://github.com/angular/angular.js/issues/11992), [#13424](https://github.com/angular/angular.js/issues/13424))
|
||||
- do not alter the provided options data
|
||||
([7a81e6fe](https://github.com/angular/angular.js/commit/7a81e6fe2db084172e34d509f0baad2b33a8722c),
|
||||
[#13040](https://github.com/angular/angular.js/issues/13040), [#13175](https://github.com/angular/angular.js/issues/13175))
|
||||
- correctly handle `$animate.pin()` host elements
|
||||
([a985adfd](https://github.com/angular/angular.js/commit/a985adfdabd871f3f3f3ee59f371da50cd9611d9),
|
||||
[#13783](https://github.com/angular/angular.js/issues/13783))
|
||||
- allow animations when pinned element is parent element
|
||||
([4cb8ac61](https://github.com/angular/angular.js/commit/4cb8ac61c7574ab4039852c358dd5946268b69fb),
|
||||
[#13466](https://github.com/angular/angular.js/issues/13466))
|
||||
- allow enabled children to animate on disabled parents
|
||||
([6d85f24e](https://github.com/angular/angular.js/commit/6d85f24e2081d2a69c80697d90ebd45f228d9682),
|
||||
[#13179](https://github.com/angular/angular.js/issues/13179), [#13695](https://github.com/angular/angular.js/issues/13695))
|
||||
- correctly access `minErr`
|
||||
([0c1b54f0](https://github.com/angular/angular.js/commit/0c1b54f04cf5bd7c1fe42ac49b4fbfdf35c60979))
|
||||
- ensure animate runner is the same with and without animations
|
||||
([937942f5](https://github.com/angular/angular.js/commit/937942f5ada6de1bdacdf0ba465f6f118c270119),
|
||||
[#13205](https://github.com/angular/angular.js/issues/13205), [#13347](https://github.com/angular/angular.js/issues/13347))
|
||||
- remove animation end event listeners on close
|
||||
([d9157849](https://github.com/angular/angular.js/commit/d9157849df224a3a8d2e0bf03099d137f51499f6),
|
||||
[#13672](https://github.com/angular/angular.js/issues/13672))
|
||||
- consider options.delay value for closing timeout
|
||||
([592bf516](https://github.com/angular/angular.js/commit/592bf516e50b9729e446d9aa01f4d9ebdd72d187),
|
||||
[#13355](https://github.com/angular/angular.js/issues/13355), [#13363](https://github.com/angular/angular.js/issues/13363))
|
||||
- **$controller:** allow identifiers containing `$`
|
||||
([2563ff7b](https://github.com/angular/angular.js/commit/2563ff7ba92d84af978e7e4131253190d4d00c20),
|
||||
[#13736](https://github.com/angular/angular.js/issues/13736))
|
||||
- **$http:** throw if url passed is not a string
|
||||
([c5bf9dae](https://github.com/angular/angular.js/commit/c5bf9daef6dfdb3e4a2942c21155a9f67d92e237),
|
||||
[#12925](https://github.com/angular/angular.js/issues/12925), [#13444](https://github.com/angular/angular.js/issues/13444))
|
||||
- **$parse:** handle interceptors with `undefined` expressions
|
||||
([7bb2414b](https://github.com/angular/angular.js/commit/7bb2414bf6461aa45a983fd322ae875f81814cc4))
|
||||
- **$resource:** don't allow using promises as `timeout` and log a warning
|
||||
([47486524](https://github.com/angular/angular.js/commit/474865242c89ba3e8143f0cd52f8c292979ea730))
|
||||
- **formatNumber:** cope with large and small number corner cases
|
||||
([9c49eb13](https://github.com/angular/angular.js/commit/9c49eb131a6100d58c965d01fb08bcd319032229),
|
||||
[#13394](https://github.com/angular/angular.js/issues/13394), [#8674](https://github.com/angular/angular.js/issues/8674), [#12709](https://github.com/angular/angular.js/issues/12709), [#8705](https://github.com/angular/angular.js/issues/8705), [#12707](https://github.com/angular/angular.js/issues/12707), [#10246](https://github.com/angular/angular.js/issues/10246), [#10252](https://github.com/angular/angular.js/issues/10252))
|
||||
- **input:**
|
||||
- fix URL validation being too strict
|
||||
([6610ae81](https://github.com/angular/angular.js/commit/6610ae816f78ee8fc1080b93a55bf19e4ce48d3e),
|
||||
[#13528](https://github.com/angular/angular.js/issues/13528), [#13544](https://github.com/angular/angular.js/issues/13544))
|
||||
- add missing chars to URL validation regex
|
||||
([2995b54a](https://github.com/angular/angular.js/commit/2995b54afdb9a3a2a81b0076a6ac0a9001041163),
|
||||
[#13379](https://github.com/angular/angular.js/issues/13379), [#13460](https://github.com/angular/angular.js/issues/13460))
|
||||
- **isArrayLike:** recognize empty instances of an Array subclass
|
||||
([323f9ab7](https://github.com/angular/angular.js/commit/323f9ab73696f223c245ddefd62a769fe102615e),
|
||||
[#13560](https://github.com/angular/angular.js/issues/13560), [#13708](https://github.com/angular/angular.js/issues/13708))
|
||||
- **ngInclude:** do not compile template if original scope is destroyed
|
||||
([9590bcf0](https://github.com/angular/angular.js/commit/9590bcf0620cd507a7795c55f9a6f4a48bfedbc1))
|
||||
- **ngOptions:**
|
||||
- don't skip `optgroup` elements with `value === ''`
|
||||
([85e392f3](https://github.com/angular/angular.js/commit/85e392f3543ef5285c7e90e843af0ab522cb0531),
|
||||
[#13487](https://github.com/angular/angular.js/issues/13487), [#13489](https://github.com/angular/angular.js/issues/13489))
|
||||
- don't `$dirty` multiple select after compilation
|
||||
([f163c905](https://github.com/angular/angular.js/commit/f163c90555774426ccb14752d089fc707cb4029c),
|
||||
[#13211](https://github.com/angular/angular.js/issues/13211), [#13326](https://github.com/angular/angular.js/issues/13326))
|
||||
- **select:** re-define `ngModelCtrl.$render` in the `select` directive's postLink function
|
||||
([529b2507](https://github.com/angular/angular.js/commit/529b2507bdb4fcc22dfa0f7ab462c79fc78d1413),
|
||||
[#13583](https://github.com/angular/angular.js/issues/13583), [#13583](https://github.com/angular/angular.js/issues/13583), [#13663](https://github.com/angular/angular.js/issues/13663))
|
||||
|
||||
## Minor Features
|
||||
|
||||
- **ngLocale:** add support for standalone months
|
||||
([54c4041e](https://github.com/angular/angular.js/commit/54c4041ebc0cc4df70cf6996f43a6aaaf56d46bd),
|
||||
[#3744](https://github.com/angular/angular.js/issues/3744), [#10247](https://github.com/angular/angular.js/issues/10247), [#12642](https://github.com/angular/angular.js/issues/12642), [#12844](https://github.com/angular/angular.js/issues/12844))
|
||||
- **ngMock:** add support for `$animate.closeAndFlush()`
|
||||
([512c0811](https://github.com/angular/angular.js/commit/512c08118786a419fabbd063fa17d224aba125cf))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **ngAnimate:** speed up `areAnimationsAllowed` check
|
||||
([2d3303dd](https://github.com/angular/angular.js/commit/2d3303ddda6330c4f45b381b6b17346f6cfe2d97))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
While we do not deem the following to be a real breaking change we are highlighting it here in the
|
||||
changelog to ensure that it does not surprise anyone.
|
||||
|
||||
- **$resource:** due to [47486524](https://github.com/angular/angular.js/commit/474865242c89ba3e8143f0cd52f8c292979ea730),
|
||||
|
||||
**Possible breaking change** for users who updated their code to provide a `timeout`
|
||||
promise for a `$resource` request in version v1.4.8.
|
||||
|
||||
Up to v1.4.7 (included), using a promise as a timeout in `$resource`, would silently
|
||||
fail (i.e. have no effect).
|
||||
|
||||
In v1.4.8, using a promise as timeout would have the (buggy) behaviour described
|
||||
in https://github.com/angular/angular.js/pull/12657#issuecomment-152108887.
|
||||
(I.e. it will work as expected for the first time you resolve the promise and will
|
||||
cancel all subsequent requests after that - one has to re-create the resource
|
||||
class. This was not documented.)
|
||||
|
||||
With this change, using a promise as timeout in v1.4.9 onwards is not allowed.
|
||||
It will log a warning and ignore the timeout value.
|
||||
|
||||
If you need support for cancellable `$resource` actions, you should upgrade to
|
||||
version 1.5 or higher.
|
||||
|
||||
|
||||
<a name="1.5.0-rc.1"></a>
|
||||
# 1.5.0-rc.1 quantum-fermentation (2016-01-15)
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:**
|
||||
- Allow ES6 classes as controllers with `bindToController: true`
|
||||
([8955cfb6](https://github.com/angular/angular.js/commit/8955cfb6462f79a32caa641ffc002f1522f08220))
|
||||
- Allow ES6 classes as controllers with `bindToController: true`
|
||||
([b0248b78](https://github.com/angular/angular.js/commit/b0248b7894649aa1e083698c66d01679fa66d1c1))
|
||||
- **$compileProvider:** - allow registering components with the component() method
|
||||
([feeb19787ca6e23e15578a4d1319f1c33853290c](https://github.com/angular/angular.js/commit/feeb19787ca6e23e15578a4d1319f1c33853290c))
|
||||
- **component:**
|
||||
- default controllerAs to `$ctrl`
|
||||
([d91cf167](https://github.com/angular/angular.js/commit/d91cf167960d47ce38fec0d33cab6119268623f0),
|
||||
[#13664](https://github.com/angular/angular.js/issues/13664), [#13710](https://github.com/angular/angular.js/issues/13710))
|
||||
- disallow non-isolate scopes
|
||||
([f31c5a39](https://github.com/angular/angular.js/commit/f31c5a3924629795cd9169e69b9e20efd4a9d927),
|
||||
[#13710](https://github.com/angular/angular.js/issues/13710))
|
||||
- allow `component()` helper to copy over custom annotations
|
||||
([90975db5](https://github.com/angular/angular.js/commit/90975db5f91dfe44fa5dc4542e92c68e0d425929),
|
||||
[#13741](https://github.com/angular/angular.js/issues/13741))
|
||||
- **$injector:** support instantiating classes.
|
||||
([8b6b4282](https://github.com/angular/angular.js/commit/8b6b42827186e5e4eb7a56f6b824c560a5058bd2))
|
||||
- **ngMock:** add support for `$animate.closeAndFlush()`
|
||||
([e1def1b8](https://github.com/angular/angular.js/commit/e1def1b8fe543fde09abda076d66606027f7dbeb),
|
||||
[#13005](https://github.com/angular/angular.js/issues/13005), [#13576](https://github.com/angular/angular.js/issues/13576), [#13707](https://github.com/angular/angular.js/issues/13707))
|
||||
- **ngMock.$componentController:** add helper to instantiate controllers for components
|
||||
([dd14e0c4](https://github.com/angular/angular.js/commit/dd14e0c44d2963d217cd4eb28f1ad6e6a643d63f),
|
||||
[#13683](https://github.com/angular/angular.js/issues/13683), [#13711](https://github.com/angular/angular.js/issues/13711))
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- allow enabled children to animate on disabled parents
|
||||
([8b636033](https://github.com/angular/angular.js/commit/8b6360338dca4bb7d8656d556bd7fb209e5aae73),
|
||||
[#13179](https://github.com/angular/angular.js/issues/13179), [#13695](https://github.com/angular/angular.js/issues/13695))
|
||||
- allow animations when pinned element is parent element
|
||||
([8f0b4825](https://github.com/angular/angular.js/commit/8f0b48259666c1496970d6ca90decb36d6fa3295),
|
||||
[#13466](https://github.com/angular/angular.js/issues/13466))
|
||||
- correctly access minErr
|
||||
([bc41ad8a](https://github.com/angular/angular.js/commit/bc41ad8aa8fc41ff30e9f68220a7c7c5fe194478))
|
||||
- **$animateCss:**
|
||||
- only (de)register listeners when events have been added
|
||||
([959f2bbb](https://github.com/angular/angular.js/commit/959f2bbb2d12c23a74902433c6247290d8f2fb89),
|
||||
[#13514](https://github.com/angular/angular.js/issues/13514))
|
||||
- remove animation end event listeners on close
|
||||
([20604e7f](https://github.com/angular/angular.js/commit/20604e7fc4f69ecfafbd8d0c1fdc70d478075c3a),
|
||||
[#10387](https://github.com/angular/angular.js/issues/10387))
|
||||
- respect transition styles already on the element
|
||||
([de9777d8](https://github.com/angular/angular.js/commit/de9777d8193531472df4b57fdeb6650d7f7c1846),
|
||||
[#12656](https://github.com/angular/angular.js/issues/12656), [#13333](https://github.com/angular/angular.js/issues/13333))
|
||||
- **$compile:**
|
||||
- add missing variable declaration
|
||||
([6cdbda7c](https://github.com/angular/angular.js/commit/6cdbda7cf1cfc1d49eb98d42d8e823e65bebb90d))
|
||||
- fix namespace detection for anchor elements
|
||||
([c9e6cf9b](https://github.com/angular/angular.js/commit/c9e6cf9be0d549fba234956f7e263f40d1bb1e76))
|
||||
- **component:**
|
||||
- remove the ability to set the `restrict` option on `component()` helper
|
||||
([25bc5318](https://github.com/angular/angular.js/commit/25bc53180248bf5e8a6467c55d913cfa38fc7a3b),
|
||||
[#13741](https://github.com/angular/angular.js/issues/13741))
|
||||
- use `false` as default value for `transclude` in `component()` helper
|
||||
([6a47c0d7](https://github.com/angular/angular.js/commit/6a47c0d75d0c6f0bfb3b5492d1f05ec900387744),
|
||||
[#13566](https://github.com/angular/angular.js/issues/13566), [#13581](https://github.com/angular/angular.js/issues/13581))
|
||||
- allow passing template/templateUrl in array notation
|
||||
([99d601a0](https://github.com/angular/angular.js/commit/99d601a048ac2b82e2f74ae88c96773e5d1a7258))
|
||||
- **$controller:** allow identifiers containing `$`
|
||||
([4e1b36c2](https://github.com/angular/angular.js/commit/4e1b36c21686ad0ca4930d1d81f77a7d9cc35851),
|
||||
[#13736](https://github.com/angular/angular.js/issues/13736))
|
||||
- **$injector:** workaround for MS Edge class detection
|
||||
([fabc6ab5](https://github.com/angular/angular.js/commit/fabc6ab5b01dc687aa8385da067752ba34da6524))
|
||||
- **$q:** make instanceof work for $q promises
|
||||
([b3ef5e08](https://github.com/angular/angular.js/commit/b3ef5e08528f5f1916876032700a016448fb196a))
|
||||
- **copy:**
|
||||
- add support for ArrayBuffer, handle multiple references to ArrayBuffer
|
||||
([986647a9](https://github.com/angular/angular.js/commit/986647a968858121c1de472fc4913221dc8d339a))
|
||||
- add support for String/Boolean/Number object types
|
||||
([7b51243b](https://github.com/angular/angular.js/commit/7b51243be597900b1f765495dadfea5fccd2228e))
|
||||
- **input:** fix URL validation being too strict
|
||||
([e3be5d6e](https://github.com/angular/angular.js/commit/e3be5d6efaec6537ab530640c64f452aa1006fcb),
|
||||
[#13528](https://github.com/angular/angular.js/issues/13528), [#13544](https://github.com/angular/angular.js/issues/13544))
|
||||
- **isArrayLike:** recognize empty instances of an Array subclass
|
||||
([93c7251f](https://github.com/angular/angular.js/commit/93c7251f5f40bdbe050c74130d90331613d968a2),
|
||||
[#13560](https://github.com/angular/angular.js/issues/13560), [#13708](https://github.com/angular/angular.js/issues/13708))
|
||||
- **linky:** throw error if input is not a string
|
||||
([98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
|
||||
[#13547](https://github.com/angular/angular.js/issues/13547), [#13693](https://github.com/angular/angular.js/issues/13693))
|
||||
- **ngAnimate:**
|
||||
- only copy over the animation options once
|
||||
([d4fa3313](https://github.com/angular/angular.js/commit/d4fa3313088a03d15ccbf266583d6ecaa0d22241),
|
||||
[#13722](https://github.com/angular/angular.js/issues/13722), [#13578](https://github.com/angular/angular.js/issues/13578))
|
||||
- allow event listeners on document in IE
|
||||
([e5cab951](https://github.com/angular/angular.js/commit/e5cab951f4e4969b092295b7f3ca7ec1d17eb9a6),
|
||||
[#13548](https://github.com/angular/angular.js/issues/13548), [#13696](https://github.com/angular/angular.js/issues/13696))
|
||||
- allow removing classes that are added by a running animation
|
||||
([776972ed](https://github.com/angular/angular.js/commit/776972ed9c49a62f5ad7c6f207209bf0f0c900bb),
|
||||
[#13339](https://github.com/angular/angular.js/issues/13339), [#13380](https://github.com/angular/angular.js/issues/13380), [#13414](https://github.com/angular/angular.js/issues/13414), [#13472](https://github.com/angular/angular.js/issues/13472), [#13678](https://github.com/angular/angular.js/issues/13678))
|
||||
- do not use event.timeStamp anymore for time tracking
|
||||
([e020b899](https://github.com/angular/angular.js/commit/e020b8993ec7b8e004c136ca40ea9bab02207dbf),
|
||||
[#13494](https://github.com/angular/angular.js/issues/13494), [#13495](https://github.com/angular/angular.js/issues/13495))
|
||||
- **ngInclude:** do not compile template if original scope is destroyed
|
||||
([98776487](https://github.com/angular/angular.js/commit/98776487a04667aa36cb24088ead198bd03b607c))
|
||||
- **ngMock:** ignore empty javascript animations in $animate.closeAndFlush()
|
||||
([a801df71](https://github.com/angular/angular.js/commit/a801df719ea8b5996676d4e7a88a26a5ece471e7))
|
||||
- **ngOptions:** don't skip optgroup elements with value === ''
|
||||
([6858caf2](https://github.com/angular/angular.js/commit/6858caf251b16a52e73d62f65c7e9e26e1f199ae),
|
||||
[#13487](https://github.com/angular/angular.js/issues/13487), [#13489](https://github.com/angular/angular.js/issues/13489))
|
||||
- **select:** re-define ngModelCtrl.$render in the select postLink fn
|
||||
([f7eab8d8](https://github.com/angular/angular.js/commit/f7eab8d8fe8cadecaee425f0db0c74e48619310c),
|
||||
[#13583](https://github.com/angular/angular.js/issues/13583), [#13583](https://github.com/angular/angular.js/issues/13583), [#13663](https://github.com/angular/angular.js/issues/13663))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$component**:
|
||||
*These breaking changes affect only applications updating from previous 1.5 beta / rc versions*
|
||||
|
||||
- Due to [d91cf167](https://github.com/angular/angular.js/commit/d91cf167960d47ce38fec0d33cab6119268623f0),
|
||||
the default `controllerAs` value for components is now `$ctrl` (previously the name of the component was used).
|
||||
To migrate, either set `controllerAs` to the component name, or change the property name in your templates
|
||||
to `$ctrl`
|
||||
|
||||
- Due to [25bc5318](https://github.com/angular/angular.js/commit/25bc5318), it is no longer possible to
|
||||
set the `restrict` option on directives created via the `module.component()` helper.
|
||||
All components are now element directives (`restrict: 'E'`). If you need a directive that is not an element then you must use the
|
||||
`module.directive()` helper instead.
|
||||
|
||||
- Due to [f31c5a39](https://github.com/angular/angular.js/commit/f31c5a3924629795cd9169e69b9e20efd4a9d927),
|
||||
components are now always created with `scope: {}` (isolate scope). Previously, it was also possible to create components
|
||||
with `scope: true` or `scope: false`. If your components rely on this scope configuration, you will have to
|
||||
create a regular directive instead.
|
||||
|
||||
- Due to [6a47c0d7](https://github.com/angular/angular.js/commit/6a47c0d75d0c6f0bfb3b5492d1f05ec900387744),
|
||||
the `transclude` property is now `false` by default (previously `true`). If you created components that expected
|
||||
transclusion then you must change your code to specify `transclude: true`.
|
||||
|
||||
- **linky:** due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
|
||||
|
||||
Before this change, the filter assumed that the input (if not undefined/null) was of type 'string'
|
||||
and that certain methods (such as `.match()`) would be available on it. Passing a non-string value
|
||||
would most likely result in a not-very-useful error being thrown (trying to call a method that does
|
||||
not exist) or in unexpected behavior (if the input happened to have the assumed methods).
|
||||
|
||||
After this change, a proper (informative) error will be thrown. If you want to pass non-string
|
||||
values through `linky`, you need to explicitly convert them to strings first.
|
||||
Since input values could be initialized asynchronously, `undefined` or `null` will still be
|
||||
returned unchanged (without throwing an error).
|
||||
|
||||
|
||||
<a name="1.5.0-rc.0"></a>
|
||||
# 1.5.0-rc.0 oblong-panoptikum (2015-12-09)
|
||||
|
||||
@@ -142,7 +521,7 @@ var User = $resource('/api/user/:id', {id: '@id'}, {
|
||||
});
|
||||
|
||||
var user = User.get({id: 1}); // sends a request
|
||||
instance.$cancelRequest(); // aborts the request
|
||||
user.$cancelRequest(); // aborts the request
|
||||
|
||||
user = User.get({id: 2});
|
||||
```
|
||||
@@ -290,57 +669,24 @@ is `$locals`.
|
||||
- fix scoping of transclusion directives inside a replace directive
|
||||
([1a98c0ee](https://github.com/angular/angular.js/commit/1a98c0ee346b718b9462da1abf4352a4605cbc7f),
|
||||
[#12975](https://github.com/angular/angular.js/issues/12975), [#12936](https://github.com/angular/angular.js/issues/12936), [#13244](https://github.com/angular/angular.js/issues/13244))
|
||||
- use createMap() for $$observe listeners when initialized from attr interpolation
|
||||
([76c2491a](https://github.com/angular/angular.js/commit/76c2491a316d6b296c721227529fcb09087d369a),
|
||||
[#10446](https://github.com/angular/angular.js/issues/10446))
|
||||
- properly sanitize xlink:href attribute interoplation
|
||||
([f33ce173](https://github.com/angular/angular.js/commit/f33ce173c90736e349cf594df717ae3ee41e0f7a),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- **$http:** apply `transformResponse` even when `data` is empty
|
||||
([7c0731ed](https://github.com/angular/angular.js/commit/7c0731edb2f72bdf0efa186f641dab3b6aecc5d5),
|
||||
[#12976](https://github.com/angular/angular.js/issues/12976), [#12979](https://github.com/angular/angular.js/issues/12979))
|
||||
- **$location:** ensure `$locationChangeSuccess` fires even if URL ends with `#`
|
||||
([4412fe23](https://github.com/angular/angular.js/commit/4412fe238f37f79a2017ee7b20ba089c0acd73e9),
|
||||
[#12175](https://github.com/angular/angular.js/issues/12175), [#13251](https://github.com/angular/angular.js/issues/13251))
|
||||
- **$parse:**
|
||||
- evaluate simple expressions in interpolations only once
|
||||
- **$parse:** evaluate simple expressions in interpolations only once
|
||||
([1caf0b6b](https://github.com/angular/angular.js/commit/1caf0b6bee5781589e20f7a27a8c60e8b1b784f5),
|
||||
[#12983](https://github.com/angular/angular.js/issues/12983), [#13002](https://github.com/angular/angular.js/issues/13002))
|
||||
- fix typo in error message ("assing" -> "assign")
|
||||
([70dac5ae](https://github.com/angular/angular.js/commit/70dac5ae82ffe9c6250681274905583747523b5d),
|
||||
[#12940](https://github.com/angular/angular.js/issues/12940))
|
||||
- block assigning to fields of a constructor
|
||||
([e1f4f23f](https://github.com/angular/angular.js/commit/e1f4f23f781a79ae8a4046b21130283cec3f2917),
|
||||
[#12860](https://github.com/angular/angular.js/issues/12860))
|
||||
- safer conversion of computed properties to strings
|
||||
([20cf7d5e](https://github.com/angular/angular.js/commit/20cf7d5e3a0af766b1929e24794859c79439351c))
|
||||
- **$resource:** allow XHR request to be cancelled via a timeout promise
|
||||
([4fc73466](https://github.com/angular/angular.js/commit/4fc734665e5dddef26ed30a9d4f75632cd269481),
|
||||
[#12657](https://github.com/angular/angular.js/issues/12657), [#12675](https://github.com/angular/angular.js/issues/12675), [#10890](https://github.com/angular/angular.js/issues/10890), [#9332](https://github.com/angular/angular.js/issues/9332))
|
||||
- **$rootScope:** prevent IE9 memory leak when destroying scopes
|
||||
([8fe781fb](https://github.com/angular/angular.js/commit/8fe781fbe7c42c64eb895c28d9fd5479b037d020),
|
||||
[#10706](https://github.com/angular/angular.js/issues/10706), [#11786](https://github.com/angular/angular.js/issues/11786))
|
||||
- **$sanitize:**
|
||||
- strip urls starting with 'unsafe:' as opposed to 'unsafe'
|
||||
([a4dfa4d0](https://github.com/angular/angular.js/commit/a4dfa4d061fd2f6baf9821f0863dcce7888232ab),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- add mXSS protection
|
||||
([bc0d8c4e](https://github.com/angular/angular.js/commit/bc0d8c4eea9a34bff5e29dd492dcdd668251be40),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- support void elements, fixups, remove dead code, typos
|
||||
([94207f8f](https://github.com/angular/angular.js/commit/94207f8fb6ee8fe26fe18657f6b5aca6def99605),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- **Angular.js:** fix `isArrayLike` for unusual cases
|
||||
([2c8d87e0](https://github.com/angular/angular.js/commit/2c8d87e064dca99a49ed35d1db885b1f2e40dcf4),
|
||||
[#10186](https://github.com/angular/angular.js/issues/10186), [#8000](https://github.com/angular/angular.js/issues/8000), [#4855](https://github.com/angular/angular.js/issues/4855), [#4751](https://github.com/angular/angular.js/issues/4751), [#10272](https://github.com/angular/angular.js/issues/10272))
|
||||
- **filters:** ensure `formatNumber` observes i18n decimal separators
|
||||
([658a865c](https://github.com/angular/angular.js/commit/658a865c5b2580eed53b340e7394945cd76e2260),
|
||||
[#10342](https://github.com/angular/angular.js/issues/10342), [#12850](https://github.com/angular/angular.js/issues/12850))
|
||||
- **injector:** support arrow functions with no parentheses
|
||||
([03726f7f](https://github.com/angular/angular.js/commit/03726f7fbd5d71c0604b8dd40e97cb2fb0fb777f),
|
||||
[#12890](https://github.com/angular/angular.js/issues/12890))
|
||||
- **input:** remove workaround for Firefox bug
|
||||
([b366f035](https://github.com/angular/angular.js/commit/b366f0352abccfe4c4868b5a9e8c0b88659bd1ee))
|
||||
- **isArrayLike:** handle jQuery objects of length 0
|
||||
([773efd08](https://github.com/angular/angular.js/commit/773efd0812097a89944c889c595485a5744326f6))
|
||||
- **jqLite:**
|
||||
@@ -359,12 +705,6 @@ is `$locals`.
|
||||
- clone elements instead of treating them like simple objects
|
||||
([17715fa3](https://github.com/angular/angular.js/commit/17715fa3668b1fcabaedcd82e2e57b2a80e0a0c2),
|
||||
[#12286](https://github.com/angular/angular.js/issues/12286))
|
||||
- **ngAnimate:**
|
||||
- ensure anchoring uses body as a container when needed
|
||||
([240d5896](https://github.com/angular/angular.js/commit/240d5896ecdfac2351f9bd6147b52de52c0b7608),
|
||||
[#12872](https://github.com/angular/angular.js/issues/12872))
|
||||
- callback detection should only use RAF when necessary
|
||||
([8b27c3f0](https://github.com/angular/angular.js/commit/8b27c3f064b34532ba99d709cadf09fc4c0cbeab))
|
||||
- **ngAria:** don't add tabindex to radio and checkbox inputs
|
||||
([662fb282](https://github.com/angular/angular.js/commit/662fb282c176ca00a85b6dec7af90446ea90f662),
|
||||
[#12492](https://github.com/angular/angular.js/issues/12492), [#13095](https://github.com/angular/angular.js/issues/13095))
|
||||
@@ -374,9 +714,6 @@ is `$locals`.
|
||||
- **ngMessage:** make ngMessage compatible with ngBind
|
||||
([4971ef12](https://github.com/angular/angular.js/commit/4971ef12d4c2c268cb8d26f90385dc96eba19db8),
|
||||
[#8089](https://github.com/angular/angular.js/issues/8089), [#13074](https://github.com/angular/angular.js/issues/13074))
|
||||
- **ngMessages:** prevent race condition with ngAnimate
|
||||
([8366622b](https://github.com/angular/angular.js/commit/8366622bed009d2cad7d0cff28b9c1e48bfbd4e1),
|
||||
[#12856](https://github.com/angular/angular.js/issues/12856), [#12903](https://github.com/angular/angular.js/issues/12903))
|
||||
- **ngMock:** reset cache before every test
|
||||
([fd83d372](https://github.com/angular/angular.js/commit/fd83d3724ad30a93254f08cb82f981eaddb5dbff),
|
||||
[#13013](https://github.com/angular/angular.js/issues/13013))
|
||||
@@ -387,18 +724,6 @@ is `$locals`.
|
||||
- override select option registration to allow compilation of empty option
|
||||
([2fcfd75a](https://github.com/angular/angular.js/commit/2fcfd75a142200e1a4b1b7ed4fb588e3befcbd57),
|
||||
[#11685](https://github.com/angular/angular.js/issues/11685), [#12972](https://github.com/angular/angular.js/issues/12972), [#12968](https://github.com/angular/angular.js/issues/12968), [#13012](https://github.com/angular/angular.js/issues/13012))
|
||||
- prevent frozen select ui in IE
|
||||
([42c97c5d](https://github.com/angular/angular.js/commit/42c97c5db5921e9e5447fb32bdae1f48da42844f),
|
||||
[#11314](https://github.com/angular/angular.js/issues/11314), [#11795](https://github.com/angular/angular.js/issues/11795))
|
||||
- allow falsy values as option group identifiers
|
||||
([b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b02d88b33c22dd90ae3cdfc27),
|
||||
[#7015](https://github.com/angular/angular.js/issues/7015), [#7024](https://github.com/angular/angular.js/issues/7024), [#12888](https://github.com/angular/angular.js/issues/12888))
|
||||
- throw if ngModel is not present
|
||||
([ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
|
||||
[#7047](https://github.com/angular/angular.js/issues/7047), [#12840](https://github.com/angular/angular.js/issues/12840))
|
||||
- **ngResource:** encode `&` in URL query param values
|
||||
([1c97a605](https://github.com/angular/angular.js/commit/1c97a6057bc013262be761bca5e5c22224c4bbf8),
|
||||
[#12201](https://github.com/angular/angular.js/issues/12201))
|
||||
- **orderByFilter:** throw error if input is not array-like
|
||||
([2a85a634](https://github.com/angular/angular.js/commit/2a85a634f86c84f15b411ce009a3515fca7ba580),
|
||||
[#11255](https://github.com/angular/angular.js/issues/11255), [#11719](https://github.com/angular/angular.js/issues/11719))
|
||||
@@ -406,24 +731,11 @@ is `$locals`.
|
||||
|
||||
## Features
|
||||
|
||||
- **$animateCss:** add support for temporary styles via `cleanupStyles`
|
||||
([9f67da62](https://github.com/angular/angular.js/commit/9f67da625293441e27559ebde7503cc63408a95c),
|
||||
[#12930](https://github.com/angular/angular.js/issues/12930))
|
||||
- **$compile:** multiple transclusion via named slots
|
||||
([a4ada8ba](https://github.com/angular/angular.js/commit/a4ada8ba9c4358273575e16778e76446ad080054),
|
||||
[#4357](https://github.com/angular/angular.js/issues/4357), [#12742](https://github.com/angular/angular.js/issues/12742), [#11736](https://github.com/angular/angular.js/issues/11736), [#12934](https://github.com/angular/angular.js/issues/12934))
|
||||
- **$http:** add `$xhrFactory` service to enable creation of custom xhr objects
|
||||
([106f90aa](https://github.com/angular/angular.js/commit/106f90aafa0fa5a81ad7af7ffc9d1e00ab97ffef),
|
||||
[#2318](https://github.com/angular/angular.js/issues/2318), [#9319](https://github.com/angular/angular.js/issues/9319), [#12159](https://github.com/angular/angular.js/issues/12159))
|
||||
- **$injector:**
|
||||
- Allow specifying a decorator on $injector
|
||||
- **$injector:** allow specifying a decorator on $injector
|
||||
([29a05984](https://github.com/angular/angular.js/commit/29a05984fe46c2c18ca51404f07c866dd92d1eec))
|
||||
- add strictDi property to $injector instance
|
||||
([79577c5d](https://github.com/angular/angular.js/commit/79577c5d316c7bf0204d7d1747ddc5b15bfe2955),
|
||||
[#11728](https://github.com/angular/angular.js/issues/11728), [#11734](https://github.com/angular/angular.js/issues/11734))
|
||||
- **$sanitize:** make svg support an opt-in
|
||||
([181fc567](https://github.com/angular/angular.js/commit/181fc567d873df065f1e84af7225deb70a8d2eb9),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- **$templateRequest:** support configuration of $http options
|
||||
([b2fc39d2](https://github.com/angular/angular.js/commit/b2fc39d2ddac64249b4f2961ee18b878a1e98251),
|
||||
[#13188](https://github.com/angular/angular.js/issues/13188), [#11868](https://github.com/angular/angular.js/issues/11868), [#6860](https://github.com/angular/angular.js/issues/6860))
|
||||
@@ -442,18 +754,12 @@ is `$locals`.
|
||||
- invoke nested calls to `module()` immediately
|
||||
([51a27c0f](https://github.com/angular/angular.js/commit/51a27c0f1ad6cd8d3e33ab0d71de22c1627c7ec3),
|
||||
[#12887](https://github.com/angular/angular.js/issues/12887))
|
||||
- **ngModel:** provide ng-empty and ng-not-empty CSS classes
|
||||
([630280c7](https://github.com/angular/angular.js/commit/630280c7fb04a83208d09c97c2efb81be3a3db74),
|
||||
[#10050](https://github.com/angular/angular.js/issues/10050), [#12848](https://github.com/angular/angular.js/issues/12848))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:**
|
||||
- use static jquery data method to avoid creating new instances
|
||||
- **$compile:** use static jquery data method to avoid creating new instances
|
||||
([9b90c32f](https://github.com/angular/angular.js/commit/9b90c32f31fd56e348539674128acec6536cd846))
|
||||
- lazily compile the `transclude` function
|
||||
([652b83eb](https://github.com/angular/angular.js/commit/652b83eb226131d131a44453520a569202aa4aac))
|
||||
- **$interpolate:** provide a simplified result for constant expressions
|
||||
([cf83b4f4](https://github.com/angular/angular.js/commit/cf83b4f445d3a1fc18fc140e65e670754401d50b))
|
||||
- **copy:**
|
||||
@@ -469,13 +775,6 @@ is `$locals`.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$sanitize:** due to [181fc567](https://github.com/angular/angular.js/commit/181fc567d873df065f1e84af7225deb70a8d2eb9),
|
||||
The svg support in is now an opt-in option
|
||||
|
||||
Applications that depend on this option can use to turn the option back on,
|
||||
but while doing so, please read the warning provided in the documentation for
|
||||
information on preventing click-hijacking attacks when this option is turned on.
|
||||
|
||||
- **ngMessage:** due to [4971ef12](https://github.com/angular/angular.js/commit/4971ef12d4c2c268cb8d26f90385dc96eba19db8),
|
||||
|
||||
ngMessage is now compiled with a priority of 1, which means directives
|
||||
@@ -486,14 +785,6 @@ passed the comment element created by the transclusion of ngMessage.
|
||||
To restore this behavior, custom directives need to have
|
||||
their priority increased to at least "1".
|
||||
|
||||
- **ngOptions:** due to [ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
|
||||
|
||||
`ngOptions` will now throw if `ngModel` is not present on the `select`
|
||||
element. Previously, having no `ngModel` let `ngOptions` silently
|
||||
fail, which could lead to hard to debug errors. The change should
|
||||
therefore not affect any applications, as it simply makes the
|
||||
requirement more strict and alerts the developer explicitly.
|
||||
|
||||
- **orderByFilter:** due to [2a85a634](https://github.com/angular/angular.js/commit/2a85a634f86c84f15b411ce009a3515fca7ba580),
|
||||
|
||||
Previously, an non array-like input would pass through the orderBy filter unchanged.
|
||||
@@ -503,9 +794,6 @@ https://github.com/petebacondarwin/angular-toArrayFilter.
|
||||
(`null` and `undefined` still pass through without an error, in order to
|
||||
support asynchronous loading of resources.)
|
||||
|
||||
Closes #11255
|
||||
Closes #11719
|
||||
|
||||
|
||||
|
||||
<a name="1.5.0-beta.1"></a>
|
||||
@@ -518,7 +806,7 @@ Closes #11719
|
||||
- use createMap() for $$observe listeners when initialized from attr interpolation
|
||||
([76c2491a](https://github.com/angular/angular.js/commit/76c2491a316d6b296c721227529fcb09087d369a),
|
||||
[#10446](https://github.com/angular/angular.js/issues/10446))
|
||||
- properly sanitize xlink:href attribute interoplation
|
||||
- properly sanitize xlink:href attribute interpolation
|
||||
([f33ce173](https://github.com/angular/angular.js/commit/f33ce173c90736e349cf594df717ae3ee41e0f7a),
|
||||
[#12524](https://github.com/angular/angular.js/issues/12524))
|
||||
- **$parse:**
|
||||
@@ -609,6 +897,16 @@ Applications that depend on this option can use to turn the option back on,
|
||||
but while doing so, please read the warning provided in the documentation for
|
||||
information on preventing click-hijacking attacks when this option is turned on.
|
||||
|
||||
- **ngOptions:** due to [b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b02d88b33c22dd90ae3cdfc27),
|
||||
|
||||
If your data contains falsy values (`''`, `0`, `false` and `null`) for option groups, then these
|
||||
options will now be placed into option groups. Previously all of these falsy values were treated as
|
||||
the option not being a member of a group.
|
||||
|
||||
Only option groups that are `undefined` will result in the option being put in no group.
|
||||
If you have data that contains falsy values that should not be used as groups then you must filter
|
||||
the values before passing them to `ngOptions` converting falsy values to `undefined`.
|
||||
|
||||
- **ngOptions:** due to [ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
|
||||
|
||||
`ngOptions` will now throw if `ngModel` is not present on the `select`
|
||||
@@ -1202,7 +1500,7 @@ describe('$q.when', function() {
|
||||
([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)
|
||||
- throw error when requesting 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
|
||||
@@ -1595,7 +1893,7 @@ $animateProvider.classNameFilter(/ng-animate-special/);
|
||||
|
||||
|
||||
Although it is unlikely that anyone is using it in this way, this change does change the
|
||||
behaviour of `ngOptions` in the following case:
|
||||
behavior of `ngOptions` in the following case:
|
||||
|
||||
* you are iterating over an array-like object, using the array form of the `ngOptions` syntax
|
||||
(`item.label for item in items`) and that object contains non-numeric property keys.
|
||||
@@ -1605,7 +1903,7 @@ In this case these properties with non-numeric keys will be ignored.
|
||||
** Here array-like is defined by the result of a call to this internal function:
|
||||
https://github.com/angular/angular.js/blob/v1.4.0-rc.1/src/Angular.js#L198-L211 **
|
||||
|
||||
To get the desired behaviour you need to iterate using the object form of the `ngOptions` syntax
|
||||
To get the desired behavior you need to iterate using the object form of the `ngOptions` syntax
|
||||
(`value.label` for (key, value) in items)`).
|
||||
|
||||
|
||||
@@ -1842,7 +2140,7 @@ styles are resolved in time.
|
||||
- **Angular:** properly compare RegExp with other objects for equality
|
||||
([f22e1fc9](https://github.com/angular/angular.js/commit/f22e1fc9610ae111a3ea8746a3a57169c99ce142),
|
||||
[#11204](https://github.com/angular/angular.js/issues/11204), [#11205](https://github.com/angular/angular.js/issues/11205))
|
||||
- **date filter:** display localised era for `G` format codes
|
||||
- **date filter:** display localized era for `G` format codes
|
||||
([2b4dfa9e](https://github.com/angular/angular.js/commit/2b4dfa9e2b63d7ebb78f3b0fd3439d18f932e1cd),
|
||||
[#10503](https://github.com/angular/angular.js/issues/10503), [#11266](https://github.com/angular/angular.js/issues/11266))
|
||||
- **filterFilter:**
|
||||
@@ -1948,7 +2246,7 @@ mechanism.
|
||||
- **Angular:** properly compare RegExp with other objects for equality
|
||||
([b8e8f9af](https://github.com/angular/angular.js/commit/b8e8f9af78f4ef3e556dd3cef6bfee35ad4cb82a),
|
||||
[#11204](https://github.com/angular/angular.js/issues/11204), [#11205](https://github.com/angular/angular.js/issues/11205))
|
||||
- **date filter:** display localised era for `G` format codes
|
||||
- **date filter:** display localized era for `G` format codes
|
||||
([f2683f95](https://github.com/angular/angular.js/commit/f2683f956fcd3216eaa263db20b31e0d46338800),
|
||||
[#10503](https://github.com/angular/angular.js/issues/10503), [#11266](https://github.com/angular/angular.js/issues/11266))
|
||||
- **filterFilter:**
|
||||
@@ -2054,7 +2352,7 @@ mechanism.
|
||||
|
||||
The `ngMessagesInclude` attribute is now its own directive and that must
|
||||
be placed as a **child** element within the element with the ngMessages
|
||||
directive. (Keep in mind that the former behaviour of the
|
||||
directive. (Keep in mind that the former behavior of the
|
||||
ngMessageInclude attribute was that all **included** ngMessage template
|
||||
code was placed at the **bottom** of the element containing the
|
||||
ngMessages directive; therefore to make this behave in the same way,
|
||||
@@ -2229,7 +2527,7 @@ $http.get(url, {
|
||||
- **filter:** format timezone correctly in the case that UTC timezone is used
|
||||
([8c469191](https://github.com/angular/angular.js/commit/8c46919199090a05634789774124b38983430c76),
|
||||
[#9359](https://github.com/angular/angular.js/issues/9359))
|
||||
- **ngRoute:** dont duplicate optional params into query
|
||||
- **ngRoute:** don't duplicate optional params into query
|
||||
([27bf2ce4](https://github.com/angular/angular.js/commit/27bf2ce40c5adfb1494d69c9d0ac9cf433834a12),
|
||||
[#10689](https://github.com/angular/angular.js/issues/10689))
|
||||
- **ngScenario:** allow ngScenario to handle lazy-loaded and manually bootstrapped applications
|
||||
@@ -2279,7 +2577,7 @@ is marked as optional and the attribute is not specified, no function will be ad
|
||||
- **$parse:** remove references to last arguments to a fn call
|
||||
([7caad220](https://github.com/angular/angular.js/commit/7caad2205a6e9927890192a3638f55532bdaaf75),
|
||||
[#10894](https://github.com/angular/angular.js/issues/10894))
|
||||
- **ngRoute:** dont duplicate optional params into query
|
||||
- **ngRoute:** don't duplicate optional params into query
|
||||
([f41ca4a5](https://github.com/angular/angular.js/commit/f41ca4a53ed53f172fb334911be56e42aad58794),
|
||||
[#10689](https://github.com/angular/angular.js/issues/10689))
|
||||
- **ngScenario:** Allow ngScenario to handle lazy-loaded and manually bootstrapped applications
|
||||
@@ -2537,7 +2835,7 @@ Now it will be something like:
|
||||
```
|
||||
|
||||
If your application code relied on this value, which it shouldn't, then you will need to modify your
|
||||
application to accommodate this. You may find that you can use the `track by` feaure of `ngOptions`
|
||||
application to accommodate this. You may find that you can use the `track by` feature of `ngOptions`
|
||||
as this provides the ability to specify the key that is stored.
|
||||
|
||||
- **ngOptions:** due to [7fda214c](https://github.com/angular/angular.js/commit/7fda214c4f65a6a06b25cf5d5aff013a364e9cef),
|
||||
@@ -2692,7 +2990,7 @@ Previously, if either value being compared in the orderBy comparator was null or
|
||||
order would, incorrectly, not change. Now, this order behaves more like Array.prototype.sort, which
|
||||
by default pushes `null` behind objects, due to `n` occurring after `[` (the first characters of their
|
||||
stringified forms) in ASCII / Unicode. If `toString` is customized, or does not exist, the
|
||||
behaviour is undefined.
|
||||
behavior is undefined.
|
||||
|
||||
|
||||
|
||||
@@ -2769,7 +3067,7 @@ behaviour is undefined.
|
||||
([96c61fe7](https://github.com/angular/angular.js/commit/96c61fe756d7d3db011818bf0925e3d86ffff8ce),
|
||||
[#10278](https://github.com/angular/angular.js/issues/10278))
|
||||
- **orderBy:**
|
||||
- make object-to-primtiive behaviour work for objects with null prototype
|
||||
- make object-to-primtiive behavior work for objects with null prototype
|
||||
([3aa57528](https://github.com/angular/angular.js/commit/3aa5752894419b4638d5c934879258fa6a1c0d07))
|
||||
- maintain order in array of objects when predicate is not provided
|
||||
([8bfeddb5](https://github.com/angular/angular.js/commit/8bfeddb5d671017f4a21b8b46334ac816710b143),
|
||||
@@ -2950,7 +3248,7 @@ would previously invoke `model.value()` in the global context.
|
||||
|
||||
Now, ngModel invokes `value` with `model` as the context.
|
||||
|
||||
It's unlikely that real apps relied on this behavior. If they did they can use `.bind` to explicilty
|
||||
It's unlikely that real apps relied on this behavior. If they did they can use `.bind` to explicitly
|
||||
bind a getter/getter to the global context, or just reference globals normally without `this`.
|
||||
|
||||
|
||||
@@ -3026,7 +3324,7 @@ bind a getter/getter to the global context, or just reference globals normally w
|
||||
- **ngMock:** call $interval callbacks even when invokeApply is false
|
||||
([d81ff888](https://github.com/angular/angular.js/commit/d81ff8885b77f70c6417d7be3124d86d07447375),
|
||||
[#10032](https://github.com/angular/angular.js/issues/10032))
|
||||
- **ngPattern:** match behaviour of native HTML pattern attribute
|
||||
- **ngPattern:** match behavior of native HTML pattern attribute
|
||||
([85eb9660](https://github.com/angular/angular.js/commit/85eb9660ef67c24d5104a6a1921bedad0bd1b57e),
|
||||
[#9881](https://github.com/angular/angular.js/issues/9881), [#9888](https://github.com/angular/angular.js/issues/9888))
|
||||
- **select:** ensure the label attribute is updated in Internet Explorer
|
||||
@@ -3253,7 +3551,7 @@ link: function(scope, element, attr) {
|
||||
- **$animate:** due to [e5f4d7b1](https://github.com/angular/angular.js/commit/e5f4d7b10ae5e6a17ab349995451c33b7d294245),
|
||||
staggering animations that use transitions will now
|
||||
always block the transition from starting (via `transition: 0s none`)
|
||||
up until the stagger step kicks in. The former behaviour was that the
|
||||
up until the stagger step kicks in. The former behavior was that the
|
||||
block was removed as soon as the pending class was added. This fix
|
||||
allows for styles to be applied in the pending class without causing
|
||||
an animation to trigger prematurely.
|
||||
@@ -3496,7 +3794,7 @@ Closes #9281
|
||||
|
||||
- $scope['this'] no longer exits on the $scope object
|
||||
- $parse-ed expressions no longer allow chaining 'this' such as this['this'] or $parent['this']
|
||||
- 'this' in $parse-ed expressions can no longer be overriden, if a variable named 'this' is put on the scope it must be accessed using this['this']
|
||||
- 'this' in $parse-ed expressions can no longer be overridden, if a variable named 'this' is put on the scope it must be accessed using this['this']
|
||||
|
||||
Closes #9105
|
||||
|
||||
@@ -3670,7 +3968,7 @@ Previously it was just a good practice to make all filters stateless. Now
|
||||
it's a requirement in order for the model change-observation to pick up
|
||||
all changes.
|
||||
|
||||
If an existing filter is statefull, it can be flagged as such but keep in
|
||||
If an existing filter is stateful, it can be flagged as such but keep in
|
||||
mind that this will result in a significant performance-penalty (or rather
|
||||
lost opportunity to benefit from a major perf improvement) that will
|
||||
affect the `$digest` duration.
|
||||
@@ -3799,7 +4097,7 @@ attribute, used for evaluating a scope expression when the switch value changes.
|
||||
While it's unlikely, applications which may be using this feature should work around the removal
|
||||
by adding a custom directive which will perform the eval instead. Directive controllers are
|
||||
re-instantiated when being transcluded, so by putting the attribute on each item that you want
|
||||
to be notified of a change to, you can more or less emulate the old behaviour.
|
||||
to be notified of a change to, you can more or less emulate the old behavior.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -4062,7 +4360,7 @@ Angular will now throw a $compile minErr each a template fails to download
|
||||
for ngView, directives and ngMessage template requests. This changes the former
|
||||
behavior of silently ignoring failed HTTP requests--or when the template itself
|
||||
is empty. Please ensure that all directive, ngView and ngMessage code now properly
|
||||
addresses this scenario. NgInclude is uneffected from this change.
|
||||
addresses this scenario. NgInclude is unaffected from this change.
|
||||
|
||||
|
||||
- **$animate**: due to [23da6140](https://github.com/angular/angular.js/commit/23da614043fe5dcf0be132b86466eecb11c766a2)
|
||||
@@ -4075,7 +4373,7 @@ applying the active CSS class.
|
||||
|
||||
- **$animate**: due to [bf0f5502](https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9)
|
||||
|
||||
Both the API for the cancallation method and the done callback for
|
||||
Both the API for the cancelation method and the done callback for
|
||||
$animate animations is different. Instead of using a callback function
|
||||
for each of the $animate animation methods, a promise is used instead.
|
||||
|
||||
@@ -4302,7 +4600,7 @@ angular.module("myApp", []).
|
||||
- **input:** due to [ebece0bc](https://github.com/angular/angular.js/commit/ebece0bcb9d64e59beb1c9b3418bed25e50ceef4),
|
||||
|
||||
Previously, `input[type=password]` would trim values by default, and would require an explicit ng-trim="false"
|
||||
to disable the trimming behaviour. After this CL, `ng-trim` no longer affects `input[type=password]`, and will
|
||||
to disable the trimming behavior. After this CL, `ng-trim` no longer affects `input[type=password]`, and will
|
||||
never trim the password value.
|
||||
|
||||
Closes #8250
|
||||
@@ -4345,7 +4643,7 @@ Closes #8230
|
||||
- **copy:** clear array destinations correctly for non-array sources
|
||||
([a603e202](https://github.com/angular/angular.js/commit/a603e202cc7e048c2ab6f12dee1cc8f277cf6f4f),
|
||||
[#8610](https://github.com/angular/angular.js/issues/8610), [#8702](https://github.com/angular/angular.js/issues/8702))
|
||||
- **forEach:** match behaviour of Array.prototype.forEach (ignore missing properties)
|
||||
- **forEach:** match behavior of Array.prototype.forEach (ignore missing properties)
|
||||
([36230194](https://github.com/angular/angular.js/commit/36230194be8aa417b0af33d618060829a75c4c5f),
|
||||
[#8510](https://github.com/angular/angular.js/issues/8510), [#8522](https://github.com/angular/angular.js/issues/8522), [#8525](https://github.com/angular/angular.js/issues/8525))
|
||||
- **input:**
|
||||
@@ -4562,7 +4860,7 @@ by this change.
|
||||
by default, do not trim `input[type=password]` values.
|
||||
|
||||
Previously, `input[type=password]` would trim values by default, and would require an explicit `ng-trim="false"`
|
||||
to disable the trimming behaviour. After this change, `ng-trim` no longer affects `input[type=password]`, and will
|
||||
to disable the trimming behavior. After this change, `ng-trim` no longer affects `input[type=password]`, and will
|
||||
never trim the password value.
|
||||
|
||||
Closes #8250
|
||||
@@ -4726,7 +5024,7 @@ Closes #8230
|
||||
- **$compile:** due to [11f5aeee](https://github.com/angular/angular.js/commit/11f5aeeee952a395edaf54e3277674f211a82fc7),
|
||||
directives now match elements by default unless specific restriction rules are set via `restrict` property.
|
||||
|
||||
This means that if a directive 'myFoo' previously didn't specify matching restrictrion, it will now match both the attribute
|
||||
This means that if a directive 'myFoo' previously didn't specify matching restriction, it will now match both the attribute
|
||||
and element form.
|
||||
|
||||
Before:
|
||||
@@ -4856,7 +5154,7 @@ Closes #8321
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** explicitly request multi-element directive behaviour
|
||||
- **$compile:** explicitly request multi-element directive behavior
|
||||
([e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
|
||||
[#5372](https://github.com/angular/angular.js/issues/5372), [#6574](https://github.com/angular/angular.js/issues/6574), [#5370](https://github.com/angular/angular.js/issues/5370), [#8044](https://github.com/angular/angular.js/issues/8044), [#7336](https://github.com/angular/angular.js/issues/7336))
|
||||
- **ngList:** use ngTrim to manage whitespace handling when splitting
|
||||
@@ -4883,7 +5181,7 @@ Closes #8321
|
||||
|
||||
- **$compile:** due to [e8066c4b](https://github.com/angular/angular.js/commit/e8066c4b4ce11496b0d8f39e41b4d753048bca2d),
|
||||
Directives which previously depended on the implicit grouping between
|
||||
directive-start and directive-end attributes must be refactored in order to see this same behaviour.
|
||||
directive-start and directive-end attributes must be refactored in order to see this same behavior.
|
||||
|
||||
Before:
|
||||
|
||||
@@ -4964,7 +5262,7 @@ Closes #8147
|
||||
The `ngList` directive no longer supports splitting the view value
|
||||
via a regular expression. We need to be able to re-join list items back
|
||||
together and doing this when you can split with regular expressions can
|
||||
lead to inconsistent behaviour and would be much more complex to support.
|
||||
lead to inconsistent behavior and would be much more complex to support.
|
||||
|
||||
If your application relies upon ngList splitting with a regular expression
|
||||
then you should either try to convert the separator to a simple string or
|
||||
@@ -5264,11 +5562,11 @@ vulnerabilities via [security@angularjs.org].
|
||||
- due to [77ada4c8](https://github.com/angular/angular.js/commit/77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
This is to disallow changing the behavior of existing functions
|
||||
in an unforeseen fashion.
|
||||
- due to [6081f207](https://github.com/angular/angular.js/commit/6081f20769e64a800ee8075c168412b21f026d99),
|
||||
|
||||
The (deprecated) __proto__ propery does not work inside angular expressions
|
||||
The (deprecated) __proto__ property does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [48fa3aad](https://github.com/angular/angular.js/commit/48fa3aadd546036c7e69f71046f659ab1de244c6),
|
||||
|
||||
@@ -5288,10 +5586,10 @@ of the original object's prototype chain directly onto the copied object.
|
||||
|
||||
This means that if you iterate over only the copied object's `hasOwnProperty`
|
||||
properties, it will no longer contain the properties from the prototype.
|
||||
This is actually much more reasonable behaviour and it is unlikely that
|
||||
This is actually much more reasonable behavior and it is unlikely that
|
||||
applications are actually relying on this.
|
||||
|
||||
If this behaviour is relied upon, in an app, then one should simply iterate
|
||||
If this behavior is relied upon, in an app, then one should simply iterate
|
||||
over all the properties on the object (and its inherited properties) and
|
||||
not filter them with `hasOwnProperty`.
|
||||
|
||||
@@ -5395,11 +5693,11 @@ or:
|
||||
- due to [07fa87a8](https://github.com/angular/angular.js/commit/07fa87a8a82b8be155d8c898bb79e5d9277adfb4),
|
||||
|
||||
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
|
||||
This is to disallow changing the behaviour of existing functions
|
||||
in an unforseen fashion.
|
||||
This is to disallow changing the behavior of existing functions
|
||||
in an unforeseen fashion.
|
||||
- due to [cb713e60](https://github.com/angular/angular.js/commit/cb713e6045413a25b54ad3267476fa29efd70646),
|
||||
|
||||
The (deprecated) __proto__ propery does not work inside angular expressions
|
||||
The (deprecated) __proto__ property does not work inside angular expressions
|
||||
anymore.
|
||||
- due to [89ca8597](https://github.com/angular/angular.js/commit/89ca8597341aa5585bcf728fa677022b7ec9c071),
|
||||
|
||||
@@ -5499,7 +5797,7 @@ If you need Object.keys, make it accessible in the scope.
|
||||
([92489886](https://github.com/angular/angular.js/commit/92489886dcce3bca00fe827aeb0817297b8a175c))
|
||||
- optimize adding nodes to a jqLite collection
|
||||
([31faeaa7](https://github.com/angular/angular.js/commit/31faeaa7293716251ed437fa54432bb89d9d48de))
|
||||
- optimize element dealocation
|
||||
- optimize element deallocation
|
||||
([e35abc9d](https://github.com/angular/angular.js/commit/e35abc9d2fac0471cbe8089dc0e33a72b8029ada))
|
||||
- don't use reflection to access expandoId
|
||||
([ea9a130a](https://github.com/angular/angular.js/commit/ea9a130a43d165f4f4389d01ac409dd3047efcb4))
|
||||
@@ -5996,7 +6294,7 @@ https://docs.angularjs.org/api/ng/service/$http#interceptors
|
||||
|
||||
- **injector:** due to [c0b4e2db](https://github.com/angular/angular.js/commit/c0b4e2db9cbc8bc3164cedc4646145d3ab72536e),
|
||||
|
||||
Previously, config blocks would be able to control behaviour of provider registration, due to being
|
||||
Previously, config blocks would be able to control behavior of provider registration, due to being
|
||||
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
|
||||
for a given module, and therefore config blocks are not able to have any control over a providers
|
||||
registration.
|
||||
@@ -6026,8 +6324,8 @@ angular.module('foo', [])
|
||||
});
|
||||
```
|
||||
|
||||
would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
|
||||
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
|
||||
would have "worked", meaning behavior of the config block between the registration of "$rootProvider"
|
||||
and "$dependentProvider" would have actually accomplished something and changed the behavior of the
|
||||
app. This is no longer possible within a single module.
|
||||
|
||||
|
||||
@@ -6543,7 +6841,7 @@ For more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approa
|
||||
- only block keyframes if a stagger is set to occur
|
||||
([e71e7b6c](https://github.com/angular/angular.js/commit/e71e7b6cae57f25c5837dda98551c8e0a5cb720d),
|
||||
[#4225](https://github.com/angular/angular.js/issues/4225))
|
||||
- ensure that animateable directives cancel expired leave animations
|
||||
- ensure that animatable directives cancel expired leave animations
|
||||
([e9881991](https://github.com/angular/angular.js/commit/e9881991ca0a5019d3a4215477738ed247898ba0),
|
||||
[#5886](https://github.com/angular/angular.js/issues/5886))
|
||||
- ensure all animated elements are taken care of during the closing timeout
|
||||
@@ -6700,7 +6998,7 @@ For more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approa
|
||||
- rename mock.animate to ngAnimateMock and ensure it contains all test helper code for ngAnimate
|
||||
([4224cd51](https://github.com/angular/angular.js/commit/4224cd5182bc93e4a210f75e0a4e4de7f3c544e8),
|
||||
[#5822](https://github.com/angular/angular.js/issues/5822), [#5917](https://github.com/angular/angular.js/issues/5917))
|
||||
- remove usage of $animate.flushNext in favour of queing
|
||||
- remove usage of $animate.flushNext in favor of queuing
|
||||
([906fdad0](https://github.com/angular/angular.js/commit/906fdad0f95465842e336e057ea97d0633712189))
|
||||
- always call functions injected with `inject` with `this` set to the current spec
|
||||
([3bf43903](https://github.com/angular/angular.js/commit/3bf43903397c703aa2e9ba1e1a48dbc9e8286ee2),
|
||||
@@ -6811,7 +7109,7 @@ The animation mock module has been renamed from `mock.animate` to `ngAnimateMock
|
||||
## Breaking Changes
|
||||
|
||||
- **$http:** due to [e1cfb195](https://github.com/angular/angular.js/commit/e1cfb1957feaf89408bccf48fae6f529e57a82fe),
|
||||
it is now necessary to seperately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
it is now necessary to separately specify default HTTP headers for PUT, POST and PATCH requests, as these no longer share a single object.
|
||||
|
||||
To migrate your code, follow the example below:
|
||||
|
||||
@@ -6900,7 +7198,7 @@ The animation mock module has been renamed from `mock.animate` to `ngAnimateMock
|
||||
- remove base href domain if the URL begins with '//'
|
||||
([760f2fb7](https://github.com/angular/angular.js/commit/760f2fb73178e56c37397b3c5876f7dac96f0455),
|
||||
[#5606](https://github.com/angular/angular.js/issues/5606))
|
||||
- fix $location.path() behaviour when $locationChangeStart is triggered by the browser
|
||||
- fix $location.path() behavior when $locationChangeStart is triggered by the browser
|
||||
([cf686285](https://github.com/angular/angular.js/commit/cf686285c22d528440e173fdb65ad1052d96df3c),
|
||||
[#4989](https://github.com/angular/angular.js/issues/4989), [#5089](https://github.com/angular/angular.js/issues/5089), [#5118](https://github.com/angular/angular.js/issues/5118), [#5580](https://github.com/angular/angular.js/issues/5580))
|
||||
- re-assign history after BFCache back on Android browser
|
||||
@@ -6957,7 +7255,7 @@ The animation mock module has been renamed from `mock.animate` to `ngAnimateMock
|
||||
- **$log:** should work in IE8
|
||||
([4f5758e6](https://github.com/angular/angular.js/commit/4f5758e6669222369889c9e789601d25ff885530),
|
||||
[#5400](https://github.com/angular/angular.js/issues/5400))
|
||||
- **$parse:** return `undefined` if an intermetiate property's value is `null`
|
||||
- **$parse:** return `undefined` if an intermediate property's value is `null`
|
||||
([26d43cac](https://github.com/angular/angular.js/commit/26d43cacdc106765bd928d41600352198f887aef),
|
||||
[#5480](https://github.com/angular/angular.js/issues/5480))
|
||||
- **closure:** add type definition for `Scope#$watchCollection`
|
||||
@@ -7333,7 +7631,7 @@ There are no breaking changes in this release (promise!)
|
||||
- attribute bindings should not break due to terminal directives
|
||||
([79223eae](https://github.com/angular/angular.js/commit/79223eae5022838893342c42dacad5eca83fabe8),
|
||||
[#4525](https://github.com/angular/angular.js/issues/4525), [#4528](https://github.com/angular/angular.js/issues/4528), [#4649](https://github.com/angular/angular.js/issues/4649))
|
||||
- instantiate controlers when re-entering compilation
|
||||
- instantiate controllers when re-entering compilation
|
||||
([faf5b980](https://github.com/angular/angular.js/commit/faf5b980da09da2b4c28f1feab33f87269f9f0ba),
|
||||
[#4434](https://github.com/angular/angular.js/issues/4434), [#4616](https://github.com/angular/angular.js/issues/4616))
|
||||
- **$injector:** allow a constructor function to return a function
|
||||
@@ -7473,7 +7771,7 @@ There are no breaking changes in this release (promise!)
|
||||
someone on the scope chain for JavaScript use, you also expose it to
|
||||
Angular expressions
|
||||
2. the new "controller as" syntax that's now in increased usage exposes the
|
||||
entire controller on the scope chain greatly increaing the exposed surface.
|
||||
entire controller on the scope chain greatly increasing the exposed surface.
|
||||
|
||||
Though Angular expressions are written and controlled by the developer, they:
|
||||
|
||||
@@ -7490,7 +7788,7 @@ There are no breaking changes in this release (promise!)
|
||||
Please use `data-ng-csp` instead.
|
||||
|
||||
- **jqLite:** due to [27e9340b](https://github.com/angular/angular.js/commit/27e9340b3c25b512e45213b39811098d07e12e3b),
|
||||
`jqLite.scope()` (connonly used through `angular.element(node).scope()`) does not return the
|
||||
`jqLite.scope()` (commonly used through `angular.element(node).scope()`) does not return the
|
||||
isolate scope on the element that triggered directive with isolate scope. Use
|
||||
`jqLite.isolateScope()` instead.
|
||||
|
||||
@@ -7742,7 +8040,7 @@ There are no breaking changes in this release (promise!)
|
||||
- **directives:** due to [b7af76b4](https://github.com/angular/angular.js/commit/b7af76b4c5aa77648cc1bfd49935b48583419023),
|
||||
the priority of ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView has changed. This could affect directives that explicitly specify their priority.
|
||||
|
||||
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precendence:
|
||||
In order to make ngRepeat, ngSwitchWhen, ngIf, ngInclude and ngView work together in all common scenarios their directives are being adjusted to achieve the following precedence:
|
||||
|
||||
```
|
||||
Directive | Old Priority | New Priority
|
||||
@@ -7816,7 +8114,7 @@ There are no breaking changes in this release (promise!)
|
||||
|
||||
- **Directives:**
|
||||
- **ngTransclude:**
|
||||
- clear the translusion point before transcluding
|
||||
- clear the transclusion point before transcluding
|
||||
([eed299a3](https://github.com/angular/angular.js/commit/eed299a31b5a6dd0363133c5f9271bf33d090c94))
|
||||
- make the transclusion available to parent post-link function
|
||||
([bf79bd41](https://github.com/angular/angular.js/commit/bf79bd4194eca2118ae1c492c08dbd217f5ae810))
|
||||
@@ -8830,7 +9128,7 @@ _Note: This release also contains all bug fixes available in [1.0.6](#1.0.6)._
|
||||
<li ng-switch-when="option">2</li>
|
||||
</ul>
|
||||
|
||||
To keep the old behaviour, use:
|
||||
To keep the old behavior, use:
|
||||
|
||||
<ul ng-switch="select">
|
||||
<li ng-switch-when="1">2</li>
|
||||
@@ -9229,7 +9527,7 @@ _Note: This release also contains all bug fixes available in [1.0.3](#1.0.3)._
|
||||
([a32bc40f](https://github.com/angular/angular.js/commit/a32bc40fd75ca46e3581ad7a6e3a24a31df6e266),
|
||||
[#1111](https://github.com/angular/angular.js/issues/1111))
|
||||
([d9eff86e](https://github.com/angular/angular.js/commit/d9eff86ef77dd76208cef21e882239d4db0eac1e))
|
||||
- **$parser:** string concatination with undefined model
|
||||
- **$parser:** string concatenation with undefined model
|
||||
([42c38b29](https://github.com/angular/angular.js/commit/42c38b29f7dcb3327fe58e630b8e2973676989e0),
|
||||
[#988](https://github.com/angular/angular.js/issues/988))
|
||||
- **$resource:**
|
||||
@@ -11094,7 +11392,7 @@ with the `$route` service
|
||||
`$browser.defer.flush()` in your test just before the point where you expect all cached
|
||||
resource/xhr requests to return any results. Please see 011fa39c2a0b5da843395b538fc4e52e5ade8287
|
||||
for more info.
|
||||
- The HTML sanitizer is slightly more strinct now. Please see info in the "Security" section above.
|
||||
- The HTML sanitizer is slightly more strict now. Please see info in the "Security" section above.
|
||||
|
||||
|
||||
<a name="0.9.5"></a>
|
||||
@@ -11137,7 +11435,7 @@ with the `$route` service
|
||||
|
||||
### Api
|
||||
- date filter now accepts strings that angular.String.toDate can convert to Date objects
|
||||
- angular.String.toDate supports ISO8061 formated strings with all time fractions being optional
|
||||
- angular.String.toDate supports ISO8061 formatted strings with all time fractions being optional
|
||||
- ng:repeat now exposes $position with values set to 'first', 'middle' or 'last'
|
||||
- ng:switch now supports ng:switch-default as fallback switch option
|
||||
|
||||
@@ -11175,7 +11473,7 @@ with the `$route` service
|
||||
- new browser() dsl statement for getting info about the emulated browser running the app
|
||||
(issue #109)
|
||||
- scenario runner is now compatible with IE8 (issue #93)
|
||||
- scenarior runner checks if URL would return a non-success status code (issue #100)
|
||||
- scenario runner checks if URL would return a non-success status code (issue #100)
|
||||
- binding() DSL now accepts regular expressions
|
||||
- new textarea() scenario runner DSL for entering text into textareas
|
||||
|
||||
@@ -11209,7 +11507,7 @@ with the `$route` service
|
||||
|
||||
### Chores
|
||||
- lots of fixes to get all tests pass on IE
|
||||
- added TzDate type to allow us to create timezone idependent tests (issue #88)
|
||||
- added TzDate type to allow us to create timezone independent tests (issue #88)
|
||||
|
||||
### Breaking changes
|
||||
- $cookieStore service is not globally published any more, if you use it, you must request it via
|
||||
|
||||
+7
-1
@@ -123,13 +123,19 @@ Before you submit your pull request consider the following guidelines:
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the Angular test suite to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
* Commit your changes to your branch (e.g. `my-fix-branch`).
|
||||
* Push the changes to your GitHub repository (this will update your Pull Request).
|
||||
|
||||
If the PR gets too outdated we may ask you to rebase and force push to update the PR:
|
||||
|
||||
```shell
|
||||
git rebase master -i
|
||||
git push origin my-fix-branch -f
|
||||
```
|
||||
|
||||
*WARNING. Squashing or reverting commits and forced push thereafter may remove GitHub comments
|
||||
on code that were previously made by you and others in your commits.*
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
#### After your pull request is merged
|
||||
|
||||
+13
-11
@@ -162,7 +162,7 @@ module.exports = function(grunt) {
|
||||
'!src/angular.bind.js' // we ignore this file since contains an early return statement
|
||||
],
|
||||
options: {
|
||||
config: ".jscsrc"
|
||||
config: '.jscsrc'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -231,9 +231,9 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-aria.js',
|
||||
src: util.wrap(files['angularModules']['ngAria'], 'module')
|
||||
},
|
||||
"promises-aplus-adapter": {
|
||||
'promises-aplus-adapter': {
|
||||
dest:'tmp/promises-aplus-adapter++.js',
|
||||
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
src:['src/ng/q.js', 'lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
}
|
||||
},
|
||||
|
||||
@@ -253,7 +253,7 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
|
||||
"ddescribe-iit": {
|
||||
'ddescribe-iit': {
|
||||
files: [
|
||||
'src/**/*.js',
|
||||
'test/**/*.js',
|
||||
@@ -274,7 +274,7 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
"merge-conflict": {
|
||||
'merge-conflict': {
|
||||
files: [
|
||||
'src/**/*',
|
||||
'test/**/*',
|
||||
@@ -304,11 +304,11 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
shell: {
|
||||
"npm-install": {
|
||||
'npm-install': {
|
||||
command: 'node scripts/npm/check-node-modules.js'
|
||||
},
|
||||
|
||||
"promises-aplus-tests": {
|
||||
'promises-aplus-tests': {
|
||||
options: {
|
||||
stdout: false,
|
||||
stderr: true,
|
||||
@@ -339,8 +339,10 @@ module.exports = function(grunt) {
|
||||
grunt.task.run('shell:npm-install');
|
||||
}
|
||||
|
||||
|
||||
|
||||
//alias tasks
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'jscs', 'package', 'test:unit', 'test:promises-aplus', 'tests:docs', 'test:protractor']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['build', 'tests:modules']);
|
||||
@@ -350,11 +352,11 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('test:travis-protractor', 'Run the end to end tests with Protractor for Travis CI builds', ['connect:testserver', 'protractor:travis']);
|
||||
grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor for Jenkins CI builds', ['webdriver', 'connect:testserver', 'protractor:jenkins']);
|
||||
grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter', 'shell:promises-aplus-tests']);
|
||||
|
||||
grunt.registerTask('minify', ['bower','clean', 'build', 'minall']);
|
||||
grunt.registerTask('minify', ['bower', 'clean', 'build', 'minall']);
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package', ['bower', 'validate-angular-files', 'clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'jscs']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
Copyright (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
Vendored
+2
-1
@@ -34,6 +34,7 @@ var angularFiles = {
|
||||
'src/ng/q.js',
|
||||
'src/ng/raf.js',
|
||||
'src/ng/rootScope.js',
|
||||
'src/ng/rootElement.js',
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
@@ -85,7 +86,7 @@ var angularFiles = {
|
||||
],
|
||||
|
||||
'angularLoader': [
|
||||
'stringify.js',
|
||||
'src/stringify.js',
|
||||
'src/minErr.js',
|
||||
'src/loader.js'
|
||||
],
|
||||
|
||||
@@ -8,20 +8,20 @@
|
||||
Large table rendered with AngularJS
|
||||
</p>
|
||||
|
||||
<div>none: <input type="radio" ng-model="benchmarkType" value="none"></div>
|
||||
<div>baseline binding: <input type="radio" ng-model="benchmarkType" value="baselineBinding"></div>
|
||||
<div>baseline interpolation: <input type="radio" ng-model="benchmarkType" value="baselineInterpolation"></div>
|
||||
<div>ngBind: <input type="radio" ng-model="benchmarkType" value="ngBind"></div>
|
||||
<div>ngBindOnce: <input type="radio" ng-model="benchmarkType" value="ngBindOnce"></div>
|
||||
<div>interpolation: <input type="radio" ng-model="benchmarkType" value="interpolation"></div>
|
||||
<div>interpolation + bind-once: <input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation"></div>
|
||||
<div>attribute interpolation: <input type="radio" ng-model="benchmarkType" value="interpolationAttr"></div>
|
||||
<div>ngBind + fnInvocation: <input type="radio" ng-model="benchmarkType" value="ngBindFn"></div>
|
||||
<div>interpolation + fnInvocation: <input type="radio" ng-model="benchmarkType" value="interpolationFn"></div>
|
||||
<div>ngBind + filter: <input type="radio" ng-model="benchmarkType" value="ngBindFilter"></div>
|
||||
<div>interpolation + filter: <input type="radio" ng-model="benchmarkType" value="interpolationFilter"></div>
|
||||
<div>ngModel (const name): <input type="radio" ng-model="benchmarkType" value="ngModelConstName"></div>
|
||||
<div>ngModel (interp name): <input type="radio" ng-model="benchmarkType" value="ngModelInterpName"></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="none">none: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="baselineBinding">baseline binding: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="baselineInterpolation">baseline interpolation: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngBind">ngBind: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindOnce">ngBindOnce: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="interpolation">interpolation: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="bindOnceInterpolation">interpolation + bind-once: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationAttr">attribute interpolation: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFn">ngBind + fnInvocation: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFn">interpolation + fnInvocation: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngBindFilter">ngBind + filter: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="interpolationFilter">interpolation + filter: </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelConstName">ngModel (const name): </label></div>
|
||||
<div><label><input type="radio" ng-model="benchmarkType" value="ngModelInterpName">ngModel (interp name): </label></div>
|
||||
|
||||
<ng-switch on="benchmarkType">
|
||||
<baseline-binding-table ng-switch-when="baselineBinding">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"name": "AngularJS",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"jquery": "2.1.1",
|
||||
"closure-compiler": "https://dl.google.com/closure-compiler/compiler-20140814.zip",
|
||||
|
||||
@@ -124,7 +124,7 @@ h1,h2,h3,h4,h5,h6 {
|
||||
font-size:1.2em;
|
||||
padding:0;
|
||||
margin:0;
|
||||
border-bottom:1px soild #aaa;
|
||||
border-bottom:1px solid #aaa;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,26 @@ angular.module('examples', [])
|
||||
|
||||
|
||||
.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
|
||||
+ 'Use of this source code is governed by an MIT-style license that\n'
|
||||
+ 'can be found in the LICENSE file at http://angular.io/license';
|
||||
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
|
||||
var COPYRIGHT_HTML = '\n\n<!-- \n' + COPYRIGHT + '\n-->';
|
||||
function getCopyright(filename) {
|
||||
switch (filename.substr(filename.lastIndexOf('.'))) {
|
||||
case '.html':
|
||||
return COPYRIGHT_HTML;
|
||||
case '.js':
|
||||
case '.css':
|
||||
return COPYRIGHT_JS_CSS;
|
||||
case '.md':
|
||||
return COPYRIGHT;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
return function(exampleFolder, clickEvent) {
|
||||
|
||||
var exampleName = 'AngularJS Example';
|
||||
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
|
||||
@@ -67,7 +86,7 @@ angular.module('examples', [])
|
||||
var postData = {};
|
||||
|
||||
angular.forEach(files, function(file) {
|
||||
postData['files[' + file.name + ']'] = file.content;
|
||||
postData['files[' + file.name + ']'] = file.content + getCopyright(file.name);
|
||||
});
|
||||
|
||||
postData['tags[0]'] = "angularjs";
|
||||
|
||||
@@ -170,4 +170,8 @@ module.exports = new Package('angularjs', [
|
||||
jqueryDeployment,
|
||||
productionDeployment
|
||||
];
|
||||
})
|
||||
|
||||
.config(function(generateKeywordsProcessor) {
|
||||
generateKeywordsProcessor.docTypesToIgnore = ['componentGroup'];
|
||||
});
|
||||
|
||||
@@ -16,9 +16,11 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
ignoreWordsFile: undefined,
|
||||
areasToSearch: ['api', 'guide', 'misc', 'error', 'tutorial'],
|
||||
propertiesToIgnore: [],
|
||||
docTypesToIgnore: [],
|
||||
$validate: {
|
||||
ignoreWordsFile: { },
|
||||
areasToSearch: { presence: true },
|
||||
docTypesToIgnore: { },
|
||||
propertiesToIgnore: { }
|
||||
},
|
||||
$runAfter: ['memberDocsProcessor'],
|
||||
@@ -28,6 +30,7 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
// Keywords to ignore
|
||||
var wordsToIgnore = [];
|
||||
var propertiesToIgnore;
|
||||
var docTypesToIgnore;
|
||||
var areasToSearch;
|
||||
|
||||
// Keywords start with "ng:" or one of $, _ or a letter
|
||||
@@ -47,6 +50,8 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
areasToSearch = _.indexBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
|
||||
log.debug('Properties to ignore', propertiesToIgnore);
|
||||
docTypesToIgnore = _.indexBy(this.docTypesToIgnore);
|
||||
log.debug('Doc types to ignore', docTypesToIgnore);
|
||||
|
||||
var ignoreWordsMap = _.indexBy(wordsToIgnore);
|
||||
|
||||
@@ -78,34 +83,36 @@ module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
|
||||
// We are only interested in docs that live in the right area
|
||||
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
|
||||
docs = _.filter(docs, function(doc) { return !docTypesToIgnore[doc.docType]; });
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
|
||||
var words = [];
|
||||
var keywordMap = _.clone(ignoreWordsMap);
|
||||
var members = [];
|
||||
var membersMap = {};
|
||||
|
||||
// Search each top level property of the document for search terms
|
||||
_.forEach(doc, function(value, key) {
|
||||
var words = [];
|
||||
var keywordMap = _.clone(ignoreWordsMap);
|
||||
var members = [];
|
||||
var membersMap = {};
|
||||
|
||||
if ( _.isString(value) && !propertiesToIgnore[key] ) {
|
||||
extractWords(value, words, keywordMap);
|
||||
}
|
||||
// Search each top level property of the document for search terms
|
||||
_.forEach(doc, function(value, key) {
|
||||
|
||||
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
|
||||
_.forEach(value, function(member) {
|
||||
extractWords(member.name, members, membersMap);
|
||||
});
|
||||
}
|
||||
});
|
||||
if ( _.isString(value) && !propertiesToIgnore[key] ) {
|
||||
extractWords(value, words, keywordMap);
|
||||
}
|
||||
|
||||
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
|
||||
_.forEach(value, function(member) {
|
||||
extractWords(member.name, members, membersMap);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
doc.searchTerms = {
|
||||
titleWords: extractTitleWords(doc.name),
|
||||
keywords: _.sortBy(words).join(' '),
|
||||
members: _.sortBy(members).join(' ')
|
||||
};
|
||||
doc.searchTerms = {
|
||||
titleWords: extractTitleWords(doc.name),
|
||||
keywords: _.sortBy(words).join(' '),
|
||||
members: _.sortBy(members).join(' ')
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
<p class="pull-right"><a back-to-top>Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2015
|
||||
Super-powered by Google ©2010-2016
|
||||
( <a id="version"
|
||||
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
|
||||
ng-bind-template="v{{version}}" title="Changelog of this version of Angular JS">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
|
||||
{# Be aware that we need these extra new lines here or marked will not realize that the <div>
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
@@ -24,5 +24,5 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Be aware that we need these extra new lines here or marked will not realise that the <div>
|
||||
{# Be aware that we need these extra new lines here or marked will not realize that the <div>
|
||||
above is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
This error occurs when a module fails to load due to some exception. The error
|
||||
message above should provide additional context.
|
||||
|
||||
A common reason why the module fails to load is that you've forgotten to
|
||||
include the file with the defined module or that the file couldn't be loaded.
|
||||
|
||||
### Using `ngRoute`
|
||||
|
||||
In AngularJS `1.2.0` and later, `ngRoute` has been moved to its own module.
|
||||
@@ -24,4 +27,4 @@ angular.module('ng').filter('tel', function (){});
|
||||
|
||||
Instead create your own module and add it as a dependency to your application's top-level module.
|
||||
See [#9692](https://github.com/angular/angular.js/issues/9692) and
|
||||
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
|
||||
[#7709](https://github.com/angular/angular.js/issues/7709) for more information
|
||||
|
||||
@@ -81,3 +81,6 @@ angular.module('myModule', [])
|
||||
// a scope object cannot be injected into a service.
|
||||
}]);
|
||||
```
|
||||
|
||||
If you encounter this error only with minified code, consider using `ngStrictDi` (see
|
||||
{@link ng.directive:ngApp ngApp}) to provoke the error with the non-minified source.
|
||||
|
||||
@@ -14,3 +14,32 @@ perform this check - it's up to the developer to not expose such sensitive and p
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid Window access.
|
||||
|
||||
### Common CoffeeScript Issue
|
||||
|
||||
Be aware that if you are using CoffeeScript, it automatically returns the value of the last statement in a
|
||||
function. So for instance
|
||||
|
||||
```coffeescript
|
||||
scope.foo = ->
|
||||
window.open 'https://example.com'
|
||||
```
|
||||
|
||||
compiles to something like
|
||||
|
||||
```js
|
||||
scope.foo = function() {
|
||||
return window.open('https://example.com');
|
||||
};
|
||||
```
|
||||
|
||||
You can see that this function will return the result of calling `window.open`, which is a `Window`
|
||||
object.
|
||||
|
||||
You can avoid this by explicitly returning something else from the function:
|
||||
|
||||
```coffeescript
|
||||
scope.foo = ->
|
||||
window.open 'https://example.com'
|
||||
return true;
|
||||
```
|
||||
|
||||
@@ -100,7 +100,7 @@ To resolve this type of issue, either fix the api to be always synchronous or as
|
||||
your callback handler to always run asynchronously by using the `$timeout` service.
|
||||
|
||||
```
|
||||
function MyController($scope, thirdPartyComponent) {
|
||||
function MyController($scope, $timeout, thirdPartyComponent) {
|
||||
thirdPartyComponent.getData(function(someData) {
|
||||
$timeout(function() {
|
||||
$scope.someData = someData;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
@ngdoc error
|
||||
@name linky:notstring
|
||||
@fullName Not a string
|
||||
@description
|
||||
|
||||
This error occurs when {@link ngSanitize.linky linky} is used with a non-empty, non-string value:
|
||||
```html
|
||||
<div ng-bind-html="42 | linky"></div>
|
||||
```
|
||||
|
||||
`linky` is supposed to be used with string values only, and therefore assumes that several methods
|
||||
(such as `.match()`) are available on the passed in value.
|
||||
The value can be initialized asynchronously and therefore null or undefined won't throw this error.
|
||||
|
||||
If you want to pass non-string values to `linky` (e.g. Objects whose `.toString()` should be
|
||||
utilized), you need to manually convert them to strings.
|
||||
@@ -0,0 +1,28 @@
|
||||
@ngdoc error
|
||||
@name ngModel:nopromise
|
||||
@fullName No promise
|
||||
@description
|
||||
|
||||
The return value of an async validator, must always be a promise. If you want to return a
|
||||
non-promise value, you can convert it to a promise using {@link ng.$q#resolve `$q.resolve()`} or
|
||||
{@link ng.$q#reject `$q.reject()`}.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
.directive('asyncValidator', function($q) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attrs, ngModel) {
|
||||
ngModel.$asyncValidators.myAsyncValidation = function(modelValue, viewValue) {
|
||||
if (/* I don't need to hit the backend API */) {
|
||||
return $q.resolve(); // to mark as valid or
|
||||
// return $q.reject(); // to mark as invalid
|
||||
} else {
|
||||
// ...send a request to the backend and return a promise
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
})
|
||||
```
|
||||
@@ -99,8 +99,13 @@ For example, the following forms are all equivalent and match the {@link ngBind}
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should show off bindings', function() {
|
||||
expect(element(by.css('div[ng-controller="Controller"] span[ng-bind]')).getText())
|
||||
.toBe('Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)');
|
||||
var containerElm = element(by.css('div[ng-controller="Controller"]'));
|
||||
var nameBindings = containerElm.all(by.binding('name'));
|
||||
|
||||
expect(nameBindings.count()).toBe(5);
|
||||
nameBindings.each(function(elem) {
|
||||
expect(elem.getText()).toEqual('Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)');
|
||||
});
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
@@ -141,63 +146,6 @@ directives when possible.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
### Text and attribute bindings
|
||||
|
||||
During the compilation process the {@link ng.$compile compiler} matches text and attributes
|
||||
using the {@link ng.$interpolate $interpolate} service to see if they contain embedded
|
||||
expressions. These expressions are registered as {@link ng.$rootScope.Scope#$watch watches}
|
||||
and will update as part of normal {@link ng.$rootScope.Scope#$digest digest} cycle. An
|
||||
example of interpolation is shown below:
|
||||
|
||||
```html
|
||||
<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>
|
||||
```
|
||||
|
||||
|
||||
### `ngAttr` attribute bindings
|
||||
|
||||
Web browsers are sometimes picky about what values they consider valid for attributes.
|
||||
|
||||
For example, considering this template:
|
||||
|
||||
```html
|
||||
<svg>
|
||||
<circle cx="{{cx}}"></circle>
|
||||
</svg>
|
||||
```
|
||||
|
||||
We would expect Angular to be able to bind to this, but when we check the console we see
|
||||
something like `Error: Invalid value for attribute cx="{{cx}}"`. Because of the SVG DOM API's
|
||||
restrictions, you cannot simply write `cx="{{cx}}"`.
|
||||
|
||||
With `ng-attr-cx` you can work around this problem.
|
||||
|
||||
If an attribute with a binding is prefixed with the `ngAttr` prefix (denormalized as `ng-attr-`)
|
||||
then during the binding it will be applied to the corresponding unprefixed attribute. This allows
|
||||
you to bind to attributes that would otherwise be eagerly processed by browsers
|
||||
(e.g. an SVG element's `circle[cx]` attributes). When using `ngAttr`, the `allOrNothing` flag of
|
||||
{@link ng.$interpolate $interpolate} is used, so if any expression in the interpolated string
|
||||
results in `undefined`, the attribute is removed and not added to the element.
|
||||
|
||||
For example, we could fix the example above by instead writing:
|
||||
|
||||
```html
|
||||
<svg>
|
||||
<circle ng-attr-cx="{{cx}}"></circle>
|
||||
</svg>
|
||||
```
|
||||
|
||||
If one wants to modify a camelcased attribute (SVG elements have valid camelcased attributes), such as `viewBox` on the `svg` element, one can use underscores to denote that the attribute to bind to is naturally camelcased.
|
||||
|
||||
For example, to bind to `viewBox`, we can write:
|
||||
|
||||
```html
|
||||
<svg ng-attr-view_box="{{viewBox}}">
|
||||
</svg>
|
||||
```
|
||||
|
||||
|
||||
## Creating Directives
|
||||
|
||||
First let's talk about the {@link ng.$compileProvider#directive API for registering directives}. Much like
|
||||
@@ -458,7 +406,7 @@ This is clearly not a great solution.
|
||||
|
||||
What we want to be able to do is separate the scope inside a directive from the scope
|
||||
outside, and then map the outer scope to a directive's inner scope. We can do this by creating what
|
||||
we call an **isolate scope**. To do this, we can use a directive's `scope` option:
|
||||
we call an **isolate scope**. To do this, we can use a {@link $compile#-scope- directive's `scope`} option:
|
||||
|
||||
<example module="docsIsolateScopeDirective">
|
||||
<file name="script.js">
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
# Angular Expressions
|
||||
|
||||
Angular expressions are JavaScript-like code snippets that are usually placed in bindings such as
|
||||
`{{ expression }}`.
|
||||
Angular expressions are JavaScript-like code snippets that are mainly placed in
|
||||
interpolation bindings such as `<span title="{{ attrBinding }}">{{ textBinding }}</span>`,
|
||||
but also used directly in directive attributes such as `ng-click="functionExpression()"`.
|
||||
|
||||
For example, these are valid expressions in Angular:
|
||||
|
||||
@@ -285,7 +286,7 @@ result is a non-undefined value (see value stabilization algorithm below).
|
||||
</example>
|
||||
|
||||
|
||||
### Why this feature
|
||||
### Reasons for using one-time binding
|
||||
|
||||
The main purpose of one-time binding expression is to provide a way to create a binding
|
||||
that gets deregistered and frees up resources once the binding is stabilized.
|
||||
|
||||
@@ -32,10 +32,13 @@ E.g. the markup `{{ 1234 | number:2 }}` formats the number 1234 with 2 decimal p
|
||||
|
||||
## Using filters in controllers, services, and directives
|
||||
|
||||
You can also use filters in controllers, services, and directives. For this, inject a dependency
|
||||
with the name `<filterName>Filter` to your controller/service/directive. E.g. using the dependency
|
||||
`numberFilter` will inject the number filter. The injected argument is a function that takes the
|
||||
value to format as first argument and filter parameters starting with the second argument.
|
||||
You can also use filters in controllers, services, and directives.
|
||||
|
||||
<div class="alert alert-info">
|
||||
For this, inject a dependency with the name `<filterName>Filter` into your controller/service/directive.
|
||||
E.g. a filter called `number` is injected by using the dependency `numberFilter`. The injected argument
|
||||
is a function that takes the value to format as first argument, and filter parameters starting with the second argument.
|
||||
</div>
|
||||
|
||||
The example below uses the filter called {@link ng.filter:filter `filter`}.
|
||||
This filter reduces arrays into sub arrays based on
|
||||
@@ -108,6 +111,7 @@ text upper-case.
|
||||
No filter: {{greeting}}<br>
|
||||
Reverse: {{greeting|reverse}}<br>
|
||||
Reverse + uppercase: {{greeting|reverse:true}}<br>
|
||||
Reverse, filtered in controller: {{filteredGreeting}}<br>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
@@ -127,8 +131,9 @@ text upper-case.
|
||||
return out;
|
||||
};
|
||||
})
|
||||
.controller('MyController', ['$scope', function($scope) {
|
||||
.controller('MyController', ['$scope', 'reverseFilter', function($scope, reverseFilter) {
|
||||
$scope.greeting = 'hello';
|
||||
$scope.filteredGreeting = reverseFilter($scope.greeting);
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
@ngdoc overview
|
||||
@name Interpolation
|
||||
@sortOrder 275
|
||||
@description
|
||||
|
||||
# Interpolation and data-binding
|
||||
|
||||
Interpolation markup with embedded {@link guide/expression expressions} is used by Angular to
|
||||
provide data-binding to text nodes and attribute values.
|
||||
|
||||
An example of interpolation is shown below:
|
||||
|
||||
```html
|
||||
<a ng-href="img/{{username}}.jpg">Hello {{username}}!</a>
|
||||
```
|
||||
|
||||
### How text and attribute bindings work
|
||||
|
||||
During the compilation process the {@link ng.$compile compiler} uses the {@link ng.$interpolate $interpolate}
|
||||
service to see if text nodes and element attributes contain interpolation markup with embedded expressions.
|
||||
|
||||
If that is the case, the compiler adds an interpolateDirective to the node and
|
||||
registers {@link ng.$rootScope.Scope#$watch watches} on the computed interpolation function,
|
||||
which will update the corresponding text nodes or attribute values as part of the
|
||||
normal {@link ng.$rootScope.Scope#$digest digest} cycle.
|
||||
|
||||
Note that the interpolateDirective has a priority of 100 and sets up the watch in the preLink function.
|
||||
|
||||
### Binding to boolean attributes
|
||||
|
||||
Attributes such as `disabled` are called `boolean` attributes, because their presence means `true` and
|
||||
their absence means `false`. We cannot use normal attribute bindings with them, because the HTML
|
||||
specification does not require browsers to preserve the values of boolean attributes. This means that
|
||||
if we put an Angular interpolation expression into such an attribute then the binding information
|
||||
would be lost, because the browser ignores the attribute value.
|
||||
|
||||
In the following example, the interpolation information would be ignored and the browser would simply
|
||||
interpret the attribute as present, meaning that the button would always be disabled.
|
||||
|
||||
```html
|
||||
Disabled: <input type="checkbox" ng-model="isDisabled" />
|
||||
<button disabled="{{isDisabled}}">Disabled</button>
|
||||
```
|
||||
|
||||
For this reason, Angular provides special `ng`-prefixed directives for the following boolean attributes:
|
||||
{@link ngDisabled `disabled`}, {@link ngRequired `required`}, {@link ngSelected `selected`},
|
||||
{@link ngChecked `checked`}, {@link ngReadonly `readOnly`} , and {@link ngOpen `open`}.
|
||||
|
||||
These directives take an expression inside the attribute, and set the corresponding boolean attribute
|
||||
to true when the expression evaluates to truthy.
|
||||
|
||||
```html
|
||||
Disabled: <input type="checkbox" ng-model="isDisabled" />
|
||||
<button ng-disabled="isDisabled">Disabled</button>
|
||||
```
|
||||
|
||||
### `ngAttr` for binding to arbitrary attributes
|
||||
|
||||
Web browsers are sometimes picky about what values they consider valid for attributes.
|
||||
|
||||
For example, considering this template:
|
||||
|
||||
```html
|
||||
<svg>
|
||||
<circle cx="{{cx}}"></circle>
|
||||
</svg>
|
||||
```
|
||||
|
||||
We would expect Angular to be able to bind to this, but when we check the console we see
|
||||
something like `Error: Invalid value for attribute cx="{{cx}}"`. Because of the SVG DOM API's
|
||||
restrictions, you cannot simply write `cx="{{cx}}"`.
|
||||
|
||||
With `ng-attr-cx` you can work around this problem.
|
||||
|
||||
If an attribute with a binding is prefixed with the `ngAttr` prefix (denormalized as `ng-attr-`)
|
||||
then during the binding it will be applied to the corresponding unprefixed attribute. This allows
|
||||
you to bind to attributes that would otherwise be eagerly processed by browsers
|
||||
(e.g. an SVG element's `circle[cx]` attributes). When using `ngAttr`, the `allOrNothing` flag of
|
||||
{@link ng.$interpolate $interpolate} is used, so if any expression in the interpolated string
|
||||
results in `undefined`, the attribute is removed and not added to the element.
|
||||
|
||||
For example, we could fix the example above by instead writing:
|
||||
|
||||
```html
|
||||
<svg>
|
||||
<circle ng-attr-cx="{{cx}}"></circle>
|
||||
</svg>
|
||||
```
|
||||
|
||||
If one wants to modify a camelcased attribute (SVG elements have valid camelcased attributes),
|
||||
such as `viewBox` on the `svg` element, one can use underscores to denote that the attribute to bind
|
||||
to is naturally camelcased.
|
||||
|
||||
For example, to bind to `viewBox`, we can write:
|
||||
|
||||
```html
|
||||
<svg ng-attr-view_box="{{viewBox}}">
|
||||
</svg>
|
||||
```
|
||||
|
||||
The following attributes are also known to cause problems when used with normal bindings:
|
||||
|
||||
- **size** in `<select>` elements (see [Github issue 1619](https://github.com/angular/angular.js/issues/1619))
|
||||
- **placeholder** in `<textarea>` in Internet Explorer 10/11 (see [Github issue 5025](https://github.com/angular/angular.js/issues/5025))
|
||||
|
||||
|
||||
### Embedding interpolation markup inside expressions
|
||||
|
||||
Angular directives take either expressions or interpolation markup with embedded expressions. So the
|
||||
following example which embeds interpolation inside an expression is a bad practice:
|
||||
|
||||
```html
|
||||
<div ng-show="form{{$index}}.$invalid"></div>
|
||||
```
|
||||
|
||||
You should instead delegate the computation of complex expressions to the scope, like this:
|
||||
|
||||
```html
|
||||
<div ng-show="getForm($index).$invalid"></div>
|
||||
```
|
||||
|
||||
```js
|
||||
function getForm() {
|
||||
return $scope['form' + $index];
|
||||
}
|
||||
```
|
||||
|
||||
You can also access the `scope` with `this` in your templates:
|
||||
|
||||
```html
|
||||
<div ng-show="this['form' + $index].$invalid"></div>
|
||||
```
|
||||
|
||||
#### Why mixing interpolation and expressions is bad practice:
|
||||
|
||||
- It increases the complexity of the markup
|
||||
- There is no guarantee that it works for every directive, because interpolation itself is a directive.
|
||||
If another directive accesses attribute data before interpolation has run, it will get the raw
|
||||
interpolation markup and not data.
|
||||
- It impacts performance, as interpolation adds another watcher to the scope.
|
||||
- Since this is not recommended usage, we do not test for this, and changes to
|
||||
Angular core may break your code.
|
||||
@@ -13,6 +13,156 @@ which drives many of these changes.
|
||||
* Several new features, especially animations, would not be possible without a few changes.
|
||||
* Finally, some outstanding bugs were best fixed by changing an existing API.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Migrate from 1.4 to 1.5
|
||||
|
||||
Angular 1.5 takes a big step towards preparing developers for a smoother transition to Angular 2 in
|
||||
the future. Architecturing your applications using components, making use of lifecycle hooks in
|
||||
directive controllers and relying on native ES6 features (such as classes and arrow functions) are
|
||||
now all possible with Angular 1.5.
|
||||
|
||||
|
||||
This release includes numerous bug and security fixes, as well as performance improvements to core
|
||||
services, directives, filters and helper functions. Existing applications can start enjoying the
|
||||
benefits of such changes in `$compile`, `$parse`, `$animate`, `$animateCss`, `$sanitize`, `ngOptions`,
|
||||
`currencyFilter`, `numberFilter`, `copy()` (to name but a few) without any change in code.
|
||||
|
||||
New features have been added to more than a dozen services, directives and filters across 7 modules.
|
||||
Among them, a few stand out:
|
||||
|
||||
* `angular.component()`: Introducing "components", a special sort of directive that are easy to
|
||||
configure and promote best practices (plus can bring Angular 1 applications closer to Angular 2's
|
||||
style of architecture).
|
||||
* Multi-slot transclusion: Enabling the design of more powerful and complex UI elements with a much
|
||||
simpler configuration and reduced boilerplate.
|
||||
* `ngAnimateSwap`: A new directive in `ngAnimate`, making it super easy to create rotating
|
||||
banner-like components
|
||||
* Testing helpers: New helper functions in `ngMock`, simplifying testing for animations, component
|
||||
controllers and routing.
|
||||
|
||||
Also, notable is the improved support for ES6 features, such as classes and arrow functions. These
|
||||
features are now more reliably detected and correctly handled within the core.
|
||||
|
||||
|
||||
All this goodness doesn't come without a price, though. Below is a list of breaking changes (grouped
|
||||
by module) that need to be taken into account while migrating from 1.4. Fortunately, the majority of
|
||||
them should have a pretty low impact on most applications.
|
||||
|
||||
|
||||
## Core
|
||||
|
||||
We tried to keep the breaking changes inside the core components to a bare minimum. Still, a few of
|
||||
them were unavoidable.
|
||||
|
||||
### Services (`$parse`)
|
||||
|
||||
Due to [0ea53503](https://github.com/angular/angular.js/commit/0ea535035a3a1a992948490c3533bffb83235052),
|
||||
a new special property, `$locals`, will be available for accessing the locals from an expression.
|
||||
This is a breaking change, only if a `$locals` property does already exist (and needs to be
|
||||
referenced) either on the `scope` or on the `locals` object. Your expressions should be changed to
|
||||
access such existing properties as `this.$locals` and `$locals.$locals` respectively.
|
||||
|
||||
|
||||
### Directives (`ngOptions`)
|
||||
|
||||
A fair amount of work has been put into the `ngOptions` directive, fixing bugs and corner-cases and
|
||||
neutralizing browser quirks. A couple of breaking changes were made in the process:
|
||||
|
||||
Due to [b71d7c3f](https://github.com/angular/angular.js/commit/b71d7c3f3c04e65b02d88b33c22dd90ae3cdfc27),
|
||||
falsy values (`''`, `0`, `false` and `null`) are properly recognized as option group identifiers for
|
||||
options passed to `ngOptions`. Previously, all of these values were ignored and the option was not
|
||||
assigned to any group. `undefined` is still interpreted as "no group".
|
||||
If you have options with falsy group indentifiers that should still not be assigned to any group,
|
||||
then you must filter the values before passing them to `ngOptions`, converting falsy values to
|
||||
`undefined`.
|
||||
|
||||
Due to [ded25187](https://github.com/angular/angular.js/commit/ded2518756d4409fdfda0d4af243f2125bea01b5),
|
||||
`ngOptions` now explicitly requires `ngModel` on the same element, thus an error will be thrown if
|
||||
`ngModel` is not found. Previously, `ngOptions` would silently fail, which could lead to
|
||||
hard-to-debug errors.
|
||||
This is not expected to have any significant impact on applications, since `ngOptions` didn't work
|
||||
without `ngModel` before either. The main difference is that now it will fail with a more
|
||||
informative error message.
|
||||
|
||||
|
||||
### Filters (`orderBy`)
|
||||
|
||||
Due to [2a85a634](https://github.com/angular/angular.js/commit/2a85a634f86c84f15b411ce009a3515fca7ba580),
|
||||
passing a non-array-like value (other than `undefined` or `null`) through the `orderBy` filter will
|
||||
throw an error. Previously, the input was returned unchanged, which could lead to hard-to-spot bugs
|
||||
and was not consistent with other filters (e.g. `filter`).
|
||||
Objects considered array-like include: arrays, array subclasses, strings, NodeLists,
|
||||
jqLite/jQuery collections
|
||||
|
||||
|
||||
## ngMessages (`ngMessage`)
|
||||
|
||||
Due to [4971ef12](https://github.com/angular/angular.js/commit/4971ef12d4c2c268cb8d26f90385dc96eba19db8),
|
||||
the `ngMessage` directive is now compiled with a priority of 1, which means directives on the same
|
||||
element as `ngMessage` with a priority lower than 1 will be applied when `ngMessage` calls its
|
||||
`$transclude` function. Previously, they were applied during the initial compile phase and were
|
||||
passed the comment element created by the transclusion of `ngMessage`.
|
||||
If you have custom directives that relied on the previous behavior, you need to give them a priority
|
||||
of 1 or greater.
|
||||
|
||||
|
||||
## ngResource (`$resource`)
|
||||
|
||||
The `$resource` service underwent a minor internal refactoring to finally solve a long-standing bug
|
||||
preventing requests from being cancelled using promises. Due to the nature of `$resource`'s
|
||||
configuration, it was not possible to follow the `$http` convention. A new `$cancelRequest()` method
|
||||
was introduced instead.
|
||||
|
||||
Due to [98528be3](https://github.com/angular/angular.js/commit/98528be311b48269ba0e15ba4e3e2ad9b89693a9),
|
||||
using a promise as `timeout` in `$resource` is no longer supported and will log a warning. This is
|
||||
hardly expected to affect the behavior of your application, since a promise as `timeout` didn't work
|
||||
before either, but it will now warn you explicitly when trying to pass one.
|
||||
If you need to be able to cancel pending requests, you can now use the new `$cancelRequest()` that
|
||||
will be available on `$resource` instances.
|
||||
|
||||
|
||||
## ngRoute (`ngView`)
|
||||
|
||||
Due to [983b0598](https://github.com/angular/angular.js/commit/983b0598121a8c5a3a51a30120e114d7e3085d4d),
|
||||
a new property will be available on the scope of the route, allowing easy access to the route's
|
||||
resolved values from the view's template. The default name for this property is `$resolve`. This is
|
||||
a breaking change, only if a `$resolve` property is already available on the scope, in which case
|
||||
the existing property will be hidden or overwritten.
|
||||
To fix this, you should choose a custom name for this property, that does not collide with other
|
||||
properties on the scope, by specifying the `resolveAs` property on the route.
|
||||
|
||||
|
||||
## ngSanitize (`$sanitize`, `linky`)
|
||||
|
||||
The HTML sanitizer has been re-implemented using inert documents, increasing security, fixing some
|
||||
corner-cases that were difficult to handle and reducing its size by about 20% (in terms of loc). In
|
||||
order to make it more secure by default, a couple of breaking changes have been introduced:
|
||||
|
||||
Due to [181fc567](https://github.com/angular/angular.js/commit/181fc567d873df065f1e84af7225deb70a8d2eb9),
|
||||
SVG support in `$sanitize` is now an opt-in feature (i.e. disabled by default), as it could make
|
||||
an application vulnerable to click-hijacking attacks. If your application relies on it, you can
|
||||
still turn it on with `$sanitizeProvider.enableSvg(true)`, but you extra precautions need to be
|
||||
taken in order to keep your application secure. Read the documentation for more information about
|
||||
the dangers and ways to mitigate them.
|
||||
|
||||
Due to [7a668cdd](https://github.com/angular/angular.js/commit/7a668cdd7d08a7016883eb3c671cbcd586223ae8),
|
||||
the `$sanitize` service will now remove instances of the `<use>` tag from the content passed to it.
|
||||
This element is used to import external SVG resources, which is a security risk as the `$sanitize`
|
||||
service does not have access to the resource in order to sanitize it.
|
||||
|
||||
Due to [98c2db7f](https://github.com/angular/angular.js/commit/98c2db7f9c2d078a408576e722407d518c7ee10a),
|
||||
passing a non-string value (other than `undefined` or `null`) through the `linky` filter will throw
|
||||
an error. This is not expected to have any significant impact on applications, since the input was
|
||||
always assumed to be of type 'string', so passing non-string values never worked correctly anyway.
|
||||
The main difference is that now it will fail faster and with a more informative error message.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Migrating from 1.3 to 1.4
|
||||
|
||||
Angular 1.4 fixes major animation issues and introduces a new API for `ngCookies`. Further, there
|
||||
|
||||
@@ -75,9 +75,8 @@ that you break your application to multiple modules like this:
|
||||
* And an application level module which depends on the above modules and contains any
|
||||
initialization code.
|
||||
|
||||
We've also
|
||||
[written a document](http://angularjs.blogspot.com/2014/02/an-angularjs-style-guide-and-best.html)
|
||||
on how we organize large apps at Google.
|
||||
You can find a community
|
||||
[style guide](https://github.com/johnpapa/angular-styleguide) to help yourself when application grows.
|
||||
|
||||
The above is a suggestion. Tailor it to your needs.
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ a few git commands.
|
||||
|
||||
### Install Git
|
||||
|
||||
You can download and install Git from http://git-scm.com/download. Once installed you should have
|
||||
You can download and install Git from http://git-scm.com/download. Once installed, you should have
|
||||
access to the `git` command line tool. The main commands that you will need to use are:
|
||||
|
||||
- `git clone ...` : clone a remote repository onto your local machine
|
||||
@@ -123,7 +123,7 @@ npm --version
|
||||
</a>.
|
||||
</div>
|
||||
|
||||
Once you have Node.js installed on your machine you can download the tool dependencies by running:
|
||||
Once you have Node.js installed on your machine, you can download the tool dependencies by running:
|
||||
|
||||
```
|
||||
npm install
|
||||
@@ -198,7 +198,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.
|
||||
To serve the web app on a different IP address or port, edit the "start" script within package.json.
|
||||
You can use `-a` to set the address and `-p` to set the port.
|
||||
</div>
|
||||
|
||||
@@ -246,6 +246,15 @@ npm run update-webdriver
|
||||
|
||||
*(You should only need to do this once.)*
|
||||
|
||||
You will need to have Java present on your dev machine to allow the Selenium standalone to be started.
|
||||
Check if you already have java installed by opening a terminal/command line window and typing
|
||||
'''
|
||||
java -version
|
||||
'''
|
||||
If java is already installed and exists in the PATH then you will be shown the version installed,
|
||||
if, however you receive a message that "java is not recognized as an internal command or external
|
||||
command" you will need to install [java].
|
||||
|
||||
Since Protractor works by interacting with a running application, we need to start our web server:
|
||||
|
||||
```
|
||||
@@ -280,3 +289,4 @@ Now that you have set up your local machine, let's get started with the tutorial
|
||||
[bower]: http://bower.io/
|
||||
[http-server]: https://github.com/nodeapps/http-server
|
||||
[karma]: https://github.com/karma-runner/karma
|
||||
[java]: https://www.java.com/en/download/help/download_options.xml
|
||||
|
||||
@@ -11,7 +11,7 @@ the AngularJS phonecat app. You will also learn how to start the development ser
|
||||
angular-seed, and run the application in the browser.
|
||||
|
||||
Before you continue, make sure you have set up your development environment and installed all necessary
|
||||
dependencies, as described in {@link tutorial/index#get-started Get Started}.
|
||||
dependencies, as described in {@link index#get-started Get Started}.
|
||||
|
||||
In the `angular-phonecat` directory, run this command:
|
||||
|
||||
|
||||
@@ -132,6 +132,8 @@ The "Angular way" of separating controller from the view, makes it easy to test
|
||||
developed. If our controller is available on the global namespace then we could simply instantiate it
|
||||
with a mock `scope` object:
|
||||
|
||||
__`test/e2e/scenarios.js`:__
|
||||
|
||||
```js
|
||||
describe('PhoneListCtrl', function(){
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ phonecatApp.controller('PhoneListCtrl', function ($scope, $http) {
|
||||
`$http` makes an HTTP GET request to our web server, asking for `phones/phones.json` (the url is
|
||||
relative to our `index.html` file). The server responds by providing the data in the json file.
|
||||
(The response might just as well have been dynamically generated by a backend server. To the
|
||||
browser and our app they both look the same. For the sake of simplicity we used a json file in this
|
||||
browser and our app, they both look the same. For the sake of simplicity, we used a json file in this
|
||||
tutorial.)
|
||||
|
||||
The `$http` service returns a {@link ng.$q promise object} with a `success`
|
||||
@@ -114,7 +114,7 @@ as strings, which will not get minified. There are two ways to provide these inj
|
||||
|
||||
* Create a `$inject` property on the controller function which holds an array of strings.
|
||||
Each string in the array is the name of the service to inject for the corresponding parameter.
|
||||
In our example we would write:
|
||||
In our example, we would write:
|
||||
|
||||
```js
|
||||
function PhoneListCtrl($scope, $http) {...}
|
||||
|
||||
@@ -43,7 +43,7 @@ __`app/index.html`:__
|
||||
...
|
||||
<ul class="phones">
|
||||
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
|
||||
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
|
||||
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}"></a>
|
||||
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
|
||||
<p>{{phone.snippet}}</p>
|
||||
</li>
|
||||
@@ -59,8 +59,8 @@ the element attribute.
|
||||
We also added phone images next to each record using an image tag with the {@link
|
||||
ng.directive:ngSrc ngSrc} directive. That directive prevents the
|
||||
browser from treating the Angular `{{ expression }}` markup literally, and initiating a request to
|
||||
invalid URL `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
||||
specified an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}">`).
|
||||
an invalid URL `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had
|
||||
only specified an attribute binding in a regular `src` attribute (`<img src="{{phone.imageUrl}}">`).
|
||||
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
|
||||
|
||||
|
||||
|
||||
@@ -53,6 +53,18 @@ preconfigured npm to run bower install for us:
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of Angular has been released since you last ran `npm install`, then you may have a
|
||||
problem with the `bower install` due to a conflict between the versions of angular.js that need to
|
||||
be installed. If you get this then simply delete your `app/bower_components` folder before running
|
||||
`npm install`.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Note:** If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
|
||||
## Multiple Views, Routing and Layout Template
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ The name of the starting class is the name of the event that is fired (like `ent
|
||||
The active class name is the same as the starting class's but with an `-active` suffix.
|
||||
This two-class CSS naming convention allows the developer to craft an animation, beginning to end.
|
||||
|
||||
In our example above, elements are expanded from a height of **0** to **120 pixels** when they're added to the
|
||||
In our example above, elements are expanded from a height of **0** to **120 pixels** when they're added to the
|
||||
list and are collapsed back down to **0 pixels** before being removed from the list.
|
||||
There's also a nice fade-in and fade-out effect that occurs at the same time. All of this is handled
|
||||
by the CSS transition declarations at the top of the example code above.
|
||||
@@ -357,10 +357,10 @@ For more on CSS animations, see the
|
||||
## Animating `ngClass` with JavaScript
|
||||
|
||||
Let's add another animation to our application. Switching to our `phone-detail.html` page,
|
||||
we see that we have a nice thumbnail swapper. By clicking on the thumbnails listed on the page,
|
||||
we see that we have a nice thumbnail swapper. By hovering over the thumbnails listed on the page,
|
||||
the profile phone image changes. But how can we change this around to add animations?
|
||||
|
||||
Let's think about it first. Basically, when you click on a thumbnail image, you're changing the
|
||||
Let's think about it first. Basically, when you hover over a thumbnail image, you're changing the
|
||||
state of the profile image to reflect the newly selected thumbnail image.
|
||||
The best way to specify state changes within HTML is to use classes.
|
||||
Much like before, how we used a CSS class to specify an animation, this time the animation will
|
||||
@@ -369,7 +369,7 @@ occur whenever the CSS class itself changes.
|
||||
Whenever a new phone thumbnail is selected, the state changes and the `.active` CSS class is added
|
||||
to the matching profile image and the animation plays.
|
||||
|
||||
Let's get started and tweak our HTML code on the `phone-detail.html` page first. Notice that we
|
||||
Let's get started and tweak our HTML code on the `phone-detail.html` page first. Notice that we
|
||||
have changed the way we display our large image:
|
||||
|
||||
__`app/partials/phone-detail.html`.__
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* using the --for_closure flag.
|
||||
* File generated from CLDR ver. 27.0.1
|
||||
*
|
||||
* This file coveres those locales that are not covered in
|
||||
* This file covers those locales that are not covered in
|
||||
* "numberformatsymbols.js".
|
||||
*
|
||||
* Before checkin, this file could have been manually edited. This is
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ set -e
|
||||
BASE_DIR=`dirname $0`
|
||||
cd $BASE_DIR
|
||||
|
||||
./run-tests.sh
|
||||
npm run test-i18n
|
||||
|
||||
node src/closureSlurper.js
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
PARENT_DIR="$(dirname "$0")"
|
||||
|
||||
../node_modules/.bin/jasmine-node "$PARENT_DIR"/spec/
|
||||
@@ -4,6 +4,7 @@ findLocaleId = closureI18nExtractor.findLocaleId;
|
||||
extractNumberSymbols = closureI18nExtractor.extractNumberSymbols;
|
||||
extractCurrencySymbols = closureI18nExtractor.extractCurrencySymbols;
|
||||
extractDateTimeSymbols = closureI18nExtractor.extractDateTimeSymbols;
|
||||
outputLocale = closureI18nExtractor.outputLocale;
|
||||
|
||||
|
||||
function newTestLocaleInfo() {
|
||||
@@ -72,7 +73,7 @@ describe("findLocaleId", function() {
|
||||
it("should throw an error otherwise", function() {
|
||||
expect(function() {
|
||||
findLocaleId("str", "otherwise")
|
||||
}).toThrow("unknown type in findLocaleId: otherwise");
|
||||
}).toThrowError("unknown type in findLocaleId: otherwise");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -131,7 +132,10 @@ describe("extractCurrencySymbols", function() {
|
||||
].join('\n');
|
||||
|
||||
var localeInfo = {};
|
||||
expect(extractCurrencySymbols(CONTENT)).toEqual({
|
||||
var currencySymbols = extractCurrencySymbols(CONTENT);
|
||||
expect(currencySymbols.GBP).toEqual([2, '£', 'GB£']);
|
||||
expect(currencySymbols.AOA).toEqual([2, 'Kz', 'Kz']);
|
||||
expect(currencySymbols).toEqual({
|
||||
'GBP':[2, '£', 'GB£'],
|
||||
'AOA':[2, 'Kz', 'Kz']
|
||||
});
|
||||
@@ -142,71 +146,71 @@ describe("extractCurrencySymbols", function() {
|
||||
describe("extractDateTimeSymbols", function() {
|
||||
it("should extract date time data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.DateTimeSymbols_fr_CA = {",
|
||||
" ERAS: ['av. J.-C.', 'ap. J.-C.'],",
|
||||
" ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],",
|
||||
" NARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],",
|
||||
" STANDALONENARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',",
|
||||
" 'N', 'D'],",
|
||||
" MONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',",
|
||||
" 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" STANDALONEMONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',",
|
||||
" 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" SHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.',",
|
||||
" 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" STANDALONESHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',",
|
||||
" 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" WEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',",
|
||||
" 'samedi'],",
|
||||
" STANDALONEWEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi',",
|
||||
" 'vendredi', 'samedi'],",
|
||||
" SHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],",
|
||||
" STANDALONESHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.',",
|
||||
" 'sam.'],",
|
||||
" NARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" SHORTQUARTERS: ['T1', 'T2', 'T3', 'T4'],",
|
||||
" QUARTERS: ['1er trimestre', '2e trimestre', '3e trimestre', '4e trimestre'],",
|
||||
" AMPMS: ['AM', 'PM'],",
|
||||
" DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'yyyy-MM-dd', 'yy-MM-dd'],",
|
||||
" TIMEFORMATS: ['HH \\'h\\' mm \\'min\\' ss \\'s\\' zzzz', 'HH:mm:ss z',",
|
||||
" 'HH:mm:ss', 'HH:mm'],",
|
||||
" FIRSTDAYOFWEEK: 6,",
|
||||
" WEEKENDRANGE: [5, 6],",
|
||||
" FIRSTWEEKCUTOFFDAY: 2",
|
||||
"};"
|
||||
"goog.i18n.DateTimeSymbols_fr_CA = {",
|
||||
" ERAS: ['av. J.-C.', 'ap. J.-C.'],",
|
||||
" ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],",
|
||||
" NARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],",
|
||||
" STANDALONENARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',",
|
||||
" 'N', 'D'],",
|
||||
" MONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',",
|
||||
" 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" STANDALONEMONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',",
|
||||
" 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" SHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.',",
|
||||
" 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" STANDALONESHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',",
|
||||
" 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" WEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',",
|
||||
" 'samedi'],",
|
||||
" STANDALONEWEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi',",
|
||||
" 'vendredi', 'samedi'],",
|
||||
" SHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],",
|
||||
" STANDALONESHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.',",
|
||||
" 'sam.'],",
|
||||
" NARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" SHORTQUARTERS: ['T1', 'T2', 'T3', 'T4'],",
|
||||
" QUARTERS: ['1er trimestre', '2e trimestre', '3e trimestre', '4e trimestre'],",
|
||||
" AMPMS: ['AM', 'PM'],",
|
||||
" DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'yyyy-MM-dd', 'yy-MM-dd'],",
|
||||
" TIMEFORMATS: ['HH \\'h\\' mm \\'min\\' ss \\'s\\' zzzz', 'HH:mm:ss z',",
|
||||
" 'HH:mm:ss', 'HH:mm'],",
|
||||
" FIRSTDAYOFWEEK: 6,",
|
||||
" WEEKENDRANGE: [5, 6],",
|
||||
" FIRSTWEEKCUTOFFDAY: 2",
|
||||
"};"
|
||||
].join('\n');
|
||||
var localeInfo = {};
|
||||
var expectedLocaleInfo = {
|
||||
fr_CA: {
|
||||
DATETIME_FORMATS: {
|
||||
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
|
||||
'octobre', 'novembre', 'décembre'],
|
||||
STANDALONEMONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
|
||||
'août', 'septembre', 'octobre', 'novembre', 'décembre'],
|
||||
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
|
||||
'nov.', 'déc.'],
|
||||
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
|
||||
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
WEEKENDRANGE: [5, 6],
|
||||
AMPMS: ['AM', 'PM'],
|
||||
ERAS: ['av. J.-C.', 'ap. J.-C.'],
|
||||
ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],
|
||||
medium: 'yyyy-MM-dd HH:mm:ss',
|
||||
short: 'yy-MM-dd HH:mm',
|
||||
fullDate: 'EEEE d MMMM y',
|
||||
longDate: 'd MMMM y',
|
||||
mediumDate: 'yyyy-MM-dd',
|
||||
shortDate: 'yy-MM-dd',
|
||||
mediumTime: 'HH:mm:ss',
|
||||
shortTime: 'HH:mm'
|
||||
}
|
||||
var localeInfo = {};
|
||||
var expectedLocaleInfo = {
|
||||
fr_CA: {
|
||||
DATETIME_FORMATS: {
|
||||
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
|
||||
'octobre', 'novembre', 'décembre'],
|
||||
STANDALONEMONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
|
||||
'août', 'septembre', 'octobre', 'novembre', 'décembre'],
|
||||
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
|
||||
'nov.', 'déc.'],
|
||||
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
|
||||
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
WEEKENDRANGE: [5, 6],
|
||||
AMPMS: ['AM', 'PM'],
|
||||
ERAS: ['av. J.-C.', 'ap. J.-C.'],
|
||||
ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],
|
||||
medium: 'yyyy-MM-dd HH:mm:ss',
|
||||
short: 'yy-MM-dd HH:mm',
|
||||
fullDate: 'EEEE d MMMM y',
|
||||
longDate: 'd MMMM y',
|
||||
mediumDate: 'yyyy-MM-dd',
|
||||
shortDate: 'yy-MM-dd',
|
||||
mediumTime: 'HH:mm:ss',
|
||||
shortTime: 'HH:mm'
|
||||
}
|
||||
};
|
||||
extractDateTimeSymbols(CONTENT, localeInfo);
|
||||
expect(localeInfo).toEqual(expectedLocaleInfo);
|
||||
})
|
||||
}
|
||||
};
|
||||
extractDateTimeSymbols(CONTENT, localeInfo);
|
||||
expect(localeInfo).toEqual(expectedLocaleInfo);
|
||||
});
|
||||
});
|
||||
|
||||
describe("pluralExtractor", function() {
|
||||
@@ -272,3 +276,10 @@ describe("serializeContent", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("outputLocale", function() {
|
||||
it("should render the correct locale ids", function() {
|
||||
var output = outputLocale(newTestLocaleInfo(), 'fr_CA');
|
||||
expect(output).toContain('"id": "fr-ca"');
|
||||
expect(output).toContain('"localeID": "fr_CA"');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -50,10 +50,10 @@ function extractNumberSymbols(content, localeInfo, currencySymbols) {
|
||||
function extractCurrencySymbols(content) {
|
||||
//eval script in the current context so that we get access to all the symbols
|
||||
eval(content.toString());
|
||||
var currencySymbols = goog.i18n.currency.CurrencyInfo;
|
||||
currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
|
||||
// var currencySymbols = goog.i18n.currency.CurrencyInfo;
|
||||
// currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
|
||||
|
||||
return currencySymbols;
|
||||
return Object.assign({}, goog.i18n.currency.CurrencyInfoTier2, goog.i18n.currency.CurrencyInfo);
|
||||
}
|
||||
|
||||
function extractDateTimeSymbols(content, localeInfo) {
|
||||
@@ -79,7 +79,7 @@ function pluralExtractor(content, localeInfo) {
|
||||
goog.LOCALE = localeIds[i].match(/[^_]+/)[0];
|
||||
try {
|
||||
eval(contentText);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.log("Error in eval(contentText): " + e.stack);
|
||||
}
|
||||
if (!goog.i18n.pluralRules.select) {
|
||||
@@ -133,7 +133,7 @@ function canonicalizeForJsonStringify(unused_key, object) {
|
||||
|
||||
function serializeContent(localeObj) {
|
||||
return JSON.stringify(localeObj, canonicalizeForJsonStringify, ' ')
|
||||
.replace(new RegExp('[\\u007f-\\uffff]', 'g'), function(c) { return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4); })
|
||||
.replace(new RegExp('[\\u007f-\\uffff]', 'g'), function(c) { return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4); })
|
||||
.replace(/"@@|@@"/g, '');
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ function outputLocale(localeInfo, localeID) {
|
||||
if (!localeObj.DATETIME_FORMATS) {
|
||||
localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS;
|
||||
}
|
||||
localeObj.localeID = localeID;
|
||||
localeObj.id = correctedLocaleId(localeID);
|
||||
|
||||
var getDecimals = [
|
||||
@@ -201,10 +202,11 @@ function outputLocale(localeInfo, localeID) {
|
||||
DATETIME_FORMATS: localeObj.DATETIME_FORMATS,
|
||||
NUMBER_FORMATS: localeObj.NUMBER_FORMATS,
|
||||
pluralCat: localeObj.pluralCat,
|
||||
id: localeObj.id
|
||||
id: localeObj.id,
|
||||
localeID: localeID
|
||||
};
|
||||
|
||||
var content = serializeContent(localeInfo[localeID]);
|
||||
var content = serializeContent(localeObj);
|
||||
if (content.indexOf('getVF(') < 0) {
|
||||
getVF = '';
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ var PATTERN_SEP = ';',
|
||||
DIGIT = '#';
|
||||
|
||||
/**
|
||||
* main funciton for parser
|
||||
* main function for parser
|
||||
* @param str {string} pattern to be parsed (e.g. #,##0.###).
|
||||
*/
|
||||
function parsePattern(pattern) {
|
||||
|
||||
@@ -2142,7 +2142,7 @@ queue}</string>
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qr
|
||||
|
||||
\f0\fs22 \cf2 $scope\
|
||||
name='Wold'}</string>
|
||||
name='World'}</string>
|
||||
<key>VerticalPad</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var glob = require("glob");
|
||||
var _ = require('lodash');
|
||||
var files = require('../../angularFiles').files;
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.registerTask('validate-angular-files', function() {
|
||||
var combinedFiles = _.clone(files.angularModules);
|
||||
combinedFiles.ng = files.angularSrc;
|
||||
combinedFiles.angularLoader = files.angularLoader;
|
||||
|
||||
var errorsDetected = false;
|
||||
var directories = [];
|
||||
var detectedFiles = {};
|
||||
|
||||
for (var section in combinedFiles) {
|
||||
var sectionFiles = combinedFiles[section];
|
||||
|
||||
if (section != 'angularLoader') {
|
||||
directories.push('src/' + section);
|
||||
}
|
||||
|
||||
grunt.log.debug('Validating ' + sectionFiles.length + ' files from the "' + section + '" module.');
|
||||
|
||||
sectionFiles.forEach(function(file) {
|
||||
detectedFiles[file] = true;
|
||||
|
||||
if (!fs.existsSync(file)) {
|
||||
grunt.log.error(file + ' does not exist in the local file structure.');
|
||||
errorsDetected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
directories.forEach(function(directory) {
|
||||
glob.sync(directory + '/**/*').forEach(function(filePath) {
|
||||
if (!fs.lstatSync(filePath).isDirectory()) {
|
||||
var fileName = path.basename(filePath);
|
||||
var isHiddenFile = fileName[0] == '.';
|
||||
if (!isHiddenFile && !detectedFiles[filePath]) {
|
||||
grunt.log.error(filePath + ' exists in the local file structure but isn\'t used by any module.');
|
||||
errorsDetected = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (errorsDetected) {
|
||||
throw new Error('Not all files were properly detected in the local file structure.');
|
||||
} else {
|
||||
grunt.log.ok('All files were detected successfully!');
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -11,8 +11,7 @@ set -e
|
||||
# Curl and run this script as part of your .travis.yml before_script section:
|
||||
# before_script:
|
||||
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
|
||||
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.7-linux.tar.gz"
|
||||
CONNECT_URL="https://saucelabs.com/downloads/sc-4.3.13-linux.tar.gz"
|
||||
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
|
||||
CONNECT_DOWNLOAD="sc-4.3.7-linux.tar.gz"
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ var getSnapshotVersion = function() {
|
||||
// last release was a non beta release. Increment the patch level to
|
||||
// indicate the next release that we will be doing.
|
||||
// E.g. last release was 1.3.0, then the snapshot will be
|
||||
// 1.3.1-build.1, which is lesser than 1.3.1 accorind the semver!
|
||||
// 1.3.1-build.1, which is lesser than 1.3.1 according to the semver!
|
||||
|
||||
// If the last release was a beta release we don't update the
|
||||
// beta number by purpose, as otherwise the semver comparison
|
||||
|
||||
+1443
-863
File diff suppressed because it is too large
Load Diff
Generated
+2394
-1478
File diff suppressed because it is too large
Load Diff
+14
-12
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"license": "MIT",
|
||||
"branchVersion": "^1.5.0-rc.0",
|
||||
"branchVersion": "^1.5.0-beta.2",
|
||||
"branchPattern": "1.5.*",
|
||||
"distTag": "beta",
|
||||
"repository": {
|
||||
@@ -16,7 +16,8 @@
|
||||
"scripts": {
|
||||
"preinstall": "node scripts/npm/check-node-modules.js --purge",
|
||||
"postinstall": "node scripts/npm/copy-npm-shrinkwrap.js",
|
||||
"commit": "git-cz"
|
||||
"commit": "git-cz",
|
||||
"test-i18n": "jasmine-node i18n/spec"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-benchpress": "0.x.x",
|
||||
@@ -30,6 +31,7 @@
|
||||
"dgeni": "^0.4.0",
|
||||
"dgeni-packages": "^0.11.0",
|
||||
"event-stream": "~3.1.0",
|
||||
"glob": "^6.0.1",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.6.0",
|
||||
@@ -50,18 +52,18 @@
|
||||
"gulp-sourcemaps": "^1.2.2",
|
||||
"gulp-uglify": "^1.0.1",
|
||||
"gulp-util": "^3.0.1",
|
||||
"jasmine-node": "~1.14.5",
|
||||
"jasmine-node": "^2.0.0",
|
||||
"jasmine-reporters": "~1.0.1",
|
||||
"jshint-stylish": "~1.0.0",
|
||||
"karma": "0.12.32",
|
||||
"karma-browserstack-launcher": "0.1.2",
|
||||
"karma-chrome-launcher": "0.1.5",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
"karma-jasmine": "0.1.5",
|
||||
"karma-junit-reporter": "0.2.2",
|
||||
"karma-ng-scenario": "0.1.0",
|
||||
"karma-sauce-launcher": "0.2.10",
|
||||
"karma-script-launcher": "0.1.0",
|
||||
"karma": "^0.13.19",
|
||||
"karma-browserstack-launcher": "^0.1.8",
|
||||
"karma-chrome-launcher": "^0.2.2",
|
||||
"karma-firefox-launcher": "^0.1.7",
|
||||
"karma-jasmine": "^0.1.6",
|
||||
"karma-junit-reporter": "^0.3.8",
|
||||
"karma-ng-scenario": "^0.1.0",
|
||||
"karma-sauce-launcher": "^0.3.0",
|
||||
"karma-script-launcher": "^0.1.0",
|
||||
"load-grunt-tasks": "~0.6.0",
|
||||
"lodash": "~2.4.1",
|
||||
"marked": "~0.3.0",
|
||||
|
||||
@@ -7,6 +7,8 @@ echo "#################################"
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
scripts/jenkins/set-node-version.sh
|
||||
|
||||
# This is the default set of browsers to use on the CI server unless overridden via env variable
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -19,6 +21,7 @@ rm -f angular.js.size
|
||||
|
||||
|
||||
# BUILD #
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
@@ -4,9 +4,7 @@ echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
ARG_DEFS=()
|
||||
|
||||
function init {
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
@@ -17,14 +15,7 @@ function init {
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
|
||||
if [[ $NO_TEST == "true" ]]; then
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
else
|
||||
./jenkins_build.sh
|
||||
fi
|
||||
|
||||
scripts/jenkins/build.sh
|
||||
cd $SCRIPT_DIR
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@ function init {
|
||||
}
|
||||
|
||||
function build {
|
||||
./set-node-version.sh
|
||||
cd ../..
|
||||
|
||||
npm install -g grunt-cli
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install nvm for this shell
|
||||
source ~/.nvm/nvm.sh
|
||||
|
||||
# Use node.js at 4.2.x
|
||||
nvm install 4.2
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p $LOGS_DIR
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
echo "start_browser_provider"
|
||||
./scripts/travis/start_browser_provider.sh
|
||||
fi
|
||||
|
||||
npm install -g grunt-cli
|
||||
|
||||
if [ $JOB != "ci-checks" ]; then
|
||||
grunt package
|
||||
echo "wait_for_browser_provider"
|
||||
./scripts/travis/wait_for_browser_provider.sh
|
||||
fi
|
||||
@@ -5,7 +5,9 @@ set -e
|
||||
export BROWSER_STACK_ACCESS_KEY=`echo $BROWSER_STACK_ACCESS_KEY | rev`
|
||||
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $JOB = "unit" ]; then
|
||||
if [ $JOB = "ci-checks" ]; then
|
||||
grunt ci-checks
|
||||
elif [ $JOB = "unit" ]; then
|
||||
if [ "$BROWSER_PROVIDER" == "browserstack" ]; then
|
||||
BROWSERS="BS_Chrome,BS_Safari,BS_Firefox,BS_IE_9,BS_IE_10,BS_IE_11,BS_iOS"
|
||||
else
|
||||
@@ -14,7 +16,6 @@ if [ $JOB = "unit" ]; then
|
||||
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers $BROWSERS --reporters dots
|
||||
grunt ci-checks
|
||||
grunt tests:docs --browsers $BROWSERS --reporters dots
|
||||
elif [ $JOB = "docs-e2e" ]; then
|
||||
grunt test:travis-protractor --specs "docs/app/e2e/**/*.scenario.js"
|
||||
@@ -31,5 +32,5 @@ elif [ $JOB = "e2e" ]; then
|
||||
export TARGET_SPECS="test/e2e/tests/**/*.js,$TARGET_SPECS"
|
||||
grunt test:travis-protractor --specs "$TARGET_SPECS"
|
||||
else
|
||||
echo "Unknown job type. Please set JOB=unit or JOB=e2e-*."
|
||||
echo "Unknown job type. Please set JOB=ci-checks, JOB=unit or JOB=e2e-*."
|
||||
fi
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
"jqLiteInheritedData": false,
|
||||
"jqLiteBuildFragment": false,
|
||||
"jqLiteParseHTML": false,
|
||||
"jqLiteWrapNode": false,
|
||||
"getBooleanAttrName": false,
|
||||
"getAliasedAttrName": false,
|
||||
"createEventHandler": false,
|
||||
|
||||
+82
-71
@@ -119,29 +119,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
|
||||
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
||||
var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.lowercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @description Converts the specified string to lowercase.
|
||||
* @param {string} string String to be converted to lowercase.
|
||||
* @returns {string} Lowercased string.
|
||||
*/
|
||||
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.uppercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @description Converts the specified string to uppercase.
|
||||
* @param {string} string String to be converted to uppercase.
|
||||
* @returns {string} Uppercased string.
|
||||
*/
|
||||
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
||||
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
|
||||
|
||||
|
||||
@@ -161,7 +141,7 @@ var manualUppercase = function(s) {
|
||||
|
||||
// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
|
||||
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
|
||||
// with correct but slower alternatives.
|
||||
// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
|
||||
if ('i' !== 'I'.toLowerCase()) {
|
||||
lowercase = manualLowercase;
|
||||
uppercase = manualUppercase;
|
||||
@@ -204,7 +184,7 @@ function isArrayLike(obj) {
|
||||
|
||||
// arrays, strings and jQuery/jqLite objects are array like
|
||||
// * jqLite is either the jQuery or jqLite constructor function
|
||||
// * we have to check the existance of jqLite first as this method is called
|
||||
// * we have to check the existence of jqLite first as this method is called
|
||||
// via the forEach method when constructing the jqLite object in the first place
|
||||
if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
|
||||
|
||||
@@ -215,7 +195,8 @@ function isArrayLike(obj) {
|
||||
// NodeList objects (with `item` method) and
|
||||
// other objects with suitable length characteristics are array-like
|
||||
return isNumber(length) &&
|
||||
(length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
|
||||
(length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,7 +293,7 @@ function forEachSorted(obj, iterator, context) {
|
||||
* @returns {function(*, string)}
|
||||
*/
|
||||
function reverseParams(iteratorFn) {
|
||||
return function(value, key) { iteratorFn(key, value); };
|
||||
return function(value, key) {iteratorFn(key, value);};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -683,6 +664,10 @@ function isTypedArray(value) {
|
||||
return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
|
||||
}
|
||||
|
||||
function isArrayBuffer(obj) {
|
||||
return toString.call(obj) === '[object ArrayBuffer]';
|
||||
}
|
||||
|
||||
|
||||
var trim = function(value) {
|
||||
return isString(value) ? value.trim() : value;
|
||||
@@ -720,7 +705,7 @@ function isElement(node) {
|
||||
* @returns {object} in the form of {key1:true, key2:true, ...}
|
||||
*/
|
||||
function makeMap(str) {
|
||||
var obj = {}, items = str.split(","), i;
|
||||
var obj = {}, items = str.split(','), i;
|
||||
for (i = 0; i < items.length; i++) {
|
||||
obj[items[i]] = true;
|
||||
}
|
||||
@@ -807,7 +792,7 @@ function copy(source, destination) {
|
||||
var stackDest = [];
|
||||
|
||||
if (destination) {
|
||||
if (isTypedArray(destination)) {
|
||||
if (isTypedArray(destination) || isArrayBuffer(destination)) {
|
||||
throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
|
||||
}
|
||||
if (source === destination) {
|
||||
@@ -881,22 +866,10 @@ function copy(source, destination) {
|
||||
}
|
||||
|
||||
var needsRecurse = false;
|
||||
var destination;
|
||||
var destination = copyType(source);
|
||||
|
||||
if (isArray(source)) {
|
||||
destination = [];
|
||||
needsRecurse = true;
|
||||
} else if (isTypedArray(source)) {
|
||||
destination = new source.constructor(source);
|
||||
} else if (isDate(source)) {
|
||||
destination = new Date(source.getTime());
|
||||
} else if (isRegExp(source)) {
|
||||
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
destination.lastIndex = source.lastIndex;
|
||||
} else if (isFunction(source.cloneNode)) {
|
||||
destination = source.cloneNode(true);
|
||||
} else {
|
||||
destination = Object.create(getPrototypeOf(source));
|
||||
if (destination === undefined) {
|
||||
destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
|
||||
needsRecurse = true;
|
||||
}
|
||||
|
||||
@@ -907,6 +880,45 @@ function copy(source, destination) {
|
||||
? copyRecurse(source, destination)
|
||||
: destination;
|
||||
}
|
||||
|
||||
function copyType(source) {
|
||||
switch (toString.call(source)) {
|
||||
case '[object Int8Array]':
|
||||
case '[object Int16Array]':
|
||||
case '[object Int32Array]':
|
||||
case '[object Float32Array]':
|
||||
case '[object Float64Array]':
|
||||
case '[object Uint8Array]':
|
||||
case '[object Uint8ClampedArray]':
|
||||
case '[object Uint16Array]':
|
||||
case '[object Uint32Array]':
|
||||
return new source.constructor(copyElement(source.buffer));
|
||||
|
||||
case '[object ArrayBuffer]':
|
||||
//Support: IE10
|
||||
if (!source.slice) {
|
||||
var copied = new ArrayBuffer(source.byteLength);
|
||||
new Uint8Array(copied).set(new Uint8Array(source));
|
||||
return copied;
|
||||
}
|
||||
return source.slice(0);
|
||||
|
||||
case '[object Boolean]':
|
||||
case '[object Number]':
|
||||
case '[object String]':
|
||||
case '[object Date]':
|
||||
return new source.constructor(source.valueOf());
|
||||
|
||||
case '[object RegExp]':
|
||||
var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
|
||||
re.lastIndex = source.lastIndex;
|
||||
return re;
|
||||
}
|
||||
|
||||
if (isFunction(source.cloneNode)) {
|
||||
return source.cloneNode(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -969,38 +981,37 @@ function equals(o1, o2) {
|
||||
if (o1 === null || o2 === null) return false;
|
||||
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
|
||||
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
|
||||
if (t1 == t2) {
|
||||
if (t1 == 'object') {
|
||||
if (isArray(o1)) {
|
||||
if (!isArray(o2)) return false;
|
||||
if ((length = o1.length) == o2.length) {
|
||||
for (key = 0; key < length; key++) {
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (isDate(o1)) {
|
||||
if (!isDate(o2)) return false;
|
||||
return equals(o1.getTime(), o2.getTime());
|
||||
} else if (isRegExp(o1)) {
|
||||
return isRegExp(o2) ? o1.toString() == o2.toString() : false;
|
||||
} else {
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
|
||||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
|
||||
keySet = createMap();
|
||||
for (key in o1) {
|
||||
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
||||
if (t1 == t2 && t1 == 'object') {
|
||||
if (isArray(o1)) {
|
||||
if (!isArray(o2)) return false;
|
||||
if ((length = o1.length) == o2.length) {
|
||||
for (key = 0; key < length; key++) {
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
keySet[key] = true;
|
||||
}
|
||||
for (key in o2) {
|
||||
if (!(key in keySet) &&
|
||||
key.charAt(0) !== '$' &&
|
||||
isDefined(o2[key]) &&
|
||||
!isFunction(o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (isDate(o1)) {
|
||||
if (!isDate(o2)) return false;
|
||||
return equals(o1.getTime(), o2.getTime());
|
||||
} else if (isRegExp(o1)) {
|
||||
if (!isRegExp(o2)) return false;
|
||||
return o1.toString() == o2.toString();
|
||||
} else {
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
|
||||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
|
||||
keySet = createMap();
|
||||
for (key in o1) {
|
||||
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
keySet[key] = true;
|
||||
}
|
||||
for (key in o2) {
|
||||
if (!(key in keySet) &&
|
||||
key.charAt(0) !== '$' &&
|
||||
isDefined(o2[key]) &&
|
||||
!isFunction(o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1239,7 +1250,7 @@ function startingTag(element) {
|
||||
return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
|
||||
elemHtml.
|
||||
match(/^(<[^>]+>)/)[1].
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
|
||||
} catch (e) {
|
||||
return lowercase(elemHtml);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
$AnchorScrollProvider,
|
||||
$AnimateProvider,
|
||||
$CoreAnimateCssProvider,
|
||||
$$CoreAnimateJsProvider,
|
||||
$$CoreAnimateQueueProvider,
|
||||
$$AnimateRunnerFactoryProvider,
|
||||
$$AnimateAsyncRunFactoryProvider,
|
||||
@@ -218,6 +219,7 @@ function publishExternalAPI(angular) {
|
||||
$anchorScroll: $AnchorScrollProvider,
|
||||
$animate: $AnimateProvider,
|
||||
$animateCss: $CoreAnimateCssProvider,
|
||||
$$animateJs: $$CoreAnimateJsProvider,
|
||||
$$animateQueue: $$CoreAnimateQueueProvider,
|
||||
$$AnimateRunner: $$AnimateRunnerFactoryProvider,
|
||||
$$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, document, undefined) {
|
||||
|
||||
+64
-29
@@ -491,8 +491,20 @@ function annotate(fn, strictDi, name) {
|
||||
*
|
||||
* Register a **service constructor**, which will be invoked with `new` to create the service
|
||||
* instance.
|
||||
* This is short for registering a service where its provider's `$get` property is the service
|
||||
* constructor function that will be used to instantiate the service instance.
|
||||
* This is short for registering a service where its provider's `$get` property is a factory
|
||||
* function that returns an instance instantiated by the injector from the service constructor
|
||||
* function.
|
||||
*
|
||||
* Internally it looks a bit like this:
|
||||
*
|
||||
* ```
|
||||
* {
|
||||
* $get: function() {
|
||||
* return $injector.instantiate(constructor);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* You should use {@link auto.$provide#service $provide.service(class)} if you define your service
|
||||
* as a type/class.
|
||||
@@ -593,7 +605,7 @@ function annotate(fn, strictDi, name) {
|
||||
* @description
|
||||
*
|
||||
* Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
|
||||
* intercepts the creation of a service, allowing it to override or modify the behaviour of the
|
||||
* intercepts the creation of a service, allowing it to override or modify the behavior of the
|
||||
* service. The object returned by the decorator may be the original service, or a new service
|
||||
* object which replaces or wraps and delegates to the original service.
|
||||
*
|
||||
@@ -804,48 +816,71 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function injectionArgs(fn, locals, serviceName) {
|
||||
var args = [],
|
||||
$inject = createInjector.$$annotate(fn, strictDi, serviceName);
|
||||
|
||||
for (var i = 0, length = $inject.length; i < length; i++) {
|
||||
var key = $inject[i];
|
||||
if (typeof key !== 'string') {
|
||||
throw $injectorMinErr('itkn',
|
||||
'Incorrect injection token! Expected service name as string, got {0}', key);
|
||||
}
|
||||
args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
|
||||
getService(key, serviceName));
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function isClass(func) {
|
||||
// IE 9-11 do not support classes and IE9 leaks with the code below.
|
||||
if (msie <= 11) {
|
||||
return false;
|
||||
}
|
||||
// Workaround for MS Edge.
|
||||
// Check https://connect.microsoft.com/IE/Feedback/Details/2211653
|
||||
return typeof func === 'function'
|
||||
&& /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
|
||||
}
|
||||
|
||||
function invoke(fn, self, locals, serviceName) {
|
||||
if (typeof locals === 'string') {
|
||||
serviceName = locals;
|
||||
locals = null;
|
||||
}
|
||||
|
||||
var args = [],
|
||||
$inject = createInjector.$$annotate(fn, strictDi, serviceName),
|
||||
length, i,
|
||||
key;
|
||||
|
||||
for (i = 0, length = $inject.length; i < length; i++) {
|
||||
key = $inject[i];
|
||||
if (typeof key !== 'string') {
|
||||
throw $injectorMinErr('itkn',
|
||||
'Incorrect injection token! Expected service name as string, got {0}', key);
|
||||
}
|
||||
args.push(
|
||||
locals && locals.hasOwnProperty(key)
|
||||
? locals[key]
|
||||
: getService(key, serviceName)
|
||||
);
|
||||
}
|
||||
var args = injectionArgs(fn, locals, serviceName);
|
||||
if (isArray(fn)) {
|
||||
fn = fn[length];
|
||||
fn = fn[fn.length - 1];
|
||||
}
|
||||
|
||||
// http://jsperf.com/angularjs-invoke-apply-vs-switch
|
||||
// #5388
|
||||
return fn.apply(self, args);
|
||||
if (!isClass(fn)) {
|
||||
// http://jsperf.com/angularjs-invoke-apply-vs-switch
|
||||
// #5388
|
||||
return fn.apply(self, args);
|
||||
} else {
|
||||
args.unshift(null);
|
||||
/*jshint -W058 */ // Applying a constructor without immediate parentheses is the point here.
|
||||
return new (Function.prototype.bind.apply(fn, args));
|
||||
/*jshint +W058 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function instantiate(Type, locals, serviceName) {
|
||||
// Check if Type is annotated and use just the given function at n-1 as parameter
|
||||
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
|
||||
// Object creation: http://jsperf.com/create-constructor/2
|
||||
var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
|
||||
var returnedValue = invoke(Type, instance, locals, serviceName);
|
||||
|
||||
return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
|
||||
var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
|
||||
var args = injectionArgs(Type, locals, serviceName);
|
||||
// Empty object at position 0 is ignored for invocation with `new`, but required.
|
||||
args.unshift(null);
|
||||
/*jshint -W058 */ // Applying a constructor without immediate parentheses is the point here.
|
||||
return new (Function.prototype.bind.apply(ctor, args));
|
||||
/*jshint +W058 */
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
invoke: invoke,
|
||||
instantiate: instantiate,
|
||||
|
||||
+12
-7
@@ -254,6 +254,16 @@ function jqLiteParseHTML(html, context) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function jqLiteWrapNode(node, wrapper) {
|
||||
var parent = node.parentNode;
|
||||
|
||||
if (parent) {
|
||||
parent.replaceChild(wrapper, node);
|
||||
}
|
||||
|
||||
wrapper.appendChild(node);
|
||||
}
|
||||
|
||||
|
||||
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
|
||||
var jqLiteContains = Node.prototype.contains || function(arg) {
|
||||
@@ -504,7 +514,7 @@ function jqLiteRemove(element, keepData) {
|
||||
function jqLiteDocumentLoaded(action, win) {
|
||||
win = win || window;
|
||||
if (win.document.readyState === 'complete') {
|
||||
// Force the action to be run async for consistent behaviour
|
||||
// Force the action to be run async for consistent behavior
|
||||
// from the action's point of view
|
||||
// i.e. it will definitely not be in a $apply
|
||||
win.setTimeout(action);
|
||||
@@ -946,12 +956,7 @@ forEach({
|
||||
},
|
||||
|
||||
wrap: function(element, wrapNode) {
|
||||
wrapNode = jqLite(wrapNode).eq(0).clone()[0];
|
||||
var parent = element.parentNode;
|
||||
if (parent) {
|
||||
parent.replaceChild(wrapNode, element);
|
||||
}
|
||||
wrapNode.appendChild(element);
|
||||
jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
|
||||
},
|
||||
|
||||
remove: jqLiteRemove,
|
||||
|
||||
+4
-104
@@ -76,7 +76,7 @@ function setupModuleLoader(window) {
|
||||
* unspecified then the module is being retrieved for further configuration.
|
||||
* @param {Function=} configFn Optional configuration function for the module. Same as
|
||||
* {@link angular.Module#config Module#config()}.
|
||||
* @returns {module} new module with the {@link angular.Module} api.
|
||||
* @returns {angular.Module} new module with the {@link angular.Module} api.
|
||||
*/
|
||||
return function module(name, requires, configFn) {
|
||||
var assertNotHasOwnProperty = function(name, context) {
|
||||
@@ -288,112 +288,12 @@ function setupModuleLoader(window) {
|
||||
* @module ng
|
||||
* @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
|
||||
* @param {Object} options Component definition object (a simplified
|
||||
* {@link ng.$compile#directive-definition-object directive definition object}),
|
||||
* has the following properties (all optional):
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – Controller constructor function that should be
|
||||
* associated with newly created scope or the name of a {@link ng.$compile#-controller-
|
||||
* registered controller} if passed as a string. Empty function by default.
|
||||
* - `controllerAs` – `{string=}` – An identifier name for a reference to the controller.
|
||||
* If present, the controller will be published to scope under the `controllerAs` name.
|
||||
* If not present, this will default to be the same as the component name.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used as the contents of this component.
|
||||
* Empty string by default.
|
||||
*
|
||||
* If `template` is a function, then it is {@link auto.$injector#invoke injected} with
|
||||
* the following locals:
|
||||
*
|
||||
* - `$element` - Current element
|
||||
* - `$attrs` - Current attributes object for the element
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* template that should be used as the contents of this component.
|
||||
*
|
||||
* If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
|
||||
* the following locals:
|
||||
*
|
||||
* - `$element` - Current element
|
||||
* - `$attrs` - Current attributes object for the element
|
||||
* - `bindings` – `{object=}` – Define DOM attribute binding to component properties.
|
||||
* Component properties are always bound to the component controller and not to the scope.
|
||||
* - `transclude` – `{boolean=}` – Whether {@link $compile#transclusion transclusion} is enabled.
|
||||
* Enabled by default.
|
||||
* - `isolate` – `{boolean=}` – Whether the new scope is isolated. Isolated by default.
|
||||
* - `restrict` - `{string=}` - String of subset of {@link ng.$compile#-restrict- EACM} which
|
||||
* restricts the component to specific directive declaration style. If omitted, this defaults to 'E'.
|
||||
* - `$canActivate` – `{function()=}` – TBD.
|
||||
* - `$routeConfig` – `{object=}` – TBD.
|
||||
* {@link ng.$compile#directive-definition-object directive definition object})
|
||||
*
|
||||
* @description
|
||||
* Register a component definition with the compiler. This is short for registering a specific
|
||||
* subset of directives which represents actual UI components in your application. Component
|
||||
* definitions are very simple and do not require the complexity behind defining directives.
|
||||
* Component definitions usually consist only of the template and the controller backing it.
|
||||
* In order to make the definition easier, components enforce best practices like controllerAs
|
||||
* and default behaviors like scope isolation, restrict to elements and allow transclusion.
|
||||
*
|
||||
* Here are a few examples of how you would usually define components:
|
||||
*
|
||||
* ```js
|
||||
* var myMod = angular.module(...);
|
||||
* myMod.component('myComp', {
|
||||
* template: '<div>My name is {{myComp.name}}</div>',
|
||||
* controller: function() {
|
||||
* this.name = 'shahar';
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* myMod.component('myComp', {
|
||||
* template: '<div>My name is {{myComp.name}}</div>',
|
||||
* bindings: {name: '@'}
|
||||
* });
|
||||
*
|
||||
* myMod.component('myComp', {
|
||||
* templateUrl: 'views/my-comp.html',
|
||||
* controller: 'MyCtrl as ctrl',
|
||||
* bindings: {name: '@'}
|
||||
* });
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
||||
* See {@link ng.$compileProvider#component $compileProvider.component()}.
|
||||
*/
|
||||
component: function(name, options) {
|
||||
function factory($injector) {
|
||||
function makeInjectable(fn) {
|
||||
if (angular.isFunction(fn)) {
|
||||
return function(tElement, tAttrs) {
|
||||
return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
|
||||
};
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
var template = (!options.template && !options.templateUrl ? '' : options.template);
|
||||
return {
|
||||
controller: options.controller || function() {},
|
||||
controllerAs: identifierForController(options.controller) || options.controllerAs || name,
|
||||
template: makeInjectable(template),
|
||||
templateUrl: makeInjectable(options.templateUrl),
|
||||
transclude: options.transclude === undefined ? true : options.transclude,
|
||||
scope: options.isolate === false ? true : {},
|
||||
bindToController: options.bindings || {},
|
||||
restrict: options.restrict || 'E'
|
||||
};
|
||||
}
|
||||
|
||||
if (options.$canActivate) {
|
||||
factory.$canActivate = options.$canActivate;
|
||||
}
|
||||
if (options.$routeConfig) {
|
||||
factory.$routeConfig = options.$routeConfig;
|
||||
}
|
||||
factory.$inject = ['$injector'];
|
||||
|
||||
return moduleInstance.directive(name, factory);
|
||||
},
|
||||
component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
'use strict';
|
||||
(function() {
|
||||
function isFunction(value) {return typeof value === 'function';};
|
||||
function isFunction(value) {return typeof value === 'function';};
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2015 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2016 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
|
||||
+24
-7
@@ -53,6 +53,10 @@ function prepareAnimateOptions(options) {
|
||||
: {};
|
||||
}
|
||||
|
||||
var $$CoreAnimateJsProvider = function() {
|
||||
this.$get = function() {};
|
||||
};
|
||||
|
||||
// this is prefixed with Core since it conflicts with
|
||||
// the animateQueueProvider defined in ngAnimate/animateQueue.js
|
||||
var $$CoreAnimateQueueProvider = function() {
|
||||
@@ -325,8 +329,8 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* // remove all the animation event listeners listening for `enter` on the given element and its children
|
||||
* $animate.off('enter', container);
|
||||
*
|
||||
* // remove the event listener function provided by `listenerFn` that is set
|
||||
* // to listen for `enter` on the given `element` as well as its children
|
||||
* // remove the event listener function provided by `callback` that is set
|
||||
* // to listen for `enter` on the given `container` as well as its children
|
||||
* $animate.off('enter', container, callback);
|
||||
* ```
|
||||
*
|
||||
@@ -548,17 +552,30 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* @kind function
|
||||
*
|
||||
* @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
|
||||
* If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
|
||||
* on the provided styles. For example, if a transition animation is set for the given className then the provided from and
|
||||
* to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
|
||||
* will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
|
||||
* If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
|
||||
* on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
|
||||
* `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
|
||||
* style in `to`, the style in `from` is applied immediately, and no animation is run.
|
||||
* If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
|
||||
* method (or as part of the `options` parameter):
|
||||
*
|
||||
* ```js
|
||||
* ngModule.animation('.my-inline-animation', function() {
|
||||
* return {
|
||||
* animate : function(element, from, to, done, options) {
|
||||
* //animation
|
||||
* done();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param {DOMElement} element the element which the CSS styles will be applied to
|
||||
* @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
|
||||
* @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
|
||||
* @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
|
||||
* this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
|
||||
* (Note that if no animation is detected then this value will not be appplied to the element.)
|
||||
* (Note that if no animation is detected then this value will not be applied to the element.)
|
||||
* @param {object=} options an optional collection of options/styles that will be applied to the element
|
||||
*
|
||||
* @return {Promise} the animation callback promise
|
||||
|
||||
@@ -15,10 +15,14 @@ var $CoreAnimateCssProvider = function() {
|
||||
this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
|
||||
|
||||
return function(element, initialOptions) {
|
||||
// we always make a copy of the options since
|
||||
// there should never be any side effects on
|
||||
// the input data when running `$animateCss`.
|
||||
var options = copy(initialOptions);
|
||||
// all of the animation functions should create
|
||||
// a copy of the options data, however, if a
|
||||
// parent service has already created a copy then
|
||||
// we should stick to using that
|
||||
var options = initialOptions || {};
|
||||
if (!options.$$prepared) {
|
||||
options = copy(options);
|
||||
}
|
||||
|
||||
// there is no point in applying the styles since
|
||||
// there is no animation that goes on at all in
|
||||
|
||||
+19
-4
@@ -28,8 +28,8 @@ var $$AnimateAsyncRunFactoryProvider = function() {
|
||||
};
|
||||
|
||||
var $$AnimateRunnerFactoryProvider = function() {
|
||||
this.$get = ['$q', '$sniffer', '$$animateAsyncRun',
|
||||
function($q, $sniffer, $$animateAsyncRun) {
|
||||
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
|
||||
function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
|
||||
|
||||
var INITIAL_STATE = 0;
|
||||
var DONE_PENDING_STATE = 1;
|
||||
@@ -74,8 +74,23 @@ var $$AnimateRunnerFactoryProvider = function() {
|
||||
function AnimateRunner(host) {
|
||||
this.setHost(host);
|
||||
|
||||
var rafTick = $$animateAsyncRun();
|
||||
var timeoutTick = function(fn) {
|
||||
$timeout(fn, 0, false);
|
||||
};
|
||||
|
||||
this._doneCallbacks = [];
|
||||
this._runInAnimationFrame = $$animateAsyncRun();
|
||||
this._tick = function(fn) {
|
||||
var doc = $document[0];
|
||||
|
||||
// the document may not be ready or attached
|
||||
// to the module for some internal tests
|
||||
if (doc && doc.hidden) {
|
||||
timeoutTick(fn);
|
||||
} else {
|
||||
rafTick(fn);
|
||||
}
|
||||
};
|
||||
this._state = 0;
|
||||
}
|
||||
|
||||
@@ -148,7 +163,7 @@ var $$AnimateRunnerFactoryProvider = function() {
|
||||
var self = this;
|
||||
if (self._state === INITIAL_STATE) {
|
||||
self._state = DONE_PENDING_STATE;
|
||||
self._runInAnimationFrame(function() {
|
||||
self._tick(function() {
|
||||
self._resolve(response);
|
||||
});
|
||||
}
|
||||
|
||||
+353
-38
@@ -128,7 +128,7 @@
|
||||
* When this property is set to true, the HTML compiler will collect DOM nodes between
|
||||
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
|
||||
* together as the directive elements. It is recommended that this feature be used on directives
|
||||
* which are not strictly behavioural (such as {@link ngClick}), and which
|
||||
* which are not strictly behavioral (such as {@link ngClick}), and which
|
||||
* do not manipulate or replace child nodes (such as {@link ngInclude}).
|
||||
*
|
||||
* #### `priority`
|
||||
@@ -212,9 +212,32 @@
|
||||
*
|
||||
*
|
||||
* #### `bindToController`
|
||||
* When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
|
||||
* allow a component to have its properties bound to the controller, rather than to scope. When the controller
|
||||
* is instantiated, the initial values of the isolate scope bindings are already available.
|
||||
* This property is used to bind scope properties directly to the controller. It can be either
|
||||
* `true` or an object hash with the same format as the `scope` property. Additionally, a controller
|
||||
* alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
|
||||
* definition: `controller: 'myCtrl as myAlias'`.
|
||||
*
|
||||
* When an isolate scope is used for a directive (see above), `bindToController: true` will
|
||||
* allow a component to have its properties bound to the controller, rather than to scope.
|
||||
*
|
||||
* After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
|
||||
* properties. You can access these bindings once they have been initialized by providing a controller method called
|
||||
* `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
|
||||
* initialized.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Deprecation warning:** although bindings for non-ES6 class controllers are currently
|
||||
* bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
|
||||
* code that relies upon bindings inside a `$onInit` method on the controller, instead.
|
||||
* </div>
|
||||
*
|
||||
* It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
|
||||
* This will set up the scope bindings to the controller directly. Note that `scope` can still be used
|
||||
* to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
|
||||
* scope (useful for component directives).
|
||||
*
|
||||
* If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
|
||||
*
|
||||
*
|
||||
* #### `controller`
|
||||
* Controller constructor function. The controller is instantiated before the
|
||||
@@ -242,12 +265,29 @@
|
||||
* The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
|
||||
* `true` if the specified slot contains content (i.e. one or more DOM nodes).
|
||||
*
|
||||
* The controller can provide the following methods that act as life-cycle hooks:
|
||||
* * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
|
||||
* had their bindings initialized (and before the pre & post linking functions for the directives on
|
||||
* this element). This is a good place to put initialization code for your controller.
|
||||
*
|
||||
* #### `require`
|
||||
* Require another directive and inject its controller as the fourth argument to the linking function. The
|
||||
* `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
|
||||
* injected argument will be an array in corresponding order. If no such directive can be
|
||||
* found, or if the directive does not have a controller, then an error is raised (unless no link function
|
||||
* is specified, in which case error checking is skipped). The name can be prefixed with:
|
||||
* `require` property can be a string, an array or an object:
|
||||
* * a **string** containing the name of the directive to pass to the linking function
|
||||
* * an **array** containing the names of directives to pass to the linking function. The argument passed to the
|
||||
* linking function will be an array of controllers in the same order as the names in the `require` property
|
||||
* * an **object** whose property values are the names of the directives to pass to the linking function. The argument
|
||||
* passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
|
||||
* controllers.
|
||||
*
|
||||
* If the `require` property is an object and `bindToController` is truthy, then the required controllers are
|
||||
* bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
|
||||
* have been constructed but before `$onInit` is called.
|
||||
* See the {@link $compileProvider#component} helper for an example of how this can be used.
|
||||
*
|
||||
* If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
|
||||
* raised (unless no link function is specified and the required controllers are not being bound to the directive
|
||||
* controller, in which case error checking is skipped). The name can be prefixed with:
|
||||
*
|
||||
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
|
||||
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
|
||||
@@ -517,7 +557,7 @@
|
||||
* content and the `scope` is the newly created transclusion scope, to which the clone is bound.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
|
||||
* **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
|
||||
* since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
|
||||
* </div>
|
||||
*
|
||||
@@ -549,7 +589,7 @@
|
||||
* </div>
|
||||
*
|
||||
* The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
|
||||
* automatically destroy their transluded clones as necessary so you do not need to worry about this if
|
||||
* automatically destroy their transcluded clones as necessary so you do not need to worry about this if
|
||||
* you are simply using {@link ngTransclude} to inject the transclusion into your directive.
|
||||
*
|
||||
*
|
||||
@@ -574,19 +614,19 @@
|
||||
*
|
||||
* The `$parent` scope hierarchy will look like this:
|
||||
*
|
||||
* ```
|
||||
* - $rootScope
|
||||
* - isolate
|
||||
* - transclusion
|
||||
* ```
|
||||
```
|
||||
- $rootScope
|
||||
- isolate
|
||||
- transclusion
|
||||
```
|
||||
*
|
||||
* but the scopes will inherit prototypically from different scopes to their `$parent`.
|
||||
*
|
||||
* ```
|
||||
* - $rootScope
|
||||
* - transclusion
|
||||
* - isolate
|
||||
* ```
|
||||
```
|
||||
- $rootScope
|
||||
- transclusion
|
||||
- isolate
|
||||
```
|
||||
*
|
||||
*
|
||||
* ### Attributes
|
||||
@@ -718,8 +758,15 @@
|
||||
* directives; if given, it will be passed through to the link functions of
|
||||
* directives found in `element` during compilation.
|
||||
* * `transcludeControllers` - an object hash with keys that map controller names
|
||||
* to controller instances; if given, it will make the controllers
|
||||
* available to directives.
|
||||
* to a hash with the key `instance`, which maps to the controller instance;
|
||||
* if given, it will make the controllers available to directives on the compileNode:
|
||||
* ```
|
||||
* {
|
||||
* parent: {
|
||||
* instance: parentControllerInstance
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
|
||||
* the cloned elements; only needed for transcludes that are allowed to contain non html
|
||||
* elements (e.g. SVG elements). See also the directive.controller property.
|
||||
@@ -867,8 +914,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
|
||||
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
|
||||
* names and the values are the factories.
|
||||
* @param {Function|Array} directiveFactory An injectable directive factory function. See
|
||||
* {@link guide/directive} for more info.
|
||||
* @param {Function|Array} directiveFactory An injectable directive factory function. See the
|
||||
* {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
|
||||
* @returns {ng.$compileProvider} Self for chaining.
|
||||
*/
|
||||
this.directive = function registerDirective(name, directiveFactory) {
|
||||
@@ -915,6 +962,242 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $compileProvider#component
|
||||
* @module ng
|
||||
* @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
|
||||
* @param {Object} options Component definition object (a simplified
|
||||
* {@link ng.$compile#directive-definition-object directive definition object}),
|
||||
* with the following properties (all optional):
|
||||
*
|
||||
* - `controller` – `{(string|function()=}` – controller constructor function that should be
|
||||
* associated with newly created scope or the name of a {@link ng.$compile#-controller-
|
||||
* registered controller} if passed as a string. An empty `noop` function by default.
|
||||
* - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
|
||||
* If present, the controller will be published to scope under the `controllerAs` name.
|
||||
* If not present, this will default to be `$ctrl`.
|
||||
* - `template` – `{string=|function()=}` – html template as a string or a function that
|
||||
* returns an html template as a string which should be used as the contents of this component.
|
||||
* Empty string by default.
|
||||
*
|
||||
* If `template` is a function, then it is {@link auto.$injector#invoke injected} with
|
||||
* the following locals:
|
||||
*
|
||||
* - `$element` - Current element
|
||||
* - `$attrs` - Current attributes object for the element
|
||||
*
|
||||
* - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
|
||||
* template that should be used as the contents of this component.
|
||||
*
|
||||
* If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
|
||||
* the following locals:
|
||||
*
|
||||
* - `$element` - Current element
|
||||
* - `$attrs` - Current attributes object for the element
|
||||
*
|
||||
* - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
|
||||
* Component properties are always bound to the component controller and not to the scope.
|
||||
* See {@link ng.$compile#-bindtocontroller- `bindToController`}.
|
||||
* - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
|
||||
* Disabled by default.
|
||||
* - `$...` – `{function()=}` – additional annotations to provide to the directive factory function.
|
||||
*
|
||||
* @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
|
||||
* @description
|
||||
* Register a **component definition** with the compiler. This is a shorthand for registering a special
|
||||
* type of directive, which represents a self-contained UI component in your application. Such components
|
||||
* are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
|
||||
*
|
||||
* Component definitions are very simple and do not require as much configuration as defining general
|
||||
* directives. Component definitions usually consist only of a template and a controller backing it.
|
||||
*
|
||||
* In order to make the definition easier, components enforce best practices like use of `controllerAs`,
|
||||
* `bindToController`. They always have **isolate scope** and are restricted to elements.
|
||||
*
|
||||
* Here are a few examples of how you would usually define components:
|
||||
*
|
||||
* ```js
|
||||
* var myMod = angular.module(...);
|
||||
* myMod.component('myComp', {
|
||||
* template: '<div>My name is {{$ctrl.name}}</div>',
|
||||
* controller: function() {
|
||||
* this.name = 'shahar';
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* myMod.component('myComp', {
|
||||
* template: '<div>My name is {{$ctrl.name}}</div>',
|
||||
* bindings: {name: '@'}
|
||||
* });
|
||||
*
|
||||
* myMod.component('myComp', {
|
||||
* templateUrl: 'views/my-comp.html',
|
||||
* controller: 'MyCtrl as ctrl',
|
||||
* bindings: {name: '@'}
|
||||
* });
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* ### Intercomponent Communication
|
||||
* Directives can require the controllers of other directives to enable communication
|
||||
* between the directives. This can be achieved in a component by providing an
|
||||
* object mapping for the `require` property. Here is the tab pane example built
|
||||
* from components...
|
||||
*
|
||||
* <example module="docsTabsExample">
|
||||
* <file name="script.js">
|
||||
* angular.module('docsTabsExample', [])
|
||||
* .component('myTabs', {
|
||||
* transclude: true,
|
||||
* controller: function() {
|
||||
* var panes = this.panes = [];
|
||||
*
|
||||
* this.select = function(pane) {
|
||||
* angular.forEach(panes, function(pane) {
|
||||
* pane.selected = false;
|
||||
* });
|
||||
* pane.selected = true;
|
||||
* };
|
||||
*
|
||||
* this.addPane = function(pane) {
|
||||
* if (panes.length === 0) {
|
||||
* this.select(pane);
|
||||
* }
|
||||
* panes.push(pane);
|
||||
* };
|
||||
* },
|
||||
* templateUrl: 'my-tabs.html'
|
||||
* })
|
||||
* .component('myPane', {
|
||||
* transclude: true,
|
||||
* require: {tabsCtrl: '^myTabs'},
|
||||
* bindings: {
|
||||
* title: '@'
|
||||
* },
|
||||
* controller: function() {
|
||||
* this.$onInit = function() {
|
||||
* this.tabsCtrl.addPane(this);
|
||||
* console.log(this);
|
||||
* };
|
||||
* },
|
||||
* templateUrl: 'my-pane.html'
|
||||
* });
|
||||
* </file>
|
||||
* <file name="index.html">
|
||||
* <my-tabs>
|
||||
* <my-pane title="Hello">
|
||||
* <h4>Hello</h4>
|
||||
* <p>Lorem ipsum dolor sit amet</p>
|
||||
* </my-pane>
|
||||
* <my-pane title="World">
|
||||
* <h4>World</h4>
|
||||
* <em>Mauris elementum elementum enim at suscipit.</em>
|
||||
* <p><a href ng-click="i = i + 1">counter: {{i || 0}}</a></p>
|
||||
* </my-pane>
|
||||
* </my-tabs>
|
||||
* </file>
|
||||
* <file name="my-tabs.html">
|
||||
* <div class="tabbable">
|
||||
* <ul class="nav nav-tabs">
|
||||
* <li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">
|
||||
* <a href="" ng-click="$ctrl.select(pane)">{{pane.title}}</a>
|
||||
* </li>
|
||||
* </ul>
|
||||
* <div class="tab-content" ng-transclude></div>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="my-pane.html">
|
||||
* <div class="tab-pane" ng-show="$ctrl.selected" ng-transclude></div>
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
*
|
||||
* <br />
|
||||
* Components are also useful as route templates (e.g. when using
|
||||
* {@link ngRoute ngRoute}):
|
||||
*
|
||||
* ```js
|
||||
* var myMod = angular.module('myMod', ['ngRoute']);
|
||||
*
|
||||
* myMod.component('home', {
|
||||
* template: '<h1>Home</h1><p>Hello, {{ home.user.name }} !</p>',
|
||||
* controller: function() {
|
||||
* this.user = {name: 'world'};
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* myMod.config(function($routeProvider) {
|
||||
* $routeProvider.when('/', {
|
||||
* template: '<home></home>'
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* <br />
|
||||
* When using {@link ngRoute.$routeProvider $routeProvider}, you can often avoid some
|
||||
* boilerplate, by assigning the resolved dependencies directly on the route scope:
|
||||
*
|
||||
* ```js
|
||||
* var myMod = angular.module('myMod', ['ngRoute']);
|
||||
*
|
||||
* myMod.component('home', {
|
||||
* template: '<h1>Home</h1><p>Hello, {{ home.user.name }} !</p>',
|
||||
* bindings: {user: '='}
|
||||
* });
|
||||
*
|
||||
* myMod.config(function($routeProvider) {
|
||||
* $routeProvider.when('/', {
|
||||
* template: '<home user="$resolve.user"></home>',
|
||||
* resolve: {user: function($http) { return $http.get('...'); }}
|
||||
* });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* <br />
|
||||
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
||||
*/
|
||||
this.component = function registerComponent(name, options) {
|
||||
var controller = options.controller || function() {};
|
||||
|
||||
function factory($injector) {
|
||||
function makeInjectable(fn) {
|
||||
if (isFunction(fn) || isArray(fn)) {
|
||||
return function(tElement, tAttrs) {
|
||||
return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
|
||||
};
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
var template = (!options.template && !options.templateUrl ? '' : options.template);
|
||||
return {
|
||||
controller: controller,
|
||||
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
|
||||
template: makeInjectable(template),
|
||||
templateUrl: makeInjectable(options.templateUrl),
|
||||
transclude: options.transclude,
|
||||
scope: {},
|
||||
bindToController: options.bindings || {},
|
||||
restrict: 'E',
|
||||
require: options.require
|
||||
};
|
||||
}
|
||||
|
||||
// Copy any annotation properties (starting with $) over to the factory function
|
||||
// These could be used by libraries such as the new component router
|
||||
forEach(options, function(val, key) {
|
||||
if (key.charAt(0) === '$') {
|
||||
factory[key] = val;
|
||||
}
|
||||
});
|
||||
|
||||
factory.$inject = ['$injector'];
|
||||
|
||||
return this.directive(name, factory);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -1008,9 +1291,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
this.$get = [
|
||||
'$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
|
||||
'$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
|
||||
'$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
|
||||
function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
|
||||
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
|
||||
$controller, $rootScope, $sce, $animate, $$sanitizeUri) {
|
||||
|
||||
var SIMPLE_ATTR_NAME = /^\w/;
|
||||
var specialAttrHolder = document.createElement('div');
|
||||
@@ -1228,7 +1511,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
* @param {string} key Normalized key. (ie ngAttribute) .
|
||||
* @param {function(interpolatedValue)} fn Function that will be called whenever
|
||||
the interpolated value of the attribute changes.
|
||||
* See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
|
||||
* See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
|
||||
* guide} for more info.
|
||||
* @returns {function()} Returns a deregistration function for this observer.
|
||||
*/
|
||||
$observe: function(key, fn) {
|
||||
@@ -1275,7 +1559,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
var startSymbol = $interpolate.startSymbol(),
|
||||
endSymbol = $interpolate.endSymbol(),
|
||||
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
|
||||
denormalizeTemplate = (startSymbol == '{{' && endSymbol == '}}')
|
||||
? identity
|
||||
: function denormalizeTemplate(template) {
|
||||
return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
|
||||
@@ -1319,13 +1603,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
// modify it.
|
||||
$compileNodes = jqLite($compileNodes);
|
||||
}
|
||||
|
||||
var NOT_EMPTY = /\S+/;
|
||||
|
||||
// We can not compile top level text elements since text nodes can be merged and we will
|
||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||
forEach($compileNodes, function(node, index) {
|
||||
if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */) {
|
||||
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
||||
for (var i = 0, len = $compileNodes.length; i < len; i++) {
|
||||
var domNode = $compileNodes[i];
|
||||
|
||||
if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
|
||||
jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var compositeLinkFn =
|
||||
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
@@ -1396,7 +1686,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
if (!node) {
|
||||
return 'html';
|
||||
} else {
|
||||
return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
|
||||
return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2105,6 +2395,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
for (var i = 0, ii = require.length; i < ii; i++) {
|
||||
value[i] = getControllers(directiveName, require[i], $element, elementControllers);
|
||||
}
|
||||
} else if (isObject(require)) {
|
||||
value = {};
|
||||
forEach(require, function(controller, property) {
|
||||
value[property] = getControllers(directiveName, controller, $element, elementControllers);
|
||||
});
|
||||
}
|
||||
|
||||
return value || null;
|
||||
@@ -2142,7 +2437,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
|
||||
var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
|
||||
var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
|
||||
attrs, removeScopeBindingWatches, removeControllerBindingWatches;
|
||||
|
||||
if (compileNode === linkNode) {
|
||||
@@ -2213,6 +2508,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
}
|
||||
|
||||
// Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
|
||||
forEach(controllerDirectives, function(controllerDirective, name) {
|
||||
var require = controllerDirective.require;
|
||||
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
|
||||
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger the `$onInit` method on all controllers that have one
|
||||
forEach(elementControllers, function(controller) {
|
||||
if (isFunction(controller.instance.$onInit)) {
|
||||
controller.instance.$onInit();
|
||||
}
|
||||
});
|
||||
|
||||
// PRELINKING
|
||||
for (i = 0, ii = preLinkFns.length; i < ii; i++) {
|
||||
linkFn = preLinkFns[i];
|
||||
@@ -2781,10 +3091,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
});
|
||||
attrs.$$observers[attrName].$$scope = scope;
|
||||
if (isString(attrs[attrName])) {
|
||||
lastValue = attrs[attrName];
|
||||
if (isString(lastValue)) {
|
||||
// If the attribute has been provided then we trigger an interpolation to ensure
|
||||
// the value is there for use in the link fn
|
||||
destination[scopeName] = $interpolate(attrs[attrName])(scope);
|
||||
destination[scopeName] = $interpolate(lastValue)(scope);
|
||||
} else if (isBoolean(lastValue)) {
|
||||
// If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
|
||||
// the value to boolean rather than a string, so we special case this situation
|
||||
destination[scopeName] = lastValue;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2805,8 +3120,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
// reset the change, or we will throw this exception on every $digest
|
||||
lastValue = destination[scopeName] = parentGet(scope);
|
||||
throw $compileMinErr('nonassign',
|
||||
"Expression '{0}' used with directive '{1}' is non-assignable!",
|
||||
attrs[attrName], directive.name);
|
||||
"Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
|
||||
attrs[attrName], attrName, directive.name);
|
||||
};
|
||||
lastValue = destination[scopeName] = parentGet(scope);
|
||||
var parentValueWatch = function parentValueWatch(parentValue) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var $controllerMinErr = minErr('$controller');
|
||||
|
||||
|
||||
var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
|
||||
var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
|
||||
function identifierForController(controller, ident) {
|
||||
if (ident && isString(ident)) return ident;
|
||||
if (isString(controller)) {
|
||||
|
||||
+20
-43
@@ -163,20 +163,7 @@
|
||||
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
||||
* attribute. The following example would make the button enabled on Chrome/Firefox
|
||||
* but not on older IEs:
|
||||
*
|
||||
* ```html
|
||||
* <!-- See below for an example of ng-disabled being used correctly -->
|
||||
* <div ng-init="isDisabled = false">
|
||||
* <button disabled="{{isDisabled}}">Disabled</button>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* This is because the HTML specification does not require browsers to preserve the values of
|
||||
* boolean attributes such as `disabled` (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
@@ -211,15 +198,9 @@
|
||||
* 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`?
|
||||
* A special directive is necessary because we cannot use interpolation inside the `checked`
|
||||
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
||||
*
|
||||
* 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
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngChecked` directive solves this problem for the `checked` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
@@ -248,13 +229,12 @@
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as readonly. (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngReadonly` directive solves this problem for the `readonly` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `readOnly`
|
||||
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
@@ -283,13 +263,11 @@
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as selected. (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngSelected` directive solves this problem for the `selected` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `selected`
|
||||
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
@@ -321,13 +299,12 @@
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* The HTML specification does not require browsers to preserve the values of boolean attributes
|
||||
* such as open. (Their presence means true and their absence means false.)
|
||||
* If we put an Angular interpolation expression into such an attribute then the
|
||||
* binding information would be lost when the browser removes the attribute.
|
||||
* The `ngOpen` directive solves this problem for the `open` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `open`
|
||||
* attribute. See the {@link guide/interpolation interpolation guide} for more info.
|
||||
*
|
||||
* @example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
|
||||
@@ -127,7 +127,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
*
|
||||
* However, if the method is used programmatically, for example by adding dynamically created controls,
|
||||
* or controls that have been previously removed without destroying their corresponding DOM element,
|
||||
* it's the developers responsiblity to make sure the current state propagates to the parent form.
|
||||
* it's the developers responsibility to make sure the current state propagates to the parent form.
|
||||
*
|
||||
* For example, if an input control is added that is already `$dirty` and has `$error` properties,
|
||||
* calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
|
||||
@@ -337,13 +337,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
*
|
||||
* In Angular, forms can be nested. This means that the outer form is valid when all of the child
|
||||
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
|
||||
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
|
||||
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
|
||||
* using Angular validation directives in forms that are dynamically generated using the
|
||||
* {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
|
||||
* attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
|
||||
* `ngForm` directive and nest these in an outer `form` element.
|
||||
*
|
||||
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
|
||||
* `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
|
||||
* of controls needs to be determined.
|
||||
*
|
||||
* # CSS classes
|
||||
* - `ng-valid` is set if the form is valid.
|
||||
|
||||
@@ -12,7 +12,18 @@
|
||||
// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
|
||||
var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
|
||||
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
|
||||
var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/[\]$'()*,;~]*)?$/;
|
||||
// Note: We are being more lenient, because browsers are too.
|
||||
// 1. Scheme
|
||||
// 2. Slashes
|
||||
// 3. Username
|
||||
// 4. Password
|
||||
// 5. Hostname
|
||||
// 6. Port
|
||||
// 7. Path
|
||||
// 8. Query
|
||||
// 9. Fragment
|
||||
// 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
|
||||
var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
|
||||
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
|
||||
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
|
||||
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
*
|
||||
* * no-inline-style: this stops Angular from injecting CSS styles into the DOM
|
||||
*
|
||||
* * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
|
||||
* * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
|
||||
*
|
||||
* You can use these values in the following combinations:
|
||||
*
|
||||
@@ -64,7 +64,7 @@
|
||||
* inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
|
||||
*
|
||||
* * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
|
||||
* run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
|
||||
* run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
|
||||
*
|
||||
* * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
|
||||
* styles nor use eval, which is the same as an empty: ng-csp.
|
||||
|
||||
@@ -232,6 +232,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
//set the 2nd param to true to ignore the template request error so that the inner
|
||||
//contents and scope can be cleaned up.
|
||||
$templateRequest(src, true).then(function(response) {
|
||||
if (scope.$$destroyed) return;
|
||||
|
||||
if (thisChangeId !== changeCounter) return;
|
||||
var newScope = scope.$new();
|
||||
ctrl.template = response;
|
||||
@@ -253,6 +255,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
|
||||
currentScope.$emit('$includeContentLoaded', src);
|
||||
scope.$eval(onloadExp);
|
||||
}, function() {
|
||||
if (scope.$$destroyed) return;
|
||||
|
||||
if (thisChangeId === changeCounter) {
|
||||
cleanupLastIncludeContent();
|
||||
scope.$emit('$includeContentError', src);
|
||||
@@ -281,7 +285,7 @@ var ngIncludeFillContentDirective = ['$compile',
|
||||
priority: -400,
|
||||
require: 'ngInclude',
|
||||
link: function(scope, $element, $attr, ctrl) {
|
||||
if (/SVG/.test($element[0].toString())) {
|
||||
if (toString.call($element[0]).match(/SVG/)) {
|
||||
// WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
|
||||
// support innerHTML, so detect this here and try to generate the contents
|
||||
// specially.
|
||||
|
||||
@@ -638,7 +638,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
forEach(ctrl.$asyncValidators, function(validator, name) {
|
||||
var promise = validator(modelValue, viewValue);
|
||||
if (!isPromiseLike(promise)) {
|
||||
throw ngModelMinErr("$asyncValidators",
|
||||
throw ngModelMinErr('nopromise',
|
||||
"Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
|
||||
}
|
||||
setValidity(name, undefined);
|
||||
@@ -793,7 +793,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* However, custom controls might also pass objects to this method. In this case, we should make
|
||||
* a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
|
||||
* perform a deep watch of objects, it only looks for a change of identity. If you only change
|
||||
* the property of the object then ngModel will not realise that the object has changed and
|
||||
* the property of the object then ngModel will not realize that the object has changed and
|
||||
* will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
|
||||
* not change properties of the copy once it has been passed to `$setViewValue`.
|
||||
* Otherwise you may cause the model value on the scope to change incorrectly.
|
||||
@@ -937,6 +937,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* - {@link ng.directive:select select}
|
||||
* - {@link ng.directive:textarea textarea}
|
||||
*
|
||||
* # Complex Models (objects or collections)
|
||||
*
|
||||
* By default, `ngModel` watches the model by reference, not value. This is important to know when
|
||||
* binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
|
||||
* object or collection change, `ngModel` will not be notified and so the input will not be re-rendered.
|
||||
*
|
||||
* The model must be assigned an entirely new object or collection before a re-rendering will occur.
|
||||
*
|
||||
* Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
|
||||
* - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
|
||||
* if the select is given the `multiple` attribute.
|
||||
*
|
||||
* The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
|
||||
* first level of the object (or only changing the properties of an item in the collection if it's an array) will still
|
||||
* not trigger a re-rendering of the model.
|
||||
*
|
||||
* # CSS classes
|
||||
* The following CSS classes are added and removed on the associated input/select/textarea element
|
||||
* depending on the validity of the model.
|
||||
|
||||
@@ -643,7 +643,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
(current === emptyOption_ ||
|
||||
current === unknownOption_ ||
|
||||
current.nodeType === NODE_TYPE_COMMENT ||
|
||||
current.value === '')) {
|
||||
(nodeName_(current) === 'option' && current.value === ''))) {
|
||||
current = current.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
|
||||
}
|
||||
|
||||
// If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
|
||||
// In JS `NaN !== NaN`, so we have to exlicitly check.
|
||||
// In JS `NaN !== NaN`, so we have to explicitly check.
|
||||
if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
|
||||
watchRemover();
|
||||
var whenExpFn = whensExpFns[count];
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
* by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
|
||||
* will not have to rebuild the DOM elements for items it has already rendered, even if the
|
||||
* JavaScript objects in the collection have been substituted for new ones. For large collections,
|
||||
* this signifincantly improves rendering performance. If you don't have a unique identifier,
|
||||
* this significantly improves rendering performance. If you don't have a unique identifier,
|
||||
* `track by $index` can also provide a performance boost.
|
||||
* </div>
|
||||
* ```html
|
||||
@@ -170,6 +170,8 @@
|
||||
*
|
||||
* **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
|
||||
*
|
||||
* See the example below for defining CSS animations with ngRepeat.
|
||||
*
|
||||
* @element ANY
|
||||
* @scope
|
||||
* @priority 1000
|
||||
@@ -222,22 +224,11 @@
|
||||
* For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
|
||||
*
|
||||
* @example
|
||||
* This example initializes the scope to a list of names and
|
||||
* then uses `ngRepeat` to display every person:
|
||||
<example module="ngAnimate" deps="angular-animate.js" animations="true">
|
||||
* This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
|
||||
* results by name. New (entering) and removed (leaving) items are animated.
|
||||
<example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
|
||||
<file name="index.html">
|
||||
<div ng-init="friends = [
|
||||
{name:'John', age:25, gender:'boy'},
|
||||
{name:'Jessie', age:30, gender:'girl'},
|
||||
{name:'Johanna', age:28, gender:'girl'},
|
||||
{name:'Joy', age:15, gender:'girl'},
|
||||
{name:'Mary', age:28, gender:'girl'},
|
||||
{name:'Peter', age:95, gender:'boy'},
|
||||
{name:'Sebastian', age:50, gender:'boy'},
|
||||
{name:'Erika', age:27, gender:'girl'},
|
||||
{name:'Patrick', age:40, gender:'boy'},
|
||||
{name:'Samantha', age:60, gender:'girl'}
|
||||
]">
|
||||
<div ng-controller="repeatController">
|
||||
I have {{friends.length}} friends. They are:
|
||||
<input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
|
||||
<ul class="example-animate-container">
|
||||
@@ -250,6 +241,22 @@
|
||||
</ul>
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
|
||||
$scope.friends = [
|
||||
{name:'John', age:25, gender:'boy'},
|
||||
{name:'Jessie', age:30, gender:'girl'},
|
||||
{name:'Johanna', age:28, gender:'girl'},
|
||||
{name:'Joy', age:15, gender:'girl'},
|
||||
{name:'Mary', age:28, gender:'girl'},
|
||||
{name:'Peter', age:95, gender:'boy'},
|
||||
{name:'Sebastian', age:50, gender:'boy'},
|
||||
{name:'Erika', age:27, gender:'girl'},
|
||||
{name:'Patrick', age:40, gender:'boy'},
|
||||
{name:'Samantha', age:60, gender:'girl'}
|
||||
];
|
||||
});
|
||||
</file>
|
||||
<file name="animations.css">
|
||||
.example-animate-container {
|
||||
background:white;
|
||||
@@ -260,7 +267,7 @@
|
||||
}
|
||||
|
||||
.animate-repeat {
|
||||
line-height:40px;
|
||||
line-height:30px;
|
||||
list-style:none;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
@@ -282,7 +289,7 @@
|
||||
.animate-repeat.ng-move.ng-move-active,
|
||||
.animate-repeat.ng-enter.ng-enter-active {
|
||||
opacity:1;
|
||||
max-height:40px;
|
||||
max-height:30px;
|
||||
}
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
+21
-10
@@ -154,7 +154,7 @@ var SelectController =
|
||||
*
|
||||
* The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
|
||||
* between the scope and the `<select>` control (including setting default values).
|
||||
* Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
|
||||
* It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
|
||||
* {@link ngOptions `ngOptions`} directives.
|
||||
*
|
||||
* When an item in the `<select>` menu is selected, the value of the selected option will be bound
|
||||
@@ -164,7 +164,7 @@ var SelectController =
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* Note that the value of a `select` directive used without `ngOptions` is always a string.
|
||||
* When the model needs to be bound to a non-string value, you must either explictly convert it
|
||||
* When the model needs to be bound to a non-string value, you must either explicitly convert it
|
||||
* using a directive (see example below) or use `ngOptions` to specify the set of options.
|
||||
* This is because an option element can only be bound to string values at present.
|
||||
* </div>
|
||||
@@ -356,7 +356,8 @@ var selectDirective = function() {
|
||||
controller: SelectController,
|
||||
priority: 1,
|
||||
link: {
|
||||
pre: selectPreLink
|
||||
pre: selectPreLink,
|
||||
post: selectPostLink
|
||||
}
|
||||
};
|
||||
|
||||
@@ -370,13 +371,6 @@ var selectDirective = function() {
|
||||
|
||||
selectCtrl.ngModelCtrl = ngModelCtrl;
|
||||
|
||||
// We delegate rendering to the `writeValue` method, which can be changed
|
||||
// if the select can have multiple selected values or if the options are being
|
||||
// generated by `ngOptions`
|
||||
ngModelCtrl.$render = function() {
|
||||
selectCtrl.writeValue(ngModelCtrl.$viewValue);
|
||||
};
|
||||
|
||||
// When the selected item(s) changes we delegate getting the value of the select control
|
||||
// to the `readValue` method, which can be changed if the select can have multiple
|
||||
// selected values or if the options are being generated by `ngOptions`
|
||||
@@ -430,6 +424,23 @@ var selectDirective = function() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function selectPostLink(scope, element, attrs, ctrls) {
|
||||
// if ngModel is not defined, we don't need to do anything
|
||||
var ngModelCtrl = ctrls[1];
|
||||
if (!ngModelCtrl) return;
|
||||
|
||||
var selectCtrl = ctrls[0];
|
||||
|
||||
// We delegate rendering to the `writeValue` method, which can be changed
|
||||
// if the select can have multiple selected values or if the options are being
|
||||
// generated by `ngOptions`.
|
||||
// This must be done in the postLink fn to prevent $render to be called before
|
||||
// all nodes have been linked correctly.
|
||||
ngModelCtrl.$render = function() {
|
||||
selectCtrl.writeValue(ngModelCtrl.$viewValue);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,62 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngRequired
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
||||
* It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
|
||||
* applied to custom controls.
|
||||
*
|
||||
* The directive sets the `required` attribute on the element if the Angular expression inside
|
||||
* `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
|
||||
* cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
|
||||
* for more info.
|
||||
*
|
||||
* The validator will set the `required` error key to true if the `required` attribute is set and
|
||||
* calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty` with the
|
||||
* {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
|
||||
* `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
|
||||
* custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
|
||||
*
|
||||
* @example
|
||||
* <example name="ngRequiredDirective" module="ngRequiredExample">
|
||||
* <file name="index.html">
|
||||
* <script>
|
||||
* angular.module('ngRequiredExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.required = true;
|
||||
* }]);
|
||||
* </script>
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="form">
|
||||
* <label for="required">Toggle required: </label>
|
||||
* <input type="checkbox" ng-model="required" id="required" />
|
||||
* <br>
|
||||
* <label for="input">This input must be filled if `required` is true: </label>
|
||||
* <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
|
||||
* <hr>
|
||||
* required error set? = <code>{{form.input.$error.required}}</code><br>
|
||||
* model = <code>{{model}}</code>
|
||||
* </form>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
var required = element(by.binding('form.input.$error.required'));
|
||||
var model = element(by.binding('model'));
|
||||
var input = element(by.id('input'));
|
||||
|
||||
it('should set the required error', function() {
|
||||
expect(required.getText()).toContain('true');
|
||||
|
||||
input.sendKeys('123');
|
||||
expect(required.getText()).not.toContain('true');
|
||||
expect(model.getText()).toContain('123');
|
||||
});
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var requiredDirective = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
@@ -19,7 +76,81 @@ var requiredDirective = function() {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngPattern
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
||||
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
||||
*
|
||||
* The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
||||
* does not match a RegExp which is obtained by evaluating the Angular expression given in the
|
||||
* `ngPattern` attribute value:
|
||||
* * If the expression evaluates to a RegExp object, then this is used directly.
|
||||
* * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
|
||||
* in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
|
||||
* start at the index of the last search's match, thus not taking the whole input value into
|
||||
* account.
|
||||
* </div>
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* **Note:** This directive is also added when the plain `pattern` attribute is used, with two
|
||||
* differences:
|
||||
* <ol>
|
||||
* <li>
|
||||
* `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
|
||||
* not available.
|
||||
* </li>
|
||||
* <li>
|
||||
* The `ngPattern` attribute must be an expression, while the `pattern` value must be
|
||||
* interpolated.
|
||||
* </li>
|
||||
* </ol>
|
||||
* </div>
|
||||
*
|
||||
* @example
|
||||
* <example name="ngPatternDirective" module="ngPatternExample">
|
||||
* <file name="index.html">
|
||||
* <script>
|
||||
* angular.module('ngPatternExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.regex = '\\d+';
|
||||
* }]);
|
||||
* </script>
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="form">
|
||||
* <label for="regex">Set a pattern (regex string): </label>
|
||||
* <input type="text" ng-model="regex" id="regex" />
|
||||
* <br>
|
||||
* <label for="input">This input is restricted by the current pattern: </label>
|
||||
* <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
|
||||
* <hr>
|
||||
* input valid? = <code>{{form.input.$valid}}</code><br>
|
||||
* model = <code>{{model}}</code>
|
||||
* </form>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
var model = element(by.binding('model'));
|
||||
var input = element(by.id('input'));
|
||||
|
||||
it('should validate the input with the default pattern', function() {
|
||||
input.sendKeys('aaa');
|
||||
expect(model.getText()).not.toContain('aaa');
|
||||
|
||||
input.clear().then(function() {
|
||||
input.sendKeys('123');
|
||||
expect(model.getText()).toContain('123');
|
||||
});
|
||||
});
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var patternDirective = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
@@ -51,7 +182,72 @@ var patternDirective = function() {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMaxlength
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
||||
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
||||
*
|
||||
* The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
||||
* is longer than the integer obtained by evaluating the Angular expression given in the
|
||||
* `ngMaxlength` attribute value.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
|
||||
* differences:
|
||||
* <ol>
|
||||
* <li>
|
||||
* `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
|
||||
* validation is not available.
|
||||
* </li>
|
||||
* <li>
|
||||
* The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
|
||||
* interpolated.
|
||||
* </li>
|
||||
* </ol>
|
||||
* </div>
|
||||
*
|
||||
* @example
|
||||
* <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
|
||||
* <file name="index.html">
|
||||
* <script>
|
||||
* angular.module('ngMaxlengthExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.maxlength = 5;
|
||||
* }]);
|
||||
* </script>
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="form">
|
||||
* <label for="maxlength">Set a maxlength: </label>
|
||||
* <input type="number" ng-model="maxlength" id="maxlength" />
|
||||
* <br>
|
||||
* <label for="input">This input is restricted by the current maxlength: </label>
|
||||
* <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
|
||||
* <hr>
|
||||
* input valid? = <code>{{form.input.$valid}}</code><br>
|
||||
* model = <code>{{model}}</code>
|
||||
* </form>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
var model = element(by.binding('model'));
|
||||
var input = element(by.id('input'));
|
||||
|
||||
it('should validate the input with the default maxlength', function() {
|
||||
input.sendKeys('abcdef');
|
||||
expect(model.getText()).not.toContain('abcdef');
|
||||
|
||||
input.clear().then(function() {
|
||||
input.sendKeys('abcde');
|
||||
expect(model.getText()).toContain('abcde');
|
||||
});
|
||||
});
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var maxlengthDirective = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
@@ -72,6 +268,70 @@ var maxlengthDirective = function() {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngMinlength
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
|
||||
* It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
|
||||
*
|
||||
* The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
|
||||
* is shorter than the integer obtained by evaluating the Angular expression given in the
|
||||
* `ngMinlength` attribute value.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* **Note:** This directive is also added when the plain `minlength` attribute is used, with two
|
||||
* differences:
|
||||
* <ol>
|
||||
* <li>
|
||||
* `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
|
||||
* validation is not available.
|
||||
* </li>
|
||||
* <li>
|
||||
* The `ngMinlength` value must be an expression, while the `minlength` value must be
|
||||
* interpolated.
|
||||
* </li>
|
||||
* </ol>
|
||||
* </div>
|
||||
*
|
||||
* @example
|
||||
* <example name="ngMinlengthDirective" module="ngMinlengthExample">
|
||||
* <file name="index.html">
|
||||
* <script>
|
||||
* angular.module('ngMinlengthExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.minlength = 3;
|
||||
* }]);
|
||||
* </script>
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="form">
|
||||
* <label for="minlength">Set a minlength: </label>
|
||||
* <input type="number" ng-model="minlength" id="minlength" />
|
||||
* <br>
|
||||
* <label for="input">This input is restricted by the current minlength: </label>
|
||||
* <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
|
||||
* <hr>
|
||||
* input valid? = <code>{{form.input.$valid}}</code><br>
|
||||
* model = <code>{{model}}</code>
|
||||
* </form>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
var model = element(by.binding('model'));
|
||||
var input = element(by.id('input'));
|
||||
|
||||
it('should validate the input with the default minlength', function() {
|
||||
input.sendKeys('ab');
|
||||
expect(model.getText()).not.toContain('ab');
|
||||
|
||||
input.sendKeys('abc');
|
||||
expect(model.getText()).toContain('abc');
|
||||
});
|
||||
* </file>
|
||||
* </example>
|
||||
*/
|
||||
var minlengthDirective = function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
|
||||
@@ -613,7 +613,7 @@ function dateFilter($locale) {
|
||||
forEach(parts, function(value) {
|
||||
fn = DATE_FORMATS[value];
|
||||
text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
|
||||
: value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
|
||||
: value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
|
||||
});
|
||||
|
||||
return text;
|
||||
|
||||
+1
-1
@@ -1034,7 +1034,7 @@ function $HttpProvider() {
|
||||
|
||||
defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
|
||||
|
||||
// using for-in instead of forEach to avoid unecessary iteration after header has been found
|
||||
// using for-in instead of forEach to avoid unnecessary iteration after header has been found
|
||||
defaultHeadersIteration:
|
||||
for (defHeaderName in defHeaders) {
|
||||
lowercaseDefHeaderName = lowercase(defHeaderName);
|
||||
|
||||
@@ -29,7 +29,7 @@ $interpolateMinErr.interr = function(text, err) {
|
||||
* </div>
|
||||
*
|
||||
* @example
|
||||
<example module="customInterpolationApp">
|
||||
<example name="custom-interpolation-markup" module="customInterpolationApp">
|
||||
<file name="index.html">
|
||||
<script>
|
||||
var customInterpolationApp = angular.module('customInterpolationApp', []);
|
||||
@@ -44,7 +44,7 @@ $interpolateMinErr.interr = function(text, err) {
|
||||
this.label = "This binding is brought you by // interpolation symbols.";
|
||||
});
|
||||
</script>
|
||||
<div ng-app="App" ng-controller="DemoController as demo">
|
||||
<div ng-controller="DemoController as demo">
|
||||
//demo.label//
|
||||
</div>
|
||||
</file>
|
||||
|
||||
+50
-19
@@ -48,23 +48,22 @@ function ensureSafeMemberName(name, fullExpression) {
|
||||
return name;
|
||||
}
|
||||
|
||||
function getStringValue(name, fullExpression) {
|
||||
// From the JavaScript docs:
|
||||
function getStringValue(name) {
|
||||
// Property names must be strings. This means that non-string objects cannot be used
|
||||
// as keys in an object. Any non-string object, including a number, is typecasted
|
||||
// into a string via the toString method.
|
||||
// -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
|
||||
//
|
||||
// So, to ensure that we are checking the same `name` that JavaScript would use,
|
||||
// we cast it to a string, if possible.
|
||||
// Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
|
||||
// this is, this will handle objects that misbehave.
|
||||
name = name + '';
|
||||
if (!isString(name)) {
|
||||
throw $parseMinErr('iseccst',
|
||||
'Cannot convert object to primitive value! '
|
||||
+ 'Expression: {0}', fullExpression);
|
||||
}
|
||||
return name;
|
||||
// So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
|
||||
// to a string. It's not always possible. If `name` is an object and its `toString` method is
|
||||
// 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
|
||||
//
|
||||
// TypeError: Cannot convert object to primitive value
|
||||
//
|
||||
// For performance reasons, we don't catch this error here and allow it to propagate up the call
|
||||
// stack. Note that you'll get the same error in JavaScript if you try to access a property using
|
||||
// such a 'broken' object as a key.
|
||||
return name + '';
|
||||
}
|
||||
|
||||
function ensureSafeObject(obj, fullExpression) {
|
||||
@@ -1231,7 +1230,7 @@ ASTCompiler.prototype = {
|
||||
},
|
||||
|
||||
getStringValue: function(item) {
|
||||
this.assign(item, 'getStringValue(' + item + ',text)');
|
||||
this.assign(item, 'getStringValue(' + item + ')');
|
||||
},
|
||||
|
||||
ensureSafeAssignContext: function(item) {
|
||||
@@ -1683,9 +1682,6 @@ Parser.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
var getterFnCacheDefault = createMap();
|
||||
var getterFnCacheExpensive = createMap();
|
||||
|
||||
function isPossiblyDangerousMemberName(name) {
|
||||
return name == 'constructor';
|
||||
}
|
||||
@@ -1761,10 +1757,19 @@ function $ParseProvider() {
|
||||
csp: noUnsafeEval,
|
||||
expensiveChecks: true
|
||||
};
|
||||
var runningChecksEnabled = false;
|
||||
|
||||
return function $parse(exp, interceptorFn, expensiveChecks) {
|
||||
$parse.$$runningExpensiveChecks = function() {
|
||||
return runningChecksEnabled;
|
||||
};
|
||||
|
||||
return $parse;
|
||||
|
||||
function $parse(exp, interceptorFn, expensiveChecks) {
|
||||
var parsedExpression, oneTime, cacheKey;
|
||||
|
||||
expensiveChecks = expensiveChecks || runningChecksEnabled;
|
||||
|
||||
switch (typeof exp) {
|
||||
case 'string':
|
||||
exp = exp.trim();
|
||||
@@ -1790,6 +1795,9 @@ function $ParseProvider() {
|
||||
} else if (parsedExpression.inputs) {
|
||||
parsedExpression.$$watchDelegate = inputsWatchDelegate;
|
||||
}
|
||||
if (expensiveChecks) {
|
||||
parsedExpression = expensiveChecksInterceptor(parsedExpression);
|
||||
}
|
||||
cache[cacheKey] = parsedExpression;
|
||||
}
|
||||
return addInterceptor(parsedExpression, interceptorFn);
|
||||
@@ -1800,7 +1808,30 @@ function $ParseProvider() {
|
||||
default:
|
||||
return addInterceptor(noop, interceptorFn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function expensiveChecksInterceptor(fn) {
|
||||
if (!fn) return fn;
|
||||
expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
|
||||
expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
|
||||
expensiveCheckFn.constant = fn.constant;
|
||||
expensiveCheckFn.literal = fn.literal;
|
||||
for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
|
||||
fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
|
||||
}
|
||||
|
||||
return expensiveCheckFn;
|
||||
|
||||
function expensiveCheckFn(scope, locals, assign, inputs) {
|
||||
var expensiveCheckOldValue = runningChecksEnabled;
|
||||
runningChecksEnabled = true;
|
||||
try {
|
||||
return fn(scope, locals, assign, inputs);
|
||||
} finally {
|
||||
runningChecksEnabled = expensiveCheckOldValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function expressionInputDirtyCheck(newValue, oldValueOfValue) {
|
||||
|
||||
|
||||
+5
-6
@@ -53,7 +53,7 @@
|
||||
*
|
||||
* Note: progress/notify callbacks are not currently supported via the ES6-style interface.
|
||||
*
|
||||
* Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
|
||||
* Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
|
||||
*
|
||||
* However, the more traditional CommonJS-style usage is still available, and documented below.
|
||||
*
|
||||
@@ -566,11 +566,6 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
|
||||
}
|
||||
|
||||
if (!(this instanceof Q)) {
|
||||
// More useful when $Q is the Promise itself.
|
||||
return new Q(resolver);
|
||||
}
|
||||
|
||||
var deferred = new Deferred();
|
||||
|
||||
function resolveFn(value) {
|
||||
@@ -586,6 +581,10 @@ function qFactory(nextTick, exceptionHandler) {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
// Let's make the instanceof operator work for promises, so that
|
||||
// `new $q(fn) instanceof $q` would evaluate to true.
|
||||
$Q.prototype = Promise.prototype;
|
||||
|
||||
$Q.defer = defer;
|
||||
$Q.reject = reject;
|
||||
$Q.when = when;
|
||||
|
||||
+2
-1
@@ -998,7 +998,7 @@ function $RootScopeProvider() {
|
||||
});
|
||||
}
|
||||
|
||||
asyncQueue.push({scope: this, expression: expr, locals: locals});
|
||||
asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
|
||||
},
|
||||
|
||||
$$postDigest: function(fn) {
|
||||
@@ -1090,6 +1090,7 @@ function $RootScopeProvider() {
|
||||
$applyAsync: function(expr) {
|
||||
var scope = this;
|
||||
expr && applyAsyncQueue.push($applyAsyncExpression);
|
||||
expr = $parse(expr);
|
||||
scheduleApplyAsync();
|
||||
|
||||
function $applyAsyncExpression() {
|
||||
|
||||
+15
-13
@@ -144,13 +144,15 @@ function $SceDelegateProvider() {
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.
|
||||
*
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
*
|
||||
* Note: **an empty whitelist array will block all URLs**!
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** an empty whitelist array will block all URLs!
|
||||
* </div>
|
||||
*
|
||||
* @return {Array} the currently set whitelist array.
|
||||
*
|
||||
@@ -173,17 +175,17 @@ function $SceDelegateProvider() {
|
||||
* @kind function
|
||||
*
|
||||
* @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.
|
||||
* provided. This must be an array or null. A snapshot of this array is used so further
|
||||
* changes to the array are ignored.
|
||||
*
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
* Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
|
||||
* allowed in this array.
|
||||
*
|
||||
* The typical usage for the blacklist is to **block
|
||||
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
|
||||
* these would otherwise be trusted but actually return content from the redirected domain.
|
||||
* The typical usage for the blacklist is to **block
|
||||
* [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
|
||||
* these would otherwise be trusted but actually return content from the redirected domain.
|
||||
*
|
||||
* Finally, **the blacklist overrides the whitelist** and has the final say.
|
||||
* Finally, **the blacklist overrides the whitelist** and has the final say.
|
||||
*
|
||||
* @return {Array} the currently set blacklist array.
|
||||
*
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"assertArg": false,
|
||||
"isPromiseLike": false,
|
||||
"mergeClasses": false,
|
||||
"mergeAnimationOptions": false,
|
||||
"mergeAnimationDetails": false,
|
||||
"prepareAnimationOptions": false,
|
||||
"applyAnimationStyles": false,
|
||||
"applyAnimationFromStyles": false,
|
||||
|
||||
+63
-43
@@ -167,7 +167,7 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
|
||||
* ```
|
||||
*
|
||||
* To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.
|
||||
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and stlyes may have been
|
||||
* If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been
|
||||
* applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties
|
||||
* and that changing them will not reconfigure the parameters of the animation.
|
||||
*
|
||||
@@ -205,10 +205,10 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
|
||||
* ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
|
||||
* * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
|
||||
* `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
|
||||
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)
|
||||
* * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)
|
||||
* * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once
|
||||
* the animation is closed. This is useful for when the styles are used purely for the sake of
|
||||
* the animation and do not have a lasting visual effect on the element (e.g. a colapse and open animation).
|
||||
* the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).
|
||||
* By default this value is set to `false`.
|
||||
*
|
||||
* @return {object} an object with start and end methods and details about the animation.
|
||||
@@ -261,7 +261,7 @@ function computeCssStyles($window, element, properties) {
|
||||
}
|
||||
|
||||
// by setting this to null in the event that the delay is not set or is set directly as 0
|
||||
// then we can still allow for zegative values to be used later on and not mistake this
|
||||
// then we can still allow for negative values to be used later on and not mistake this
|
||||
// value for being greater than any other negative value.
|
||||
if (val === 0) {
|
||||
val = null;
|
||||
@@ -352,9 +352,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
var gcsStaggerLookup = createLocalCacheLookup();
|
||||
|
||||
this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
|
||||
'$$forceReflow', '$sniffer', '$$rAFScheduler', '$animate',
|
||||
'$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
|
||||
function($window, $$jqLite, $$AnimateRunner, $timeout,
|
||||
$$forceReflow, $sniffer, $$rAFScheduler, $animate) {
|
||||
$$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
|
||||
|
||||
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
||||
|
||||
@@ -377,7 +377,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
// we keep putting this in multiple times even though the value and the cacheKey are the same
|
||||
// because we're keeping an interal tally of how many duplicate animations are detected.
|
||||
// because we're keeping an internal tally of how many duplicate animations are detected.
|
||||
gcsLookup.put(cacheKey, timings);
|
||||
return timings;
|
||||
}
|
||||
@@ -447,21 +447,23 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
|
||||
return function init(element, initialOptions) {
|
||||
// we always make a copy of the options since
|
||||
// there should never be any side effects on
|
||||
// the input data when running `$animateCss`.
|
||||
var options = copy(initialOptions);
|
||||
// all of the animation functions should create
|
||||
// a copy of the options data, however, if a
|
||||
// parent service has already created a copy then
|
||||
// we should stick to using that
|
||||
var options = initialOptions || {};
|
||||
if (!options.$$prepared) {
|
||||
options = prepareAnimationOptions(copy(options));
|
||||
}
|
||||
|
||||
var restoreStyles = {};
|
||||
var node = getDomNode(element);
|
||||
if (!node
|
||||
|| !node.parentNode
|
||||
|| !$animate.enabled()) {
|
||||
|| !$$animateQueue.enabled()) {
|
||||
return closeAndReturnNoopAnimator();
|
||||
}
|
||||
|
||||
options = prepareAnimationOptions(options);
|
||||
|
||||
var temporaryStyles = [];
|
||||
var classes = element.attr('class');
|
||||
var styles = packageStyles(options);
|
||||
@@ -474,6 +476,8 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
var maxDelayTime;
|
||||
var maxDuration;
|
||||
var maxDurationTime;
|
||||
var startTime;
|
||||
var events = [];
|
||||
|
||||
if (options.duration === 0 || (!$sniffer.animations && !$sniffer.transitions)) {
|
||||
return closeAndReturnNoopAnimator();
|
||||
@@ -747,6 +751,18 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
options.onDone();
|
||||
}
|
||||
|
||||
if (events && events.length) {
|
||||
// Remove the transitionend / animationend listener(s)
|
||||
element.off(events.join(' '), onAnimationProgress);
|
||||
}
|
||||
|
||||
//Cancel the fallback closing timeout and remove the timer data
|
||||
var animationTimerData = element.data(ANIMATE_TIMER_KEY);
|
||||
if (animationTimerData) {
|
||||
$timeout.cancel(animationTimerData[0].timer);
|
||||
element.removeData(ANIMATE_TIMER_KEY);
|
||||
}
|
||||
|
||||
// if the preparation function fails then the promise is not setup
|
||||
if (runner) {
|
||||
runner.complete(!rejected);
|
||||
@@ -782,6 +798,33 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
};
|
||||
}
|
||||
|
||||
function onAnimationProgress(event) {
|
||||
event.stopPropagation();
|
||||
var ev = event.originalEvent || event;
|
||||
|
||||
// we now always use `Date.now()` due to the recent changes with
|
||||
// event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)
|
||||
var timeStamp = ev.$manualTimeStamp || Date.now();
|
||||
|
||||
/* Firefox (or possibly just Gecko) likes to not round values up
|
||||
* when a ms measurement is used for the animation */
|
||||
var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
|
||||
|
||||
/* $manualTimeStamp is a mocked timeStamp value which is set
|
||||
* within browserTrigger(). This is only here so that tests can
|
||||
* mock animations properly. Real events fallback to event.timeStamp,
|
||||
* or, if they don't, then a timeStamp is automatically created for them.
|
||||
* We're checking to see if the timeStamp surpasses the expected delay,
|
||||
* but we're using elapsedTime instead of the timeStamp on the 2nd
|
||||
* pre-condition since animationPauseds sometimes close off early */
|
||||
if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
|
||||
// we set this flag to ensure that if the transition is paused then, when resumed,
|
||||
// the animation will automatically close itself since transitions cannot be paused.
|
||||
animationCompleted = true;
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (animationClosed) return;
|
||||
if (!node.parentNode) {
|
||||
@@ -789,8 +832,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startTime, events = [];
|
||||
|
||||
// even though we only pause keyframe animations here the pause flag
|
||||
// will still happen when transitions are used. Only the transition will
|
||||
// not be paused since that is not possible. If the animation ends when
|
||||
@@ -810,9 +851,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
}
|
||||
};
|
||||
|
||||
// checking the stagger duration prevents an accidently cascade of the CSS delay style
|
||||
// checking the stagger duration prevents an accidentally cascade of the CSS delay style
|
||||
// being inherited from the parent. If the transition duration is zero then we can safely
|
||||
// rely that the delay value is an intential stagger delay style.
|
||||
// rely that the delay value is an intentional stagger delay style.
|
||||
var maxStagger = itemIndex > 0
|
||||
&& ((timings.transitionDuration && stagger.transitionDuration === 0) ||
|
||||
(timings.animationDuration && stagger.animationDuration === 0))
|
||||
@@ -931,7 +972,10 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
element.data(ANIMATE_TIMER_KEY, animationsData);
|
||||
}
|
||||
|
||||
element.on(events.join(' '), onAnimationProgress);
|
||||
if (events.length) {
|
||||
element.on(events.join(' '), onAnimationProgress);
|
||||
}
|
||||
|
||||
if (options.to) {
|
||||
if (options.cleanupStyles) {
|
||||
registerRestorableStyles(restoreStyles, node, Object.keys(options.to));
|
||||
@@ -953,30 +997,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
|
||||
element.removeData(ANIMATE_TIMER_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
function onAnimationProgress(event) {
|
||||
event.stopPropagation();
|
||||
var ev = event.originalEvent || event;
|
||||
var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
|
||||
|
||||
/* Firefox (or possibly just Gecko) likes to not round values up
|
||||
* when a ms measurement is used for the animation */
|
||||
var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
|
||||
|
||||
/* $manualTimeStamp is a mocked timeStamp value which is set
|
||||
* within browserTrigger(). This is only here so that tests can
|
||||
* mock animations properly. Real events fallback to event.timeStamp,
|
||||
* or, if they don't, then a timeStamp is automatically created for them.
|
||||
* We're checking to see if the timeStamp surpasses the expected delay,
|
||||
* but we're using elapsedTime instead of the timeStamp on the 2nd
|
||||
* pre-condition since animations sometimes close off early */
|
||||
if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
|
||||
// we set this flag to ensure that if the transition is paused then, when resumed,
|
||||
// the animation will automatically close itself since transitions cannot be paused.
|
||||
animationCompleted = true;
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -24,7 +24,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
||||
|
||||
var rootBodyElement = jqLite(
|
||||
// this is to avoid using something that exists outside of the body
|
||||
// we also special case the doc fragement case because our unit test code
|
||||
// we also special case the doc fragment case because our unit test code
|
||||
// appends the $rootElement to the body after the app has been bootstrapped
|
||||
isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
|
||||
);
|
||||
@@ -124,7 +124,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
|
||||
var coords = getDomNode(anchor).getBoundingClientRect();
|
||||
|
||||
// we iterate directly since safari messes up and doesn't return
|
||||
// all the keys for the coods object when iterated
|
||||
// all the keys for the coords object when iterated
|
||||
forEach(['width','height','top','left'], function(key) {
|
||||
var value = coords[key];
|
||||
switch (key) {
|
||||
|
||||
@@ -11,6 +11,8 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
||||
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
||||
// $animateJs(element, 'enter');
|
||||
return function(element, event, classes, options) {
|
||||
var animationClosed = false;
|
||||
|
||||
// the `classes` argument is optional and if it is not used
|
||||
// then the classes will be resolved from the element's className
|
||||
// property as well as options.addClass/options.removeClass.
|
||||
@@ -63,8 +65,32 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
||||
applyAnimationClasses(element, options);
|
||||
}
|
||||
|
||||
function close() {
|
||||
animationClosed = true;
|
||||
applyOptions();
|
||||
applyAnimationStyles(element, options);
|
||||
}
|
||||
|
||||
var runner;
|
||||
|
||||
return {
|
||||
$$willAnimate: true,
|
||||
end: function() {
|
||||
if (runner) {
|
||||
runner.end();
|
||||
} else {
|
||||
close();
|
||||
runner = new $$AnimateRunner();
|
||||
runner.complete(true);
|
||||
}
|
||||
return runner;
|
||||
},
|
||||
start: function() {
|
||||
if (runner) {
|
||||
return runner;
|
||||
}
|
||||
|
||||
runner = new $$AnimateRunner();
|
||||
var closeActiveAnimations;
|
||||
var chain = [];
|
||||
|
||||
@@ -89,8 +115,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
||||
});
|
||||
}
|
||||
|
||||
var animationClosed = false;
|
||||
var runner = new $$AnimateRunner({
|
||||
runner.setHost({
|
||||
end: function() {
|
||||
endAnimations();
|
||||
},
|
||||
@@ -103,9 +128,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
|
||||
return runner;
|
||||
|
||||
function onComplete(success) {
|
||||
animationClosed = true;
|
||||
applyOptions();
|
||||
applyAnimationStyles(element, options);
|
||||
close(success);
|
||||
runner.complete(success);
|
||||
}
|
||||
|
||||
|
||||
+103
-45
@@ -5,6 +5,7 @@ var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
|
||||
var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
var PRE_DIGEST_STATE = 1;
|
||||
var RUNNING_STATE = 2;
|
||||
var ONE_SPACE = ' ';
|
||||
|
||||
var rules = this.rules = {
|
||||
skip: [],
|
||||
@@ -12,28 +13,50 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
join: []
|
||||
};
|
||||
|
||||
function makeTruthyCssClassMap(classString) {
|
||||
if (!classString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var keys = classString.split(ONE_SPACE);
|
||||
var map = Object.create(null);
|
||||
|
||||
forEach(keys, function(key) {
|
||||
map[key] = true;
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function hasMatchingClasses(newClassString, currentClassString) {
|
||||
if (newClassString && currentClassString) {
|
||||
var currentClassMap = makeTruthyCssClassMap(currentClassString);
|
||||
return newClassString.split(ONE_SPACE).some(function(className) {
|
||||
return currentClassMap[className];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
|
||||
return rules[ruleType].some(function(fn) {
|
||||
return fn(element, currentAnimation, previousAnimation);
|
||||
});
|
||||
}
|
||||
|
||||
function hasAnimationClasses(options, and) {
|
||||
options = options || {};
|
||||
var a = (options.addClass || '').length > 0;
|
||||
var b = (options.removeClass || '').length > 0;
|
||||
function hasAnimationClasses(animation, and) {
|
||||
var a = (animation.addClass || '').length > 0;
|
||||
var b = (animation.removeClass || '').length > 0;
|
||||
return and ? a && b : a || b;
|
||||
}
|
||||
|
||||
rules.join.push(function(element, newAnimation, currentAnimation) {
|
||||
// if the new animation is class-based then we can just tack that on
|
||||
return !newAnimation.structural && hasAnimationClasses(newAnimation.options);
|
||||
return !newAnimation.structural && hasAnimationClasses(newAnimation);
|
||||
});
|
||||
|
||||
rules.skip.push(function(element, newAnimation, currentAnimation) {
|
||||
// there is no need to animate anything if no classes are being added and
|
||||
// there is no structural animation that will be triggered
|
||||
return !newAnimation.structural && !hasAnimationClasses(newAnimation.options);
|
||||
return !newAnimation.structural && !hasAnimationClasses(newAnimation);
|
||||
});
|
||||
|
||||
rules.skip.push(function(element, newAnimation, currentAnimation) {
|
||||
@@ -59,11 +82,17 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
});
|
||||
|
||||
rules.cancel.push(function(element, newAnimation, currentAnimation) {
|
||||
var nO = newAnimation.options;
|
||||
var cO = currentAnimation.options;
|
||||
var nA = newAnimation.addClass;
|
||||
var nR = newAnimation.removeClass;
|
||||
var cA = currentAnimation.addClass;
|
||||
var cR = currentAnimation.removeClass;
|
||||
|
||||
// if the exact same CSS class is added/removed then it's safe to cancel it
|
||||
return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);
|
||||
// early detection to save the global CPU shortage :)
|
||||
if ((isUndefined(nA) && isUndefined(nR)) || (isUndefined(cA) && isUndefined(cR))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
|
||||
});
|
||||
|
||||
this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
|
||||
@@ -135,10 +164,17 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
|
||||
var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
|
||||
|
||||
function normalizeAnimationOptions(element, options) {
|
||||
return mergeAnimationOptions(element, options, {});
|
||||
function normalizeAnimationDetails(element, animation) {
|
||||
return mergeAnimationDetails(element, animation, {});
|
||||
}
|
||||
|
||||
// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
|
||||
var contains = Node.prototype.contains || function(arg) {
|
||||
// jshint bitwise: false
|
||||
return this === arg || !!(this.compareDocumentPosition(arg) & 16);
|
||||
// jshint bitwise: true
|
||||
};
|
||||
|
||||
function findCallbacks(parent, element, event) {
|
||||
var targetNode = getDomNode(element);
|
||||
var targetParentNode = getDomNode(parent);
|
||||
@@ -147,9 +183,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
var entries = callbackRegistry[event];
|
||||
if (entries) {
|
||||
forEach(entries, function(entry) {
|
||||
if (entry.node.contains(targetNode)) {
|
||||
if (contains.call(entry.node, targetNode)) {
|
||||
matches.push(entry.callback);
|
||||
} else if (event === 'leave' && entry.node.contains(targetParentNode)) {
|
||||
} else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {
|
||||
matches.push(entry.callback);
|
||||
}
|
||||
});
|
||||
@@ -224,12 +260,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
bool = !recordExists;
|
||||
} else {
|
||||
// (element, bool) - Element setter
|
||||
bool = !!bool;
|
||||
if (!bool) {
|
||||
disabledElementsLookup.put(node, true);
|
||||
} else if (recordExists) {
|
||||
disabledElementsLookup.remove(node);
|
||||
}
|
||||
disabledElementsLookup.put(node, !bool);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -303,7 +334,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
// this is a hard disable of all animations for the application or on
|
||||
// the element itself, therefore there is no need to continue further
|
||||
// past this point if not enabled
|
||||
var skipAnimations = !animationsEnabled || disabledElementsLookup.get(node);
|
||||
// Animations are also disabled if the document is currently hidden (page is not visible
|
||||
// to the user), because browsers slow down or do not flush calls to requestAnimationFrame
|
||||
var skipAnimations = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node);
|
||||
var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
|
||||
var hasExistingAnimation = !!existingAnimation.state;
|
||||
|
||||
@@ -326,6 +359,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
structural: isStructural,
|
||||
element: element,
|
||||
event: event,
|
||||
addClass: options.addClass,
|
||||
removeClass: options.removeClass,
|
||||
close: close,
|
||||
options: options,
|
||||
runner: runner
|
||||
@@ -338,11 +373,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
close();
|
||||
return runner;
|
||||
} else {
|
||||
mergeAnimationOptions(element, existingAnimation.options, options);
|
||||
mergeAnimationDetails(element, existingAnimation, newAnimation);
|
||||
return existingAnimation.runner;
|
||||
}
|
||||
}
|
||||
|
||||
var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
|
||||
if (cancelAnimationFlag) {
|
||||
if (existingAnimation.state === RUNNING_STATE) {
|
||||
@@ -357,7 +391,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
existingAnimation.close();
|
||||
} else {
|
||||
// this will merge the new animation options into existing animation options
|
||||
mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);
|
||||
mergeAnimationDetails(element, existingAnimation, newAnimation);
|
||||
|
||||
return existingAnimation.runner;
|
||||
}
|
||||
} else {
|
||||
@@ -367,12 +402,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);
|
||||
if (joinAnimationFlag) {
|
||||
if (existingAnimation.state === RUNNING_STATE) {
|
||||
normalizeAnimationOptions(element, options);
|
||||
normalizeAnimationDetails(element, newAnimation);
|
||||
} else {
|
||||
applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
|
||||
|
||||
event = newAnimation.event = existingAnimation.event;
|
||||
options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);
|
||||
options = mergeAnimationDetails(element, existingAnimation, newAnimation);
|
||||
|
||||
//we return the same runner since only the option values of this animation will
|
||||
//be fed into the `existingAnimation`.
|
||||
@@ -383,7 +418,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
} else {
|
||||
// normalization in this case means that it removes redundant CSS classes that
|
||||
// already exist (addClass) or do not exist (removeClass) on the element
|
||||
normalizeAnimationOptions(element, options);
|
||||
normalizeAnimationDetails(element, newAnimation);
|
||||
}
|
||||
|
||||
// when the options are merged and cleaned up we may end up not having to do
|
||||
@@ -393,7 +428,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
if (!isValidAnimation) {
|
||||
// animate (from/to) can be quickly checked first, otherwise we check if any classes are present
|
||||
isValidAnimation = (newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0)
|
||||
|| hasAnimationClasses(newAnimation.options);
|
||||
|| hasAnimationClasses(newAnimation);
|
||||
}
|
||||
|
||||
if (!isValidAnimation) {
|
||||
@@ -423,7 +458,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
var isValidAnimation = parentElement.length > 0
|
||||
&& (animationDetails.event === 'animate'
|
||||
|| animationDetails.structural
|
||||
|| hasAnimationClasses(animationDetails.options));
|
||||
|| hasAnimationClasses(animationDetails));
|
||||
|
||||
// this means that the previous animation was cancelled
|
||||
// even if the follow-up animation is the same event
|
||||
@@ -455,7 +490,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
|
||||
// this combined multiple class to addClass / removeClass into a setClass event
|
||||
// so long as a structural event did not take over the animation
|
||||
event = !animationDetails.structural && hasAnimationClasses(animationDetails.options, true)
|
||||
event = !animationDetails.structural && hasAnimationClasses(animationDetails, true)
|
||||
? 'setClass'
|
||||
: animationDetails.event;
|
||||
|
||||
@@ -535,12 +570,20 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
|
||||
}
|
||||
|
||||
/**
|
||||
* This fn returns false if any of the following is true:
|
||||
* a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed
|
||||
* b) a parent element has an ongoing structural animation, and animateChildren is false
|
||||
* c) the element is not a child of the body
|
||||
* d) the element is not a child of the $rootElement
|
||||
*/
|
||||
function areAnimationsAllowed(element, parentElement, event) {
|
||||
var bodyElement = jqLite($document[0].body);
|
||||
var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
|
||||
var rootElementDetected = isMatchingElement(element, $rootElement);
|
||||
var parentAnimationDetected = false;
|
||||
var animateChildren;
|
||||
var elementDisabled = disabledElementsLookup.get(getDomNode(element));
|
||||
|
||||
var parentHost = element.data(NG_ANIMATE_PIN_DATA);
|
||||
if (parentHost) {
|
||||
@@ -565,7 +608,18 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
// therefore we can't allow any animations to take place
|
||||
// but if a parent animation is class-based then that's ok
|
||||
if (!parentAnimationDetected) {
|
||||
parentAnimationDetected = details.structural || disabledElementsLookup.get(parentNode);
|
||||
var parentElementDisabled = disabledElementsLookup.get(parentNode);
|
||||
|
||||
if (parentElementDisabled === true && elementDisabled !== false) {
|
||||
// disable animations if the user hasn't explicitly enabled animations on the
|
||||
// current element
|
||||
elementDisabled = true;
|
||||
// element is disabled via parent element, no need to check anything else
|
||||
break;
|
||||
} else if (parentElementDisabled === false) {
|
||||
elementDisabled = false;
|
||||
}
|
||||
parentAnimationDetected = details.structural;
|
||||
}
|
||||
|
||||
if (isUndefined(animateChildren) || animateChildren === true) {
|
||||
@@ -578,28 +632,32 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
|
||||
// there is no need to continue traversing at this point
|
||||
if (parentAnimationDetected && animateChildren === false) break;
|
||||
|
||||
if (!rootElementDetected) {
|
||||
// angular doesn't want to attempt to animate elements outside of the application
|
||||
// therefore we need to ensure that the rootElement is an ancestor of the current element
|
||||
rootElementDetected = isMatchingElement(parentElement, $rootElement);
|
||||
if (!rootElementDetected) {
|
||||
parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);
|
||||
if (parentHost) {
|
||||
parentElement = parentHost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bodyElementDetected) {
|
||||
// we also need to ensure that the element is or will be apart of the body element
|
||||
// we also need to ensure that the element is or will be a part of the body element
|
||||
// otherwise it is pointless to even issue an animation to be rendered
|
||||
bodyElementDetected = isMatchingElement(parentElement, bodyElement);
|
||||
}
|
||||
|
||||
if (bodyElementDetected && rootElementDetected) {
|
||||
// If both body and root have been found, any other checks are pointless,
|
||||
// as no animation data should live outside the application
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rootElementDetected) {
|
||||
// If no rootElement is detected, check if the parentElement is pinned to another element
|
||||
parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);
|
||||
if (parentHost) {
|
||||
// The pin target element becomes the next parent element
|
||||
parentElement = parentHost;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
parentElement = parentElement.parent();
|
||||
}
|
||||
|
||||
var allowAnimation = !parentAnimationDetected || animateChildren;
|
||||
var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
|
||||
return allowAnimation && rootElementDetected && bodyElementDetected;
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
|
||||
};
|
||||
|
||||
// the anchor animations require that the from and to elements both have at least
|
||||
// one shared CSS class which effictively marries the two elements together to use
|
||||
// one shared CSS class which effectively marries the two elements together to use
|
||||
// the same animation driver and to properly sequence the anchor animation.
|
||||
if (group.classes.length) {
|
||||
preparedAnimations.push(group);
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
*
|
||||
* ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
|
||||
* CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the
|
||||
* `module.animation()` module function we can register the ainmation.
|
||||
* `module.animation()` module function we can register the animation.
|
||||
*
|
||||
* Let's see an example of a enter/leave animation using `ngRepeat`:
|
||||
*
|
||||
|
||||
@@ -14,7 +14,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
|
||||
queue = scheduler.queue = [];
|
||||
|
||||
/* waitUntilQuiet does two things:
|
||||
* 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through
|
||||
* 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through
|
||||
* 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
|
||||
*
|
||||
* The motivation here is that animation code can request more time from the scheduler
|
||||
|
||||
@@ -73,6 +73,7 @@ var isPromiseLike = function(p) {
|
||||
return p && p.then ? true : false;
|
||||
};
|
||||
|
||||
var ngMinErr = angular.$$minErr('ng');
|
||||
function assertArg(arg, name, reason) {
|
||||
if (!arg) {
|
||||
throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
|
||||
@@ -217,7 +218,10 @@ function applyAnimationToStyles(element, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function mergeAnimationOptions(element, target, newOptions) {
|
||||
function mergeAnimationDetails(element, oldAnimation, newAnimation) {
|
||||
var target = oldAnimation.options || {};
|
||||
var newOptions = newAnimation.options || {};
|
||||
|
||||
var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');
|
||||
var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
|
||||
var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
|
||||
@@ -249,6 +253,9 @@ function mergeAnimationOptions(element, target, newOptions) {
|
||||
target.removeClass = null;
|
||||
}
|
||||
|
||||
oldAnimation.addClass = target.addClass;
|
||||
oldAnimation.removeClass = target.removeClass;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,16 +34,17 @@ angular.module('ngCookies', ['ng']).
|
||||
* The object may have following properties:
|
||||
*
|
||||
* - **path** - `{string}` - The cookie will be available only for this path and its
|
||||
* sub-paths. By default, this would be the URL that appears in your base tag.
|
||||
* sub-paths. By default, this is the URL that appears in your `<base>` tag.
|
||||
* - **domain** - `{string}` - The cookie will be available only for this domain and
|
||||
* its sub-domains. For obvious security reasons the user agent will not accept the
|
||||
* cookie if the current domain is not a sub domain or equals to the requested domain.
|
||||
* its sub-domains. For security reasons the user agent will not accept the cookie
|
||||
* if the current domain is not a sub-domain of this domain or equal to it.
|
||||
* - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT"
|
||||
* or a Date object indicating the exact date/time this cookie will expire.
|
||||
* - **secure** - `{boolean}` - The cookie will be available only in secured connection.
|
||||
* - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a
|
||||
* secured connection.
|
||||
*
|
||||
* Note: by default the address that appears in your `<base>` tag will be used as path.
|
||||
* This is important so that cookies will be visible for all routes in case html5mode is enabled
|
||||
* Note: By default, the address that appears in your `<base>` tag will be used as the path.
|
||||
* This is important so that cookies will be visible for all routes when html5mode is enabled.
|
||||
*
|
||||
**/
|
||||
var defaults = this.defaults = {};
|
||||
|
||||
Vendored
+1
@@ -119,6 +119,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "af-na",
|
||||
"localeID": "af_NA",
|
||||
"pluralCat": function(n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
Vendored
+1
@@ -119,6 +119,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "af-za",
|
||||
"localeID": "af_ZA",
|
||||
"pluralCat": function(n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
Vendored
+1
@@ -119,6 +119,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "af",
|
||||
"localeID": "af",
|
||||
"pluralCat": function(n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
+1
@@ -137,6 +137,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "agq-cm",
|
||||
"localeID": "agq_CM",
|
||||
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
Vendored
+1
@@ -137,6 +137,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "agq",
|
||||
"localeID": "agq",
|
||||
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
Vendored
+1
@@ -137,6 +137,7 @@ $provide.value("$locale", {
|
||||
]
|
||||
},
|
||||
"id": "ak-gh",
|
||||
"localeID": "ak_GH",
|
||||
"pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
|
||||
});
|
||||
}]);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user