Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
||||
|
||||
+191
@@ -1,3 +1,194 @@
|
||||
<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)
|
||||
|
||||
|
||||
+108
-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,4 @@ 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
|
||||
|
||||
+15
-12
@@ -4,6 +4,7 @@ var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
grunt.loadNpmTasks('grunt-bump');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
@@ -106,45 +107,38 @@ module.exports = function(grunt) {
|
||||
},
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: true,
|
||||
},
|
||||
ng: {
|
||||
files: { src: files['angularSrc'] },
|
||||
options: { jshintrc: 'src/.jshintrc' }
|
||||
},
|
||||
ngAnimate: {
|
||||
files: { src: 'src/ngAnimate/**/*.js' },
|
||||
options: { jshintrc: 'src/ngAnimate/.jshintrc' }
|
||||
},
|
||||
ngCookies: {
|
||||
files: { src: 'src/ngCookies/**/*.js' },
|
||||
options: { jshintrc: 'src/ngCookies/.jshintrc' }
|
||||
},
|
||||
ngLocale: {
|
||||
files: { src: 'src/ngLocale/**/*.js' },
|
||||
options: { jshintrc: 'src/ngLocale/.jshintrc' }
|
||||
},
|
||||
ngMock: {
|
||||
files: { src: 'src/ngMock/**/*.js' },
|
||||
options: { jshintrc: 'src/ngMock/.jshintrc' }
|
||||
},
|
||||
ngResource: {
|
||||
files: { src: 'src/ngResource/**/*.js' },
|
||||
options: { jshintrc: 'src/ngResource/.jshintrc' }
|
||||
},
|
||||
ngRoute: {
|
||||
files: { src: 'src/ngRoute/**/*.js' },
|
||||
options: { jshintrc: 'src/ngRoute/.jshintrc' }
|
||||
},
|
||||
ngSanitize: {
|
||||
files: { src: 'src/ngSanitize/**/*.js' },
|
||||
options: { jshintrc: 'src/ngSanitize/.jshintrc' }
|
||||
},
|
||||
ngScenario: {
|
||||
files: { src: 'src/ngScenario/**/*.js' },
|
||||
options: { jshintrc: 'src/ngScenario/.jshintrc' }
|
||||
},
|
||||
ngTouch: {
|
||||
files: { src: 'src/ngTouch/**/*.js' },
|
||||
options: { jshintrc: 'src/ngTouch/.jshintrc' }
|
||||
}
|
||||
},
|
||||
|
||||
@@ -178,7 +172,7 @@ module.exports = function(grunt) {
|
||||
},
|
||||
mocks: {
|
||||
dest: 'build/angular-mocks.js',
|
||||
src: files['angularModules']['ngMock'],
|
||||
src: util.wrap(files['angularModules']['ngMock'], 'module'),
|
||||
strict: false
|
||||
},
|
||||
sanitize: {
|
||||
@@ -275,6 +269,15 @@ module.exports = function(grunt) {
|
||||
write: {
|
||||
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
|
||||
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
|
||||
},
|
||||
|
||||
bump: {
|
||||
options: {
|
||||
files: ['package.json'],
|
||||
commit: false,
|
||||
createTag: false,
|
||||
push: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -294,6 +297,6 @@ module.exports = function(grunt) {
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['bower','clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('package-without-bower', ['clean', 'buildall', 'minall', 'collect-errors', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint', 'test:docgen']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict', 'jshint']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
# 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
|
||||
|
||||
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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -115,9 +115,14 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
|
||||
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
Similarly, control is an instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
The control instance can similarly be published into the form instance using the `name` attribute.
|
||||
This implies that the internal state of both the form and the control is available for binding in the view using the standard binding primitives.
|
||||
|
||||
Similarly, an input control that has the {@link api/ng.directive:ngModel} directive holds an
|
||||
instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
Such a control instance can be published as a property of the form instance using the `name` attribute
|
||||
on the input control. The name attribute specifies the name of the property on the form instance.
|
||||
|
||||
This implies that the internal state of both the form and the control is available for binding in
|
||||
the view using the standard binding primitives.
|
||||
|
||||
This allows us to extend the above example with these features:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ to various URLs and verify that the correct view was rendered.
|
||||
<pre>
|
||||
...
|
||||
it('should redirect index.html to index.html#/phones', function() {
|
||||
browser().navigateTo('../../app/index.html');
|
||||
browser().navigateTo('app/index.html');
|
||||
expect(browser().location().url()).toBe('/phones');
|
||||
});
|
||||
...
|
||||
@@ -266,7 +266,7 @@ to various URLs and verify that the correct view was rendered.
|
||||
describe('Phone detail view', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
browser().navigateTo('../../app/index.html#/phones/nexus-s');
|
||||
browser().navigateTo('app/index.html#/phones/nexus-s');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ Angular's server}.
|
||||
|
||||
<button ng-click="hello('Elmo')">Hello</button>
|
||||
|
||||
to the `phone-details.html` template.
|
||||
to the `phone-detail.html` template.
|
||||
|
||||
<div style="display: none">
|
||||
TODO!
|
||||
|
||||
@@ -11,7 +11,7 @@ In this step, you will improve the way our app fetches data.
|
||||
<div doc-tutorial-reset="11"></div>
|
||||
|
||||
|
||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||
The next improvement we will make to our app is to define a custom service that represents a {@link
|
||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||
api/ng.$http $http} API, HTTP methods and URLs.
|
||||
@@ -185,7 +185,7 @@ describe('PhoneCat controllers', function() {
|
||||
xyzPhoneData = function() {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ __`app/index.html`.__
|
||||
<pre>
|
||||
...
|
||||
<!-- jQuery is used for JavaScript animations (include this before angular.js) -->
|
||||
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
|
||||
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||
|
||||
<!-- required module to enable animation support in AngularJS -->
|
||||
<script src="lib/angular/angular-animate.js"></script>
|
||||
@@ -56,6 +56,10 @@ __`app/index.html`.__
|
||||
...
|
||||
</pre>
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
|
||||
</div>
|
||||
|
||||
Animations can now be created within the CSS code (`animations.css`) as well as the JavaScript code (`animations.js`).
|
||||
But before we start, let's create a new module which uses the ngAnimate module as a dependency just like we did before
|
||||
with `ngResource`.
|
||||
@@ -153,7 +157,7 @@ __`app/css/animations.css`__
|
||||
</pre>
|
||||
|
||||
As you can see our `phone-listing` CSS class is combined together with the animation hooks that occur when items are
|
||||
inserted info and removed from the list:
|
||||
inserted into and removed from the list:
|
||||
|
||||
* The `ng-enter` class is applied to the element when a new phone is added to the list and rendered on the page.
|
||||
* The `ng-move` class is applied when items are moved around in the list.
|
||||
@@ -383,10 +387,6 @@ isn't required to do JavaScript animations with AngularJS, but we're going to us
|
||||
your own JavaScript animation library is beyond the scope of this tutorial. For more on
|
||||
`jQuery.animate`, see the {@link http://api.jquery.com/animate/ jQuery documentation}.
|
||||
|
||||
<div class="alert alert-error">
|
||||
**Important:** Be sure to use jQuery version `1.10.x`. AngularJS does not yet support jQuery `2.x`.
|
||||
</div>
|
||||
|
||||
The `addClass` and `removeClass` callback functions are called whenever an a class is added or removed
|
||||
on the element that contains the class we registered, which is in this case `.phone`. When the `.active`
|
||||
class is added to the element (via the `ng-class` directive) the `addClass` JavaScript callback will
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
exports.appCache = appCache;
|
||||
var fs = require('q-fs');
|
||||
var fs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
function identity($) {return $;}
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ function writeTheRest(writesFuture) {
|
||||
var versions = ngdoc.ngVersions();
|
||||
var currentVersion = ngdoc.ngCurrentVersion();
|
||||
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/content/notes', 'build/docs/notes', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'directory'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'directory'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'directory'));
|
||||
|
||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ exports.collect = collect;
|
||||
|
||||
var ngdoc = require('./ngdoc.js'),
|
||||
Q = require('qq'),
|
||||
qfs = require('q-fs'),
|
||||
qfs = require('q-io/fs'),
|
||||
PATH = require('path');
|
||||
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
@@ -144,6 +144,27 @@
|
||||
.content h4,
|
||||
.content h5 {
|
||||
margin-top: 1em;
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
font-size: 36px;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.content h3 {
|
||||
font-size: 24px;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: .5em;
|
||||
}
|
||||
|
||||
.content h4 {
|
||||
font-size: 16px;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.content ul {
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
ul.parameters > li > p,
|
||||
@@ -522,6 +543,10 @@ pre ol li {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
|
||||
.definition-table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.component-heading {
|
||||
text-transform:capitalize;
|
||||
}
|
||||
|
||||
@@ -335,9 +335,8 @@
|
||||
|
||||
<div ng-hide="loading" ng-include src="currentPage.partialUrl" onload="afterPartialLoaded()" autoscroll class="content slide-reveal"></div>
|
||||
|
||||
<div id="disqus" class="disqus">
|
||||
<h2>Discussion</h2>
|
||||
<div id="disqus_thread" class="content-panel-content"></div>
|
||||
<div class="alert alert-info">
|
||||
<a href="http://blog.angularjs.org/2013/11/farewell-disqus.html">Where did Disqus go?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -365,7 +364,7 @@
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p class="pull-right"><a href="#">Back to top</a></p>
|
||||
<p class="pull-right"><a back-to-top href="#">Back to top</a></p>
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2012
|
||||
|
||||
@@ -273,10 +273,10 @@ docsApp.directive.docTutorialNav = function(templateMerge) {
|
||||
element.addClass('btn-group');
|
||||
element.addClass('tutorial-nav');
|
||||
element.append(templateMerge(
|
||||
'<li class="btn btn-primary"><a href="tutorial/{{prev}}"><i class="icon-step-backward"></i> Previous</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><i class="icon-play"></i> Live Demo</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><i class="icon-search"></i> Code Diff</a></li>\n' +
|
||||
'<li class="btn btn-primary"><a href="tutorial/{{next}}">Next <i class="icon-step-forward"></i></a></li>', props));
|
||||
'<a href="tutorial/{{prev}}"><li class="btn btn-primary"><i class="icon-step-backward"></i> Previous</li></a>\n' +
|
||||
'<a href="http://angular.github.com/angular-phonecat/step-{{seq}}/app"><li class="btn btn-primary"><i class="icon-play"></i> Live Demo</li></a>\n' +
|
||||
'<a href="https://github.com/angular/angular-phonecat/compare/step-{{diffLo}}...step-{{diffHi}}"><li class="btn btn-primary"><i class="icon-search"></i> Code Diff</li></a>\n' +
|
||||
'<a href="tutorial/{{next}}"><li class="btn btn-primary">Next <i class="icon-step-forward"></i></li></a>', props));
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -372,6 +372,21 @@ docsApp.directive.errorDisplay = ['$location', 'errorLinkFilter', function ($loc
|
||||
}];
|
||||
|
||||
|
||||
/**
|
||||
* backToTop Directive
|
||||
* @param {Function} $anchorScroll
|
||||
*
|
||||
* @description Ensure that the browser scrolls when the anchor is clicked
|
||||
*/
|
||||
docsApp.directive.backToTop = ['$anchorScroll', function($anchorScroll) {
|
||||
return function link(scope, element) {
|
||||
element.on('click', function(event) {
|
||||
scope.$apply($anchorScroll);
|
||||
});
|
||||
};
|
||||
}];
|
||||
|
||||
|
||||
docsApp.serviceFactory.angularUrls = function($document) {
|
||||
var urls = {};
|
||||
|
||||
@@ -680,7 +695,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
var currentPageId = $location.path();
|
||||
$scope.partialTitle = $scope.currentPage.shortName;
|
||||
$window._gaq.push(['_trackPageview', currentPageId]);
|
||||
loadDisqus(currentPageId);
|
||||
};
|
||||
|
||||
/** stores a cookie that is used by apache to decide which manifest ot send */
|
||||
@@ -892,29 +906,6 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
return namespace;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadDisqus(currentPageId) {
|
||||
// http://docs.disqus.com/help/2/
|
||||
window.disqus_shortname = 'angularjs-next';
|
||||
window.disqus_identifier = currentPageId;
|
||||
window.disqus_url = 'http://docs.angularjs.org' + currentPageId;
|
||||
|
||||
if ($location.host() == 'localhost') {
|
||||
return; // don't display disqus on localhost, comment this out if needed
|
||||
//window.disqus_developer = 1;
|
||||
}
|
||||
|
||||
// http://docs.disqus.com/developers/universal/
|
||||
(function() {
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = 'http://angularjs.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] ||
|
||||
document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
})();
|
||||
|
||||
angular.element(document.getElementById('disqus_thread')).html('');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
* for testability
|
||||
*/
|
||||
var pathUtils = require('path');
|
||||
var qfs = require('q-fs');
|
||||
var qfs = require('q-io/fs');
|
||||
var Q = require('qq');
|
||||
var OUTPUT_DIR = pathUtils.join('build','docs');
|
||||
var TEMPLATES_DIR = pathUtils.join('docs','src','templates');
|
||||
@@ -76,7 +76,7 @@ function symlink(from, to, type) {
|
||||
// qfs will normalize the path arguments for us here
|
||||
return qfs.exists(to).then(function(exists) {
|
||||
if (!exists) {
|
||||
return qfs.symbolicLink(to, from, type);
|
||||
return qfs.symbolicLink(to, from, type || 'file');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
|
||||
# Define reasonable set of browsers in case we are running manually from commandline
|
||||
if [[ -z "$BROWSERS" ]]
|
||||
then
|
||||
@@ -25,11 +28,12 @@ rm -f angular.js.size
|
||||
npm install --color false
|
||||
grunt ci-checks package --no-color
|
||||
|
||||
# DOCS generator unit tests #
|
||||
grunt test:docgen --no-color
|
||||
|
||||
# UNIT TESTS #
|
||||
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
# END TO END TESTS #
|
||||
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
|
||||
|
||||
|
||||
+3
-1
@@ -20,6 +20,8 @@ module.exports = function(config) {
|
||||
junitReporter: {
|
||||
outputFile: 'test_out/e2e.xml',
|
||||
suite: 'E2E'
|
||||
}
|
||||
},
|
||||
|
||||
browserNoActivityTimeout: 90000
|
||||
});
|
||||
};
|
||||
|
||||
+121
-5
@@ -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:
|
||||
@@ -49,12 +61,77 @@ module.exports = function(config, specificOptions) {
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 2012',
|
||||
version: '10'
|
||||
},
|
||||
'SL_IE_11': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 8.1',
|
||||
version: '11'
|
||||
},
|
||||
|
||||
'BS_Chrome': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'chrome',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
},
|
||||
'BS_Safari': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'safari',
|
||||
os: 'OS X',
|
||||
os_version: 'Mountain Lion'
|
||||
},
|
||||
'BS_Firefox': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'firefox',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_8': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '8.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE_9': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '9.0',
|
||||
os: 'Windows',
|
||||
os_version: '7'
|
||||
},
|
||||
'BS_IE_10': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '10.0',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE_11': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '11.0',
|
||||
os: 'Windows',
|
||||
os_version: '8.1'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
var buildLabel = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
|
||||
config.logLevel = config.LOG_DEBUG;
|
||||
config.transports = ['websocket', 'xhr-polling'];
|
||||
|
||||
config.browserStack.build = buildLabel;
|
||||
config.browserStack.startTunnel = false;
|
||||
|
||||
config.sauceLabs.build = buildLabel;
|
||||
config.sauceLabs.startConnect = false;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
// TODO(vojta): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
config.transports = ['xhr-polling'];
|
||||
@@ -62,8 +139,47 @@ module.exports = function(config, specificOptions) {
|
||||
// Debug logging into a file, that we print out at the end of the build.
|
||||
config.loggers.push({
|
||||
type: 'file',
|
||||
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log'),
|
||||
level: config.LOG_DEBUG
|
||||
filename: process.env.LOGS_DIR + '/' + (specificOptions.logFile || 'karma.log')
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Terrible hack to workaround inflexibility of log4js:
|
||||
// - ignore web-server's 404 warnings,
|
||||
// - ignore DEBUG logs (on Travis), we log them into a file instead.
|
||||
var IGNORED_404 = [
|
||||
'/favicon.ico',
|
||||
'/%7B%7BtestUrl%7D%7D',
|
||||
'/someSanitizedUrl',
|
||||
'/{{testUrl}}'
|
||||
];
|
||||
var log4js = require('./node_modules/karma/node_modules/log4js');
|
||||
var layouts = require('./node_modules/karma/node_modules/log4js/lib/layouts');
|
||||
var originalConfigure = log4js.configure;
|
||||
log4js.configure = function(log4jsConfig) {
|
||||
var consoleAppender = log4jsConfig.appenders.shift();
|
||||
var originalResult = originalConfigure.call(log4js, log4jsConfig);
|
||||
var layout = layouts.layout(consoleAppender.layout.type, consoleAppender.layout);
|
||||
|
||||
|
||||
|
||||
log4js.addAppender(function(log) {
|
||||
var msg = log.data[0];
|
||||
|
||||
// ignore web-server's 404s
|
||||
if (log.categoryName === 'web-server' && log.level.levelStr === config.LOG_WARN &&
|
||||
IGNORED_404.some(function(ignoredLog) {return msg.indexOf(ignoredLog) !== -1})) {
|
||||
return;
|
||||
}
|
||||
|
||||
// on Travis, ignore DEBUG statements
|
||||
if (process.env.TRAVIS && log.level.levelStr === config.LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(layout(log));
|
||||
});
|
||||
|
||||
return originalResult;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
var BrowserStackTunnel = require('browserstacktunnel-wrapper');
|
||||
|
||||
var HOSTNAME = 'localhost';
|
||||
var PORTS = require('../grunt/utils').availablePorts;
|
||||
var ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY;
|
||||
var READY_FILE = process.env.SAUCE_CONNECT_READY_FILE;
|
||||
|
||||
// We need to start fake servers, otherwise the tunnel does not start.
|
||||
var fakeServers = [];
|
||||
var hosts = [];
|
||||
|
||||
PORTS.forEach(function(port) {
|
||||
fakeServers.push(http.createServer(function() {}).listen(port));
|
||||
hosts.push({
|
||||
name: HOSTNAME,
|
||||
port: port,
|
||||
sslFlag: 0
|
||||
});
|
||||
});
|
||||
|
||||
var tunnel = new BrowserStackTunnel({
|
||||
key: ACCESS_KEY,
|
||||
hosts: hosts
|
||||
});
|
||||
|
||||
console.log('Starting tunnel on ports', PORTS.join(', '));
|
||||
tunnel.start(function(error) {
|
||||
if (error) {
|
||||
console.error('Can not establish the tunnel', error);
|
||||
} else {
|
||||
console.log('Tunnel established.');
|
||||
fakeServers.forEach(function(server) {
|
||||
server.close();
|
||||
});
|
||||
|
||||
if (READY_FILE) {
|
||||
fs.writeFile(READY_FILE, '');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tunnel.on('error', function(error) {
|
||||
console.error(error);
|
||||
});
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
node ./lib/browser-stack/start-tunnel.js &
|
||||
+26
-3
@@ -5,6 +5,22 @@ var spawn = require('child_process').spawn;
|
||||
var version;
|
||||
var CSP_CSS_HEADER = '/* Include this file in your html if you are using the CSP mode. */\n\n';
|
||||
|
||||
var PORT_MIN = 8000;
|
||||
var PORT_MAX = 9999;
|
||||
var TRAVIS_BUILD_NUMBER = parseInt(process.env.TRAVIS_BUILD_NUMBER, 10);
|
||||
var getRandomPorts = function() {
|
||||
if (!process.env.TRAVIS) {
|
||||
return [9876, 9877];
|
||||
}
|
||||
|
||||
// Generate two numbers between PORT_MIN and PORT_MAX, based on TRAVIS_BUILD_NUMBER.
|
||||
return [
|
||||
PORT_MIN + (TRAVIS_BUILD_NUMBER % (PORT_MAX - PORT_MIN)),
|
||||
PORT_MIN + ((TRAVIS_BUILD_NUMBER + 100) % (PORT_MAX - PORT_MIN))
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
init: function() {
|
||||
@@ -20,13 +36,12 @@ module.exports = {
|
||||
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
|
||||
var match = package.version.match(/^([^\-]*)(?:\-(.+))?$/);
|
||||
var semver = match[1].split('.');
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
|
||||
var fullVersion = match[1];
|
||||
|
||||
if (match[2]) {
|
||||
fullVersion += '-';
|
||||
fullVersion += (match[2] == 'snapshot') ? hash : match[2];
|
||||
fullVersion += (match[2] == 'snapshot') ? getSnapshotSuffix() : match[2];
|
||||
}
|
||||
|
||||
version = {
|
||||
@@ -39,6 +54,12 @@ module.exports = {
|
||||
};
|
||||
|
||||
return version;
|
||||
|
||||
function getSnapshotSuffix() {
|
||||
var jenkinsBuild = process.env.BUILD_NUMBER || 'local';
|
||||
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
|
||||
return 'build.'+jenkinsBuild+'+sha.'+hash;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -295,5 +316,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
// see http://saucelabs.com/docs/connect#localhost
|
||||
sauceLabsAvailablePorts: [9000, 9001, 9080, 9090, 9876]
|
||||
sauceLabsAvailablePorts: [9000, 9001, 9080, 9090, 9876],
|
||||
// pseudo-random port numbers for BrowserStack
|
||||
availablePorts: getRandomPorts()
|
||||
};
|
||||
|
||||
@@ -36,8 +36,8 @@ ARGS=""
|
||||
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
|
||||
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
|
||||
fi
|
||||
if [ ! -z "$SAUCE_CONNECT_READY_FILE" ]; then
|
||||
ARGS="$ARGS --readyfile $SAUCE_CONNECT_READY_FILE"
|
||||
if [ ! -z "$BROWSER_PROVIDER_READY_FILE" ]; then
|
||||
ARGS="$ARGS --readyfile $BROWSER_PROVIDER_READY_FILE"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
+10
-7
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"version": "1.2.2",
|
||||
"cdnVersion": "1.2.1",
|
||||
"codename": "consciousness-inertia",
|
||||
"version": "1.2.6",
|
||||
"cdnVersion": "1.2.5",
|
||||
"codename": "taco-salsafication",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
@@ -10,13 +10,14 @@
|
||||
"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",
|
||||
@@ -24,7 +25,7 @@
|
||||
"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-junit-reporter": "~0.2.1",
|
||||
"karma-sauce-launcher": "~0.1.1",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"yaml-js": "~0.0.8",
|
||||
@@ -37,7 +38,9 @@
|
||||
"promises-aplus-tests": "~1.3.2",
|
||||
"grunt-shell": "~0.4.0",
|
||||
"semver": "~2.1.0",
|
||||
"lodash": "~2.1.0"
|
||||
"lodash": "~2.1.0",
|
||||
"karma-browserstack-launcher": "git://github.com/karma-runner/karma-browserstack-launcher.git#master",
|
||||
"browserstacktunnel-wrapper": "~1.1.1"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
@@ -46,6 +49,6 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"grunt-contrib-jshint": "~0.6.4"
|
||||
"grunt-contrib-jshint": "~0.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function catch_errors() {
|
||||
echo "ERROR. That's life."
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap catch_errors ERR
|
||||
|
||||
TMP_FILE='changelog.tmp'
|
||||
CHANGELOG_FILE='CHANGELOG.md'
|
||||
|
||||
echo "Getting current version..."
|
||||
VERSION=`./version.js --current`
|
||||
|
||||
echo "Generating changelog..."
|
||||
./changelog.js $VERSION $TMP_FILE
|
||||
|
||||
cat $CHANGELOG_FILE >> $TMP_FILE
|
||||
mv -f $TMP_FILE $CHANGELOG_FILE
|
||||
|
||||
|
||||
echo "Updating version..."
|
||||
./version.js --remove-snapshot
|
||||
|
||||
echo "CONFIRM TO COMMIT"
|
||||
read WHATEVER
|
||||
|
||||
|
||||
echo "Creating commit..."
|
||||
git commit version.yaml CHANGELOG.md -m "chore(relase): cutting the v$VERSION release"
|
||||
|
||||
echo "Creating tag..."
|
||||
git tag "v$VERSION"
|
||||
@@ -0,0 +1,15 @@
|
||||
# Angular Bower Script
|
||||
|
||||
Script for updating the Angular bower repos from current local build.
|
||||
|
||||
## Instructions
|
||||
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
Executable
+88
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
SCRIPT_DIR=`pwd`
|
||||
TMP_DIR=../../tmp
|
||||
BUILD_DIR=../../build
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
REPOS=(
|
||||
angular \
|
||||
angular-animate \
|
||||
angular-cookies \
|
||||
angular-i18n \
|
||||
angular-loader \
|
||||
angular-mocks \
|
||||
angular-route \
|
||||
angular-resource \
|
||||
angular-sanitize \
|
||||
angular-scenario \
|
||||
angular-touch \
|
||||
)
|
||||
|
||||
#
|
||||
# clone repos
|
||||
#
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Cloning bower-$repo"
|
||||
git clone git@github.com:angular/bower-$repo.git $TMP_DIR/bower-$repo
|
||||
done
|
||||
|
||||
|
||||
#
|
||||
# move the files from the build
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
if [ -f $BUILD_DIR/$repo.js ] # ignore i18l
|
||||
then
|
||||
echo "-- Updating files in bower-$repo"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd $SCRIPT_DIR
|
||||
cp $BUILD_DIR/$repo.* $TMP_DIR/bower-$repo/
|
||||
fi
|
||||
done
|
||||
|
||||
# move i18n files
|
||||
cp $BUILD_DIR/i18n/*.js $TMP_DIR/bower-angular-i18n/
|
||||
|
||||
# move csp.css
|
||||
cp $BUILD_DIR/angular-csp.css $TMP_DIR/bower-angular
|
||||
|
||||
|
||||
#
|
||||
# update bower.json
|
||||
# tag each repo
|
||||
#
|
||||
|
||||
for repo in "${REPOS[@]}"
|
||||
do
|
||||
echo "-- Updating version in bower-$repo to $NEW_VERSION"
|
||||
cd $TMP_DIR/bower-$repo
|
||||
sed -i .tmp -E 's/"(version)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
sed -i .tmp -E 's/"(angular.*)":[ ]*".*"/"\1": "'$NEW_VERSION'"/g' bower.json
|
||||
# delete tmp files
|
||||
rm *.tmp
|
||||
git add -A
|
||||
|
||||
echo "-- Committing, tagging and pushing bower-$repo"
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git tag v$NEW_VERSION
|
||||
git push origin master
|
||||
git push origin v$NEW_VERSION
|
||||
cd $SCRIPT_DIR
|
||||
done
|
||||
@@ -0,0 +1,18 @@
|
||||
# code.angular.js.org Script
|
||||
|
||||
Script for updating code.angularjs.org repo from current local build.
|
||||
|
||||
Note: For a snapshot build, this will fetch the data from the ci server
|
||||
and NOT take the local build!
|
||||
|
||||
## Instructions
|
||||
|
||||
`grunt package`: Build angular locally
|
||||
|
||||
```shell
|
||||
./publish.sh
|
||||
```
|
||||
|
||||
## License
|
||||
MIT
|
||||
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`
|
||||
|
||||
TMP_DIR=../../tmp
|
||||
REPO_DIR=$TMP_DIR/code.angularjs.org
|
||||
BUILD_DIR=../../build
|
||||
SCRIPT_DIR=`pwd`
|
||||
NEW_VERSION=`cat $BUILD_DIR/version.txt`
|
||||
|
||||
#
|
||||
# Snapshot builds are kept in a temp directory in code.angularjs.org
|
||||
# that is filled by calling a php script there.
|
||||
#
|
||||
if [[ "$NEW_VERSION" =~ sha ]] ;then
|
||||
echo "-- updating snapshot version"
|
||||
curl -G --data-urlencode "ver=$NEW_VERSION" http://code.angularjs.org/fetchLatestSnapshot.php
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
#
|
||||
# clone
|
||||
#
|
||||
|
||||
echo "-- Cloning code.angularjs.org"
|
||||
git clone git@github.com:angular/code.angularjs.org.git $REPO_DIR
|
||||
|
||||
#
|
||||
# copy the files from the build
|
||||
#
|
||||
|
||||
echo "-- Updating code.angularjs.org"
|
||||
mkdir $REPO_DIR/$NEW_VERSION
|
||||
cd $REPO_DIR
|
||||
git reset --hard HEAD
|
||||
git checkout master
|
||||
git fetch --all
|
||||
git reset --hard origin/master
|
||||
cd $SCRIPT_DIR
|
||||
cp -r $BUILD_DIR/* $REPO_DIR/$NEW_VERSION/
|
||||
|
||||
#
|
||||
# commit and push
|
||||
#
|
||||
echo "-- Committing and pushing code.angularjs.org"
|
||||
cd $REPO_DIR
|
||||
git add -A
|
||||
git commit -m "v$NEW_VERSION"
|
||||
git push origin master
|
||||
cd $SCRIPT_DIR
|
||||
|
||||
#
|
||||
# refresh code.angularjs.org from github
|
||||
#
|
||||
curl http://code.angularjs.org/gitFetchSite.php
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Increment version and add "-snapshot" ##"
|
||||
echo "############################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- increment version "
|
||||
grunt bump:$BUMP_TYPE
|
||||
NEXT_VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
sed -i .tmp -E 's/"version": "(.*)"/"version": "\1-snapshot"/' package.json
|
||||
echo "-- new version: `grep '"version"' package.json`"
|
||||
echo "-- commit"
|
||||
git add package.json
|
||||
git commit -m "chore(release): start v$NEXT_VERSION"
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "############################################"
|
||||
echo "## Remove "-snapshot" from version ########"
|
||||
echo "############################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "-- old version: `grep '"version"' package.json`"
|
||||
sed -i .tmp -E 's/"version": "(.*)-snapshot"/"version": "\1"/' package.json
|
||||
VERSION=`sed -En 's/.*"version"[ ]*:[ ]*"(.*)".*/\1/p' package.json`
|
||||
echo "-- local version: $VERSION"
|
||||
|
||||
echo "-- commit and tag with v$VERSION"
|
||||
git add package.json
|
||||
git commit -m "chore(release): cut v$VERSION release"
|
||||
git tag -m "v$VERSION" v$VERSION
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update master ##############"
|
||||
echo "#################################"
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
cd `dirname $0`/../..
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Jenkins Build ############"
|
||||
echo "#################################"
|
||||
./jenkins_build.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "## Update code.angular.js.org ###"
|
||||
echo "#################################"
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Update bower ###############"
|
||||
echo "#################################"
|
||||
./scripts/bower/publish.sh
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "#################################"
|
||||
echo "#### Cut release ################"
|
||||
echo "#################################"
|
||||
|
||||
if [ "$1" != "patch" -a "$1" != "minor" -a "$1" != "major" ]; then
|
||||
echo "Please specify the next version type: patch|minor|major"
|
||||
exit 1
|
||||
fi
|
||||
BUMP_TYPE=$1
|
||||
|
||||
# Enable tracing and exit on first failure
|
||||
set -xe
|
||||
|
||||
# Jump onto the master branch and make sure we are using the latest
|
||||
git checkout -f master
|
||||
git merge --ff-only origin/master
|
||||
|
||||
|
||||
# Normalize working dir to script dir
|
||||
cd `dirname $0`/../..
|
||||
|
||||
|
||||
# Bump versions: remove "-snapshot" suffix
|
||||
./scripts/jenkins/bump-remove-snapshot.sh
|
||||
|
||||
# Build
|
||||
./jenkins_build.sh
|
||||
|
||||
# Bump versions: Increment version and add "-snapshot"
|
||||
./scripts/jenkins/bump-increment.sh $BUMP_TYPE
|
||||
|
||||
echo "-- push to Github"
|
||||
# push to github
|
||||
git push --all
|
||||
|
||||
# Update code.angularjs.org
|
||||
./scripts/code.angularjs.org/publish.sh
|
||||
|
||||
# Update bower
|
||||
./scripts/bower/publish.sh
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
|
||||
if [ $JOB = "unit" ]; then
|
||||
grunt ci-checks
|
||||
grunt test:docgen
|
||||
grunt test:promises-aplus
|
||||
grunt test:unit --browsers SL_Chrome,SL_Safari,SL_Firefox,SL_IE_8,SL_IE_9,SL_IE_10,SL_IE_11 --reporters dots
|
||||
elif [ $JOB = "e2e" ]; then
|
||||
grunt test:e2e --browsers SL_Chrome --reporters dots
|
||||
else
|
||||
echo "Unknown job type. Please set JOB=unit or JOB=e2e."
|
||||
fi
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
|
||||
# Wait for Connect to be ready before exiting
|
||||
while [ ! -f $SAUCE_CONNECT_READY_FILE ]; do
|
||||
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
|
||||
sleep .5
|
||||
done
|
||||
+30
-26
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -974,7 +976,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 +1332,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) {
|
||||
|
||||
+29
-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>
|
||||
@@ -747,24 +769,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) {
|
||||
|
||||
/**
|
||||
|
||||
+54
-57
@@ -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) {
|
||||
|
||||
+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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
+15
-45
@@ -395,15 +395,17 @@ 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;
|
||||
@@ -449,15 +451,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);
|
||||
@@ -951,39 +953,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 +1099,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 +1156,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
|
||||
ctrl.$render();
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}];
|
||||
|
||||
@@ -1463,7 +1434,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
|
||||
*
|
||||
|
||||
@@ -69,7 +69,14 @@ forEach(
|
||||
* a dblclick. (The Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-dblclick="count = count + 1" ng-init="count=0">
|
||||
Increment (on double click)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -85,7 +92,14 @@ forEach(
|
||||
* mousedown. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousedown="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse down)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -101,7 +115,14 @@ forEach(
|
||||
* mouseup. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseup="count = count + 1" ng-init="count=0">
|
||||
Increment (on mouse up)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -116,7 +137,14 @@ forEach(
|
||||
* mouseover. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseover="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse is over)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -132,7 +160,14 @@ forEach(
|
||||
* mouseenter. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseenter="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse enters)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -148,7 +183,14 @@ forEach(
|
||||
* mouseleave. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mouseleave="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse leaves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -164,7 +206,14 @@ forEach(
|
||||
* mousemove. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<button ng-mousemove="count = count + 1" ng-init="count=0">
|
||||
Increment (when mouse moves)
|
||||
</button>
|
||||
count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -180,7 +229,12 @@ forEach(
|
||||
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keydown="count = count + 1" ng-init="count=0">
|
||||
key down count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -196,7 +250,12 @@ forEach(
|
||||
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keyup="count = count + 1" ng-init="count=0">
|
||||
key up count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -212,7 +271,12 @@ forEach(
|
||||
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-keypress="count = count + 1" ng-init="count=0">
|
||||
key press count: {{count}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
|
||||
@@ -311,7 +375,12 @@ forEach(
|
||||
* copy. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
|
||||
copied: {{copied}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -326,7 +395,12 @@ forEach(
|
||||
* cut. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
|
||||
cut: {{cut}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -341,5 +415,10 @@ forEach(
|
||||
* paste. (Event object is available as `$event`)
|
||||
*
|
||||
* @example
|
||||
* See {@link ng.directive:ngClick ngClick}
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
|
||||
pasted: {{paste}}
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
padding:10px;
|
||||
}
|
||||
|
||||
/*
|
||||
The transition styles can also be placed on the CSS base class above
|
||||
*/
|
||||
.animate-if.ng-enter, .animate-if.ng-leave {
|
||||
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
|
||||
@@ -94,9 +91,12 @@ var ngIfDirective = ['$animate', function($animate) {
|
||||
if (!childScope) {
|
||||
childScope = $scope.$new();
|
||||
$transclude(childScope, function (clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when it's template arrives.
|
||||
block = {
|
||||
startNode: clone[0],
|
||||
endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
|
||||
clone: clone
|
||||
};
|
||||
$animate.enter(clone, $element.parent(), $element);
|
||||
});
|
||||
@@ -109,7 +109,7 @@ var ngIfDirective = ['$animate', function($animate) {
|
||||
}
|
||||
|
||||
if (block) {
|
||||
$animate.leave(getBlockElements(block));
|
||||
$animate.leave(getBlockElements(block.clone));
|
||||
block = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,13 +147,14 @@
|
||||
* @description
|
||||
* Emitted every time the ngInclude content is reloaded.
|
||||
*/
|
||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
|
||||
function($http, $templateCache, $anchorScroll, $compile, $animate, $sce) {
|
||||
var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
|
||||
function($http, $templateCache, $anchorScroll, $animate, $sce) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: 400,
|
||||
terminal: true,
|
||||
transclude: 'element',
|
||||
controller: angular.noop,
|
||||
compile: function(element, attr) {
|
||||
var srcExp = attr.ngInclude || attr.src,
|
||||
onloadExp = attr.onload || '',
|
||||
@@ -187,6 +188,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||
$http.get(src, {cache: $templateCache}).success(function(response) {
|
||||
if (thisChangeId !== changeCounter) return;
|
||||
var newScope = scope.$new();
|
||||
ctrl.template = response;
|
||||
|
||||
// Note: This will also link all children of ng-include that were contained in the original
|
||||
// html. If that content contains controllers, ... they could pollute/change the scope.
|
||||
@@ -194,15 +196,14 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||
// Note: We can't remove them in the cloneAttchFn of $transclude as that
|
||||
// function is called before linking the content, which would apply child
|
||||
// directives to non existing elements.
|
||||
var clone = $transclude(newScope, noop);
|
||||
cleanupLastIncludeContent();
|
||||
var clone = $transclude(newScope, function(clone) {
|
||||
cleanupLastIncludeContent();
|
||||
$animate.enter(clone, null, $element, afterAnimation);
|
||||
});
|
||||
|
||||
currentScope = newScope;
|
||||
currentElement = clone;
|
||||
|
||||
currentElement.html(response);
|
||||
$animate.enter(currentElement, null, $element, afterAnimation);
|
||||
$compile(currentElement.contents())(currentScope);
|
||||
currentScope.$emit('$includeContentLoaded');
|
||||
scope.$eval(onloadExp);
|
||||
}).error(function() {
|
||||
@@ -211,9 +212,28 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
||||
scope.$emit('$includeContentRequested');
|
||||
} else {
|
||||
cleanupLastIncludeContent();
|
||||
ctrl.template = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
// This directive is called during the $transclude call of the first `ngInclude` directive.
|
||||
// It will replace and compile the content of the element with the loaded template.
|
||||
// We need this directive so that the element content is already filled when
|
||||
// the link function of another directive on the same element as ngInclude
|
||||
// is called.
|
||||
var ngIncludeFillContentDirective = ['$compile',
|
||||
function($compile) {
|
||||
return {
|
||||
restrict: 'ECA',
|
||||
priority: -400,
|
||||
require: 'ngInclude',
|
||||
link: function(scope, $element, $attr, ctrl) {
|
||||
$element.html(ctrl.template);
|
||||
$compile($element.contents())(scope);
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
* current scope.
|
||||
*
|
||||
* <div class="alert alert-error">
|
||||
* The only appropriate use of `ngInit` for aliasing special properties of
|
||||
* The only appropriate use of `ngInit` is for aliasing special properties of
|
||||
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
|
||||
* should use {@link guide/controller controllers} rather than `ngInit`
|
||||
* to initialize values on a scope.
|
||||
* </div>
|
||||
*
|
||||
* @priority 450
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} ngInit {@link guide/expression Expression} to eval.
|
||||
*
|
||||
@@ -47,6 +49,7 @@
|
||||
</doc:example>
|
||||
*/
|
||||
var ngInitDirective = ngDirective({
|
||||
priority: 450,
|
||||
compile: function() {
|
||||
return {
|
||||
pre: function(scope, element, attrs) {
|
||||
|
||||
@@ -203,7 +203,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
$$tlb: true,
|
||||
link: function($scope, $element, $attr, ctrl, $transclude){
|
||||
var expression = $attr.ngRepeat;
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
var match = expression.match(/^\s*(.+)\s+in\s+([\r\n\s\S]*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
|
||||
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
|
||||
lhs, rhs, valueIdentifier, keyIdentifier,
|
||||
hashFnLocals = {$id: hashKey};
|
||||
@@ -301,7 +301,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
} else if (nextBlockMap.hasOwnProperty(trackById)) {
|
||||
// restore lastBlockMap
|
||||
forEach(nextBlockOrder, function(block) {
|
||||
if (block && block.startNode) lastBlockMap[block.id] = block;
|
||||
if (block && block.scope) lastBlockMap[block.id] = block;
|
||||
});
|
||||
// This is a duplicate and we need to throw an error
|
||||
throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
|
||||
@@ -318,7 +318,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
// lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
|
||||
if (lastBlockMap.hasOwnProperty(key)) {
|
||||
block = lastBlockMap[key];
|
||||
elementsToRemove = getBlockElements(block);
|
||||
elementsToRemove = getBlockElements(block.clone);
|
||||
$animate.leave(elementsToRemove);
|
||||
forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
|
||||
block.scope.$destroy();
|
||||
@@ -330,9 +330,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
key = (collection === collectionKeys) ? index : collectionKeys[index];
|
||||
value = collection[key];
|
||||
block = nextBlockOrder[index];
|
||||
if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;
|
||||
if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
|
||||
|
||||
if (block.startNode) {
|
||||
if (block.scope) {
|
||||
// if we have already seen this object, then we need to reuse the
|
||||
// associated scope/element
|
||||
childScope = block.scope;
|
||||
@@ -342,11 +342,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
nextNode = nextNode.nextSibling;
|
||||
} while(nextNode && nextNode[NG_REMOVED]);
|
||||
|
||||
if (block.startNode != nextNode) {
|
||||
if (getBlockStart(block) != nextNode) {
|
||||
// existing item which got moved
|
||||
$animate.move(getBlockElements(block), null, jqLite(previousNode));
|
||||
$animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
|
||||
}
|
||||
previousNode = block.endNode;
|
||||
previousNode = getBlockEnd(block);
|
||||
} else {
|
||||
// new item which we don't know about
|
||||
childScope = $scope.$new();
|
||||
@@ -362,14 +362,16 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
childScope.$odd = !(childScope.$even = (index&1) === 0);
|
||||
// jshint bitwise: true
|
||||
|
||||
if (!block.startNode) {
|
||||
if (!block.scope) {
|
||||
$transclude(childScope, function(clone) {
|
||||
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
|
||||
$animate.enter(clone, null, jqLite(previousNode));
|
||||
previousNode = clone;
|
||||
block.scope = childScope;
|
||||
block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
|
||||
block.endNode = clone[clone.length - 1];
|
||||
// Note: We only need the first/last node of the cloned nodes.
|
||||
// However, we need to keep the reference to the jqlite wrapper as it might be changed later
|
||||
// by a directive with templateUrl when it's template arrives.
|
||||
block.clone = clone;
|
||||
nextBlockMap[block.id] = block;
|
||||
});
|
||||
}
|
||||
@@ -378,5 +380,13 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function getBlockStart(block) {
|
||||
return block.clone[0];
|
||||
}
|
||||
|
||||
function getBlockEnd(block) {
|
||||
return block.clone[block.clone.length - 1];
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
@@ -6,19 +6,26 @@
|
||||
* @restrict EA
|
||||
*
|
||||
* @description
|
||||
* The ngSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
|
||||
* Elements within ngSwitch but without ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
|
||||
* The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
|
||||
* Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
|
||||
* as specified in the template.
|
||||
*
|
||||
* The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
|
||||
* from the template cache), ngSwitch simply choses one of the nested elements and makes it visible based on which element
|
||||
* from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
|
||||
* matches the value obtained from the evaluated expression. In other words, you define a container element
|
||||
* (where you place the directive), place an expression on the **on="..." attribute**
|
||||
* (or the **ng-switch="..." attribute**), define any inner elements inside of the directive and place
|
||||
* (where you place the directive), place an expression on the **`on="..."` attribute**
|
||||
* (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
|
||||
* a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
|
||||
* expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
|
||||
* attribute is displayed.
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* Be aware that the attribute values to match against cannot be expressions. They are interpreted
|
||||
* as literal string values to match against.
|
||||
* For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
|
||||
* value of the expression `$scope.someVal`.
|
||||
* </div>
|
||||
|
||||
* @animations
|
||||
* enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
|
||||
* leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
|
||||
@@ -30,6 +37,7 @@
|
||||
* <ANY ng-switch-default>...</ANY>
|
||||
* </ANY>
|
||||
*
|
||||
*
|
||||
* @scope
|
||||
* @priority 800
|
||||
* @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
|
||||
|
||||
@@ -69,7 +69,7 @@ var ngTranscludeDirective = ngDirective({
|
||||
|
||||
link: function($scope, $element, $attrs, controller) {
|
||||
controller.$transclude(function(clone) {
|
||||
$element.html('');
|
||||
$element.empty();
|
||||
$element.append(clone);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -221,18 +221,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
|
||||
|
||||
// required validator
|
||||
if (multiple && (attr.required || attr.ngRequired)) {
|
||||
var requiredValidator = function(value) {
|
||||
ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
|
||||
return value;
|
||||
if (multiple) {
|
||||
ngModelCtrl.$isEmpty = function(value) {
|
||||
return !value || value.length === 0;
|
||||
};
|
||||
|
||||
ngModelCtrl.$parsers.push(requiredValidator);
|
||||
ngModelCtrl.$formatters.unshift(requiredValidator);
|
||||
|
||||
attr.$observe('required', function() {
|
||||
requiredValidator(ngModelCtrl.$viewValue);
|
||||
});
|
||||
}
|
||||
|
||||
if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
|
||||
@@ -333,13 +325,13 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
// becomes the compilation root
|
||||
nullOption.removeClass('ng-scope');
|
||||
|
||||
// we need to remove it before calling selectElement.html('') because otherwise IE will
|
||||
// we need to remove it before calling selectElement.empty() because otherwise IE will
|
||||
// remove the label from the element. wtf?
|
||||
nullOption.remove();
|
||||
}
|
||||
|
||||
// clear contents, we'll add what's needed based on the model
|
||||
selectElement.html('');
|
||||
selectElement.empty();
|
||||
|
||||
selectElement.on('change', function() {
|
||||
scope.$apply(function() {
|
||||
|
||||
@@ -28,12 +28,11 @@ var XHR = window.XMLHttpRequest || function() {
|
||||
*/
|
||||
function $HttpBackendProvider() {
|
||||
this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
|
||||
return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
|
||||
$document[0], $window.location.protocol.replace(':', ''));
|
||||
return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
|
||||
}];
|
||||
}
|
||||
|
||||
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
|
||||
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
|
||||
var ABORTED = -1;
|
||||
|
||||
// TODO(vojta): fix the signature
|
||||
@@ -113,14 +112,14 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
||||
}
|
||||
|
||||
function completeRequest(callback, status, response, headersString) {
|
||||
var protocol = locationProtocol || urlResolve(url).protocol;
|
||||
var protocol = urlResolve(url).protocol;
|
||||
|
||||
// cancel timeout and subsequent timeout promise resolution
|
||||
timeoutId && $browserDefer.cancel(timeoutId);
|
||||
jsonpDone = xhr = null;
|
||||
|
||||
// fix status code for file protocol (it's always 0)
|
||||
status = (protocol == 'file') ? (response ? 200 : 404) : status;
|
||||
status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
|
||||
|
||||
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
|
||||
status = status == 1223 ? 204 : status;
|
||||
|
||||
@@ -103,8 +103,8 @@ function $InterpolateProvider() {
|
||||
*
|
||||
<pre>
|
||||
var $interpolate = ...; // injected
|
||||
var exp = $interpolate('Hello {{name}}!');
|
||||
expect(exp({name:'Angular'}).toEqual('Hello Angular!');
|
||||
var exp = $interpolate('Hello {{name | uppercase}}!');
|
||||
expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
|
||||
</pre>
|
||||
*
|
||||
*
|
||||
|
||||
@@ -24,6 +24,14 @@ function $IntervalProvider() {
|
||||
* In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
|
||||
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
|
||||
* time.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note**: Intervals created by this service must be explicitly destroyed when you are finished
|
||||
* with them. In particular they are not automatically destroyed when a controller's scope or a
|
||||
* directive's element are destroyed.
|
||||
* You should take this into consideration and make sure to always cancel the interval at the
|
||||
* appropriate moment. See the example below for more details on how and when to do this.
|
||||
* </div>
|
||||
*
|
||||
* @param {function()} fn A function that should be called repeatedly.
|
||||
* @param {number} delay Number of milliseconds between each function call.
|
||||
@@ -32,6 +40,95 @@ function $IntervalProvider() {
|
||||
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
|
||||
* will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
|
||||
* @returns {promise} A promise which will be notified on each iteration.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$interval) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
// Don't start a new fight if we are already fighting
|
||||
if ( angular.isDefined(stop) ) return;
|
||||
|
||||
stop = $interval(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
} else {
|
||||
$scope.stopFight();
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
if (angular.isDefined(stop)) {
|
||||
$interval.cancel(stop);
|
||||
stop = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
// Make sure that the interval is destroyed too
|
||||
$scope.stopFight();
|
||||
});
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $interval and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($interval, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
stopTime; // so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
stopTime = $interval(updateTime, 1000);
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$interval.cancel(stopTime);
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function interval(fn, delay, count, invokeApply) {
|
||||
var setInterval = $window.setInterval,
|
||||
|
||||
@@ -179,7 +179,47 @@ function LocationHashbangUrl(appBase, hashPrefix) {
|
||||
hashPrefix);
|
||||
}
|
||||
parseAppUrl(withoutHashUrl, this, appBase);
|
||||
|
||||
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
|
||||
|
||||
this.$$compose();
|
||||
|
||||
/*
|
||||
* In Windows, on an anchor node on documents loaded from
|
||||
* the filesystem, the browser will return a pathname
|
||||
* prefixed with the drive name ('/C:/path') when a
|
||||
* pathname without a drive is set:
|
||||
* * a.setAttribute('href', '/foo')
|
||||
* * a.pathname === '/C:/foo' //true
|
||||
*
|
||||
* Inside of Angular, we're always using pathnames that
|
||||
* do not include drive names for routing.
|
||||
*/
|
||||
function removeWindowsDriveName (path, url, base) {
|
||||
/*
|
||||
Matches paths for file protocol on windows,
|
||||
such as /C:/foo/bar, and captures only /foo/bar.
|
||||
*/
|
||||
var windowsFilePathExp = /^\/?.*?:(\/.*)/;
|
||||
|
||||
var firstPathSegmentMatch;
|
||||
|
||||
//Get the relative path from the input URL.
|
||||
if (url.indexOf(base) === 0) {
|
||||
url = url.replace(base, '');
|
||||
}
|
||||
|
||||
/*
|
||||
* The input URL intentionally contains a
|
||||
* first path segment that ends with a colon.
|
||||
*/
|
||||
if (windowsFilePathExp.exec(url)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
firstPathSegmentMatch = windowsFilePathExp.exec(path);
|
||||
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -589,6 +629,13 @@ function $LocationProvider(){
|
||||
}
|
||||
|
||||
var absHref = elm.prop('href');
|
||||
|
||||
if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
|
||||
// SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
|
||||
// an animation.
|
||||
absHref = urlResolve(absHref.animVal).href;
|
||||
}
|
||||
|
||||
var rewrittenUrl = $location.$$rewrite(absHref);
|
||||
|
||||
if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
|
||||
|
||||
+9
-2
@@ -139,9 +139,16 @@ function $LogProvider(){
|
||||
|
||||
function consoleLog(type) {
|
||||
var console = $window.console || {},
|
||||
logFn = console[type] || console.log || noop;
|
||||
logFn = console[type] || console.log || noop,
|
||||
hasApply = false;
|
||||
|
||||
if (logFn.apply) {
|
||||
// Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
|
||||
// The reason behind this is that console.log has type "object" in IE8...
|
||||
try {
|
||||
hasApply = !! logFn.apply;
|
||||
} catch (e) {}
|
||||
|
||||
if (hasApply) {
|
||||
return function() {
|
||||
var args = [];
|
||||
forEach(arguments, function(arg) {
|
||||
|
||||
+59
-33
@@ -44,23 +44,24 @@ function ensureSafeMemberName(name, fullExpression) {
|
||||
|
||||
function ensureSafeObject(obj, fullExpression) {
|
||||
// nifty check if obj is Function that is fast and works across iframes and other contexts
|
||||
if (obj && obj.constructor === obj) {
|
||||
throw $parseMinErr('isecfn',
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isWindow(obj)
|
||||
obj && obj.document && obj.location && obj.alert && obj.setInterval) {
|
||||
throw $parseMinErr('isecwindow',
|
||||
'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isElement(obj)
|
||||
obj && (obj.nodeName || (obj.on && obj.find))) {
|
||||
throw $parseMinErr('isecdom',
|
||||
'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else {
|
||||
return obj;
|
||||
if (obj) {
|
||||
if (obj.constructor === obj) {
|
||||
throw $parseMinErr('isecfn',
|
||||
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isWindow(obj)
|
||||
obj.document && obj.location && obj.alert && obj.setInterval) {
|
||||
throw $parseMinErr('isecwindow',
|
||||
'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
} else if (// isElement(obj)
|
||||
obj.children && (obj.nodeName || (obj.on && obj.find))) {
|
||||
throw $parseMinErr('isecdom',
|
||||
'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
|
||||
fullExpression);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
var OPERATORS = {
|
||||
@@ -890,19 +891,19 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
? function cspSafeGetter(scope, locals) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
pathVal = pathVal[key0];
|
||||
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key1 ? undefined : pathVal;
|
||||
pathVal = pathVal[key1];
|
||||
|
||||
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key2 ? undefined : pathVal;
|
||||
pathVal = pathVal[key2];
|
||||
|
||||
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key3 ? undefined : pathVal;
|
||||
pathVal = pathVal[key3];
|
||||
|
||||
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key4 ? undefined : pathVal;
|
||||
pathVal = pathVal[key4];
|
||||
|
||||
return pathVal;
|
||||
@@ -911,7 +912,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
|
||||
promise;
|
||||
|
||||
if (pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return pathVal;
|
||||
|
||||
pathVal = pathVal[key0];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -923,7 +924,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key1 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key1];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -935,7 +936,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key2 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key2];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -947,7 +948,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key3 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key3];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -959,7 +960,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
}
|
||||
pathVal = pathVal.$$v;
|
||||
}
|
||||
if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
|
||||
if (pathVal == null) return key4 ? undefined : pathVal;
|
||||
|
||||
pathVal = pathVal[key4];
|
||||
if (pathVal && pathVal.then) {
|
||||
@@ -975,6 +976,26 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn1(key0, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
|
||||
return function simpleGetterFn1(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
};
|
||||
}
|
||||
|
||||
function simpleGetterFn2(key0, key1, fullExp) {
|
||||
ensureSafeMemberName(key0, fullExp);
|
||||
ensureSafeMemberName(key1, fullExp);
|
||||
|
||||
return function simpleGetterFn2(scope, locals) {
|
||||
if (scope == null) return undefined;
|
||||
scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
|
||||
return scope == null ? undefined : scope[key1];
|
||||
};
|
||||
}
|
||||
|
||||
function getterFn(path, options, fullExp) {
|
||||
// Check whether the cache has this getter already.
|
||||
// We can use hasOwnProperty directly on the cache because we ensure,
|
||||
@@ -987,7 +1008,13 @@ function getterFn(path, options, fullExp) {
|
||||
pathKeysLength = pathKeys.length,
|
||||
fn;
|
||||
|
||||
if (options.csp) {
|
||||
// When we have only 1 or 2 tokens, use optimized special case closures.
|
||||
// http://jsperf.com/angularjs-parse-getter/6
|
||||
if (!options.unwrapPromises && pathKeysLength === 1) {
|
||||
fn = simpleGetterFn1(pathKeys[0], fullExp);
|
||||
} else if (!options.unwrapPromises && pathKeysLength === 2) {
|
||||
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
|
||||
} else if (options.csp) {
|
||||
if (pathKeysLength < 6) {
|
||||
fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
|
||||
options);
|
||||
@@ -1005,11 +1032,10 @@ function getterFn(path, options, fullExp) {
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var code = 'var l, fn, p;\n';
|
||||
var code = 'var p;\n';
|
||||
forEach(pathKeys, function(key, index) {
|
||||
ensureSafeMemberName(key, fullExp);
|
||||
code += 'if(s === null || s === undefined) return s;\n' +
|
||||
'l=s;\n' +
|
||||
code += 'if(s == null) return undefined;\n' +
|
||||
's='+ (index
|
||||
// we simply dereference 's' on any .dot notation
|
||||
? 's'
|
||||
@@ -1032,10 +1058,10 @@ function getterFn(path, options, fullExp) {
|
||||
/* jshint -W054 */
|
||||
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
|
||||
/* jshint +W054 */
|
||||
evaledFnGetter.toString = function() { return code; };
|
||||
fn = function(scope, locals) {
|
||||
evaledFnGetter.toString = valueFn(code);
|
||||
fn = options.unwrapPromises ? function(scope, locals) {
|
||||
return evaledFnGetter(scope, locals, promiseWarning);
|
||||
};
|
||||
} : evaledFnGetter;
|
||||
}
|
||||
|
||||
// Only cache the value if it's not going to mess up the cache object
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@
|
||||
*
|
||||
* # Differences between Kris Kowal's Q and $q
|
||||
*
|
||||
* There are three main differences:
|
||||
* There are two main differences:
|
||||
*
|
||||
* - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
|
||||
* mechanism in angular, which means faster propagation of resolution or rejection into your
|
||||
|
||||
+79
-57
@@ -71,6 +71,7 @@
|
||||
function $RootScopeProvider(){
|
||||
var TTL = 10;
|
||||
var $rootScopeMinErr = minErr('$rootScope');
|
||||
var lastDirtyWatch = null;
|
||||
|
||||
this.digestTtl = function(value) {
|
||||
if (arguments.length) {
|
||||
@@ -155,11 +156,11 @@ function $RootScopeProvider(){
|
||||
* @description
|
||||
* Creates a new child {@link ng.$rootScope.Scope scope}.
|
||||
*
|
||||
* The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
|
||||
* {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
|
||||
* scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
|
||||
* The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and
|
||||
* {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the
|
||||
* scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}.
|
||||
*
|
||||
* {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
|
||||
* {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is
|
||||
* desired for the scope and its child scopes to be permanently detached from the parent and
|
||||
* thus stop participating in model change detection and listener notification by invoking.
|
||||
*
|
||||
@@ -172,7 +173,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
*/
|
||||
$new: function(isolate) {
|
||||
var Child,
|
||||
var ChildScope,
|
||||
child;
|
||||
|
||||
if (isolate) {
|
||||
@@ -182,11 +183,11 @@ function $RootScopeProvider(){
|
||||
child.$$asyncQueue = this.$$asyncQueue;
|
||||
child.$$postDigestQueue = this.$$postDigestQueue;
|
||||
} else {
|
||||
Child = function() {}; // should be anonymous; This is so that when the minifier munges
|
||||
ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
|
||||
// the name it does not become random set of chars. This will then show up as class
|
||||
// name in the debugger.
|
||||
Child.prototype = this;
|
||||
child = new Child();
|
||||
ChildScope.prototype = this;
|
||||
child = new ChildScope();
|
||||
child.$id = nextUid();
|
||||
}
|
||||
child['this'] = child;
|
||||
@@ -212,11 +213,11 @@ function $RootScopeProvider(){
|
||||
* @description
|
||||
* Registers a `listener` callback to be executed whenever the `watchExpression` changes.
|
||||
*
|
||||
* - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
|
||||
* - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest
|
||||
* $digest()} and should return the value that will be watched. (Since
|
||||
* {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
|
||||
* {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the
|
||||
* `watchExpression` can execute multiple times per
|
||||
* {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
|
||||
* {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.)
|
||||
* - The `listener` is called only when the value from the current `watchExpression` and the
|
||||
* previous call to `watchExpression` are not equal (with the exception of the initial run,
|
||||
* see below). The inequality is determined according to
|
||||
@@ -228,13 +229,13 @@ function $RootScopeProvider(){
|
||||
* iteration limit is 10 to prevent an infinite loop deadlock.
|
||||
*
|
||||
*
|
||||
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
|
||||
* If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called,
|
||||
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
|
||||
* can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
|
||||
* can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a
|
||||
* change is detected, be prepared for multiple calls to your listener.)
|
||||
*
|
||||
* After a watcher is registered with the scope, the `listener` fn is called asynchronously
|
||||
* (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
|
||||
* (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the
|
||||
* watcher. In rare cases, this is undesirable because the listener is called when the result
|
||||
* of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
|
||||
* can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
|
||||
@@ -266,7 +267,7 @@ function $RootScopeProvider(){
|
||||
|
||||
|
||||
|
||||
// Using a listener function
|
||||
// Using a listener function
|
||||
var food;
|
||||
scope.foodCounter = 0;
|
||||
expect(scope.foodCounter).toEqual(0);
|
||||
@@ -291,14 +292,14 @@ function $RootScopeProvider(){
|
||||
// Update food and run digest. Now the counter will increment
|
||||
food = 'cheeseburger';
|
||||
scope.$digest();
|
||||
expect(scope.foodCounter).toEqual(1);
|
||||
expect(scope.foodCounter).toEqual(1);
|
||||
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param {(function()|string)} watchExpression Expression that is evaluated on each
|
||||
* {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
|
||||
* {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers
|
||||
* a call to the `listener`.
|
||||
*
|
||||
* - `string`: Evaluated as {@link guide/expression expression}
|
||||
@@ -325,6 +326,8 @@ function $RootScopeProvider(){
|
||||
eq: !!objectEquality
|
||||
};
|
||||
|
||||
lastDirtyWatch = null;
|
||||
|
||||
// in the case user pass string, we need to compile it, do we really need this ?
|
||||
if (!isFunction(listener)) {
|
||||
var listenFn = compileToFn(listener || noop, 'listener');
|
||||
@@ -394,7 +397,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
|
||||
* expression value should evaluate to an object or an array which is observed on each
|
||||
* {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
|
||||
* {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the
|
||||
* collection will trigger a call to the `listener`.
|
||||
*
|
||||
* @param {function(newCollection, oldCollection, scope)} listener a callback function that is
|
||||
@@ -499,9 +502,9 @@ function $RootScopeProvider(){
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
|
||||
* its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
|
||||
* the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
|
||||
* Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and
|
||||
* its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change
|
||||
* the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers}
|
||||
* until no more listeners are firing. This means that it is possible to get into an infinite
|
||||
* loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
|
||||
* iterations exceeds 10.
|
||||
@@ -509,12 +512,12 @@ function $RootScopeProvider(){
|
||||
* Usually, you don't call `$digest()` directly in
|
||||
* {@link ng.directive:ngController controllers} or in
|
||||
* {@link ng.$compileProvider#methods_directive directives}.
|
||||
* Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
|
||||
* Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within
|
||||
* a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
|
||||
*
|
||||
* If you want to be notified whenever `$digest()` is called,
|
||||
* you can register a `watchExpression` function with
|
||||
* {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
|
||||
* {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`.
|
||||
*
|
||||
* In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
|
||||
*
|
||||
@@ -553,6 +556,8 @@ function $RootScopeProvider(){
|
||||
|
||||
beginPhase('$digest');
|
||||
|
||||
lastDirtyWatch = null;
|
||||
|
||||
do { // "while dirty" loop
|
||||
dirty = false;
|
||||
current = target;
|
||||
@@ -562,10 +567,13 @@ function $RootScopeProvider(){
|
||||
asyncTask = asyncQueue.shift();
|
||||
asyncTask.scope.$eval(asyncTask.expression);
|
||||
} catch (e) {
|
||||
clearPhase();
|
||||
$exceptionHandler(e);
|
||||
}
|
||||
lastDirtyWatch = null;
|
||||
}
|
||||
|
||||
traverseScopesLoop:
|
||||
do { // "traverse the scopes" loop
|
||||
if ((watchers = current.$$watchers)) {
|
||||
// process our watches
|
||||
@@ -575,25 +583,34 @@ function $RootScopeProvider(){
|
||||
watch = watchers[length];
|
||||
// Most common watches are on primitives, in which case we can short
|
||||
// circuit it with === operator, only when === fails do we use .equals
|
||||
if (watch && (value = watch.get(current)) !== (last = watch.last) &&
|
||||
!(watch.eq
|
||||
? equals(value, last)
|
||||
: (typeof value == 'number' && typeof last == 'number'
|
||||
&& isNaN(value) && isNaN(last)))) {
|
||||
dirty = true;
|
||||
watch.last = watch.eq ? copy(value) : value;
|
||||
watch.fn(value, ((last === initWatchVal) ? value : last), current);
|
||||
if (ttl < 5) {
|
||||
logIdx = 4 - ttl;
|
||||
if (!watchLog[logIdx]) watchLog[logIdx] = [];
|
||||
logMsg = (isFunction(watch.exp))
|
||||
? 'fn: ' + (watch.exp.name || watch.exp.toString())
|
||||
: watch.exp;
|
||||
logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
|
||||
watchLog[logIdx].push(logMsg);
|
||||
if (watch) {
|
||||
if ((value = watch.get(current)) !== (last = watch.last) &&
|
||||
!(watch.eq
|
||||
? equals(value, last)
|
||||
: (typeof value == 'number' && typeof last == 'number'
|
||||
&& isNaN(value) && isNaN(last)))) {
|
||||
dirty = true;
|
||||
lastDirtyWatch = watch;
|
||||
watch.last = watch.eq ? copy(value) : value;
|
||||
watch.fn(value, ((last === initWatchVal) ? value : last), current);
|
||||
if (ttl < 5) {
|
||||
logIdx = 4 - ttl;
|
||||
if (!watchLog[logIdx]) watchLog[logIdx] = [];
|
||||
logMsg = (isFunction(watch.exp))
|
||||
? 'fn: ' + (watch.exp.name || watch.exp.toString())
|
||||
: watch.exp;
|
||||
logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
|
||||
watchLog[logIdx].push(logMsg);
|
||||
}
|
||||
} else if (watch === lastDirtyWatch) {
|
||||
// If the most recently dirty watcher is now clean, short circuit since the remaining watchers
|
||||
// have already been tested.
|
||||
dirty = false;
|
||||
break traverseScopesLoop;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
clearPhase();
|
||||
$exceptionHandler(e);
|
||||
}
|
||||
}
|
||||
@@ -602,13 +619,16 @@ function $RootScopeProvider(){
|
||||
// Insanity Warning: scope depth-first traversal
|
||||
// yes, this code is a bit crazy, but it works and we have tests to prove it!
|
||||
// this piece should be kept in sync with the traversal in $broadcast
|
||||
if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
|
||||
if (!(next = (current.$$childHead ||
|
||||
(current !== target && current.$$nextSibling)))) {
|
||||
while(current !== target && !(next = current.$$nextSibling)) {
|
||||
current = current.$parent;
|
||||
}
|
||||
}
|
||||
} while ((current = next));
|
||||
|
||||
// `break traverseScopesLoop;` takes us to here
|
||||
|
||||
if(dirty && !(ttl--)) {
|
||||
clearPhase();
|
||||
throw $rootScopeMinErr('infdig',
|
||||
@@ -616,6 +636,7 @@ function $RootScopeProvider(){
|
||||
'Watchers fired in the last 5 iterations: {1}',
|
||||
TTL, toJson(watchLog));
|
||||
}
|
||||
|
||||
} while (dirty || asyncQueue.length);
|
||||
|
||||
clearPhase();
|
||||
@@ -651,7 +672,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* @description
|
||||
* Removes the current scope (and all of its children) from the parent scope. Removal implies
|
||||
* that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
|
||||
* that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer
|
||||
* propagate to the current scope and its children. Removal also implies that the current
|
||||
* scope is eligible for garbage collection.
|
||||
*
|
||||
@@ -668,11 +689,12 @@ function $RootScopeProvider(){
|
||||
*/
|
||||
$destroy: function() {
|
||||
// we can't destroy the root scope or a scope that has been already destroyed
|
||||
if ($rootScope == this || this.$$destroyed) return;
|
||||
if (this.$$destroyed) return;
|
||||
var parent = this.$parent;
|
||||
|
||||
this.$broadcast('$destroy');
|
||||
this.$$destroyed = true;
|
||||
if (this === $rootScope) return;
|
||||
|
||||
if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
|
||||
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
|
||||
@@ -710,7 +732,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
|
||||
* - `function(scope)`: execute the function with the current `scope` parameter.
|
||||
*
|
||||
*
|
||||
* @param {(object)=} locals Local variables object, useful for overriding values in scope.
|
||||
* @returns {*} The result of evaluating the expression.
|
||||
*/
|
||||
@@ -732,7 +754,7 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* - it will execute after the function that scheduled the evaluation (preferably before DOM
|
||||
* rendering).
|
||||
* - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
|
||||
* - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after
|
||||
* `expression` execution.
|
||||
*
|
||||
* Any exceptions from the execution of the expression are forwarded to the
|
||||
@@ -777,7 +799,7 @@ function $RootScopeProvider(){
|
||||
* framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
|
||||
* Because we are calling into the angular framework we need to perform proper scope life
|
||||
* cycle of {@link ng.$exceptionHandler exception handling},
|
||||
* {@link ng.$rootScope.Scope#$digest executing watches}.
|
||||
* {@link ng.$rootScope.Scope#methods_$digest executing watches}.
|
||||
*
|
||||
* ## Life cycle
|
||||
*
|
||||
@@ -798,11 +820,11 @@ function $RootScopeProvider(){
|
||||
* Scope's `$apply()` method transitions through the following stages:
|
||||
*
|
||||
* 1. The {@link guide/expression expression} is executed using the
|
||||
* {@link ng.$rootScope.Scope#$eval $eval()} method.
|
||||
* {@link ng.$rootScope.Scope#methods_$eval $eval()} method.
|
||||
* 2. Any exceptions from the execution of the expression are forwarded to the
|
||||
* {@link ng.$exceptionHandler $exceptionHandler} service.
|
||||
* 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
|
||||
* expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
|
||||
* 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the
|
||||
* expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method.
|
||||
*
|
||||
*
|
||||
* @param {(string|function())=} exp An angular expression to be executed.
|
||||
@@ -836,7 +858,7 @@ function $RootScopeProvider(){
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
|
||||
* Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for
|
||||
* discussion of event life cycle.
|
||||
*
|
||||
* The event listener function format is: `function(event, args...)`. The `event` object
|
||||
@@ -877,20 +899,20 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* @description
|
||||
* Dispatches an event `name` upwards through the scope hierarchy notifying the
|
||||
* registered {@link ng.$rootScope.Scope#$on} listeners.
|
||||
* registered {@link ng.$rootScope.Scope#methods_$on} listeners.
|
||||
*
|
||||
* The event life cycle starts at the scope on which `$emit` was called. All
|
||||
* {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
|
||||
* {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
|
||||
* notified. Afterwards, the event traverses upwards toward the root scope and calls all
|
||||
* registered listeners along the way. The event will stop propagating if one of the listeners
|
||||
* cancels it.
|
||||
*
|
||||
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
||||
* Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
|
||||
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
||||
*
|
||||
* @param {string} name Event name to emit.
|
||||
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
|
||||
* @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
|
||||
* @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
|
||||
*/
|
||||
$emit: function(name, args) {
|
||||
var empty = [],
|
||||
@@ -946,19 +968,19 @@ function $RootScopeProvider(){
|
||||
*
|
||||
* @description
|
||||
* Dispatches an event `name` downwards to all child scopes (and their children) notifying the
|
||||
* registered {@link ng.$rootScope.Scope#$on} listeners.
|
||||
* registered {@link ng.$rootScope.Scope#methods_$on} listeners.
|
||||
*
|
||||
* The event life cycle starts at the scope on which `$broadcast` was called. All
|
||||
* {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
|
||||
* {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
|
||||
* notified. Afterwards, the event propagates to all direct and indirect scopes of the current
|
||||
* scope and calls all registered listeners along the way. The event cannot be canceled.
|
||||
*
|
||||
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
|
||||
* Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
|
||||
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
|
||||
*
|
||||
* @param {string} name Event name to broadcast.
|
||||
* @param {...*} args Optional set of arguments which will be passed onto the event listeners.
|
||||
* @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
|
||||
* @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
|
||||
*/
|
||||
$broadcast: function(name, args) {
|
||||
var target = this,
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Private service to sanitize uris for links and images. Used by $compile and $sanitize.
|
||||
*/
|
||||
function $$SanitizeUriProvider() {
|
||||
var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
|
||||
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* urls during a[href] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into
|
||||
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
|
||||
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
|
||||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.aHrefSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
aHrefSanitizationWhitelist = regexp;
|
||||
return this;
|
||||
}
|
||||
return aHrefSanitizationWhitelist;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* urls during img[src] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into
|
||||
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
|
||||
* regular expression. If a match is found, the original url is written into the dom. Otherwise,
|
||||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.imgSrcSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
imgSrcSanitizationWhitelist = regexp;
|
||||
return this;
|
||||
}
|
||||
return imgSrcSanitizationWhitelist;
|
||||
};
|
||||
|
||||
this.$get = function() {
|
||||
return function sanitizeUri(uri, isImage) {
|
||||
var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
|
||||
var normalizedVal;
|
||||
// NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
|
||||
if (!msie || msie >= 8 ) {
|
||||
normalizedVal = urlResolve(uri).href;
|
||||
if (normalizedVal !== '' && !normalizedVal.match(regex)) {
|
||||
return 'unsafe:'+normalizedVal;
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -85,6 +85,7 @@ function $SnifferProvider() {
|
||||
vendorPrefix: vendorPrefix,
|
||||
transitions : transitions,
|
||||
animations : animations,
|
||||
android: android,
|
||||
msie : msie,
|
||||
msieDocumentMode: documentMode
|
||||
};
|
||||
|
||||
@@ -32,93 +32,6 @@ function $TimeoutProvider() {
|
||||
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
|
||||
* promise will be resolved with is the return value of the `fn` function.
|
||||
*
|
||||
* @example
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope,$timeout) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
|
||||
var stop;
|
||||
$scope.fight = function() {
|
||||
stop = $timeout(function() {
|
||||
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
|
||||
$scope.blood_1 = $scope.blood_1 - 3;
|
||||
$scope.blood_2 = $scope.blood_2 - 4;
|
||||
$scope.fight();
|
||||
} else {
|
||||
$timeout.cancel(stop);
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
$scope.stopFight = function() {
|
||||
$timeout.cancel(stop);
|
||||
};
|
||||
|
||||
$scope.resetFight = function() {
|
||||
$scope.blood_1 = 100;
|
||||
$scope.blood_2 = 120;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('time', [])
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $timeout and dateFilter service since the factory method is DI.
|
||||
.directive('myCurrentTime', function($timeout, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
timeoutId; // timeoutId, so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
// schedule update in one second
|
||||
function updateLater() {
|
||||
// save the timeoutId for canceling
|
||||
timeoutId = $timeout(function() {
|
||||
updateTime(); // update DOM
|
||||
updateLater(); // schedule another update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
});
|
||||
|
||||
updateLater(); // kick off the UI update process.
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model="format"> <hr/>
|
||||
Current time is: <span my-current-time="format"></span>
|
||||
<hr/>
|
||||
Blood 1 : <font color='red'>{{blood_1}}</font>
|
||||
Blood 2 : <font color='red'>{{blood_2}}</font>
|
||||
<button type="button" data-ng-click="fight()">Fight</button>
|
||||
<button type="button" data-ng-click="stopFight()">StopFight</button>
|
||||
<button type="button" data-ng-click="resetFight()">resetFight</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
*/
|
||||
function timeout(fn, delay, invokeApply) {
|
||||
var deferred = $q.defer(),
|
||||
|
||||
+4
-44
@@ -7,11 +7,6 @@
|
||||
// exactly the behavior needed here. There is little value is mocking these out for this
|
||||
// service.
|
||||
var urlParsingNode = document.createElement("a");
|
||||
/*
|
||||
Matches paths for file protocol on windows,
|
||||
such as /C:/foo/bar, and captures only /foo/bar.
|
||||
*/
|
||||
var windowsFilePathExp = /^\/?.*?:(\/.*)/;
|
||||
var originUrl = urlResolve(window.location.href, true);
|
||||
|
||||
|
||||
@@ -68,8 +63,7 @@ var originUrl = urlResolve(window.location.href, true);
|
||||
*
|
||||
*/
|
||||
function urlResolve(url, base) {
|
||||
var href = url,
|
||||
pathname;
|
||||
var href = url;
|
||||
|
||||
if (msie) {
|
||||
// Normalize before parse. Refer Implementation Notes on why this is
|
||||
@@ -80,21 +74,6 @@ function urlResolve(url, base) {
|
||||
|
||||
urlParsingNode.setAttribute('href', href);
|
||||
|
||||
/*
|
||||
* In Windows, on an anchor node on documents loaded from
|
||||
* the filesystem, the browser will return a pathname
|
||||
* prefixed with the drive name ('/C:/path') when a
|
||||
* pathname without a drive is set:
|
||||
* * a.setAttribute('href', '/foo')
|
||||
* * a.pathname === '/C:/foo' //true
|
||||
*
|
||||
* Inside of Angular, we're always using pathnames that
|
||||
* do not include drive names for routing.
|
||||
*/
|
||||
|
||||
pathname = removeWindowsDriveName(urlParsingNode.pathname, url, base);
|
||||
pathname = (pathname.charAt(0) === '/') ? pathname : '/' + pathname;
|
||||
|
||||
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
|
||||
return {
|
||||
href: urlParsingNode.href,
|
||||
@@ -104,11 +83,12 @@ function urlResolve(url, base) {
|
||||
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
|
||||
hostname: urlParsingNode.hostname,
|
||||
port: urlParsingNode.port,
|
||||
pathname: pathname
|
||||
pathname: (urlParsingNode.pathname.charAt(0) === '/')
|
||||
? urlParsingNode.pathname
|
||||
: '/' + urlParsingNode.pathname
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a request URL and determine whether this is a same-origin request as the application document.
|
||||
*
|
||||
@@ -121,23 +101,3 @@ function urlIsSameOrigin(requestUrl) {
|
||||
return (parsed.protocol === originUrl.protocol &&
|
||||
parsed.host === originUrl.host);
|
||||
}
|
||||
|
||||
function removeWindowsDriveName (path, url, base) {
|
||||
var firstPathSegmentMatch;
|
||||
|
||||
//Get the relative path from the input URL.
|
||||
if (url.indexOf(base) === 0) {
|
||||
url = url.replace(base, '');
|
||||
}
|
||||
|
||||
/*
|
||||
* The input URL intentionally contains a
|
||||
* first path segment that ends with a colon.
|
||||
*/
|
||||
if (windowsFilePathExp.exec(url)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
firstPathSegmentMatch = windowsFilePathExp.exec(path);
|
||||
return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user