Compare commits
293 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f9a1c21e6 | |||
| ece7854972 | |||
| 8ace8073fd | |||
| 43a2f3d0bf | |||
| a9cccbe14f | |||
| 36c9e42de2 | |||
| 9f566db33c | |||
| c77b2bcca3 | |||
| 5a4145fe16 | |||
| 039b990d8d | |||
| 5a9cb8be3f | |||
| 63cd873fef | |||
| 69452fa94f | |||
| 2ed4ad5502 | |||
| 1d2a388830 | |||
| ac05276a51 | |||
| cb9c0f200a | |||
| b1d676b7f7 | |||
| 9ddef840b6 | |||
| 28fc80bba0 | |||
| b6c42d5e81 | |||
| 1c045f1b46 | |||
| 95e1b2d612 | |||
| 75345e3487 | |||
| f4fe28bd92 | |||
| ace13b94e6 | |||
| 5df7e73adf | |||
| e115342fce | |||
| e89150ca0f | |||
| 9693a426e3 | |||
| 162485d303 | |||
| affcbad501 | |||
| 7e916455b3 | |||
| cdc4d485a6 | |||
| c894470d41 | |||
| 1b0718bf89 | |||
| 53fd24ffcb | |||
| eb90672aae | |||
| 28cfd96fdc | |||
| 99d5defb1a | |||
| efbc242875 | |||
| d4d58f287f | |||
| dc89db33df | |||
| 5dc27959d5 | |||
| 4c21355940 | |||
| 6f6cb5c8d8 | |||
| 821ed310a7 | |||
| a7aa4cc0a9 | |||
| e0ce9ed36d | |||
| caeb740265 | |||
| 1bb33cccbe | |||
| d9ed9c5ac1 | |||
| 00cac6ed10 | |||
| 2e9d7cc6cb | |||
| 32cc6cbb6f | |||
| 3b1a4fe0c8 | |||
| 9569778f2f | |||
| 0f61316b24 | |||
| 86151b0cea | |||
| 1b7a6c66f8 | |||
| 0ef76dde41 | |||
| 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 |
@@ -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
|
||||
|
||||
+297
@@ -1,3 +1,297 @@
|
||||
<a name="1.2.8"></a>
|
||||
# 1.2.8 interdimensional-cartography (2014-01-10)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$http:**
|
||||
- return responseText on IE8 for requests with responseType set
|
||||
([a9cccbe1](https://github.com/angular/angular.js/commit/a9cccbe14f1bd9048f5dab4443f58c804d4259a1),
|
||||
[#4464](https://github.com/angular/angular.js/issues/4464), [#4738](https://github.com/angular/angular.js/issues/4738), [#5636](https://github.com/angular/angular.js/issues/5636))
|
||||
- Allow status code 0 from any protocol
|
||||
([28fc80bb](https://github.com/angular/angular.js/commit/28fc80bba0107075ab371fd0a7634a38891626b2),
|
||||
[#1356](https://github.com/angular/angular.js/issues/1356), [#5547](https://github.com/angular/angular.js/issues/5547))
|
||||
- cancelled JSONP requests will not print error in the console
|
||||
([95e1b2d6](https://github.com/angular/angular.js/commit/95e1b2d6121b4e26cf87dcf6746a7b8cb4c25e7f),
|
||||
[#5615](https://github.com/angular/angular.js/issues/5615), [#5616](https://github.com/angular/angular.js/issues/5616))
|
||||
- **$location:** return '/' for root path in hashbang mode
|
||||
([63cd873f](https://github.com/angular/angular.js/commit/63cd873fef3207deef30c7a7ed66f4b8f647dc12),
|
||||
[#5650](https://github.com/angular/angular.js/issues/5650), [#5712](https://github.com/angular/angular.js/issues/5712))
|
||||
- **$parse:** fix CSP nested property evaluation, and issue that prevented its tests from failing
|
||||
([3b1a4fe0](https://github.com/angular/angular.js/commit/3b1a4fe0c83c7898ecd7261ab4213998ee7be0ec),
|
||||
[#5591](https://github.com/angular/angular.js/issues/5591), [#5592](https://github.com/angular/angular.js/issues/5592))
|
||||
- **closure:** add Closure externs for angular.$q.Promise.finally
|
||||
([caeb7402](https://github.com/angular/angular.js/commit/caeb7402651702cd13df2f1594e9827439a8b760),
|
||||
[#4757](https://github.com/angular/angular.js/issues/4757))
|
||||
- **ngMock window.inject:** Remove Error 'stack' property changes
|
||||
([7e916455](https://github.com/angular/angular.js/commit/7e916455b36dc9ca4d4afc1e44cade90006d00e3))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **select:** allow multiline ng-options
|
||||
([43a2f3d0](https://github.com/angular/angular.js/commit/43a2f3d0bf435e3626cd679caff4281cfb3415bd),
|
||||
[#5602](https://github.com/angular/angular.js/issues/5602))
|
||||
|
||||
<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)
|
||||
|
||||
@@ -4193,3 +4487,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)
|
||||
|
||||
+23
-13
@@ -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');
|
||||
@@ -100,51 +101,49 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
|
||||
runprotractor: {
|
||||
normal: 'protractor-conf.js'
|
||||
},
|
||||
|
||||
|
||||
clean: {
|
||||
build: ['build'],
|
||||
tmp: ['tmp']
|
||||
},
|
||||
|
||||
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 +177,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,18 +274,29 @@ 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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//alias tasks
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e']);
|
||||
grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:e2e', 'webdriver', 'runprotractor:normal']);
|
||||
grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']);
|
||||
grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']);
|
||||
grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']);
|
||||
grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']);
|
||||
grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']);
|
||||
grunt.registerTask('test:e2e', 'Run the end to end tests with Karma and keep a test server running in the background', ['connect:testserver', 'tests:end2end']);
|
||||
// This should eventually replace test:e2e
|
||||
grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'runprotractor:normal']);
|
||||
grunt.registerTask('test:docgen', ['jasmine_node']);
|
||||
grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']);
|
||||
|
||||
@@ -294,6 +304,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 border-spacing (!ie) and zoom (ie) CSS properties are
|
||||
* used below since they trigger a transition without making the browser
|
||||
* animate anything and they're both highly underused CSS properties */
|
||||
.ng-animate-start { border-spacing:1px 1px; -ms-zoom:1.0001; }
|
||||
.ng-animate-active { border-spacing:0px 0px; -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -19,7 +19,7 @@ testable.
|
||||
To register a service, you must have a module that this service will be part of. Afterwards, you
|
||||
can register the service with the module either via the {@link api/angular.Module Module api} or
|
||||
by using the {@link api/AUTO.$provide $provide} service in the module configuration
|
||||
function.The following pseudo-code shows both approaches:
|
||||
function. The following pseudo-code shows both approaches:
|
||||
|
||||
Using the angular.Module api:
|
||||
<pre>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -163,7 +163,7 @@ function MyClass(xhr) {
|
||||
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. This is dependency-injection is in a nutshell.
|
||||
creation from the logic. This is dependency-injection in a nutshell.
|
||||
|
||||
The class above is testable, since in the test we can write:
|
||||
<pre>
|
||||
@@ -222,7 +222,7 @@ 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 and this results in
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -280,7 +280,7 @@ using `templateUrl` instead:
|
||||
</example>
|
||||
|
||||
Great! But what if we wanted to have our directive match the tag name `<my-customer>` instead?
|
||||
If we simply put a `<my-customer>` element into the HMTL, it doesn't work.
|
||||
If we simply put a `<my-customer>` element into the HTML, it doesn't work.
|
||||
|
||||
<div class="alert alert-waring">
|
||||
**Note:** When you create a directive, it is restricted to attribute only by default. In order to
|
||||
@@ -506,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">
|
||||
@@ -528,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">
|
||||
@@ -537,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,
|
||||
@@ -552,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 {
|
||||
@@ -583,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?
|
||||
|
||||
@@ -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 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',
|
||||
|
||||
@@ -97,7 +97,7 @@ locale, it is fine to rely on the default currency symbol. However, if you antic
|
||||
in other locales might use your app, you should provide your own currency symbol to make sure the
|
||||
actual value is understood.
|
||||
|
||||
For example, if you want to display account balance of 1000 dollars with the following binding
|
||||
For example, if you want to display an account balance of 1000 dollars with the following binding
|
||||
containing currency filter: `{{ 1000 | currency }}`, and your app is currently in en-US locale.
|
||||
'$1000.00' will be shown. However, if someone in a different local (say, Japan) views your app, her
|
||||
browser will specify the locale as ja, and the balance of '¥1000.00' will be shown instead. This
|
||||
|
||||
@@ -23,7 +23,7 @@ It is very unlikely that issues specific to IE7 or earlier will be given any tim
|
||||
|
||||
To make your Angular application work on IE please make sure that:
|
||||
|
||||
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
|
||||
1. You polyfill JSON.stringify for IE7 and below. You can use
|
||||
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
|
||||
<pre>
|
||||
@@ -51,7 +51,7 @@ To make your Angular application work on IE please make sure that:
|
||||
3. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
|
||||
`<div ng-view>` instead), or
|
||||
|
||||
4. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
||||
4. if you **do use** custom element tags, then you must take these steps to make IE 8 and below happy:
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -590,6 +590,10 @@ See [79223eae](https://github.com/angular/angular.js/commit/79223eae502283889334
|
||||
|
||||
## 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.
|
||||
These properties will not be available to Angular expressions (i.e. {{
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ directory.</p></li>
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> and its plugins if you
|
||||
don't have it already:</p>
|
||||
<pre>
|
||||
npm install -g karma
|
||||
npm install
|
||||
</pre></li>
|
||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
||||
|
||||
@@ -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/`
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -184,7 +184,11 @@ 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
|
||||
@@ -213,9 +217,13 @@ is located at `./config/karma.conf.js`).
|
||||
|
||||
* Create a new model property in the controller and bind to it from the template. For example:
|
||||
|
||||
$scope.hello = "Hello, World!"
|
||||
$scope.name = "World"
|
||||
|
||||
Refresh your browser to make sure it says, "Hello, World!"
|
||||
Then add a new binding to `index.html`:
|
||||
|
||||
<p>Hello, {{name}}!</p>
|
||||
|
||||
Refresh your browser and verifies that it says "Hello, World!".
|
||||
|
||||
* Create a repeater that constructs a simple table:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ view, Angular will use the `phone-list.html` template and the `PhoneListCtrl` co
|
||||
We reused the `PhoneListCtrl` controller that we constructed in previous steps and we added a new,
|
||||
empty `PhoneDetailCtrl` controller to the `app/js/controllers.js` file for the phone details view.
|
||||
|
||||
`$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
|
||||
`$routeProvider.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when the browser
|
||||
address doesn't match either of our routes.
|
||||
|
||||
Note the use of the `:phoneId` parameter in the second route declaration. The `$route` service uses
|
||||
@@ -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.
|
||||
@@ -289,8 +293,7 @@ Let's add another animation to our application. Switching to our `phone-detail.h
|
||||
we see that we have a nice thumbnail swapper. By clicking on the thumbnails listed on the page,
|
||||
the profile phone image changes. But how can we change this around to add animations?
|
||||
|
||||
Lets think about it first,
|
||||
basically when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
|
||||
Let's think about it first. Basically, when you click on a thumbnail image, you're changing the state of the profile image to reflect the newly
|
||||
selected thumbnail image.
|
||||
The best way to specify state changes within HTML is to use classes.
|
||||
Much like before, how we used a CSS class to specify
|
||||
@@ -383,10 +386,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
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
var ngdoc = require('../src/ngdoc.js');
|
||||
var DOM = require('../src/dom.js').DOM;
|
||||
var gruntUtil = require('../../lib/grunt/utils.js');
|
||||
|
||||
|
||||
describe('ngdoc', function() {
|
||||
var Doc = ngdoc.Doc;
|
||||
@@ -287,6 +289,33 @@ describe('ngdoc', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('api section', function() {
|
||||
|
||||
it('should render a "view source" button with link to the source in master', function() {
|
||||
var doc = new Doc({
|
||||
id: 'ng.abc',
|
||||
name: 'ng.abc',
|
||||
section: 'api',
|
||||
ngdoc: 'service',
|
||||
file: 'fooService.js',
|
||||
line: '333'
|
||||
});
|
||||
|
||||
if (gruntUtil.getVersion().full.indexOf('-') === -1) {
|
||||
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
|
||||
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/v\d+\.\d+\.\d+\/fooService\.js#L333" class="view-source/
|
||||
);
|
||||
} else {
|
||||
expect(doc.html().match(/^(<a .*?<\/a>)/)[1]).toMatch(
|
||||
/<a href="http:\/\/github\.com\/angular\/angular\.js\/tree\/[a-z0-9]{7}\/fooService\.js#L333" class="view-source/
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
describe('TAG', function() {
|
||||
|
||||
@@ -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 $;}
|
||||
|
||||
|
||||
+16
-3
@@ -6,7 +6,8 @@ var makeUnique = {
|
||||
'script.js': true,
|
||||
'unit.js': true,
|
||||
'spec.js': true,
|
||||
'scenario.js': true
|
||||
'scenario.js': true,
|
||||
'protractorTest.js': true
|
||||
}
|
||||
|
||||
function ids(list) {
|
||||
@@ -14,7 +15,7 @@ function ids(list) {
|
||||
};
|
||||
|
||||
|
||||
exports.Example = function(scenarios) {
|
||||
exports.Example = function(scenarios, protractorTests) {
|
||||
this.module = '';
|
||||
this.deps = ['angular.js'];
|
||||
this.html = [];
|
||||
@@ -24,6 +25,8 @@ exports.Example = function(scenarios) {
|
||||
this.unit = [];
|
||||
this.scenario = [];
|
||||
this.scenarios = scenarios;
|
||||
this.protractorTest = [];
|
||||
this.protractorTests = protractorTests;
|
||||
}
|
||||
|
||||
exports.Example.prototype.setModule = function(module) {
|
||||
@@ -44,6 +47,10 @@ exports.Example.prototype.addSource = function(name, content) {
|
||||
var ext = name == 'scenario.js' ? 'scenario' : name.split('.')[1],
|
||||
id = name;
|
||||
|
||||
if (name == 'protractorTest.js') {
|
||||
ext = 'protractorTest';
|
||||
}
|
||||
|
||||
if (makeUnique[name] && usedIds[id]) {
|
||||
id = name + '-' + (seqCount++);
|
||||
}
|
||||
@@ -56,6 +63,9 @@ exports.Example.prototype.addSource = function(name, content) {
|
||||
if (ext == 'scenario') {
|
||||
this.scenarios.push(content);
|
||||
}
|
||||
if (ext == 'protractorTest') {
|
||||
this.protractorTests.push(content);
|
||||
}
|
||||
};
|
||||
|
||||
exports.Example.prototype.enableAnimations = function() {
|
||||
@@ -92,6 +102,7 @@ exports.Example.prototype.toHtmlEdit = function() {
|
||||
out.push(' source-edit-json="' + ids(this.json) + '"');
|
||||
out.push(' source-edit-unit="' + ids(this.unit) + '"');
|
||||
out.push(' source-edit-scenario="' + ids(this.scenario) + '"');
|
||||
out.push(' source-edit-protractor="' + ids(this.protractorTest) + '"');
|
||||
out.push('></div>\n');
|
||||
return out.join('');
|
||||
};
|
||||
@@ -107,6 +118,7 @@ exports.Example.prototype.toHtmlTabs = function() {
|
||||
htmlTabs(this.json);
|
||||
htmlTabs(this.unit);
|
||||
htmlTabs(this.scenario);
|
||||
htmlTabs(this.protractorTest);
|
||||
out.push('</div>');
|
||||
return out.join('');
|
||||
|
||||
@@ -119,7 +131,8 @@ exports.Example.prototype.toHtmlTabs = function() {
|
||||
if (name === 'index.html') {
|
||||
wrap = ' ng-html-wrap="' + self.module + ' ' + self.deps.join(' ') + '"';
|
||||
}
|
||||
if (name == 'scenario.js') name = 'End to end test';
|
||||
if (name == 'scenario.js') name = 'ngScenario e2e test';
|
||||
if (name == 'protractorTest.js') name = 'Protractor e2e test';
|
||||
|
||||
out.push(
|
||||
'<div class="tab-pane" title="' + name + '">\n' +
|
||||
|
||||
+10
-4
@@ -17,6 +17,8 @@ writer.makeDir('build/docs/', true).then(function() {
|
||||
return writer.makeDir('build/docs/components/bootstrap');
|
||||
}).then(function() {
|
||||
return writer.makeDir('build/docs/components/font-awesome');
|
||||
}).then(function() {
|
||||
return writer.makeDir('build/docs/e2etests');
|
||||
}).then(function() {
|
||||
console.log('Generating AngularJS Reference Documentation...');
|
||||
return reader.collect();
|
||||
@@ -53,6 +55,10 @@ writer.makeDir('build/docs/', true).then(function() {
|
||||
var id = doc.id.replace('angular.Module', 'angular.IModule');
|
||||
|
||||
fileFutures.push(writer.output('partials/' + doc.section + '/' + id + '.html', doc.html()));
|
||||
// If it has a sample Protractor test, output that as well.
|
||||
if (doc.protractorTests.length) {
|
||||
fileFutures.push(writer.output('ptore2e/' + doc.section + '/' + id + '_test.js', ngdoc.writeProtractorTest(doc)));
|
||||
}
|
||||
});
|
||||
|
||||
ngdoc.checkBrokenLinks(docs);
|
||||
@@ -74,10 +80,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"';
|
||||
|
||||
|
||||
+23
-3
@@ -35,6 +35,7 @@ var lookupMinerrMsg = function (doc) {
|
||||
exports.trim = trim;
|
||||
exports.metadata = metadata;
|
||||
exports.scenarios = scenarios;
|
||||
exports.writeProtractorTest = writeProtractorTest;
|
||||
exports.merge = merge;
|
||||
exports.checkBrokenLinks = checkBrokenLinks;
|
||||
exports.Doc = Doc;
|
||||
@@ -155,6 +156,7 @@ function Doc(text, file, line) {
|
||||
this.line = line;
|
||||
}
|
||||
this.scenarios = this.scenarios || [];
|
||||
this.protractorTests = this.protractorTests || [];
|
||||
this.requires = this.requires || [];
|
||||
this.param = this.param || [];
|
||||
this.properties = this.properties || [];
|
||||
@@ -292,7 +294,7 @@ Doc.prototype = {
|
||||
replace(/<example(?:\s+module="([^"]*)")?(?:\s+deps="([^"]*)")?(\s+animations="true")?>([\s\S]*?)<\/example>/gmi,
|
||||
function(_, module, deps, animations, content) {
|
||||
|
||||
var example = new Example(self.scenarios);
|
||||
var example = new Example(self.scenarios, self.protractorTests);
|
||||
if(animations) {
|
||||
example.enableAnimations();
|
||||
example.addDeps('angular-animate.js');
|
||||
@@ -329,7 +331,7 @@ Doc.prototype = {
|
||||
}).
|
||||
replace(/^<doc:example(\s+[^>]*)?>([\s\S]*)<\/doc:example>/mi, function(_, attrs, content) {
|
||||
var html, script, scenario,
|
||||
example = new Example(self.scenarios);
|
||||
example = new Example(self.scenarios, self.protractorTests);
|
||||
|
||||
example.setModule((attrs||'module=""').match(/^\s*module=["'](.*)["']\s*$/)[1]);
|
||||
content.
|
||||
@@ -347,6 +349,8 @@ Doc.prototype = {
|
||||
}).
|
||||
replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi, function(_, before, content){
|
||||
example.addSource('scenario.js', content);
|
||||
}).replace(/(<doc:protractor>)([\s\S]*)(<\/doc:protractor>)/mi, function(_, before, content){
|
||||
example.addSource('protractorTest.js', content);
|
||||
});
|
||||
|
||||
return placeholder(example.toHtml());
|
||||
@@ -548,7 +552,7 @@ Doc.prototype = {
|
||||
minerrMsg;
|
||||
|
||||
var gitTagFromFullVersion = function(version) {
|
||||
var match = version.match(/-(\w{7})/);
|
||||
var match = version.match(/sha\.(\w{7})/);
|
||||
|
||||
if (match) {
|
||||
// git sha
|
||||
@@ -1106,6 +1110,22 @@ function scenarios(docs){
|
||||
}
|
||||
}
|
||||
|
||||
function writeProtractorTest(doc){
|
||||
var lines = [];
|
||||
lines.push('describe("' + doc.section + '/' + doc.id + '", function() {');
|
||||
lines.push(' beforeEach(function() {');
|
||||
lines.push(' browser.get("index-nocache.html#!/' + doc.section + '/' + doc.id + '");');
|
||||
lines.push(' });');
|
||||
lines.push('');
|
||||
doc.protractorTests.forEach(function(test){
|
||||
lines.push(indentCode(trim(test), 2));
|
||||
lines.push('');
|
||||
});
|
||||
lines.push('});');
|
||||
lines.push('');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
function metadata(docs){
|
||||
|
||||
+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,32 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
.content h6 {
|
||||
text-transform:none;
|
||||
color:black;
|
||||
}
|
||||
|
||||
ul.parameters > li > p,
|
||||
@@ -522,6 +548,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');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+7
-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,13 +28,15 @@ 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
|
||||
grunt test:protractor
|
||||
|
||||
# Promises/A+ TESTS #
|
||||
grunt test:promises-aplus --no-color
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ module.exports = function(config) {
|
||||
junitReporter: {
|
||||
outputFile: 'test_out/e2e.xml',
|
||||
suite: 'E2E'
|
||||
}
|
||||
},
|
||||
|
||||
browserNoActivityTimeout: 90000
|
||||
});
|
||||
};
|
||||
|
||||
+125
-8
@@ -6,13 +6,25 @@ module.exports = function(config, specificOptions) {
|
||||
logColors: true,
|
||||
browsers: ['Chrome'],
|
||||
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:
|
||||
@@ -24,13 +36,14 @@ module.exports = function(config, specificOptions) {
|
||||
},
|
||||
'SL_Firefox': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox'
|
||||
browserName: 'firefox',
|
||||
version: '26'
|
||||
},
|
||||
'SL_Safari': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'Mac 10.8',
|
||||
version: '6'
|
||||
platform: 'OS X 10.9',
|
||||
version: '7'
|
||||
},
|
||||
'SL_IE_8': {
|
||||
base: 'SauceLabs',
|
||||
@@ -49,12 +62,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 +140,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 &
|
||||
@@ -61,6 +61,14 @@ module.exports = function(grunt) {
|
||||
util.startKarma.call(util, this.data, false, this.async());
|
||||
});
|
||||
|
||||
grunt.registerTask('webdriver', 'Update webdriver', function() {
|
||||
util.updateWebdriver.call(util, this.async());
|
||||
});
|
||||
|
||||
grunt.registerMultiTask('runprotractor', 'Run Protractor integration tests', function() {
|
||||
util.startProtractor.call(util, this.data, this.async());
|
||||
});
|
||||
|
||||
grunt.registerTask('collect-errors', 'Combine stripped error files', function () {
|
||||
util.collectErrors();
|
||||
});
|
||||
|
||||
+58
-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;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -63,6 +84,38 @@ module.exports = {
|
||||
},
|
||||
|
||||
|
||||
updateWebdriver: function(done){
|
||||
var p = spawn('node', ['node_modules/protractor/bin/webdriver-manager', 'update']);
|
||||
p.stdout.pipe(process.stdout);
|
||||
p.stderr.pipe(process.stderr);
|
||||
p.on('exit', function(code){
|
||||
if(code !== 0) grunt.fail.warn('Webdriver failed to update');
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
startProtractor: function(config, done){
|
||||
var sauceUser = grunt.option('sauceUser');
|
||||
var sauceKey = grunt.option('sauceKey');
|
||||
var tunnelIdentifier = grunt.option('capabilities.tunnel-identifier');
|
||||
var sauceBuild = grunt.option('capabilities.build');
|
||||
var args = ['node_modules/protractor/bin/protractor', config];
|
||||
if (sauceUser) args.push('--sauceUser=' + sauceUser);
|
||||
if (sauceKey) args.push('--sauceKey=' + sauceKey);
|
||||
if (tunnelIdentifier) args.push('--capabilities.tunnel-identifier=' + tunnelIdentifier);
|
||||
if (sauceBuild) args.push('--capabilities.build=' + sauceBuild);
|
||||
|
||||
|
||||
var p = spawn('node', args);
|
||||
p.stdout.pipe(process.stdout);
|
||||
p.stderr.pipe(process.stderr);
|
||||
p.on('exit', function(code){
|
||||
if(code !== 0) grunt.fail.warn('Protractor test(s) failed. Exit code: ' + code);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
wrap: function(src, name){
|
||||
src.unshift('src/' + name + '.prefix');
|
||||
src.push('src/' + name + '.suffix');
|
||||
@@ -295,5 +348,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
|
||||
|
||||
|
||||
|
||||
+18
-14
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.2.2",
|
||||
"cdnVersion": "1.2.1",
|
||||
"codename": "consciousness-inertia",
|
||||
"version": "1.2.8",
|
||||
"cdnVersion": "1.2.7",
|
||||
"codename": "interdimensional-cartography",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,23 +10,26 @@
|
||||
"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-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-script-launcher": "~0.1.0",
|
||||
"karma": "0.11.12",
|
||||
"karma-jasmine": "0.1.5",
|
||||
"karma-chrome-launcher": "0.1.2",
|
||||
"karma-firefox-launcher": "0.1.3",
|
||||
"karma-ng-scenario": "0.1.0",
|
||||
"karma-junit-reporter": "0.2.1",
|
||||
"karma-sauce-launcher": "0.2.0",
|
||||
"karma-script-launcher": "0.1.0",
|
||||
"karma-browserstack-launcher": "0.0.7",
|
||||
"protractor": "~0.16.1",
|
||||
"yaml-js": "~0.0.8",
|
||||
"marked": "0.2.9",
|
||||
"rewire": "1.1.3",
|
||||
@@ -37,7 +40,8 @@
|
||||
"promises-aplus-tests": "~1.3.2",
|
||||
"grunt-shell": "~0.4.0",
|
||||
"semver": "~2.1.0",
|
||||
"lodash": "~2.1.0"
|
||||
"lodash": "~2.1.0",
|
||||
"browserstacktunnel-wrapper": "~1.1.1"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
@@ -46,6 +50,6 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"grunt-contrib-jshint": "~0.6.4"
|
||||
"grunt-contrib-jshint": "~0.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
|
||||
specs: [
|
||||
'build/docs/ptore2e/**/*.js',
|
||||
'test/e2e/docsAppE2E.js'
|
||||
],
|
||||
|
||||
capabilities: {
|
||||
'browserName': 'chrome'
|
||||
},
|
||||
|
||||
baseUrl: 'http://localhost:8000/build/docs/',
|
||||
|
||||
framework: 'jasmine',
|
||||
|
||||
jasmineNodeOpts: {
|
||||
defaultTimeoutInterval: 30000
|
||||
}
|
||||
};
|
||||
@@ -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"
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating angular-phonecat repo from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update angular-phonecat ###"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
BUILD_DIR=$(resolveDir ../../build)
|
||||
REPO_DIR=$TMP_DIR/angular-phonecat
|
||||
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
|
||||
}
|
||||
|
||||
function prepare {
|
||||
echo "-- Cloning angular-phonecat"
|
||||
git clone git@github.com:angular/angular-phonecat.git $REPO_DIR
|
||||
|
||||
#
|
||||
# copy the files from the build
|
||||
#
|
||||
echo "-- Updating angular-phonecat"
|
||||
cd $REPO_DIR
|
||||
./scripts/private/update-angular.sh $BUILD_DIR
|
||||
|
||||
# Test
|
||||
if [[ $NO_TEST != "true" ]]; then
|
||||
./scripts/private/test-all.sh
|
||||
fi
|
||||
|
||||
# Generate demo
|
||||
./scripts/private/snapshot-web.sh
|
||||
git checkout gh-pages
|
||||
git pull
|
||||
rm -r step*
|
||||
mv angular-phonecat-snapshots-web/step* .
|
||||
git add step*
|
||||
git commit -am "Angular $NEW_VERSION release"
|
||||
}
|
||||
|
||||
function publish {
|
||||
cd $REPO_DIR
|
||||
echo "-- Pushing angular-phonecat"
|
||||
git push origin master -f --tags
|
||||
git push origin gh-pages -f
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating angular-seed repo from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update angular-seed ###"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
BUILD_DIR=$(resolveDir ../../build)
|
||||
REPO_DIR=$TMP_DIR/angular-seed
|
||||
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
|
||||
}
|
||||
|
||||
function prepare {
|
||||
echo "-- Cloning angular-seed"
|
||||
git clone git@github.com:angular/angular-seed.git $REPO_DIR
|
||||
|
||||
#
|
||||
# copy the files from the build
|
||||
#
|
||||
echo "-- Updating angular-seed"
|
||||
cd $REPO_DIR
|
||||
./scripts/update-angular.sh $BUILD_DIR
|
||||
|
||||
# Test
|
||||
if [[ $NO_TEST != "true" ]]; then
|
||||
./scripts/test-all.sh
|
||||
fi
|
||||
}
|
||||
|
||||
function publish {
|
||||
cd $REPO_DIR
|
||||
echo "-- Pushing angular-seed"
|
||||
git push origin master
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Remove "-snapshot" from version ########"
|
||||
echo "############################################"
|
||||
|
||||
ARG_DEFS=()
|
||||
|
||||
function run {
|
||||
cd ../..
|
||||
|
||||
replaceJsonProp "package.json" "version" "(.*)-snapshot" "\2"
|
||||
VERSION=$(readJsonProp "package.json" "version")
|
||||
|
||||
git add package.json
|
||||
git commit -m "chore(release): cut v$VERSION release"
|
||||
git tag -m "v$VERSION" v$VERSION
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Increment version, add "-snapshot" and set version name ##"
|
||||
echo "############################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--next-version-type=(patch|minor|major)"
|
||||
"--next-version-name=(.+)"
|
||||
)
|
||||
|
||||
function run {
|
||||
cd ../..
|
||||
|
||||
grunt bump:$NEXT_VERSION_TYPE
|
||||
NEXT_VERSION=$(readJsonProp "package.json" "version")
|
||||
replaceJsonProp "package.json" "version" "(.*)" "\2-snapshot"
|
||||
replaceJsonProp "package.json" "codename" ".*" "$NEXT_VERSION_NAME"
|
||||
|
||||
git add package.json
|
||||
git commit -m "chore(release): start v$NEXT_VERSION ($NEXT_VERSION)"
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script for updating cdnVersion of angular.js
|
||||
|
||||
echo "###################################"
|
||||
echo "## Update angular.js cdnVersion ###"
|
||||
echo "###################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--cdn-version=(.*)"
|
||||
"--action=(prepare|publish)"
|
||||
)
|
||||
|
||||
function init {
|
||||
cd ../..
|
||||
}
|
||||
|
||||
function prepare {
|
||||
replaceJsonProp "package.json" "cdnVersion" "(.*)" "$CDN_VERSION"
|
||||
git add package.json
|
||||
git commit -m "chore(release): update cdn version"
|
||||
}
|
||||
|
||||
function publish {
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
# push the commits to github
|
||||
git push origin $BRANCH
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating angular.js repo from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update angular.js ###"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
"--next-version-type=(patch|minor|major)"
|
||||
"--next-version-name=(.+)"
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
cd ../..
|
||||
}
|
||||
|
||||
function prepare() {
|
||||
./scripts/angular.js/finalize-version.sh
|
||||
|
||||
# Build
|
||||
if [[ $NO_TEST == "true" ]]; then
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
else
|
||||
./jenkins_build.sh
|
||||
fi
|
||||
|
||||
./scripts/angular.js/initialize-new-version.sh --next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
|
||||
}
|
||||
|
||||
function publish() {
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
# push the commits to github
|
||||
git push origin $BRANCH
|
||||
# push the release tag
|
||||
git push origin v`cat build/version.txt`
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# Script for updating angularjs.org repo
|
||||
|
||||
echo "#################################"
|
||||
echo "##### Update angularjs.org ######"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
"--cdn-version=(.*)"
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
REPO_DIR=$TMP_DIR/angularjs.org
|
||||
}
|
||||
|
||||
function prepare {
|
||||
echo "-- Cloning angularjs.org"
|
||||
git clone git@github.com:angular/angularjs.org.git $REPO_DIR
|
||||
|
||||
#
|
||||
# update files
|
||||
#
|
||||
echo "-- Updating angularjs.org"
|
||||
cd $REPO_DIR
|
||||
VERSION_REGEX="[a-z0-9\-\.\+]+"
|
||||
|
||||
replaceInFile "index.html" "(ajax\/libs\/angularjs\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "index.html" "(<span class=\"version\">[^<]*<span>)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "index.html" "(code.angularjs.org\/)$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
|
||||
replaceInFile "js/homepage.js" "($scope.CURRENT_STABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
replaceInFile "js/homepage.js" "($scope.CURRENT_UNSTABLE_VERSION[ ]*=[ ]*')$VERSION_REGEX" "\1$CDN_VERSION"
|
||||
|
||||
git add index.html
|
||||
git add js/homepage.js
|
||||
git commit -m "update(version): update angular version to $CDN_VERSION"
|
||||
}
|
||||
|
||||
function publish {
|
||||
cd $REPO_DIR
|
||||
echo "-- Pushing angularjs.org"
|
||||
git push origin master
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating the Angular bower repos from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
BUILD_DIR=$(resolveDir ../../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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function prepare {
|
||||
#
|
||||
# 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
|
||||
replaceJsonProp "bower.json" "version" ".*" "$NEW_VERSION"
|
||||
replaceJsonProp "bower.json" "angular.*" ".*" "$NEW_VERSION"
|
||||
|
||||
git add -A
|
||||
|
||||
echo "-- Committing and tagging bower-$repo"
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git tag v$NEW_VERSION
|
||||
cd $SCRIPT_DIR
|
||||
done
|
||||
}
|
||||
|
||||
function publish {
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Pushing bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
cd $SCRIPT_DIR
|
||||
done
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script for updating code.angularjs.org repo from current local build.
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--action=(prepare|publish)"
|
||||
)
|
||||
|
||||
function init {
|
||||
TMP_DIR=$(resolveDir ../../tmp)
|
||||
BUILD_DIR=$(resolveDir ../../build)
|
||||
REPO_DIR=$TMP_DIR/code.angularjs.org
|
||||
NEW_VERSION=$(cat $BUILD_DIR/version.txt)
|
||||
if [[ "$NEW_VERSION" =~ sha ]]; then
|
||||
IS_SNAPSHOT_BUILD=true
|
||||
else
|
||||
IS_SNAPSHOT_BUILD=
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare {
|
||||
if [[ $IS_SNAPSHOT_BUILD ]]; then
|
||||
# nothing to prepare for snapshot builds as
|
||||
# code.angularjs.org will fetch the current snapshot from
|
||||
# the build server during publish
|
||||
exit 0
|
||||
fi
|
||||
|
||||
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
|
||||
#
|
||||
echo "-- Committing code.angularjs.org"
|
||||
cd $REPO_DIR
|
||||
git add -A
|
||||
git commit -m "v$NEW_VERSION"
|
||||
}
|
||||
|
||||
function publish {
|
||||
if [[ $IS_SNAPSHOT_BUILD ]]; then
|
||||
echo "-- Updating snapshot version"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
cd $REPO_DIR
|
||||
echo "-- Pushing code.angularjs.org"
|
||||
git push origin master
|
||||
|
||||
echo "-- Refreshing code.angularjs.org"
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
VERBOSE=false
|
||||
fi
|
||||
VERBOSE_ARG="--verbose=$VERBOSE"
|
||||
}
|
||||
|
||||
function build {
|
||||
cd ../..
|
||||
|
||||
if [[ $NO_TEST == "true" ]]; then
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
else
|
||||
./jenkins_build.sh
|
||||
fi
|
||||
|
||||
cd $SCRIPT_DIR
|
||||
}
|
||||
|
||||
function phase {
|
||||
ACTION_ARG="--action=$1"
|
||||
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
}
|
||||
|
||||
function run {
|
||||
build
|
||||
|
||||
# First prepare all scripts (build, test, commit, tag, ...),
|
||||
# so we are sure everything is all right
|
||||
phase prepare
|
||||
# only then publish to github
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
|
||||
ARG_DEFS=(
|
||||
# require the git dryrun flag so the script can't be run without
|
||||
# thinking about this!
|
||||
"--git-push-dryrun=(true|false)"
|
||||
"--cdn-version=(.*)"
|
||||
)
|
||||
|
||||
function init {
|
||||
NG_ARGS=("$@")
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
VERBOSE=false
|
||||
fi
|
||||
VERBOSE_ARG="--verbose=$VERBOSE"
|
||||
}
|
||||
|
||||
function phase {
|
||||
ACTION_ARG="--action=$1"
|
||||
CDN_VERSION_ARG="--cdn-version=$CDN_VERSION"
|
||||
./scripts/angular.js/publish-cdn-version.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
|
||||
./scripts/angularjs.org/publish.sh $ACTION_ARG $CDN_VERSION_ARG $VERBOSE_ARG
|
||||
}
|
||||
|
||||
function checkCdn {
|
||||
STATUS=$(curl http://ajax.googleapis.com/ajax/libs/angularjs/$CDN_VERSION/angular.min.js --write-out '%{http_code}' -o /dev/null -silent)
|
||||
if [[ $STATUS != 200 ]]; then
|
||||
echo "Could not find release $CDN_VERSION on CDN"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function run {
|
||||
cd ../..
|
||||
checkCdn
|
||||
|
||||
phase prepare
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Cut release ################"
|
||||
echo "#################################"
|
||||
|
||||
ARG_DEFS=(
|
||||
"--next-version-type=(patch|minor|major)"
|
||||
"--next-version-name=(.+)"
|
||||
# require the git dryrun flag so the script can't be run without
|
||||
# thinking about this!
|
||||
"--git-push-dryrun=(true|false)"
|
||||
"[--no-test=(true|false)]"
|
||||
)
|
||||
|
||||
function init {
|
||||
NG_ARGS=("$@")
|
||||
if [[ ! $VERBOSE ]]; then
|
||||
VERBOSE=false
|
||||
fi
|
||||
if [[ ! $NO_TEST ]]; then
|
||||
NO_TEST=false
|
||||
fi
|
||||
VERBOSE_ARG="--verbose=$VERBOSE"
|
||||
NO_TEST_ARG="--no_test=$NO_TEST"
|
||||
}
|
||||
|
||||
function phase {
|
||||
ACTION_ARG="--action=$1"
|
||||
../angular.js/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG \
|
||||
--next-version-type=$NEXT_VERSION_TYPE --next-version-name=$NEXT_VERSION_NAME
|
||||
../code.angularjs.org/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
../bower/publish.sh $ACTION_ARG $VERBOSE_ARG
|
||||
../angular-seed/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
|
||||
../angular-phonecat/publish.sh $ACTION_ARG $VERBOSE_ARG $NO_TEST_ARG
|
||||
}
|
||||
|
||||
function run {
|
||||
# First prepare all scripts (build, test, commit, tag, ...),
|
||||
# so we are sure everything is all right
|
||||
phase prepare
|
||||
# only then publish to github
|
||||
phase publish
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils.inc
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/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
|
||||
grunt test:protractor --sauceUser $SAUCE_USERNAME \
|
||||
--sauceKey $SAUCE_ACCESS_KEY \
|
||||
--capabilities.tunnel-identifier=$TRAVIS_JOB_NUMBER \
|
||||
--capabilities.build=$TRAVIS_BUILD_NUMBER
|
||||
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
|
||||
@@ -0,0 +1,279 @@
|
||||
# This file provides:
|
||||
# - a default control flow
|
||||
# * initializes the environment
|
||||
# * able to mock "git push" in your script and in all sub scripts
|
||||
# * call a function in your script based on the arguments
|
||||
# - named argument parsing and automatic generation of the "usage" for your script
|
||||
# - intercepting "git push" in your script and all sub scripts
|
||||
# - utility functions
|
||||
#
|
||||
# Usage:
|
||||
# - define the variable ARGS_DEF (see below) with the arguments for your script
|
||||
# - include this file using `source utils.inc` at the end of your script.
|
||||
#
|
||||
# Default control flow:
|
||||
# 0. Set the current directory to the directory of the script. By this
|
||||
# the script can be called from anywhere.
|
||||
# 1. Parse the named arguments
|
||||
# 2. If the parameter "git_push_dryrun" is set, all calls the `git push` in this script
|
||||
# or in child scripts will be intercepted so that the `--dry-run` and `--porcelain` is added
|
||||
# to show what the push would do but not actually do it.
|
||||
# 3. If the parameter "verbose" is set, the `-x` flag will be set in bash.
|
||||
# 4. The function "init" will be called if it exists
|
||||
# 5. If the parameter "action" is set, it will call the function with the name of that parameter.
|
||||
# Otherwise the function "run" will be called.
|
||||
#
|
||||
# Named Argument Parsing:
|
||||
# - The variable ARGS_DEF defines the valid command arguments
|
||||
# * Required args syntax: --paramName=paramRegex
|
||||
# * Optional args syntax: [--paramName=paramRegex]
|
||||
# * e.g. ARG_DEFS=("--required_param=(.+)" "[--optional_param=(.+)]")
|
||||
# - Checks that:
|
||||
# * all arguments match to an entry in ARGS_DEF
|
||||
# * all required arguments are present
|
||||
# * all arguments match their regex
|
||||
# - Afterwards, every paramter value will be stored in a variable
|
||||
# with the name of the parameter in upper case (with dash converted to underscore).
|
||||
#
|
||||
# Special arguments that are always available:
|
||||
# - "--action=.*": This parameter will be used to dispatch to a function with that name when the
|
||||
# script is started
|
||||
# - "--git_push_dryrun=true": This will intercept all calls to `git push` in this script
|
||||
# or in child scripts so that the `--dry-run` and `--porcelain` is added
|
||||
# to show what the push would do but not actually do it.
|
||||
# - "--verbose=true": This will set the `-x` flag in bash so that all calls will be logged
|
||||
#
|
||||
# Utility functions:
|
||||
# - readJsonProp
|
||||
# - replaceJsonProp
|
||||
# - resolveDir
|
||||
# - getVar
|
||||
# - serVar
|
||||
# - isFunction
|
||||
|
||||
# always stop on errors
|
||||
set -e
|
||||
|
||||
function usage {
|
||||
echo "Usage: ${0} ${ARG_DEFS[@]}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
function parseArgs {
|
||||
local REQUIRED_ARG_NAMES=()
|
||||
|
||||
# -- helper functions
|
||||
function varName {
|
||||
# everything to upper case and dash to underscore
|
||||
echo ${1//-/_} | tr '[:lower:]' '[:upper:]'
|
||||
}
|
||||
|
||||
function readArgDefs {
|
||||
local ARG_DEF
|
||||
local AD_OPTIONAL
|
||||
local AD_NAME
|
||||
local AD_RE
|
||||
|
||||
# -- helper functions
|
||||
function parseArgDef {
|
||||
local ARG_DEF_REGEX="(\[?)--([^=]+)=(.*)"
|
||||
if [[ ! $1 =~ $ARG_DEF_REGEX ]]; then
|
||||
echo "Internal error: arg def has wrong format: $ARG_DEF"
|
||||
exit 1
|
||||
fi
|
||||
AD_OPTIONAL="${BASH_REMATCH[1]}"
|
||||
AD_NAME="${BASH_REMATCH[2]}"
|
||||
AD_RE="${BASH_REMATCH[3]}"
|
||||
if [[ $AD_OPTIONAL ]]; then
|
||||
# Remove last bracket for optional args.
|
||||
# Can't put this into the ARG_DEF_REGEX somehow...
|
||||
AD_RE=${AD_RE%?}
|
||||
fi
|
||||
}
|
||||
|
||||
# -- run
|
||||
for ARG_DEF in "${ARG_DEFS[@]}"
|
||||
do
|
||||
parseArgDef $ARG_DEF
|
||||
|
||||
local AD_NAME_UPPER=$(varName $AD_NAME)
|
||||
setVar "${AD_NAME_UPPER}_OPTIONAL" "$AD_OPTIONAL"
|
||||
setVar "${AD_NAME_UPPER}_RE" "$AD_RE"
|
||||
if [[ ! $AD_OPTIONAL ]]; then
|
||||
REQUIRED_ARG_NAMES+=($AD_NAME)
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function readAndValidateArgs {
|
||||
local ARG_NAME
|
||||
local ARG_VALUE
|
||||
local ARG_NAME_UPPER
|
||||
|
||||
# -- helper functions
|
||||
function parseArg {
|
||||
local ARG_REGEX="--([^=]+)=?(.*)"
|
||||
|
||||
if [[ ! $1 =~ $ARG_REGEX ]]; then
|
||||
echo "Can't parse argument $i"
|
||||
usage
|
||||
fi
|
||||
|
||||
ARG_NAME="${BASH_REMATCH[1]}"
|
||||
ARG_VALUE="${BASH_REMATCH[2]}"
|
||||
ARG_NAME_UPPER=$(varName $ARG_NAME)
|
||||
}
|
||||
|
||||
function validateArg {
|
||||
local AD_RE=$(getVar ${ARG_NAME_UPPER}_RE)
|
||||
|
||||
if [[ ! $AD_RE ]]; then
|
||||
echo "Unknown option: $ARG_NAME"
|
||||
usage
|
||||
fi
|
||||
|
||||
if [[ ! $ARG_VALUE =~ ^${AD_RE}$ ]]; then
|
||||
echo "Wrong format: $ARG_NAME"
|
||||
usage;
|
||||
fi
|
||||
|
||||
# validate that the "action" option points to a valid function
|
||||
if [[ $ARG_NAME == "action" ]] && ! isFunction $ARG_VALUE; then
|
||||
echo "No action $ARG_VALUE defined in this script"
|
||||
usage;
|
||||
fi
|
||||
}
|
||||
|
||||
# -- run
|
||||
for i in "$@"
|
||||
do
|
||||
parseArg $i
|
||||
validateArg
|
||||
setVar "${ARG_NAME_UPPER}" "$ARG_VALUE"
|
||||
done
|
||||
}
|
||||
|
||||
function checkMissingArgs {
|
||||
local ARG_NAME
|
||||
for ARG_NAME in "${REQUIRED_ARG_NAMES[@]}"
|
||||
do
|
||||
ARG_VALUE=$(getVar $(varName $ARG_NAME))
|
||||
|
||||
if [[ ! $ARG_VALUE ]]; then
|
||||
echo "Missing: $ARG_NAME"
|
||||
usage;
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# -- run
|
||||
readArgDefs
|
||||
readAndValidateArgs "$@"
|
||||
checkMissingArgs
|
||||
|
||||
}
|
||||
|
||||
# getVar(varName)
|
||||
function getVar {
|
||||
echo ${!1}
|
||||
}
|
||||
|
||||
# setVar(varName, varValue)
|
||||
function setVar {
|
||||
eval "$1=\"$2\""
|
||||
}
|
||||
|
||||
# isFunction(name)
|
||||
# - to be used in an if, so return 0 if successful and 1 if not!
|
||||
function isFunction {
|
||||
if [[ $(type -t $1) == "function" ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# readJsonProp(jsonFile, property)
|
||||
# - restriction: property needs to be on an own line!
|
||||
function readJsonProp {
|
||||
echo $(sed -En 's/.*"'$2'"[ ]*:[ ]*"(.*)".*/\1/p' $1)
|
||||
}
|
||||
|
||||
# replaceJsonProp(jsonFile, propertyRegex, valueRegex, replacePattern)
|
||||
# - note: propertyRegex will be automatically placed into a
|
||||
# capturing group! -> all other groups start at index 2!
|
||||
function replaceJsonProp {
|
||||
replaceInFile $1 '"('$2')"[ ]*:[ ]*"'$3'"' '"\1": "'$4'"'
|
||||
}
|
||||
|
||||
# replaceInFile(file, findPattern, replacePattern)
|
||||
function replaceInFile {
|
||||
sed -i .tmp -E "s/$2/$3/" $1
|
||||
rm $1.tmp
|
||||
}
|
||||
|
||||
# resolveDir(relativeDir)
|
||||
# - resolves a directory relative to the current script
|
||||
function resolveDir {
|
||||
echo $(cd $SCRIPT_DIR; cd $1; pwd)
|
||||
}
|
||||
|
||||
function git_push_dryrun_proxy {
|
||||
echo "## git push dryrun proxy enabled!"
|
||||
export ORIGIN_GIT=$(which git)
|
||||
|
||||
function git {
|
||||
local ARGS=("$@")
|
||||
local RC
|
||||
if [[ $1 == "push" ]]; then
|
||||
ARGS+=("--dry-run" "--porcelain")
|
||||
echo "####### START GIT PUSH DRYRUN #######"
|
||||
echo "${ARGS[@]}"
|
||||
fi
|
||||
if [[ $1 == "commit" ]]; then
|
||||
echo "${ARGS[@]}"
|
||||
fi
|
||||
$ORIGIN_GIT "${ARGS[@]}"
|
||||
RC=$?
|
||||
if [[ $1 == "push" ]]; then
|
||||
echo "####### END GIT PUSH DRYRUN #######"
|
||||
fi
|
||||
return $RC
|
||||
}
|
||||
|
||||
export -f git
|
||||
}
|
||||
|
||||
function main {
|
||||
# normalize the working dir to the directory of the script
|
||||
cd $(dirname $0);SCRIPT_DIR=$(pwd)
|
||||
|
||||
ARG_DEFS+=("[--git-push-dryrun=(true|false)]" "[--verbose=(true|false)]")
|
||||
parseArgs "$@"
|
||||
|
||||
# --git_push_dryrun argument
|
||||
if [[ $GIT_PUSH_DRYRUN == "true" ]]; then
|
||||
git_push_dryrun_proxy
|
||||
fi
|
||||
|
||||
# --verbose argument
|
||||
if [[ $VERBOSE == "true" ]]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
if isFunction init; then
|
||||
init "$@"
|
||||
fi
|
||||
|
||||
# jump to the function denoted by the --action argument,
|
||||
# otherwise call the "run" function
|
||||
if [[ $ACTION ]]; then
|
||||
$ACTION "$@"
|
||||
else
|
||||
run "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
main "$@"
|
||||
+33
-27
@@ -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;
|
||||
@@ -1330,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) {
|
||||
|
||||
+34
-22
@@ -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>
|
||||
@@ -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,
|
||||
|
||||
+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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
/**
|
||||
|
||||
+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) {
|
||||
|
||||
+56
-59
@@ -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;
|
||||
@@ -730,16 +729,7 @@ function $CompileProvider($provide) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
this[key] = value = $$sanitizeUri(value, key === 'src');
|
||||
}
|
||||
|
||||
if (writeAttr !== false) {
|
||||
@@ -828,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
|
||||
@@ -842,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;
|
||||
@@ -875,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.
|
||||
@@ -895,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;
|
||||
}
|
||||
@@ -916,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++) {
|
||||
@@ -931,7 +927,6 @@ function $CompileProvider($provide) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new();
|
||||
$node.data('$scope', childScope);
|
||||
safeAddClass($node, 'ng-scope');
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
@@ -941,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);
|
||||
@@ -1014,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
|
||||
}
|
||||
@@ -1229,7 +1222,7 @@ function $CompileProvider($provide) {
|
||||
});
|
||||
} else {
|
||||
$template = jqLite(jqLiteClone(compileNode)).contents();
|
||||
$compileNode.html(''); // clear contents
|
||||
$compileNode.empty(); // clear contents
|
||||
childTranscludeFn = compile($template, transcludeFn);
|
||||
}
|
||||
}
|
||||
@@ -1410,7 +1403,7 @@ function $CompileProvider($provide) {
|
||||
optional = (match[2] == '?'),
|
||||
mode = match[1], // @, =, or &
|
||||
lastValue,
|
||||
parentGet, parentSet;
|
||||
parentGet, parentSet, compare;
|
||||
|
||||
isolateScope.$$isolateBindings[scopeName] = mode + attrName;
|
||||
|
||||
@@ -1433,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);
|
||||
@@ -1443,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 '&':
|
||||
@@ -1657,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) {
|
||||
@@ -1960,7 +1957,7 @@ function directiveNormalize(name) {
|
||||
*
|
||||
*
|
||||
* @param {string} name Normalized element attribute name of the property to modify. The name is
|
||||
* revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
|
||||
* reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
|
||||
* property to the original name.
|
||||
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
|
||||
*/
|
||||
|
||||
+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
|
||||
*
|
||||
@@ -180,6 +184,7 @@
|
||||
* @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
|
||||
@@ -214,6 +219,7 @@
|
||||
* @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
|
||||
@@ -223,7 +229,6 @@
|
||||
* 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>
|
||||
@@ -249,6 +254,7 @@
|
||||
* @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
|
||||
@@ -258,6 +264,7 @@
|
||||
* 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>
|
||||
@@ -285,6 +292,7 @@
|
||||
* @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
|
||||
@@ -294,8 +302,6 @@
|
||||
* 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>
|
||||
@@ -330,12 +336,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
|
||||
ngAttributeAliasDirectives[normalized] = function() {
|
||||
return {
|
||||
priority: 100,
|
||||
compile: function() {
|
||||
return function(scope, element, attr) {
|
||||
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
||||
attr.$set(attrName, !!value);
|
||||
});
|
||||
};
|
||||
link: function(scope, element, attr) {
|
||||
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
|
||||
attr.$set(attrName, !!value);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
@@ -236,10 +249,10 @@ function FormController(element, attrs) {
|
||||
*
|
||||
*
|
||||
* # CSS classes
|
||||
* - `ng-valid` Is set if the form is valid.
|
||||
* - `ng-invalid` Is set if the form is invalid.
|
||||
* - `ng-pristine` Is set if the form is pristine.
|
||||
* - `ng-dirty` Is set if the form is dirty.
|
||||
* - `ng-valid` is set if the form is valid.
|
||||
* - `ng-invalid` is set if the form is invalid.
|
||||
* - `ng-pristine` is set if the form is pristine.
|
||||
* - `ng-dirty` is set if the form is dirty.
|
||||
*
|
||||
*
|
||||
* # Submitting a form and preventing the default action
|
||||
|
||||
+39
-109
@@ -390,20 +390,28 @@ var inputType = {
|
||||
'reset': noop
|
||||
};
|
||||
|
||||
// A helper function to call $setValidity and return the value / undefined,
|
||||
// a pattern that is repeated a lot in the input validation logic.
|
||||
function validate(ctrl, validatorName, validity, value){
|
||||
ctrl.$setValidity(validatorName, validity);
|
||||
return validity ? value : undefined;
|
||||
}
|
||||
|
||||
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
|
||||
var composing = false;
|
||||
if (!$sniffer.android) {
|
||||
var composing = false;
|
||||
|
||||
element.on('compositionstart', function() {
|
||||
composing = true;
|
||||
});
|
||||
element.on('compositionstart', function(data) {
|
||||
composing = true;
|
||||
});
|
||||
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
element.on('compositionend', function() {
|
||||
composing = false;
|
||||
});
|
||||
}
|
||||
|
||||
var listener = function() {
|
||||
if (composing) return;
|
||||
@@ -417,9 +425,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);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -449,15 +461,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);
|
||||
@@ -468,22 +480,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
patternValidator,
|
||||
match;
|
||||
|
||||
var validate = function(regexp, value) {
|
||||
if (ctrl.$isEmpty(value) || regexp.test(value)) {
|
||||
ctrl.$setValidity('pattern', true);
|
||||
return value;
|
||||
} else {
|
||||
ctrl.$setValidity('pattern', false);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
if (pattern) {
|
||||
var validateRegex = function(regexp, value) {
|
||||
return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
|
||||
};
|
||||
match = pattern.match(/^\/(.*)\/([gim]*)$/);
|
||||
if (match) {
|
||||
pattern = new RegExp(match[1], match[2]);
|
||||
patternValidator = function(value) {
|
||||
return validate(pattern, value);
|
||||
return validateRegex(pattern, value);
|
||||
};
|
||||
} else {
|
||||
patternValidator = function(value) {
|
||||
@@ -494,7 +499,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
|
||||
patternObj, startingTag(element));
|
||||
}
|
||||
return validate(patternObj, value);
|
||||
return validateRegex(patternObj, value);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -506,13 +511,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
if (attr.ngMinlength) {
|
||||
var minlength = int(attr.ngMinlength);
|
||||
var minLengthValidator = function(value) {
|
||||
if (!ctrl.$isEmpty(value) && value.length < minlength) {
|
||||
ctrl.$setValidity('minlength', false);
|
||||
return undefined;
|
||||
} else {
|
||||
ctrl.$setValidity('minlength', true);
|
||||
return value;
|
||||
}
|
||||
return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
|
||||
};
|
||||
|
||||
ctrl.$parsers.push(minLengthValidator);
|
||||
@@ -523,13 +522,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
if (attr.ngMaxlength) {
|
||||
var maxlength = int(attr.ngMaxlength);
|
||||
var maxLengthValidator = function(value) {
|
||||
if (!ctrl.$isEmpty(value) && value.length > maxlength) {
|
||||
ctrl.$setValidity('maxlength', false);
|
||||
return undefined;
|
||||
} else {
|
||||
ctrl.$setValidity('maxlength', true);
|
||||
return value;
|
||||
}
|
||||
return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
|
||||
};
|
||||
|
||||
ctrl.$parsers.push(maxLengthValidator);
|
||||
@@ -558,13 +551,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
if (attr.min) {
|
||||
var minValidator = function(value) {
|
||||
var min = parseFloat(attr.min);
|
||||
if (!ctrl.$isEmpty(value) && value < min) {
|
||||
ctrl.$setValidity('min', false);
|
||||
return undefined;
|
||||
} else {
|
||||
ctrl.$setValidity('min', true);
|
||||
return value;
|
||||
}
|
||||
return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
|
||||
};
|
||||
|
||||
ctrl.$parsers.push(minValidator);
|
||||
@@ -574,13 +561,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
if (attr.max) {
|
||||
var maxValidator = function(value) {
|
||||
var max = parseFloat(attr.max);
|
||||
if (!ctrl.$isEmpty(value) && value > max) {
|
||||
ctrl.$setValidity('max', false);
|
||||
return undefined;
|
||||
} else {
|
||||
ctrl.$setValidity('max', true);
|
||||
return value;
|
||||
}
|
||||
return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
|
||||
};
|
||||
|
||||
ctrl.$parsers.push(maxValidator);
|
||||
@@ -588,14 +569,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
}
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
|
||||
if (ctrl.$isEmpty(value) || isNumber(value)) {
|
||||
ctrl.$setValidity('number', true);
|
||||
return value;
|
||||
} else {
|
||||
ctrl.$setValidity('number', false);
|
||||
return undefined;
|
||||
}
|
||||
return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -603,13 +577,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
||||
|
||||
var urlValidator = function(value) {
|
||||
if (ctrl.$isEmpty(value) || URL_REGEXP.test(value)) {
|
||||
ctrl.$setValidity('url', true);
|
||||
return value;
|
||||
} else {
|
||||
ctrl.$setValidity('url', false);
|
||||
return undefined;
|
||||
}
|
||||
return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(urlValidator);
|
||||
@@ -620,13 +588,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
||||
|
||||
var emailValidator = function(value) {
|
||||
if (ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value)) {
|
||||
ctrl.$setValidity('email', true);
|
||||
return value;
|
||||
} else {
|
||||
ctrl.$setValidity('email', false);
|
||||
return undefined;
|
||||
}
|
||||
return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(emailValidator);
|
||||
@@ -951,39 +913,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',
|
||||
@@ -1130,7 +1059,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`.
|
||||
@@ -1187,6 +1116,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
ctrl.$render();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}];
|
||||
|
||||
@@ -1463,7 +1394,6 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
||||
id="{{name}}"
|
||||
name="favorite">
|
||||
</label>
|
||||
</span>
|
||||
<div>You chose {{my.favorite}}</div>
|
||||
</form>
|
||||
</doc:source>
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
<doc:protractor>
|
||||
it('should check ng-click', function() {
|
||||
expect(binding('count')).toBe('0');
|
||||
element('.doc-example-live :button').click();
|
||||
expect(binding('count')).toBe('1');
|
||||
expect(element(by.binding('count')).getText()).toMatch('0');
|
||||
element(by.css('.doc-example-live button')).click();
|
||||
expect(element(by.binding('count')).getText()).toMatch('1');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:protractor>
|
||||
</doc:example>
|
||||
*/
|
||||
/*
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user