Compare commits
264 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de38899f74 | |||
| 729c238e19 | |||
| dc3de7fb7a | |||
| ace40d5526 | |||
| fd8997551f | |||
| d8c8b2ebb7 | |||
| f5bb34ab4a | |||
| 4b83f6ca2c | |||
| a591e8b8d3 | |||
| 6b05105c08 | |||
| 728832ec85 | |||
| f1a75a445c | |||
| c59bee5d21 | |||
| 17ecf84b90 | |||
| df8d9507aa | |||
| 6e7fbe77c9 | |||
| 3686f45398 | |||
| ad28baaa6c | |||
| 8f9c4daca5 | |||
| f0c94ea292 | |||
| 729129b461 | |||
| bf2c55ea29 | |||
| deafb5e545 | |||
| 0702aef7ee | |||
| f0ee335311 | |||
| 02169d4957 | |||
| 25d0eff3e6 | |||
| bd41bd594c | |||
| 373d7c95d9 | |||
| 4c5c762378 | |||
| d1434c999a | |||
| 8b8f6f5124 | |||
| 25082b3439 | |||
| 27b3ea4d32 | |||
| ffc32b4e42 | |||
| 80b0909927 | |||
| efbb365533 | |||
| 38e0ab9bd8 | |||
| 3c53b28cc2 | |||
| 0ba864184b | |||
| 4f9dc44f88 | |||
| f3884df0a9 | |||
| f7a4a70c28 | |||
| 8428a0adef | |||
| 14a92a5982 | |||
| 798ed3be21 | |||
| 4627410245 | |||
| 7c6026437a | |||
| 76741a9393 | |||
| 8900390add | |||
| fca6be7127 | |||
| ec9c0d76fe | |||
| fd2d6c02f9 | |||
| cfdd16157e | |||
| 06280a14b4 | |||
| 8173382c4b | |||
| 55244390c8 | |||
| fb7e05cc38 | |||
| ea94e63e35 | |||
| e7ac08a061 | |||
| 7ffe524171 | |||
| 30354c58fe | |||
| 19871d28cf | |||
| 63761fdac1 | |||
| 3d367eb7b9 | |||
| d13b4bd1f5 | |||
| c1f2c3ea83 | |||
| 6af2ff2c7d | |||
| 67919c8087 | |||
| 5cf1d89692 | |||
| 58adaa6634 | |||
| 0eadee5c24 | |||
| 6a96a8200a | |||
| 871f321f50 | |||
| bd8a912774 | |||
| a3962f0df3 | |||
| eb4afd45f7 | |||
| 1c8a7459c9 | |||
| 9cd272ac60 | |||
| 1a1ef62903 | |||
| 3e51b84bc1 | |||
| a0d6e64889 | |||
| 1d36cff22e | |||
| 56f09f0b44 | |||
| 9314719d1e | |||
| 14183833f9 | |||
| d307e77ff3 | |||
| f0d3722e07 | |||
| fb39e322ea | |||
| d1318f7dc7 | |||
| c54990ca6e | |||
| 3c538c1d21 | |||
| 64c3b745fb | |||
| f94d551529 | |||
| 9ad7d745ab | |||
| 90cd1e0a1b | |||
| b3b476db7d | |||
| 456dcb020b | |||
| 7235329ff8 | |||
| 06fa2868de | |||
| bd8ad0fbe8 | |||
| 6639ca9d6b | |||
| 719f42e949 | |||
| 73916108f8 | |||
| ed63733000 | |||
| f33a938545 | |||
| 01ef12884b | |||
| 732d72d991 | |||
| 66103c8277 | |||
| fee8f1c07b | |||
| 6046e14bd2 | |||
| 2a5af502c5 | |||
| 9bedeb3353 | |||
| df9e60c8e7 | |||
| 41cec4d680 | |||
| 0f3ea45d73 | |||
| cddd48fe20 | |||
| be3b62cd09 | |||
| 40308e5935 | |||
| f6aa1c5561 | |||
| 43c67ccd16 | |||
| 1cfd49ddf0 | |||
| 907b8c1675 | |||
| 432aa9e4e4 | |||
| b95dabb881 | |||
| 0f3adece3b | |||
| e322cd9b3b | |||
| b3b672130d | |||
| 8b5d33dab8 | |||
| cbdaabfb59 | |||
| 3471fedfbc | |||
| c3a58a9f34 | |||
| 99d95f1639 | |||
| 48e66cff40 | |||
| adb5c6d6cc | |||
| b01a03c1b9 | |||
| 43e0dc2dfe | |||
| 976da56d50 | |||
| 088545c185 | |||
| b350283503 | |||
| 25541c1f87 | |||
| 7b273a2c97 | |||
| 3952408cf1 | |||
| 02bada130e | |||
| 712299c2a2 | |||
| 6d1e7cdc51 | |||
| 86c6be82e5 | |||
| ae952fbf0b | |||
| 73157b0a0b | |||
| 0ee0ce18c1 | |||
| 7f87988e41 | |||
| 9a09f1d96d | |||
| e96be5bfb8 | |||
| 095627ad17 | |||
| 1b4a2c8fee | |||
| b474c36e41 | |||
| 007e320835 | |||
| f211419be6 | |||
| 5dd9f138c7 | |||
| 821da26e18 | |||
| 300bffc4fe | |||
| 5b2a386b1f | |||
| 953ee22f76 | |||
| c3064f728c | |||
| 0f806d9659 | |||
| ac535549c9 | |||
| d9cdb105fc | |||
| 44cf2e1904 | |||
| ce25ac83b4 | |||
| d2d8117edd | |||
| 63fb60de86 | |||
| 29714a34ab | |||
| d5686ffc48 | |||
| 203ea10f9e | |||
| bf59d7274f | |||
| 995a8d39af | |||
| fc706d13d8 | |||
| 9525d0ad1d | |||
| e0d49a3109 | |||
| c5b32f14d5 | |||
| 2e0982c1ec | |||
| b2902446eb | |||
| 202aed7770 | |||
| 271572c20e | |||
| 550ba01b32 | |||
| 22948807e3 | |||
| b9007df590 | |||
| 0604bb7b7a | |||
| 92576743ee | |||
| c9b0bfecc9 | |||
| 2ae10f67fc | |||
| c2aaddbe4b | |||
| 6f7018d52f | |||
| 4f9ac078d5 | |||
| 9057ed21ac | |||
| c09f619318 | |||
| 1eda18365a | |||
| 77ce5b89f9 | |||
| c5f1ca3d91 | |||
| 7a36d49533 | |||
| cd21602d5b | |||
| 5f3f25a1a6 | |||
| cb73a37c7c | |||
| 49455a75dc | |||
| 85880a6490 | |||
| 46343c603d | |||
| 3b5d75c021 | |||
| 719c747cd8 | |||
| 2137542e09 | |||
| ab878a6c03 | |||
| 474a0337bd | |||
| 97a1b399b7 | |||
| c6bde52006 | |||
| 563be7e879 | |||
| e0489abd8d | |||
| 2218e6f8cd | |||
| cec9ecf951 | |||
| 36a547b852 | |||
| b3ec730c42 | |||
| 2ab0d5d370 | |||
| ac68ee49c1 | |||
| be8ef25a5a | |||
| 41c1b8858f | |||
| fce8915f39 | |||
| d4dd5dfa18 | |||
| a1e5cd5fe3 | |||
| 3660fd0912 | |||
| 4bca4c44b9 | |||
| a70e2833ea | |||
| 3be00df495 | |||
| 2efe1c2e7b | |||
| d8a02f9987 | |||
| a4520a745d | |||
| fe697527b4 | |||
| ea6fc6e69c | |||
| e94d454b84 | |||
| 2ae4f40be1 | |||
| db044c408a | |||
| 0e44ac2de0 | |||
| 5a1a0c9622 | |||
| 4ebbd7e210 | |||
| 5f90340abb | |||
| cc6fc199f5 | |||
| 29f0b568de | |||
| 4739b1d9da | |||
| feed7d6944 | |||
| 9da8d63ef4 | |||
| 0462b688f9 | |||
| 1b331f3729 | |||
| a6bd4bc866 | |||
| 23da614043 | |||
| bf0f5502b1 | |||
| 2f4437b3a1 | |||
| d0b41890bf | |||
| 7ef2921cae | |||
| 5e15b11509 | |||
| 42f28751e0 | |||
| b728030be0 | |||
| 2e3a7fd3e9 | |||
| fdf9989f7c | |||
| addfc567fd | |||
| a9371a1875 | |||
| 8ac90357a6 | |||
| 525a8f851e |
+1
-2
@@ -10,8 +10,7 @@ performance/temp*.html
|
||||
*.swp
|
||||
angular.js.tmproj
|
||||
/node_modules/
|
||||
/components/
|
||||
/bower_components/
|
||||
bower_components/
|
||||
angular.xcodeproj
|
||||
.idea
|
||||
.agignore
|
||||
|
||||
@@ -11,7 +11,6 @@ env:
|
||||
- JOB=unit
|
||||
- JOB=e2e TEST_TARGET=jqlite
|
||||
- JOB=e2e TEST_TARGET=jquery
|
||||
- JOB=e2e TEST_TARGET=doce2e
|
||||
global:
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
|
||||
+734
@@ -1,3 +1,729 @@
|
||||
<a name="1.3.0-rc.3"></a>
|
||||
# 1.3.0-rc.3 aggressive-pacification (2014-09-23)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **ngModel:** support milliseconds in time and datetime
|
||||
([4b83f6ca](https://github.com/angular/angular.js/commit/4b83f6ca2c15bd65fe2b3894a02c04f9967fbff4),
|
||||
[#8874](https://github.com/angular/angular.js/issues/8874))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$location:** add ability to opt-out of <base/> tag requirement in html5Mode
|
||||
([dc3de7fb](https://github.com/angular/angular.js/commit/dc3de7fb7a14c38b5c3dc7decfafb0b51d422dd1),
|
||||
[#8934](https://github.com/angular/angular.js/issues/8934))
|
||||
- **formController:** add $setUntouched to propagate untouched state
|
||||
([fd899755](https://github.com/angular/angular.js/commit/fd8997551f9ed4431f5e99d61f637139485076b9),
|
||||
[#9050](https://github.com/angular/angular.js/issues/9050))
|
||||
- **input:** support dynamic element validation
|
||||
([729c238e](https://github.com/angular/angular.js/commit/729c238e19ab27deff01448d79342ea53721bfed),
|
||||
[#4791](https://github.com/angular/angular.js/issues/4791), [#1404](https://github.com/angular/angular.js/issues/1404))
|
||||
- **ngAria:** add an ngAria module to make a11y easier
|
||||
([d1434c99](https://github.com/angular/angular.js/commit/d1434c999a66c6bb915ee1a8b091e497d288d940),
|
||||
[#5486](https://github.com/angular/angular.js/issues/5486))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **map:** use Array.prototype.map
|
||||
([a591e8b8](https://github.com/angular/angular.js/commit/a591e8b8d302efefd67bf0d5c4bad300a5f3aded))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$location:** due to [dc3de7fb](https://github.com/angular/angular.js/commit/dc3de7fb7a14c38b5c3dc7decfafb0b51d422dd1),
|
||||
The $location.html5Mode API has changed to allow enabling html5Mode by
|
||||
passing an object (as well as still supporting passing a boolean). Symmetrically, the
|
||||
method now returns an object instead of a boolean value.
|
||||
|
||||
To migrate, follow the code example below:
|
||||
|
||||
Before:
|
||||
|
||||
var mode = $locationProvider.html5Mode();
|
||||
|
||||
After:
|
||||
|
||||
var mode = $locationProvider.html5Mode().enabled;
|
||||
|
||||
Fixes #8934
|
||||
|
||||
|
||||
<a name="1.2.25"></a>
|
||||
# 1.2.25 hypnotic-gesticulation (2014-09-16)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **i18n:** fix typo at i18n generation code
|
||||
([1b6d74cc](https://github.com/angular/angular.js/commit/1b6d74cc9f7f7b7bd529abe6ce612de3ae661601))
|
||||
- **ngLocale:** Regenerate Locale Files
|
||||
([06c76694](https://github.com/angular/angular.js/commit/06c76694ac9b2280594712e6a4b46a1d5987d098))
|
||||
- **select:** update option labels when model changes
|
||||
([d89d59f4](https://github.com/angular/angular.js/commit/d89d59f453d4e28be4f595fea7e2c4ff2338351f),
|
||||
[#9025](https://github.com/angular/angular.js/issues/9025))
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-rc.2"></a>
|
||||
# 1.3.0-rc.2 tactile-perception (2014-09-16)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:** update `'@'`-bindings in controller when `bindToController` is `true`
|
||||
([e7ac08a0](https://github.com/angular/angular.js/commit/e7ac08a0619d2bdc91c125d341772b4fbc0d5a78),
|
||||
[#9052](https://github.com/angular/angular.js/issues/9052), [#9077](https://github.com/angular/angular.js/issues/9077))
|
||||
- **$parse:** ensure CSP assignable expressions have `assign()`
|
||||
([d13b4bd1](https://github.com/angular/angular.js/commit/d13b4bd1f5f2abaad00f5d1bf81f79549a8d0e46),
|
||||
[#9048](https://github.com/angular/angular.js/issues/9048))
|
||||
- **i18n:** fix typo at i18n generation code
|
||||
([eb4afd45](https://github.com/angular/angular.js/commit/eb4afd45f77d7d67744e01ce63a831c13c2b22e8))
|
||||
- **input:** always pass in the model value to `ctrl.$isEmpty`
|
||||
([3e51b84b](https://github.com/angular/angular.js/commit/3e51b84bc19f7e6acc61cb536ddcdbfed307c831),
|
||||
[#5164](https://github.com/angular/angular.js/issues/5164), [#9017](https://github.com/angular/angular.js/issues/9017))
|
||||
- **jqLite:** fix `event.stopImmediatePropagation()` so it works as expected
|
||||
([30354c58](https://github.com/angular/angular.js/commit/30354c58fe2bd371df364f7a3f55b270692a4051),
|
||||
[#4833](https://github.com/angular/angular.js/issues/4833))
|
||||
- **ngLocale:** Regenerate Locale Files
|
||||
([6a96a820](https://github.com/angular/angular.js/commit/6a96a8200aff4749bc84c44a1e8018b09d9ebdb4),
|
||||
[#8931](https://github.com/angular/angular.js/issues/8931), [#8583](https://github.com/angular/angular.js/issues/8583), [#7799](https://github.com/angular/angular.js/issues/7799))
|
||||
- **ngModel:**
|
||||
- do not reset bound date objects
|
||||
([1a1ef629](https://github.com/angular/angular.js/commit/1a1ef62903c8fdf4ceb81277d966a8eff67f0a96),
|
||||
[#6666](https://github.com/angular/angular.js/issues/6666))
|
||||
- don’t clear the model when an external validator failed
|
||||
([9314719d](https://github.com/angular/angular.js/commit/9314719d1eb5f480b877f5513f6e0e474edcb67d),
|
||||
[#8357](https://github.com/angular/angular.js/issues/8357), [#8080](https://github.com/angular/angular.js/issues/8080))
|
||||
- **ngResource:** make badcfg error message more helpful
|
||||
([a3962f0d](https://github.com/angular/angular.js/commit/a3962f0df3f9b8382b47952f9e4fcb48a4cc098b),
|
||||
[#9005](https://github.com/angular/angular.js/issues/9005), [#9010](https://github.com/angular/angular.js/issues/9010))
|
||||
- **select:** update option labels when model changes
|
||||
([46274102](https://github.com/angular/angular.js/commit/46274102454038ee7fd4543a32166e9bbbc98904),
|
||||
[#9025](https://github.com/angular/angular.js/issues/9025))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **limitTo:** support numeric input to limitTo
|
||||
([1c8a7459](https://github.com/angular/angular.js/commit/1c8a7459c90efc77b1a0987f976e3bddab4565fe),
|
||||
[#8926](https://github.com/angular/angular.js/issues/8926))
|
||||
- **ngInclude:** add template url parameter to events
|
||||
([fd2d6c02](https://github.com/angular/angular.js/commit/fd2d6c02f9654e753d3655a3377a9534f7a54de3),
|
||||
[#8453](https://github.com/angular/angular.js/issues/8453), [#8454](https://github.com/angular/angular.js/issues/8454))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:** move `$$isolateBinding` creation to directive factory instead of on each link
|
||||
([56f09f0b](https://github.com/angular/angular.js/commit/56f09f0b44048b62f964d29db4d3d2630662f6ea))
|
||||
- **$parse:**
|
||||
- execute watched expressions only when the inputs change
|
||||
([fca6be71](https://github.com/angular/angular.js/commit/fca6be71274e537c7df86ae9e27a3bd1597e9ffa),
|
||||
[#9006](https://github.com/angular/angular.js/issues/9006), [#9082](https://github.com/angular/angular.js/issues/9082))
|
||||
- remove `binaryFn` and `valueFn` wrappers from filter expressions
|
||||
([67919c80](https://github.com/angular/angular.js/commit/67919c808771a9b185a9d552cd32a90748d36666))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$parse:** due to [fca6be71](https://github.com/angular/angular.js/commit/fca6be71274e537c7df86ae9e27a3bd1597e9ffa),
|
||||
all filters are assumed to be stateless functions
|
||||
|
||||
Previously it was just a good practice to make all filters stateless. Now
|
||||
it's a requirement in order for the model change-observation to pick up
|
||||
all changes.
|
||||
|
||||
If an existing filter is statefull, it can be flagged as such but keep in
|
||||
mind that this will result in a significant performance-penalty (or rather
|
||||
lost opportunity to benefit from a major perf improvement) that will
|
||||
affect the `$digest` duration.
|
||||
|
||||
To flag a filter as stateful do the following:
|
||||
|
||||
```javascript
|
||||
myApp.filter('myFilter', function() {
|
||||
function myFilter(input) { ... };
|
||||
myFilter.$stateful = true;
|
||||
return myFilter;
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-rc.1"></a>
|
||||
# 1.3.0-rc.1 backyard-atomicity (2014-09-09)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$location:**
|
||||
- don't call toString on null values
|
||||
([c3a58a9f](https://github.com/angular/angular.js/commit/c3a58a9f34919f121587540e03ecbd51b25198d4))
|
||||
- remove an unused parameter of $location.url
|
||||
([99d95f16](https://github.com/angular/angular.js/commit/99d95f1639b64c39231448d77209676b54e6f0be))
|
||||
- allow numeric location setter arguments
|
||||
([adb5c6d6](https://github.com/angular/angular.js/commit/adb5c6d6cc76b928436743707727ab0974d6810b),
|
||||
[#7054](https://github.com/angular/angular.js/issues/7054))
|
||||
- set `baseHref` in mock browser to `/`
|
||||
([fc706d13](https://github.com/angular/angular.js/commit/fc706d13d80bb40eb3dade58ea4b92dca33ce4e7),
|
||||
[#8866](https://github.com/angular/angular.js/issues/8866), [#8889](https://github.com/angular/angular.js/issues/8889))
|
||||
- **$parse:** disallow passing Function to Array.sort
|
||||
([bd8ad0fb](https://github.com/angular/angular.js/commit/bd8ad0fbe81f6c280baa26a596d78e58fc7842e6))
|
||||
- **input:** check `scope.$$phase` only on `$rootScope`
|
||||
([bf59d727](https://github.com/angular/angular.js/commit/bf59d7274f4a667c5b19e6d4ba5ed2730ca2fe42))
|
||||
- **ngAnimate:** support removing classes from SVG elements when using jQuery
|
||||
([b3b67213](https://github.com/angular/angular.js/commit/b3b672130d4d1c6f13bdf7e58be76b2aafea2497),
|
||||
[#8872](https://github.com/angular/angular.js/issues/8872), [#8893](https://github.com/angular/angular.js/issues/8893))
|
||||
- **ngEventDirs:** check `scope.$$phase` only on `$rootScope`
|
||||
([203ea10f](https://github.com/angular/angular.js/commit/203ea10f9ea49d7e29569a4232d3b2a666307cd8),
|
||||
[#8891](https://github.com/angular/angular.js/issues/8891))
|
||||
- **ngForm:** don't clear validity of whole form when removing control
|
||||
([953ee22f](https://github.com/angular/angular.js/commit/953ee22f76f8c1137949ed07f36fafc5bbfeb7fe),
|
||||
[#8863](https://github.com/angular/angular.js/issues/8863))
|
||||
- **ngInclude:** correctly add svg-namespaced template content
|
||||
([6639ca9d](https://github.com/angular/angular.js/commit/6639ca9d6bc00a6e3a31e54c50474361ae3561c6),
|
||||
[#7538](https://github.com/angular/angular.js/issues/7538), [#8981](https://github.com/angular/angular.js/issues/8981), [#8997](https://github.com/angular/angular.js/issues/8997))
|
||||
- **ngModel:**
|
||||
- update model value with async validators correctly
|
||||
([64c3b745](https://github.com/angular/angular.js/commit/64c3b745fba0792166f30e057f9251f263d80dac))
|
||||
- render immediately also with async validators
|
||||
([f94d5515](https://github.com/angular/angular.js/commit/f94d551529b7c970c38b29e3073cec4e7f6b0e00))
|
||||
- properly parse min/max date values as strings for date inputs
|
||||
([088545c1](https://github.com/angular/angular.js/commit/088545c1856ce1c3ec3416965dff65077a6e0523),
|
||||
[#6755](https://github.com/angular/angular.js/issues/6755))
|
||||
- revalidate the model when min/max expression values change for date inputs
|
||||
([b3502835](https://github.com/angular/angular.js/commit/b3502835039178296b730b7526e5666b66ba9156),
|
||||
[#6755](https://github.com/angular/angular.js/issues/6755))
|
||||
- consider ngMin/ngMax values when validating number input types
|
||||
([25541c1f](https://github.com/angular/angular.js/commit/25541c1f876a16c892d71faae11727bec7bba98c))
|
||||
- revalidate the model when min/max expression values change for number inputs
|
||||
([7b273a2c](https://github.com/angular/angular.js/commit/7b273a2c978d5f5ef374f5335afab0ca7d8cfd4d),
|
||||
[#2404](https://github.com/angular/angular.js/issues/2404))
|
||||
- **ngModelOptions:** do not trigger digest on `setViewValue` if debouncing
|
||||
([e322cd9b](https://github.com/angular/angular.js/commit/e322cd9b3b8b47b95c9de3edf631bb46f919c492),
|
||||
[#8814](https://github.com/angular/angular.js/issues/8814), [#8850](https://github.com/angular/angular.js/issues/8850), [#8911](https://github.com/angular/angular.js/issues/8911))
|
||||
- **ngRepeat:** preserve original position of elements that are being animated away
|
||||
([ed637330](https://github.com/angular/angular.js/commit/ed6373300028deda9a0878b3975699d183c1f75c),
|
||||
[#8918](https://github.com/angular/angular.js/issues/8918), [#8994](https://github.com/angular/angular.js/issues/8994))
|
||||
- **ngSwitch:** ensure correct iterator is passed to async function
|
||||
([712299c2](https://github.com/angular/angular.js/commit/712299c2a24390e74cd5c20f51cb1d78f0233b6f),
|
||||
[#8833](https://github.com/angular/angular.js/issues/8833))
|
||||
- **numberFilter:** format numbers that round to zero as nonnegative
|
||||
([ae952fbf](https://github.com/angular/angular.js/commit/ae952fbf0be925a48743d1c925ffe4e31a42c280),
|
||||
[#8489](https://github.com/angular/angular.js/issues/8489))
|
||||
- **orderBy:** allow arrayLike objects to be ordered
|
||||
([cbdaabfb](https://github.com/angular/angular.js/commit/cbdaabfb59bf3348588d5b581f2754e0f9f034a4),
|
||||
[#8944](https://github.com/angular/angular.js/issues/8944))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **angular.forEach:** add the array/object as the 3rd param like the native array forEach
|
||||
([df9e60c8](https://github.com/angular/angular.js/commit/df9e60c8e7453cdca2cb5a4fa48f3981ecc23a7d),
|
||||
[#7902](https://github.com/angular/angular.js/issues/7902))
|
||||
- **ngModelOptions:** add allowInvalid option
|
||||
([3c538c1d](https://github.com/angular/angular.js/commit/3c538c1d21c43422c7b4cd9b69cb67981bce2b87),
|
||||
[#8290](https://github.com/angular/angular.js/issues/8290), [#8313](https://github.com/angular/angular.js/issues/8313))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$parse:**
|
||||
- remove getterFn wrapper for internal use
|
||||
([b3b476db](https://github.com/angular/angular.js/commit/b3b476db7d34bc2f8b099ab5b993b1e899b9cffd),
|
||||
[#8901](https://github.com/angular/angular.js/issues/8901))
|
||||
- removing references to Parser/Lexer from parsed expressions
|
||||
([43c67ccd](https://github.com/angular/angular.js/commit/43c67ccd167aecc3549e1b7f7d100956204e3ed4))
|
||||
- calculate array lengths once at start of loop
|
||||
([907b8c16](https://github.com/angular/angular.js/commit/907b8c1675865ac38dd055f3f304272e68b233d0))
|
||||
- **extend:** remove use of forEach to remove calls/closures/passing arguments
|
||||
([9bedeb33](https://github.com/angular/angular.js/commit/9bedeb3353969fba631ad9164edea3c38059fbda),
|
||||
[#8898](https://github.com/angular/angular.js/issues/8898))
|
||||
- **jQuery:** only trigger $destroy if a handler exists
|
||||
([f6aa1c55](https://github.com/angular/angular.js/commit/f6aa1c55616b34215f562e0445e436210860ef04),
|
||||
[#8859](https://github.com/angular/angular.js/issues/8859))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngModelController,formController:** due to [6046e14b](https://github.com/angular/angular.js/commit/6046e14bd22491168116e61ffdf5fd3fed5f135c),
|
||||
|
||||
- `ctrl.$error` no longer contains entries for validators that were
|
||||
successful.
|
||||
- `ctrl.$setValidity` now differentiates between `true`, `false`,
|
||||
`undefined` and `null`, instead of previously only truthy vs falsy.
|
||||
|
||||
Closes #8941- **ngSwitch:** due to [0f806d96](https://github.com/angular/angular.js/commit/0f806d9659b5b89a4bd9493364bc36398677e939),
|
||||
|
||||
|
||||
Ever since 0df93fd, tagged in v1.0.0rc1, the ngSwitch directive has had an undocumented `change`
|
||||
attribute, used for evaluating a scope expression when the switch value changes.
|
||||
|
||||
While it's unlikely, applications which may be using this feature should work around the removal
|
||||
by adding a custom directive which will perform the eval instead. Directive controllers are
|
||||
re-instantiated when being transcluded, so by putting the attribute on each item that you want
|
||||
to be notified of a change to, you can more or less emulate the old behaviour.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
angular.module("switchChangeWorkaround", []).
|
||||
directive("onSwitchChanged", function() {
|
||||
return {
|
||||
link: function($scope, $element, $attrs) {
|
||||
$scope.$parent.$eval($attrs.onSwitchChanged);
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<div ng-switch="switcher">
|
||||
<div ng-switch-when="a" on-switch-changed="doSomethingInParentScope()"></div>
|
||||
<div ng-switch-when="b" on-switch-changed="doSomethingInParentScope()"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Closes #8858
|
||||
Closes #8822
|
||||
|
||||
|
||||
<a name="1.2.24"></a>
|
||||
# 1.2.24 static-levitation (2014-09-09)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$browser:** detect changes to the browser url that happened in sync
|
||||
([2ece4d03](https://github.com/angular/angular.js/commit/2ece4d0347a8a18d4d35993bb882ed6b5b24266c),
|
||||
[#6976](https://github.com/angular/angular.js/issues/6976))
|
||||
- **$compile:**
|
||||
- render nested transclusion at the root of a template
|
||||
([9d9cdfb5](https://github.com/angular/angular.js/commit/9d9cdfb575b89e96ae957c986734a49995e2b511),
|
||||
[#8914](https://github.com/angular/angular.js/issues/8914), [#8925](https://github.com/angular/angular.js/issues/8925))
|
||||
- render nested transclusion at the root of a template
|
||||
([466320f6](https://github.com/angular/angular.js/commit/466320f6911698048bae5406e341d25af7efafa0),
|
||||
[#8914](https://github.com/angular/angular.js/issues/8914), [#8925](https://github.com/angular/angular.js/issues/8925))
|
||||
- **$location:**
|
||||
- don't call toString on null values
|
||||
([c12e8d46](https://github.com/angular/angular.js/commit/c12e8d4665b635ba6b09d12802efb88d38b7ad5c))
|
||||
- remove an unused parameter of $location.url
|
||||
([c65796d4](https://github.com/angular/angular.js/commit/c65796d496038554861e70da8012f9d0e2521e6d))
|
||||
- allow numeric location setter arguments
|
||||
([68a09ba7](https://github.com/angular/angular.js/commit/68a09ba74d10a1490feca1d248f85b0023aa399b),
|
||||
[#7054](https://github.com/angular/angular.js/issues/7054))
|
||||
- **$parse:** disallow passing Function to Array.sort
|
||||
([b39e1d47](https://github.com/angular/angular.js/commit/b39e1d47b9a1b39a9fe34c847a81f589fba522f8))
|
||||
- **form:** ensure concurrent animations use setClass
|
||||
([d7548fdf](https://github.com/angular/angular.js/commit/d7548fdf1ce6f543bf55d330985a83ef09d0cb83),
|
||||
[#8166](https://github.com/angular/angular.js/issues/8166))
|
||||
- **input:** check `scope.$$phase` only on `$rootScope`
|
||||
([36e6de1d](https://github.com/angular/angular.js/commit/36e6de1d91937d73e900ac115ae366fbefcdf6da))
|
||||
- **ngEventDirs:**
|
||||
- check `scope.$$phase` only on `$rootScope`
|
||||
([2712c2f1](https://github.com/angular/angular.js/commit/2712c2f1979db23eeb53be8a519b9f79bd75e217),
|
||||
[#8891](https://github.com/angular/angular.js/issues/8891))
|
||||
- execute `blur` and `focus` expression using `scope.$evalAsync`
|
||||
([54f0bc0f](https://github.com/angular/angular.js/commit/54f0bc0fe0c6b6d974d23f2c5ef07359dd93eb99),
|
||||
[#4979](https://github.com/angular/angular.js/issues/4979), [#5945](https://github.com/angular/angular.js/issues/5945), [#8803](https://github.com/angular/angular.js/issues/8803), [#6910](https://github.com/angular/angular.js/issues/6910), [#5402](https://github.com/angular/angular.js/issues/5402))
|
||||
- **ngRepeat:** improve errors for duplicate items
|
||||
([1812af58](https://github.com/angular/angular.js/commit/1812af58c2d470d586c2a543c9a7db3f0baca04f))
|
||||
- **numberFilter:** format numbers that round to zero as nonnegative
|
||||
([7e02fa07](https://github.com/angular/angular.js/commit/7e02fa07eb5b02e75b1db0058d638af3d1074942),
|
||||
[#8489](https://github.com/angular/angular.js/issues/8489))
|
||||
- **orderBy:** allow arrayLike objects to be ordered
|
||||
([94b0f2d3](https://github.com/angular/angular.js/commit/94b0f2d35de601ded3d93ea4fa78a4d9b139c0a0),
|
||||
[#8944](https://github.com/angular/angular.js/issues/8944))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **ngEventDirs:** due to [54f0bc0f](https://github.com/angular/angular.js/commit/54f0bc0fe0c6b6d974d23f2c5ef07359dd93eb99),
|
||||
|
||||
The `blur` and `focus` event fire synchronously, also during DOM operations
|
||||
that remove elements. This lead to errors as the Angular model was not
|
||||
in a consistent state. See this [fiddle](http://jsfiddle.net/fq1dq5yb/) for a demo.
|
||||
|
||||
This change executes the expression of those events using
|
||||
`scope.$evalAsync` if an `$apply` is in progress, otherwise
|
||||
keeps the old behavior.
|
||||
|
||||
Fixes #4979
|
||||
Fixes #5945
|
||||
Closes #8803
|
||||
Closes #6910
|
||||
Closes #5402
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.3.0-RC.0"></a>
|
||||
# 1.3.0-RC.0 sonic-boltification (2014-08-29)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$animate:**
|
||||
- wait two until two digests are over until enabling animations
|
||||
([92576743](https://github.com/angular/angular.js/commit/92576743eec0cef5ffdd701b83f72a61e6489c3b),
|
||||
[#8844](https://github.com/angular/angular.js/issues/8844))
|
||||
- ensure guarded animations consider AJAX requests upon bootstrap
|
||||
([4bca4c44](https://github.com/angular/angular.js/commit/4bca4c44b95a7435722605a750804043f2960160),
|
||||
[#8275](https://github.com/angular/angular.js/issues/8275), [#5262](https://github.com/angular/angular.js/issues/5262))
|
||||
- use $timeout to handle the delay within staggering animations
|
||||
([23da6140](https://github.com/angular/angular.js/commit/23da614043fe5dcf0be132b86466eecb11c766a2),
|
||||
[#7228](https://github.com/angular/angular.js/issues/7228), [#7547](https://github.com/angular/angular.js/issues/7547), [#8297](https://github.com/angular/angular.js/issues/8297), [#8547](https://github.com/angular/angular.js/issues/8547))
|
||||
- **$browser:** detect changes to the browser url that happened in sync
|
||||
([3be00df4](https://github.com/angular/angular.js/commit/3be00df495f6eed3b3d9587ebab1fdd633e94e08),
|
||||
[#6976](https://github.com/angular/angular.js/issues/6976))
|
||||
- **$compile:** use the correct namespace for transcluded svg elements
|
||||
([cb73a37c](https://github.com/angular/angular.js/commit/cb73a37c7cae5cdebadf7b3ddd44c5a452495e4e),
|
||||
[#8808](https://github.com/angular/angular.js/issues/8808), [#8816](https://github.com/angular/angular.js/issues/8816))
|
||||
- **$location:** always resolve relative links in html5mode to `<base>` url
|
||||
([22948807](https://github.com/angular/angular.js/commit/22948807e324eb0b182b15b31045dc306a9f3231),
|
||||
[#8492](https://github.com/angular/angular.js/issues/8492), [#8172](https://github.com/angular/angular.js/issues/8172))
|
||||
- **$parse:** properly handle dots at the end of identifiers
|
||||
([8ac90357](https://github.com/angular/angular.js/commit/8ac90357a66ae0c62dbfe6db2c6eaf1d600ecc65),
|
||||
[#4613](https://github.com/angular/angular.js/issues/4613), [#4912](https://github.com/angular/angular.js/issues/4912), [#8559](https://github.com/angular/angular.js/issues/8559))
|
||||
- **Angular:** remove duplicate nodeName_ references
|
||||
([a4520a74](https://github.com/angular/angular.js/commit/a4520a745d917c77f1d12cdbce48272c643f7255))
|
||||
- **currencyFilter:** pass through null and undefined values
|
||||
([c2aaddbe](https://github.com/angular/angular.js/commit/c2aaddbe4b21348aab8c13a78cdd6aaee846ae4e),
|
||||
[#8605](https://github.com/angular/angular.js/issues/8605))
|
||||
- **docs:** don't throw exception on the 404 page
|
||||
([550ba01b](https://github.com/angular/angular.js/commit/550ba01b325fc29460030fc9c24fa00269dec2a9),
|
||||
[#8518](https://github.com/angular/angular.js/issues/8518))
|
||||
- **input:**
|
||||
- validate minlength/maxlength for non-string values
|
||||
([77ce5b89](https://github.com/angular/angular.js/commit/77ce5b89f97aa83c3eb1fe2e19375ef00a822015),
|
||||
[#7967](https://github.com/angular/angular.js/issues/7967), [#8811](https://github.com/angular/angular.js/issues/8811))
|
||||
- allow to use seconds in `input[time]` and `input[datetime-local]`
|
||||
([5f90340a](https://github.com/angular/angular.js/commit/5f90340abb78aa08dde4876328bcc00e46232e46))
|
||||
- use year 1970 instead of 1900 for `input[time]`
|
||||
([29f0b568](https://github.com/angular/angular.js/commit/29f0b568debab7810752969d363d337099e96cdc))
|
||||
- **ngBindHtml:** throw error if interpolation is used in expression
|
||||
([cd21602d](https://github.com/angular/angular.js/commit/cd21602d5b1650d8be373618cb7320d697e32c4d),
|
||||
[#8824](https://github.com/angular/angular.js/issues/8824))
|
||||
- **ngEventDirs:** execute `blur` and `focus` expression using `scope.$evalAsync`
|
||||
([719c747c](https://github.com/angular/angular.js/commit/719c747cd892ee933e7e414a7dc97e657b88317d),
|
||||
[#4979](https://github.com/angular/angular.js/issues/4979), [#5945](https://github.com/angular/angular.js/issues/5945), [#8803](https://github.com/angular/angular.js/issues/8803), [#6910](https://github.com/angular/angular.js/issues/6910), [#5402](https://github.com/angular/angular.js/issues/5402))
|
||||
- **ngModel:**
|
||||
- always format the viewValue as a string for text, url and email types
|
||||
([1eda1836](https://github.com/angular/angular.js/commit/1eda18365a348c9597aafba9d195d345e4f13d1e))
|
||||
- allow non-assignable binding when getterSetter is used
|
||||
([ab878a6c](https://github.com/angular/angular.js/commit/ab878a6c038f47b95f3a7e85a4fdb599e0c73e63),
|
||||
[#8704](https://github.com/angular/angular.js/issues/8704))
|
||||
- treat undefined parse responses as parse errors
|
||||
([db044c40](https://github.com/angular/angular.js/commit/db044c408a7f8082758b96ab739348810c36e15a))
|
||||
- **ngRepeat:** improve errors for duplicate items
|
||||
([0604bb7b](https://github.com/angular/angular.js/commit/0604bb7b7a6156e33679396e805e327662d9a178))
|
||||
- **ngSwitch:** avoid removing DOM nodes twice within watch operation
|
||||
([c9b0bfec](https://github.com/angular/angular.js/commit/c9b0bfecc99837af1c97792b3ca3408ba182b0bb),
|
||||
[#8662](https://github.com/angular/angular.js/issues/8662))
|
||||
- **numberFilter:** pass through null and undefined values
|
||||
([2ae10f67](https://github.com/angular/angular.js/commit/2ae10f67fcde3e172f695956301ef796b68a50c2),
|
||||
[#8605](https://github.com/angular/angular.js/issues/8605), [#8842](https://github.com/angular/angular.js/issues/8842))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **core:**
|
||||
- add angular.reloadWithDebugInfo()
|
||||
([41c1b88](https://github.com/angular/angular.js/commit/41c1b8858f02c7310bfabdd545ebb28e90eb4258))
|
||||
- **$animate:**
|
||||
- use promises instead of callbacks for animations
|
||||
([bf0f5502](https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9))
|
||||
- coalesce concurrent class-based animations within a digest loop
|
||||
([2f4437b3](https://github.com/angular/angular.js/commit/2f4437b3a149eafb899f25933bd6c713b167d10e))
|
||||
- **$compile:**
|
||||
- bind isolate scope properties to controller
|
||||
([5f3f25a1](https://github.com/angular/angular.js/commit/5f3f25a1a6f9d4f2a66e2700df3b9c5606f1c255),
|
||||
[#7635](https://github.com/angular/angular.js/issues/7635), [#7645](https://github.com/angular/angular.js/issues/7645))
|
||||
- allow disabling scope info
|
||||
([a1e5cd5f](https://github.com/angular/angular.js/commit/a1e5cd5fe3906ebee8c400247a1f793d3e2239fb))
|
||||
- **$compile/ngBind:** allow disabling binding info
|
||||
([3660fd09](https://github.com/angular/angular.js/commit/3660fd0912d3ccf6def8c9f02d8d4c0621c8d91f))
|
||||
- **$http:** implement mechanism for coalescing calls to $apply in $http
|
||||
([ea6fc6e6](https://github.com/angular/angular.js/commit/ea6fc6e69c2a2aa213c71ed4e917a0d54d064e4c),
|
||||
[#8736](https://github.com/angular/angular.js/issues/8736), [#7634](https://github.com/angular/angular.js/issues/7634), [#5297](https://github.com/angular/angular.js/issues/5297))
|
||||
- **$rootScope:** implement $applyAsync to support combining calls to $apply into a single digest.
|
||||
([e94d454b](https://github.com/angular/angular.js/commit/e94d454b840f6cc55a440741382b407836ad245b))
|
||||
- **$templateRequest:** introduce the $templateRequest service
|
||||
([a70e2833](https://github.com/angular/angular.js/commit/a70e2833ea276107b11aafea96ef4a6724ad4d83))
|
||||
- **filter:** allow to define the timezone for formatting dates
|
||||
([4739b1d9](https://github.com/angular/angular.js/commit/4739b1d9daebfd094b6181c5f2cb52ff71e31c61))
|
||||
- **filterFilter:** pass index to function predicate
|
||||
([46343c60](https://github.com/angular/angular.js/commit/46343c603db6192daf5303b92eb664749326c7e6),
|
||||
[#654](https://github.com/angular/angular.js/issues/654))
|
||||
- **input:** allow to define the timezone for parsing dates
|
||||
([cc6fc199](https://github.com/angular/angular.js/commit/cc6fc199f5abaacdf781aa03634337d776eb0fc9),
|
||||
[#8447](https://github.com/angular/angular.js/issues/8447))
|
||||
- **minErr:** allow specifying ErrorConstructor in minErr constructor
|
||||
([a6bd4bc8](https://github.com/angular/angular.js/commit/a6bd4bc866a18f860c7548fa1b3f6d4c2a953416))
|
||||
- **ngModel:** provide validation API functions for sync and async validations
|
||||
([2ae4f40b](https://github.com/angular/angular.js/commit/2ae4f40be1803d999ca2a8cc30ec17ff19ea6d86))
|
||||
- **ngRoute:** alias string as redirectTo property in .otherwise()
|
||||
([3b5d75c0](https://github.com/angular/angular.js/commit/3b5d75c021e21fa6ec4dc6c47b8eafa55680ea63),
|
||||
[#7794](https://github.com/angular/angular.js/issues/7794))
|
||||
- **testability:** add $$testability service
|
||||
([85880a64](https://github.com/angular/angular.js/commit/85880a64900fa22a61feb926bf52de0965332ca5))
|
||||
|
||||
|
||||
## Performance Improvements
|
||||
|
||||
- **$compile:**
|
||||
- add debug classes in compile phase
|
||||
([e0489abd](https://github.com/angular/angular.js/commit/e0489abd8d9e4971ae23cc38805a92d227d1f3a1))
|
||||
- only iterate over elements with link functions
|
||||
([fdf9989f](https://github.com/angular/angular.js/commit/fdf9989f7cf1ed81982a788b75a338ac33334571),
|
||||
[#8741](https://github.com/angular/angular.js/issues/8741))
|
||||
- **nodeName_:** simplify the code and reduce the number of DOM calls
|
||||
([5a1a0c96](https://github.com/angular/angular.js/commit/5a1a0c96220101b5e040f0755e5eb401e2c73f65))
|
||||
- **select:** execute render after $digest cycle
|
||||
([6f7018d5](https://github.com/angular/angular.js/commit/6f7018d52fa4f9f9c7fa8e3035317d1239efb20f),
|
||||
[#8825](https://github.com/angular/angular.js/issues/8825))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$location**: due to [22948807](https://github.com/angular/angular.js/commit/22948807e324eb0b182b15b31045dc306a9f3231)
|
||||
|
||||
#### since 1.2.0 and 1.3.0-beta.1
|
||||
|
||||
Angular now requires a `<base>` tag when html5 mode of `$location` is enabled. Reasoning:
|
||||
Using html5 mode without a `<base href="...">` tag makes relative links for images, links, ...
|
||||
relative to the current url if the browser supports
|
||||
the history API. However, if the browser does not support the history API Angular falls back to using the `#`,
|
||||
and then all those relative links would be broken.
|
||||
|
||||
The `<base>` tag is also needed when a deep url is loaded from the server, e.g. `http://server/some/page/url`.
|
||||
In that case, Angular needs to decide which part of the url is the base of the application, and which part
|
||||
is path inside of the application.
|
||||
|
||||
To summarize: Now all relative links are always relative to the `<base>` tag.
|
||||
|
||||
Exception (also a breaking change):
|
||||
Link tags whose `href` attribute starts with a `#` will only change the hash of the url, but nothing else
|
||||
(e.g. `<a href="#someAnchor">`). This is to make it easy to scroll to anchors inside a document.
|
||||
|
||||
Related to #6162
|
||||
Closes #8492
|
||||
|
||||
#### since 1.2.17 and 1.3.0-beta.10
|
||||
|
||||
In html5 mode without a `<base>` tag on older browser that don't support the history API
|
||||
relative paths were adding up. E.g. clicking on `<a href="page1">` and then on `<a href="page2">`
|
||||
would produce `$location.path()==='/page1/page2'`. The code that introduced this behavior was removed
|
||||
and Angular now also requires a `<base>` tag to be present when using html5 mode.
|
||||
|
||||
Closes #8172, #8233
|
||||
|
||||
|
||||
- **ngInclude, ngMessage, ngView and directives that load templates**: due to [a70e2833](https://github.com/angular/angular.js/commit/a70e2833ea276107b11aafea96ef4a6724ad4d83)
|
||||
|
||||
Angular will now throw a $compile minErr each a template fails to download
|
||||
for ngView, directives and ngMessage template requests. This changes the former
|
||||
behavior of silently ignoring failed HTTP requests--or when the template itself
|
||||
is empty. Please ensure that all directive, ngView and ngMessage code now properly
|
||||
addresses this scenario. NgInclude is uneffected from this change.
|
||||
|
||||
|
||||
- **$animate**: due to [23da6140](https://github.com/angular/angular.js/commit/23da614043fe5dcf0be132b86466eecb11c766a2)
|
||||
|
||||
If any stagger code consisted of having BOTH transition staggers and delay staggers
|
||||
together then that will not work the same way. Angular will now instead choose
|
||||
the highest stagger delay value and set the timeout to wait for that before
|
||||
applying the active CSS class.
|
||||
|
||||
|
||||
- **$animate**: due to [bf0f5502](https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9)
|
||||
|
||||
Both the API for the cancallation method and the done callback for
|
||||
$animate animations is different. Instead of using a callback function
|
||||
for each of the $animate animation methods, a promise is used instead.
|
||||
|
||||
```js
|
||||
//before
|
||||
$animate.enter(element, container, null, callbackFn);
|
||||
|
||||
//after
|
||||
$animate.enter(element, container).then(callbackFn);
|
||||
```
|
||||
|
||||
The animation can now be cancelled via `$animate.cancel(promise)`.
|
||||
|
||||
```js
|
||||
//before
|
||||
var cancelFn = $animate.enter(element, container);
|
||||
cancelFn(); //cancels the animation
|
||||
|
||||
//after
|
||||
var promise = $animate.enter(element, container);
|
||||
$animate.cancel(promise); //cancels the animation
|
||||
```
|
||||
|
||||
keep in mind that you will still need to run $scope.$apply inside of the `then` callback
|
||||
to trigger a digest.
|
||||
|
||||
|
||||
- **$animate**: due to [2f4437b3](https://github.com/angular/angular.js/commit/2f4437b3a149eafb899f25933bd6c713b167d10e)
|
||||
|
||||
$animate.addClass, $animate.removeClass and $animate.setClass will no longer start the animation
|
||||
right after being called in the directive code. The animation will only commence once a digest
|
||||
has passed. This means that all animation-related testing code requires an extra digest to kick
|
||||
off the animation.
|
||||
|
||||
```js
|
||||
//before this fix
|
||||
$animate.addClass(element, 'super');
|
||||
expect(element).toHaveClass('super');
|
||||
|
||||
//now
|
||||
$animate.addClass(element, 'super');
|
||||
$rootScope.$digest();
|
||||
expect(element).toHaveClass('super');
|
||||
```
|
||||
|
||||
$animate will also tally the amount of times classes are added and removed and only animate
|
||||
the left over classes once the digest kicks in. This means that for any directive code that
|
||||
adds and removes the same CSS class on the same element then this may result in no animation
|
||||
being triggered at all.
|
||||
|
||||
```js
|
||||
$animate.addClass(element, 'klass');
|
||||
$animate.removeClass(element, 'klass');
|
||||
|
||||
$rootScope.$digest();
|
||||
|
||||
//nothing happens...
|
||||
```
|
||||
|
||||
|
||||
- **$compile/ngBind:** due to [3660fd09](https://github.com/angular/angular.js/commit/3660fd0912d3ccf6def8c9f02d8d4c0621c8d91f),
|
||||
|
||||
The value of `$binding` data property on an element is always an array now
|
||||
and the expressions do not include the curly braces `{{ ... }}`.
|
||||
|
||||
|
||||
- **currencyFilter:** due to [c2aaddbe](https://github.com/angular/angular.js/commit/c2aaddbe4b21348aab8c13a78cdd6aaee846ae4e),
|
||||
previously the currency filter would convert null and undefined values into empty string, after this change
|
||||
these values will be passed through.
|
||||
|
||||
Only cases when the currency filter is chained with another filter that doesn't expect null/undefined will be affected. This
|
||||
should be very rare.
|
||||
|
||||
This change will not change the visual output of the filter because the interpolation will convert the null/undefined to
|
||||
an empty string.
|
||||
|
||||
Closes #8605
|
||||
|
||||
|
||||
- **numberFilter:** due to [2ae10f67](https://github.com/angular/angular.js/commit/2ae10f67fcde3e172f695956301ef796b68a50c2),
|
||||
previously the number filter would convert null and undefined values into empty string, after this change
|
||||
these values will be passed through.
|
||||
|
||||
Only cases when the number filter is chained with another filter that doesn't expect null/undefined will be affected. This
|
||||
should be very rare.
|
||||
|
||||
This change will not change the visual output of the filter because the interpolation will convert the null/undefined to
|
||||
an empty string.
|
||||
|
||||
Closes #8605
|
||||
Closes #8842
|
||||
|
||||
|
||||
- **input:**
|
||||
- due to [77ce5b89](https://github.com/angular/angular.js/commit/77ce5b89f97aa83c3eb1fe2e19375ef00a822015),
|
||||
|
||||
NgModel.viewValue will always be used when rendering validations for `minlength` and `maxlength`.
|
||||
|
||||
Closes #7967
|
||||
Closes #8811
|
||||
|
||||
- **input:**
|
||||
- due to [29f0b568](https://github.com/angular/angular.js/commit/29f0b568debab7810752969d363d337099e96cdc),
|
||||
|
||||
|
||||
According to the HTML5 spec `input[time]` should create dates
|
||||
based on the year 1970 (used to be based on the year 1900).
|
||||
|
||||
Related to #8447.
|
||||
|
||||
|
||||
- **ngModel**: due to [db044c40](https://github.com/angular/angular.js/commit/db044c408a7f8082758b96ab739348810c36e15a)
|
||||
|
||||
Any parser code from before that returned an `undefined` value
|
||||
(or nothing at all) will now cause a parser failure. When this occurs
|
||||
none of the validators present in `$validators` will run until the parser
|
||||
error is gone. The error will be stored on `ngModel.$error`.
|
||||
|
||||
|
||||
|
||||
|
||||
- **ngEventDirs:** due to [719c747c](https://github.com/angular/angular.js/commit/719c747cd892ee933e7e414a7dc97e657b88317d),
|
||||
|
||||
The `blur` and `focus` event fire synchronously, also during DOM operations
|
||||
that remove elements. This lead to errors as the Angular model was not
|
||||
in a consistent state. See this [fiddle](http://jsfiddle.net/fq1dq5yb/) for a demo.
|
||||
|
||||
This change executes the expression of those events using
|
||||
`scope.$evalAsync` if an `$apply` is in progress, otherwise
|
||||
keeps the old behavior.
|
||||
|
||||
Fixes #4979
|
||||
Fixes #5945
|
||||
Closes #8803
|
||||
Closes #6910
|
||||
Closes #5402
|
||||
|
||||
- **$compile:** due to [5f3f25a1](https://github.com/angular/angular.js/commit/5f3f25a1a6f9d4f2a66e2700df3b9c5606f1c255),
|
||||
|
||||
The returned value from directive controller constructors are now ignored, and only the constructed
|
||||
instance itself will be attached to the node's expando. This change is necessary in order to ensure
|
||||
that it's possible to bind properties to the controller's instance before the actual constructor is
|
||||
invoked, as a convenience to developers.
|
||||
|
||||
In the past, the following would have worked:
|
||||
|
||||
```js
|
||||
angular.module("myApp", []).
|
||||
directive("myDirective", function() {
|
||||
return {
|
||||
controller: function($scope) {
|
||||
return {
|
||||
doAThing: function() { $scope.thingDone = true; },
|
||||
undoAThing: function() { $scope.thingDone = false; }
|
||||
};
|
||||
},
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
ctrl.doAThing();
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
However now, the reference to `doAThing()` will be undefined, because the return value of the controller's constructor is ignored. In order to work around this, one can opt for several strategies, including the use of `_.extend()` or `merge()` like routines, like so:
|
||||
|
||||
```js
|
||||
angular.module("myApp", []).
|
||||
directive("myDirective", function() {
|
||||
return {
|
||||
controller: function($scope) {
|
||||
_.extend(this, {
|
||||
doAThing: function() { $scope.thingDone = true; },
|
||||
undoAThing: function() { $scope.thingDone = false; }
|
||||
});
|
||||
},
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
ctrl.doAThing();
|
||||
}
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
<a name="1.2.23"></a>
|
||||
# 1.2.23 superficial-malady (2014-08-22)
|
||||
|
||||
@@ -1281,6 +2007,7 @@ this limitation, use a regular expression object as the value for the expression
|
||||
|
||||
//after
|
||||
$scope.exp = /abc/i;
|
||||
|
||||
- **Scope:** due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
|
||||
Scope#$id is now of time number rather than string. Since the
|
||||
id is primarily being used for debugging purposes this change should not affect
|
||||
@@ -2381,6 +3108,13 @@ For more info: http://blog.angularjs.org/2013/12/angularjs-13-new-release-approa
|
||||
application if 100s of elements are being inserted into the page. Therefore after this
|
||||
change callbacks are only fired if registered on the element being animated.
|
||||
|
||||
- **input:**
|
||||
- due to [a9fcb0d0](https://github.com/angular/angular.js/commit/a9fcb0d0fc6456f80501b8820d02b04d7c15b6d6),
|
||||
input[type=file] will no longer support ngModel. Due to browser support being spotty among target browsers,
|
||||
file inputs cannot be cleanly supported, and even features which technically do work (such as ng-change)
|
||||
work in an inconsistent way depending on the attributes of the form control.
|
||||
|
||||
As a workaround, one can manually listen for change events on file inputs and handle them manually.
|
||||
|
||||
<a name="1.2.12"></a>
|
||||
# 1.2.12 cauliflower-eradication (2014-02-07)
|
||||
|
||||
+9
-1
@@ -153,6 +153,9 @@ module.exports = function(grunt) {
|
||||
},
|
||||
ngTouch: {
|
||||
files: { src: 'src/ngTouch/**/*.js' },
|
||||
},
|
||||
ngAria: {
|
||||
files: {src: 'src/ngAria/**/*.js'},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -220,6 +223,10 @@ module.exports = function(grunt) {
|
||||
dest: 'build/angular-cookies.js',
|
||||
src: util.wrap(files['angularModules']['ngCookies'], 'module')
|
||||
},
|
||||
aria: {
|
||||
dest: 'build/angular-aria.js',
|
||||
src: util.wrap(files['angularModules']['ngAria'], 'module')
|
||||
},
|
||||
"promises-aplus-adapter": {
|
||||
dest:'tmp/promises-aplus-adapter++.js',
|
||||
src:['src/ng/q.js','lib/promises-aplus/promises-aplus-test-adapter.js']
|
||||
@@ -236,7 +243,8 @@ module.exports = function(grunt) {
|
||||
touch: 'build/angular-touch.js',
|
||||
resource: 'build/angular-resource.js',
|
||||
route: 'build/angular-route.js',
|
||||
sanitize: 'build/angular-sanitize.js'
|
||||
sanitize: 'build/angular-sanitize.js',
|
||||
aria: 'build/angular-aria.js'
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -6,16 +6,17 @@ use good old HTML (or HAML, Jade and friends!) as your template language and let
|
||||
syntax to express your application’s components clearly and succinctly. It automatically
|
||||
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
|
||||
binding. To help you structure your application better and make it easy to test, AngularJS teaches
|
||||
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
|
||||
server-side communication, taming async callbacks with promises and deferreds; and makes client-side
|
||||
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
|
||||
it makes development fun!
|
||||
the browser how to do dependency injection and inversion of control.
|
||||
|
||||
Oh yeah and it helps with server-side communication, taming async callbacks with promises and
|
||||
deferreds. It also makes client-side navigation and deeplinking with hashbang urls or HTML5 pushState a
|
||||
piece of cake. The best of all: it makes development fun!
|
||||
|
||||
* Web site: http://angularjs.org
|
||||
* Tutorial: http://docs.angularjs.org/tutorial
|
||||
* API Docs: http://docs.angularjs.org/api
|
||||
* Developer Guide: http://docs.angularjs.org/guide
|
||||
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
|
||||
* Contribution guidelines: [CONTRIBUTING.md](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md)
|
||||
* Dashboard: http://dashboard.angularjs.org
|
||||
|
||||
Building AngularJS
|
||||
@@ -37,7 +38,7 @@ To execute end-to-end (e2e) tests, use:
|
||||
grunt test:e2e
|
||||
|
||||
To learn more about the grunt tasks, run `grunt --help` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
|
||||
[contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
|
||||
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
@@ -26,7 +26,6 @@ This process based on the idea of minimizing user pain
|
||||
* You can triage older issues as well
|
||||
* Triage to your heart's content
|
||||
1. Assign yourself: Pick an issue that is not assigned to anyone and assign it to you
|
||||
|
||||
1. Understandable? - verify if the description of the request is clear.
|
||||
* If not, [close it][] according to the instructions below and go to the last step.
|
||||
1. Duplicate?
|
||||
@@ -36,7 +35,6 @@ This process based on the idea of minimizing user pain
|
||||
* Label `Type: Bug`
|
||||
* Reproducible? - Steps to reproduce the bug are clear. If they are not, ask for a clarification. If there's no reply after a week, [close it][].
|
||||
* Reproducible on master? - <http://code.angularjs.org/snapshot/>
|
||||
|
||||
1. Non bugs:
|
||||
* Label `Type: Feature`, `Type: Chore`, or `Type: Perf`
|
||||
* Belongs in core? – Often new features should be implemented as a third-party module rather than an addition to the core.
|
||||
@@ -59,7 +57,6 @@ This process based on the idea of minimizing user pain
|
||||
* In rare cases, it's ok to have multiple components.
|
||||
1. Label `PRs plz!` - These issues are good targets for PRs from the open source community. Apply to issues where the problem and solution are well defined in the comments, and it's not too complex.
|
||||
1. Label `origin: google` for issues from Google
|
||||
|
||||
1. Assign a milestone:
|
||||
* Backlog - triaged fixes and features, should be the default choice
|
||||
* Current 1.x.y milestone (e.g. 1.3.0-beta-2) - regressions and urgent bugs only
|
||||
|
||||
Vendored
+11
-3
@@ -34,6 +34,8 @@ var angularFiles = {
|
||||
'src/ng/sanitizeUri.js',
|
||||
'src/ng/sce.js',
|
||||
'src/ng/sniffer.js',
|
||||
'src/ng/templateRequest.js',
|
||||
'src/ng/testability.js',
|
||||
'src/ng/timeout.js',
|
||||
'src/ng/urlUtils.js',
|
||||
'src/ng/window.js',
|
||||
@@ -106,6 +108,9 @@ var angularFiles = {
|
||||
'src/ngTouch/directive/ngClick.js',
|
||||
'src/ngTouch/directive/ngSwipe.js'
|
||||
],
|
||||
'ngAria': [
|
||||
'src/ngAria/aria.js'
|
||||
]
|
||||
},
|
||||
|
||||
'angularScenario': [
|
||||
@@ -139,7 +144,8 @@ var angularFiles = {
|
||||
'test/ngRoute/**/*.js',
|
||||
'test/ngSanitize/**/*.js',
|
||||
'test/ngMock/*.js',
|
||||
'test/ngTouch/**/*.js'
|
||||
'test/ngTouch/**/*.js',
|
||||
'test/ngAria/*.js'
|
||||
],
|
||||
|
||||
'karma': [
|
||||
@@ -173,7 +179,8 @@ var angularFiles = {
|
||||
'test/ngRoute/**/*.js',
|
||||
'test/ngResource/*.js',
|
||||
'test/ngSanitize/**/*.js',
|
||||
'test/ngTouch/**/*.js'
|
||||
'test/ngTouch/**/*.js',
|
||||
'test/ngAria/*.js'
|
||||
],
|
||||
|
||||
'karmaJquery': [
|
||||
@@ -201,7 +208,8 @@ angularFiles['angularSrcModules'] = [].concat(
|
||||
angularFiles['angularModules']['ngRoute'],
|
||||
angularFiles['angularModules']['ngSanitize'],
|
||||
angularFiles['angularModules']['ngMock'],
|
||||
angularFiles['angularModules']['ngTouch']
|
||||
angularFiles['angularModules']['ngTouch'],
|
||||
angularFiles['angularModules']['ngAria']
|
||||
);
|
||||
|
||||
if (exports) {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
var app = angular.module('largetableBenchmark', []);
|
||||
|
||||
app.config(function($compileProvider) {
|
||||
if ($compileProvider.debugInfoEnabled) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('noop', function() {
|
||||
return function(input) {
|
||||
return input;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div>ngBind + fnInvocation: <input type=radio ng-model="benchmarkType" value="ngBindFn"></div>
|
||||
<div>interpolation + fnInvocation: <input type=radio ng-model="benchmarkType" value="interpolationFn"></div>
|
||||
<div>ngBind + filter: <input type=radio ng-model="benchmarkType" value="ngBindFilter"></div>
|
||||
<div>ngBind + filter: <input type=radio ng-model="benchmarkType" value="interpolationFilter"></div>
|
||||
<div>interpolation + filter: <input type=radio ng-model="benchmarkType" value="interpolationFilter"></div>
|
||||
|
||||
<ng-switch on="benchmarkType">
|
||||
<baseline-binding-table ng-switch-when="baselineBinding">
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
var app = angular.module('orderByBenchmark', []);
|
||||
|
||||
app.controller('DataController', function($rootScope, $scope) {
|
||||
this.ngRepeatCount = 5000;
|
||||
this.rows = [];
|
||||
var self = this;
|
||||
|
||||
$scope.benchmarkType = 'basic';
|
||||
|
||||
$scope.rawProperty = function(key) {
|
||||
return function(item) {
|
||||
return item[key];
|
||||
};
|
||||
};
|
||||
|
||||
// Returns a random integer between min (included) and max (excluded)
|
||||
function getRandomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'setup',
|
||||
description: 'Set rows to empty array and apply, then push new rows to be applied in next step',
|
||||
fn: function() {
|
||||
var oldRows = self.rows;
|
||||
$rootScope.$apply(function() {
|
||||
self.rows = [];
|
||||
});
|
||||
self.rows = oldRows;
|
||||
if (self.rows.length !== self.ngRepeatCount) {
|
||||
self.rows = [];
|
||||
for (var i = 0; i < self.ngRepeatCount; i++) {
|
||||
self.rows.push({
|
||||
'name': getRandomInt(i, (i + 40)),
|
||||
'index': i
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$apply',
|
||||
fn: function() {
|
||||
$rootScope.$apply();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [
|
||||
{
|
||||
"id": "jquery",
|
||||
"src": "jquery-noop.js"
|
||||
},{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},{
|
||||
src: 'app.js',
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
<div class="container-fluid" ng-app="orderByBenchmark">
|
||||
<div class="row" ng-controller="DataController as ctrl">
|
||||
<div class="col-lg-8">
|
||||
<p>Filters</p>
|
||||
|
||||
<p>
|
||||
<label>Number of ngRepeats:</label>
|
||||
<input type="number" ng-model="ctrl.ngRepeatCount">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" ng-model="benchmarkType" value="baseline">baseline
|
||||
</label>
|
||||
</div>
|
||||
<pre><code>ng-repeat="row in ctrl.rows"</code></pre>
|
||||
<br />
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" ng-model="benchmarkType" value="orderBy">orderBy
|
||||
</label>
|
||||
</div>
|
||||
<pre><code>ng-repeat="row in ctrl.rows | orderBy:'name'"</code></pre>
|
||||
<br />
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" ng-model="benchmarkType" value="orderByArray">orderBy array expression
|
||||
</label>
|
||||
</div>
|
||||
<pre><code>ng-repeat="row in ctrl.rows | orderBy:['name', 'index']"</code></pre>
|
||||
<br />
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" ng-model="benchmarkType"
|
||||
value="orderByFunction">orderBy function expression
|
||||
</label>
|
||||
</div>
|
||||
<pre><code>ng-repeat="row in ctrl.rows | orderBy:rawProperty('name')"</code></pre>
|
||||
<br />
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" ng-model="benchmarkType"
|
||||
value="orderByArrayFunction">orderBy array function expression
|
||||
</label>
|
||||
</div>
|
||||
<pre><code>ng-repeat="row in ctrl.rows | orderBy:[rawProperty('name'), rawProperty('index')]"</code></pre>
|
||||
</p>
|
||||
|
||||
|
||||
Debug output:
|
||||
<ng-switch on="benchmarkType">
|
||||
<div ng-switch-when="baseline">
|
||||
<span ng-repeat="row in ctrl.rows">
|
||||
<span ng-bind="row.name"></span>,
|
||||
</span>
|
||||
</div>
|
||||
<div ng-switch-when="orderBy">
|
||||
<span ng-repeat="row in ctrl.rows | orderBy:'name'">
|
||||
<span ng-bind="row.name"></span>,
|
||||
</span>
|
||||
</div>
|
||||
<div ng-switch-when="orderByArray">
|
||||
<span ng-repeat="row in ctrl.rows | orderBy:['name', 'index']">
|
||||
<span ng-bind="row.name"></span>,
|
||||
</span>
|
||||
</div>
|
||||
<div ng-switch-when="orderByFunction">
|
||||
<span ng-repeat="row in ctrl.rows | orderBy:rawProperty('name')">
|
||||
<span ng-bind="row.name"></span>,
|
||||
</span>
|
||||
</div>
|
||||
<div ng-switch-when="orderByArrayFunction">
|
||||
<span ng-repeat="row in ctrl.rows | orderBy:[rawProperty('name'), rawProperty('index')]">
|
||||
<span ng-bind="row.name"></span>,
|
||||
</span>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
var app = angular.module('parsedExpressionBenchmark', []);
|
||||
|
||||
app.config(function($compileProvider) {
|
||||
if ($compileProvider.debugInfoEnabled) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
app.filter('noop', function() {
|
||||
return function(input) {
|
||||
return input;
|
||||
};
|
||||
});
|
||||
|
||||
//Executes the specified expression as a watcher
|
||||
app.directive('bmPeWatch', function() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, $attrs) {
|
||||
$element.text( $attrs.bmPeWatch );
|
||||
return function($scope, $element, $attrs) {
|
||||
$scope.$watch($attrs.bmPeWatch, function(val) {
|
||||
$element.text(val);
|
||||
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
//Executes the specified expression as a watcher
|
||||
//Adds a simple wrapper method to allow use of $watch instead of $watchCollection
|
||||
app.directive('bmPeWatchLiteral', function($parse) {
|
||||
function retZero() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, $attrs) {
|
||||
$element.text( $attrs.bmPeWatchLiteral );
|
||||
return function($scope, $element, $attrs) {
|
||||
$scope.$watch( $parse($attrs.bmPeWatchLiteral, retZero) );
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('DataController', function($scope, $rootScope) {
|
||||
var totalRows = 10000;
|
||||
|
||||
var data = $scope.data = [];
|
||||
|
||||
var star = '*';
|
||||
|
||||
$scope.func = function() { return star;};
|
||||
|
||||
for (var i=0; i<totalRows; i++) {
|
||||
data.push({
|
||||
index: i,
|
||||
odd: i%2 === 0,
|
||||
even: i%2 === 1,
|
||||
str0: "foo-" + Math.random()*Date.now(),
|
||||
str1: "bar-" + Math.random()*Date.now(),
|
||||
str2: "baz-" + Math.random()*Date.now(),
|
||||
num0: Math.random()*Date.now(),
|
||||
num1: Math.random()*Date.now(),
|
||||
num2: Math.random()*Date.now(),
|
||||
date0: new Date(Math.random()*Date.now()),
|
||||
date1: new Date(Math.random()*Date.now()),
|
||||
date2: new Date(Math.random()*Date.now()),
|
||||
func: function(){ return star; },
|
||||
obj: data[i-1],
|
||||
keys: data[i-1] && (data[i-1].keys || Object.keys(data[i-1]))
|
||||
});
|
||||
}
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$apply',
|
||||
fn: function() {
|
||||
for (var i=0; i<50; i++) {
|
||||
$rootScope.$digest();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [ {
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
src: 'app.js',
|
||||
}]
|
||||
});
|
||||
};
|
||||
Executable
+209
@@ -0,0 +1,209 @@
|
||||
<div ng-app="parsedExpressionBenchmark" ng-cloak>
|
||||
<div ng-controller="DataController">
|
||||
<div class="container-fluid">
|
||||
<p>
|
||||
Tests the execution of $parse()ed expressions. Each test tries to isolate specific expression types. Expressions should (probably) not be constant so they get evaluated per digest.
|
||||
</p>
|
||||
|
||||
<ul style="list-style:none">
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="simplePath" id="simplePath">
|
||||
<label for="simplePath">Simple Paths</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="complexPath" id="complexPath">
|
||||
<label for="complexPath">Complex Paths</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="fieldAccess" id="fieldAccess">
|
||||
<label for="fieldAccess">Field Accessors</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="fieldIndex" id="fieldIndex">
|
||||
<label for="fieldIndex">Field Indexes</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="operators" id="operators">
|
||||
<label for="operators">Binary/Unary operators</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="shortCircuitingOperators" id="shortCircuitingOperators">
|
||||
<label for="shortCircuitingOperators">AND/OR short-circuiting operators</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="filters" id="filters">
|
||||
<label for="filters">Filters</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="functionCalls" id="functionCalls">
|
||||
<label for="functionCalls">Function calls</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="objectLiterals" id="objectLiterals">
|
||||
<label for="objectLiterals">Object Literals</label>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<input type="radio" ng-model="expressionType" value="arrayLiterals" id="arrayLiterals">
|
||||
<label for="arrayLiterals">Array Literals</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!--
|
||||
NOTES:
|
||||
- ensure each tested expression has at least one variable in it to avoid constant expressions
|
||||
-->
|
||||
|
||||
<ul ng-switch="expressionType">
|
||||
<li ng-switch-when="simplePath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="rowIdx"></span>
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.num0"></span>
|
||||
<span bm-pe-watch="row.num1"></span>
|
||||
<span bm-pe-watch="row.num2"></span>
|
||||
<span bm-pe-watch="row.str0"></span>
|
||||
<span bm-pe-watch="row.str1"></span>
|
||||
<span bm-pe-watch="row.str2"></span>
|
||||
<span bm-pe-watch="row.date0"></span>
|
||||
<span bm-pe-watch="row.obj"></span>
|
||||
<span bm-pe-watch="row.keys"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="complexPath" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="row.index"></span>
|
||||
<span bm-pe-watch="row.num0"></span>
|
||||
<span bm-pe-watch="row.num1"></span>
|
||||
<span bm-pe-watch="row.str0"></span>
|
||||
<span bm-pe-watch="row.str1"></span>
|
||||
<span bm-pe-watch="row.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.obj.obj.index"></span>
|
||||
<span bm-pe-watch="row.obj.obj.obj.index"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="fieldAccess" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="data[rowIdx].index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].num0"></span>
|
||||
<span bm-pe-watch="data[rowIdx].num1"></span>
|
||||
<span bm-pe-watch="data[rowIdx].str0"></span>
|
||||
<span bm-pe-watch="data[rowIdx].str1"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.obj.obj.index"></span>
|
||||
<span bm-pe-watch="data[rowIdx].obj.obj.obj.index"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="fieldIndex" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="data[rowIdx]"></span>
|
||||
<span bm-pe-watch="row['str0']"></span>
|
||||
<span bm-pe-watch="row['str1']"></span>
|
||||
<span bm-pe-watch="data[row['index']]['index']"></span>
|
||||
<span bm-pe-watch="data[rowIdx]['obj']"></span>
|
||||
<span bm-pe-watch="data[rowIdx]['obj']['obj']"></span>
|
||||
<span bm-pe-watch="row[row['keys'][0]]"></span>
|
||||
<span bm-pe-watch="row[row['keys'][1]]"></span>
|
||||
<span bm-pe-watch="row[row['keys'][2]]"></span>
|
||||
<span bm-pe-watch="row[row['keys'][3]]"></span>
|
||||
<span bm-pe-watch="row[row['keys'][4]]"></span>
|
||||
<span bm-pe-watch="row[row['keys'][5]]"></span>
|
||||
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="operators" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="+rowIdx"></span>
|
||||
<span bm-pe-watch="-rowIdx"></span>
|
||||
<span bm-pe-watch="rowIdx + 1"></span>
|
||||
<span bm-pe-watch="rowIdx - 1"></span>
|
||||
<span bm-pe-watch="rowIdx * 2"></span>
|
||||
<span bm-pe-watch="rowIdx + -1"></span>
|
||||
<span bm-pe-watch="rowIdx - -1"></span>
|
||||
<span bm-pe-watch="-rowIdx * 2 + 1"></span>
|
||||
<span bm-pe-watch="rowIdx % 2"></span>
|
||||
<span bm-pe-watch="rowIdx % 2 === 1"></span>
|
||||
<span bm-pe-watch="rowIdx % 2 === 0"></span>
|
||||
<span bm-pe-watch="rowIdx / 1"></span>
|
||||
<span bm-pe-watch="-rowIdx * 2 * rowIdx + rowIdx / rowIdx + 1"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="shortCircuitingOperators" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="rowIdx && row.odd"></span>
|
||||
<span bm-pe-watch="row.odd && row.even"></span>
|
||||
<span bm-pe-watch="row.odd && !row.even"></span>
|
||||
<span bm-pe-watch="row.odd || row.even"></span>
|
||||
<span bm-pe-watch="row.odd || row.even || row.index"></span>
|
||||
<span bm-pe-watch="row.index === 1 || row.index === 2"></span>
|
||||
<span bm-pe-watch="row.num0 < row.num1 && row.num1 < row.num2"></span>
|
||||
<span bm-pe-watch="row.num0 < row.num1 || row.num1 < row.num2"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="filters" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="rowIdx | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:1"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:rowIdx"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:1:2:3:4:5"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:rowIdx:rowIdx:rowIdx"></span>
|
||||
<span bm-pe-watch="rowIdx | noop | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:1 | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop | noop:null:undefined:0"></span>
|
||||
<span bm-pe-watch="rowIdx | noop | noop | noop"></span>
|
||||
<span bm-pe-watch="rowIdx | noop:1 | noop:2 | noop:3"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="functionCalls" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch="func()"></span>
|
||||
<span bm-pe-watch="func(1)"></span>
|
||||
<span bm-pe-watch="func(1, 2)"></span>
|
||||
<span bm-pe-watch="func(1, 2, 3)"></span>
|
||||
<span bm-pe-watch="row.func()"></span>
|
||||
<span bm-pe-watch="row.func(1)"></span>
|
||||
<span bm-pe-watch="row.func(1, 2)"></span>
|
||||
<span bm-pe-watch="row.func(1, 2, 3)"></span>
|
||||
<span bm-pe-watch="func(func())"></span>
|
||||
<span bm-pe-watch="func(func(), func())"></span>
|
||||
<span bm-pe-watch="row.func(row.func())"></span>
|
||||
<span bm-pe-watch="row.func(row.func(), row.func())"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="objectLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch-literal="{foo: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{foo: row, bar: rowIdx}"></span>
|
||||
<span bm-pe-watch-literal="{0: row, 1: rowIdx, 2: 3}"></span>
|
||||
<span bm-pe-watch-literal="{str: 'foo', num: rowIdx, b: true}"></span>
|
||||
<span bm-pe-watch-literal="{a: {b: {c: {d: {e: {f: rowIdx}}}}}}"></span>
|
||||
<span bm-pe-watch-literal="{a: rowIdx, b: 1, c: 2, d: 3, e: 4, f: 5, g: rowIdx, h: 6, i: 7, j: 8, k: rowIdx}"></span>
|
||||
</li>
|
||||
|
||||
<li ng-switch-when="arrayLiterals" ng-repeat="(rowIdx, row) in ::data">
|
||||
<span bm-pe-watch-literal="[rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, 0, 1, 2, 3]"></span>
|
||||
<span bm-pe-watch-literal="[[], [rowIdx], [], [], [3], [[[]]]]"></span>
|
||||
<span bm-pe-watch-literal="[rowIdx, undefined, null, true, false]"></span>
|
||||
<span bm-pe-watch-literal="[[][0], [0][0], [][rowIdx]]"></span>
|
||||
<span bm-pe-watch-literal="[0, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, rowIdx]"></span>
|
||||
<span bm-pe-watch-literal="[0, 1, 2, 3, rowIdx]"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+2
-6
@@ -2,11 +2,7 @@
|
||||
"name": "AngularJS",
|
||||
"devDependencies": {
|
||||
"jquery": "2.1.1",
|
||||
"lunr.js": "0.4.3",
|
||||
"open-sans-fontface": "1.0.4",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip",
|
||||
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip",
|
||||
"bootstrap": "3.1.1"
|
||||
"closure-compiler": "https://dl.google.com/closure-compiler/compiler-20140814.zip",
|
||||
"ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ then(allInSeries(function (branch) {
|
||||
line = line.split(' ');
|
||||
var sha = line.shift();
|
||||
var msg = line.join(' ');
|
||||
return sha + (msg.toLowerCase().indexOf('fix') === -1 ? ' ' : ' * ') + msg;
|
||||
return sha + ((/fix\([^\)]+\):/i.test(msg)) ? ' * ' : ' ') + msg;
|
||||
});
|
||||
branch.log = log.map(function (line) {
|
||||
return line.substr(41);
|
||||
|
||||
@@ -316,10 +316,10 @@ iframe.example {
|
||||
}
|
||||
|
||||
.search-results-group.col-group-api { width:30%; }
|
||||
.search-results-group.col-group-guide { width:30%; }
|
||||
.search-results-group.col-group-tutorial { width:25%; }
|
||||
.search-results-group.col-group-guide,
|
||||
.search-results-group.col-group-tutorial { width:20%; }
|
||||
.search-results-group.col-group-misc,
|
||||
.search-results-group.col-group-error { float:right; clear:both; width:15% }
|
||||
.search-results-group.col-group-error { width:15%; float: right; }
|
||||
|
||||
|
||||
.search-results-group.col-group-api .search-result {
|
||||
@@ -391,7 +391,6 @@ iframe.example {
|
||||
position:fixed;
|
||||
top:120px;
|
||||
bottom:0;
|
||||
padding-bottom:120px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
@@ -412,6 +411,7 @@ iframe.example {
|
||||
|
||||
.main-body-grid .side-navigation {
|
||||
position:relative;
|
||||
padding-bottom:120px;
|
||||
}
|
||||
|
||||
.main-body-grid .side-navigation.ng-hide {
|
||||
@@ -635,12 +635,14 @@ ul.events > li {
|
||||
display:inline-block;
|
||||
padding:3px 0;
|
||||
}
|
||||
.nav-index-group .nav-index-listing:not(.nav-index-section) + .nav-index-listing:not(.nav-index-section):after {
|
||||
padding-right:5px;
|
||||
content:", ";
|
||||
.nav-index-group .nav-index-listing:not(.nav-index-section):after {
|
||||
padding-right:5px;
|
||||
margin-left:-3px;
|
||||
content:", ";
|
||||
}
|
||||
.nav-index-group .nav-index-listing:last-child {
|
||||
.nav-index-group .nav-index-listing:last-child:after {
|
||||
content:"";
|
||||
display:inline-block;
|
||||
}
|
||||
.nav-index-group .nav-index-section {
|
||||
display:block;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
/* jshint browser: true */
|
||||
/* global importScripts, onmessage: true, postMessage, lunr */
|
||||
|
||||
// Load up the lunr library
|
||||
importScripts('../components/lunr.js-0.4.2/lunr.min.js');
|
||||
|
||||
// Create the lunr index - the docs should be an array of object, each object containing
|
||||
// the path and search terms for a page
|
||||
var index = lunr(function() {
|
||||
this.ref('path');
|
||||
this.field('titleWords', {boost: 50});
|
||||
this.field('members', { boost: 40});
|
||||
this.field('keywords', { boost : 20 });
|
||||
});
|
||||
|
||||
// Retrieve the searchData which contains the information about each page to be indexed
|
||||
var searchData = {};
|
||||
var searchDataRequest = new XMLHttpRequest();
|
||||
searchDataRequest.onload = function() {
|
||||
|
||||
// Store the pages data to be used in mapping query results back to pages
|
||||
searchData = JSON.parse(this.responseText);
|
||||
// Add search terms from each page to the search index
|
||||
searchData.forEach(function(page) {
|
||||
index.add(page);
|
||||
});
|
||||
postMessage({ e: 'index-ready' });
|
||||
};
|
||||
searchDataRequest.open('GET', 'search-data.json');
|
||||
searchDataRequest.send();
|
||||
|
||||
// The worker receives a message everytime the web app wants to query the index
|
||||
onmessage = function(oEvent) {
|
||||
var q = oEvent.data.q;
|
||||
var hits = index.search(q);
|
||||
var results = [];
|
||||
// Only return the array of paths to pages
|
||||
hits.forEach(function(hit) {
|
||||
results.push(hit.ref);
|
||||
});
|
||||
// The results of the query are sent back to the web app via a new message
|
||||
postMessage({ e: 'query-ready', q: q, d: results });
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"extends": "../../../.jshintrc-base",
|
||||
|
||||
"globals": {
|
||||
|
||||
/* jasmine / karma */
|
||||
"it": false,
|
||||
"iit": false,
|
||||
"describe": false,
|
||||
"ddescribe": false,
|
||||
"beforeEach": false,
|
||||
"afterEach": false,
|
||||
"expect": false,
|
||||
"jasmine": false,
|
||||
"spyOn": false,
|
||||
"waits": false,
|
||||
"waitsFor": false,
|
||||
"runs": false,
|
||||
"dump": false,
|
||||
|
||||
/* e2e */
|
||||
"browser": false,
|
||||
"element": false,
|
||||
"by": false,
|
||||
|
||||
/* testabilityPatch / matchers */
|
||||
"inject": false,
|
||||
"module": false,
|
||||
"dealoc": false,
|
||||
"_jQuery": false,
|
||||
"_jqLiteMode": false,
|
||||
"sortedHtml": false,
|
||||
"childrenTagsOf": false,
|
||||
"assertHidden": false,
|
||||
"assertVisible": false,
|
||||
"provideLog": false,
|
||||
"spyOnlyCallsWithArgs": false,
|
||||
"createMockStyleSheet": false,
|
||||
"browserTrigger": false,
|
||||
"jqLiteCacheSize": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
describe("doc.angularjs.org", function() {
|
||||
|
||||
describe("API pages", function() {
|
||||
|
||||
it("should display links to code on GitHub", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
|
||||
it('should change the page content when clicking a link to a service', function () {
|
||||
browser.get('');
|
||||
|
||||
var ngBindLink = element(by.css('.definition-table td a[href="api/ng/directive/ngClick"]'));
|
||||
ngBindLink.click();
|
||||
|
||||
var pageBody = element(by.css('h1'));
|
||||
expect(pageBody.getText()).toEqual('ngClick');
|
||||
});
|
||||
|
||||
|
||||
it('should show the functioning input directive example', function () {
|
||||
browser.get('index-debug.html#!/api/ng/directive/input');
|
||||
|
||||
// Ensure that the page is loaded before trying to switch frames.
|
||||
browser.waitForAngular();
|
||||
|
||||
browser.switchTo().frame('example-input-directive');
|
||||
|
||||
var nameInput = element(by.model('user.name'));
|
||||
nameInput.sendKeys('!!!');
|
||||
|
||||
var code = element.all(by.css('tt')).first();
|
||||
expect(code.getText()).toContain('guest!!!');
|
||||
});
|
||||
|
||||
it("should trim indentation from code blocks", function() {
|
||||
browser.get('index-debug.html#!/api/ng/type/$rootScope.Scope');
|
||||
|
||||
var codeBlocks = element.all(by.css('pre > code.lang-js'));
|
||||
codeBlocks.each(function(codeBlock) {
|
||||
var firstSpan = codeBlock.all(by.css('span')).first();
|
||||
expect(firstSpan.getText()).not.toMatch(/^\W+$/);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
describe("provider pages", function() {
|
||||
|
||||
it("should show the related service", function() {
|
||||
browser.get('index-debug.html#!/api/ng/provider/$compileProvider');
|
||||
var serviceLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(serviceLink.getText()).toEqual('- $compile');
|
||||
expect(serviceLink.getAttribute('href')).toMatch(/api\/ng\/service\/\$compile/);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
describe("service pages", function() {
|
||||
|
||||
it("should show the related provider if there is one", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$compile');
|
||||
var providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).toEqual('- $compileProvider');
|
||||
expect(providerLink.getAttribute('href')).toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$q');
|
||||
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).not.toEqual('- $qProvider');
|
||||
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
});
|
||||
|
||||
it("should show parameter defaults", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$timeout');
|
||||
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,6 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
var webdriver = require('protractor/node_modules/selenium-webdriver');
|
||||
|
||||
describe('docs.angularjs.org', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
// read and clear logs from previous tests
|
||||
browser.manage().logs().get('browser');
|
||||
});
|
||||
|
||||
|
||||
afterEach(function() {
|
||||
// verify that there were no console errors in the browser
|
||||
browser.manage().logs().get('browser').then(function(browserLog) {
|
||||
var filteredLog = browserLog.filter(function(logEntry) {
|
||||
return logEntry.level.value > webdriver.logging.Level.WARNING.value;
|
||||
});
|
||||
expect(filteredLog.length).toEqual(0);
|
||||
if (filteredLog.length) {
|
||||
console.log('browser console errors: ' + require('util').inspect(filteredLog));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('App', function () {
|
||||
// it('should filter the module list when searching', function () {
|
||||
// browser.get();
|
||||
@@ -26,21 +49,6 @@ describe('docs.angularjs.org', function () {
|
||||
});
|
||||
|
||||
|
||||
it('should show the functioning input directive example', function () {
|
||||
browser.get('index-debug.html#!/api/ng/directive/input');
|
||||
|
||||
// Ensure that the page is loaded before trying to switch frames.
|
||||
browser.waitForAngular();
|
||||
|
||||
browser.switchTo().frame('example-input-directive');
|
||||
|
||||
var nameInput = element(by.model('user.name'));
|
||||
nameInput.sendKeys('!!!');
|
||||
|
||||
var code = element.all(by.css('tt')).first();
|
||||
expect(code.getText()).toContain('guest!!!');
|
||||
});
|
||||
|
||||
|
||||
it('should be resilient to trailing slashes', function() {
|
||||
browser.get('index-debug.html#!/api/ng/function/angular.noop/');
|
||||
@@ -67,22 +75,15 @@ describe('docs.angularjs.org', function () {
|
||||
browser.get('index-debug.html#!error/ng/areq?p0=Missing&p1=not%20a%20function,%20got%20undefined');
|
||||
expect(element(by.css('.minerr-errmsg')).getText()).toEqual("Argument 'Missing' is not a function, got undefined");
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe("templates", function() {
|
||||
it("should show parameter defaults", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$timeout');
|
||||
expect(element.all(by.css('.input-arguments p em')).first().getText()).toContain('(default: 0)');
|
||||
});
|
||||
});
|
||||
|
||||
describe("API pages", function() {
|
||||
it("should display links to code on GitHub", function() {
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.improve-docs')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/edit\/.+\/src\/ng\/http\.js/);
|
||||
|
||||
browser.get('index-debug.html#!/api/ng/service/$http');
|
||||
expect(element(by.css('.view-source')).getAttribute('href')).toMatch(/https?:\/\/github\.com\/angular\/angular\.js\/tree\/.+\/src\/ng\/http\.js#L\d+/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', function() {
|
||||
it("should display an error if the page does not exist", function() {
|
||||
browser.get('index-debug.html#!/api/does/not/exist');
|
||||
expect(element(by.css('h1')).getText()).toBe('Oops!');
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ angular.module('docsApp', [
|
||||
'DocsController',
|
||||
'versionsData',
|
||||
'pagesData',
|
||||
'navData',
|
||||
'directives',
|
||||
'errors',
|
||||
'examples',
|
||||
|
||||
+12
-72
@@ -6,87 +6,39 @@ angular.module('DocsController', [])
|
||||
function($scope, $rootScope, $location, $window, $cookies, openPlunkr,
|
||||
NG_PAGES, NG_NAVIGATION, NG_VERSION) {
|
||||
|
||||
|
||||
$scope.openPlunkr = openPlunkr;
|
||||
|
||||
$scope.docsVersion = NG_VERSION.isSnapshot ? 'snapshot' : NG_VERSION.version;
|
||||
|
||||
$scope.fold = function(url) {
|
||||
if(url) {
|
||||
$scope.docs_fold = '/notes/' + url;
|
||||
if(/\/build/.test($window.location.href)) {
|
||||
$scope.docs_fold = '/build/docs' + $scope.docs_fold;
|
||||
}
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
else {
|
||||
$scope.docs_fold = null;
|
||||
}
|
||||
};
|
||||
var OFFLINE_COOKIE_NAME = 'ng-offline',
|
||||
INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
|
||||
|
||||
|
||||
/**********************************
|
||||
Publish methods
|
||||
***********************************/
|
||||
|
||||
$scope.navClass = function(navItem) {
|
||||
return {
|
||||
active: navItem.href && this.currentPage.path,
|
||||
active: navItem.href && this.currentPage && this.currentPage.path,
|
||||
'nav-index-section': navItem.type === 'section'
|
||||
};
|
||||
};
|
||||
|
||||
$scope.afterPartialLoaded = function() {
|
||||
|
||||
|
||||
$scope.$on('$includeContentLoaded', function() {
|
||||
var pagePath = $scope.currentPage ? $scope.currentPage.path : $location.path();
|
||||
$window._gaq.push(['_trackPageview', pagePath]);
|
||||
};
|
||||
});
|
||||
|
||||
/** stores a cookie that is used by apache to decide which manifest ot send */
|
||||
$scope.enableOffline = function() {
|
||||
//The cookie will be good for one year!
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime()+(365*24*60*60*1000));
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
var value = angular.version.full;
|
||||
document.cookie = OFFLINE_COOKIE_NAME + "="+value+expires+"; path=" + $location.path;
|
||||
|
||||
//force the page to reload so server can serve new manifest file
|
||||
window.location.reload(true);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**********************************
|
||||
Watches
|
||||
***********************************/
|
||||
$scope.$on('$includeContentError', function() {
|
||||
$scope.partialPath = 'Error404.html';
|
||||
});
|
||||
|
||||
|
||||
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
|
||||
|
||||
var currentPage = $scope.currentPage = NG_PAGES[path];
|
||||
if ( !currentPage && path.charAt(0)==='/' ) {
|
||||
// Strip off leading slash
|
||||
path = path.substr(1);
|
||||
}
|
||||
path = path.replace(/^\/?(.+?)(\/index)?\/?$/, '$1');
|
||||
|
||||
currentPage = $scope.currentPage = NG_PAGES[path];
|
||||
if ( !currentPage && path.charAt(path.length-1) === '/' && path.length > 1 ) {
|
||||
// Strip off trailing slash
|
||||
path = path.substr(0, path.length-1);
|
||||
}
|
||||
|
||||
currentPage = $scope.currentPage = NG_PAGES[path];
|
||||
if ( !currentPage && /\/index$/.test(path) ) {
|
||||
// Strip off index from the end
|
||||
path = path.substr(0, path.length - 6);
|
||||
}
|
||||
$scope.partialPath = 'partials/' + path + '.html';
|
||||
|
||||
currentPage = $scope.currentPage = NG_PAGES[path];
|
||||
|
||||
if ( currentPage ) {
|
||||
$scope.currentArea = currentPage && NG_NAVIGATION[currentPage.area];
|
||||
$scope.currentArea = NG_NAVIGATION[currentPage.area];
|
||||
var pathParts = currentPage.path.split('/');
|
||||
var breadcrumb = $scope.breadcrumb = [];
|
||||
var breadcrumbPath = '';
|
||||
@@ -107,24 +59,12 @@ angular.module('DocsController', [])
|
||||
|
||||
$scope.versionNumber = angular.version.full;
|
||||
$scope.version = angular.version.full + " " + angular.version.codeName;
|
||||
$scope.subpage = false;
|
||||
$scope.offlineEnabled = ($cookies[OFFLINE_COOKIE_NAME] == angular.version.full);
|
||||
$scope.futurePartialTitle = null;
|
||||
$scope.loading = 0;
|
||||
$scope.$cookies = $cookies;
|
||||
|
||||
$cookies.platformPreference = $cookies.platformPreference || 'gitUnix';
|
||||
|
||||
var INDEX_PATH = /^(\/|\/index[^\.]*.html)$/;
|
||||
if (!$location.path() || INDEX_PATH.test($location.path())) {
|
||||
$location.path('/api').replace();
|
||||
}
|
||||
|
||||
// bind escape to hash reset callback
|
||||
angular.element(window).on('keydown', function(e) {
|
||||
if (e.keyCode === 27) {
|
||||
$scope.$apply(function() {
|
||||
$scope.subpage = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
angular.module('docsApp.navigationService', [])
|
||||
|
||||
.factory('navigationService', function($window) {
|
||||
var service = {
|
||||
currentPage: null,
|
||||
currentVersion: null,
|
||||
changePage: function(newPage) {
|
||||
|
||||
},
|
||||
changeVersion: function(newVersion) {
|
||||
|
||||
//TODO =========
|
||||
// var currentPagePath = '';
|
||||
|
||||
// // preserve URL path when switching between doc versions
|
||||
// if (angular.isObject($rootScope.currentPage) && $rootScope.currentPage.section && $rootScope.currentPage.id) {
|
||||
// currentPagePath = '/' + $rootScope.currentPage.section + '/' + $rootScope.currentPage.id;
|
||||
// }
|
||||
|
||||
// $window.location = version.url + currentPagePath;
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
+123
-62
@@ -10,22 +10,35 @@ angular.module('search', [])
|
||||
$scope.search = function(q) {
|
||||
var MIN_SEARCH_LENGTH = 2;
|
||||
if(q.length >= MIN_SEARCH_LENGTH) {
|
||||
var results = docsSearch(q);
|
||||
var totalAreas = 0;
|
||||
for(var i in results) {
|
||||
++totalAreas;
|
||||
}
|
||||
if(totalAreas > 0) {
|
||||
$scope.colClassName = 'cols-' + totalAreas;
|
||||
}
|
||||
$scope.hasResults = totalAreas > 0;
|
||||
$scope.results = results;
|
||||
docsSearch(q).then(function(hits) {
|
||||
var results = {};
|
||||
angular.forEach(hits, function(hit) {
|
||||
var area = hit.area;
|
||||
|
||||
var limit = (area == 'api') ? 40 : 14;
|
||||
results[area] = results[area] || [];
|
||||
if(results[area].length < limit) {
|
||||
results[area].push(hit);
|
||||
}
|
||||
});
|
||||
|
||||
var totalAreas = 0;
|
||||
for(var i in results) {
|
||||
++totalAreas;
|
||||
}
|
||||
if(totalAreas > 0) {
|
||||
$scope.colClassName = 'cols-' + totalAreas;
|
||||
}
|
||||
$scope.hasResults = totalAreas > 0;
|
||||
$scope.results = results;
|
||||
});
|
||||
}
|
||||
else {
|
||||
clearResults();
|
||||
}
|
||||
if(!$scope.$$phase) $scope.$apply();
|
||||
};
|
||||
|
||||
$scope.submit = function() {
|
||||
var result;
|
||||
for(var i in $scope.results) {
|
||||
@@ -39,76 +52,124 @@ angular.module('search', [])
|
||||
$scope.hideResults();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.hideResults = function() {
|
||||
clearResults();
|
||||
$scope.q = '';
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch', function($scope, $location, docsSearch) {
|
||||
$scope.results = docsSearch($location.path().split(/[\/\.:]/).pop());
|
||||
|
||||
.controller('Error404SearchCtrl', ['$scope', '$location', 'docsSearch',
|
||||
function($scope, $location, docsSearch) {
|
||||
docsSearch($location.path().split(/[\/\.:]/).pop()).then(function(results) {
|
||||
$scope.results = {};
|
||||
angular.forEach(results, function(result) {
|
||||
var area = $scope.results[result.area] || [];
|
||||
area.push(result);
|
||||
$scope.results[result.area] = area;
|
||||
});
|
||||
});
|
||||
}])
|
||||
|
||||
.factory('lunrSearch', function() {
|
||||
return function(properties) {
|
||||
if (window.RUNNING_IN_NG_TEST_RUNNER) return null;
|
||||
|
||||
var engine = lunr(properties);
|
||||
return {
|
||||
store : function(values) {
|
||||
engine.add(values);
|
||||
},
|
||||
search : function(q) {
|
||||
return engine.search(q);
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.provider('docsSearch', function() {
|
||||
|
||||
.factory('docsSearch', ['$rootScope','lunrSearch', 'NG_PAGES',
|
||||
function($rootScope, lunrSearch, NG_PAGES) {
|
||||
if (window.RUNNING_IN_NG_TEST_RUNNER) {
|
||||
return null;
|
||||
}
|
||||
// This version of the service builds the index in the current thread,
|
||||
// which blocks rendering and other browser activities.
|
||||
// It should only be used where the browser does not support WebWorkers
|
||||
function localSearchFactory($http, $timeout, NG_PAGES) {
|
||||
|
||||
var index = lunrSearch(function() {
|
||||
this.ref('id');
|
||||
this.field('title', {boost: 50});
|
||||
this.field('keywords', { boost : 20 });
|
||||
});
|
||||
console.log('Using Local Search Index');
|
||||
|
||||
angular.forEach(NG_PAGES, function(page, key) {
|
||||
if(page.searchTerms) {
|
||||
index.store({
|
||||
id : key,
|
||||
title : page.searchTerms.titleWords,
|
||||
keywords : page.searchTerms.keywords
|
||||
// Create the lunr index
|
||||
var index = lunr(function() {
|
||||
this.ref('path');
|
||||
this.field('titleWords', {boost: 50});
|
||||
this.field('members', { boost: 40});
|
||||
this.field('keywords', { boost : 20 });
|
||||
});
|
||||
|
||||
// Delay building the index by loading the data asynchronously
|
||||
var indexReadyPromise = $http.get('js/search-data.json').then(function(response) {
|
||||
var searchData = response.data;
|
||||
// Delay building the index for 500ms to allow the page to render
|
||||
return $timeout(function() {
|
||||
// load the page data into the index
|
||||
angular.forEach(searchData, function(page) {
|
||||
index.add(page);
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// The actual service is a function that takes a query string and
|
||||
// returns a promise to the search results
|
||||
// (In this case we just resolve the promise immediately as it is not
|
||||
// inherently an async process)
|
||||
return function(q) {
|
||||
return indexReadyPromise.then(function() {
|
||||
var hits = index.search(q);
|
||||
var results = [];
|
||||
angular.forEach(hits, function(hit) {
|
||||
results.push(NG_PAGES[hit.ref]);
|
||||
});
|
||||
return results;
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
localSearchFactory.$inject = ['$http', '$timeout', 'NG_PAGES'];
|
||||
|
||||
return function(q) {
|
||||
var results = {
|
||||
api : [],
|
||||
tutorial : [],
|
||||
guide : [],
|
||||
error : [],
|
||||
misc : []
|
||||
// This version of the service builds the index in a WebWorker,
|
||||
// which does not block rendering and other browser activities.
|
||||
// It should only be used where the browser does support WebWorkers
|
||||
function webWorkerSearchFactory($q, $rootScope, NG_PAGES) {
|
||||
|
||||
console.log('Using WebWorker Search Index')
|
||||
|
||||
var searchIndex = $q.defer();
|
||||
var results;
|
||||
|
||||
var worker = new Worker('js/search-worker.js');
|
||||
|
||||
// The worker will send us a message in two situations:
|
||||
// - when the index has been built, ready to run a query
|
||||
// - when it has completed a search query and the results are available
|
||||
worker.onmessage = function(oEvent) {
|
||||
$rootScope.$apply(function() {
|
||||
|
||||
switch(oEvent.data.e) {
|
||||
case 'index-ready':
|
||||
searchIndex.resolve();
|
||||
break;
|
||||
case 'query-ready':
|
||||
var pages = oEvent.data.d.map(function(path) {
|
||||
return NG_PAGES[path];
|
||||
});
|
||||
results.resolve(pages);
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
angular.forEach(index.search(q), function(result) {
|
||||
var key = result.ref;
|
||||
var item = NG_PAGES[key];
|
||||
var area = item.area;
|
||||
item.path = key;
|
||||
|
||||
var limit = area == 'api' ? 40 : 14;
|
||||
if(results[area].length < limit) {
|
||||
results[area].push(item);
|
||||
}
|
||||
});
|
||||
return results;
|
||||
// The actual service is a function that takes a query string and
|
||||
// returns a promise to the search results
|
||||
return function(q) {
|
||||
|
||||
// We only run the query once the index is ready
|
||||
return searchIndex.promise.then(function() {
|
||||
|
||||
results = $q.defer();
|
||||
worker.postMessage({ q: q });
|
||||
return results.promise;
|
||||
});
|
||||
};
|
||||
}
|
||||
webWorkerSearchFactory.$inject = ['$q', '$rootScope', 'NG_PAGES'];
|
||||
|
||||
return {
|
||||
$get: window.Worker ? webWorkerSearchFactory : localSearchFactory
|
||||
};
|
||||
}])
|
||||
})
|
||||
|
||||
.directive('focused', function($timeout) {
|
||||
return function(scope, element, attrs) {
|
||||
|
||||
@@ -19,7 +19,7 @@ describe("DocsController", function() {
|
||||
it("should update the Google Analytics with currentPage path if currentPage exists", inject(function($window) {
|
||||
$window._gaq = [];
|
||||
$scope.currentPage = { path: 'a/b/c' };
|
||||
$scope.afterPartialLoaded();
|
||||
$scope.$broadcast('$includeContentLoaded');
|
||||
expect($window._gaq.pop()).toEqual(['_trackPageview', 'a/b/c']);
|
||||
}));
|
||||
|
||||
@@ -27,7 +27,7 @@ describe("DocsController", function() {
|
||||
it("should update the Google Analytics with $location.path if currentPage is missing", inject(function($window, $location) {
|
||||
$window._gaq = [];
|
||||
spyOn($location, 'path').andReturn('x/y/z');
|
||||
$scope.afterPartialLoaded();
|
||||
$scope.$broadcast('$includeContentLoaded');
|
||||
expect($window._gaq.pop()).toEqual(['_trackPageview', 'x/y/z']);
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "AngularJS-docs-app",
|
||||
"dependencies": {
|
||||
"jquery": "2.1.1",
|
||||
"lunr.js": "0.4.3",
|
||||
"open-sans-fontface": "1.0.4",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"bootstrap": "3.1.1"
|
||||
}
|
||||
}
|
||||
+148
-31
@@ -1,43 +1,160 @@
|
||||
var _ = require('lodash');
|
||||
"use strict";
|
||||
|
||||
var path = require('canonical-path');
|
||||
var packagePath = __dirname;
|
||||
|
||||
var basePackage = require('dgeni-packages/ngdoc');
|
||||
var examplesPackage = require('dgeni-packages/examples');
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function(config) {
|
||||
// Create and export a new Dgeni package called dgeni-example. This package depends upon
|
||||
// the jsdoc and nunjucks packages defined in the dgeni-packages npm module.
|
||||
module.exports = new Package('angularjs', [
|
||||
require('dgeni-packages/ngdoc'),
|
||||
require('dgeni-packages/nunjucks'),
|
||||
require('dgeni-packages/examples')
|
||||
])
|
||||
|
||||
config = basePackage(config);
|
||||
config = examplesPackage(config);
|
||||
|
||||
config.append('processing.processors', [
|
||||
require('./processors/git-data'),
|
||||
require('./processors/error-docs'),
|
||||
require('./processors/keywords'),
|
||||
require('./processors/versions-data'),
|
||||
require('./processors/pages-data'),
|
||||
require('./processors/protractor-generate'),
|
||||
require('./processors/index-page'),
|
||||
require('./processors/debug-dump')
|
||||
]);
|
||||
.factory(require('./services/errorNamespaceMap'))
|
||||
.factory(require('./services/getMinerrInfo'))
|
||||
.factory(require('./services/getVersion'))
|
||||
.factory(require('./services/gitData'))
|
||||
|
||||
config.append('processing.tagDefinitions', [
|
||||
require('./tag-defs/tutorial-step')
|
||||
]);
|
||||
.factory(require('./services/deployments/debug'))
|
||||
.factory(require('./services/deployments/default'))
|
||||
.factory(require('./services/deployments/jquery'))
|
||||
.factory(require('./services/deployments/production'))
|
||||
|
||||
config.append('processing.defaultTagTransforms', [
|
||||
require('dgeni-packages/jsdoc/tag-defs/transforms/trim-whitespace')
|
||||
]);
|
||||
.factory(require('./inline-tag-defs/type'))
|
||||
|
||||
config.append('processing.inlineTagDefinitions', [
|
||||
require('./inline-tag-defs/type')
|
||||
]);
|
||||
|
||||
config.set('processing.search.ignoreWordsFile', path.resolve(packagePath, 'ignore.words'));
|
||||
.processor(require('./processors/error-docs'))
|
||||
.processor(require('./processors/index-page'))
|
||||
.processor(require('./processors/keywords'))
|
||||
.processor(require('./processors/pages-data'))
|
||||
.processor(require('./processors/versions-data'))
|
||||
|
||||
config.prepend('rendering.templateFolders', [
|
||||
path.resolve(packagePath, 'templates')
|
||||
]);
|
||||
|
||||
return config;
|
||||
};
|
||||
.config(function(dgeni, log, readFilesProcessor, writeFilesProcessor) {
|
||||
|
||||
dgeni.stopOnValidationError = true;
|
||||
dgeni.stopOnProcessingError = true;
|
||||
|
||||
log.level = 'info';
|
||||
|
||||
readFilesProcessor.basePath = path.resolve(__dirname,'../..');
|
||||
readFilesProcessor.sourceFiles = [
|
||||
{ include: 'src/**/*.js', basePath: 'src' },
|
||||
{ include: 'docs/content/**/*.ngdoc', basePath: 'docs/content' }
|
||||
];
|
||||
|
||||
writeFilesProcessor.outputFolder = 'build/docs';
|
||||
|
||||
})
|
||||
|
||||
|
||||
.config(function(parseTagsProcessor) {
|
||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/tutorial-step'));
|
||||
parseTagsProcessor.tagDefinitions.push(require('./tag-defs/sortOrder'));
|
||||
})
|
||||
|
||||
|
||||
.config(function(inlineTagProcessor, typeInlineTagDef) {
|
||||
inlineTagProcessor.inlineTagDefinitions.push(typeInlineTagDef);
|
||||
})
|
||||
|
||||
|
||||
.config(function(templateFinder, renderDocsProcessor, gitData) {
|
||||
templateFinder.templateFolders.unshift(path.resolve(packagePath, 'templates'));
|
||||
renderDocsProcessor.extraData.git = gitData;
|
||||
})
|
||||
|
||||
|
||||
.config(function(computePathsProcessor, computeIdsProcessor) {
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['error'],
|
||||
pathTemplate: 'error/${namespace}/${name}',
|
||||
outputPathTemplate: 'partials/error/${namespace}/${name}.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['errorNamespace'],
|
||||
pathTemplate: 'error/${name}',
|
||||
outputPathTemplate: 'partials/error/${name}.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['overview', 'tutorial'],
|
||||
getPath: function(doc) {
|
||||
var docPath = path.dirname(doc.fileInfo.relativePath);
|
||||
if ( doc.fileInfo.baseName !== 'index' ) {
|
||||
docPath = path.join(docPath, doc.fileInfo.baseName);
|
||||
}
|
||||
return docPath;
|
||||
},
|
||||
outputPathTemplate: 'partials/${path}.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['e2e-test'],
|
||||
getPath: function() {},
|
||||
outputPathTemplate: 'ptore2e/${example.id}/${deployment.name}_test.js'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['indexPage'],
|
||||
getPath: function() {},
|
||||
outputPathTemplate: '${id}.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['module' ],
|
||||
pathTemplate: '${area}/${name}',
|
||||
outputPathTemplate: 'partials/${area}/${name}.html'
|
||||
});
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['componentGroup' ],
|
||||
pathTemplate: '${area}/${moduleName}/${groupType}',
|
||||
outputPathTemplate: 'partials/${area}/${moduleName}/${groupType}.html'
|
||||
});
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['overview', 'tutorial', 'e2e-test', 'indexPage'],
|
||||
getId: function(doc) { return doc.fileInfo.baseName; },
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['error', 'errorNamespace'],
|
||||
getId: function(doc) { return 'error:' + doc.name; },
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
.config(function(
|
||||
generateIndexPagesProcessor,
|
||||
generateProtractorTestsProcessor,
|
||||
generateExamplesProcessor,
|
||||
debugDeployment, defaultDeployment,
|
||||
jqueryDeployment, productionDeployment) {
|
||||
|
||||
generateIndexPagesProcessor.deployments = [
|
||||
debugDeployment,
|
||||
defaultDeployment,
|
||||
jqueryDeployment,
|
||||
productionDeployment
|
||||
];
|
||||
|
||||
generateProtractorTestsProcessor.deployments = [
|
||||
defaultDeployment,
|
||||
jqueryDeployment
|
||||
];
|
||||
|
||||
generateExamplesProcessor.deployments = [
|
||||
debugDeployment,
|
||||
defaultDeployment,
|
||||
jqueryDeployment,
|
||||
productionDeployment
|
||||
];
|
||||
});
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
var typeClassFilter = require('dgeni-packages/ngdoc/rendering/filters/type-class');
|
||||
"use strict";
|
||||
|
||||
var encoder = new require('node-html-encoder').Encoder();
|
||||
|
||||
module.exports = {
|
||||
name: 'type',
|
||||
description: 'Replace with markup that displays a nice type',
|
||||
handlerFactory: function() {
|
||||
return function(doc, tagName, tagDescription) {
|
||||
return '<a href="" class="' + typeClassFilter.process(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
|
||||
};
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @dgService typeInlineTagDef
|
||||
* @description
|
||||
* Replace with markup that displays a nice type
|
||||
*/
|
||||
module.exports = function typeInlineTagDef(getTypeClass) {
|
||||
return {
|
||||
name: 'type',
|
||||
handler: function(doc, tagName, tagDescription) {
|
||||
return '<a href="" class="' + getTypeClass(tagDescription) + '">'+encoder.htmlEncode(tagDescription) + '</a>';
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
var fs = require('q-io/fs');
|
||||
var log = require('winston');
|
||||
var util = require("util");
|
||||
|
||||
module.exports = {
|
||||
name: 'debug-dump',
|
||||
runBefore: ['write-files'],
|
||||
description: 'This processor dumps docs that match a filter to a file',
|
||||
process: function(docs, config) {
|
||||
|
||||
var filter, outputPath, depth;
|
||||
|
||||
filter = config.get('processing.debug-dump.filter');
|
||||
outputPath = config.get('processing.debug-dump.outputPath');
|
||||
depth = config.get('processing.debug-dump.depth', 2);
|
||||
|
||||
|
||||
if ( filter && outputPath ) {
|
||||
log.info('Dumping docs:', filter, outputPath);
|
||||
var filteredDocs = filter(docs);
|
||||
var dumpedDocs = util.inspect(filteredDocs, depth);
|
||||
return writeFile(outputPath, dumpedDocs).then(function() {
|
||||
return docs;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function writeFile(file, content) {
|
||||
return fs.makeTree(fs.directory(file)).then(function() {
|
||||
return fs.write(file, content, 'wb');
|
||||
});
|
||||
}
|
||||
@@ -1,59 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('lodash');
|
||||
var log = require('winston');
|
||||
var path = require('canonical-path');
|
||||
|
||||
module.exports = {
|
||||
name: 'error-docs',
|
||||
description: 'Compute the various fields for docs in the Error area',
|
||||
runAfter: ['tags-extracted', 'compute-path'],
|
||||
runBefore: ['extra-docs-added'],
|
||||
exports: {
|
||||
errorNamespaces: ['factory', function() { return {}; }],
|
||||
minerrInfo: ['factory', function(config) {
|
||||
var minerrInfoPath = config.get('processing.errors.minerrInfoPath');
|
||||
if ( !minerrInfoPath ) {
|
||||
throw new Error('Error in configuration: Please provide a path to the minerr info file (errors.json) ' +
|
||||
'in the `config.processing.errors.minerrInfoPath` property');
|
||||
}
|
||||
return require(minerrInfoPath);
|
||||
}]
|
||||
},
|
||||
process: function(docs, partialNames, errorNamespaces, minerrInfo) {
|
||||
/**
|
||||
* @dgProcessor errorDocsProcessor
|
||||
* @description
|
||||
* Process "error" docType docs and generate errorNamespace docs
|
||||
*/
|
||||
module.exports = function errorDocsProcessor(errorNamespaceMap, getMinerrInfo) {
|
||||
return {
|
||||
$runAfter: ['tags-extracted'],
|
||||
$runBefore: ['extra-docs-added'],
|
||||
$process: function(docs) {
|
||||
|
||||
// Create error namespace docs and attach error docs to each
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'error' ) {
|
||||
// Create error namespace docs and attach error docs to each
|
||||
docs.forEach(function(doc) {
|
||||
var parts, namespaceDoc;
|
||||
|
||||
// Parse out the error info from the id
|
||||
parts = doc.name.split(':');
|
||||
doc.namespace = parts[0];
|
||||
doc.name = parts[1];
|
||||
if ( doc.docType === 'error' ) {
|
||||
|
||||
// Parse out the error info from the id
|
||||
parts = doc.name.split(':');
|
||||
doc.namespace = parts[0];
|
||||
doc.name = parts[1];
|
||||
|
||||
var namespaceDoc = errorNamespaces[doc.namespace];
|
||||
if ( !namespaceDoc ) {
|
||||
// First time we came across this namespace, so create a new one
|
||||
namespaceDoc = errorNamespaces[doc.namespace] = {
|
||||
area: doc.area,
|
||||
name: doc.namespace,
|
||||
errors: [],
|
||||
path: path.dirname(doc.path),
|
||||
outputPath: path.dirname(doc.outputPath) + '.html',
|
||||
docType: 'errorNamespace'
|
||||
};
|
||||
// Get or create the relevant errorNamespace doc
|
||||
namespaceDoc = errorNamespaceMap.get(doc.namespace);
|
||||
if ( !namespaceDoc ) {
|
||||
namespaceDoc = {
|
||||
area: 'error',
|
||||
name: doc.namespace,
|
||||
errors: [],
|
||||
docType: 'errorNamespace'
|
||||
};
|
||||
errorNamespaceMap.set(doc.namespace, namespaceDoc);
|
||||
}
|
||||
|
||||
// Link this error doc to its namespace doc
|
||||
namespaceDoc.errors.push(doc);
|
||||
doc.namespaceDoc = namespaceDoc;
|
||||
doc.formattedErrorMessage = getMinerrInfo().errors[doc.namespace][doc.name];
|
||||
}
|
||||
});
|
||||
|
||||
// Add this error to the namespace
|
||||
namespaceDoc.errors.push(doc);
|
||||
doc.namespace = namespaceDoc;
|
||||
|
||||
doc.formattedErrorMessage = minerrInfo.errors[doc.namespace.name][doc.name];
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
return docs.concat(_.values(errorNamespaces));
|
||||
}
|
||||
};
|
||||
errorNamespaceMap.forEach(function(errorNamespace) {
|
||||
docs.push(errorNamespace);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
var gruntUtils = require('../../../lib/grunt/utils');
|
||||
var versionInfo = require('../../../lib/versions/version-info');
|
||||
|
||||
module.exports = {
|
||||
name: 'git-data',
|
||||
runBefore: ['reading-files'],
|
||||
description: 'This processor adds information from the local git repository to the extraData injectable',
|
||||
exports: {
|
||||
gitData: ['factory', function() {
|
||||
return {
|
||||
version: versionInfo.currentVersion,
|
||||
versions: versionInfo.previousVersions,
|
||||
info: versionInfo.gitRepoInfo
|
||||
};
|
||||
}]
|
||||
},
|
||||
process: function(extraData, gitData) {
|
||||
extraData.git = gitData;
|
||||
}
|
||||
};
|
||||
@@ -1,40 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('lodash');
|
||||
var log = require('winston');
|
||||
var path = require('canonical-path');
|
||||
|
||||
module.exports = {
|
||||
name: 'index-page',
|
||||
runAfter: ['adding-extra-docs'],
|
||||
runBefore: ['extra-docs-added'],
|
||||
description: 'This processor creates docs that will be rendered as the index page for the app',
|
||||
process: function(docs, config) {
|
||||
/**
|
||||
* @dgProcessor generateIndexPagesProcessor
|
||||
* @description
|
||||
* This processor creates docs that will be rendered as the index page for the app
|
||||
*/
|
||||
module.exports = function generateIndexPagesProcessor() {
|
||||
return {
|
||||
deployments: [],
|
||||
$validate: {
|
||||
deployments: { presence: true }
|
||||
},
|
||||
$runAfter: ['adding-extra-docs'],
|
||||
$runBefore: ['extra-docs-added'],
|
||||
$process: function(docs) {
|
||||
|
||||
var deployment = config.deployment;
|
||||
if ( !deployment || !deployment.environments ) {
|
||||
throw new Error('No deployment environments found in the config.');
|
||||
// Collect up all the areas in the docs
|
||||
var areas = {};
|
||||
docs.forEach(function(doc) {
|
||||
if ( doc.area ) {
|
||||
areas[doc.area] = doc.area;
|
||||
}
|
||||
});
|
||||
areas = _.keys(areas);
|
||||
|
||||
this.deployments.forEach(function(deployment) {
|
||||
|
||||
var indexDoc = _.defaults({
|
||||
docType: 'indexPage',
|
||||
areas: areas
|
||||
}, deployment);
|
||||
|
||||
indexDoc.id = 'index' + (deployment.name === 'default' ? '' : '-' + deployment.name);
|
||||
|
||||
docs.push(indexDoc);
|
||||
});
|
||||
}
|
||||
|
||||
// Collect up all the areas in the docs
|
||||
var areas = {};
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.area ) {
|
||||
areas[doc.area] = doc.area;
|
||||
}
|
||||
});
|
||||
areas = _.keys(areas);
|
||||
|
||||
_.forEach(deployment.environments, function(environment) {
|
||||
|
||||
var indexDoc = _.defaults({
|
||||
docType: 'indexPage',
|
||||
areas: areas
|
||||
}, environment);
|
||||
|
||||
indexDoc.id = 'index' + (environment.name === 'default' ? '' : '-' + environment.name);
|
||||
// Use .. to put it at the root of the build
|
||||
indexDoc.outputPath = indexDoc.id + '.html';
|
||||
|
||||
docs.push(indexDoc);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,50 +1,64 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('lodash');
|
||||
var log = require('winston');
|
||||
var fs = require('fs');
|
||||
var path = require('canonical-path');
|
||||
|
||||
module.exports = {
|
||||
name: 'keywords',
|
||||
runAfter: ['docs-processed'],
|
||||
runBefore: ['adding-extra-docs'],
|
||||
description: 'This processor extracts all the keywords from the document',
|
||||
process: function(docs, config) {
|
||||
/**
|
||||
* @dgProcessor generateKeywordsProcessor
|
||||
* @description
|
||||
* This processor extracts all the keywords from each document and creates
|
||||
* a new document that will be rendered as a JavaScript file containing all
|
||||
* this data.
|
||||
*/
|
||||
module.exports = function generateKeywordsProcessor(log, readFilesProcessor) {
|
||||
return {
|
||||
ignoreWordsFile: undefined,
|
||||
areasToSearch: ['api', 'guide', 'misc', 'error', 'tutorial'],
|
||||
propertiesToIgnore: [],
|
||||
$validate: {
|
||||
ignoreWordsFile: { },
|
||||
areasToSearch: { presence: true },
|
||||
propertiesToIgnore: { }
|
||||
},
|
||||
$runAfter: ['memberDocsProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
$process: function(docs) {
|
||||
|
||||
// Keywords to ignore
|
||||
var wordsToIgnore = [];
|
||||
var propertiesToIgnore;
|
||||
var areasToSearch;
|
||||
// Keywords to ignore
|
||||
var wordsToIgnore = [];
|
||||
var propertiesToIgnore;
|
||||
var areasToSearch;
|
||||
|
||||
// Keywords start with "ng:" or one of $, _ or a letter
|
||||
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
|
||||
// Keywords start with "ng:" or one of $, _ or a letter
|
||||
var KEYWORD_REGEX = /^((ng:|[\$_a-z])[\w\-_]+)/;
|
||||
|
||||
// Load up the keywords to ignore, if specified in the config
|
||||
if ( config.processing.search && config.processing.search.ignoreWordsFile ) {
|
||||
// Load up the keywords to ignore, if specified in the config
|
||||
if ( this.ignoreWordsFile ) {
|
||||
|
||||
var ignoreWordsPath = path.resolve(config.basePath, config.processing.search.ignoreWordsFile);
|
||||
wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm);
|
||||
var ignoreWordsPath = path.resolve(readFilesProcessor.basePath, this.ignoreWordsFile);
|
||||
wordsToIgnore = fs.readFileSync(ignoreWordsPath, 'utf8').toString().split(/[,\s\n\r]+/gm);
|
||||
|
||||
log.debug('Loaded ignore words from "' + ignoreWordsPath + '"');
|
||||
log.silly(wordsToIgnore);
|
||||
log.debug('Loaded ignore words from "' + ignoreWordsPath + '"');
|
||||
log.silly(wordsToIgnore);
|
||||
|
||||
}
|
||||
|
||||
areasToSearch = _.indexBy(config.get('processing.search.areasToSearch', ['api', 'guide', 'misc', 'error', 'tutorial']));
|
||||
|
||||
propertiesToIgnore = _.indexBy(config.get('processing.search.propertiesToIgnore', []));
|
||||
log.debug('Properties to ignore', propertiesToIgnore);
|
||||
|
||||
var ignoreWordsMap = _.indexBy(wordsToIgnore);
|
||||
|
||||
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
|
||||
// without the ng to the title text, e.g. "controller".
|
||||
function extractTitleWords(title) {
|
||||
var match = /ng([A-Z]\w*)/.exec(title);
|
||||
if ( match ) {
|
||||
title = title + ' ' + match[1].toLowerCase();
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
areasToSearch = _.indexBy(this.areasToSearch);
|
||||
propertiesToIgnore = _.indexBy(this.propertiesToIgnore);
|
||||
log.debug('Properties to ignore', propertiesToIgnore);
|
||||
|
||||
var ignoreWordsMap = _.indexBy(wordsToIgnore);
|
||||
|
||||
// If the title contains a name starting with ng, e.g. "ngController", then add the module name
|
||||
// without the ng to the title text, e.g. "controller".
|
||||
function extractTitleWords(title) {
|
||||
var match = /ng([A-Z]\w*)/.exec(title);
|
||||
if ( match ) {
|
||||
title = title + ' ' + match[1].toLowerCase();
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
function extractWords(text, words, keywordMap) {
|
||||
|
||||
@@ -52,37 +66,49 @@ module.exports = {
|
||||
_.forEach(tokens, function(token){
|
||||
var match = token.match(KEYWORD_REGEX);
|
||||
if (match){
|
||||
key = match[1];
|
||||
var key = match[1];
|
||||
if ( !keywordMap[key]) {
|
||||
keywordMap[key] = true;
|
||||
words.push(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// We are only interested in docs that live in the right area
|
||||
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
|
||||
// We are only interested in docs that live in the right area
|
||||
docs = _.filter(docs, function(doc) { return areasToSearch[doc.area]; });
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
_.forEach(docs, function(doc) {
|
||||
|
||||
var words = [];
|
||||
var keywordMap = _.clone(ignoreWordsMap);
|
||||
var members = [];
|
||||
var membersMap = {};
|
||||
|
||||
// Search each top level property of the document for search terms
|
||||
_.forEach(doc, function(value, key) {
|
||||
|
||||
if ( _.isString(value) && !propertiesToIgnore[key] ) {
|
||||
extractWords(value, words, keywordMap);
|
||||
}
|
||||
|
||||
if ( key === 'methods' || key === 'properties' || key === 'events' ) {
|
||||
_.forEach(value, function(member) {
|
||||
extractWords(member.name, members, membersMap);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
doc.searchTerms = {
|
||||
titleWords: extractTitleWords(doc.name),
|
||||
keywords: _.sortBy(words).join(' ')
|
||||
keywords: _.sortBy(words).join(' '),
|
||||
members: _.sortBy(members).join(' ')
|
||||
};
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
var log = require('winston');
|
||||
|
||||
var AREA_NAMES = {
|
||||
api: 'API',
|
||||
@@ -33,182 +34,206 @@ function getNavGroup(pages, area, pageSorter, pageMapper) {
|
||||
}
|
||||
|
||||
|
||||
var navGroupMappers = {
|
||||
api: function(areaPages, area) {
|
||||
var navGroups = _(areaPages)
|
||||
.filter('module') // We are not interested in docs that are not in a module
|
||||
/**
|
||||
* @dgProcessor generatePagesDataProcessor
|
||||
* @description
|
||||
* This processor will create a new doc that will be rendered as a JavaScript file
|
||||
* containing meta information about the pages and navigation
|
||||
*/
|
||||
module.exports = function generatePagesDataProcessor(log) {
|
||||
|
||||
.groupBy('module')
|
||||
|
||||
.map(function(modulePages, moduleName) {
|
||||
log.debug('moduleName: ' + moduleName);
|
||||
var navItems = [];
|
||||
var modulePage;
|
||||
var navGroupMappers = {
|
||||
api: function(areaPages, area) {
|
||||
var navGroups = _(areaPages)
|
||||
.filter('module') // We are not interested in docs that are not in a module
|
||||
|
||||
_(modulePages)
|
||||
.groupBy('module')
|
||||
|
||||
.groupBy('docType')
|
||||
.map(function(modulePages, moduleName) {
|
||||
log.debug('moduleName: ' + moduleName);
|
||||
var navItems = [];
|
||||
var modulePage;
|
||||
|
||||
.tap(function(docTypes) {
|
||||
log.debug(_.keys(docTypes));
|
||||
// Extract the module page from the collection
|
||||
modulePage = docTypes.module[0];
|
||||
delete docTypes.module;
|
||||
})
|
||||
_(modulePages)
|
||||
|
||||
.tap(function(docTypes) {
|
||||
if ( docTypes.input ) {
|
||||
docTypes.directive = docTypes.directive || [];
|
||||
// Combine input docTypes into directive docTypes
|
||||
docTypes.directive = docTypes.directive.concat(docTypes.input);
|
||||
delete docTypes.input;
|
||||
}
|
||||
})
|
||||
.groupBy('docType')
|
||||
|
||||
.forEach(function(sectionPages, sectionName) {
|
||||
.tap(function(docTypes) {
|
||||
log.debug(moduleName, _.keys(docTypes));
|
||||
// Extract the module page from the collection
|
||||
modulePage = docTypes.module[0];
|
||||
delete docTypes.module;
|
||||
})
|
||||
|
||||
sectionPages = _.sortBy(sectionPages, 'name');
|
||||
.tap(function(docTypes) {
|
||||
if ( docTypes.input ) {
|
||||
docTypes.directive = docTypes.directive || [];
|
||||
// Combine input docTypes into directive docTypes
|
||||
docTypes.directive = docTypes.directive.concat(docTypes.input);
|
||||
delete docTypes.input;
|
||||
}
|
||||
})
|
||||
|
||||
if ( sectionPages.length > 0 ) {
|
||||
// Push a navItem for this section
|
||||
navItems.push({
|
||||
name: sectionName,
|
||||
type: 'section',
|
||||
href: path.dirname(sectionPages[0].path)
|
||||
});
|
||||
.forEach(function(sectionPages, sectionName) {
|
||||
|
||||
// Push the rest of the sectionPages for this section
|
||||
_.forEach(sectionPages, function(sectionPage) {
|
||||
sectionPages = _.sortBy(sectionPages, 'name');
|
||||
|
||||
if ( sectionPages.length > 0 ) {
|
||||
// Push a navItem for this section
|
||||
navItems.push({
|
||||
name: sectionPage.name,
|
||||
href: sectionPage.path,
|
||||
type: sectionPage.docType
|
||||
name: sectionName,
|
||||
type: 'section',
|
||||
href: path.dirname(sectionPages[0].path)
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
// Push the rest of the sectionPages for this section
|
||||
_.forEach(sectionPages, function(sectionPage) {
|
||||
|
||||
navItems.push({
|
||||
name: sectionPage.name,
|
||||
href: sectionPage.path,
|
||||
type: sectionPage.docType
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
name: moduleName,
|
||||
href: modulePage.path,
|
||||
type: 'group',
|
||||
navItems: navItems
|
||||
};
|
||||
})
|
||||
.value();
|
||||
return navGroups;
|
||||
},
|
||||
tutorial: function(pages, area) {
|
||||
return [getNavGroup(pages, area, 'step', function(page) {
|
||||
return {
|
||||
name: moduleName,
|
||||
href: modulePage.path,
|
||||
type: 'group',
|
||||
navItems: navItems
|
||||
name: page.name,
|
||||
step: page.step,
|
||||
href: page.path,
|
||||
type: 'tutorial'
|
||||
};
|
||||
})
|
||||
.value();
|
||||
return navGroups;
|
||||
},
|
||||
tutorial: function(pages, area) {
|
||||
return [getNavGroup(pages, area, 'step', function(page) {
|
||||
return {
|
||||
name: page.name,
|
||||
step: page.step,
|
||||
href: page.path,
|
||||
type: 'tutorial'
|
||||
};
|
||||
})];
|
||||
},
|
||||
error: function(pages, area) {
|
||||
return [getNavGroup(pages, area, 'path', function(page) {
|
||||
return {
|
||||
name: page.name,
|
||||
href: page.path,
|
||||
type: page.docType === 'errorNamespace' ? 'section' : 'error'
|
||||
};
|
||||
})];
|
||||
},
|
||||
pages: function(pages, area) {
|
||||
return [getNavGroup(pages, area, 'path', function(page) {
|
||||
return {
|
||||
name: page.name,
|
||||
href: page.path,
|
||||
type: 'page'
|
||||
};
|
||||
})];
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
name: 'pages-data',
|
||||
description: 'This plugin will create a new doc that will be rendered as an angularjs module ' +
|
||||
'which will contain meta information about the pages and navigation',
|
||||
runAfter: ['adding-extra-docs', 'component-groups-generate', 'compute-path'],
|
||||
runBefore: ['extra-docs-added'],
|
||||
process: function(docs, config) {
|
||||
|
||||
var outputFolder = config.rendering.outputFolder;
|
||||
|
||||
_(docs)
|
||||
.filter(function(doc) { return doc.area === 'api'; })
|
||||
.filter(function(doc) { return doc.docType === 'module'; })
|
||||
.forEach(function(doc) { if ( !doc.path ) {
|
||||
log.warn('Missing path property for ', doc.id);
|
||||
}})
|
||||
.map(function(doc) { return _.pick(doc, ['id', 'module', 'docType', 'area']); })
|
||||
.tap(function(docs) {
|
||||
log.debug(docs);
|
||||
});
|
||||
|
||||
|
||||
// We are only interested in docs that are in a area and not landing pages
|
||||
var navPages = _.filter(docs, function(page) {
|
||||
return page.area &&
|
||||
page.docType != 'componentGroup';
|
||||
});
|
||||
|
||||
// Generate an object collection of pages that is grouped by area e.g.
|
||||
// - area "api"
|
||||
// - group "ng"
|
||||
// - section "directive"
|
||||
// - ngApp
|
||||
// - ngBind
|
||||
// - section "global"
|
||||
// - angular.element
|
||||
// - angular.bootstrap
|
||||
// - section "service"
|
||||
// - $compile
|
||||
// - group "ngRoute"
|
||||
// - section "directive"
|
||||
// - ngView
|
||||
// - section "service"
|
||||
// - $route
|
||||
//
|
||||
var areas = {};
|
||||
_(navPages)
|
||||
.groupBy('area')
|
||||
.forEach(function(pages, areaId) {
|
||||
var area = {
|
||||
id: areaId,
|
||||
name: AREA_NAMES[areaId]
|
||||
})];
|
||||
},
|
||||
error: function(pages, area) {
|
||||
return [getNavGroup(pages, area, 'path', function(page) {
|
||||
return {
|
||||
name: page.name,
|
||||
href: page.path,
|
||||
type: page.docType === 'errorNamespace' ? 'section' : 'error'
|
||||
};
|
||||
areas[areaId] = area;
|
||||
})];
|
||||
},
|
||||
pages: function(pages, area) {
|
||||
return [getNavGroup(
|
||||
pages,
|
||||
area,
|
||||
function(page) {
|
||||
return page.sortOrder || page.path;
|
||||
},
|
||||
function(page) {
|
||||
return {
|
||||
name: page.name,
|
||||
href: page.path,
|
||||
type: 'page'
|
||||
};
|
||||
}
|
||||
)];
|
||||
}
|
||||
};
|
||||
|
||||
var navGroupMapper = navGroupMappers[area.id] || navGroupMappers['pages'];
|
||||
area.navGroups = navGroupMapper(pages, area);
|
||||
return {
|
||||
$runAfter: ['paths-computed', 'generateKeywordsProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
$process: function(docs) {
|
||||
|
||||
// We are only interested in docs that are in an area
|
||||
var pages = _.filter(docs, function(doc) {
|
||||
return doc.area;
|
||||
});
|
||||
|
||||
// Extract a list of basic page information for mapping paths to partials and for client side searching
|
||||
var pages = _(docs)
|
||||
.map(function(doc) {
|
||||
var page = _.pick(doc, [
|
||||
'docType', 'id', 'name', 'area', 'outputPath', 'path', 'searchTerms'
|
||||
]);
|
||||
return page;
|
||||
})
|
||||
.indexBy('path')
|
||||
.value();
|
||||
// We are only interested in pages that are not landing pages
|
||||
var navPages = _.filter(pages, function(page) {
|
||||
return page.docType != 'componentGroup';
|
||||
});
|
||||
|
||||
// Generate an object collection of pages that is grouped by area e.g.
|
||||
// - area "api"
|
||||
// - group "ng"
|
||||
// - section "directive"
|
||||
// - ngApp
|
||||
// - ngBind
|
||||
// - section "global"
|
||||
// - angular.element
|
||||
// - angular.bootstrap
|
||||
// - section "service"
|
||||
// - $compile
|
||||
// - group "ngRoute"
|
||||
// - section "directive"
|
||||
// - ngView
|
||||
// - section "service"
|
||||
// - $route
|
||||
//
|
||||
var areas = {};
|
||||
_(navPages)
|
||||
.groupBy('area')
|
||||
.forEach(function(pages, areaId) {
|
||||
var area = {
|
||||
id: areaId,
|
||||
name: AREA_NAMES[areaId]
|
||||
};
|
||||
areas[areaId] = area;
|
||||
|
||||
var navGroupMapper = navGroupMappers[area.id] || navGroupMappers['pages'];
|
||||
area.navGroups = navGroupMapper(pages, area);
|
||||
});
|
||||
|
||||
docs.push({
|
||||
docType: 'nav-data',
|
||||
id: 'nav-data',
|
||||
template: 'nav-data.template.js',
|
||||
outputPath: 'js/nav-data.js',
|
||||
areas: areas
|
||||
});
|
||||
|
||||
|
||||
var docData = {
|
||||
docType: 'pages-data',
|
||||
id: 'pages-data',
|
||||
template: 'pages-data.template.js',
|
||||
outputPath: 'js/pages-data.js',
|
||||
|
||||
areas: areas,
|
||||
pages: pages
|
||||
};
|
||||
docs.push(docData);
|
||||
}
|
||||
var searchData = _(pages)
|
||||
.filter(function(page) {
|
||||
return page.searchTerms;
|
||||
})
|
||||
.map(function(page) {
|
||||
return _.extend({ path: page.path }, page.searchTerms);
|
||||
})
|
||||
.value();
|
||||
|
||||
docs.push({
|
||||
docType: 'json-doc',
|
||||
id: 'search-data-json',
|
||||
template: 'json-doc.template.json',
|
||||
outputPath: 'js/search-data.json',
|
||||
data: searchData
|
||||
});
|
||||
|
||||
// Extract a list of basic page information for mapping paths to partials and for client side searching
|
||||
var pageData = _(docs)
|
||||
.map(function(doc) {
|
||||
return _.pick(doc, ['name', 'area', 'path']);
|
||||
})
|
||||
.indexBy('path')
|
||||
.value();
|
||||
|
||||
docs.push({
|
||||
docType: 'pages-data',
|
||||
id: 'pages-data',
|
||||
template: 'pages-data.template.js',
|
||||
outputPath: 'js/pages-data.js',
|
||||
pages: pageData
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
|
||||
module.exports = {
|
||||
name: 'protractor-generate',
|
||||
description: 'Generate a protractor test file from the e2e tests in the examples',
|
||||
runAfter: ['adding-extra-docs'],
|
||||
runBefore: ['extra-docs-added'],
|
||||
process: function(docs, examples, config) {
|
||||
var protractorFolder = config.get('rendering.protractor.outputFolder', 'ptore2e');
|
||||
|
||||
_.forEach(examples, function(example) {
|
||||
|
||||
_.forEach(example.files, function(file) {
|
||||
|
||||
// Check if it's a Protractor test.
|
||||
if (file.type !== 'protractor') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new files for the tests.
|
||||
docs.push(createProtractorDoc(example, file, 'jquery'));
|
||||
docs.push(createProtractorDoc(example, file, 'jqlite'));
|
||||
});
|
||||
});
|
||||
|
||||
function createProtractorDoc(example, file, env) {
|
||||
var protractorDoc = {
|
||||
docType: 'e2e-test',
|
||||
id: 'protractorTest' + '-' + example.id,
|
||||
template: 'protractorTests.template.js',
|
||||
outputPath: path.join(protractorFolder, example.id, env + '_test.js'),
|
||||
innerTest: file.fileContents,
|
||||
pathPrefix: '.', // Hold for if we test with full jQuery
|
||||
exampleId: example.id,
|
||||
description: example.doc.id,
|
||||
'ng-app-included': example['ng-app-included']
|
||||
};
|
||||
|
||||
if (env === 'jquery') {
|
||||
protractorDoc.examplePath = example.outputFolder + '/index-jquery.html';
|
||||
} else {
|
||||
protractorDoc.examplePath = example.outputFolder + '/index.html';
|
||||
}
|
||||
return protractorDoc;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
@@ -1,38 +1,34 @@
|
||||
"use strict";
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
name: 'versions-data',
|
||||
description: 'This plugin will create a new doc that will be rendered as an angularjs module ' +
|
||||
'which will contain meta information about the versions of angular',
|
||||
runAfter: ['adding-extra-docs', 'pages-data'],
|
||||
runBefore: ['extra-docs-added'],
|
||||
process: function(docs, gitData) {
|
||||
/**
|
||||
* @dgProcessor generateVersionDocProcessor
|
||||
* @description
|
||||
* This processor will create a new doc that will be rendered as a JavaScript file
|
||||
* containing meta information about the current versions of AngularJS
|
||||
*/
|
||||
module.exports = function generateVersionDocProcessor(gitData) {
|
||||
return {
|
||||
$runAfter: ['generatePagesDataProcessor'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
$process: function(docs) {
|
||||
|
||||
var version = gitData.version;
|
||||
var versions = gitData.versions;
|
||||
var versionDoc = {
|
||||
docType: 'versions-data',
|
||||
id: 'versions-data',
|
||||
template: 'versions-data.template.js',
|
||||
outputPath: 'js/versions-data.js',
|
||||
currentVersion: gitData.version
|
||||
};
|
||||
|
||||
if ( !version ) {
|
||||
throw new Error('Invalid configuration. Please provide a valid `source.currentVersion` property');
|
||||
versionDoc.versions = _(gitData.versions)
|
||||
.filter(function(version) { return version.major > 0; })
|
||||
.push(gitData.version)
|
||||
.reverse()
|
||||
.value();
|
||||
|
||||
docs.push(versionDoc);
|
||||
}
|
||||
if ( !versions ) {
|
||||
throw new Error('Invalid configuration. Please provide a valid `source.previousVersions` property');
|
||||
}
|
||||
|
||||
var versionDoc = {
|
||||
docType: 'versions-data',
|
||||
id: 'versions-data',
|
||||
template: 'versions-data.template.js',
|
||||
outputPath: 'js/versions-data.js',
|
||||
};
|
||||
|
||||
versionDoc.currentVersion = version;
|
||||
|
||||
versionDoc.versions = _(versions)
|
||||
.filter(function(version) { return version.major > 0; })
|
||||
.push(version)
|
||||
.reverse()
|
||||
.value();
|
||||
|
||||
docs.push(versionDoc);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function debugDeployment(getVersion) {
|
||||
return {
|
||||
name: 'debug',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.js' ]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.js',
|
||||
'../angular-resource.js',
|
||||
'../angular-route.js',
|
||||
'../angular-cookies.js',
|
||||
'../angular-sanitize.js',
|
||||
'../angular-touch.js',
|
||||
'../angular-animate.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/nav-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function defaultDeployment(getVersion) {
|
||||
return {
|
||||
name: 'default',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.min.js' ]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.min.js',
|
||||
'../angular-resource.min.js',
|
||||
'../angular-route.min.js',
|
||||
'../angular-cookies.min.js',
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/nav-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
};
|
||||
};
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function jqueryDeployment(getVersion) {
|
||||
return {
|
||||
name: 'jquery',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [
|
||||
'../../components/jquery-' + getVersion('jquery') + '/jquery.js',
|
||||
'../../../angular.js'
|
||||
]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'components/jquery-' + getVersion('jquery') + '/jquery.js',
|
||||
'../angular.min.js',
|
||||
'../angular-resource.min.js',
|
||||
'../angular-route.min.js',
|
||||
'../angular-cookies.min.js',
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/nav-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
var versionInfo = require('../../../../lib/versions/version-info');
|
||||
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.cdnVersion;
|
||||
|
||||
module.exports = function productionDeployment(getVersion) {
|
||||
return {
|
||||
name: 'production',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ cdnUrl + '/angular.min.js' ]
|
||||
},
|
||||
dependencyPath: cdnUrl + '/'
|
||||
},
|
||||
scripts: [
|
||||
cdnUrl + '/angular.min.js',
|
||||
cdnUrl + '/angular-resource.min.js',
|
||||
cdnUrl + '/angular-route.min.js',
|
||||
cdnUrl + '/angular-cookies.min.js',
|
||||
cdnUrl + '/angular-sanitize.min.js',
|
||||
cdnUrl + '/angular-touch.min.js',
|
||||
cdnUrl + '/angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/nav-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
var StringMap = require('stringmap');
|
||||
|
||||
/**
|
||||
* @dgService errorNamespaceMap
|
||||
* A map of error namespaces by name.
|
||||
*/
|
||||
module.exports = function errorNamespaceMap() {
|
||||
return new StringMap();
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
var path = require('canonical-path');
|
||||
|
||||
/**
|
||||
* @dgService minErrInfo
|
||||
* @description
|
||||
* Load the error information that was generated during the AngularJS build.
|
||||
*/
|
||||
module.exports = function getMinerrInfo(readFilesProcessor) {
|
||||
return function() {
|
||||
var minerrInfoPath = path.resolve(readFilesProcessor.basePath, 'build/errors.json');
|
||||
return require(minerrInfoPath);
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
var path = require('canonical-path');
|
||||
|
||||
/**
|
||||
* dgService getVersion
|
||||
* @description
|
||||
* Find the current version of the bower component (or npm module)
|
||||
*/
|
||||
module.exports = function getVersion(readFilesProcessor) {
|
||||
var basePath = readFilesProcessor.basePath;
|
||||
|
||||
return function(component, sourceFolder, packageFile) {
|
||||
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
|
||||
packageFile = packageFile || 'bower.json';
|
||||
return require(path.join(sourceFolder,component,packageFile)).version;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
var gruntUtils = require('../../../lib/grunt/utils');
|
||||
var versionInfo = require('../../../lib/versions/version-info');
|
||||
|
||||
/**
|
||||
* @dgService gitData
|
||||
* @description
|
||||
* Information from the local git repository
|
||||
*/
|
||||
module.exports = function gitData() {
|
||||
return {
|
||||
version: versionInfo.currentVersion,
|
||||
versions: versionInfo.previousVersions,
|
||||
info: versionInfo.gitRepoInfo
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
name: 'sortOrder',
|
||||
transforms: function(doc, tag, value) {
|
||||
return parseInt(value, 10);
|
||||
}
|
||||
};
|
||||
@@ -56,15 +56,6 @@
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// force page reload when new update is available
|
||||
window.applicationCache && window.applicationCache.addEventListener('updateready', function(e) {
|
||||
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
|
||||
window.applicationCache.swapCache();
|
||||
window.location.reload();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// GA asynchronous tracker
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-8594346-3']);
|
||||
@@ -219,7 +210,7 @@
|
||||
</div>
|
||||
<div class="grid-right">
|
||||
<div id="loading" ng-show="loading">Loading...</div>
|
||||
<div ng-hide="loading" ng-include="currentPage.outputPath || 'Error404.html'" onload="afterPartialLoaded()" autoscroll></div>
|
||||
<div ng-hide="loading" ng-include="partialPath" autoscroll></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{$ doc.data | json $}
|
||||
@@ -0,0 +1,3 @@
|
||||
// Meta data used by the AngularJS docs app
|
||||
angular.module('navData', [])
|
||||
.value('NG_NAVIGATION', {$ doc.areas | json $});
|
||||
@@ -1,4 +1,3 @@
|
||||
// Meta data used by the AngularJS docs app
|
||||
angular.module('pagesData', [])
|
||||
.value('NG_PAGES', {$ doc.pages | json $})
|
||||
.value('NG_NAVIGATION', {$ doc.areas | json $});
|
||||
.value('NG_PAGES', {$ doc.pages | json $});
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
describe("{$ doc.description $}", function() {
|
||||
var rootEl;
|
||||
beforeEach(function() {
|
||||
rootEl = browser.rootEl;{% if doc['ng-app-included'] %}
|
||||
browser.rootEl = '[ng-app]';{% endif %}
|
||||
browser.get("{$ doc.pathPrefix $}/{$ doc.examplePath $}");
|
||||
});
|
||||
{% if doc['ng-app-included'] %}afterEach(function() { browser.rootEl = rootEl; });{% endif %}
|
||||
{$ doc.innerTest $}
|
||||
});
|
||||
@@ -2,15 +2,16 @@
|
||||
is HTML and wrap each line in a <p> - thus breaking the HTML #}
|
||||
|
||||
<div>
|
||||
<a ng-click="openPlunkr('{$ doc.example.outputFolder $}')" class="btn pull-right">
|
||||
<a ng-click="openPlunkr('{$ doc.path $}')" class="btn pull-right">
|
||||
<i class="glyphicon glyphicon-edit"> </i>
|
||||
Edit in Plunker</a>
|
||||
|
||||
<div class="runnable-example"
|
||||
path="{$ doc.example.outputFolder $}"
|
||||
path="{$ doc.example.deployments.default.path $}"
|
||||
{%- for attrName, attrValue in doc.example.attributes %}
|
||||
{$ attrName $}="{$ attrValue $}"{% endfor %}>
|
||||
|
||||
{% for fileName, file in doc.example.files %}
|
||||
{% for fileName, file in doc.example.files %}
|
||||
<div class="runnable-example-file" {% for attrName, attrValue in file.attributes %}
|
||||
{$ attrName $}="{$ attrValue $}"{% endfor %}>
|
||||
{% code -%}
|
||||
@@ -19,7 +20,7 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<iframe class="runnable-example-frame" src="{$ doc.example.outputFolder $}/index.html" name="{$ doc.example.id $}"></iframe>
|
||||
<iframe class="runnable-example-frame" src="{$ doc.example.deployments.default.outputPath $}" name="{$ doc.example.id $}"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ The documentation is organized into **{@link guide/module modules}** which conta
|
||||
These components are {@link guide/directive directives}, {@link guide/services services}, {@link guide/filter filters}, {@link guide/providers providers}, {@link guide/templates templates}, global APIs, and testing mocks.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Angular Namespaces `$` and `$$`**
|
||||
**Angular Prefixes `$` and `$$`**:
|
||||
|
||||
To prevent accidental name collisions with your code,
|
||||
Angular prefixes names of public objects with `$` and names of private objects with `$$`.
|
||||
Please do not use the `$` or `$$` prefix in your code.
|
||||
</div>
|
||||
|
||||
## Angular Namespace
|
||||
## Angular Modules
|
||||
|
||||
|
||||
## {@link ng ng (core module)}
|
||||
|
||||
@@ -12,10 +12,10 @@ $controller(MyController);
|
||||
$controller(MyController, {scope: newScope});
|
||||
```
|
||||
|
||||
To fix the example above please provide a scope to the $controller call:
|
||||
To fix the example above please provide a scope (using the `$scope` property in the locals object) to the $controller call:
|
||||
|
||||
```
|
||||
$controller(MyController, {$scope, newScope});
|
||||
$controller(MyController, {$scope: newScope});
|
||||
```
|
||||
|
||||
Please consult the {@link ng.$controller $controller} service api docs to learn more.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
@ngdoc error
|
||||
@name $location:nobase
|
||||
@fullName $location in HTML5 mode requires a <base> tag to be present!
|
||||
@description
|
||||
|
||||
If you configure {@link ng.$location `$location`} to use
|
||||
{@link api/ng.provider.$locationProvider `html5Mode`} (`history.pushState`), you need to specify the base URL for the application with a [`<base href="">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag or configure
|
||||
`$locationProvider` to not require a base tag by passing a definition object with
|
||||
`requireBase:false` to `$locationProvider.html5Mode()`:
|
||||
|
||||
```javascript
|
||||
$locationProvider.html5Mode({
|
||||
enabled: true,
|
||||
requireBase: false
|
||||
});
|
||||
```
|
||||
|
||||
Note that removing the requirement for a <base> tag will have adverse side effects when resolving
|
||||
relative paths with `$location` in IE9.
|
||||
|
||||
The base URL is then used to resolve all relative URLs throughout the application regardless of the
|
||||
entry point into the app.
|
||||
|
||||
If you are deploying your app into the root context (e.g. `https://myapp.com/`), set the base URL to `/`:
|
||||
|
||||
```html
|
||||
<head>
|
||||
<base href="/">
|
||||
...
|
||||
</head>
|
||||
```
|
||||
|
||||
If you are deploying your app into a sub-context (e.g. `https://myapp.com/subapp/`), set the base URL to the
|
||||
URL of the subcontext:
|
||||
|
||||
```html
|
||||
<head>
|
||||
<base href="/subapp">
|
||||
...
|
||||
</head>
|
||||
```
|
||||
|
||||
Before Angular 1.3 we didn't have this hard requirement and it was easy to write apps that worked
|
||||
when deployed in the root context but were broken when moved to a sub-context because in the
|
||||
sub-context all absolute urls would resolve to the root context of the app. To prevent this,
|
||||
use relative URLs throughout your app:
|
||||
|
||||
```html
|
||||
<!-- wrong: -->
|
||||
<a href="/userProfile">User Profile</a>
|
||||
|
||||
|
||||
<!-- correct: -->
|
||||
<a href="userProfile">User Profile</a>
|
||||
|
||||
```
|
||||
|
||||
Additionally, if you want to support [browsers that don't have the `history.pushState`
|
||||
API](http://caniuse.com/#feat=history), the fallback mechanism provided by `$location`
|
||||
won't work well without specifying the base url of the application.
|
||||
|
||||
In order to make it easier to migrate from hashbang mode to html5 mode, we require that the base
|
||||
URL is always specified when `$location`'s `html5mode` is enabled.
|
||||
@@ -0,0 +1,17 @@
|
||||
@ngdoc error
|
||||
@name $q:norslvr
|
||||
@fullName No resolver function passed to $Q
|
||||
@description
|
||||
|
||||
Occurs when calling creating a promise using {@link $q} as a constructor, without providing the
|
||||
required `resolver` function.
|
||||
|
||||
```
|
||||
//bad
|
||||
var promise = $q().then(doSomething);
|
||||
|
||||
//good
|
||||
var promise = $q(function(resolve, reject) {
|
||||
waitForSomethingAsync.then(resolve);
|
||||
}).then(doSomething);
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
@ngdoc error
|
||||
@name $q:qcycle
|
||||
@fullName Cannot resolve a promise with itself
|
||||
@description
|
||||
|
||||
Occurs when resolving a promise with itself as the value, including returning the promise in a
|
||||
function passed to `then`. The A+ 1.1 spec mandates that this behavior throw a TypeError.
|
||||
https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
|
||||
|
||||
```
|
||||
var promise = $q.defer().promise;
|
||||
|
||||
//bad
|
||||
promise.then(function (val) {
|
||||
//Cannot return self
|
||||
return promise;
|
||||
});
|
||||
|
||||
//good
|
||||
promise.then(function (val) {
|
||||
return 'some other value';
|
||||
});
|
||||
```
|
||||
@@ -10,7 +10,7 @@ Angular's {@link ng.$sce Strict Contextual Escaping (SCE)} mode
|
||||
contexts to result in a value that is trusted as safe for use in such a context. (e.g. loading an
|
||||
Angular template from a URL requires that the URL is one considered safe for loading resources.)
|
||||
|
||||
This helps prevent XSS and other security issues. Read more at {@link
|
||||
api/ng.$sce Strict Contextual Escaping (SCE)}
|
||||
This helps prevent XSS and other security issues. Read more at
|
||||
{@link ng.$sce Strict Contextual Escaping (SCE)}
|
||||
|
||||
You may want to include the ngSanitize module to use the automatic sanitizing.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Using $location
|
||||
@sortOrder 500
|
||||
@description
|
||||
|
||||
# What does it do?
|
||||
@@ -90,10 +91,11 @@ To configure the `$location` service, retrieve the
|
||||
{@link ng.$locationProvider $locationProvider} and set the parameters as follows:
|
||||
|
||||
|
||||
- **html5Mode(mode)**: {boolean}<br />
|
||||
`true` - see HTML5 mode<br />
|
||||
`false` - see Hashbang mode<br />
|
||||
default: `false`
|
||||
- **html5Mode(mode)**: {boolean|Object}<br />
|
||||
`true` or `enabled:true` - see HTML5 mode<br />
|
||||
`false` or `enabled:false` - see Hashbang mode<br />
|
||||
`requireBase:true` - see Relative links<br />
|
||||
default: `enabled:false`
|
||||
|
||||
- **hashPrefix(prefix)**: {string}<br />
|
||||
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)<br />
|
||||
@@ -163,7 +165,7 @@ encoded.
|
||||
|
||||
`$location` service has two configuration modes which control the format of the URL in the browser
|
||||
address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the
|
||||
HTML5 [History API](http://www.w3.org/TR/html5/history.html). Applications use the same API in
|
||||
HTML5 [History API](http://www.w3.org/TR/html5/introduction.html#history-0). Applications use the same API in
|
||||
both modes and the `$location` service will work with appropriate URL segments and browser APIs to
|
||||
facilitate the browser URL change and history management.
|
||||
|
||||
@@ -210,6 +212,10 @@ facilitate the browser URL change and history management.
|
||||
## Hashbang mode (default mode)
|
||||
|
||||
In this mode, `$location` uses Hashbang URLs in all browsers.
|
||||
Angular also does not intercept and rewrite links in this mode. I.e. links work
|
||||
as expected and also perform full page reloads when other parts of the url
|
||||
than the hash fragment was changed.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
@@ -240,7 +246,7 @@ it('should show example', inject(
|
||||
## HTML5 mode
|
||||
|
||||
In HTML5 mode, the `$location` service getters and setters interact with the browser URL address
|
||||
through the HTML5 history API, which allows for use of regular URL path and search segments,
|
||||
through the HTML5 history API. This allows for use of regular URL path and search segments,
|
||||
instead of their hashbang equivalents. If the HTML5 History API is not supported by a browser, the
|
||||
`$location` service will fall back to using the hashbang URLs automatically. This frees you from
|
||||
having to worry about whether the browser displaying your app supports the history API or not; the
|
||||
@@ -249,6 +255,10 @@ having to worry about whether the browser displaying your app supports the histo
|
||||
- Opening a regular URL in a legacy browser -> redirects to a hashbang URL
|
||||
- Opening hashbang URL in a modern browser -> rewrites to a regular URL
|
||||
|
||||
Note that in this mode, Angular intercepts all links (subject to the "Html link rewriting" rules below)
|
||||
and updates the url in a way that never performs a full page reload.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
```js
|
||||
@@ -297,8 +307,8 @@ history API or not; the `$location` service makes this transparent to you.
|
||||
|
||||
### Html link rewriting
|
||||
|
||||
When you use HTML5 history API mode, you will need different links in different browsers, but all you
|
||||
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||
When you use HTML5 history API mode, you will not need special hashbang links. All you have to do
|
||||
is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||
|
||||
When a user clicks on this link,
|
||||
|
||||
@@ -313,32 +323,28 @@ reload to the original link.
|
||||
Example: `<a href="/ext/link?a=b" target="_self">link</a>`
|
||||
- Absolute links that go to a different domain<br>
|
||||
Example: `<a href="http://angularjs.org/">link</a>`
|
||||
- Links starting with '/' that lead to a different base path when base is defined<br>
|
||||
- Links starting with '/' that lead to a different base path<br>
|
||||
Example: `<a href="/not-my-base/link">link</a>`
|
||||
|
||||
When running Angular in the root of a domain, along side perhaps a normal application in the same
|
||||
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
|
||||
to static files.
|
||||
|
||||
To prevent this, you can set your base href for the app to `<base href=".">` and then prefix links
|
||||
to URLs that should be handled with `.`. Now, links to locations, which are not to be routed by Angular,
|
||||
are not prefixed with `.` and will not be intercepted by the `otherwise` rule in your `$routeProvider`.
|
||||
### Relative links
|
||||
|
||||
Be sure to check all relative links, images, scripts etc. Angular requires you to specify the url
|
||||
base in the head of your main html file (`<base href="/my-base">`) unless `html5Mode.requireBase` is
|
||||
set to `false` in the html5Mode definition object passed to `$locationProvider.html5Mode()`. With
|
||||
that, relative urls will always be resolved to this base url, event if the initial url of the
|
||||
document was different.
|
||||
|
||||
There is one exception: Links that only contain a hash fragment (e.g. `<a href="#target">`)
|
||||
will only change `$location.hash()` and not modify the url otherwise. This is useful for scrolling
|
||||
to anchors on the same page without needing to know on which page the user currently is.
|
||||
|
||||
### Server side
|
||||
|
||||
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links
|
||||
to entry point of your application (e.g. index.html)
|
||||
|
||||
### Relative links
|
||||
|
||||
Be sure to check all relative links, images, scripts etc. You must either specify the url base in
|
||||
the head of your main html file (`<base href="/my-base">`) or you must use absolute urls
|
||||
(starting with `/`) everywhere because relative urls will be resolved to absolute urls using the
|
||||
initial absolute url of the document, which is often different from the root of the application.
|
||||
|
||||
Running Angular apps with the History API enabled from document root is strongly encouraged as it
|
||||
takes care of all relative link issues.
|
||||
to entry point of your application (e.g. index.html). Requiring a `<base>` tag is also important for
|
||||
this case, as it allows Angular to differentiate between the part of the url that is the application
|
||||
base and the path that should be handeled by the application.
|
||||
|
||||
### Sending links among different browsers
|
||||
|
||||
@@ -469,12 +475,12 @@ In these examples we use `<base href="/base/index.html" />`
|
||||
it("should show fake browser info on load", function(){
|
||||
expect(addressBar.getAttribute('value')).toBe(url);
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('h');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('h');
|
||||
|
||||
});
|
||||
|
||||
@@ -485,24 +491,24 @@ In these examples we use `<base href="/base/index.html" />`
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/first?a=b");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('');
|
||||
|
||||
|
||||
navigation.get(1).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/sec/ond?flag#hash");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('hash');
|
||||
});
|
||||
|
||||
</file>
|
||||
@@ -621,12 +627,12 @@ In these examples we use `<base href="/base/index.html" />`
|
||||
it("should show fake browser info on load", function(){
|
||||
expect(addressBar.getAttribute('value')).toBe(url);
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('h');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/path');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('h');
|
||||
|
||||
});
|
||||
|
||||
@@ -637,24 +643,24 @@ In these examples we use `<base href="/base/index.html" />`
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/first?a=b");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/first');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('');
|
||||
|
||||
|
||||
navigation.get(1).click();
|
||||
|
||||
expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/sec/ond?flag#hash");
|
||||
|
||||
expect(element(by.binding('$location.protocol')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash')).getText()).toBe('hash');
|
||||
expect(element(by.binding('$location.protocol()')).getText()).toBe('http');
|
||||
expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com');
|
||||
expect(element(by.binding('$location.port()')).getText()).toBe('80');
|
||||
expect(element(by.binding('$location.path()')).getText()).toBe('/sec/ond');
|
||||
expect(element(by.binding('$location.search()')).getText()).toBe('{"flag":true}');
|
||||
expect(element(by.binding('$location.hash()')).getText()).toBe('hash');
|
||||
|
||||
});
|
||||
</file>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Animations
|
||||
@sortOrder 310
|
||||
@description
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Bootstrap
|
||||
@sortOrder 350
|
||||
@description
|
||||
|
||||
# Bootstrap
|
||||
@@ -86,7 +87,9 @@ Here is an example of manually initializing Angular:
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
Hello {{greetMe}}!
|
||||
<div ng-controller="MyController">
|
||||
Hello {{greetMe}}!
|
||||
</div>
|
||||
<script src="http://code.angularjs.org/snapshot/angular.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name HTML Compiler
|
||||
@sortOrder 330
|
||||
@description
|
||||
|
||||
<div class="alert alert-warning">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Conceptual Overview
|
||||
@sortOrder 200
|
||||
@description
|
||||
|
||||
# Conceptual Overview
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Controllers
|
||||
@sortOrder 220
|
||||
@description
|
||||
|
||||
# Understanding Controllers
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Working With CSS
|
||||
@sortOrder 510
|
||||
@description
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Data Binding
|
||||
@sortOrder 210
|
||||
@description
|
||||
|
||||
Data-binding in Angular apps is the automatic synchronization of data between the model and view
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Dependency Injection
|
||||
@sortOrder 250
|
||||
@description
|
||||
|
||||
# Dependency Injection
|
||||
@@ -109,7 +110,7 @@ asks the injector to create an instance of the controller and its dependencies.
|
||||
injector.instantiate(MyController);
|
||||
```
|
||||
|
||||
This is all done behinds the scenes. Notice that by having the `ng-controller` ask the injector to
|
||||
This is all done behind the scenes. Notice that by having the `ng-controller` ask the injector to
|
||||
instantiate the class, it can satisfy all of the dependencies of `MyController` without the
|
||||
controller ever knowing about the injector.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Directives
|
||||
@sortOrder 300
|
||||
@description
|
||||
|
||||
# Creating Custom Directives
|
||||
@@ -84,7 +85,7 @@ Here are some equivalent examples of elements that match `ngBind`:
|
||||
<span x-ng-bind="name"></span> <br/>
|
||||
</div>
|
||||
</file>
|
||||
<file name="protractorTest.js">
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should show off bindings', function() {
|
||||
expect(element(by.css('div[ng-controller="Controller"] span[ng-bind]')).getText())
|
||||
.toBe('Max Karl Ernst Ludwig Planck (April 23, 1858 – October 4, 1947)');
|
||||
@@ -159,7 +160,7 @@ restrictions, you cannot simply write `cx="{{cx}}"`.
|
||||
With `ng-attr-cx` you can work around this problem.
|
||||
|
||||
If an attribute with a binding is prefixed with the `ngAttr` prefix (denormalized as `ng-attr-`)
|
||||
then during the binding will be applied to the corresponding unprefixed attribute. This allows
|
||||
then during the binding it will be applied to the corresponding unprefixed attribute. This allows
|
||||
you to bind to attributes that would otherwise be eagerly processed by browsers
|
||||
(e.g. an SVG element's `circle[cx]` attributes). When using `ngAttr`, the `allOrNothing` flag of
|
||||
{@link ng.$interpolate $interpolate} is used, so if any expression in the interpolated string
|
||||
@@ -281,12 +282,9 @@ using `templateUrl` instead:
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Great! But what if we wanted to have our directive match the tag name `<my-customer>` instead?
|
||||
If we simply put a `<my-customer>` element into the HTML, it doesn't work.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** When you create a directive, it is restricted to attribute only by default. In order to
|
||||
create directives that are triggered by element or class name, you need to use the `restrict` option.
|
||||
**Note:** When you create a directive, it is restricted to attribute and elements only by default. In order to
|
||||
create directives that are triggered by class name, you need to use the `restrict` option.
|
||||
</div>
|
||||
|
||||
The `restrict` option is typically set to:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name E2E Testing
|
||||
@sortOrder 420
|
||||
@description
|
||||
|
||||
# E2E Testing
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Expressions
|
||||
@sortOrder 270
|
||||
@description
|
||||
|
||||
# Angular Expressions
|
||||
@@ -38,7 +39,9 @@ the method from your view. If you want to `eval()` an Angular expression yoursel
|
||||
## Example
|
||||
<example>
|
||||
<file name="index.html">
|
||||
1+2={{1+2}}
|
||||
<span>
|
||||
1+2={{1+2}}
|
||||
</span>
|
||||
</file>
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Filters
|
||||
@sortOrder 280
|
||||
@description
|
||||
|
||||
A filter formats the value of an expression for display to the user. They can be used in view templates,
|
||||
@@ -86,12 +87,16 @@ This factory function should return a new filter function which takes the input
|
||||
as the first argument. Any filter arguments are passed in as additional arguments to the filter
|
||||
function.
|
||||
|
||||
The filter function should be a [pure function](http://en.wikipedia.org/wiki/Pure_function), which
|
||||
means that it should be stateless and idempotent. Angular relies on these properties and executes
|
||||
the filter only when the inputs to the function change.
|
||||
|
||||
The following sample filter reverses a text string. In addition, it conditionally makes the
|
||||
text upper-case.
|
||||
|
||||
<example module="myReverseModule">
|
||||
<example module="myReverseFilterApp">
|
||||
<file name="index.html">
|
||||
<div ng-controller="Controller">
|
||||
<div ng-controller="MyController">
|
||||
<input ng-model="greeting" type="text"><br>
|
||||
No filter: {{greeting}}<br>
|
||||
Reverse: {{greeting|reverse}}<br>
|
||||
@@ -100,7 +105,7 @@ text upper-case.
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('myReverseModule', [])
|
||||
angular.module('myReverseFilterApp', [])
|
||||
.filter('reverse', function() {
|
||||
return function(input, uppercase) {
|
||||
input = input || '';
|
||||
@@ -115,12 +120,53 @@ text upper-case.
|
||||
return out;
|
||||
};
|
||||
})
|
||||
.controller('Controller', ['$scope', function($scope) {
|
||||
.controller('MyController', ['$scope', function($scope) {
|
||||
$scope.greeting = 'hello';
|
||||
}]);
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
## Stateful filters
|
||||
|
||||
It is strongly discouraged to write filters that are stateful, because the execution of those can't
|
||||
be optimized by Angular, which often leads to performance issues. Many stateful filters can be
|
||||
converted into stateless filters just by exposing the hidden state as a model and turning it into an
|
||||
argument for the filter.
|
||||
|
||||
If you however do need to write a stateful filter, you have to mark the filter as `$stateful`, which
|
||||
means that it will be executed one or more times during the each `$digest` cycle.
|
||||
|
||||
<example module="myStatefulFilterApp">
|
||||
<file name="index.html">
|
||||
<div ng-controller="MyController">
|
||||
Input: <input ng-model="greeting" type="text"><br>
|
||||
Decoration: <input ng-model="decoration.symbol" type="text"><br>
|
||||
No filter: {{greeting}}<br>
|
||||
Decorated: {{greeting | decorate}}<br>
|
||||
</div>
|
||||
</file>
|
||||
|
||||
<file name="script.js">
|
||||
angular.module('myStatefulFilterApp', [])
|
||||
.filter('decorate', ['decoration', function(decoration) {
|
||||
|
||||
function decorateFilter(input) {
|
||||
return decoration.symbol + input + decoration.symbol;
|
||||
}
|
||||
decorateFilter.$stateful = true;
|
||||
|
||||
return decorateFilter;
|
||||
}])
|
||||
.controller('MyController', ['$scope', 'decoration', function($scope, decoration) {
|
||||
$scope.greeting = 'hello';
|
||||
$scope.decoration = decoration;
|
||||
}])
|
||||
.value('decoration', {symbol: '*'});
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
## Testing custom filters
|
||||
|
||||
See the [phonecat tutorial](http://docs.angularjs.org/tutorial/step_09#test) for an example.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Forms
|
||||
@sortOrder 290
|
||||
@description
|
||||
|
||||
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
@@ -285,7 +286,7 @@ In the following example we create two directives.
|
||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
||||
For example `1.23` is an invalid value, since it contains a fraction.
|
||||
Note that we unshift the array instead of pushing.
|
||||
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
This is because we want it to be the first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
|
||||
* The second directive is a `smart-float`.
|
||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name i18n and l10n
|
||||
@sortOrder 520
|
||||
@description
|
||||
|
||||
# i18n and l10n
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Internet Explorer Compatibility
|
||||
@sortOrder 530
|
||||
@description
|
||||
|
||||
# Internet Explorer Compatibility
|
||||
|
||||
@@ -70,7 +70,7 @@ 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://angular-translate.github.io), [angular-gettext](http://angular-gettext.rocketeer.be/)
|
||||
* **Internationalization:** [angular-translate](http://angular-translate.github.io), [angular-gettext](http://angular-gettext.rocketeer.be/), [angular-localization](http://doshprompt.github.io/angular-localization/)
|
||||
* **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/), [ngTagsInput](https://github.com/mbenford/ngTagsInput)
|
||||
@@ -81,6 +81,7 @@ This is a short list of libraries with specific support and documentation for wo
|
||||
|
||||
### General
|
||||
|
||||
* **Docs Page:** {@link guide/production Running an AngularJS App in Production}
|
||||
* **Javascript minification: **[Background](http://thegreenpizza.github.io/2013/05/25/building-minification-safe-angular.js-applications/), [ng-annotate automation tool](https://github.com/olov/ng-annotate)
|
||||
* **Analytics and Logging:** [Angularyitcs (Google Analytics)](http://ngmodules.org/modules/angularytics), [Angulartics (Analytics)](https://github.com/luisfarzati/angulartics), [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/)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Introduction
|
||||
@sortOrder 100
|
||||
@description
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Migrating from Previous Versions
|
||||
@sortOrder 550
|
||||
@description
|
||||
|
||||
Minor version releases in AngularJS introduce several breaking changes that may require changes to your
|
||||
@@ -95,7 +96,7 @@ this limitation, use a regular expression object as the value for the expression
|
||||
//after
|
||||
$scope.exp = /abc/i;
|
||||
- **Scope:** due to [8c6a8171](https://github.com/angular/angular.js/commit/8c6a8171f9bdaa5cdabc0cc3f7d3ce10af7b434d),
|
||||
Scope#$id is now of time number rather than string. Since the
|
||||
Scope#$id is now of type number rather than string. Since the
|
||||
id is primarily being used for debugging purposes this change should not affect
|
||||
anyone.
|
||||
- **forEach:** due to [55991e33](https://github.com/angular/angular.js/commit/55991e33af6fece07ea347a059da061b76fc95f5),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Modules
|
||||
@sortOrder 320
|
||||
@description
|
||||
|
||||
# What is a Module?
|
||||
@@ -50,7 +51,7 @@ I'm in a hurry. How do I get a Hello World module working?
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should add Hello to the name', function() {
|
||||
expect(element(by.binding("{{ 'World' | greet }}")).getText()).toEqual('Hello, World!');
|
||||
expect(element(by.binding("'World' | greet")).getText()).toEqual('Hello, World!');
|
||||
});
|
||||
</file>
|
||||
</example>
|
||||
@@ -128,7 +129,7 @@ The above is a suggestion. Tailor it to your needs.
|
||||
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should add Hello to the name', function() {
|
||||
expect(element(by.binding("{{ greeting }}")).getText()).toEqual('Bonjour World!');
|
||||
expect(element(by.binding("greeting")).getText()).toEqual('Bonjour World!');
|
||||
});
|
||||
</file>
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
@ngdoc overview
|
||||
@name Running in Production
|
||||
@sortOrder 540
|
||||
@description
|
||||
|
||||
# Running an AngularJS App in Production
|
||||
|
||||
There are a few things you might consider when running your AngularJS application in production.
|
||||
|
||||
|
||||
## Disabling Debug Data
|
||||
|
||||
By default AngularJS attaches information about scopes to DOM nodes, and adds CSS classes
|
||||
to data-bound elements. The information that is not included is:
|
||||
|
||||
As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class
|
||||
`ng-class` is attached to the corresponding element.
|
||||
|
||||
Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope`
|
||||
CSS class are attached to the corresponding element. These scope references can then be accessed via
|
||||
`element.scope()` and `element.isolateScope()`.
|
||||
|
||||
Tools like [Protractor](github.com/angular/protractor) and
|
||||
[Batarang](https://github.com/angular/angularjs-batarang) need this information to run,
|
||||
but you can disable this in production for a significant performance boost with:
|
||||
|
||||
```js
|
||||
myApp.config(['$compileProvider', function ($compileProvider) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}]);
|
||||
```
|
||||
|
||||
If you wish to debug an application with this information then you should open up a debug
|
||||
console in the browser then call this method directly in this console:
|
||||
|
||||
```js
|
||||
angular.reloadWithDebugInfo();
|
||||
```
|
||||
|
||||
The page should reload and the debug information should now be available.
|
||||
|
||||
For more see the docs pages on {@link ng.$compileProvider#debugInfoEnabled `$compileProvider`}
|
||||
and {@link ng/function/angular.reloadWithDebugInfo `angular.reloadWithDebugInfo`}.
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Providers
|
||||
@sortOrder 340
|
||||
@description
|
||||
|
||||
# Providers
|
||||
@@ -97,9 +98,8 @@ created by this recipe.
|
||||
Note: All services in Angular are singletons. That means that the injector uses each recipe at most
|
||||
once to create the object. The injector then caches the reference for all future needs.
|
||||
|
||||
Since Factory is more a powerful version of the Value recipe, you can construct the same service with it.
|
||||
Using our previous `clientId` Value recipe example, we can rewrite it as a Factory recipe like
|
||||
this:
|
||||
Since a Factory is a more powerful version of the Value recipe, the same service can be constructed with it.
|
||||
Using our previous `clientId` Value recipe example, we can rewrite it as a Factory recipe like this:
|
||||
|
||||
```javascript
|
||||
myApp.factory('clientId', function clientIdFactory() {
|
||||
@@ -134,11 +134,11 @@ token.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** name the factory functions as `<serviceId>Factory`
|
||||
(e.g. apiTokenFactory). While this naming convention is not required, it helps when navigating the code base
|
||||
(e.g., apiTokenFactory). While this naming convention is not required, it helps when navigating the codebase
|
||||
or looking at stack traces in the debugger.
|
||||
</div>
|
||||
|
||||
Just like with Value recipe, Factory recipe can create a service of any type, whether it be a
|
||||
Just like with the Value recipe, the Factory recipe can create a service of any type, whether it be a
|
||||
primitive, object literal, function, or even an instance of a custom type.
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ function UnicornLauncher(apiToken) {
|
||||
|
||||
this.launchedCount = 0;
|
||||
this.launch = function() {
|
||||
// make a request to the remote api and include the apiToken
|
||||
// Make a request to the remote API and include the apiToken
|
||||
...
|
||||
this.launchedCount++;
|
||||
}
|
||||
@@ -170,7 +170,7 @@ myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
|
||||
```
|
||||
|
||||
|
||||
This is, however, exactly the use-case that Service recipe is the most suitable for.
|
||||
This is, however, exactly the use-case that the Service recipe is the most suitable for.
|
||||
|
||||
The Service recipe produces a service just like the Value or Factory recipes, but it does so by
|
||||
*invoking a constructor with the `new` operator*. The constructor can take zero or more arguments,
|
||||
@@ -189,7 +189,7 @@ myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);
|
||||
Much simpler!
|
||||
|
||||
Note: Yes, we have called one of our service recipes 'Service'. We regret this and know that we'll
|
||||
be somehow punished for our mis-deed. It's like we named one of our offspring 'Child'. Boy,
|
||||
be somehow punished for our misdeed. It's like we named one of our offspring 'Child'. Boy,
|
||||
that would mess with the teachers.
|
||||
|
||||
|
||||
@@ -199,8 +199,8 @@ As already mentioned in the intro, the Provider recipe is the core recipe type a
|
||||
all the other recipe types are just syntactic sugar on top of it. It is the most verbose recipe
|
||||
with the most abilities, but for most services it's overkill.
|
||||
|
||||
Provider recipe is syntactically defined as a custom type that implements a `$get` method. This
|
||||
method is a factory function just like the one we use in Factory recipe. In fact, if you define
|
||||
The Provider recipe is syntactically defined as a custom type that implements a `$get` method. This
|
||||
method is a factory function just like the one we use in the Factory recipe. In fact, if you define
|
||||
a Factory recipe, an empty Provider type with the `$get` method set to your factory function is
|
||||
automatically created under the hood.
|
||||
|
||||
@@ -248,7 +248,7 @@ and wires (injects) all provider instances only.
|
||||
|
||||
During application bootstrap, before Angular goes off creating all services, it configures and
|
||||
instantiates all providers. We call this the configuration phase of the application life-cycle.
|
||||
During this phase services aren't accessible because they haven't been created yet.
|
||||
During this phase, services aren't accessible because they haven't been created yet.
|
||||
|
||||
Once the configuration phase is over, interaction with providers is disallowed and the process of
|
||||
creating services starts. We call this part of the application life-cycle the run phase.
|
||||
@@ -259,9 +259,9 @@ creating services starts. We call this part of the application life-cycle the ru
|
||||
We've just learned how Angular splits the life-cycle into configuration phase and run phase and how
|
||||
you can provide configuration to your application via the config function. Since the config
|
||||
function runs in the configuration phase when no services are available, it doesn't have access
|
||||
even to simple value objects created via Value recipe.
|
||||
even to simple value objects created via the Value recipe.
|
||||
|
||||
Since simple values, like url prefix, don't have dependencies or configuration, it is often handy
|
||||
Since simple values, like URL prefixes, don't have dependencies or configuration, it's often handy
|
||||
to make them available in both the configuration and run phases. This is what the Constant recipe
|
||||
is for.
|
||||
|
||||
@@ -317,7 +317,7 @@ Let's take a look at how we would create a very simple component via the directi
|
||||
on the `planetName` constant we've just defined and displays the planet name, in our case:
|
||||
"Planet Name: Greasy Giant".
|
||||
|
||||
Since the directives are registered via Factory recipe, we can use the same syntax as with factories.
|
||||
Since the directives are registered via the Factory recipe, we can use the same syntax as with factories.
|
||||
|
||||
```javascript
|
||||
myApp.directive('myPlanet', ['planetName', function myPlanetDirectiveFactory(planetName) {
|
||||
@@ -340,7 +340,7 @@ We can then use the component like this:
|
||||
</html>
|
||||
```
|
||||
|
||||
Using Factory recipes you can also define Angular's filters and animations, but the controllers
|
||||
Using Factory recipes, you can also define Angular's filters and animations, but the controllers
|
||||
are a bit special. You create a controller as a custom type that declares its dependencies as
|
||||
arguments for its constructor function. This constructor is then registered with a module. Let's
|
||||
take a look at the `DemoController`, created in one of the early examples:
|
||||
@@ -351,7 +351,7 @@ myApp.controller('DemoController', ['clientId', function DemoController(clientId
|
||||
}]);
|
||||
```
|
||||
|
||||
The DemoController is instantiated via its constructor every time the app needs an instance of
|
||||
The DemoController is instantiated via its constructor, every time the app needs an instance of
|
||||
DemoController (in our simple app it's just once). So unlike services, controllers are not
|
||||
singletons. The constructor is called with all the requested services, in our case the `clientId`
|
||||
service.
|
||||
@@ -365,12 +365,12 @@ To wrap it up, let's summarize the most important points:
|
||||
- There are five recipe types that define how to create objects: Value, Factory, Service, Provider
|
||||
and Constant.
|
||||
- Factory and Service are the most commonly used recipes. The only difference between them is that
|
||||
Service recipe works better for objects of custom type, while Factory can produce JavaScript
|
||||
the Service recipe works better for objects of a custom type, while the Factory can produce JavaScript
|
||||
primitives and functions.
|
||||
- The Provider recipe is the core recipe type and all the other ones are just syntactic sugar on it.
|
||||
- Provider is the most complex recipe type. You don't need it unless you are building a reusable
|
||||
piece of code that needs global configuration.
|
||||
- All special purpose objects except for Controller are defined via Factory recipes.
|
||||
- All special purpose objects except for the Controller are defined via Factory recipes.
|
||||
|
||||
<table class="table table-bordered code-table">
|
||||
<thead>
|
||||
@@ -409,7 +409,15 @@ To wrap it up, let's summarize the most important points:
|
||||
<td class="success">yes\*\*</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>can create functions/primitives</td>
|
||||
<td>can create functions</td>
|
||||
<td class="success">yes</td>
|
||||
<td class="success">yes</td>
|
||||
<td class="success">yes</td>
|
||||
<td class="success">yes</td>
|
||||
<td class="success">yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>can create primitives</td>
|
||||
<td class="success">yes</td>
|
||||
<td class="error">no</td>
|
||||
<td class="success">yes</td>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Scopes
|
||||
@sortOrder 240
|
||||
@description
|
||||
|
||||
# What are Scopes?
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Services
|
||||
@sortOrder 230
|
||||
@description
|
||||
|
||||
# Services
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Templates
|
||||
@sortOrder 260
|
||||
@description
|
||||
|
||||
In Angular, templates are written with HTML that contains Angular-specific elements and attributes.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@ngdoc overview
|
||||
@name Unit Testing
|
||||
@sortOrder 410
|
||||
@description
|
||||
|
||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
||||
@@ -337,6 +338,16 @@ We inject the $compile service and $rootScope before each jasmine test. The $com
|
||||
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
|
||||
replaced the content and "lidless, wreathed in flame, 2 times" is present.
|
||||
|
||||
<div class="alert alert-info">
|
||||
**Underscore notation**:
|
||||
|
||||
The use of the underscore notation (e.g.: `_$rootScope_`) is a convention wide spread in AngularJS
|
||||
community to keep the variable names clean in your tests. That's why the
|
||||
{@link $injector} strips out the leading and the trailing underscores when
|
||||
matching the parameters. The underscore rule applies ***only*** if the name starts **and** ends with
|
||||
exactly one underscore, otherwise no replacing happens.
|
||||
</div>
|
||||
|
||||
### Testing Transclusion Directives
|
||||
|
||||
Directives that use transclusion are treated specially by the compiler. Before their compile
|
||||
|
||||
@@ -205,7 +205,7 @@ If you want to apply a directive to each inner piece of the repeat, put it on a
|
||||
|
||||
### `$rootScope` exists, but it can be used for evil
|
||||
|
||||
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
|
||||
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree.
|
||||
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
|
||||
|
||||
Occasionally there are pieces of data that you want to make global to the whole app.
|
||||
|
||||
@@ -233,7 +233,7 @@ browser is limited, which results in your karma tests running extremely slow.
|
||||
|
||||
Refresh your browser and verify that it says "Hello, World!".
|
||||
|
||||
* Update the unit test for the controller in ./test/unit/controllersSpec.js to reflect the previous change. For example by adding:
|
||||
* Update the unit test for the controller in `./test/unit/controllersSpec.js` to reflect the previous change. For example by adding:
|
||||
|
||||
expect(scope.name).toBe('World');
|
||||
|
||||
@@ -250,6 +250,8 @@ browser is limited, which results in your karma tests running extremely slow.
|
||||
<tr><th>row number</th></tr>
|
||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
||||
</table>
|
||||
|
||||
Extra points: try and make an 8x8 table using an additional `ng-repeat`.
|
||||
|
||||
* Make the unit test fail by changing `expect(scope.phones.length).toBe(3)` to instead use `toBe(4)`.
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ describe('PhoneCat App', function() {
|
||||
});
|
||||
|
||||
|
||||
it('should filter the phone list as user types into the search box', function() {
|
||||
it('should filter the phone list as a user types into the search box', function() {
|
||||
|
||||
var phoneList = element.all(by.repeater('phone in phones'));
|
||||
var query = element(by.model('query'));
|
||||
@@ -159,7 +159,7 @@ Let's see how we can get the current value of the `query` model to appear in the
|
||||
var phoneList = element.all(by.repeater('phone in phones'));
|
||||
var query = element(by.model('query'));
|
||||
|
||||
it('should filter the phone list as user types into the search box', function() {
|
||||
it('should filter the phone list as a user types into the search box', function() {
|
||||
expect(phoneList.count()).toBe(3);
|
||||
|
||||
query.sendKeys('nexus');
|
||||
|
||||
@@ -11,7 +11,7 @@ from our server using one of Angular's built-in {@link guide/services services}
|
||||
ng.$http $http}. We will use Angular's {@link guide/di dependency
|
||||
injection (DI)} to provide the service to the `PhoneListCtrl` controller.
|
||||
|
||||
* There are now a list of 20 phones, loaded from the server.
|
||||
* There is now a list of 20 phones, loaded from the server.
|
||||
|
||||
<div doc-tutorial-reset="5"></div>
|
||||
|
||||
@@ -166,7 +166,7 @@ Because we started using dependency injection and our controller has dependencie
|
||||
controller in our tests is a bit more complicated. We could use the `new` operator and provide the
|
||||
constructor with some kind of fake `$http` implementation. However, Angular provides a mock `$http`
|
||||
service that we can use in unit tests. We configure "fake" responses to server requests by calling
|
||||
methods on a service called $httpBackend:
|
||||
methods on a service called `$httpBackend`:
|
||||
|
||||
```js
|
||||
describe('PhoneCat controllers', function() {
|
||||
|
||||
@@ -26,15 +26,16 @@ We are using [Bower][bower] to install client side dependencies. This step upda
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "angular-seed",
|
||||
"name": "angular-phonecat",
|
||||
"description": "A starter project for AngularJS",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular-seed",
|
||||
"homepage": "https://github.com/angular/angular-phonecat",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"angular": "1.2.x",
|
||||
"angular-mocks": "~1.2.x",
|
||||
"jquery": "1.10.2",
|
||||
"bootstrap": "~3.1.1",
|
||||
"angular-route": "~1.2.x"
|
||||
}
|
||||
|
||||
@@ -49,8 +49,15 @@ and install this dependency. We can do this by running:
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of Angular has been released since you last ran `npm install`, then you may have a
|
||||
problem with the `bower install` due to a conflict between the versions of angular.js that need to
|
||||
be installed. If you get this then simply delete your `app/bower_components` folder before running
|
||||
`npm install`.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
**Note:** If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ animations on top of the template code we created before.
|
||||
## Dependencies
|
||||
|
||||
The animation functionality is provided by Angular in the `ngAnimate` module, which is distributed
|
||||
separately from the core Angular framework. In addition we will use `JQuery` in this project to do
|
||||
separately from the core Angular framework. In addition we will use `jQuery` in this project to do
|
||||
extra JavaScript animations.
|
||||
|
||||
We are using [Bower][bower] to install client side dependencies. This step updates the
|
||||
@@ -49,8 +49,8 @@ We are using [Bower][bower] to install client side dependencies. This step upda
|
||||
|
||||
* `"angular-animate": "~1.2.x"` tells bower to install a version of the
|
||||
angular-animate component that is compatible with version 1.2.x.
|
||||
* `"jquery": "1.10.2"` tells bower to install the 1.10.2 version of JQuery. Note that this is not an
|
||||
Angular library, it is the standard JQuery library. We can use bower to install a wide range of 3rd
|
||||
* `"jquery": "1.10.2"` tells bower to install the 1.10.2 version of jQuery. Note that this is not an
|
||||
Angular library, it is the standard jQuery library. We can use bower to install a wide range of 3rd
|
||||
party libraries.
|
||||
|
||||
We must ask bower to download and install this dependency. We can do this by running:
|
||||
@@ -59,8 +59,15 @@ We must ask bower to download and install this dependency. We can do this by run
|
||||
npm install
|
||||
```
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Warning:** If a new version of Angular has been released since you last ran `npm install`, then you may have a
|
||||
problem with the `bower install` due to a conflict between the versions of angular.js that need to
|
||||
be installed. If you get this then simply delete your `app/bower_components` folder before running
|
||||
`npm install`.
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
**Note:** If you have bower installed globally then you can run `bower install` but for this project we have
|
||||
preconfigured `npm install` to run bower for us.
|
||||
</div>
|
||||
|
||||
@@ -248,7 +255,7 @@ which are described in detail below.
|
||||
Next let's add an animation for transitions between route changes in {@link api/ngRoute.directive:ngView `ngView`}.
|
||||
|
||||
To start, let's add a new CSS class to our HTML like we did in the example above.
|
||||
This time, instead of the `ng-repeat` element, let's add it to the element containing the ng-view directive.
|
||||
This time, instead of the `ng-repeat` element, let's add it to the element containing the `ng-view` directive.
|
||||
In order to do this, we'll have to make some small changes to the HTML code so that we can have more control over our
|
||||
animations between view changes.
|
||||
|
||||
@@ -333,13 +340,13 @@ a cross fade animation in between. So as the previous page is just about to be r
|
||||
while the new page fades in right on top of it.
|
||||
|
||||
Once the leave animation is over then element is removed and once the enter animation is complete
|
||||
then the `ng-enter` and `ng-enter-active` CSS classes are removed from the element rendering it to
|
||||
be position itself with its default CSS code (so no more absolute positioning once the animation is
|
||||
then the `ng-enter` and `ng-enter-active` CSS classes are removed from the element, causing it to rerender and
|
||||
reposition itself with its default CSS code (so no more absolute positioning once the animation is
|
||||
over). This works fluidly so that pages flow naturally between route changes without anything
|
||||
jumping around.
|
||||
|
||||
The CSS classes applied (the start and end classes) are much the same as with `ng-repeat`. Each time
|
||||
a new page is loaded the ng-view directive will create a copy of itself, download the template and
|
||||
a new page is loaded the `ng-view` directive will create a copy of itself, download the template and
|
||||
append the contents. This ensures that all views are contained within a single HTML element which
|
||||
allows for easy animation control.
|
||||
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
var path = require('canonical-path');
|
||||
var versionInfo = require('../lib/versions/version-info');
|
||||
var basePath = __dirname;
|
||||
|
||||
var basePackage = require('./config');
|
||||
|
||||
module.exports = function(config) {
|
||||
|
||||
var cdnUrl = "//ajax.googleapis.com/ajax/libs/angularjs/" + versionInfo.cdnVersion;
|
||||
|
||||
var getVersion = function(component, sourceFolder, packageFile) {
|
||||
sourceFolder = sourceFolder || '../bower_components';
|
||||
packageFile = packageFile || 'bower.json';
|
||||
return require(path.join(sourceFolder,component,packageFile)).version;
|
||||
};
|
||||
|
||||
|
||||
config = basePackage(config);
|
||||
|
||||
config.set('source.projectPath', path.resolve(basePath, '..'));
|
||||
|
||||
config.set('source.files', [
|
||||
{ pattern: 'src/**/*.js', basePath: path.resolve(basePath,'..') },
|
||||
{ pattern: '**/*.ngdoc', basePath: path.resolve(basePath, 'content') }
|
||||
]);
|
||||
|
||||
config.set('processing.stopOnError', true);
|
||||
|
||||
config.set('processing.errors.minerrInfoPath', path.resolve(basePath, '../build/errors.json'));
|
||||
|
||||
config.set('rendering.outputFolder', '../build/docs');
|
||||
config.set('rendering.contentsFolder', 'partials');
|
||||
|
||||
config.set('logging.level', 'info');
|
||||
|
||||
config.merge('deployment', {
|
||||
environments: [{
|
||||
name: 'debug',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.js' ]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.js',
|
||||
'../angular-resource.js',
|
||||
'../angular-route.js',
|
||||
'../angular-cookies.js',
|
||||
'../angular-sanitize.js',
|
||||
'../angular-touch.js',
|
||||
'../angular-animate.js',
|
||||
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'default',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ '../../../angular.min.js' ]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'../angular.min.js',
|
||||
'../angular-resource.min.js',
|
||||
'../angular-route.min.js',
|
||||
'../angular-cookies.min.js',
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'jquery',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [
|
||||
'../../components/jquery-' + getVersion('jquery') + '/jquery.js',
|
||||
'../../../angular.js'
|
||||
]
|
||||
},
|
||||
dependencyPath: '../../../'
|
||||
},
|
||||
scripts: [
|
||||
'components/jquery-' + getVersion('jquery') + '/jquery.js',
|
||||
'../angular.min.js',
|
||||
'../angular-resource.min.js',
|
||||
'../angular-route.min.js',
|
||||
'../angular-cookies.min.js',
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'production',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [ cdnUrl + '/angular.min.js' ]
|
||||
},
|
||||
dependencyPath: cdnUrl + '/'
|
||||
},
|
||||
scripts: [
|
||||
cdnUrl + '/angular.min.js',
|
||||
cdnUrl + '/angular-resource.min.js',
|
||||
cdnUrl + '/angular-route.min.js',
|
||||
cdnUrl + '/angular-cookies.min.js',
|
||||
cdnUrl + '/angular-sanitize.min.js',
|
||||
cdnUrl + '/angular-touch.min.js',
|
||||
cdnUrl + '/angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked', '../node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/bootstrap.js',
|
||||
'js/angular-bootstrap/bootstrap-prettify.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr.js-' + getVersion('lunr.js') + '/lunr.min.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/prettify.js',
|
||||
'components/google-code-prettify-' + getVersion('google-code-prettify') + '/src/lang-css.js',
|
||||
'js/versions-data.js',
|
||||
'js/pages-data.js',
|
||||
'js/docs.js'
|
||||
],
|
||||
stylesheets: [
|
||||
'components/bootstrap-' + getVersion('bootstrap') + '/css/bootstrap.min.css',
|
||||
'components/open-sans-fontface-' + getVersion('open-sans-fontface') + '/open-sans.css',
|
||||
'css/prettify-theme.css',
|
||||
'css/docs.css',
|
||||
'css/animations.css'
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return config;
|
||||
};
|
||||
+26
-12
@@ -1,8 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
var gulp = require('gulp');
|
||||
var log = require('gulp-util').log;
|
||||
var concat = require('gulp-concat');
|
||||
var jshint = require('gulp-jshint');
|
||||
var bower = require('bower');
|
||||
var dgeni = require('dgeni');
|
||||
var Dgeni = require('dgeni');
|
||||
var merge = require('event-stream').merge;
|
||||
var path = require('canonical-path');
|
||||
|
||||
@@ -12,8 +15,10 @@ var path = require('canonical-path');
|
||||
// See clean and bower for async tasks, and see assets and doc-gen for dependent tasks below
|
||||
|
||||
var outputFolder = '../build/docs';
|
||||
var bowerFolder = '../bower_components';
|
||||
var bowerFolder = 'bower_components';
|
||||
|
||||
var src = 'app/src/**/*.js';
|
||||
var assets = 'app/assets/**/*';
|
||||
|
||||
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
|
||||
pattern = pattern || '/**/*';
|
||||
@@ -26,34 +31,40 @@ var copyComponent = function(component, pattern, sourceFolder, packageFile) {
|
||||
};
|
||||
|
||||
gulp.task('bower', function() {
|
||||
return bower.commands.install();
|
||||
var bowerTask = bower.commands.install();
|
||||
bowerTask.on('log', function (result) {
|
||||
log('bower:', result.id, result.data.endpoint.name);
|
||||
});
|
||||
bowerTask.on('error', function(error) {
|
||||
log(error);
|
||||
});
|
||||
return bowerTask;
|
||||
});
|
||||
|
||||
gulp.task('build-app', function() {
|
||||
gulp.src('app/src/**/*.js')
|
||||
gulp.src(src)
|
||||
.pipe(concat('docs.js'))
|
||||
.pipe(gulp.dest(outputFolder + '/js/'));
|
||||
});
|
||||
|
||||
gulp.task('assets', ['bower'], function() {
|
||||
return merge(
|
||||
gulp.src(['app/assets/**/*']).pipe(gulp.dest(outputFolder)),
|
||||
gulp.src([assets]).pipe(gulp.dest(outputFolder)),
|
||||
copyComponent('bootstrap', '/dist/**/*'),
|
||||
copyComponent('open-sans-fontface'),
|
||||
copyComponent('lunr.js','/*.js'),
|
||||
copyComponent('google-code-prettify'),
|
||||
copyComponent('jquery', '/jquery.*'),
|
||||
copyComponent('jquery', '/dist/*.js'),
|
||||
copyComponent('marked', '/**/*.js', '../node_modules', 'package.json')
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('doc-gen', function() {
|
||||
var generateDocs = dgeni.generator('docs.config.js');
|
||||
return generateDocs()
|
||||
.catch(function(error) {
|
||||
process.exit(1);
|
||||
});
|
||||
gulp.task('doc-gen', ['bower'], function() {
|
||||
var dgeni = new Dgeni([require('./config')]);
|
||||
return dgeni.generate().catch(function(error) {
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
||||
// JSHint the example and protractor test files
|
||||
@@ -68,3 +79,6 @@ gulp.task('jshint', ['doc-gen'], function() {
|
||||
// The default task that will be run if no task is supplied
|
||||
gulp.task('default', ['assets', 'doc-gen', 'build-app', 'jshint']);
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch([src, assets], ['assets', 'build-app']);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../protractor-shared-conf').config;
|
||||
|
||||
config.specs = [
|
||||
'app/e2e/**/*.scenario.js'
|
||||
];
|
||||
|
||||
config.capabilities = {
|
||||
browserName: 'chrome',
|
||||
};
|
||||
|
||||
exports.config = config;
|
||||
@@ -319,7 +319,6 @@ goog.provide('goog.i18n.DateTimeSymbols_fur');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fur_IT');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fy');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fy_NL');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_ga');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_ga_IE');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_gd');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_gd_GB');
|
||||
@@ -10770,9 +10769,9 @@ goog.i18n.DateTimeSymbols_fy_NL = goog.i18n.DateTimeSymbols_fy;
|
||||
|
||||
|
||||
/**
|
||||
* Date/time formatting symbols for locale ga.
|
||||
* Date/time formatting symbols for locale ga_IE.
|
||||
*/
|
||||
goog.i18n.DateTimeSymbols_ga = {
|
||||
goog.i18n.DateTimeSymbols_ga_IE = {
|
||||
ERAS: ['RC', 'AD'],
|
||||
ERANAMES: ['Roimh Chríost', 'Anno Domini'],
|
||||
NARROWMONTHS: ['E', 'F', 'M', 'A', 'B', 'M', 'I', 'L', 'M', 'D', 'S', 'N'],
|
||||
@@ -10809,12 +10808,6 @@ goog.i18n.DateTimeSymbols_ga = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Date/time formatting symbols for locale ga_IE.
|
||||
*/
|
||||
goog.i18n.DateTimeSymbols_ga_IE = goog.i18n.DateTimeSymbols_ga;
|
||||
|
||||
|
||||
/**
|
||||
* Date/time formatting symbols for locale gd.
|
||||
*/
|
||||
@@ -21329,12 +21322,8 @@ if (goog.LOCALE == 'fy_NL' || goog.LOCALE == 'fy-NL') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_fy;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ga') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_ga;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ga_IE' || goog.LOCALE == 'ga-IE') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_ga;
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_ga_IE;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'gd') {
|
||||
|
||||
@@ -67,6 +67,7 @@ goog.provide('goog.i18n.DateTimeSymbols_fi');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fil');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fr');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_fr_CA');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_ga');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_gl');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_gsw');
|
||||
goog.provide('goog.i18n.DateTimeSymbols_gu');
|
||||
@@ -1409,6 +1410,46 @@ goog.i18n.DateTimeSymbols_fr_CA = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Date/time formatting symbols for locale ga.
|
||||
*/
|
||||
goog.i18n.DateTimeSymbols_ga = {
|
||||
ERAS: ['RC', 'AD'],
|
||||
ERANAMES: ['Roimh Chríost', 'Anno Domini'],
|
||||
NARROWMONTHS: ['E', 'F', 'M', 'A', 'B', 'M', 'I', 'L', 'M', 'D', 'S', 'N'],
|
||||
STANDALONENARROWMONTHS: ['E', 'F', 'M', 'A', 'B', 'M', 'I', 'L', 'M', 'D',
|
||||
'S', 'N'],
|
||||
MONTHS: ['Eanáir', 'Feabhra', 'Márta', 'Aibreán', 'Bealtaine', 'Meitheamh',
|
||||
'Iúil', 'Lúnasa', 'Meán Fómhair', 'Deireadh Fómhair', 'Samhain',
|
||||
'Nollaig'],
|
||||
STANDALONEMONTHS: ['Eanáir', 'Feabhra', 'Márta', 'Aibreán', 'Bealtaine',
|
||||
'Meitheamh', 'Iúil', 'Lúnasa', 'Meán Fómhair', 'Deireadh Fómhair',
|
||||
'Samhain', 'Nollaig'],
|
||||
SHORTMONTHS: ['Ean', 'Feabh', 'Márta', 'Aib', 'Beal', 'Meith', 'Iúil',
|
||||
'Lún', 'MFómh', 'DFómh', 'Samh', 'Noll'],
|
||||
STANDALONESHORTMONTHS: ['Ean', 'Feabh', 'Márta', 'Aib', 'Beal', 'Meith',
|
||||
'Iúil', 'Lún', 'MFómh', 'DFómh', 'Samh', 'Noll'],
|
||||
WEEKDAYS: ['Dé Domhnaigh', 'Dé Luain', 'Dé Máirt', 'Dé Céadaoin',
|
||||
'Déardaoin', 'Dé hAoine', 'Dé Sathairn'],
|
||||
STANDALONEWEEKDAYS: ['Dé Domhnaigh', 'Dé Luain', 'Dé Máirt',
|
||||
'Dé Céadaoin', 'Déardaoin', 'Dé hAoine', 'Dé Sathairn'],
|
||||
SHORTWEEKDAYS: ['Domh', 'Luan', 'Máirt', 'Céad', 'Déar', 'Aoine', 'Sath'],
|
||||
STANDALONESHORTWEEKDAYS: ['Domh', 'Luan', 'Máirt', 'Céad', 'Déar', 'Aoine',
|
||||
'Sath'],
|
||||
NARROWWEEKDAYS: ['D', 'L', 'M', 'C', 'D', 'A', 'S'],
|
||||
STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'C', 'D', 'A', 'S'],
|
||||
SHORTQUARTERS: ['R1', 'R2', 'R3', 'R4'],
|
||||
QUARTERS: ['1ú ráithe', '2ú ráithe', '3ú ráithe', '4ú ráithe'],
|
||||
AMPMS: ['a.m.', 'p.m.'],
|
||||
DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'd MMM y', 'dd/MM/y'],
|
||||
TIMEFORMATS: ['HH:mm:ss zzzz', 'HH:mm:ss z', 'HH:mm:ss', 'HH:mm'],
|
||||
DATETIMEFORMATS: ['{1} {0}', '{1} {0}', '{1} {0}', '{1} {0}'],
|
||||
FIRSTDAYOFWEEK: 6,
|
||||
WEEKENDRANGE: [5, 6],
|
||||
FIRSTWEEKCUTOFFDAY: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Date/time formatting symbols for locale gl.
|
||||
*/
|
||||
@@ -4307,6 +4348,8 @@ if (goog.LOCALE == 'af') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_fr;
|
||||
} else if (goog.LOCALE == 'fr_CA' || goog.LOCALE == 'fr-CA') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_fr_CA;
|
||||
} else if (goog.LOCALE == 'ga') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_ga;
|
||||
} else if (goog.LOCALE == 'gl') {
|
||||
goog.i18n.DateTimeSymbols = goog.i18n.DateTimeSymbols_gl;
|
||||
} else if (goog.LOCALE == 'gsw') {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user