Compare commits
289 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c6d04b3a3d | |||
| e31560cf6b | |||
| 3d38fff8b4 | |||
| bc492c0fc1 | |||
| 162144202c | |||
| 05596527ed | |||
| 5fea3471e8 | |||
| 131e4014b8 | |||
| 01c5be4681 | |||
| fd9a03e147 | |||
| 6c17d02bc4 | |||
| 6a6f71f238 | |||
| cf686285c2 | |||
| 7dfedb732d | |||
| 760f2fb731 | |||
| c9705b7556 | |||
| 53ec33f07f | |||
| 884ef0dbcd | |||
| 010413f90a | |||
| 4f57236614 | |||
| 50bf029625 | |||
| eff52ad877 | |||
| e9ee492d35 | |||
| e415e916e8 | |||
| 07084e1c8b | |||
| 186a591228 | |||
| a80049fd0a | |||
| d158dd131e | |||
| 1147f21999 | |||
| bddd46c8ec | |||
| 80e7a45584 | |||
| 498365f219 | |||
| 056c849352 | |||
| 7d6e5a2d01 | |||
| d1c4766d14 | |||
| 98473835a2 | |||
| 870232bd05 | |||
| c31df32ca0 | |||
| df2b88e230 | |||
| 83451d552e | |||
| af7203e0b8 | |||
| 98ee3719f9 | |||
| 94b5f2dadb | |||
| fe7decd1b0 | |||
| cef084ade9 | |||
| 937caab647 | |||
| 3fc8017119 | |||
| 54637a335f | |||
| 277a5ea05d | |||
| 9865a7c0ad | |||
| efba4731e4 | |||
| a965984733 | |||
| 14d3e559d4 | |||
| 3d156a76e3 | |||
| c7a1d1ab0b | |||
| 26d43cacdc | |||
| 4f5758e666 | |||
| 274a6734ef | |||
| f0e3dfd008 | |||
| bc3ff2cecd | |||
| 8f329ffb82 | |||
| 864b2596b2 | |||
| f3a796e522 | |||
| 09f8962df2 | |||
| a13c4ba770 | |||
| 040e743b39 | |||
| bf816d3ade | |||
| 74b4ab8867 | |||
| 6e2359caa0 | |||
| 41534816a4 | |||
| 30252a0504 | |||
| 3dc18037e8 | |||
| 57d50582aa | |||
| 73c66715c9 | |||
| cb29632a58 | |||
| 5c97731a22 | |||
| b2e472e7a2 | |||
| 6ac773f350 | |||
| 3174f73336 | |||
| 3c62e4244e | |||
| c432999572 | |||
| f8d319c11a | |||
| 4f72433392 | |||
| 2f91cfd0d2 | |||
| d5c5e2b584 | |||
| cbb3ce2c30 | |||
| 45af02de04 | |||
| 6144df52af | |||
| b0474cb984 | |||
| 9a4c9e6487 | |||
| 11fff8fa0d | |||
| da8ab2f928 | |||
| 6d01384a55 | |||
| 109ffac975 | |||
| 8c10db3847 | |||
| 03088d6010 | |||
| 18e0768a2b | |||
| ed4a1fddce | |||
| cfde6f507c | |||
| 3468ad1b61 | |||
| e9c79cad43 | |||
| e455e7d878 | |||
| 3410f65e79 | |||
| f3de5b6eac | |||
| fcd2a8131a | |||
| 62dbe85798 | |||
| 1d5e18b062 | |||
| a0ed371389 | |||
| 05e4fd3488 | |||
| 30a8b7d0b5 | |||
| f8944efe70 | |||
| 43072e3812 | |||
| 9396d55414 | |||
| 82e97cf53e | |||
| cf2a7614a4 | |||
| 9e538e7c31 | |||
| 4ac21ac039 | |||
| f69dc16241 | |||
| f1a8d419d5 | |||
| 8864e54f1f | |||
| dc4df93177 | |||
| 043190f397 | |||
| f4d850e168 | |||
| 8ec2743ca1 | |||
| ecbee8147b | |||
| f8c6ee3df5 | |||
| fe84f7bef8 | |||
| d653607162 | |||
| 082fe180ec | |||
| d3491083a5 | |||
| c3d6ca97e1 | |||
| a14266e464 | |||
| b4d44e1298 | |||
| ca116c35a6 | |||
| 78ba429e6a | |||
| dbf8c3c745 | |||
| 3602c9785b | |||
| acaac21fd1 | |||
| c98ef94706 | |||
| b0972a2e75 | |||
| 2dbb6f9a54 | |||
| 785a5fd7c1 | |||
| a55c1e79cf | |||
| d070450cd2 | |||
| 09648e4888 | |||
| 2adbcf189b | |||
| 39c5ffb2a6 | |||
| 04a570d31c | |||
| 958d3d56b1 | |||
| 0e50810c53 | |||
| 21e48abbc1 | |||
| b6d5439343 | |||
| 93901bdde4 | |||
| d802ed1b36 | |||
| e8f4305e9d | |||
| b38a2287f2 | |||
| 1e7675ad4c | |||
| 280b5ce3c0 | |||
| fbc5cf514b | |||
| f01087f802 | |||
| 4ac6424e87 | |||
| d3c486dd6d | |||
| 2d0f6ccba8 | |||
| 9a81b8668a | |||
| 9481d69d1c | |||
| 7615723547 | |||
| 338f949259 | |||
| d0192b31a3 | |||
| 6127528b50 | |||
| 0410572322 | |||
| fd2371cfc2 | |||
| 267fcc999c | |||
| 84187b6d94 | |||
| 5d6482bb3b | |||
| 023765c593 | |||
| 4a401bbcf3 | |||
| 7401c70718 | |||
| bb36bc7edf | |||
| bf1972dc1e | |||
| 689dfb1679 | |||
| 1169b54456 | |||
| 81b81856ee | |||
| fd4b99936e | |||
| 09271a8ab9 | |||
| 5a8d9acacb | |||
| 04d5a5072f | |||
| 55c30e1be6 | |||
| 97fc84c151 | |||
| 4ee0687f3f | |||
| ddff347b91 | |||
| 05ef1bd853 | |||
| d0f8bd30a6 | |||
| 1a8d3c8b3a | |||
| 753687e5c2 | |||
| 1a15c01b64 | |||
| 7f33e1ca89 | |||
| 28d00945ba | |||
| 6f40c88f47 | |||
| 68dd621082 | |||
| 3abfb4ef51 | |||
| 1014e52349 | |||
| cda061f723 | |||
| 1497c6c1fb | |||
| e41e445b51 | |||
| 7ab73190b7 | |||
| 450b3a5460 | |||
| 38fb542838 | |||
| 7ab5098c14 | |||
| bcca80548d | |||
| 736c8fbbae | |||
| 947562220d | |||
| 333523483f | |||
| 68ceb17272 | |||
| 5bd6596856 | |||
| b3f2a20832 | |||
| e8d8c7a8d7 | |||
| 7a91d7fa7e | |||
| c6bd58eb58 | |||
| c2e45c769e | |||
| b08427dde9 | |||
| ffd075b440 | |||
| 3fcd228441 | |||
| 8383ecfcdf | |||
| eed2333298 | |||
| a2809dacc4 | |||
| b837a31afa | |||
| 66b0fcd3c0 | |||
| 2efe82309a | |||
| a090400f09 | |||
| 84e0eea164 | |||
| bcf12e70e5 | |||
| 1ca98b2c09 | |||
| 3efdeebcb7 | |||
| 16febf8357 | |||
| 0f7c4ca671 | |||
| a3172a285f | |||
| 84c408ce63 | |||
| 40647b179c | |||
| 0421cb4200 | |||
| 6f1050df4f | |||
| 4d16472b91 | |||
| 9e89a31b12 | |||
| e6521e7491 | |||
| 0a7cbb33b0 | |||
| 579242346c | |||
| c42d0a0418 | |||
| 3fbb25e25c | |||
| 6760d7a315 | |||
| 062fbed8fc | |||
| 76e4db6f3d | |||
| 0cd7e8f227 | |||
| ba1b47f85b | |||
| 0a3481e23a | |||
| e33c365144 | |||
| e3ceb50b73 | |||
| 6b5772bbbd | |||
| 6288cf5ca4 | |||
| f6ecf9a3c9 | |||
| a4e6d962d7 | |||
| 7874a4d007 | |||
| 1d50663b38 | |||
| ec3c4f94c7 | |||
| 6b8bbe4d90 | |||
| 7067a8fb0b | |||
| c47abd0dd7 | |||
| 68d71bbc01 | |||
| 334303e485 | |||
| b95fd53c6e | |||
| c77dd040b4 | |||
| dc027f22e5 | |||
| 043500fb27 | |||
| 3ceb6ab477 | |||
| 999fa44616 | |||
| 5f9121ad56 | |||
| b4cf8483d7 | |||
| 8a9816e06b | |||
| c0e10683a6 | |||
| cad5a367c3 | |||
| f2453eabb3 | |||
| aa0b11d794 | |||
| b9fa5c5a67 | |||
| 751f058f30 | |||
| 29274e1d8d | |||
| 23ba287897 | |||
| 8f1e3606dd | |||
| ac56d1c9d9 | |||
| de2919cb9a | |||
| 61943276f0 | |||
| 88ce00a3cf |
@@ -17,3 +17,4 @@ angular.xcodeproj
|
||||
libpeerconnection.log
|
||||
npm-debug.log
|
||||
/tmp/
|
||||
/scripts/bower/bower-*
|
||||
|
||||
+9
-5
@@ -3,11 +3,16 @@ node_js:
|
||||
- 0.10
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- JOB=unit
|
||||
- JOB=e2e
|
||||
global:
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
|
||||
- BROWSER_STACK_USERNAME=VojtaJina
|
||||
- BROWSER_STACK_ACCESS_KEY=HAfHZaypxAc3PEUrUU9a
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- BROWSER_PROVIDER_READY_FILE=/tmp/sauce-connect-ready
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
@@ -16,11 +21,10 @@ before_script:
|
||||
- grunt bower
|
||||
- grunt bower
|
||||
- grunt package-without-bower
|
||||
- grunt ci-checks
|
||||
- ./lib/sauce/sauce_connect_block.sh
|
||||
- ./scripts/travis/wait_for_browser_provider.sh
|
||||
|
||||
script:
|
||||
- ./travis_build.sh
|
||||
- ./scripts/travis/build.sh
|
||||
|
||||
after_script:
|
||||
- ./travis_print_logs.sh
|
||||
- ./scripts/travis/print_logs.sh
|
||||
|
||||
+345
@@ -1,3 +1,345 @@
|
||||
<a name="1.2.7"></a>
|
||||
# 1.2.7 emoji-clairvoyance (2014-01-03)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensue class-based animations are always skipped before structural post-digest tasks are run
|
||||
([bc492c0f](https://github.com/angular/angular.js/commit/bc492c0fc17257ddf2bc5964e205379aa766b3d8),
|
||||
[#5582](https://github.com/angular/angular.js/issues/5582))
|
||||
- remove trailing `s` from computed transition duration styles
|
||||
([50bf0296](https://github.com/angular/angular.js/commit/50bf029625d603fc652f0f413e709f43803743db))
|
||||
- **$http:**
|
||||
([3d38fff8](https://github.com/angular/angular.js/commit/3d38fff8b4ea2fd60fadef2028ea4dcddfccb1a4))
|
||||
- use ActiveX XHR when making PATCH requests on IE8
|
||||
([6c17d02b](https://github.com/angular/angular.js/commit/6c17d02bc4cc02f478775d62e1f9f77da9da82ad),
|
||||
[#2518](https://github.com/angular/angular.js/issues/2518), [#5043](https://github.com/angular/angular.js/issues/5043))
|
||||
- fix 'type mismatch' error on IE8 after each request
|
||||
([fd9a03e1](https://github.com/angular/angular.js/commit/fd9a03e147aac7e952c6dda1f381fd4662276ba2))
|
||||
- Ignore multiple calls to onreadystatechange with readyState=4
|
||||
([4f572366](https://github.com/angular/angular.js/commit/4f57236614415eea919221ea5f99c4d8689b3267),
|
||||
[#5426](https://github.com/angular/angular.js/issues/5426))
|
||||
- **$injector:** remove the `INSTANTIATING` flag properly when done
|
||||
([186a5912](https://github.com/angular/angular.js/commit/186a5912288acfff0ee59dae29af83c37c987921),
|
||||
[#4361](https://github.com/angular/angular.js/issues/4361), [#5577](https://github.com/angular/angular.js/issues/5577))
|
||||
- **$location:**
|
||||
- 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
|
||||
([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
|
||||
([bddd46c8](https://github.com/angular/angular.js/commit/bddd46c8ecf49cfe6c999cd6b4a69b7d7e1f9a33),
|
||||
[#5425](https://github.com/angular/angular.js/issues/5425))
|
||||
- **$resource:** prevent URL template from collapsing into an empty string
|
||||
([131e4014](https://github.com/angular/angular.js/commit/131e4014b831ac81b7979c4523da81ebc5861c70),
|
||||
[#5455](https://github.com/angular/angular.js/issues/5455), [#5493](https://github.com/angular/angular.js/issues/5493))
|
||||
- **$sanitize:** consider the `size` attribute as a valid/allowed attribute
|
||||
([056c8493](https://github.com/angular/angular.js/commit/056c8493521988dbb330c6636135b505737da918),
|
||||
[#5522](https://github.com/angular/angular.js/issues/5522))
|
||||
- **Scope:** don't let watch deregistration mess up the dirty-checking digest loop
|
||||
([884ef0db](https://github.com/angular/angular.js/commit/884ef0dbcdfe614cedc824d079361b53e675d033),
|
||||
[#5525](https://github.com/angular/angular.js/issues/5525))
|
||||
- **input:**
|
||||
- use apply on the change event only when one isn't already in progress
|
||||
([a80049fd](https://github.com/angular/angular.js/commit/a80049fd0ac858eeeb645a4209cb2a661d0b4c33),
|
||||
[#5293](https://github.com/angular/angular.js/issues/5293))
|
||||
- prevent double $digest when using jQuery trigger.
|
||||
([1147f219](https://github.com/angular/angular.js/commit/1147f21999edf9a434cd8d24865a6455e744d858),
|
||||
[#5293](https://github.com/angular/angular.js/issues/5293))
|
||||
- **ngRepeat:** allow for more flexible coding style in ngRepeat expression
|
||||
([c9705b75](https://github.com/angular/angular.js/commit/c9705b755645a4bfe066243f2ba15a733c3787e1),
|
||||
[#5537](https://github.com/angular/angular.js/issues/5537), [#5598](https://github.com/angular/angular.js/issues/5598))
|
||||
- **ngRoute:** instantiate controller when template is empty
|
||||
([498365f2](https://github.com/angular/angular.js/commit/498365f219f65d6c29bdf2f03610a4d3646009bb),
|
||||
[#5550](https://github.com/angular/angular.js/issues/5550))
|
||||
- **ngShow/ngHide, ngIf:** functions with zero args should be truthy
|
||||
([01c5be46](https://github.com/angular/angular.js/commit/01c5be4681e34cdc5f5c461b7a618fefe8038919),
|
||||
[#5414](https://github.com/angular/angular.js/issues/5414))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **Scope:** limit propagation of $broadcast to scopes that have listeners for the event
|
||||
([80e7a455](https://github.com/angular/angular.js/commit/80e7a4558490f7ffd33d142844b9153a5ed00e86),
|
||||
[#5341](https://github.com/angular/angular.js/issues/5341), [#5371](https://github.com/angular/angular.js/issues/5371))
|
||||
|
||||
<a name="1.2.6"></a>
|
||||
# 1.2.6 taco-salsafication (2013-12-19)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:** use a scheduled timeout in favor of a fallback property to close transitions
|
||||
([54637a33](https://github.com/angular/angular.js/commit/54637a335f885110efaa702a3bab29c77644b36c),
|
||||
[#5255](https://github.com/angular/angular.js/issues/5255), [#5241](https://github.com/angular/angular.js/issues/5241), [#5405](https://github.com/angular/angular.js/issues/5405))
|
||||
- **$compile:** remove invalid IE exceptional case for `href`
|
||||
([c7a1d1ab](https://github.com/angular/angular.js/commit/c7a1d1ab0b663edffc1ac7b54deea847e372468d),
|
||||
[#5479](https://github.com/angular/angular.js/issues/5479))
|
||||
- **$location:** parse xlink:href for SVGAElements
|
||||
([bc3ff2ce](https://github.com/angular/angular.js/commit/bc3ff2cecd0861766a9e8606f3cc2c582d9875df),
|
||||
[#5472](https://github.com/angular/angular.js/issues/5472), [#5198](https://github.com/angular/angular.js/issues/5198), [#5199](https://github.com/angular/angular.js/issues/5199), [#4098](https://github.com/angular/angular.js/issues/4098), [#1420](https://github.com/angular/angular.js/issues/1420))
|
||||
- **$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`
|
||||
([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`
|
||||
([8f329ffb](https://github.com/angular/angular.js/commit/8f329ffb829410e1fd8f86a766929134e736e3e5),
|
||||
[#5475](https://github.com/angular/angular.js/issues/5475))
|
||||
- **forEach:** allow looping over result of `querySelectorAll` in IE8
|
||||
([274a6734](https://github.com/angular/angular.js/commit/274a6734ef1fff543cc50388a0958d1988baeb57))
|
||||
- **input:** do not hold input for composition on Android
|
||||
([3dc18037](https://github.com/angular/angular.js/commit/3dc18037e8db8766641a4d39f0fee96077db1fcb),
|
||||
[#5308](https://github.com/angular/angular.js/issues/5308))
|
||||
- **jqLite:** support unbind self within handler
|
||||
([2f91cfd0](https://github.com/angular/angular.js/commit/2f91cfd0d2986899c38641100c1851b2f9d3888a))
|
||||
- **ngRepeat:** allow multiline expressions
|
||||
([cbb3ce2c](https://github.com/angular/angular.js/commit/cbb3ce2c309052b951d0cc87e4c6daa9c48a3dd8),
|
||||
[#5000](https://github.com/angular/angular.js/issues/5000))
|
||||
- **select:** invalidate when `multiple`, `required`, and model is `[]`
|
||||
([5c97731a](https://github.com/angular/angular.js/commit/5c97731a22ed87d64712e673efea0e8a05eae65f),
|
||||
[#5337](https://github.com/angular/angular.js/issues/5337))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **jqLite:** provide support for `element.one()`
|
||||
([937caab6](https://github.com/angular/angular.js/commit/937caab6475e53a7ea0206e992f8a52449232e78))
|
||||
- **ngAnimate:** provide configuration support to match specific className values to trigger animations
|
||||
([cef084ad](https://github.com/angular/angular.js/commit/cef084ade9072090259d8c679751cac3ffeaed51),
|
||||
[#5357](https://github.com/angular/angular.js/issues/5357), [#5283](https://github.com/angular/angular.js/issues/5283))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **compile:** add class 'ng-scope' before cloning and other micro-optimizations
|
||||
([f3a796e5](https://github.com/angular/angular.js/commit/f3a796e522afdbd3b640d14426edb2fbfab463c5),
|
||||
[#5471](https://github.com/angular/angular.js/issues/5471))
|
||||
- **$parse:** use a faster path when the number of path parts is low
|
||||
([f4462319](https://github.com/angular/angular.js/commit/864b2596b246470cca9d4e223eaed720f4462319))
|
||||
- use faster check for `$$` prefix
|
||||
([06c5cfc7](https://github.com/angular/angular.js/commit/cb29632a5802e930262919b3db64ca4806c5cfc7))
|
||||
|
||||
<a name="1.2.5"></a>
|
||||
# 1.2.5 singularity-expansion (2013-12-13)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** allow literals in isolate scope references
|
||||
([43072e38](https://github.com/angular/angular.js/commit/43072e3812e32b89b97ad03144577cba50d4b776),
|
||||
[#5296](https://github.com/angular/angular.js/issues/5296))
|
||||
- **angular-mocks:** use copy of mock data in $httpBackend
|
||||
([f69dc162](https://github.com/angular/angular.js/commit/f69dc16241c8b631123ad0b09674f0a5e0ff32fe))
|
||||
- **closure:** add missing FormController extern definitions
|
||||
([1d5e18b0](https://github.com/angular/angular.js/commit/1d5e18b062c3e33b2a8d96aa58d905ed2cd48649),
|
||||
[#5303](https://github.com/angular/angular.js/issues/5303))
|
||||
- **ngInclude:** add template to DOM before linking other directives
|
||||
([30a8b7d0](https://github.com/angular/angular.js/commit/30a8b7d0b5d4882c2bf3b20eb696a02f5b667726),
|
||||
[#5247](https://github.com/angular/angular.js/issues/5247))
|
||||
- **ngView:** add template to DOM before linking other directives
|
||||
([f8944efe](https://github.com/angular/angular.js/commit/f8944efe70b81e02704df9b53ea2546c80c73d3b))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$injector:** remove invoke optimization that doesn't work
|
||||
([05e4fd34](https://github.com/angular/angular.js/commit/05e4fd3488b89e670c36869f18defe26deac2efa),
|
||||
[#5388](https://github.com/angular/angular.js/issues/5388))
|
||||
- **$resource:** use shallow copy instead of angular.copy
|
||||
([fcd2a813](https://github.com/angular/angular.js/commit/fcd2a8131a3cb3e59a616bf31e61510b5c3a97d3),
|
||||
[#5300](https://github.com/angular/angular.js/issues/5300))
|
||||
- **a:** do not link when href or name exists in template
|
||||
([f3de5b6e](https://github.com/angular/angular.js/commit/f3de5b6eac90baf649506072162f36dbc6d2f028),
|
||||
[#5362](https://github.com/angular/angular.js/issues/5362))
|
||||
- **jqLite:** implement and use the `empty` method in place of `html(‘’)`
|
||||
([3410f65e](https://github.com/angular/angular.js/commit/3410f65e790a81d457b4f4601a1e760a6f8ede5e),
|
||||
[#4457](https://github.com/angular/angular.js/issues/4457))
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **angular-mocks:** due to [f69dc162](https://github.com/angular/angular.js/commit/f69dc16241c8b631123ad0b09674f0a5e0ff32fe),
|
||||
some tests that rely on identity comparison rather than equality comparison in checking mock http responses will be broken,
|
||||
since now each mock response is a copy of the original response. This is usually fixable by changing a `.toBe()` comparison
|
||||
to `toEqual()` inside of tests.
|
||||
|
||||
<a name="1.2.4"></a>
|
||||
# 1.2.4 wormhole-blaster (2013-12-06)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensure animations work with directives that share a transclusion
|
||||
([958d3d56](https://github.com/angular/angular.js/commit/958d3d56b1899a2cfc7b18c0292e5a1d8c64d0a5),
|
||||
[#4716](https://github.com/angular/angular.js/issues/4716), [#4871](https://github.com/angular/angular.js/issues/4871), [#5021](https://github.com/angular/angular.js/issues/5021), [#5278](https://github.com/angular/angular.js/issues/5278))
|
||||
- ensure ms durations are properly rounded
|
||||
([93901bdd](https://github.com/angular/angular.js/commit/93901bdde4bb9f0ba114ebb33b8885808e1823e1),
|
||||
[#5113](https://github.com/angular/angular.js/issues/5113), [#5162](https://github.com/angular/angular.js/issues/5162))
|
||||
- **$compile:**
|
||||
- update cloned elements if the template arrives after the cloning
|
||||
([b0972a2e](https://github.com/angular/angular.js/commit/b0972a2e75909e41dbac6e4413ada7df2d51df3a))
|
||||
- ensure the isolated local watch `lastValue` is always in sync
|
||||
([2d0f6ccb](https://github.com/angular/angular.js/commit/2d0f6ccba896fe34141d6d4f59eef6fba580c5c2),
|
||||
[#5182](https://github.com/angular/angular.js/issues/5182))
|
||||
- **$rootScope:**
|
||||
- ensure that when the $destroy event is broadcast on $rootScope that it does something
|
||||
([d802ed1b](https://github.com/angular/angular.js/commit/d802ed1b3680cfc1751777fac465b92ee29944dc),
|
||||
[#5169](https://github.com/angular/angular.js/issues/5169))
|
||||
- ensure the phase is cleared within a digest if an exception is raised by a watcher
|
||||
([d3c486dd](https://github.com/angular/angular.js/commit/d3c486dd6dfa8d5dca32a3e28aa685fb7260c878))
|
||||
- **$sanitize:** don't rely on YARR regex engine executing immediately in order to prevent object mutation
|
||||
([81b81856](https://github.com/angular/angular.js/commit/81b81856ee43d2876927c4e1f774affa87e99707),
|
||||
[#5193](https://github.com/angular/angular.js/issues/5193), [#5192](https://github.com/angular/angular.js/issues/5192))
|
||||
- **closure:** closure compiler shouldn't rename .defaults.transformRequest
|
||||
([f01087f8](https://github.com/angular/angular.js/commit/f01087f802839637843115cbcf99702e09d866f6))
|
||||
- **input:** ensure ngModelWatch() triggers second digest pass when appropriate
|
||||
([b6d54393](https://github.com/angular/angular.js/commit/b6d5439343b9801f7f2a009d0de09cba9aa21a1d),
|
||||
[#5258](https://github.com/angular/angular.js/issues/5258), [#5282](https://github.com/angular/angular.js/issues/5282))
|
||||
- **isElement:** return boolean value rather than `truthy` value.
|
||||
([2dbb6f9a](https://github.com/angular/angular.js/commit/2dbb6f9a54eb5ff5847eed11c85ac4cf119eb41c),
|
||||
[#4519](https://github.com/angular/angular.js/issues/4519), [#4534](https://github.com/angular/angular.js/issues/4534))
|
||||
- **jqLite:** ignore incompatible nodes on find()
|
||||
([1169b544](https://github.com/angular/angular.js/commit/1169b5445691e1495354d235a3badf05240e3904),
|
||||
[#4120](https://github.com/angular/angular.js/issues/4120))
|
||||
- **ngInit:** evaluate ngInit before ngInclude
|
||||
([0e50810c](https://github.com/angular/angular.js/commit/0e50810c53428f4c1f5bfdba9599df54cb7a6c6e),
|
||||
[#5167](https://github.com/angular/angular.js/issues/5167), [#5208](https://github.com/angular/angular.js/issues/5208))
|
||||
- **ngSanitize:** prefer textContent to innerText to avoid layout trashing
|
||||
([bf1972dc](https://github.com/angular/angular.js/commit/bf1972dc1e8ffbeaddfa53df1d49bc5a2177f09c))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$parse:** micro-optimization for ensureSafeObject function
|
||||
([689dfb16](https://github.com/angular/angular.js/commit/689dfb167924a61aef444ce7587fb987d8080990),
|
||||
[#5246](https://github.com/angular/angular.js/issues/5246))
|
||||
- **Scope:** short-circuit after dirty-checking last dirty watcher
|
||||
([d070450c](https://github.com/angular/angular.js/commit/d070450cd2b3b3a3aa34b69d3fa1f4cc3be025dd),
|
||||
[#5272](https://github.com/angular/angular.js/issues/5272), [#5287](https://github.com/angular/angular.js/issues/5287))
|
||||
|
||||
|
||||
|
||||
<a name="1.2.3"></a>
|
||||
# 1.2.3 unicorn-zapper (2013-11-27)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensure blocked keyframe animations are unblocked before the DOM operation
|
||||
([2efe8230](https://github.com/angular/angular.js/commit/2efe82309ac8ff4f67df8b6e40a539ea31e15804),
|
||||
[#5106](https://github.com/angular/angular.js/issues/5106))
|
||||
- ensure animations are disabled during bootstrap to prevent unwanted structural animations
|
||||
([eed23332](https://github.com/angular/angular.js/commit/eed2333298412fbad04eda97ded3487c845b9eb9),
|
||||
[#5130](https://github.com/angular/angular.js/issues/5130))
|
||||
- **$sanitize:** use the same whitelist mechanism as `$compile` does
|
||||
([33352348](https://github.com/angular/angular.js/commit/333523483f3ce6dd3177b697a5e5a7177ca364c8),
|
||||
[#3748](https://github.com/angular/angular.js/issues/3748))
|
||||
- **input:** react to form auto completion, through the `change` event, on modern browsers
|
||||
([a090400f](https://github.com/angular/angular.js/commit/a090400f09d7993d102f527609879cdc74abae60),
|
||||
[#1460](https://github.com/angular/angular.js/issues/1460))
|
||||
- **$attrs:** add `$attrs.$attr` to externs so that it isn't renamed on js minification
|
||||
([bcca8054](https://github.com/angular/angular.js/commit/bcca80548dde85ffe3838c943ba8e5c2deb1c721))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
No new features in this release
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
There are no breaking changes in this release (promise!)
|
||||
|
||||
|
||||
|
||||
<a name="1.2.2"></a>
|
||||
# 1.2.2 consciousness-inertia (2013-11-22)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- ensure keyframe animations are blocked around the reflow
|
||||
([6760d7a3](https://github.com/angular/angular.js/commit/6760d7a315d7ea5cbd4f8ab74b200f754a2041f4),
|
||||
[#5018](https://github.com/angular/angular.js/issues/5018))
|
||||
- ensure transition animations are unblocked before the dom operation occurs
|
||||
([062fbed8](https://github.com/angular/angular.js/commit/062fbed8fc3f7bc55433f8c6915c27520e6f63c5),
|
||||
[#5014](https://github.com/angular/angular.js/issues/5014),
|
||||
[#4265](https://github.com/angular/angular.js/issues/4265))
|
||||
- ensure addClass/removeClass animations do not snap during reflow
|
||||
([76e4db6f](https://github.com/angular/angular.js/commit/76e4db6f3d15199ac1fbe85f9cfa6079a1c4fa56),
|
||||
[#4892](https://github.com/angular/angular.js/issues/4892))
|
||||
- ensure the DOM operation isn't run twice
|
||||
([7067a8fb](https://github.com/angular/angular.js/commit/7067a8fb0b18d5b5489006e1960cee721a88b4d2),
|
||||
[#4949](https://github.com/angular/angular.js/issues/4949))
|
||||
- **$compile:**
|
||||
- secure form[action] & iframe[srcdoc]
|
||||
([0421cb42](https://github.com/angular/angular.js/commit/0421cb4200e672818ed10996e92311404c150c3a),
|
||||
[#4927](https://github.com/angular/angular.js/issues/4927),
|
||||
[#4933](https://github.com/angular/angular.js/issues/4933))
|
||||
- ensure CSS classes are added and removed only when necessary
|
||||
([0cd7e8f2](https://github.com/angular/angular.js/commit/0cd7e8f22721f62b62440bb059ae764ebbe7b42a))
|
||||
- **$httpBackend:** only IE8 and below can't use `script.onload` for JSONP
|
||||
([a3172a28](https://github.com/angular/angular.js/commit/a3172a285fd74b5aa6c8d68a4988c767c06f549c),
|
||||
[#4523](https://github.com/angular/angular.js/issues/4523),
|
||||
[#4527](https://github.com/angular/angular.js/issues/4527),
|
||||
[#4922](https://github.com/angular/angular.js/issues/4922))
|
||||
- **$parse:** allow for new lines in expr when promise unwrapping is on
|
||||
([40647b17](https://github.com/angular/angular.js/commit/40647b179c473f3f470bb1b3237d6f006269582f),
|
||||
[#4718](https://github.com/angular/angular.js/issues/4718))
|
||||
- **$resource:** Always return a resource instance when calling class methods on resources.
|
||||
([f6ecf9a3](https://github.com/angular/angular.js/commit/f6ecf9a3c9090593faf5fa50586c99a56b51c776),
|
||||
[#4545](https://github.com/angular/angular.js/issues/4545),
|
||||
[#5061](https://github.com/angular/angular.js/issues/5061))
|
||||
- **httpBackend:** should not read response data when request is aborted
|
||||
([6f1050df](https://github.com/angular/angular.js/commit/6f1050df4fa885bd59ce85adbef7350ea93911a3),
|
||||
[#4913](https://github.com/angular/angular.js/issues/4913),
|
||||
[#4940](https://github.com/angular/angular.js/issues/4940))
|
||||
- **loader:** expose `$$minErr` to modules such as`ngResource`
|
||||
([9e89a31b](https://github.com/angular/angular.js/commit/9e89a31b129e40c805178535c244899ffafb77d8),
|
||||
[#5050](https://github.com/angular/angular.js/issues/5050))
|
||||
- **ngAnimate:**
|
||||
- correctly retain and restore existing styles during and after animation
|
||||
([c42d0a04](https://github.com/angular/angular.js/commit/c42d0a041890b39fc98afd357ec1307a3a36208d),
|
||||
[#4869](https://github.com/angular/angular.js/issues/4869))
|
||||
- use a fallback CSS property that doesn't break existing styles
|
||||
([1d50663b](https://github.com/angular/angular.js/commit/1d50663b38ba042e8d748ffa6d48cfb5e93cfd7e),
|
||||
[#4902](https://github.com/angular/angular.js/issues/4902),
|
||||
[#5030](https://github.com/angular/angular.js/issues/5030))
|
||||
- **ngClass:** ensure that ngClass only adds/removes the changed classes
|
||||
([6b8bbe4d](https://github.com/angular/angular.js/commit/6b8bbe4d90640542eed5607a8c91f6b977b1d6c0),
|
||||
[#4960](https://github.com/angular/angular.js/issues/4960),
|
||||
[#4944](https://github.com/angular/angular.js/issues/4944))
|
||||
- **ngController:** fix issue with ngInclude on the same element
|
||||
([6288cf5c](https://github.com/angular/angular.js/commit/6288cf5ca471b0615a026fdb4db3ba242c9d8f88),
|
||||
[#4431](https://github.com/angular/angular.js/issues/4431))
|
||||
- **ngInclude:**
|
||||
- Don't throw when the ngInclude element contains content with directives.
|
||||
([0a7cbb33](https://github.com/angular/angular.js/commit/0a7cbb33b06778833a4d99b1868cc07690a827a7))
|
||||
- allow ngInclude to load scripts when jQuery is included
|
||||
([c47abd0d](https://github.com/angular/angular.js/commit/c47abd0dd7490576f4b84ee51ebaca385c1036da),
|
||||
[#3756](https://github.com/angular/angular.js/issues/3756))
|
||||
- **ngMock:** fixes httpBackend expectation with body object
|
||||
([4d16472b](https://github.com/angular/angular.js/commit/4d16472b918a3482942d76f1e273a5aa01f65e83),
|
||||
[#4956](https://github.com/angular/angular.js/issues/4956))
|
||||
- **ngView:** Don't throw when the ngView element contains content with directives.
|
||||
([e6521e74](https://github.com/angular/angular.js/commit/e6521e7491242504250b57dd0ee66af49e653c33),
|
||||
[#5069](https://github.com/angular/angular.js/issues/5069))
|
||||
- **tests:** Correct tests for IE11
|
||||
([57924234](https://github.com/angular/angular.js/commit/579242346c4202ea58fc2cae6df232289cbea0bb),
|
||||
[#5046](https://github.com/angular/angular.js/issues/5046))
|
||||
- **input:** hold listener during text composition
|
||||
([a4e6d962](https://github.com/angular/angular.js/commit/a4e6d962d78b26f5112d48c4f88c1e6234d0cae7),
|
||||
[#4684](https://github.com/angular/angular.js/issues/4684))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.2.1"></a>
|
||||
# 1.2.1 underscore-empathy (2013-11-14)
|
||||
|
||||
@@ -4110,3 +4452,6 @@ with the `$route` service
|
||||
[module]: http://docs-next.angularjs.org/api/angular.mock.module
|
||||
[guide2.di]: http://docs-next.angularjs.org/guide/dev_guide.di
|
||||
[jqLite2]: http://docs.angularjs.org/#!/api/angular.element
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
+111
-64
@@ -29,32 +29,124 @@ duplication of work, and help you to craft the change so that it is successfully
|
||||
project.
|
||||
* **Small Changes** can be crafted and submitted to [GitHub Repository][github] as a Pull Request.
|
||||
|
||||
|
||||
## Want a Doc Fix?
|
||||
If you want to help improve the docs, it's a good idea to let others know what you're working on to
|
||||
minimize duplication of effort. Before starting, check out the issue queue for [Milestone:Docs Only](https://github.com/angular/angular.js/issues?milestone=24&state=open).
|
||||
Comment on an issue to let others know what you're working on, or create a new issue if your work
|
||||
doesn't fit within the scope of any of the existing doc fix projects.
|
||||
|
||||
For large fixes, please build and test the documentation before submitting the PR to be sure you haven't
|
||||
accidentally introduced any layout or formatting issues.You should also make sure that your commit message
|
||||
is labeled "docs:" and follows the **Git Commit Guidelines** outlined below.
|
||||
|
||||
If you're just making a small change, don't worry about filing an issue first. Use the friendly blue "Improve this doc" button at the top right of the doc page to fork the repository in-place and make a quick change on the fly.
|
||||
|
||||
## Submission Guidelines
|
||||
|
||||
### Submitting an Issue
|
||||
Before you submit your issue follow the following guidelines:
|
||||
|
||||
* Search the archive first, it's likely that your question was already answered.
|
||||
* A live example demonstrating the issue, will get an answer faster.
|
||||
* Create one using [Plunker][plunker] or [JSFiddle][jsfiddle].
|
||||
* If you get help, help others. Good karma rulez!
|
||||
Before you submit your issue search the archive, maybe your question was already answered.
|
||||
|
||||
If your issue appears to be a bug, and hasn't been reported, open a new issue.
|
||||
Help us to maximize the effort we can spend fixing issues and adding new
|
||||
features, by not reporting duplicate issues.
|
||||
features, by not reporting duplicate issues. Providing the following information will increase the
|
||||
chances of your issue being dealt with quickly:
|
||||
|
||||
* **Overview of the issue** - if an error is being thrown a non-minified stack trace helps
|
||||
* **Motivation for or Use Case** - explain why this is a bug for you
|
||||
* **Angular Version(s)** - is it a regression?
|
||||
* **Browsers and Operating System** - is this a problem with all browsers or only IE8?
|
||||
* **Reproduce the error** - provide a live example (using [Plunker][plunker] or
|
||||
[JSFiddle][jsfiddle]) or a unambiguous set of steps.
|
||||
* **Related issues** - has a similar issue been reported before?
|
||||
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
|
||||
causing the problem (line of code or commit)
|
||||
|
||||
Here is a great example of a well defined issue: https://github.com/angular/angular.js/issues/5069
|
||||
|
||||
**If you get help, help others. Good karma rulez!**
|
||||
|
||||
### Submitting a Pull Request
|
||||
Before you submit your pull request follow the following guidelines:
|
||||
Before you submit your pull request consider the following guidelines:
|
||||
|
||||
* Search GitHub for an open or closed Pull Request that relates to your submission. You don't want
|
||||
to duplicate effort.
|
||||
* Search [GitHub](https://github.com/angular/angular.js/pulls) for an open or closed Pull Request
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* Please sign our [Contributor License Agreement (CLA)](#signing-the-cla) before sending pull
|
||||
requests. We cannot accept code without this.
|
||||
* Make your changes in a new git branch
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
* Create your patch, including appropriate test cases.
|
||||
* Follow our Coding Rules
|
||||
* Follow our Git Commit Guidelines
|
||||
* Build your changes locally and on Travis (by pushing to GitHub) to ensure all the tests pass.
|
||||
* Sign the Contributor License Agreement (CLA). We cannot accept code without this.
|
||||
* Commit your changes and create a descriptive commit message (the
|
||||
commit message is used to generate release notes, please check out our
|
||||
[commit message conventions](#commit-message-format) and our commit message presubmit hook
|
||||
`validate-commit-msg.js`):
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
|
||||
* Build your changes locally to ensure all the tests pass
|
||||
|
||||
```shell
|
||||
grunt test
|
||||
```
|
||||
|
||||
* Push your branch to Github:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
* In Github, send a pull request to `angular:master`.
|
||||
* If we suggest changes then you can modify your branch, rebase and force a new push to your GitHub
|
||||
repository to update the Pull Request.
|
||||
repository to update the Pull Request:
|
||||
|
||||
```shell
|
||||
git rebase master -i
|
||||
git push -f
|
||||
```
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
When the patch is reviewed and merged, you can safely delete your branch and pull the changes
|
||||
from the main (upstream) repository:
|
||||
|
||||
* Delete the remote branch on Github:
|
||||
|
||||
```shell
|
||||
git push origin --delete my-fix-branch
|
||||
```
|
||||
|
||||
* Check out the master branch:
|
||||
|
||||
```shell
|
||||
git checkout master -f
|
||||
```
|
||||
|
||||
* Delete the local branch:
|
||||
|
||||
```shell
|
||||
git branch -D my-fix-branch
|
||||
```
|
||||
|
||||
* Update your master with the latest upstream version:
|
||||
|
||||
```shell
|
||||
git pull --ff upstream master
|
||||
```
|
||||
|
||||
### GitHub Pull Request Helper
|
||||
|
||||
We track Pull Requests by attaching labels and assigning to milestones. For some reason GitHub
|
||||
does not provide a good UI for managing labels on Pull Requests (unlike Issues). We have developed
|
||||
a simple Chrome Extension that enables you to view (and manage if you have permission) the labels
|
||||
on Pull Requests. You can get the extension from the Chrome WebStore -
|
||||
[GitHub PR Helper][github-pr-helper]
|
||||
|
||||
## Coding Rules
|
||||
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
||||
@@ -106,6 +198,7 @@ Must be one of the following:
|
||||
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
|
||||
semi-colons, etc)
|
||||
* **refactor**: A code change that neither fixes a bug or adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
@@ -146,56 +239,6 @@ You can find out more detailed information about contributing in the
|
||||
[AngularJS documentation][contributing].
|
||||
|
||||
|
||||
## Submitting Your Changes
|
||||
|
||||
To create and submit a change:
|
||||
|
||||
1. Please sign our [Contributor License Agreement (CLA)](#signing-the-cla) before sending pull
|
||||
requests.
|
||||
|
||||
2. Create and checkout a new branch off the master branch for your changes:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
3. Create your patch, including appropriate test cases.
|
||||
|
||||
4. Commit your changes and create a descriptive commit message (the commit message is used to
|
||||
generate release notes, please check out our [commit message conventions](#commit-message-format)
|
||||
and our commit message presubmit hook `validate-commit-msg.js`):
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
|
||||
5. Push your branch to Github:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
6. In Github, send a pull request to `angular:master`.
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
When the patch is reviewed and merged, you can safely delete your branch and pull the changes
|
||||
from the main (upstream) repository:
|
||||
|
||||
```shell
|
||||
# Delete the remote branch on Github:
|
||||
git push origin :my-fix-branch
|
||||
|
||||
# Check out the master branch:
|
||||
git checkout master
|
||||
|
||||
# Delete the local branch:
|
||||
git branch -D my-fix-branch
|
||||
|
||||
# Update your master with the latest upstream version:
|
||||
git pull --ff upstream master
|
||||
```
|
||||
|
||||
|
||||
[github]: https://github.com/angular/angular.js
|
||||
[Google Closure I18N library]: https://code.google.com/p/closure-library/source/browse/closure/goog/i18n/
|
||||
@@ -214,3 +257,7 @@ git pull --ff upstream master
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
||||
[corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
+15
-12
@@ -4,6 +4,7 @@ var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
grunt.loadNpmTasks('grunt-bump');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
@@ -106,45 +107,38 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true,
|
||||
},
|
||||
ng: {
|
||||
files: { src: files['angularSrc'] },
|
||||
options: { jshintrc: 'src/.jshintrc' }
|
||||
},
|
||||
ngAnimate: {
|
||||
files: { src: 'src/ngAnimate/**/*.js' },
|
||||
options: { jshintrc: 'src/ngAnimate/.jshintrc' }
|
||||
},
|
||||
ngCookies: {
|
||||
files: { src: 'src/ngCookies/**/*.js' },
|
||||
options: { jshintrc: 'src/ngCookies/.jshintrc' }
|
||||
},
|
||||
ngLocale: {
|
||||
files: { src: 'src/ngLocale/**/*.js' },
|
||||
options: { jshintrc: 'src/ngLocale/.jshintrc' }
|
||||
},
|
||||
ngMock: {
|
||||
files: { src: 'src/ngMock/**/*.js' },
|
||||
options: { jshintrc: 'src/ngMock/.jshintrc' }
|
||||
},
|
||||
ngResource: {
|
||||
files: { src: 'src/ngResource/**/*.js' },
|
||||
options: { jshintrc: 'src/ngResource/.jshintrc' }
|
||||
},
|
||||
ngRoute: {
|
||||
files: { src: 'src/ngRoute/**/*.js' },
|
||||
options: { jshintrc: 'src/ngRoute/.jshintrc' }
|
||||
},
|
||||
ngSanitize: {
|
||||
files: { src: 'src/ngSanitize/**/*.js' },
|
||||
options: { jshintrc: 'src/ngSanitize/.jshintrc' }
|
||||
},
|
||||
ngScenario: {
|
||||
files: { src: 'src/ngScenario/**/*.js' },
|
||||
options: { jshintrc: 'src/ngScenario/.jshintrc' }
|
||||
},
|
||||
ngTouch: {
|
||||
files: { src: 'src/ngTouch/**/*.js' },
|
||||
options: { jshintrc: 'src/ngTouch/.jshintrc' }
|
||||
}
|
||||
},
|
||||
|
||||
@@ -178,7 +172,7 @@ module.exports = function(grunt) {
|
||||
},
|
||||
mocks: {
|
||||
dest: 'build/angular-mocks.js',
|
||||
src: files['angularModules']['ngMock'],
|
||||
src: util.wrap(files['angularModules']['ngMock'], 'module'),
|
||||
strict: false
|
||||
},
|
||||
sanitize: {
|
||||
@@ -275,6 +269,15 @@ module.exports = function(grunt) {
|
||||
write: {
|
||||
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
|
||||
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
|
||||
},
|
||||
|
||||
bump: {
|
||||
options: {
|
||||
files: ['package.json'],
|
||||
commit: false,
|
||||
createTag: false,
|
||||
push: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -294,6 +297,6 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
@@ -38,3 +38,7 @@ To execute end-to-end (e2e) tests, use:
|
||||
|
||||
To learn more about the grunt tasks, run `grunt --help` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# Triage new issues/PRs on github
|
||||
|
||||
This document shows the steps the Angular team is using to triage issues.
|
||||
The labels are used later on for planning releases.
|
||||
|
||||
## Tips ##
|
||||
|
||||
* install [github pr helper extension](https://github.com/petebacondarwin/github-pr-helper) and become 356% more productive
|
||||
* Label "resolution:*"
|
||||
* these tags can be used for labeling a closed issue/PR with a reason why it was closed. (we can add reasons as we need them, right there are only a few rejection reasons. it doesn't make sense to label issues that were fixed or prs that were merged)
|
||||
|
||||
|
||||
## Automatic processing ##
|
||||
|
||||
We have automatic tools (e.g. Mary Poppins) that automatically add comments / labels to issues and PRs.
|
||||
The following is done automatically and should not be done manually:
|
||||
|
||||
* Label "cla: yes" or "cla: no" for pull requests
|
||||
|
||||
## Process ##
|
||||
|
||||
1. Open list of [non triaged issues](https://github.com/angular/angular.js/issues?direction=desc&milestone=none&page=1&sort=created&state=open)
|
||||
1. Assign yourself: Pick an issue that is not assigned to anyone and assign it to you
|
||||
1. Assign milestone:
|
||||
* "Docs only" milestone - for documentation PR -> **Done**.
|
||||
* Current/next milestone - regressions
|
||||
* 1.2.x - everything else
|
||||
1. Label "GH: *" (to be automated via Mary Poppins)
|
||||
* PR - issue is a PR
|
||||
* issue - otherwise
|
||||
1. Bugs:
|
||||
* Label "Type: Bug"
|
||||
* Label "Type: Regression" - if the bug is a regression
|
||||
* Duplicate? - Check if there are comments pointing out that this is a dupe, if they do exist verify that this is indeed a dupe and close it and go to the last step
|
||||
* Reproducible? - Steps to reproduce the bug are clear, if not ask for clarification (ideally plunker or fiddle)
|
||||
* Reproducible on master? - http://code.angularjs.org/snapshot/
|
||||
|
||||
1. Non bugs:
|
||||
* Label "Type: Feature" or "Type: Chore" or "Type: Perf"
|
||||
* Label "needs: breaking change" - if needed
|
||||
* Label "needs: public api" - if a new public api is needed
|
||||
* Understandable? - verify if the description of the request is clear. if not ask for clarification
|
||||
* Goals of angular core? - Often new features should be implemented as a third-party module rather than an addition to the core.
|
||||
|
||||
1. Label "component: *"
|
||||
* In rare cases, it's ok to have multiple components.
|
||||
1. Label "impact: *"
|
||||
* small - obscure issue affecting one or handful of developers
|
||||
* medium - impacts some usage patterns
|
||||
* large - impacts most or all of angular apps
|
||||
1. Label "complexity: *"
|
||||
* small - trivial change
|
||||
* medium - non-trivial but straightforward change
|
||||
* large - changes to many components in angular or any changes to $compile, ngRepeat or other "fun" components
|
||||
1. Label "PRs welcome" for "GH: issue"
|
||||
* if complexity is small or medium and the problem as well as solution are well captured in the issue
|
||||
1. Label "origin: google" for issues from Google
|
||||
1. Label "high priority" for security issues, major performance regressions or memory leaks
|
||||
|
||||
1. Unassign yourself from the issue
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
Vendored
+1
@@ -27,6 +27,7 @@ angularFiles = {
|
||||
'src/ng/parse.js',
|
||||
'src/ng/q.js',
|
||||
'src/ng/rootScope.js',
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
'src/ng/timeout.js',
|
||||
|
||||
+3
-1
@@ -142,6 +142,7 @@ var writeChangelog = function(stream, commits, version) {
|
||||
var sections = {
|
||||
fix: {},
|
||||
feat: {},
|
||||
perf: {},
|
||||
breaks: {}
|
||||
};
|
||||
|
||||
@@ -169,6 +170,7 @@ var writeChangelog = function(stream, commits, version) {
|
||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||
printSection(stream, 'Bug Fixes', sections.fix);
|
||||
printSection(stream, 'Features', sections.feat);
|
||||
printSection(stream, 'Performance Improvements', sections.perf);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||
}
|
||||
|
||||
@@ -186,7 +188,7 @@ var getPreviousTag = function() {
|
||||
var generate = function(version, file) {
|
||||
getPreviousTag().then(function(tag) {
|
||||
console.log('Reading git log since', tag);
|
||||
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
|
||||
readGitLog('^fix|^feat|^perf|BREAKING', tag).then(function(commits) {
|
||||
console.log('Parsed', commits.length, 'commits');
|
||||
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
|
||||
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
<a name="v1.0.0rc3"></a>
|
||||
# v1.0.0rc3 (2012-03-27)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- create new (isolate) scopes for directives on root elements ([5390fb37](https://github.com/angular/angular.js/commit/5390fb37d2c01937922613fc57df4986af521787), closes [#817](https://github.com/angular/angular.js/issues/817))
|
||||
- don't touch static element attributes ([9cb2195e](https://github.com/angular/angular.js/commit/9cb2195e61a78e99020ec19d687a221ca88b5900))
|
||||
- Merge interpolated css class when replacing an element ([f49eaf8b](https://github.com/angular/angular.js/commit/f49eaf8bf2df5f4e0e82d6c89e849a4f82c8d414))
|
||||
- **$http:**
|
||||
- don't send Content-Type header when no data ([1a5bebd9](https://github.com/angular/angular.js/commit/1a5bebd927ecd22f9c34617642fdf58fe3f62efb), closes [#749](https://github.com/angular/angular.js/issues/749))
|
||||
- **$log:**
|
||||
- avoid console.log.apply calls in IE ([15213ec2](https://github.com/angular/angular.js/commit/15213ec212769837cb2b7e781ffc5bfd598d27ca), closes [#805](https://github.com/angular/angular.js/issues/805))
|
||||
- **$resource:**
|
||||
- support escaping of ':' in resource url ([6d6f8753](https://github.com/angular/angular.js/commit/6d6f875345e01f2c6c63ef95164f6f39e923da15))
|
||||
- **compiler:**
|
||||
- allow transclusion of root elements ([9918b748](https://github.com/angular/angular.js/commit/9918b748be01266eb10db39d51b4d3098d54ab66))
|
||||
- **e2e runner:**
|
||||
- fix typo that caused errors on IE8 ([ee5a5352](https://github.com/angular/angular.js/commit/ee5a5352fd4b94cedee6ef20d4bf2d43ce77e00b), closes [#806](https://github.com/angular/angular.js/issues/806))
|
||||
- **forEach:**
|
||||
- should ignore prototypically inherited properties ([8d7e6948](https://github.com/angular/angular.js/commit/8d7e6948496ff26ef1da8854ba02fcb8eebfed61), closes [#813](https://github.com/angular/angular.js/issues/813))
|
||||
- **forms:**
|
||||
- Remove double registering of form ([1faafa31](https://github.com/angular/angular.js/commit/1faafa31582c4e9413f48dc7d12f5b681f9fe9fd))
|
||||
- Set ng-valid/ng-invalid correctly ([08bfea18](https://github.com/angular/angular.js/commit/08bfea183a850b29da270eac47f80b598cbe600f))
|
||||
- **init:**
|
||||
- use jQuery#ready for init if available ([cb2ad9ab](https://github.com/angular/angular.js/commit/cb2ad9abf24e6f855cc749efe3155bd7987ece9d), closes [#818](https://github.com/angular/angular.js/issues/818))
|
||||
- **json:**
|
||||
- added support for iso8061 timezone ([5ac14f63](https://github.com/angular/angular.js/commit/5ac14f633a69f49973b5512780c6ec7752405967))
|
||||
- **matchers.toHaveClass:**
|
||||
- Correct reference to angular.mock.dump ([f701ce08](https://github.com/angular/angular.js/commit/f701ce08f9d63be05fc3b92f57ad473e1e749b2d))
|
||||
- **ng-switch:**
|
||||
- properly destroy child scopes ([2315d9b3](https://github.com/angular/angular.js/commit/2315d9b3610994b36c44e4a97fb1427d59471ce8))
|
||||
- **ngDocSpec:**
|
||||
- fix broken tests ([53b6f522](https://github.com/angular/angular.js/commit/53b6f522a56eea314cbd084816e08f24b2c7879f))
|
||||
- **ngForm:**
|
||||
- alias name||ngForm ([823adb23](https://github.com/angular/angular.js/commit/823adb231995e917bc060bfa49453e2a96bac2b6))
|
||||
- **ngRepeat:**
|
||||
- correct variable reference in error message ([935c1018](https://github.com/angular/angular.js/commit/935c1018da05dbf3124b2dd33619c4a3c82d7a2a))
|
||||
- **ngView:**
|
||||
- controller not published ([21e74c2d](https://github.com/angular/angular.js/commit/21e74c2d2e8e985b23711785287feb59965cbd90))
|
||||
- **q:**
|
||||
- resolve all of nothing to nothing ([ac75079e](https://github.com/angular/angular.js/commit/ac75079e2113949d5d64adbcf23d56f3cf295d41))
|
||||
- **select:**
|
||||
- multiselect failes to update view on selection insert ([6ecac8e7](https://github.com/angular/angular.js/commit/6ecac8e71a84792a434d21db2c245b3648c55f18))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:**
|
||||
- do not interpolate boolean attributes, rather evaluate them ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
|
||||
- **$controller:**
|
||||
- support controller registration via $controllerProvider ([d54dfecb](https://github.com/angular/angular.js/commit/d54dfecb00fba41455536c5ddd55310592fdaf84))
|
||||
- **$route:**
|
||||
- when matching consider trailing slash as optional ([a4fe51da](https://github.com/angular/angular.js/commit/a4fe51da3ba0dc297ecd389e230d6664f250c9a6), closes [#784](https://github.com/angular/angular.js/issues/784))
|
||||
- **assertArgFn:**
|
||||
- should support array annotated fns ([4b8d9260](https://github.com/angular/angular.js/commit/4b8d926062eb4d4483555bdbdec4656f585ab40b))
|
||||
- **http:**
|
||||
- added params parameter ([73c85930](https://github.com/angular/angular.js/commit/73c8593077155a9f2e8ef42efd4c497eba0bef4f))
|
||||
- **injector:**
|
||||
- infer _foo_ as foo ([f13dd339](https://github.com/angular/angular.js/commit/f13dd3393dfb7a33565c9360342c193bc0bddcb6))
|
||||
- **input.radio:**
|
||||
- Allow value attribute to be interpolated ([ade6c452](https://github.com/angular/angular.js/commit/ade6c452753145c84884d17027a7865bf4b34b0c))
|
||||
- **jqLite:**
|
||||
- make injector() and scope() work with the document object ([5fdab52d](https://github.com/angular/angular.js/commit/5fdab52dd7c269f99839f4fa6b5854d9548269fa))
|
||||
- add .controller() method ([6c5a05ad](https://github.com/angular/angular.js/commit/6c5a05ad49a1e083570c3dfe331403398f899dbe))
|
||||
- **ngValue:**
|
||||
- allow radio inputs to have non string values ([09e175f0](https://github.com/angular/angular.js/commit/09e175f02cca0f4a295fd0c9b980cd8f432e722b), closes [#816](https://github.com/angular/angular.js/issues/816))
|
||||
- **scope:**
|
||||
- broadcast $destroy event on scope destruction ([9b1aff90](https://github.com/angular/angular.js/commit/9b1aff905b638aa274a5fc8f88662df446d374bd))
|
||||
- **scope.$eval:**
|
||||
- Allow passing locals to the expression ([192ff61f](https://github.com/angular/angular.js/commit/192ff61f5d61899e667c6dbce4d3e6e399429d8b))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- boolean attrs are evaluated rather than interpolated ([a08cbc02](https://github.com/angular/angular.js/commit/a08cbc02e78e789a66e9af771c410e8ad1646e25))
|
||||
- ng-bind-attr directive removed ([55027132](https://github.com/angular/angular.js/commit/55027132f3d57e5dcf94683e6e6bd7b0aae0087d))
|
||||
- any app that depends on this service and its fallback to Modernizr, please ([aaedefb9](https://github.com/angular/angular.js/commit/aaedefb92e6bec6626e173e5155072c91471596a))
|
||||
|
||||
Vendored
+66
-3
@@ -225,6 +225,11 @@ angular.uppercase = function(s) {};
|
||||
*/
|
||||
angular.Attributes;
|
||||
|
||||
/**
|
||||
* @type {Object.<string, string>}
|
||||
*/
|
||||
angular.Attributes.$attr;
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @return {string}
|
||||
@@ -757,7 +762,9 @@ angular.Module.requires;
|
||||
* $parent: angular.Scope,
|
||||
* $root: angular.Scope,
|
||||
* $watch: function(
|
||||
* (string|Function), (string|Function)=, boolean=):function()
|
||||
* (string|Function), (string|Function)=, boolean=):function(),
|
||||
* $watchCollection: function(
|
||||
* (string|Function), (string|Function)=):function()
|
||||
* }}
|
||||
*/
|
||||
angular.Scope;
|
||||
@@ -829,6 +836,13 @@ angular.Scope.$root;
|
||||
*/
|
||||
angular.Scope.$watch = function(exp, opt_listener, opt_objectEquality) {};
|
||||
|
||||
/**
|
||||
* @param {string|Function} exp
|
||||
* @param {(string|Function)=} opt_listener
|
||||
* @return {function()}
|
||||
*/
|
||||
angular.Scope.$watchCollection = function(exp, opt_listener) {};
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* currentScope: angular.Scope,
|
||||
@@ -1048,6 +1062,10 @@ angular.$http;
|
||||
*/
|
||||
angular.$http.Config;
|
||||
|
||||
angular.$http.Config.transformRequest;
|
||||
|
||||
angular.$http.Config.transformResponse;
|
||||
|
||||
// /**
|
||||
// * This extern is currently incomplete as delete is a reserved word.
|
||||
// * To use delete, index $http.
|
||||
@@ -1154,6 +1172,13 @@ angular.$http.HttpPromise.error = function(callback) {};
|
||||
*/
|
||||
angular.$http.Response;
|
||||
|
||||
angular.$HttpProvider;
|
||||
|
||||
/**
|
||||
* @type {angular.$http.Config}
|
||||
*/
|
||||
angular.$HttpProvider.defaults;
|
||||
|
||||
/******************************************************************************
|
||||
* $injector Service
|
||||
*****************************************************************************/
|
||||
@@ -1425,6 +1450,11 @@ angular.NgModelController.prototype.$viewValue;
|
||||
*/
|
||||
angular.FormController = function() {};
|
||||
|
||||
/**
|
||||
* @param {*} control
|
||||
*/
|
||||
angular.FormController.prototype.$addControl = function(control) {};
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
@@ -1440,11 +1470,39 @@ angular.FormController.prototype.$error;
|
||||
*/
|
||||
angular.FormController.prototype.$invalid;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
angular.FormController.prototype.$name;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
angular.FormController.prototype.$pristine;
|
||||
|
||||
/**
|
||||
* @param {*} control
|
||||
*/
|
||||
angular.FormController.prototype.$removeControl = function(control) {};
|
||||
|
||||
/**
|
||||
* @type {function()}
|
||||
*/
|
||||
angular.FormController.prototype.$setDirty = function() {};
|
||||
|
||||
/**
|
||||
* @type {function()}
|
||||
*/
|
||||
angular.FormController.prototype.$setPristine = function() {};
|
||||
|
||||
/**
|
||||
* @param {string} validationToken
|
||||
* @param {boolean} isValid
|
||||
* @param {*} control
|
||||
*/
|
||||
angular.FormController.prototype.$setValidity = function(
|
||||
validationToken, isValid, control) {};
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
@@ -1578,6 +1636,7 @@ angular.$q.when = function(value) {};
|
||||
* @typedef {{
|
||||
* resolve: function(*=),
|
||||
* reject: function(*=),
|
||||
* notify: function(*=),
|
||||
* promise: angular.$q.Promise
|
||||
* }}
|
||||
*/
|
||||
@@ -1589,6 +1648,9 @@ angular.$q.Deferred.resolve = function(opt_value) {};
|
||||
/** @param {*=} opt_reason */
|
||||
angular.$q.Deferred.reject = function(opt_reason) {};
|
||||
|
||||
/** @param {*=} opt_value */
|
||||
angular.$q.Deferred.notify = function(opt_value) {};
|
||||
|
||||
/** @type {angular.$q.Promise} */
|
||||
angular.$q.Deferred.promise;
|
||||
|
||||
@@ -1689,7 +1751,8 @@ angular.$routeProvider.when = function(path, route) {};
|
||||
* resolve: (Object.<string, (
|
||||
* string|Function|Array.<string|Function>|angular.$q.Promise
|
||||
* )>|undefined),
|
||||
* redirectTo: (string|function()|undefined),
|
||||
* redirectTo: (
|
||||
* string|function(Object.<string>, string, Object): string|undefined),
|
||||
* reloadOnSearch: (boolean|undefined)
|
||||
* }}
|
||||
*/
|
||||
@@ -1712,7 +1775,7 @@ angular.$routeProvider.Params.templateUrl;
|
||||
*/
|
||||
angular.$routeProvider.Params.resolve;
|
||||
|
||||
/** @type {string|function()} */
|
||||
/** @type {string|function(Object.<string>, string, Object): string} */
|
||||
angular.$routeProvider.Params.redirectTo;
|
||||
|
||||
/** @type {boolean} */
|
||||
|
||||
@@ -9,14 +9,3 @@
|
||||
ng\:form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* The styles below ensure that the CSS transition will ALWAYS
|
||||
* animate and close. A nasty bug occurs with CSS transitions where
|
||||
* when the active class isn't set, or if the active class doesn't
|
||||
* contain any styles to transition to, then, if ngAnimate is used,
|
||||
* it will appear as if the webpage is broken due to the forever hanging
|
||||
* animations. The clip (!ie) and zoom (ie) CSS properties are used
|
||||
* since they trigger a transition without making the browser
|
||||
* animate anything and they're both highly underused CSS properties */
|
||||
.ng-animate-start { clip:rect(0, auto, auto, 0); -ms-zoom:1.0001; }
|
||||
.ng-animate-active { clip:rect(-1px, auto, auto, 0); -ms-zoom:1; }
|
||||
|
||||
@@ -5,7 +5,7 @@ describe('Docs Annotations', function() {
|
||||
var body;
|
||||
beforeEach(function() {
|
||||
body = angular.element(document.body);
|
||||
body.html('');
|
||||
body.empty();
|
||||
});
|
||||
|
||||
var normalizeHtml = function(html) {
|
||||
|
||||
+2
-12
@@ -28,7 +28,7 @@ function escape(text) {
|
||||
function setHtmlIe8SafeWay(element, html) {
|
||||
var newElement = angular.element('<pre>' + html + '</pre>');
|
||||
|
||||
element.html('');
|
||||
element.empty();
|
||||
element.append(newElement.contents());
|
||||
return element;
|
||||
}
|
||||
@@ -215,17 +215,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
|
||||
}];
|
||||
this.html5Mode = angular.noop;
|
||||
});
|
||||
$provide.decorator('$timeout', ['$rootScope', '$delegate', function($rootScope, $delegate) {
|
||||
return angular.extend(function(fn, delay) {
|
||||
if (delay && delay > 50) {
|
||||
return setTimeout(function() {
|
||||
$rootScope.$apply(fn);
|
||||
}, delay);
|
||||
} else {
|
||||
return $delegate.apply(this, arguments);
|
||||
}
|
||||
}, $delegate);
|
||||
}]);
|
||||
|
||||
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
|
||||
embedRootScope = $delegate;
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@description
|
||||
|
||||
# ng (core module)
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself contains the essential components to for an AngularJS application to function. The table below lists a high level breakdown of each of the services/factories, filters, directives and testing components available within this core module.
|
||||
The ng module is loaded by default when an AngularJS application is started. The module itself
|
||||
contains the essential components for an AngularJS application to function. The table below
|
||||
lists a high level breakdown of each of the services/factories, filters, directives and testing
|
||||
components available within this core module.
|
||||
|
||||
<div doc-module-components="ng"></div>
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $httpBackend:noxhr
|
||||
@fullName Unsupported XHR
|
||||
@description
|
||||
|
||||
This error occurs in browsers that do not support XmlHttpRequest. AngularJS
|
||||
supports Safari, Chrome, Firefox, Opera, IE8 and higher, and mobile browsers
|
||||
(Android, Chrome Mobile, iOS Safari). To avoid this error, use an officially
|
||||
supported browser.
|
||||
@@ -4,4 +4,4 @@
|
||||
@description
|
||||
This error occurs when 'ngPattern' is passed an expression that isn't a regular expression or doesn't have the expected format.
|
||||
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:select input} directive docs.
|
||||
For more information on valid expression syntax, see 'ngPattern' in {@link api/ng.directive:input input} directive docs.
|
||||
|
||||
@@ -13,7 +13,7 @@ For example the issue can be triggered by this *invalid* code:
|
||||
<div ng-repeat="value in [4, 4]"></div>
|
||||
```
|
||||
|
||||
To resolve this error either ensure that the items in the collection have unique identity of use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
To resolve this error either ensure that the items in the collection have unique identity or use the `track by` syntax to specify how to track the association between models and DOM.
|
||||
|
||||
To resolve the example above can be resolved by using `track by $index`, which will cause the items to be keyed by their position in the array instead of their value:
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
@fullName Orphan ngTransclude Directive
|
||||
@description
|
||||
|
||||
Occurs when an `ngTransclude` occurs without a transcluded ancesstor element.
|
||||
Occurs when an `ngTransclude` occurs without a transcluded ancestor element.
|
||||
|
||||
This error often occurs when you have forgotten to set `transclude: true` in some directive definition, and then used `ngTranslude` in the driective's template.
|
||||
This error often occurs when you have forgotten to set `transclude: true` in some directive definition, and then used `ngTransclude` in the directive's template.
|
||||
|
||||
To resolve, either remove the offending `ngTransclude` or check that `transclude: true` is included in the intended directive definition.
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ This should help give you an idea of what Angular does internally.
|
||||
<pre>
|
||||
var $compile = ...; // injected into your code
|
||||
var scope = ...;
|
||||
var parent = ...; // DOM element where the compiled template can be appended
|
||||
|
||||
var html = '<div ng-bind="exp"></div>';
|
||||
|
||||
@@ -200,7 +201,10 @@ This should help give you an idea of what Angular does internally.
|
||||
var linkFn = $compile(template);
|
||||
|
||||
// Step 3: link the compiled template with the scope.
|
||||
linkFn(scope);
|
||||
var element = linkFn(scope);
|
||||
|
||||
// Step 4: Append to DOM (optional)
|
||||
parent.appendChild(element);
|
||||
</pre>
|
||||
|
||||
### The difference between Compile and Link
|
||||
@@ -350,7 +354,7 @@ Creating local properties on widget scope creates two problems:
|
||||
|
||||
|
||||
To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An
|
||||
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
||||
isolated scope does not prototypically inherit from the parent scope, and therefore we don't have
|
||||
to worry about accidentally clobbering any properties.
|
||||
|
||||
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
|
||||
|
||||
@@ -270,7 +270,7 @@ When Angular starts, it will use the configuration of the module with the name d
|
||||
including the configuration of all modules that this module depends on.
|
||||
|
||||
In the example above:
|
||||
The template contains the directive `ng-app="invoice"`. This tells Angular
|
||||
The template contains the directive `ng-app="invoice2"`. This tells Angular
|
||||
to use the `invoice` module as the main module for the application.
|
||||
The code snippet `angular.module('invoice', ['finance'])` specifies that the `invoice` module depends on the
|
||||
`finance` module. By this, Angular uses the `InvoiceController` as well as the `currencyConverter` service.
|
||||
|
||||
@@ -50,7 +50,7 @@ of which depend on other services that are provided by the Angular framework:
|
||||
* @param {*} message Message to be logged.
|
||||
*/
|
||||
function batchLogModule($provide){
|
||||
$provide.factory('batchLog', ['$timeout', '$log', function($timeout, $log) {
|
||||
$provide.factory('batchLog', ['$interval', '$log', function($interval, $log) {
|
||||
var messageQueue = [];
|
||||
|
||||
function log() {
|
||||
@@ -58,11 +58,10 @@ of which depend on other services that are provided by the Angular framework:
|
||||
$log('batchLog messages: ', messageQueue);
|
||||
messageQueue = [];
|
||||
}
|
||||
$timeout(log, 50000);
|
||||
}
|
||||
|
||||
// start periodic checking
|
||||
log();
|
||||
$interval(log, 50000);
|
||||
|
||||
return function(message) {
|
||||
messageQueue.push(message);
|
||||
@@ -82,13 +81,13 @@ of which depend on other services that are provided by the Angular framework:
|
||||
}]);
|
||||
}
|
||||
|
||||
// get the main service to kick of the application
|
||||
// get the main service to kick off the application
|
||||
angular.injector([batchLogModule]).get('routeTemplateMonitor');
|
||||
</pre>
|
||||
|
||||
Things to notice in this example:
|
||||
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$timeout $timeout} and
|
||||
* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and
|
||||
{@link api/ng.$log $log} services, and allows messages to be logged into the
|
||||
`console.log` in batches.
|
||||
* The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route
|
||||
|
||||
@@ -13,45 +13,44 @@ Unit testing as the name implies is about testing individual units of code. Unit
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order the list
|
||||
in the right order?"
|
||||
|
||||
In order to answer such question it is very important that we can isolate the unit of code under test.
|
||||
In order to answer such a question it is very important that we can isolate the unit of code under test.
|
||||
That is because when we are testing the sort function we don't want to be forced into creating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.
|
||||
|
||||
While
|
||||
this may seem obvious it usually is very difficult to be able to call an individual function on a
|
||||
typical project. The reason is that the developers often mix concerns, and they end up with a
|
||||
piece of code which does everything. It reads the data from XHR, it sorts it and then it
|
||||
While this may seem obvious it can be very difficult to call an individual function on a
|
||||
typical project. The reason is that the developers often mix concerns resulting in a
|
||||
piece of code which does everything. It makes an XHR request, it sorts the response data and then it
|
||||
manipulates the DOM.
|
||||
|
||||
With Angular we try to make it easy for you to do the right thing, and so we
|
||||
provide dependency injection for your XHR (which you can mock out) and we created abstraction which
|
||||
provide dependency injection for your XHR (which you can mock out) and we created abstractions which
|
||||
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
||||
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
||||
apply the function, and assert that the resulting model is in the correct order. The test does not
|
||||
have to wait for XHR, or create the right kind of DOM, or assert that your function has mutated the
|
||||
DOM in the right way.
|
||||
have to wait for the XHR response to arrive, create the right kind of test DOM, nor assert that your
|
||||
function has mutated the DOM in the right way.
|
||||
|
||||
## With great power comes great responsibility
|
||||
|
||||
Angular is written with testability in mind, but it still requires that you
|
||||
do the right thing. We tried to make the right thing easy, but Angular is not magic, which means if
|
||||
you don't follow these guidelines you may very well end up with an untestable application.
|
||||
Angular is written with testability in mind, but it still requires that you do the right thing.
|
||||
We tried to make the right thing easy, but Angular is not magic. If you don't follow these guidelines
|
||||
you may very well end up with an untestable application.
|
||||
|
||||
## Dependency Injection
|
||||
There are several ways in which you can get a hold of a dependency:
|
||||
1. You could create it using the `new` operator.
|
||||
2. You could look for it in a well known place, also known as global singleton.
|
||||
3. You could ask a registry (also known as service registry) for it. (But how do you get a hold of
|
||||
the registry? Most likely by looking it up in a well known place. See #2)
|
||||
4. You could expect that it be handed to you.
|
||||
There are several ways in which you can get a hold of a dependency. You can:
|
||||
1. Create it using the `new` operator.
|
||||
2. Look for it in a well-known place, also known as a global singleton.
|
||||
3. Ask a registry (also known as service registry) for it. (But how do you get a hold of
|
||||
the registry? Most likely by looking it up in a well known place. See #2.)
|
||||
4. Expect it to be handed to you.
|
||||
|
||||
Out of the four options in the list above, only the last one is testable. Let's look at why:
|
||||
|
||||
### Using the `new` operator
|
||||
|
||||
While there is nothing wrong with the `new` operator fundamentally the issue is that calling a new
|
||||
on a constructor permanently binds the call site to the type. For example lets say that we are
|
||||
trying to instantiate an `XHR` so that we can get some data from the server.
|
||||
While there is nothing wrong with the `new` operator fundamentally, a problem arises when calling `new`
|
||||
on a constructor. This permanently binds the call site to the type. For example, lets say that we try to
|
||||
instantiate an `XHR` that will retrieve data from the server.
|
||||
|
||||
<pre>
|
||||
function MyClass() {
|
||||
@@ -64,12 +63,12 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The issue becomes that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||
A problem surfaces in tests when we would like to instantiate a `MockXHR` that would
|
||||
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
||||
permanently bound to the actual XHR, and there is no good way to replace it. Yes there is monkey
|
||||
patching. That is a bad idea for many reasons which are outside the scope of this document.
|
||||
permanently bound to the actual XHR and there is no way to replace it. Yes, we could monkey
|
||||
patch, but that is a bad idea for many reasons which are outside the scope of this document.
|
||||
|
||||
The class above is hard to test since we have to resort to monkey patching:
|
||||
Here's an example of how the class above becomes hard to test when resorting to monkey patching:
|
||||
<pre>
|
||||
var oldXHR = XHR;
|
||||
XHR = function MockXHR() {};
|
||||
@@ -81,7 +80,7 @@ XHR = oldXHR; // if you forget this bad things will happen
|
||||
|
||||
|
||||
### Global look-up:
|
||||
Another way to approach the problem is to look for the service in a well known location.
|
||||
Another way to approach the problem is to look for the service in a well-known location.
|
||||
|
||||
<pre>
|
||||
function MyClass() {
|
||||
@@ -95,14 +94,14 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
While no new instance of the dependency is being created, it is fundamentally the same as `new`, in
|
||||
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
|
||||
While no new dependency instance is created, it is fundamentally the same as `new` in
|
||||
that no way exists to intercept the call to `global.xhr` for testing purposes, other then
|
||||
through monkey patching. The basic issue for testing is that a global variable needs to be mutated in
|
||||
order to replace it with call to a mock method. For further explanation why this is bad see: {@link
|
||||
order to replace it with call to a mock method. For further explanation of why this is bad see: {@link
|
||||
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global
|
||||
State & Singletons}
|
||||
|
||||
The class above is hard to test since we have to change global state:
|
||||
The class above is hard to test since we have to change the global state:
|
||||
<pre>
|
||||
var oldXHR = global.xhr;
|
||||
global.xhr = function mockXHR() {};
|
||||
@@ -115,7 +114,7 @@ global.xhr = oldXHR; // if you forget this bad things will happen
|
||||
|
||||
### Service Registry:
|
||||
|
||||
It may seem as that this can be solved by having a registry for all of the services, and then
|
||||
It may seem that this can be solved by having a registry of all the services and then
|
||||
having the tests replace the services as needed.
|
||||
|
||||
<pre>
|
||||
@@ -131,12 +130,12 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
However, where does the serviceRegistry come from? if it is:
|
||||
* `new`-ed up, the test has no chance to reset the services for testing
|
||||
* global look-up, then the service returned is global as well (but resetting is easier, since
|
||||
there is only one global variable to be reset).
|
||||
However, where does the serviceRegistry come from? If it is:
|
||||
* `new`-ed up, the test has no chance to reset the services for testing.
|
||||
* a global look-up then the service returned is global as well (but resetting is easier, since
|
||||
only one global variable exists to be reset).
|
||||
|
||||
The class above is hard to test since we have to change global state:
|
||||
The class above is hard to test since we have to change the global state:
|
||||
<pre>
|
||||
var oldServiceLocator = global.serviceLocator;
|
||||
global.serviceLocator.set('xhr', function mockXHR() {});
|
||||
@@ -148,7 +147,7 @@ global.serviceLocator = oldServiceLocator; // if you forget this bad things will
|
||||
|
||||
|
||||
### Passing in Dependencies:
|
||||
Lastly the dependency can be passed in.
|
||||
Last, the dependency can be passed in.
|
||||
|
||||
<pre>
|
||||
function MyClass(xhr) {
|
||||
@@ -161,12 +160,12 @@ function MyClass(xhr) {
|
||||
}
|
||||
</pre>
|
||||
|
||||
This is the preferred way since the code makes no assumptions as to where the `xhr` comes from,
|
||||
rather that whoever created the class was responsible for passing it in. Since the creator of the
|
||||
This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares
|
||||
instead about whoever created the class responsible for passing it in. Since the creator of the
|
||||
class should be different code than the user of the class, it separates the responsibility of
|
||||
creation from the logic, and that is what dependency-injection is in a nutshell.
|
||||
creation from the logic. This is dependency-injection in a nutshell.
|
||||
|
||||
The class above is very testable, since in the test we can write:
|
||||
The class above is testable, since in the test we can write:
|
||||
<pre>
|
||||
function xhrMock(args) {...}
|
||||
var myClass = new MyClass(xhrMock);
|
||||
@@ -176,12 +175,12 @@ myClass.doWork();
|
||||
|
||||
Notice that no global variables were harmed in the writing of this test.
|
||||
|
||||
Angular comes with {@link di dependency injection} built in which makes the right thing
|
||||
Angular comes with {@link di dependency injection} built-in, making the right thing
|
||||
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||
|
||||
## Controllers
|
||||
What makes each application unique is its logic, which is what we would like to test. If the logic
|
||||
for your application is mixed in with DOM manipulation, it will be hard to test as in the example
|
||||
What makes each application unique is its logic, and the logic is what we would like to test. If the logic
|
||||
for your application contains DOM manipulation, it will be hard to test. See the example
|
||||
below:
|
||||
|
||||
<pre>
|
||||
@@ -209,7 +208,7 @@ function PasswordCtrl() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The code above is problematic from a testability point of view, since it requires your test to have the right kind
|
||||
The code above is problematic from a testability point of view since it requires your test to have the right kind
|
||||
of DOM present when the code executes. The test would look like this:
|
||||
|
||||
<pre>
|
||||
@@ -223,11 +222,11 @@ var pc = new PasswordCtrl();
|
||||
input.val('abc');
|
||||
pc.grade();
|
||||
expect(span.text()).toEqual('weak');
|
||||
$('body').html('');
|
||||
$('body').empty();
|
||||
</pre>
|
||||
|
||||
In angular the controllers are strictly separated from the DOM manipulation logic which results in
|
||||
a much easier testability story as can be seen in this example:
|
||||
In angular the controllers are strictly separated from the DOM manipulation logic and this results in
|
||||
a much easier testability story as the following example shows:
|
||||
|
||||
<pre>
|
||||
function PasswordCtrl($scope) {
|
||||
@@ -245,7 +244,7 @@ function PasswordCtrl($scope) {
|
||||
}
|
||||
</pre>
|
||||
|
||||
and the test is straight forward
|
||||
and the test is straight forward:
|
||||
|
||||
<pre>
|
||||
var $scope = {};
|
||||
@@ -255,11 +254,11 @@ $scope.grade();
|
||||
expect($scope.strength).toEqual('weak');
|
||||
</pre>
|
||||
|
||||
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
||||
Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
|
||||
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||
|
||||
## Filters
|
||||
{@link api/ng.$filterProvider Filters} are functions which transform the data into user readable
|
||||
{@link api/ng.$filterProvider Filters} are functions which transform the data into a user readable
|
||||
format. They are important because they remove the formatting responsibility from the application
|
||||
logic, further simplifying the application logic.
|
||||
|
||||
@@ -282,7 +281,7 @@ you create with directives may be used throughout your application and in many d
|
||||
|
||||
### Simple HTML Element Directive
|
||||
|
||||
Lets start with an angular app with no dependencies.
|
||||
Let's start with an angular app with no dependencies.
|
||||
|
||||
<pre>
|
||||
var app = angular.module('myApp', []);
|
||||
|
||||
@@ -146,7 +146,7 @@ of service names to inject.
|
||||
var MyController = function(renamed$scope, renamedGreeter) {
|
||||
...
|
||||
}
|
||||
MyController.$inject = ['$scope', 'greeter'];
|
||||
MyController['$inject'] = ['$scope', 'greeter'];
|
||||
</pre>
|
||||
|
||||
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
|
||||
|
||||
@@ -56,9 +56,9 @@ The following also **matches** `ngModel`:
|
||||
Angular **normalizes** an element's tag and attribute name to determine which elements match which
|
||||
directives. We typically refer to directives by their case-sensitive
|
||||
{@link http://en.wikipedia.org/wiki/CamelCase camelCase} **normalized** name (e.g. `ngModel`).
|
||||
However, in the DOM, we refer to directives by case-insensitive forms, typically using
|
||||
{@link http://en.wikipedia.org/wiki/Letter_case#Computers dash-delimited} attributes on DOM elements
|
||||
(e.g. `ng-model`).
|
||||
However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case
|
||||
forms, typically using {@link http://en.wikipedia.org/wiki/Letter_case#Computers dash-delimited}
|
||||
attributes on DOM elements (e.g. `ng-model`).
|
||||
|
||||
The **normalization** process is as follows:
|
||||
|
||||
@@ -404,40 +404,43 @@ we call an **isolate scope**. To do this, we can use a directive's `scope` optio
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
customer: '=customer'
|
||||
customerInfo: '=info'
|
||||
},
|
||||
templateUrl: 'my-customer.html'
|
||||
templateUrl: 'my-customer-iso.html'
|
||||
};
|
||||
});
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Ctrl">
|
||||
<my-customer customer="naomi"></my-customer>
|
||||
<my-customer info="naomi"></my-customer>
|
||||
<hr>
|
||||
<my-customer customer="igor"></my-customer>
|
||||
<my-customer info="igor"></my-customer>
|
||||
</div>
|
||||
</file>
|
||||
<file name="my-customer.html">
|
||||
Name: {{customer.name}} Address: {{customer.address}}
|
||||
<file name="my-customer-iso.html">
|
||||
Name: {{customerInfo.name}} Address: {{customerInfo.address}}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Looking at `index.html`, the first `<my-customer>` element binds the inner scope's `customer` to
|
||||
`naomi`, which we have exposed on our controller's scope. The second binds `customer` to `igor`.
|
||||
Looking at `index.html`, the first `<my-customer>` element binds the `info` attribute to `naomi`,
|
||||
which we have exposed on our controller's scope. The second binds `info` to `igor`.
|
||||
|
||||
Let's take a closer look at the scope option:
|
||||
|
||||
```javascript
|
||||
//...
|
||||
scope: {
|
||||
customer: '=customer'
|
||||
customerInfo: '=info'
|
||||
},
|
||||
//...
|
||||
```
|
||||
|
||||
The property name (`customer`) corresponds to the variable name of the `myCustomer` directive's
|
||||
isolated scope. The value of the property (`=customer`) tells `$compile` to bind to the `customer`
|
||||
attribute.
|
||||
The **scope option** is an object that contains a property for each isolate scope binding. In this
|
||||
case it has just one property:
|
||||
|
||||
- Its name (`customerInfo`) corresponds to the
|
||||
directive's **isolate scope** property `customerInfo`.
|
||||
- Its value (`=info`) tells `$compile` to bind to the `info` attribute.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** These `=attr` attributes in the `scope` option of directives are normalized just like
|
||||
@@ -449,12 +452,12 @@ For cases where the attribute name is the same as the value you want to bind to
|
||||
directive's scope, you can use this shorthand syntax:
|
||||
|
||||
```javascript
|
||||
//...
|
||||
...
|
||||
scope: {
|
||||
// same as '=customer'
|
||||
// same as '=customer'
|
||||
customer: '='
|
||||
},
|
||||
//...
|
||||
...
|
||||
```
|
||||
|
||||
Besides making it possible to bind different data to the scope inside a directive, using an isolated
|
||||
@@ -475,7 +478,7 @@ within our directive's template:
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
customer: '=customer'
|
||||
customerInfo: '=info'
|
||||
},
|
||||
templateUrl: 'my-customer-plus-vojta.html'
|
||||
};
|
||||
@@ -483,11 +486,11 @@ within our directive's template:
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Ctrl">
|
||||
<my-customer customer="naomi"></my-customer>
|
||||
<my-customer info="naomi"></my-customer>
|
||||
</div>
|
||||
</file>
|
||||
<file name="my-customer-plus-vojta.html">
|
||||
Name: {{customer.name}} Address: {{customer.address}}
|
||||
Name: {{customerInfo.name}} Address: {{customerInfo.address}}
|
||||
<hr>
|
||||
Name: {{vojta.name}} Address: {{vojta.address}}
|
||||
</file>
|
||||
@@ -503,6 +506,8 @@ that you explicitly pass in.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** Normally, a scope prototypically inherits from its parent. An isolated scope does not.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
"Isolating the Scope of a Directive"} section for more information about isolate scopes.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
@@ -525,8 +530,10 @@ where:
|
||||
* `attrs` is an object with the normalized attribute names and their corresponding values.
|
||||
|
||||
In our `link` function, we want to update the displayed time once a second, or whenever a user
|
||||
changes the time formatting string that our directive binds to. We also want to remove the timeout
|
||||
if the directive is deleted so we don't introduce a memory leak.
|
||||
changes the time formatting string that our directive binds to. We will use the `$interval` service
|
||||
to call a handler on a regular basis. This is easier than using `$timeout` but also works better with
|
||||
end 2 end testing, where we want to ensure that all $timeouts have completed before completing the test.
|
||||
We also want to remove the `$interval` if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
<example module="docsTimeDirective">
|
||||
<file name="script.js">
|
||||
@@ -534,7 +541,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
.controller('Ctrl2', function($scope) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
})
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
|
||||
function link(scope, element, attrs) {
|
||||
var format,
|
||||
@@ -549,20 +556,14 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
updateTime();
|
||||
});
|
||||
|
||||
function scheduleUpdate() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
scheduleUpdate(); // schedule the next update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
element.on('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
$interval.cancel(timeoutId);
|
||||
});
|
||||
|
||||
// start the UI update process.
|
||||
scheduleUpdate();
|
||||
// start the UI update process; save the timeoutId for canceling
|
||||
timeoutId = $interval(function() {
|
||||
updateTime(); // update DOM
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -580,7 +581,7 @@ if the directive is deleted so we don't introduce a memory leak.
|
||||
|
||||
There are a couple of things to note here.
|
||||
Just like the `module.controller` API, the function argument in `module.directive` is dependency
|
||||
injected. Because of this, we can use `$timeout` and `dateFilter` inside our directive's `link`
|
||||
injected. Because of this, we can use `$interval` and `dateFilter` inside our directive's `link`
|
||||
function.
|
||||
|
||||
We register an event `element.on('$destroy', ...)`. What fires this `$destroy` event?
|
||||
@@ -717,7 +718,7 @@ own behavior to it.
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<div ng-controller="Ctrl">
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="dialogIsHidden = true">
|
||||
<my-dialog ng-hide="dialogIsHidden" on-close="hideDialog()">
|
||||
Check out the contents, {{name}}!
|
||||
</my-dialog>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ It might be tempting to think of Angular view expressions as JavaScript expressi
|
||||
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of Angular expressions as JavaScript expressions with following differences:
|
||||
|
||||
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
|
||||
* **Attribute Evaluation:** evaluation of all properties are against the scope doing the
|
||||
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
||||
`window`.
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ In addition it provides an {@link api/ng.directive:ngModel.NgModelController API
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master= angular.copy(user);
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
@@ -115,9 +115,14 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
|
||||
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
Similarly, control is an instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
The control instance can similarly be published into the form instance using the `name` attribute.
|
||||
This implies that the internal state of both the form and the control is available for binding in the view using the standard binding primitives.
|
||||
|
||||
Similarly, an input control that has the {@link api/ng.directive:ngModel} directive holds an
|
||||
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
Such a control instance can be published as a property of the form instance using the `name` attribute
|
||||
on the input control. The name attribute specifies the name of the property on the form instance.
|
||||
|
||||
This implies that the internal state of both the form and the control is available for binding in
|
||||
the view using the standard binding primitives.
|
||||
|
||||
This allows us to extend the above example with these features:
|
||||
|
||||
@@ -230,7 +235,7 @@ In the following example we create two directives.
|
||||
<script>
|
||||
var app = angular.module('form-example1', []);
|
||||
|
||||
var INTEGER_REGEXP = /^\-?\d*$/;
|
||||
var INTEGER_REGEXP = /^\-?\d+$/;
|
||||
app.directive('integer', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
|
||||
@@ -43,7 +43,7 @@ http://userguide.icu-project.org/locale ICU } website for more information about
|
||||
**Supported locales in Angular**
|
||||
Angular separates number and datetime format rule sets into different files, each file for a
|
||||
particular locale. You can find a list of currently supported locales {@link
|
||||
https://github.com/angular/angular.js/tree/master/i18n/locale here}
|
||||
https://github.com/angular/angular.js/tree/master/src/ngLocale here}
|
||||
# Providing locale rules to Angular
|
||||
|
||||
There are two approaches to providing locale rules to Angular:
|
||||
|
||||
@@ -8,6 +8,17 @@ This document describes the Internet Explorer (IE) idiosyncrasies when dealing w
|
||||
attributes and tags. Read this document if you are planning on deploying your Angular application
|
||||
on IE v8.0 or earlier.
|
||||
|
||||
The project currently supports and will attempt to fix bugs for IE8 and above. The continuous
|
||||
integration server runs all the tests against IE8. See http://ci.angularjs.org.
|
||||
|
||||
IE7 and below are not tested and the project makes no guarantee that Angular will work on it.
|
||||
A subset of the AngularJS functionality may work. It is up to you to test and decide whether
|
||||
it works for your particular app.
|
||||
|
||||
It is very unlikely that issues specific to IE7 or earlier will be given any time by the core team.
|
||||
[GitHub](https://github.com/angular/angular.js/issues/4974)
|
||||
|
||||
|
||||
# Short Version
|
||||
|
||||
To make your Angular application work on IE please make sure that:
|
||||
@@ -80,7 +91,7 @@ The **important** parts are:
|
||||
IE has issues with element tag names which are not standard HTML tag names. These fall into two
|
||||
categories, and each category has its own fix.
|
||||
|
||||
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
|
||||
* If the tag name starts with `my:` prefix then it is considered an XML namespace and must
|
||||
have corresponding namespace declaration on `<html xmlns:my="ignored">`
|
||||
|
||||
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
|
||||
|
||||
@@ -7,19 +7,14 @@
|
||||
Everything you need to know about AngularJS
|
||||
|
||||
* {@link guide/introduction What is AngularJS?}
|
||||
|
||||
* {@link guide/concepts Conceptual Overview}
|
||||
|
||||
## Tutorials
|
||||
|
||||
* {@link tutorial/index Official AngularJS Tutorial}
|
||||
|
||||
* [10 Reasons Why You Should Use AngularJS](http://www.sitepoint.com/10-reasons-use-angularjs/)
|
||||
|
||||
* [Design Principles of AngularJS (video)](https://www.youtube.com/watch?v=HCR7i5F5L8c)
|
||||
|
||||
* [Fundamentals in 60 Minutes (video)](http://www.youtube.com/watch?v=i9MHigUZKEM)
|
||||
|
||||
* [For folks with jQuery background](http://stackoverflow.com/questions/14994391/how-do-i-think-in-angularjs-if-i-have-a-jquery-background)
|
||||
|
||||
## Core Concepts
|
||||
@@ -29,63 +24,44 @@ Everything you need to know about AngularJS
|
||||
In Angular applications, you move the job of filling page templates with data from the server to the client. The result is a system better structured for dynamic page updates. Below are the core features you'll use.
|
||||
|
||||
* {@link guide/databinding Data binding}
|
||||
|
||||
* {@link guide/expression Expressions}
|
||||
|
||||
* {@link guide/directive Directives}
|
||||
|
||||
* {@link api/ngRoute.$route Views and routes (see the example)}
|
||||
|
||||
* {@link guide/filter Filters}
|
||||
|
||||
* {@link guide/forms Forms} and [Concepts of AngularJS Forms](http://mrbool.com/the-concepts-of-angularjs-forms/29117)
|
||||
|
||||
### Application Structure
|
||||
|
||||
* **Blog post: **[When to use directives, controllers or services](http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/)
|
||||
|
||||
* **App wiring:** {@link guide/di Dependency injection}
|
||||
|
||||
* **Exposing model to templates:** {@link guide/scope Scopes}
|
||||
|
||||
* **Communicating with servers:** {@link api/ng.$http $http}, {@link api/ngResource.$resource $resource}
|
||||
|
||||
### Other AngularJS Features
|
||||
|
||||
* **Animation:** {@link guide/animations Core concepts}, {@link api/ngAnimate ngAnimate API}, and [Animation in AngularJS 1.2](http://www.yearofmoo.com/2013/08/remastered-animation-in-angularjs-1-2.html)
|
||||
|
||||
* **Security:** {@link api/ng.$sce Strict Contextual Escaping}, {@link api/ng.directive:ngCsp Content Security Policy}, {@link api/ngSanitize.$sanitize $sanitize}, [video](https://www.youtube.com/watch?v=18ifoT-Id54)
|
||||
|
||||
* **Internationalization and Localization:** {@link guide/i18n Angular Guide to i18n and l10n}, {@link api/ng.filter:date date filter}, {@link api/ng.filter:currency currency filter}, [Creating multilingual support](http://www.novanet.no/blog/hallstein-brotan/dates/2013/10/creating-multilingual-support-using-angularjs/)
|
||||
|
||||
* **Mobile:** {@link api/ngTouch Touch events}
|
||||
|
||||
### Testing
|
||||
|
||||
* **Unit testing:** [Using Karma (video)](http://www.youtube.com/watch?v=YG5DEzaQBIc), {@link guide/dev_guide.unit-testing Unit testing}, {@link guide/dev_guide.services.testing_services Testing services}, [Karma in Webstorm](http://blog.jetbrains.com/webstorm/2013/10/running-javascript-tests-with-karma-in-webstorm-7/)
|
||||
|
||||
* **Scenario testing:** [Protractor](https://github.com/angular/protractor)
|
||||
|
||||
## Specific Topics
|
||||
|
||||
* **Login: **[Google example](https://developers.google.com/+/photohunt/python), [Facebook example](http://blog.brunoscopelliti.com/facebook-authentication-in-your-angularjs-web-app), [authentication strategy](http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app), [unix-style authorization](http://frederiknakstad.com/authentication-in-single-page-applications-with-angular-js/)
|
||||
|
||||
* **Mobile:** [Angular on Mobile Guide](http://www.ng-newsletter.com/posts/angular-on-mobile.html), [PhoneGap](http://devgirl.org/2013/06/10/quick-start-guide-phonegap-and-angularjs/)
|
||||
|
||||
* **Other Languages:** [CoffeeScript](http://www.coffeescriptlove.com/2013/08/angularjs-and-coffeescript-tutorials.html), [Dart](https://github.com/angular/angular.dart.tutorial/wiki)
|
||||
|
||||
* **Realtime: **[Socket.io](http://www.creativebloq.com/javascript/angularjs-collaboration-board-socketio-2132885), [OmniBinder](https://github.com/jeffbcross/omnibinder)
|
||||
|
||||
* **Visualization:** [SVG](http://gaslight.co/blog/angular-backed-svgs), [D3.js](http://www.ng-newsletter.com/posts/d3-on-angular.html)
|
||||
|
||||
## Tools
|
||||
|
||||
* **Debugging:** [Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en)
|
||||
|
||||
* **Testing:** [Karma](http://karma-runner.github.io), [Protractor](https://github.com/angular/protractor)
|
||||
|
||||
* **Editor support:** [Webstorm](http://plugins.jetbrains.com/plugin/6971) (and [video](http://www.youtube.com/watch?v=LJOyrSh1kDU)), [Sublime Text](https://github.com/angular-ui/AngularJS-sublime-package), [Visual Studio](http://madskristensen.net/post/angularjs-intellisense-in-visual-studio-2012)
|
||||
|
||||
* **Workflow:** [Yeoman.io](https://github.com/yeoman/generator-angular) and [Angular Yeoman Tutorial](http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower/)
|
||||
|
||||
## Complementary Libraries
|
||||
@@ -93,37 +69,26 @@ In Angular applications, you move the job of filling page templates with data fr
|
||||
This is a short list of libraries with specific support and documentation for working with Angular. You can find a full list of all known Angular external libraries at [ngmodules.org](http://ngmodules.org/).
|
||||
|
||||
* **Internationalization:** [angular-translate](http://pascalprecht.github.io/angular-translate/), [angular-gettext](http://angular-gettext.rocketeer.be/)
|
||||
|
||||
* **RESTful services:** [Restangular](https://github.com/mgonto/restangular)
|
||||
|
||||
* **SQL and NoSQL backends:** [BreezeJS](http://www.breezejs.com/), [AngularFire](http://angularfire.com/)
|
||||
|
||||
* **UI Widgets: **[KendoUI](http://kendo-labs.github.io/angular-kendo/#/), [UI Bootstrap](http://angular-ui.github.io/bootstrap/), [Wijmo](http://wijmo.com/tag/angularjs-2/)
|
||||
|
||||
## Deployment
|
||||
|
||||
### General
|
||||
### General
|
||||
|
||||
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ngmin automation tool](http://www.thinkster.io/pick/XlWneEZCqY/angularjs-ngmin)
|
||||
|
||||
* **Tracking:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Logging Client-Side Errors](http://www.bennadel.com/blog/2542-Logging-Client-Side-Errors-With-AngularJS-And-Stacktrace-js.htm)
|
||||
|
||||
* **SEO:** [By hand](http://www.yearofmoo.com/2012/11/angularjs-and-seo.html), [prerender.io](http://prerender.io/), [Brombone](http://www.brombone.com/), [SEO.js](http://getseojs.com/), [SEO4Ajax](http://www.seo4ajax.com/)
|
||||
|
||||
### Server-Specific
|
||||
|
||||
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html)
|
||||
|
||||
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
|
||||
|
||||
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/resources/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
|
||||
|
||||
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
|
||||
|
||||
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
|
||||
|
||||
* **Rails: **[Tutorial](http://coderberry.me/blog/2013/04/22/angularjs-on-rails-4-part-1/), [AngularJS with Rails4](https://shellycloud.com/blog/2013/10/how-to-integrate-angularjs-with-rails-4), [angularjs-rails](https://github.com/hiravgandhi/angularjs-rails)
|
||||
|
||||
* **PHP: **[Building a RESTful web service](http://blog.brunoscopelliti.com/building-a-restful-web-service-with-angularjs-and-php-more-power-with-resource), [End to End with Laravel 4 (video)](http://www.youtube.com/watch?v=hqAyiqUs93c)
|
||||
|
||||
## Learning Resources
|
||||
@@ -137,18 +102,18 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
|
||||
###Videos:
|
||||
* [egghead.io](http://egghead.io/),
|
||||
* [egghead.io](http://egghead.io/)
|
||||
* [Angular on YouTube](http://youtube.com/angularjs)
|
||||
|
||||
###Courses
|
||||
* **Free on-line:**
|
||||
### Courses
|
||||
* **Free online:**
|
||||
[thinkster.io](http://thinkster.io),
|
||||
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1)
|
||||
* **Paid on-line:**
|
||||
* **Paid online:**
|
||||
[Pluralsite (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
|
||||
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
|
||||
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html)
|
||||
* **Paid on-site:**
|
||||
* **Paid onsite:**
|
||||
[angularbootcamp.com](http://angularbootcamp.com/)
|
||||
|
||||
## Getting Help
|
||||
@@ -156,19 +121,14 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
The recipe for getting help on your unique issue is to create an example that could work (even if it doesn't) in a shareable example on [Plunker](http://plnkr.co/), [JSFiddle](http://jsfiddle.net/), or similar site and then post to one of the following:
|
||||
|
||||
* [Stackoverflow.com](http://stackoverflow.com/search?q=angularjs)
|
||||
|
||||
* [AngularJS mailing list](https://groups.google.com/forum/#!forum/angular)
|
||||
|
||||
* [AngularJS IRC channel](http://webchat.freenode.net/?channels=angularjs&uio=d4)
|
||||
|
||||
## Social Channels
|
||||
|
||||
* **Daily updates:** [Google+](https://plus.google.com/u/0/+AngularJS) or [Twitter](https://twitter.com/angularjs)
|
||||
|
||||
* **Weekly newsletter:** [ng-newsletter](http://www.ng-newsletter.com/)
|
||||
|
||||
* **Meetups: **[meetup.com](http://www.meetup.com/find/?keywords=angularJS&radius=Infinity&userFreeform=San+Francisco%2C+CA&mcId=z94108&mcName=San+Francisco%2C+CA&sort=member_count&eventFilter=mysugg)
|
||||
|
||||
* **Official news and releases: **[AngularJS Blog](http://blog.angularjs.org/)
|
||||
|
||||
## Contributing to AngularJS
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
|
||||
AngularJS version 1.2 introduces several breaking changes that will may require changes to your
|
||||
AngularJS version 1.2 introduces several breaking changes that may require changes to your
|
||||
application's source code.
|
||||
|
||||
Although we try to avoid breaking changes, there are some cases where it is unavoidable.
|
||||
@@ -35,7 +35,7 @@ below should still apply, but you may want to consult the
|
||||
<li>{@link guide/migration#resource-methods-return-the-promise Resource methods return the promise}</li>
|
||||
<li>{@link guide/migration#resource-promises-are-resolved-with-the-resource-instance Resource promises are resolved with the resource instance}</li>
|
||||
<li>{@link guide/migration#$locationsearch-supports-multiple-keys $location.search supports multiple keys}</li>
|
||||
<li>{@link guide/migration#nghtmlbindunsafe-has-been-removed-and-replaced-by-nghtmlbind ngHtmlBindUnsafe has been removed and replaced by ngHtmlBind}</li>
|
||||
<li>{@link guide/migration#ngbindhtmlunsafe-has-been-removed-and-replaced-by-ngbindhtml ngBindHtmlUnsafe has been removed and replaced by ngBindHtml}</li>
|
||||
<li>{@link guide/migration#form-names-that-are-expressions-are-evaluated Form names that are expressions are evaluated}</li>
|
||||
<li>{@link guide/migration#hasownproperty-disallowed-as-an-input-name hasOwnProperty disallowed as an input name}</li>
|
||||
<li>{@link guide/migration#directives-order-of-postlink-functions-reversed Directives: Order of postLink functions reversed}</li>
|
||||
@@ -45,7 +45,7 @@ below should still apply, but you may want to consult the
|
||||
<li>{@link guide/migration#urls-are-now-sanitized-against-a-whitelist URLs are now sanitized against a whitelist}</li>
|
||||
<li>{@link guide/migration#isolate-scope-only-exposed-to-directives-with-property Isolate scope only exposed to directives with <code>scope</code> property}</li>
|
||||
<li>{@link guide/migration#change-to-interpolation-priority Change to interpolation priority}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed/suffixed-prorperties-are-non-bindable Underscore-prefixed/suffixed prorperties are non-bindable}</li>
|
||||
<li>{@link guide/migration#underscore-prefixed/suffixed-properties-are-non-bindable Underscore-prefixed/suffixed properties are non-bindable}</li>
|
||||
<li>{@link guide/migration#you-cannot-bind-to-select[multiple] You cannot bind to select[multiple]}</li>
|
||||
<li>{@link guide/migration#uncommon-region-specific-local-files-were-removed-from-i18n Uncommon region-specific local files were removed from i18n}</li>
|
||||
</ul>
|
||||
@@ -376,11 +376,11 @@ passing it to `$location`.
|
||||
See [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe).
|
||||
|
||||
|
||||
## ngHtmlBindUnsafe has been removed and replaced by ngHtmlBind
|
||||
## ngBindHtmlUnsafe has been removed and replaced by ngBindHtml
|
||||
|
||||
`ngHtmlBind` which has been moved from `ngSanitize` module to the core `ng` module.
|
||||
`ngBindHtml` which has been moved from `ngSanitize` module to the core `ng` module.
|
||||
|
||||
`ngBindHtml` provides `ngHtmlBindUnsafe` like
|
||||
`ngBindHtml` provides `ngBindHtmlUnsafe` like
|
||||
behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result
|
||||
of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanitized via
|
||||
`$sanitize` before being innerHTML'd. If the `$sanitize` service isn't available (`ngSanitize`
|
||||
@@ -588,7 +588,11 @@ See [79223eae](https://github.com/angular/angular.js/commit/79223eae502283889334
|
||||
[#4528](https://github.com/angular/angular.js/issues/4528), and
|
||||
[#4649](https://github.com/angular/angular.js/issues/4649)
|
||||
|
||||
## Underscore-prefixed/suffixed prorperties are non-bindable
|
||||
## Underscore-prefixed/suffixed properties are non-bindable
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p>**Reverted**: This breaking change has been reverted in 1.2.1, and so can be ignored if you're using **version 1.2.1 or higher**</p>
|
||||
</div>
|
||||
|
||||
This change introduces the notion of "private" properties (properties
|
||||
whose names begin and/or end with an underscore) on the scope chain.
|
||||
|
||||
@@ -110,7 +110,7 @@ myApp.factory('clientId', function clientIdFactory() {
|
||||
But given that the token is just a string literal, sticking with the Value recipe is still more
|
||||
appropriate as it makes the code easier to follow.
|
||||
|
||||
Let's say, however, that we would also like create a service that computes a token used for
|
||||
Let's say, however, that we would also like to create a service that computes a token used for
|
||||
authentication against a remote API. This token will be called 'apiToken' and will be computed
|
||||
based on the `clientId` value and a secret stored in browser's local storage:
|
||||
|
||||
@@ -228,7 +228,7 @@ myApp.provider('unicornLauncher', function UnicornLauncherProvider() {
|
||||
// let's assume that the UnicornLauncher constructor was also changed to
|
||||
// accept and use the useTinfoilShielding argument
|
||||
return new UnicornLauncher(apiToken, useTinfoilShielding);
|
||||
}]);
|
||||
}];
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
@@ -18,8 +18,12 @@ watch {@link guide/expression expressions} and propagate events.
|
||||
propagate any model changes through the system into the view from outside of the "Angular
|
||||
realm" (controllers, services, Angular event handlers).
|
||||
|
||||
- Scopes can be nested to isolate application components while providing access to shared model
|
||||
properties. A scope (prototypically) inherits properties from its parent scope.
|
||||
- Scopes can be nested to limit access to the properties of application components while providing
|
||||
access to shared model properties. Nested scopes are either "child scopes" or "isolate scopes".
|
||||
A "child scope" (prototypically) inherits properties from its parent scope. An "isolate scope"
|
||||
does not. See {@link
|
||||
guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive isolated
|
||||
scopes} for more information.
|
||||
|
||||
- Scopes provide context against which {@link guide/expression expressions} are evaluated. For
|
||||
example `{{username}}` expression is meaningless, unless it is evaluated against a specific
|
||||
@@ -177,7 +181,7 @@ To examine the scope in the debugger:
|
||||
2. The debugger allows you to access the currently selected element in the console as `$0`
|
||||
variable.
|
||||
|
||||
3. To retrieve the associated scope in console execute: `angular.element($0).scope()`
|
||||
3. To retrieve the associated scope in console execute: `angular.element($0).scope()` or just type $scope
|
||||
|
||||
|
||||
## Scope Events Propagation
|
||||
@@ -259,8 +263,8 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||
For mutations to be properly observed, you should make them only within the {@link
|
||||
api/ng.$rootScope.Scope#methods_$apply scope.$apply()}. (Angular APIs do this
|
||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||
or asynchronous work with {@link api/ng.$http $http} or {@link
|
||||
api/ng.$timeout $timeout} services.
|
||||
or asynchronous work with {@link api/ng.$http $http}, {@link api/ng.$timeout $timeout}
|
||||
or {@link api/ng.$interval $interval} services.
|
||||
|
||||
4. **Mutation observation**
|
||||
|
||||
@@ -306,6 +310,8 @@ api/ng.directive:ngController ng-controller} and {@link
|
||||
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||
and attach the child scope to the corresponding DOM element. You can retrieve a scope for any DOM
|
||||
element by using an `angular.element(aDomElement).scope()` method call.
|
||||
See the {@link guide/directive#creating-custom-directives_demo_isolating-the-scope-of-a-directive
|
||||
directives guide} for more information about isolate scopes.
|
||||
|
||||
### Controllers and Scopes
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ for how to contribute your own code to AngularJS.
|
||||
Before you can build AngularJS, you must install and configure the following dependencies on your
|
||||
machine:
|
||||
|
||||
* {@link http://git-scm.com/ Git}: The {@link http://help.github.com/mac-git-installation Github Guide to
|
||||
* {@link http://git-scm.com/ Git}: The {@link https://help.github.com/articles/set-up-git Github Guide to
|
||||
Installing Git} is a good source of information.
|
||||
|
||||
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation, run a
|
||||
@@ -46,6 +46,8 @@ and included in your {@link http://docs.oracle.com/javase/tutorial/essential/env
|
||||
npm install -g bower
|
||||
```
|
||||
|
||||
**Note:** You may need to use sudo (for OSX, *nix, BSD etc) or run your command shell as Administrator (for Windows) to install Grunt &
|
||||
Bower globally.
|
||||
|
||||
## Forking Angular on Github
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ illustration we typically build snappy apps with hundreds or thousands of active
|
||||
|
||||
### How big is the angular.js file that I need to include?
|
||||
|
||||
The size of the file is < 29KB compressed and minified.
|
||||
The size of the file is < 36KB compressed and minified.
|
||||
|
||||
|
||||
### Can I use the open-source Closure Library with Angular?
|
||||
|
||||
@@ -85,7 +85,7 @@ to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></l
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.10 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
|
||||
@@ -26,7 +26,7 @@ angular-seed, and run the application in the browser.
|
||||
<ol>
|
||||
<li>In a <i>separate</i> terminal tab or window, run <code>node ./scripts/web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a
|
||||
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
||||
href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>For other http servers:</b>
|
||||
@@ -54,7 +54,7 @@ angular-seed, and run the application in the browser.
|
||||
<li><b>For node.js users:</b>
|
||||
<ol>
|
||||
<li>In a <i>separate</i> terminal tab or window, run <code>node scripts\web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
||||
<li>Open a browser window for the app and navigate to <a href="http://localhost:8000/app/index.html" target="_blank">`http://localhost:8000/app/index.html`</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><b>For other http servers:</b>
|
||||
@@ -179,7 +179,7 @@ For the purposes of this tutorial, we modified the angular-seed with the followi
|
||||
* Removed the example app
|
||||
* Added phone images to `app/img/phones/`
|
||||
* Added phone data files (JSON) to `app/phones/`
|
||||
* Added [Bootstrap](http://twitter.github.com/bootstrap/) files to `app/css/` and `app/img/`
|
||||
* Added [Bootstrap](http://getbootstrap.com) files to `app/css/` and `app/img/`
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -180,11 +180,15 @@ is available to be injected.
|
||||
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
|
||||
this tutorial in Jasmine. You can learn about Jasmine on the {@link
|
||||
http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
|
||||
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
||||
http://pivotal.github.com/jasmine/ Jasmine home page} and at the {@link
|
||||
http://pivotal.github.io/jasmine/ Jasmine docs}.
|
||||
|
||||
The angular-seed project is pre-configured to run all unit tests using {@link
|
||||
http://karma-runner.github.io/ Karma}. To run the test, do the following:
|
||||
http://karma-runner.github.io/ Karma}. Ensure that the necessary karma plugins are installed.
|
||||
You can do this by issuing `npm install` into your terminal.
|
||||
|
||||
|
||||
To run the test, do the following:
|
||||
|
||||
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
||||
`./scripts/test.sh` to start the Karma server (the config file necessary to start the server
|
||||
|
||||
@@ -127,8 +127,8 @@ end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests
|
||||
with unit tests, Karma will exit after the test run and will not automatically rerun the test
|
||||
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
|
||||
|
||||
Note: You must ensure you've installed karma-ng-scenario prior to running the `e2e-test.sh` script.
|
||||
You can do this by issuing `npm install karma-ng-scenario` into your terminal.
|
||||
Note: You must ensure you've installed the karma-ng-scenario framework plugin prior to running the
|
||||
`e2e-test.sh` script. You can do this by issuing `npm install` into your terminal.
|
||||
|
||||
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
|
||||
@@ -154,7 +154,7 @@ really is that easy to set up any functional, readable, end-to-end test.
|
||||
`ngController` declaration to the HTML element because it is the common parent of both the body
|
||||
and title elements:
|
||||
|
||||
<html ng-app ng-controller="PhoneListCtrl">
|
||||
<html ng-app="phonecatApp" ng-controller="PhoneListCtrl">
|
||||
|
||||
Be sure to __remove__ the `ng-controller` declaration from the body element.
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ phonecatApp.controller('PhoneListCtrl', function ($scope) {
|
||||
record. This property is used to order phones by age.
|
||||
|
||||
* We added a line to the controller that sets the default value of `orderProp` to `age`. If we had
|
||||
not set the default value here, the model would stay uninitialized until our user would pick an
|
||||
not set the default value here, the model would stay uninitialized until our user picks an
|
||||
option from the drop down menu.
|
||||
|
||||
This is a good time to talk about two-way data-binding. Notice that when the app is loaded in the
|
||||
@@ -112,11 +112,12 @@ describe('PhoneCat controllers', function() {
|
||||
describe('PhoneListCtrl', function(){
|
||||
var scope, ctrl;
|
||||
|
||||
beforeEach(function() {
|
||||
scope = {},
|
||||
ctrl = new PhoneListCtrl(scope);
|
||||
});
|
||||
|
||||
beforeEach(module('phonecatApp'));
|
||||
|
||||
beforeEach(inject(function($controller) {
|
||||
scope = {};
|
||||
ctrl = $controller('PhoneListCtrl', {$scope:scope});
|
||||
}));
|
||||
|
||||
it('should create "phones" model with 3 phones', function() {
|
||||
expect(scope.phones.length).toBe(3);
|
||||
|
||||
@@ -199,7 +199,7 @@ isolated from the work done in other tests.
|
||||
|
||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||
|
||||
* We called the injected `$controller` function passing the name of the`PhoneListCtrl` controller
|
||||
* We called the injected `$controller` function passing the name of the `PhoneListCtrl` controller
|
||||
and the created scope as parameters.
|
||||
|
||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||
|
||||
@@ -64,7 +64,7 @@ We also added phone images next to each record using an image tag with the {@lin
|
||||
api/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 class="diagram" src="{{phone.imageUrl}}">`).
|
||||
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.
|
||||
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ to various URLs and verify that the correct view was rendered.
|
||||
<pre>
|
||||
...
|
||||
it('should redirect index.html to index.html#/phones', function() {
|
||||
browser().navigateTo('../../app/index.html');
|
||||
browser().navigateTo('app/index.html');
|
||||
expect(browser().location().url()).toBe('/phones');
|
||||
});
|
||||
...
|
||||
@@ -266,7 +266,7 @@ to various URLs and verify that the correct view was rendered.
|
||||
describe('Phone detail view', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
||||
browser().navigateTo('app/index.html#/phones/nexus-s');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ Angular's server}.
|
||||
|
||||
<button ng-click="hello('Elmo')">Hello</button>
|
||||
|
||||
to the `phone-details.html` template.
|
||||
to the `phone-detail.html` template.
|
||||
|
||||
<div style="display: none">
|
||||
TODO!
|
||||
|
||||
@@ -11,7 +11,7 @@ In this step, you will improve the way our app fetches data.
|
||||
<div doc-tutorial-reset="11"></div>
|
||||
|
||||
|
||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||
The next improvement we will make to our app is to define a custom service that represents a {@link
|
||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||
api/ng.$http $http} API, HTTP methods and URLs.
|
||||
@@ -185,7 +185,7 @@ describe('PhoneCat controllers', function() {
|
||||
xyzPhoneData = function() {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ __`app/index.html`.__
|
||||
<pre>
|
||||
...
|
||||
<!-- jQuery is used for JavaScript animations (include this before angular.js) -->
|
||||
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||
|
||||
<!-- required module to enable animation support in AngularJS -->
|
||||
<script src="lib/angular/angular-animate.js"></script>
|
||||
@@ -56,6 +56,10 @@ __`app/index.html`.__
|
||||
...
|
||||
</pre>
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
|
||||
</div>
|
||||
|
||||
Animations can now be created within the CSS code (`animations.css`) as well as the JavaScript code (`animations.js`).
|
||||
But before we start, let's create a new module which uses the ngAnimate module as a dependency just like we did before
|
||||
with `ngResource`.
|
||||
@@ -153,7 +157,7 @@ __`app/css/animations.css`__
|
||||
</pre>
|
||||
|
||||
As you can see our `phone-listing` CSS class is combined together with the animation hooks that occur when items are
|
||||
inserted info and removed from the list:
|
||||
inserted into and removed from the list:
|
||||
|
||||
* The `ng-enter` class is applied to the element when a new phone is added to the list and rendered on the page.
|
||||
* The `ng-move` class is applied when items are moved around in the list.
|
||||
@@ -383,10 +387,6 @@ isn't required to do JavaScript animations with AngularJS, but we're going to us
|
||||
your own JavaScript animation library is beyond the scope of this tutorial. For more on
|
||||
`jQuery.animate`, see the {@link http://api.jquery.com/animate/ jQuery documentation}.
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
|
||||
</div>
|
||||
|
||||
The `addClass` and `removeClass` callback functions are called whenever an a class is added or removed
|
||||
on the element that contains the class we registered, which is in this case `.phone`. When the `.active`
|
||||
class is added to the element (via the `ng-class` directive) the `addClass` JavaScript callback will
|
||||
|
||||
@@ -34,8 +34,8 @@ describe('ngdoc', function() {
|
||||
var d1 = new Doc('@name a.b.c').parse();
|
||||
var d2 = new Doc('@name a.b.ng-c').parse();
|
||||
var d3 = new Doc('@name some text: more text').parse();
|
||||
expect(ngdoc.metadata([d1])[0].shortName).toEqual('c');
|
||||
expect(ngdoc.metadata([d2])[0].shortName).toEqual('ng-c');
|
||||
expect(ngdoc.metadata([d1])[0].shortName).toEqual('a.b.c');
|
||||
expect(ngdoc.metadata([d2])[0].shortName).toEqual('a.b.ng-c');
|
||||
expect(ngdoc.metadata([d3])[0].shortName).toEqual('more text');
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('Docs Links', function() {
|
||||
});
|
||||
|
||||
it('should have an "view source" button', function() {
|
||||
spyOn(gruntUtil, 'getVersion').andReturn({cdn: '1.2.299'});
|
||||
spyOn(gruntUtil, 'getVersion').andReturn({full: '1.2.299'});
|
||||
|
||||
expect(doc.html()).
|
||||
toContain('<a href="http://github.com/angular/angular.js/tree/v1.2.299/test.js#L42" class="view-source btn btn-action"><i class="icon-zoom-in"> </i> View source</a>');
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
exports.appCache = appCache;
|
||||
var fs = require('q-fs');
|
||||
var fs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
function identity($) {return $;}
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ function writeTheRest(writesFuture) {
|
||||
var versions = ngdoc.ngVersions();
|
||||
var currentVersion = ngdoc.ngCurrentVersion();
|
||||
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'directory'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'directory'));
|
||||
|
||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ exports.collect = collect;
|
||||
|
||||
var ngdoc = require('./ngdoc.js'),
|
||||
Q = require('qq'),
|
||||
qfs = require('q-fs'),
|
||||
qfs = require('q-io/fs'),
|
||||
PATH = require('path');
|
||||
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
@@ -144,6 +144,27 @@
|
||||
.content h4,
|
||||
.content h5 {
|
||||
margin-top: 1em;
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
font-size: 36px;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.content h3 {
|
||||
font-size: 24px;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: .5em;
|
||||
}
|
||||
|
||||
.content h4 {
|
||||
font-size: 16px;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.content ul {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
ul.parameters > li > p,
|
||||
@@ -522,6 +543,10 @@ pre ol li {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.definition-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.component-heading {
|
||||
text-transform:capitalize;
|
||||
}
|
||||
|
||||
@@ -335,9 +335,8 @@
|
||||
|
||||
<div ng-hide="loading" ng-include src="currentPage.partialUrl" onload="afterPartialLoaded()" autoscroll class="content slide-reveal"></div>
|
||||
|
||||
<div id="disqus" class="disqus">
|
||||
<h2>Discussion</h2>
|
||||
<div id="disqus_thread" class="content-panel-content"></div>
|
||||
<div class="alert alert-info">
|
||||
<a href="http://blog.angularjs.org/2013/11/farewell-disqus.html">Where did Disqus go?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -365,7 +364,7 @@
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p class="pull-right"><a href="#">Back to top</a></p>
|
||||
<p class="pull-right"><a back-to-top href="#">Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2012
|
||||
|
||||
@@ -273,10 +273,10 @@ docsApp.directive.docTutorialNav = function(templateMerge) {
|
||||
element.addClass('btn-group');
|
||||
element.addClass('tutorial-nav');
|
||||
element.append(templateMerge(
|
||||
'<li class="btn btn-primary"><a href="tutorial/{{prev}}"><i class="icon-step-backward"></i> Previous</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><i class="icon-play"></i> Live Demo</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><i class="icon-search"></i> Code Diff</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="tutorial/{{next}}">Next <i class="icon-step-forward"></i></a></li>', props));
|
||||
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="icon-step-backward"></i> Previous</li></a>\n' +
|
||||
'<a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="icon-play"></i> Live Demo</li></a>\n' +
|
||||
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="icon-search"></i> Code Diff</li></a>\n' +
|
||||
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="icon-step-forward"></i></li></a>', props));
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -372,6 +372,21 @@ docsApp.directive.errorDisplay = ['$location', 'errorLinkFilter', function ($loc
|
||||
}];
|
||||
|
||||
|
||||
/**
|
||||
* backToTop Directive
|
||||
* @param {Function} $anchorScroll
|
||||
*
|
||||
* @description Ensure that the browser scrolls when the anchor is clicked
|
||||
*/
|
||||
docsApp.directive.backToTop = ['$anchorScroll', function($anchorScroll) {
|
||||
return function link(scope, element) {
|
||||
element.on('click', function(event) {
|
||||
scope.$apply($anchorScroll);
|
||||
});
|
||||
};
|
||||
}];
|
||||
|
||||
|
||||
docsApp.serviceFactory.angularUrls = function($document) {
|
||||
var urls = {};
|
||||
|
||||
@@ -680,7 +695,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
var currentPageId = $location.path();
|
||||
$scope.partialTitle = $scope.currentPage.shortName;
|
||||
$window._gaq.push(['_trackPageview', currentPageId]);
|
||||
loadDisqus(currentPageId);
|
||||
};
|
||||
|
||||
/** stores a cookie that is used by apache to decide which manifest ot send */
|
||||
@@ -892,29 +906,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
return namespace;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadDisqus(currentPageId) {
|
||||
// http://docs.disqus.com/help/2/
|
||||
window.disqus_shortname = 'angularjs-next';
|
||||
window.disqus_identifier = currentPageId;
|
||||
window.disqus_url = 'http://docs.angularjs.org' + currentPageId;
|
||||
|
||||
if ($location.host() == 'localhost') {
|
||||
return; // don't display disqus on localhost, comment this out if needed
|
||||
//window.disqus_developer = 1;
|
||||
}
|
||||
|
||||
// http://docs.disqus.com/developers/universal/
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = 'http://angularjs.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] ||
|
||||
document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
|
||||
angular.element(document.getElementById('disqus_thread')).html('');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
* for testability
|
||||
*/
|
||||
var pathUtils = require('path');
|
||||
var qfs = require('q-fs');
|
||||
var qfs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
var OUTPUT_DIR = pathUtils.join('build','docs');
|
||||
var TEMPLATES_DIR = pathUtils.join('docs','src','templates');
|
||||
@@ -76,7 +76,7 @@ function symlink(from, to, type) {
|
||||
// qfs will normalize the path arguments for us here
|
||||
return qfs.exists(to).then(function(exists) {
|
||||
if (!exists) {
|
||||
return qfs.symbolicLink(to, from, type);
|
||||
return qfs.symbolicLink(to, from, type || 'file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -25,11 +28,12 @@ rm -f angular.js.size
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
# DOCS generator unit tests #
|
||||
grunt test:docgen --no-color
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# END TO END TESTS #
|
||||
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ module.exports = function(config) {
|
||||
junitReporter: {
|
||||
outputFile: 'test_out/e2e.xml',
|
||||
suite: 'E2E'
|
||||
}
|
||||
},
|
||||
|
||||
browserNoActivityTimeout: 90000
|
||||
});
|
||||
};
|
||||
|
||||
+122
-6
@@ -5,14 +5,26 @@ module.exports = function(config, specificOptions) {
|
||||
logLevel: config.LOG_INFO,
|
||||
logColors: true,
|
||||
browsers: ['Chrome'],
|
||||
browserDisconnectTimeout: 5000,
|
||||
browserDisconnectTimeout: 10000,
|
||||
browserDisconnectTolerance: 2,
|
||||
browserNoActivityTimeout: 20000,
|
||||
|
||||
|
||||
// config for Travis CI
|
||||
// SauceLabs config for local development.
|
||||
sauceLabs: {
|
||||
testName: specificOptions.testName || 'AngularJS',
|
||||
startConnect: false,
|
||||
tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
|
||||
startConnect: true,
|
||||
options: {
|
||||
'selenium-version': '2.37.0'
|
||||
}
|
||||
},
|
||||
|
||||
// BrowserStack config for local development.
|
||||
browserStack: {
|
||||
project: 'AngularJS',
|
||||
name: specificOptions.testName,
|
||||
startTunnel: true,
|
||||
timeout: 600 // 10min
|
||||
},
|
||||
|
||||
// For more browsers on Sauce Labs see:
|
||||
@@ -49,12 +61,77 @@ module.exports = function(config, specificOptions) {
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 2012',
|
||||
version: '10'
|
||||
},
|
||||
'SL_IE_11': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 8.1',
|
||||
version: '11'
|
||||
},
|
||||
|
||||
'BS_Chrome': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
},
|
||||
'BS_Safari': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
},
|
||||
'BS_Firefox': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'firefox',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_8': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '8.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE_9': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '9.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE_10': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '10.0',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_11': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '11.0',
|
||||
os: 'Windows',
|
||||
os_version: '8.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
var buildLabel = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
|
||||
config.logLevel = config.LOG_DEBUG;
|
||||
config.transports = ['websocket', 'xhr-polling'];
|
||||
|
||||
config.browserStack.build = buildLabel;
|
||||
config.browserStack.startTunnel = false;
|
||||
|
||||
config.sauceLabs.build = buildLabel;
|
||||
config.sauceLabs.startConnect = false;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
// TODO(vojta): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
config.transports = ['xhr-polling'];
|
||||
@@ -62,8 +139,47 @@ module.exports = function(config, specificOptions) {
|
||||
// Debug logging into a file, that we print out at the end of the build.
|
||||
config.loggers.push({
|
||||
type: 'file',
|
||||
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log'),
|
||||
level: config.LOG_DEBUG
|
||||
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log')
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Terrible hack to workaround inflexibility of log4js:
|
||||
// - ignore web-server's 404 warnings,
|
||||
// - ignore DEBUG logs (on Travis), we log them into a file instead.
|
||||
var IGNORED_404 = [
|
||||
'/favicon.ico',
|
||||
'/%7B%7BtestUrl%7D%7D',
|
||||
'/someSanitizedUrl',
|
||||
'/{{testUrl}}'
|
||||
];
|
||||
var log4js = require('./node_modules/karma/node_modules/log4js');
|
||||
var layouts = require('./node_modules/karma/node_modules/log4js/lib/layouts');
|
||||
var originalConfigure = log4js.configure;
|
||||
log4js.configure = function(log4jsConfig) {
|
||||
var consoleAppender = log4jsConfig.appenders.shift();
|
||||
var originalResult = originalConfigure.call(log4js, log4jsConfig);
|
||||
var layout = layouts.layout(consoleAppender.layout.type, consoleAppender.layout);
|
||||
|
||||
|
||||
|
||||
log4js.addAppender(function(log) {
|
||||
var msg = log.data[0];
|
||||
|
||||
// ignore web-server's 404s
|
||||
if (log.categoryName === 'web-server' && log.level.levelStr === config.LOG_WARN &&
|
||||
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1})) {
|
||||
return;
|
||||
}
|
||||
|
||||
// on Travis, ignore DEBUG statements
|
||||
if (process.env.TRAVIS && log.level.levelStr === config.LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(layout(log));
|
||||
});
|
||||
|
||||
return originalResult;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
|
||||
|
||||
var HOSTNAME = 'localhost';
|
||||
var PORTS = require('../grunt/utils').availablePorts;
|
||||
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
|
||||
var READY_FILE = process.env.SAUCE_CONNECT_READY_FILE;
|
||||
|
||||
// We need to start fake servers, otherwise the tunnel does not start.
|
||||
var fakeServers = [];
|
||||
var hosts = [];
|
||||
|
||||
PORTS.forEach(function(port) {
|
||||
fakeServers.push(http.createServer(function() {}).listen(port));
|
||||
hosts.push({
|
||||
name: HOSTNAME,
|
||||
port: port,
|
||||
sslFlag: 0
|
||||
});
|
||||
});
|
||||
|
||||
var tunnel = new BrowserStackTunnel({
|
||||
key: ACCESS_KEY,
|
||||
hosts: hosts
|
||||
});
|
||||
|
||||
console.log('Starting tunnel on ports', PORTS.join(', '));
|
||||
tunnel.start(function(error) {
|
||||
if (error) {
|
||||
console.error('Can not establish the tunnel', error);
|
||||
} else {
|
||||
console.log('Tunnel established.');
|
||||
fakeServers.forEach(function(server) {
|
||||
server.close();
|
||||
});
|
||||
|
||||
if (READY_FILE) {
|
||||
fs.writeFile(READY_FILE, '');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tunnel.on('error', function(error) {
|
||||
console.error(error);
|
||||
});
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
node ./lib/browser-stack/start-tunnel.js &
|
||||
+26
-3
@@ -5,6 +5,22 @@ var spawn = require('child_process').spawn;
|
||||
var version;
|
||||
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
|
||||
|
||||
var PORT_MIN = 8000;
|
||||
var PORT_MAX = 9999;
|
||||
var TRAVIS_BUILD_NUMBER = parseInt(process.env.TRAVIS_BUILD_NUMBER, 10);
|
||||
var getRandomPorts = function() {
|
||||
if (!process.env.TRAVIS) {
|
||||
return [9876, 9877];
|
||||
}
|
||||
|
||||
// Generate two numbers between PORT_MIN and PORT_MAX, based on TRAVIS_BUILD_NUMBER.
|
||||
return [
|
||||
PORT_MIN + (TRAVIS_BUILD_NUMBER % (PORT_MAX - PORT_MIN)),
|
||||
PORT_MIN + ((TRAVIS_BUILD_NUMBER + 100) % (PORT_MAX - PORT_MIN))
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function() {
|
||||
@@ -20,13 +36,12 @@ module.exports = {
|
||||
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
|
||||
var match = package.version.match(/^([^\-]*)(?:\-(.+))?$/);
|
||||
var semver = match[1].split('.');
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
|
||||
var fullVersion = match[1];
|
||||
|
||||
if (match[2]) {
|
||||
fullVersion += '-';
|
||||
fullVersion += (match[2] == 'snapshot') ? hash : match[2];
|
||||
fullVersion += (match[2] == 'snapshot') ? getSnapshotSuffix() : match[2];
|
||||
}
|
||||
|
||||
version = {
|
||||
@@ -39,6 +54,12 @@ module.exports = {
|
||||
};
|
||||
|
||||
return version;
|
||||
|
||||
function getSnapshotSuffix() {
|
||||
var jenkinsBuild = process.env.BUILD_NUMBER || 'local';
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'build.'+jenkinsBuild+'+sha.'+hash;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -295,5 +316,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
// see http://saucelabs.com/docs/connect#localhost
|
||||
sauceLabsAvailablePorts: [9000, 9001, 9080, 9090, 9876]
|
||||
sauceLabsAvailablePorts: [9000, 9001, 9080, 9090, 9876],
|
||||
// pseudo-random port numbers for BrowserStack
|
||||
availablePorts: getRandomPorts()
|
||||
};
|
||||
|
||||
@@ -36,8 +36,8 @@ ARGS=""
|
||||
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
|
||||
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
|
||||
fi
|
||||
if [ ! -z "$SAUCE_CONNECT_READY_FILE" ]; then
|
||||
ARGS="$ARGS --readyfile $SAUCE_CONNECT_READY_FILE"
|
||||
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
|
||||
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
+13
-10
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.2.1",
|
||||
"cdnVersion": "1.2.0",
|
||||
"codename": "underscore-empathy",
|
||||
"version": "1.2.7",
|
||||
"cdnVersion": "1.2.6",
|
||||
"codename": "emoji-clairvoyance",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,34 +10,37 @@
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.1",
|
||||
"bower": "~1.2.2",
|
||||
"grunt-bump": "~0.0.13",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-compress": "~0.5.2",
|
||||
"grunt-contrib-connect": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.4.1",
|
||||
"jasmine-node": "~1.11.0",
|
||||
"q": "~0.9.2",
|
||||
"q-fs": "~0.1.36",
|
||||
"q-io": "~1.10.6",
|
||||
"qq": "~0.3.5",
|
||||
"shelljs": "~0.2.6",
|
||||
"karma": "~0.11",
|
||||
"karma": "0.11.11",
|
||||
"karma-jasmine": "~0.1.0",
|
||||
"karma-chrome-launcher": "~0.1.0",
|
||||
"karma-firefox-launcher": "~0.1.0",
|
||||
"karma-ng-scenario": "~0.1.0",
|
||||
"karma-junit-reporter": "git://github.com/karma-runner/karma-junit-reporter#karma-0.11",
|
||||
"karma-sauce-launcher": "~0.1.1",
|
||||
"karma-junit-reporter": "~0.2.1",
|
||||
"karma-sauce-launcher": "~0.2.0",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"yaml-js": "~0.0.8",
|
||||
"marked": "0.2.9",
|
||||
"rewire": "1.1.3",
|
||||
"grunt-jasmine-node": "~0.1.0",
|
||||
"grunt-jasmine-node": "git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code",
|
||||
"grunt-parallel": "~0.3.1",
|
||||
"grunt-ddescribe-iit": "~0.0.1",
|
||||
"grunt-merge-conflict": "~0.0.1",
|
||||
"promises-aplus-tests": "~1.3.2",
|
||||
"grunt-shell": "~0.4.0",
|
||||
"semver": "~2.1.0",
|
||||
"lodash": "~2.1.0"
|
||||
"lodash": "~2.1.0",
|
||||
"karma-browserstack-launcher": "git://github.com/karma-runner/karma-browserstack-launcher.git#master",
|
||||
"browserstacktunnel-wrapper": "~1.1.1"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
@@ -46,6 +49,6 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"grunt-contrib-jshint": "~0.6.4"
|
||||
"grunt-contrib-jshint": "~0.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function catch_errors() {
|
||||
echo "ERROR. That's life."
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap catch_errors ERR
|
||||
|
||||
TMP_FILE='changelog.tmp'
|
||||
CHANGELOG_FILE='CHANGELOG.md'
|
||||
|
||||
echo "Getting current version..."
|
||||
VERSION=`./version.js --current`
|
||||
|
||||
echo "Generating changelog..."
|
||||
./changelog.js $VERSION $TMP_FILE
|
||||
|
||||
cat $CHANGELOG_FILE >> $TMP_FILE
|
||||
mv -f $TMP_FILE $CHANGELOG_FILE
|
||||
|
||||
|
||||
echo "Updating version..."
|
||||
./version.js --remove-snapshot
|
||||
|
||||
echo "CONFIRM TO COMMIT"
|
||||
read WHATEVER
|
||||
|
||||
|
||||
echo "Creating commit..."
|
||||
git commit version.yaml CHANGELOG.md -m "chore(relase): cutting the v$VERSION release"
|
||||
|
||||
echo "Creating tag..."
|
||||
git tag "v$VERSION"
|
||||
@@ -0,0 +1,15 @@
|
||||
# Angular Bower Script
|
||||
|
||||
Script for updating the Angular bower repos from current local build.
|
||||
|
||||
## Instructions
|
||||
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
SCRIPT_DIR=`pwd`
|
||||
TMP_DIR=../../tmp
|
||||
BUILD_DIR=../../build
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
REPOS=(
|
||||
angular \
|
||||
angular-animate \
|
||||
angular-cookies \
|
||||
angular-i18n \
|
||||
angular-loader \
|
||||
angular-mocks \
|
||||
angular-route \
|
||||
angular-resource \
|
||||
angular-sanitize \
|
||||
angular-scenario \
|
||||
angular-touch \
|
||||
)
|
||||
|
||||
#
|
||||
# clone repos
|
||||
#
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Cloning bower-$repo"
|
||||
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# move the files from the build
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
|
||||
then
|
||||
echo "-- Updating files in bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd $SCRIPT_DIR
|
||||
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
|
||||
fi
|
||||
done
|
||||
|
||||
# move i18n files
|
||||
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
|
||||
|
||||
# move csp.css
|
||||
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
|
||||
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Updating version in bower-$repo to $NEW_VERSION"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
sed -i .tmp -E 's/"(version)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
sed -i .tmp -E 's/"(angular.*)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
# delete tmp files
|
||||
rm *.tmp
|
||||
git add -A
|
||||
|
||||
echo "-- Committing, tagging and pushing bower-$repo"
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git tag v$NEW_VERSION
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
cd $SCRIPT_DIR
|
||||
done
|
||||
@@ -0,0 +1,18 @@
|
||||
# code.angular.js.org Script
|
||||
|
||||
Script for updating code.angularjs.org repo from current local build.
|
||||
|
||||
Note: For a snapshot build, this will fetch the data from the ci server
|
||||
and NOT take the local build!
|
||||
|
||||
## Instructions
|
||||
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
TMP_DIR=../../tmp
|
||||
REPO_DIR=$TMP_DIR/code.angularjs.org
|
||||
BUILD_DIR=../../build
|
||||
SCRIPT_DIR=`pwd`
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
#
|
||||
# Snapshot builds are kept in a temp directory in code.angularjs.org
|
||||
# that is filled by calling a php script there.
|
||||
#
|
||||
if [[ "$NEW_VERSION" =~ sha ]] ;then
|
||||
echo "-- updating snapshot version"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
#
|
||||
# clone
|
||||
#
|
||||
|
||||
echo "-- Cloning code.angularjs.org"
|
||||
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
|
||||
|
||||
#
|
||||
# copy the files from the build
|
||||
#
|
||||
|
||||
echo "-- Updating code.angularjs.org"
|
||||
mkdir $REPO_DIR/$NEW_VERSION
|
||||
cd $REPO_DIR
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd $SCRIPT_DIR
|
||||
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
|
||||
|
||||
#
|
||||
# commit and push
|
||||
#
|
||||
echo "-- Committing and pushing code.angularjs.org"
|
||||
cd $REPO_DIR
|
||||
git add -A
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git push origin master
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
#
|
||||
# refresh code.angularjs.org from github
|
||||
#
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Increment version and add "-snapshot" ##"
|
||||
echo "############################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- increment version "
|
||||
grunt bump:$BUMP_TYPE
|
||||
NEXT_VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
sed -i .tmp -E 's/"version": "(.*)"/"version": "\1-snapshot"/' package.json
|
||||
echo "-- new version: `grep '"version"' package.json`"
|
||||
echo "-- commit"
|
||||
git add package.json
|
||||
git commit -m "chore(release): start v$NEXT_VERSION"
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Remove "-snapshot" from version ########"
|
||||
echo "############################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- old version: `grep '"version"' package.json`"
|
||||
sed -i .tmp -E 's/"version": "(.*)-snapshot"/"version": "\1"/' package.json
|
||||
VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
echo "-- local version: $VERSION"
|
||||
|
||||
echo "-- commit and tag with v$VERSION"
|
||||
git add package.json
|
||||
git commit -m "chore(release): cut v$VERSION release"
|
||||
git tag -m "v$VERSION" v$VERSION
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
./jenkins_build.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
./scripts/bower/publish.sh
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Cut release ################"
|
||||
echo "#################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
# Jump onto the master branch and make sure we are using the latest
|
||||
git checkout -f master
|
||||
git merge --ff-only origin/master
|
||||
|
||||
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
|
||||
# Bump versions: remove "-snapshot" suffix
|
||||
./scripts/jenkins/bump-remove-snapshot.sh
|
||||
|
||||
# Build
|
||||
./jenkins_build.sh
|
||||
|
||||
# Bump versions: Increment version and add "-snapshot"
|
||||
./scripts/jenkins/bump-increment.sh $BUMP_TYPE
|
||||
|
||||
echo "-- push to Github"
|
||||
# push the commits to github
|
||||
git push origin master
|
||||
# push the release tag
|
||||
git push origin v`cat build/version.txt`
|
||||
|
||||
# Update code.angularjs.org
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
# Update bower
|
||||
./scripts/bower/publish.sh
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $JOB = "unit" ]; then
|
||||
grunt ci-checks
|
||||
grunt test:docgen
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
elif [ $JOB = "e2e" ]; then
|
||||
grunt test:e2e --browsers SL_Chrome --reporters dots
|
||||
else
|
||||
echo "Unknown job type. Please set JOB=unit or JOB=e2e."
|
||||
fi
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
|
||||
# Wait for Connect to be ready before exiting
|
||||
while [ ! -f $SAUCE_CONNECT_READY_FILE ]; do
|
||||
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
|
||||
sleep .5
|
||||
done
|
||||
+1
-1
@@ -162,4 +162,4 @@
|
||||
"nullFormCtrl": false
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+62
-44
@@ -80,7 +80,7 @@
|
||||
-assertArgFn,
|
||||
-assertNotHasOwnProperty,
|
||||
-getter,
|
||||
-getBlockElements
|
||||
-getBlockElements,
|
||||
|
||||
*/
|
||||
|
||||
@@ -213,7 +213,9 @@ function forEach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (isFunction(obj)){
|
||||
for (key in obj) {
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
|
||||
// Need to check if hasOwnProperty exists,
|
||||
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
|
||||
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
|
||||
iterator.call(context, obj[key], key);
|
||||
}
|
||||
}
|
||||
@@ -393,7 +395,7 @@ function valueFn(value) {return function() {return value;};}
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is undefined.
|
||||
*/
|
||||
function isUndefined(value){return typeof value == 'undefined';}
|
||||
function isUndefined(value){return typeof value === 'undefined';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -407,7 +409,7 @@ function isUndefined(value){return typeof value == 'undefined';}
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is defined.
|
||||
*/
|
||||
function isDefined(value){return typeof value != 'undefined';}
|
||||
function isDefined(value){return typeof value !== 'undefined';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -422,7 +424,7 @@ function isDefined(value){return typeof value != 'undefined';}
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is an `Object` but not `null`.
|
||||
*/
|
||||
function isObject(value){return value != null && typeof value == 'object';}
|
||||
function isObject(value){return value != null && typeof value === 'object';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -436,7 +438,7 @@ function isObject(value){return value != null && typeof value == 'object';}
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is a `String`.
|
||||
*/
|
||||
function isString(value){return typeof value == 'string';}
|
||||
function isString(value){return typeof value === 'string';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -450,7 +452,7 @@ function isString(value){return typeof value == 'string';}
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is a `Number`.
|
||||
*/
|
||||
function isNumber(value){return typeof value == 'number';}
|
||||
function isNumber(value){return typeof value === 'number';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -465,7 +467,7 @@ function isNumber(value){return typeof value == 'number';}
|
||||
* @returns {boolean} True if `value` is a `Date`.
|
||||
*/
|
||||
function isDate(value){
|
||||
return toString.apply(value) == '[object Date]';
|
||||
return toString.call(value) === '[object Date]';
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +483,7 @@ function isDate(value){
|
||||
* @returns {boolean} True if `value` is an `Array`.
|
||||
*/
|
||||
function isArray(value) {
|
||||
return toString.apply(value) == '[object Array]';
|
||||
return toString.call(value) === '[object Array]';
|
||||
}
|
||||
|
||||
|
||||
@@ -496,7 +498,7 @@ function isArray(value) {
|
||||
* @param {*} value Reference to check.
|
||||
* @returns {boolean} True if `value` is a `Function`.
|
||||
*/
|
||||
function isFunction(value){return typeof value == 'function';}
|
||||
function isFunction(value){return typeof value === 'function';}
|
||||
|
||||
|
||||
/**
|
||||
@@ -507,7 +509,7 @@ function isFunction(value){return typeof value == 'function';}
|
||||
* @returns {boolean} True if `value` is a `RegExp`.
|
||||
*/
|
||||
function isRegExp(value) {
|
||||
return toString.apply(value) == '[object RegExp]';
|
||||
return toString.call(value) === '[object RegExp]';
|
||||
}
|
||||
|
||||
|
||||
@@ -529,12 +531,12 @@ function isScope(obj) {
|
||||
|
||||
|
||||
function isFile(obj) {
|
||||
return toString.apply(obj) === '[object File]';
|
||||
return toString.call(obj) === '[object File]';
|
||||
}
|
||||
|
||||
|
||||
function isBoolean(value) {
|
||||
return typeof value == 'boolean';
|
||||
return typeof value === 'boolean';
|
||||
}
|
||||
|
||||
|
||||
@@ -544,7 +546,7 @@ var trim = (function() {
|
||||
// TODO: we should move this into IE/ES5 polyfill
|
||||
if (!String.prototype.trim) {
|
||||
return function(value) {
|
||||
return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
|
||||
return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
|
||||
};
|
||||
}
|
||||
return function(value) {
|
||||
@@ -565,9 +567,9 @@ var trim = (function() {
|
||||
* @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
|
||||
*/
|
||||
function isElement(node) {
|
||||
return node &&
|
||||
return !!(node &&
|
||||
(node.nodeName // we are a direct element
|
||||
|| (node.on && node.find)); // we have an on and find method part of jQuery API
|
||||
|| (node.on && node.find))); // we have an on and find method part of jQuery API
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -638,7 +640,7 @@ function includes(array, obj) {
|
||||
function indexOf(array, obj) {
|
||||
if (array.indexOf) return array.indexOf(obj);
|
||||
|
||||
for ( var i = 0; i < array.length; i++) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (obj === array[i]) return i;
|
||||
}
|
||||
return -1;
|
||||
@@ -768,8 +770,8 @@ function shallowCopy(src, dst) {
|
||||
|
||||
for(var key in src) {
|
||||
// shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
|
||||
// so we don't need to worry hasOwnProperty here
|
||||
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
||||
// so we don't need to worry about using our custom hasOwnProperty here
|
||||
if (src.hasOwnProperty(key) && key.charAt(0) !== '$' && key.charAt(1) !== '$') {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
@@ -957,7 +959,9 @@ function fromJson(json) {
|
||||
|
||||
|
||||
function toBoolean(value) {
|
||||
if (value && value.length !== 0) {
|
||||
if (typeof value === 'function') {
|
||||
value = true;
|
||||
} else if (value && value.length !== 0) {
|
||||
var v = lowercase("" + value);
|
||||
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
|
||||
} else {
|
||||
@@ -974,7 +978,7 @@ function startingTag(element) {
|
||||
try {
|
||||
// turns out IE does not let you set .html() on elements which
|
||||
// are not allowed to have children. So we just ignore it.
|
||||
element.html('');
|
||||
element.empty();
|
||||
} catch(e) {}
|
||||
// As Per DOM Standards
|
||||
var TEXT_NODE = 3;
|
||||
@@ -1102,26 +1106,38 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* Use this directive to auto-bootstrap an application. Only
|
||||
* one ngApp directive can be used per HTML document. The directive
|
||||
* designates the root of the application and is typically placed
|
||||
* at the root of the page.
|
||||
* Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
|
||||
* designates the **root element** of the application and is typically placed near the root element
|
||||
* of the page - e.g. on the `<body>` or `<html>` tags.
|
||||
*
|
||||
* The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in
|
||||
* an HTML document you must manually bootstrap them using {@link angular.bootstrap}.
|
||||
* Applications cannot be nested.
|
||||
* Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
|
||||
* found in the document will be used to define the root element to auto-bootstrap as an
|
||||
* application. To run multiple applications in an HTML document you must manually bootstrap them using
|
||||
* {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
|
||||
*
|
||||
* In the example below if the `ngApp` directive were not placed
|
||||
* on the `html` element then the document would not be compiled
|
||||
* and the `{{ 1+2 }}` would not be resolved to `3`.
|
||||
* You can specify an **AngularJS module** to be used as the root module for the application. This
|
||||
* module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
|
||||
* should contain the application code needed or have dependencies on other modules that will
|
||||
* contain the code. See {@link angular.module} for more information.
|
||||
*
|
||||
* `ngApp` is the easiest way to bootstrap an application.
|
||||
* In the example below if the `ngApp` directive were not placed on the `html` element then the
|
||||
* document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
|
||||
* would not be resolved to `3`.
|
||||
*
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
I can add: 1 + 2 = {{ 1+2 }}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
* `ngApp` is the easiest, and most common, way to bootstrap an application.
|
||||
*
|
||||
<example module="ngAppDemo">
|
||||
<file name="index.html">
|
||||
<div ng-controller="ngAppDemoController">
|
||||
I can add: {{a}} + {{b}} = {{ a+b }}
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
|
||||
$scope.a = 1;
|
||||
$scope.b = 2;
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
*
|
||||
*/
|
||||
function angularInit(element, bootstrap) {
|
||||
@@ -1318,23 +1334,25 @@ function getter(obj, path, bindFnToScope) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the siblings between `startNode` and `endNode`, inclusive
|
||||
* @param {Object} object with `startNode` and `endNode` properties
|
||||
* Return the DOM siblings between the first and last node in the given array.
|
||||
* @param {Array} array like object
|
||||
* @returns jQlite object containing the elements
|
||||
*/
|
||||
function getBlockElements(block) {
|
||||
if (block.startNode === block.endNode) {
|
||||
return jqLite(block.startNode);
|
||||
function getBlockElements(nodes) {
|
||||
var startNode = nodes[0],
|
||||
endNode = nodes[nodes.length - 1];
|
||||
if (startNode === endNode) {
|
||||
return jqLite(startNode);
|
||||
}
|
||||
|
||||
var element = block.startNode;
|
||||
var element = startNode;
|
||||
var elements = [element];
|
||||
|
||||
do {
|
||||
element = element.nextSibling;
|
||||
if (!element) break;
|
||||
elements.push(element);
|
||||
} while (element !== block.endNode);
|
||||
} while (element !== endNode);
|
||||
|
||||
return jqLite(elements);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
ngHideDirective,
|
||||
ngIfDirective,
|
||||
ngIncludeDirective,
|
||||
ngIncludeFillContentDirective,
|
||||
ngInitDirective,
|
||||
ngNonBindableDirective,
|
||||
ngPluralizeDirective,
|
||||
@@ -65,6 +66,7 @@
|
||||
$ParseProvider,
|
||||
$RootScopeProvider,
|
||||
$QProvider,
|
||||
$$SanitizeUriProvider,
|
||||
$SceProvider,
|
||||
$SceDelegateProvider,
|
||||
$SnifferProvider,
|
||||
@@ -136,6 +138,10 @@ function publishExternalAPI(angular){
|
||||
|
||||
angularModule('ng', ['ngLocale'], ['$provide',
|
||||
function ngModule($provide) {
|
||||
// $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
|
||||
$provide.provider({
|
||||
$$sanitizeUri: $$SanitizeUriProvider
|
||||
});
|
||||
$provide.provider('$compile', $CompileProvider).
|
||||
directive({
|
||||
a: htmlAnchorDirective,
|
||||
@@ -176,6 +182,9 @@ function publishExternalAPI(angular){
|
||||
ngRequired: requiredDirective,
|
||||
ngValue: ngValueDirective
|
||||
}).
|
||||
directive({
|
||||
ngInclude: ngIncludeFillContentDirective
|
||||
}).
|
||||
directive(ngAttributeAliasDirectives).
|
||||
directive(ngEventDirectives);
|
||||
$provide.provider({
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, document, undefined) {
|
||||
|
||||
+37
-25
@@ -27,6 +27,28 @@
|
||||
* $rootScope.$digest();
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* Sometimes you want to get access to the injector of a currently running Angular app
|
||||
* from outside Angular. Perhaps, you want to inject and compile some markup after the
|
||||
* application has been bootstrapped. You can do this using extra `injector()` added
|
||||
* to JQuery/jqLite elements. See {@link angular.element}.
|
||||
*
|
||||
* *This is fairly rare but could be the case if a third party library is injecting the
|
||||
* markup.*
|
||||
*
|
||||
* In the following example a new block of HTML containing a `ng-controller`
|
||||
* directive is added to the end of the document body by JQuery. We then compile and link
|
||||
* it into the current AngularJS scope.
|
||||
*
|
||||
* <pre>
|
||||
* var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
|
||||
* $(document.body).append($div);
|
||||
*
|
||||
* angular.element(document).injector().invoke(function($compile) {
|
||||
* var scope = angular.element($div).scope();
|
||||
* $compile($div)(scope);
|
||||
* });
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
|
||||
@@ -221,7 +243,7 @@ function annotate(fn) {
|
||||
* // ...
|
||||
* }
|
||||
* // Define function dependencies
|
||||
* MyController.$inject = ['$scope', '$route'];
|
||||
* MyController['$inject'] = ['$scope', '$route'];
|
||||
*
|
||||
* // Then
|
||||
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
|
||||
@@ -463,15 +485,15 @@ function annotate(fn) {
|
||||
* {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
|
||||
* <pre>
|
||||
* class Ping
|
||||
* constructor: (@$http)->
|
||||
* send: ()=>
|
||||
* constructor: (@$http) ->
|
||||
* send: () =>
|
||||
* @$http.get('/ping')
|
||||
*
|
||||
* $provide.service('ping', ['$http', Ping])
|
||||
* </pre>
|
||||
* You would then inject and use this service like this:
|
||||
* <pre>
|
||||
* someModule.controller 'Ctrl', ['ping', (ping)->
|
||||
* someModule.controller 'Ctrl', ['ping', (ping) ->
|
||||
* ping.send()
|
||||
* ]
|
||||
* </pre>
|
||||
@@ -501,11 +523,11 @@ function annotate(fn) {
|
||||
* @example
|
||||
* Here are some examples of creating value services.
|
||||
* <pre>
|
||||
* $provide.constant('ADMIN_USER', 'admin');
|
||||
* $provide.value('ADMIN_USER', 'admin');
|
||||
*
|
||||
* $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
|
||||
* $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
|
||||
*
|
||||
* $provide.constant('halfOf', function(value) {
|
||||
* $provide.value('halfOf', function(value) {
|
||||
* return value / 2;
|
||||
* });
|
||||
* </pre>
|
||||
@@ -718,6 +740,11 @@ function createInjector(modulesToLoad) {
|
||||
path.unshift(serviceName);
|
||||
cache[serviceName] = INSTANTIATING;
|
||||
return cache[serviceName] = factory(serviceName);
|
||||
} catch (err) {
|
||||
if (cache[serviceName] === INSTANTIATING) {
|
||||
delete cache[serviceName];
|
||||
}
|
||||
throw err;
|
||||
} finally {
|
||||
path.shift();
|
||||
}
|
||||
@@ -747,24 +774,9 @@ function createInjector(modulesToLoad) {
|
||||
fn = fn[length];
|
||||
}
|
||||
|
||||
|
||||
// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
|
||||
switch (self ? -1 : args.length) {
|
||||
case 0: return fn();
|
||||
case 1: return fn(args[0]);
|
||||
case 2: return fn(args[0], args[1]);
|
||||
case 3: return fn(args[0], args[1], args[2]);
|
||||
case 4: return fn(args[0], args[1], args[2], args[3]);
|
||||
case 5: return fn(args[0], args[1], args[2], args[3], args[4]);
|
||||
case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||
case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
||||
case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
|
||||
case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
|
||||
args[8]);
|
||||
case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
|
||||
args[8], args[9]);
|
||||
default: return fn.apply(self, args);
|
||||
}
|
||||
// http://jsperf.com/angularjs-invoke-apply-vs-switch
|
||||
// #5388
|
||||
return fn.apply(self, args);
|
||||
}
|
||||
|
||||
function instantiate(Type, locals) {
|
||||
|
||||
+41
-6
@@ -46,6 +46,7 @@
|
||||
* - [`contents()`](http://api.jquery.com/contents/)
|
||||
* - [`css()`](http://api.jquery.com/css/)
|
||||
* - [`data()`](http://api.jquery.com/data/)
|
||||
* - [`empty()`](http://api.jquery.com/empty/)
|
||||
* - [`eq()`](http://api.jquery.com/eq/)
|
||||
* - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
|
||||
* - [`hasClass()`](http://api.jquery.com/hasClass/)
|
||||
@@ -53,6 +54,7 @@
|
||||
* - [`next()`](http://api.jquery.com/next/) - Does not support selectors
|
||||
* - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
|
||||
* - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
|
||||
* - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
|
||||
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
|
||||
* - [`prepend()`](http://api.jquery.com/prepend/)
|
||||
* - [`prop()`](http://api.jquery.com/prop/)
|
||||
@@ -358,6 +360,15 @@ function jqLiteInheritedData(element, name, value) {
|
||||
}
|
||||
}
|
||||
|
||||
function jqLiteEmpty(element) {
|
||||
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
|
||||
jqLiteDealoc(childNodes[i]);
|
||||
}
|
||||
while (element.firstChild) {
|
||||
element.removeChild(element.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Functions which are declared directly.
|
||||
//////////////////////////////////////////
|
||||
@@ -552,7 +563,9 @@ forEach({
|
||||
jqLiteDealoc(childNodes[i]);
|
||||
}
|
||||
element.innerHTML = value;
|
||||
}
|
||||
},
|
||||
|
||||
empty: jqLiteEmpty
|
||||
}, function(fn, name){
|
||||
/**
|
||||
* Properties: writes return selection, reads return first value
|
||||
@@ -562,11 +575,13 @@ forEach({
|
||||
|
||||
// jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
|
||||
// in a way that survives minification.
|
||||
if (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined) {
|
||||
// jqLiteEmpty takes no arguments but is a setter.
|
||||
if (fn !== jqLiteEmpty &&
|
||||
(((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
|
||||
if (isObject(arg1)) {
|
||||
|
||||
// we are a write, but the object properties are the key/values
|
||||
for(i=0; i < this.length; i++) {
|
||||
for (i = 0; i < this.length; i++) {
|
||||
if (fn === jqLiteData) {
|
||||
// data() takes the whole object in jQuery
|
||||
fn(this[i], arg1);
|
||||
@@ -591,7 +606,7 @@ forEach({
|
||||
}
|
||||
} else {
|
||||
// we are a write, so apply to all children
|
||||
for(i=0; i < this.length; i++) {
|
||||
for (i = 0; i < this.length; i++) {
|
||||
fn(this[i], arg1, arg2);
|
||||
}
|
||||
// return self for chaining
|
||||
@@ -631,7 +646,10 @@ function createEventHandler(element, events) {
|
||||
return event.defaultPrevented || event.returnValue === false;
|
||||
};
|
||||
|
||||
forEach(events[type || event.type], function(fn) {
|
||||
// Copy event handlers in case event handlers array is modified during execution.
|
||||
var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
|
||||
|
||||
forEach(eventHandlersCopy, function(fn) {
|
||||
fn.call(element, event);
|
||||
});
|
||||
|
||||
@@ -727,6 +745,19 @@ forEach({
|
||||
|
||||
off: jqLiteOff,
|
||||
|
||||
one: function(element, type, fn) {
|
||||
element = jqLite(element);
|
||||
|
||||
//add the listener twice so that when it is called
|
||||
//you can remove the original function and still be
|
||||
//able to call element.off(ev, fn) normally
|
||||
element.on(type, function onFn() {
|
||||
element.off(type, fn);
|
||||
element.off(type, onFn);
|
||||
});
|
||||
element.on(type, fn);
|
||||
},
|
||||
|
||||
replaceWith: function(element, replaceNode) {
|
||||
var index, parent = element.parentNode;
|
||||
jqLiteDealoc(element);
|
||||
@@ -822,7 +853,11 @@ forEach({
|
||||
},
|
||||
|
||||
find: function(element, selector) {
|
||||
return element.getElementsByTagName(selector);
|
||||
if (element.getElementsByTagName) {
|
||||
return element.getElementsByTagName(selector);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
clone: jqLiteClone,
|
||||
|
||||
+6
-1
@@ -17,7 +17,12 @@ function setupModuleLoader(window) {
|
||||
return obj[name] || (obj[name] = factory());
|
||||
}
|
||||
|
||||
return ensure(ensure(window, 'angular', Object), 'module', function() {
|
||||
var angular = ensure(window, 'angular', Object);
|
||||
|
||||
// We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
|
||||
angular.$$minErr = angular.$$minErr || minErr;
|
||||
|
||||
return ensure(angular, 'module', function() {
|
||||
/** @type {Object.<string, angular.Module>} */
|
||||
var modules = {};
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @license AngularJS v"NG_VERSION_FULL"
|
||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
||||
* (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
* License: MIT
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
|
||||
+30
-7
@@ -61,6 +61,28 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
$provide.factory(key, factory);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$animateProvider#classNameFilter
|
||||
* @methodOf ng.$animateProvider
|
||||
*
|
||||
* @description
|
||||
* Sets and/or returns the CSS class regular expression that is checked when performing
|
||||
* an animation. Upon bootstrap the classNameFilter value is not set at all and will
|
||||
* therefore enable $animate to attempt to perform an animation on any element.
|
||||
* When setting the classNameFilter value, animations will only be performed on elements
|
||||
* that successfully match the filter expression. This in turn can boost performance
|
||||
* for low-powered devices as well as applications containing a lot of structural operations.
|
||||
* @param {RegExp=} expression The className expression which will be checked against all animations
|
||||
* @return {RegExp} The current CSS className expression value. If null then there is no expression value
|
||||
*/
|
||||
this.classNameFilter = function(expression) {
|
||||
if(arguments.length === 1) {
|
||||
this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
|
||||
}
|
||||
return this.$$classNameFilter;
|
||||
};
|
||||
|
||||
this.$get = ['$timeout', function($timeout) {
|
||||
|
||||
/**
|
||||
@@ -99,13 +121,14 @@ var $AnimateProvider = ['$provide', function($provide) {
|
||||
* inserted into the DOM
|
||||
*/
|
||||
enter : function(element, parent, after, done) {
|
||||
var afterNode = after && after[after.length - 1];
|
||||
var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
|
||||
// IE does not like undefined so we have to pass null.
|
||||
var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
|
||||
forEach(element, function(node) {
|
||||
parentNode.insertBefore(node, afterNextSibling);
|
||||
});
|
||||
if (after) {
|
||||
after.after(element);
|
||||
} else {
|
||||
if (!parent || !parent[0]) {
|
||||
parent = after.parent();
|
||||
}
|
||||
parent.append(element);
|
||||
}
|
||||
done && $timeout(done, 0, false);
|
||||
},
|
||||
|
||||
|
||||
+7
-6
@@ -148,8 +148,9 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @param {boolean=} replace Should new url replace current history record ?
|
||||
*/
|
||||
self.url = function(url, replace) {
|
||||
// Android Browser BFCache causes location reference to become stale.
|
||||
// Android Browser BFCache causes location, history reference to become stale.
|
||||
if (location !== window.location) location = window.location;
|
||||
if (history !== window.history) history = window.history;
|
||||
|
||||
// setter
|
||||
if (url) {
|
||||
@@ -201,7 +202,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* @description
|
||||
* Register callback function that will be called, when url changes.
|
||||
*
|
||||
* It's only called when the url is changed by outside of angular:
|
||||
* It's only called when the url is changed from outside of angular:
|
||||
* - user types different url into address bar
|
||||
* - user clicks on history (forward/back) button
|
||||
* - user clicks on a link
|
||||
@@ -243,7 +244,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
/**
|
||||
* @name ng.$browser#baseHref
|
||||
* @methodOf ng.$browser
|
||||
*
|
||||
*
|
||||
* @description
|
||||
* Returns current <base href>
|
||||
* (always relative - without domain)
|
||||
@@ -252,7 +253,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
*/
|
||||
self.baseHref = function() {
|
||||
var href = baseElement.attr('href');
|
||||
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
|
||||
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@@ -274,13 +275,13 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* It is not meant to be used directly, use the $cookie service instead.
|
||||
*
|
||||
* The return values vary depending on the arguments that the method was called with as follows:
|
||||
*
|
||||
*
|
||||
* - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
|
||||
* it
|
||||
* - cookies(name, value) -> set name to value, if value is undefined delete the cookie
|
||||
* - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
|
||||
* way)
|
||||
*
|
||||
*
|
||||
* @returns {Object} Hash of all cookies (if called without any parameter)
|
||||
*/
|
||||
self.cookies = function(name, value) {
|
||||
|
||||
+141
-117
@@ -24,7 +24,7 @@
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Compiles a piece of HTML string or DOM into a template and produces a template function, which
|
||||
* Compiles an HTML string or DOM into a template and produces a template function, which
|
||||
* can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
|
||||
*
|
||||
* The compilation is a process of walking the DOM tree and matching DOM elements to
|
||||
@@ -192,7 +192,7 @@
|
||||
* * (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.
|
||||
* * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
|
||||
* * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the
|
||||
* * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
|
||||
* `link` fn if not found.
|
||||
*
|
||||
*
|
||||
@@ -283,7 +283,7 @@
|
||||
* </div>
|
||||
*
|
||||
* <div class="alert alert-error">
|
||||
* **Note:** The `transclude` function that is passed to the compile function is deperecated, as it
|
||||
* **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
|
||||
* e.g. does not know about the right outer scope. Please use the transclude function that is passed
|
||||
* to the link function instead.
|
||||
* </div>
|
||||
@@ -469,14 +469,14 @@
|
||||
* example would not point to the clone, but rather to the original template that was cloned. In
|
||||
* this case, you can access the clone via the cloneAttachFn:
|
||||
* <pre>
|
||||
* var templateHTML = angular.element('<p>{{total}}</p>'),
|
||||
* var templateElement = angular.element('<p>{{total}}</p>'),
|
||||
* scope = ....;
|
||||
*
|
||||
* var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
|
||||
* var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
|
||||
* //attach the clone to DOM document at the right place
|
||||
* });
|
||||
*
|
||||
* //now we have reference to the cloned DOM via `clone`
|
||||
* //now we have reference to the cloned DOM via `clonedElement`
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
@@ -493,14 +493,12 @@ var $compileMinErr = minErr('$compile');
|
||||
*
|
||||
* @description
|
||||
*/
|
||||
$CompileProvider.$inject = ['$provide'];
|
||||
function $CompileProvider($provide) {
|
||||
$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
|
||||
function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
var hasDirectives = {},
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
||||
aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
|
||||
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
|
||||
|
||||
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
|
||||
// The assumption is that future DOM event attribute names will begin with
|
||||
@@ -584,10 +582,11 @@ function $CompileProvider($provide) {
|
||||
*/
|
||||
this.aHrefSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
aHrefSanitizationWhitelist = regexp;
|
||||
$$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
|
||||
return this;
|
||||
} else {
|
||||
return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
|
||||
}
|
||||
return aHrefSanitizationWhitelist;
|
||||
};
|
||||
|
||||
|
||||
@@ -614,18 +613,18 @@ function $CompileProvider($provide) {
|
||||
*/
|
||||
this.imgSrcSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
imgSrcSanitizationWhitelist = regexp;
|
||||
$$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
|
||||
return this;
|
||||
} else {
|
||||
return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
|
||||
}
|
||||
return imgSrcSanitizationWhitelist;
|
||||
};
|
||||
|
||||
|
||||
this.$get = [
|
||||
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
|
||||
'$controller', '$rootScope', '$document', '$sce', '$animate',
|
||||
'$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
|
||||
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
|
||||
$controller, $rootScope, $document, $sce, $animate) {
|
||||
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
|
||||
|
||||
var Attributes = function(element, attr) {
|
||||
this.$$element = element;
|
||||
@@ -672,6 +671,24 @@ function $CompileProvider($provide) {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$compile.directive.Attributes#$updateClass
|
||||
* @methodOf ng.$compile.directive.Attributes
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Adds and removes the appropriate CSS class values to the element based on the difference
|
||||
* between the new and old CSS class values (specified as newClasses and oldClasses).
|
||||
*
|
||||
* @param {string} newClasses The current CSS className value
|
||||
* @param {string} oldClasses The former CSS className value
|
||||
*/
|
||||
$updateClass : function(newClasses, oldClasses) {
|
||||
this.$removeClass(tokenDifference(oldClasses, newClasses));
|
||||
this.$addClass(tokenDifference(newClasses, oldClasses));
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a normalized attribute on the element in a way such that all directives
|
||||
* can share the attribute. This function properly handles boolean attributes.
|
||||
@@ -682,59 +699,44 @@ function $CompileProvider($provide) {
|
||||
* @param {string=} attrName Optional none normalized name. Defaults to key.
|
||||
*/
|
||||
$set: function(key, value, writeAttr, attrName) {
|
||||
//special case for class attribute addition + removal
|
||||
//so that class changes can tap into the animation
|
||||
//hooks provided by the $animate service
|
||||
if(key == 'class') {
|
||||
value = value || '';
|
||||
var current = this.$$element.attr('class') || '';
|
||||
this.$removeClass(tokenDifference(current, value).join(' '));
|
||||
this.$addClass(tokenDifference(value, current).join(' '));
|
||||
// TODO: decide whether or not to throw an error if "class"
|
||||
//is set through this function since it may cause $updateClass to
|
||||
//become unstable.
|
||||
|
||||
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
||||
normalizedVal,
|
||||
nodeName;
|
||||
|
||||
if (booleanKey) {
|
||||
this.$$element.prop(key, value);
|
||||
attrName = booleanKey;
|
||||
}
|
||||
|
||||
this[key] = value;
|
||||
|
||||
// translate normalized key to actual key
|
||||
if (attrName) {
|
||||
this.$attr[key] = attrName;
|
||||
} else {
|
||||
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
||||
normalizedVal,
|
||||
nodeName;
|
||||
|
||||
if (booleanKey) {
|
||||
this.$$element.prop(key, value);
|
||||
attrName = booleanKey;
|
||||
attrName = this.$attr[key];
|
||||
if (!attrName) {
|
||||
this.$attr[key] = attrName = snake_case(key, '-');
|
||||
}
|
||||
}
|
||||
|
||||
this[key] = value;
|
||||
nodeName = nodeName_(this.$$element);
|
||||
|
||||
// translate normalized key to actual key
|
||||
if (attrName) {
|
||||
this.$attr[key] = attrName;
|
||||
// sanitize a[href] and img[src] values
|
||||
if ((nodeName === 'A' && key === 'href') ||
|
||||
(nodeName === 'IMG' && key === 'src')) {
|
||||
this[key] = value = $$sanitizeUri(value, key === 'src');
|
||||
}
|
||||
|
||||
if (writeAttr !== false) {
|
||||
if (value === null || value === undefined) {
|
||||
this.$$element.removeAttr(attrName);
|
||||
} else {
|
||||
attrName = this.$attr[key];
|
||||
if (!attrName) {
|
||||
this.$attr[key] = attrName = snake_case(key, '-');
|
||||
}
|
||||
}
|
||||
|
||||
nodeName = nodeName_(this.$$element);
|
||||
|
||||
// sanitize a[href] and img[src] values
|
||||
if ((nodeName === 'A' && key === 'href') ||
|
||||
(nodeName === 'IMG' && key === 'src')) {
|
||||
// NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
|
||||
if (!msie || msie >= 8 ) {
|
||||
normalizedVal = urlResolve(value).href;
|
||||
if (normalizedVal !== '') {
|
||||
if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
|
||||
(key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
|
||||
this[key] = value = 'unsafe:' + normalizedVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeAttr !== false) {
|
||||
if (value === null || value === undefined) {
|
||||
this.$$element.removeAttr(attrName);
|
||||
} else {
|
||||
this.$$element.attr(attrName, value);
|
||||
}
|
||||
this.$$element.attr(attrName, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,22 +749,6 @@ function $CompileProvider($provide) {
|
||||
$exceptionHandler(e);
|
||||
}
|
||||
});
|
||||
|
||||
function tokenDifference(str1, str2) {
|
||||
var values = [],
|
||||
tokens1 = str1.split(/\s+/),
|
||||
tokens2 = str2.split(/\s+/);
|
||||
|
||||
outer:
|
||||
for(var i=0;i<tokens1.length;i++) {
|
||||
var token = tokens1[i];
|
||||
for(var j=0;j<tokens2.length;j++) {
|
||||
if(token == tokens2[j]) continue outer;
|
||||
}
|
||||
values.push(token);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -832,6 +818,7 @@ function $CompileProvider($provide) {
|
||||
var compositeLinkFn =
|
||||
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
safeAddClass($compileNodes, 'ng-scope');
|
||||
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
|
||||
assertArg(scope, 'scope');
|
||||
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
|
||||
@@ -846,12 +833,13 @@ function $CompileProvider($provide) {
|
||||
|
||||
// Attach scope only to non-text nodes.
|
||||
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
||||
var node = $linkNode[i];
|
||||
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
||||
var node = $linkNode[i],
|
||||
nodeType = node.nodeType;
|
||||
if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
|
||||
$linkNode.eq(i).data('$scope', scope);
|
||||
}
|
||||
}
|
||||
safeAddClass($linkNode, 'ng-scope');
|
||||
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
||||
return $linkNode;
|
||||
@@ -879,15 +867,15 @@ function $CompileProvider($provide) {
|
||||
* @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
|
||||
* the rootElement must be set the jqLite collection of the compile root. This is
|
||||
* needed so that the jqLite collection items can be replaced with widgets.
|
||||
* @param {number=} max directive priority
|
||||
* @param {number=} maxPriority Max directive priority.
|
||||
* @returns {?function} A composite linking function of all of the matched directives or null.
|
||||
*/
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
|
||||
previousCompileContext) {
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
|
||||
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
@@ -899,16 +887,19 @@ function $CompileProvider($provide) {
|
||||
null, [], [], previousCompileContext)
|
||||
: null;
|
||||
|
||||
if (nodeLinkFn && nodeLinkFn.scope) {
|
||||
safeAddClass(jqLite(nodeList[i]), 'ng-scope');
|
||||
}
|
||||
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
|
||||
!nodeList[i].childNodes ||
|
||||
!nodeList[i].childNodes.length)
|
||||
!(childNodes = nodeList[i].childNodes) ||
|
||||
!childNodes.length)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
: compileNodes(childNodes,
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
linkFns.push(nodeLinkFn, childLinkFn);
|
||||
linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
|
||||
//use the previous context only for the first element in the virtual group
|
||||
previousCompileContext = null;
|
||||
}
|
||||
@@ -920,9 +911,10 @@ function $CompileProvider($provide) {
|
||||
var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
|
||||
|
||||
// copy nodeList so that linking doesn't break due to live list updates.
|
||||
var stableNodeList = [];
|
||||
for (i = 0, ii = nodeList.length; i < ii; i++) {
|
||||
stableNodeList.push(nodeList[i]);
|
||||
var nodeListLength = nodeList.length,
|
||||
stableNodeList = new Array(nodeListLength);
|
||||
for (i = 0; i < nodeListLength; i++) {
|
||||
stableNodeList[i] = nodeList[i];
|
||||
}
|
||||
|
||||
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
@@ -935,7 +927,6 @@ function $CompileProvider($provide) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new();
|
||||
$node.data('$scope', childScope);
|
||||
safeAddClass($node, 'ng-scope');
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
@@ -945,7 +936,7 @@ function $CompileProvider($provide) {
|
||||
createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
|
||||
);
|
||||
} else {
|
||||
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
|
||||
}
|
||||
} else if (childLinkFn) {
|
||||
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
||||
@@ -1018,9 +1009,7 @@ function $CompileProvider($provide) {
|
||||
|
||||
nName = directiveNormalize(name.toLowerCase());
|
||||
attrsMap[nName] = name;
|
||||
attrs[nName] = value = trim((msie && name == 'href')
|
||||
? decodeURIComponent(node.getAttribute(name, 2))
|
||||
: attr.value);
|
||||
attrs[nName] = value = trim(attr.value);
|
||||
if (getBooleanAttrName(node, nName)) {
|
||||
attrs[nName] = true; // presence means true
|
||||
}
|
||||
@@ -1233,7 +1222,7 @@ function $CompileProvider($provide) {
|
||||
});
|
||||
} else {
|
||||
$template = jqLite(jqLiteClone(compileNode)).contents();
|
||||
$compileNode.html(''); // clear contents
|
||||
$compileNode.empty(); // clear contents
|
||||
childTranscludeFn = compile($template, transcludeFn);
|
||||
}
|
||||
}
|
||||
@@ -1414,7 +1403,7 @@ function $CompileProvider($provide) {
|
||||
optional = (match[2] == '?'),
|
||||
mode = match[1], // @, =, or &
|
||||
lastValue,
|
||||
parentGet, parentSet;
|
||||
parentGet, parentSet, compare;
|
||||
|
||||
isolateScope.$$isolateBindings[scopeName] = mode + attrName;
|
||||
|
||||
@@ -1437,6 +1426,11 @@ function $CompileProvider($provide) {
|
||||
return;
|
||||
}
|
||||
parentGet = $parse(attrs[attrName]);
|
||||
if (parentGet.literal) {
|
||||
compare = equals;
|
||||
} else {
|
||||
compare = function(a,b) { return a === b; };
|
||||
}
|
||||
parentSet = parentGet.assign || function() {
|
||||
// reset the change, or we will throw this exception on every $digest
|
||||
lastValue = isolateScope[scopeName] = parentGet(scope);
|
||||
@@ -1447,19 +1441,18 @@ function $CompileProvider($provide) {
|
||||
lastValue = isolateScope[scopeName] = parentGet(scope);
|
||||
isolateScope.$watch(function parentValueWatch() {
|
||||
var parentValue = parentGet(scope);
|
||||
|
||||
if (parentValue !== isolateScope[scopeName]) {
|
||||
if (!compare(parentValue, isolateScope[scopeName])) {
|
||||
// we are out of sync and need to copy
|
||||
if (parentValue !== lastValue) {
|
||||
if (!compare(parentValue, lastValue)) {
|
||||
// parent changed and it has precedence
|
||||
lastValue = isolateScope[scopeName] = parentValue;
|
||||
isolateScope[scopeName] = parentValue;
|
||||
} else {
|
||||
// if the parent can be assigned then do so
|
||||
parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
|
||||
parentSet(scope, parentValue = isolateScope[scopeName]);
|
||||
}
|
||||
}
|
||||
return parentValue;
|
||||
});
|
||||
return lastValue = parentValue;
|
||||
}, null, parentGet.literal);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
@@ -1661,7 +1654,7 @@ function $CompileProvider($provide) {
|
||||
? origAsyncDirective.templateUrl($compileNode, tAttrs)
|
||||
: origAsyncDirective.templateUrl;
|
||||
|
||||
$compileNode.html('');
|
||||
$compileNode.empty();
|
||||
|
||||
$http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
|
||||
success(function(content) {
|
||||
@@ -1784,10 +1777,15 @@ function $CompileProvider($provide) {
|
||||
|
||||
|
||||
function getTrustedContext(node, attrNormalizedName) {
|
||||
if (attrNormalizedName == "srcdoc") {
|
||||
return $sce.HTML;
|
||||
}
|
||||
var tag = nodeName_(node);
|
||||
// maction[xlink:href] can source SVG. It's not limited to <maction>.
|
||||
if (attrNormalizedName == "xlinkHref" ||
|
||||
(nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
|
||||
attrNormalizedName == "ngSrc"))) {
|
||||
(tag == "FORM" && attrNormalizedName == "action") ||
|
||||
(tag != "IMG" && (attrNormalizedName == "src" ||
|
||||
attrNormalizedName == "ngSrc"))) {
|
||||
return $sce.RESOURCE_URL;
|
||||
}
|
||||
}
|
||||
@@ -1832,9 +1830,19 @@ function $CompileProvider($provide) {
|
||||
attr[name] = interpolateFn(scope);
|
||||
($$observers[name] || ($$observers[name] = [])).$$inter = true;
|
||||
(attr.$$observers && attr.$$observers[name].$$scope || scope).
|
||||
$watch(interpolateFn, function interpolateFnWatchAction(value) {
|
||||
attr.$set(name, value);
|
||||
});
|
||||
$watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
|
||||
//special case for class attribute addition + removal
|
||||
//so that class changes can tap into the animation
|
||||
//hooks provided by the $animate service. Be sure to
|
||||
//skip animations when the first digest occurs (when
|
||||
//both the new and the old values are the same) since
|
||||
//the CSS classes are the non-interpolated values
|
||||
if(name === 'class' && newValue != oldValue) {
|
||||
attr.$updateClass(newValue, oldValue);
|
||||
} else {
|
||||
attr.$set(name, newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1974,3 +1982,19 @@ function directiveLinkingFn(
|
||||
/* Element */ rootElement,
|
||||
/* function(Function) */ boundTranscludeFn
|
||||
){}
|
||||
|
||||
function tokenDifference(str1, str2) {
|
||||
var values = '',
|
||||
tokens1 = str1.split(/\s+/),
|
||||
tokens2 = str2.split(/\s+/);
|
||||
|
||||
outer:
|
||||
for(var i = 0; i < tokens1.length; i++) {
|
||||
var token = tokens1[i];
|
||||
for(var j = 0; j < tokens2.length; j++) {
|
||||
if(token == tokens2[j]) continue outer;
|
||||
}
|
||||
values += (values.length > 0 ? ' ' : '') + token;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
+10
-8
@@ -32,13 +32,15 @@ var htmlAnchorDirective = valueFn({
|
||||
element.append(document.createComment('IE fix'));
|
||||
}
|
||||
|
||||
return function(scope, element) {
|
||||
element.on('click', function(event){
|
||||
// if we have no href url, then don't navigate anywhere.
|
||||
if (!element.attr('href')) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
if (!attr.href && !attr.name) {
|
||||
return function(scope, element) {
|
||||
element.on('click', function(event){
|
||||
// if we have no href url, then don't navigate anywhere.
|
||||
if (!element.attr('href')) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngHref
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in an href attribute will
|
||||
@@ -87,6 +88,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrc
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `src` attribute doesn't
|
||||
@@ -112,6 +114,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSrcset
|
||||
* @restrict A
|
||||
* @priority 99
|
||||
*
|
||||
* @description
|
||||
* Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
|
||||
@@ -137,6 +140,7 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngDisabled
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
*
|
||||
@@ -149,8 +153,11 @@
|
||||
*
|
||||
* 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.)
|
||||
* This prevents the Angular compiler from retrieving the binding expression.
|
||||
* 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 `ngDisabled` directive solves this problem for the `disabled` attribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
@@ -177,12 +184,16 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngChecked
|
||||
* @restrict A
|
||||
* @priority 100
|
||||
*
|
||||
* @description
|
||||
* 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.)
|
||||
* This prevents the Angular compiler from retrieving the binding expression.
|
||||
* 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
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -208,12 +219,16 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngReadonly
|
||||
* @restrict A
|
||||
* @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.)
|
||||
* This prevents the Angular compiler from retrieving the binding expression.
|
||||
* 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.
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -239,12 +254,17 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngSelected
|
||||
* @restrict A
|
||||
* @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.)
|
||||
* This prevents the Angular compiler from retrieving the binding expression.
|
||||
* 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` atttribute.
|
||||
* This complementary directive is not removed by the browser and so provides
|
||||
* a permanent reliable place to store the binding information.
|
||||
*
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -272,13 +292,16 @@
|
||||
* @ngdoc directive
|
||||
* @name ng.directive:ngOpen
|
||||
* @restrict A
|
||||
* @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.)
|
||||
* This prevents the Angular compiler from retrieving the binding expression.
|
||||
* 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.
|
||||
* @example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
|
||||
@@ -21,9 +21,22 @@ var nullFormCtrl = {
|
||||
* @property {Object} $error Is an object hash, containing references to all invalid controls or
|
||||
* forms, where:
|
||||
*
|
||||
* - keys are validation tokens (error names) — such as `required`, `url` or `email`,
|
||||
* - values are arrays of controls or forms that are invalid with given error.
|
||||
* - keys are validation tokens (error names),
|
||||
* - values are arrays of controls or forms that are invalid for given error name.
|
||||
*
|
||||
*
|
||||
* Built-in validation tokens:
|
||||
*
|
||||
* - `email`
|
||||
* - `max`
|
||||
* - `maxlength`
|
||||
* - `min`
|
||||
* - `minlength`
|
||||
* - `number`
|
||||
* - `pattern`
|
||||
* - `required`
|
||||
* - `url`
|
||||
*
|
||||
* @description
|
||||
* `FormController` keeps track of all its controls and nested forms as well as state of them,
|
||||
* such as being valid/invalid or dirty/pristine.
|
||||
|
||||
+27
-40
@@ -392,8 +392,23 @@ var inputType = {
|
||||
|
||||
|
||||
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
// In composition mode, users are still inputing intermediate text buffer,
|
||||
// hold the listener until composition is done.
|
||||
// More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
|
||||
if (!$sniffer.android) {
|
||||
var composing = false;
|
||||
|
||||
element.on('compositionstart', function(data) {
|
||||
composing = true;
|
||||
});
|
||||
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
}
|
||||
|
||||
var listener = function() {
|
||||
if (composing) return;
|
||||
var value = element.val();
|
||||
|
||||
// By default we will trim the value
|
||||
@@ -404,9 +419,13 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
}
|
||||
|
||||
if (ctrl.$viewValue !== value) {
|
||||
scope.$apply(function() {
|
||||
if (scope.$$phase) {
|
||||
ctrl.$setViewValue(value);
|
||||
});
|
||||
} else {
|
||||
scope.$apply(function() {
|
||||
ctrl.$setViewValue(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -436,15 +455,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
deferListener();
|
||||
});
|
||||
|
||||
// if user paste into input using mouse, we need "change" event to catch it
|
||||
element.on('change', listener);
|
||||
|
||||
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
|
||||
if ($sniffer.hasEvent('paste')) {
|
||||
element.on('paste cut', deferListener);
|
||||
}
|
||||
}
|
||||
|
||||
// if user paste into input using mouse on older browser
|
||||
// or form autocomplete on newer browser, we need "change" event to catch it
|
||||
element.on('change', listener);
|
||||
|
||||
ctrl.$render = function() {
|
||||
element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
|
||||
@@ -938,39 +957,6 @@ var VALID_CLASS = 'ng-valid',
|
||||
</file>
|
||||
* </example>
|
||||
*
|
||||
* ## Isolated Scope Pitfall
|
||||
*
|
||||
* Note that if you have a directive with an isolated scope, you cannot require `ngModel`
|
||||
* since the model value will be looked up on the isolated scope rather than the outer scope.
|
||||
* When the directive updates the model value, calling `ngModel.$setViewValue()` the property
|
||||
* on the outer scope will not be updated. However you can get around this by using $parent.
|
||||
*
|
||||
* Here is an example of this situation. You'll notice that the first div is not updating the input.
|
||||
* However the second div can update the input properly.
|
||||
*
|
||||
* <example module="badIsolatedDirective">
|
||||
<file name="script.js">
|
||||
angular.module('badIsolatedDirective', []).directive('isolate', function() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
scope: { },
|
||||
template: '<input ng-model="innerModel">',
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
scope.$watch('innerModel', function(value) {
|
||||
console.log(value);
|
||||
ngModel.$setViewValue(value);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
</file>
|
||||
<file name="index.html">
|
||||
<input ng-model="someModel"/>
|
||||
<div isolate ng-model="someModel"></div>
|
||||
<div isolate ng-model="$parent.someModel"></div>
|
||||
</file>
|
||||
* </example>
|
||||
*
|
||||
*
|
||||
*/
|
||||
var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
|
||||
@@ -1117,7 +1103,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
* It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
|
||||
* which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
|
||||
* `$modelValue` and the **expression** specified in the `ng-model` attribute.
|
||||
*
|
||||
*
|
||||
* Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
|
||||
*
|
||||
* Note that calling this function does not trigger a `$digest`.
|
||||
@@ -1174,6 +1160,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
ctrl.$render();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}];
|
||||
|
||||
@@ -1450,7 +1438,6 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
||||
id="{{name}}"
|
||||
name="favorite">
|
||||
</label>
|
||||
</span>
|
||||
<div>You chose {{my.favorite}}</div>
|
||||
</form>
|
||||
</doc:source>
|
||||
|
||||
@@ -20,11 +20,10 @@ function classDirective(name, selector) {
|
||||
// jshint bitwise: false
|
||||
var mod = $index & 1;
|
||||
if (mod !== old$index & 1) {
|
||||
if (mod === selector) {
|
||||
addClass(scope.$eval(attr[name]));
|
||||
} else {
|
||||
removeClass(scope.$eval(attr[name]));
|
||||
}
|
||||
var classes = flattenClasses(scope.$eval(attr[name]));
|
||||
mod === selector ?
|
||||
attr.$addClass(classes) :
|
||||
attr.$removeClass(classes);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -32,24 +31,17 @@ function classDirective(name, selector) {
|
||||
|
||||
function ngClassWatchAction(newVal) {
|
||||
if (selector === true || scope.$index % 2 === selector) {
|
||||
if (oldVal && !equals(newVal,oldVal)) {
|
||||
removeClass(oldVal);
|
||||
var newClasses = flattenClasses(newVal || '');
|
||||
if(!oldVal) {
|
||||
attr.$addClass(newClasses);
|
||||
} else if(!equals(newVal,oldVal)) {
|
||||
attr.$updateClass(newClasses, flattenClasses(oldVal));
|
||||
}
|
||||
addClass(newVal);
|
||||
}
|
||||
oldVal = copy(newVal);
|
||||
}
|
||||
|
||||
|
||||
function removeClass(classVal) {
|
||||
attr.$removeClass(flattenClasses(classVal));
|
||||
}
|
||||
|
||||
|
||||
function addClass(classVal) {
|
||||
attr.$addClass(flattenClasses(classVal));
|
||||
}
|
||||
|
||||
function flattenClasses(classVal) {
|
||||
if(isArray(classVal)) {
|
||||
return classVal.join(' ');
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
*
|
||||
* Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
|
||||
* cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
|
||||
* class `ngCloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
* class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
|
||||
*
|
||||
* @element ANY
|
||||
*
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
var ngControllerDirective = [function() {
|
||||
return {
|
||||
scope: true,
|
||||
controller: '@'
|
||||
controller: '@',
|
||||
priority: 500
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -69,7 +69,14 @@ forEach(
|
||||
* a dblclick. (The Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-dblclick="count = count + 1" ng-init="count=0">
|
||||
Increment (on double click)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -85,7 +92,14 @@ forEach(
|
||||
* mousedown. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousedown="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse down)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -101,7 +115,14 @@ forEach(
|
||||
* mouseup. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseup="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse up)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -116,7 +137,14 @@ forEach(
|
||||
* mouseover. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseover="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse is over)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -132,7 +160,14 @@ forEach(
|
||||
* mouseenter. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseenter="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse enters)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -148,7 +183,14 @@ forEach(
|
||||
* mouseleave. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseleave="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse leaves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -164,7 +206,14 @@ forEach(
|
||||
* mousemove. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousemove="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse moves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -180,7 +229,12 @@ forEach(
|
||||
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keydown="count = count + 1" ng-init="count=0">
|
||||
key down count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -196,7 +250,12 @@ forEach(
|
||||
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keyup="count = count + 1" ng-init="count=0">
|
||||
key up count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -212,7 +271,12 @@ forEach(
|
||||
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keypress="count = count + 1" ng-init="count=0">
|
||||
key press count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -311,7 +375,12 @@ forEach(
|
||||
* copy. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
|
||||
copied: {{copied}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -326,7 +395,12 @@ forEach(
|
||||
* cut. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
|
||||
cut: {{cut}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -341,5 +415,10 @@ forEach(
|
||||
* paste. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
|
||||
pasted: {{paste}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
/*
|
||||
The transition styles can also be placed on the CSS base class above
|
||||
*/
|
||||
.animate-if.ng-enter, .animate-if.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
@@ -94,9 +91,12 @@ var ngIfDirective = ['$animate', function($animate) {
|
||||
if (!childScope) {
|
||||
childScope = $scope.$new();
|
||||
$transclude(childScope, function (clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when it's template arrives.
|
||||
block = {
|
||||
startNode: clone[0],
|
||||
endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
|
||||
clone: clone
|
||||
};
|
||||
$animate.enter(clone, $element.parent(), $element);
|
||||
});
|
||||
@@ -109,7 +109,7 @@ var ngIfDirective = ['$animate', function($animate) {
|
||||
}
|
||||
|
||||
if (block) {
|
||||
$animate.leave(getBlockElements(block));
|
||||
$animate.leave(getBlockElements(block.clone));
|
||||
block = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,13 +147,14 @@
|
||||
* @description
|
||||
* Emitted every time the ngInclude content is reloaded.
|
||||
*/
|
||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
|
||||
function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) {
|
||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
|
||||
function($http, $templateCache, $anchorScroll, $animate, $sce) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: 400,
|
||||
terminal: true,
|
||||
transclude: 'element',
|
||||
controller: angular.noop,
|
||||
compile: function(element, attr) {
|
||||
var srcExp = attr.ngInclude || attr.src,
|
||||
onloadExp = attr.onload || '',
|
||||
@@ -187,28 +188,52 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||
$http.get(src, {cache: $templateCache}).success(function(response) {
|
||||
if (thisChangeId !== changeCounter) return;
|
||||
var newScope = scope.$new();
|
||||
ctrl.template = response;
|
||||
|
||||
$transclude(newScope, function(clone) {
|
||||
// Note: This will also link all children of ng-include that were contained in the original
|
||||
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||
// However, using ng-include on an element with additional content does not make sense...
|
||||
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
cleanupLastIncludeContent();
|
||||
|
||||
currentScope = newScope;
|
||||
currentElement = clone;
|
||||
|
||||
currentElement.html(response);
|
||||
$animate.enter(currentElement, null, $element, afterAnimation);
|
||||
$compile(currentElement.contents())(currentScope);
|
||||
currentScope.$emit('$includeContentLoaded');
|
||||
scope.$eval(onloadExp);
|
||||
$animate.enter(clone, null, $element, afterAnimation);
|
||||
});
|
||||
|
||||
currentScope = newScope;
|
||||
currentElement = clone;
|
||||
|
||||
currentScope.$emit('$includeContentLoaded');
|
||||
scope.$eval(onloadExp);
|
||||
}).error(function() {
|
||||
if (thisChangeId === changeCounter) cleanupLastIncludeContent();
|
||||
});
|
||||
scope.$emit('$includeContentRequested');
|
||||
} else {
|
||||
cleanupLastIncludeContent();
|
||||
ctrl.template = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
// This directive is called during the $transclude call of the first `ngInclude` directive.
|
||||
// It will replace and compile the content of the element with the loaded template.
|
||||
// We need this directive so that the element content is already filled when
|
||||
// the link function of another directive on the same element as ngInclude
|
||||
// is called.
|
||||
var ngIncludeFillContentDirective = ['$compile',
|
||||
function($compile) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: -400,
|
||||
require: 'ngInclude',
|
||||
link: function(scope, $element, $attr, ctrl) {
|
||||
$element.html(ctrl.template);
|
||||
$compile($element.contents())(scope);
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
* current scope.
|
||||
*
|
||||
* <div class="alert alert-error">
|
||||
* The only appropriate use of `ngInit` for aliasing special properties of
|
||||
* The only appropriate use of `ngInit` is for aliasing special properties of
|
||||
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
||||
* should use {@link guide/controller controllers} rather than `ngInit`
|
||||
* to initialize values on a scope.
|
||||
* </div>
|
||||
*
|
||||
* @priority 450
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngInit {@link guide/expression Expression} to eval.
|
||||
*
|
||||
@@ -47,6 +49,7 @@
|
||||
</doc:example>
|
||||
*/
|
||||
var ngInitDirective = ngDirective({
|
||||
priority: 450,
|
||||
compile: function() {
|
||||
return {
|
||||
pre: function(scope, element, attrs) {
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
* other numbers, for example 12, so that instead of showing "12 people are viewing", you can
|
||||
* show "a dozen people are viewing".
|
||||
*
|
||||
* You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
|
||||
* You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
|
||||
* into pluralized strings. In the previous example, Angular will replace `{}` with
|
||||
* <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
|
||||
* for <span ng-non-bindable>{{numberExpression}}</span>.
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
|
||||
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
|
||||
* with the corresponding item in the array by identity. Moving the same object in array would move the DOM
|
||||
* element in the same way ian the DOM.
|
||||
* element in the same way in the DOM.
|
||||
*
|
||||
* For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
|
||||
* case the object identity does not matter. Two objects are considered equivalent as long as their `id`
|
||||
@@ -203,7 +203,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
$$tlb: true,
|
||||
link: function($scope, $element, $attr, ctrl, $transclude){
|
||||
var expression = $attr.ngRepeat;
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
|
||||
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
lhs, rhs, valueIdentifier, keyIdentifier,
|
||||
hashFnLocals = {$id: hashKey};
|
||||
@@ -215,7 +215,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
|
||||
lhs = match[1];
|
||||
rhs = match[2];
|
||||
trackByExp = match[4];
|
||||
trackByExp = match[3];
|
||||
|
||||
if (trackByExp) {
|
||||
trackByExpGetter = $parse(trackByExp);
|
||||
@@ -301,7 +301,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
} else if (nextBlockMap.hasOwnProperty(trackById)) {
|
||||
// restore lastBlockMap
|
||||
forEach(nextBlockOrder, function(block) {
|
||||
if (block && block.startNode) lastBlockMap[block.id] = block;
|
||||
if (block && block.scope) lastBlockMap[block.id] = block;
|
||||
});
|
||||
// This is a duplicate and we need to throw an error
|
||||
throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
|
||||
@@ -318,7 +318,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
// lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
|
||||
if (lastBlockMap.hasOwnProperty(key)) {
|
||||
block = lastBlockMap[key];
|
||||
elementsToRemove = getBlockElements(block);
|
||||
elementsToRemove = getBlockElements(block.clone);
|
||||
$animate.leave(elementsToRemove);
|
||||
forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
|
||||
block.scope.$destroy();
|
||||
@@ -330,9 +330,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
||||
value = collection[key];
|
||||
block = nextBlockOrder[index];
|
||||
if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;
|
||||
if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
|
||||
|
||||
if (block.startNode) {
|
||||
if (block.scope) {
|
||||
// if we have already seen this object, then we need to reuse the
|
||||
// associated scope/element
|
||||
childScope = block.scope;
|
||||
@@ -342,11 +342,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
nextNode = nextNode.nextSibling;
|
||||
} while(nextNode && nextNode[NG_REMOVED]);
|
||||
|
||||
if (block.startNode != nextNode) {
|
||||
if (getBlockStart(block) != nextNode) {
|
||||
// existing item which got moved
|
||||
$animate.move(getBlockElements(block), null, jqLite(previousNode));
|
||||
$animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
|
||||
}
|
||||
previousNode = block.endNode;
|
||||
previousNode = getBlockEnd(block);
|
||||
} else {
|
||||
// new item which we don't know about
|
||||
childScope = $scope.$new();
|
||||
@@ -362,14 +362,16 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
childScope.$odd = !(childScope.$even = (index&1) === 0);
|
||||
// jshint bitwise: true
|
||||
|
||||
if (!block.startNode) {
|
||||
if (!block.scope) {
|
||||
$transclude(childScope, function(clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
|
||||
$animate.enter(clone, null, jqLite(previousNode));
|
||||
previousNode = clone;
|
||||
block.scope = childScope;
|
||||
block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
|
||||
block.endNode = clone[clone.length - 1];
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when it's template arrives.
|
||||
block.clone = clone;
|
||||
nextBlockMap[block.id] = block;
|
||||
});
|
||||
}
|
||||
@@ -378,5 +380,13 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getBlockStart(block) {
|
||||
return block.clone[0];
|
||||
}
|
||||
|
||||
function getBlockEnd(block) {
|
||||
return block.clone[block.clone.length - 1];
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user