Compare commits
563 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f73a651461 | |||
| d65636988b | |||
| e75fbc494e | |||
| 5e28b6ea8c | |||
| 586ec15398 | |||
| 8541d25ded | |||
| a580f8132b | |||
| 41aa9125b9 | |||
| b4581e3e99 | |||
| bdb5bc82a3 | |||
| 1cf93fd2b0 | |||
| 4f3858e7c3 | |||
| 4993728819 | |||
| 6933cf64fe | |||
| 32e656b769 | |||
| 11fbc17f65 | |||
| 02f045be8d | |||
| 71083a4455 | |||
| 700aafe3ab | |||
| 2b6bfc36ae | |||
| 31716eec4d | |||
| f670c451f4 | |||
| 6d0ff9fb7f | |||
| e3d02070ab | |||
| a9708de84b | |||
| 77ed85bcd3 | |||
| 0ddbcafd9e | |||
| 536da55705 | |||
| bdeb3392a8 | |||
| 7f45b5fee7 | |||
| a3cd7d8011 | |||
| 3a767a9943 | |||
| 1d29c91c34 | |||
| 0e666eb0b9 | |||
| b748046c04 | |||
| 3ecaccf719 | |||
| 250fcecae1 | |||
| 0b81a26045 | |||
| 3205e1c08c | |||
| dcb5d32055 | |||
| d69a64047b | |||
| ebd841165d | |||
| f62079d452 | |||
| ad6ac68509 | |||
| 03ff634598 | |||
| bf1e3e0eac | |||
| 0f001786d8 | |||
| 97eca91927 | |||
| 3821e8a951 | |||
| 1f61f30799 | |||
| c57779d872 | |||
| 404046081d | |||
| 5b7ec8c84e | |||
| 24471cf992 | |||
| 8d644bd066 | |||
| 78eecb43db | |||
| 2791a855a6 | |||
| bbe8ad5698 | |||
| 5041cf1f32 | |||
| d1bbc2562d | |||
| e19ad74ea4 | |||
| 7586fa2b86 | |||
| 70fa4d308a | |||
| 75c83ff319 | |||
| e36dbab396 | |||
| 4836278830 | |||
| 3a8cc38b69 | |||
| a41efb2025 | |||
| b8ce60ac4a | |||
| 5386fe4316 | |||
| 82f85eda11 | |||
| 5b0e4cae49 | |||
| 8c77aeb9b1 | |||
| f9354dc099 | |||
| 7648811a94 | |||
| e1c683be52 | |||
| cd298d6272 | |||
| 1cfb04d5c2 | |||
| 6c8450206e | |||
| e269ad1244 | |||
| 551983e7e1 | |||
| 87625a4581 | |||
| bcc44f13e5 | |||
| 1b6a1c30ee | |||
| a29fceadcd | |||
| 7b997ffa13 | |||
| 89f2be1c10 | |||
| 600509bb67 | |||
| 9aae7e8bb6 | |||
| 163f08ce86 | |||
| f3cb6e309a | |||
| 0abf65b353 | |||
| 136e65cc04 | |||
| 593a503484 | |||
| 48dfeb2006 | |||
| ffa46b95b9 | |||
| fddc534a13 | |||
| 4bf8921813 | |||
| ee2e36d810 | |||
| 87a31177b6 | |||
| 95fa35afc4 | |||
| dd0449c06f | |||
| e900f457fb | |||
| b655744676 | |||
| 748fee4ee7 | |||
| 8e480d8d0c | |||
| 4513dafd1a | |||
| 9bc4ee89c8 | |||
| b1c9075bcf | |||
| 44d70b384f | |||
| 6de412311a | |||
| 49dce2ea4b | |||
| 3ab1c3610b | |||
| 7717b96e95 | |||
| cc54e433c2 | |||
| 73ed7ef957 | |||
| 2316ad7be9 | |||
| e73dc0f31b | |||
| 9efe8426e5 | |||
| feede20a3b | |||
| b4735fdcbd | |||
| ed8aa16d30 | |||
| a5264090b6 | |||
| 609264f8b0 | |||
| f159e61893 | |||
| 2875d9f6b0 | |||
| 5a4e4e928e | |||
| eea9c597ac | |||
| 6aeb442db4 | |||
| 22979904fb | |||
| 6c0fd3e26f | |||
| db39512236 | |||
| 57ef6a9237 | |||
| 024bc1e160 | |||
| 7e7b5151db | |||
| 530395059f | |||
| 9ea1e440ea | |||
| 9b9f14e52e | |||
| b11a513429 | |||
| a419ff03d4 | |||
| 9449893763 | |||
| 07e1ba365f | |||
| 287a5dd4bd | |||
| 12752f66ac | |||
| fbdfd193f7 | |||
| 05896d44ad | |||
| 00b01e09ca | |||
| afc093b8b7 | |||
| fcffa181ce | |||
| e105dda1de | |||
| 0e1651bfd2 | |||
| af4a44cbaf | |||
| ed89fc8ee6 | |||
| 6a7a3250cf | |||
| 8455d2a797 | |||
| 862dc2532f | |||
| 7d11bc4f91 | |||
| 006e05074a | |||
| 1ea884ae7e | |||
| c82bb89964 | |||
| bb7f4a8733 | |||
| 0cf5be5264 | |||
| 584a6b39e4 | |||
| f86576def4 | |||
| 609e807b04 | |||
| 31d464feef | |||
| 5c9399d18a | |||
| a8da25c74d | |||
| 6bb775ccd1 | |||
| a4a22266f1 | |||
| 401da6873a | |||
| 311b5faf08 | |||
| 6cd911c132 | |||
| 9ae793d8a6 | |||
| 7fa2fdba3b | |||
| b871be1392 | |||
| 65bfce7d68 | |||
| 67126bd3a0 | |||
| ce6558fd80 | |||
| 64f6a616d4 | |||
| 07b8761233 | |||
| 2e7121b8e4 | |||
| da3f2df163 | |||
| 51944b3999 | |||
| 612589d0bc | |||
| 1b32fad833 | |||
| 3bf758063e | |||
| 82ea2de3fb | |||
| 8ace661ba5 | |||
| 8a9cd3e01d | |||
| 9ea37de0f5 | |||
| b44432a719 | |||
| ac0e10d287 | |||
| 1237c77850 | |||
| 9a9b07dea8 | |||
| 8b913b99d9 | |||
| 4edd2d95c1 | |||
| 353e3a6cd8 | |||
| 6ce2913d99 | |||
| 6a24885771 | |||
| 367da583bc | |||
| 68fb70ed29 | |||
| e8e8186d40 | |||
| 0f3385d45d | |||
| 4897430559 | |||
| 098b6f519a | |||
| 549edc9d01 | |||
| 6ed4c61e72 | |||
| f83c3dea23 | |||
| f60254f79a | |||
| d2a57b9dff | |||
| 33a693ea62 | |||
| dd1a957bb3 | |||
| 775c247085 | |||
| 4d753d197a | |||
| 8b51d03c83 | |||
| b1bc25169e | |||
| 9f10428651 | |||
| 6b28705dbf | |||
| 802cdf6ccb | |||
| a19d026bff | |||
| d23512c7f3 | |||
| 8e58e22d93 | |||
| 42cff065b8 | |||
| 2c852cf62a | |||
| bf4f51573d | |||
| 5a7dc50f26 | |||
| f9e7dabb2a | |||
| 296da4b561 | |||
| 9019c2dac5 | |||
| 83a12a54a2 | |||
| 9fdb4f8c51 | |||
| fcce237902 | |||
| d7e31b5dc7 | |||
| b014607030 | |||
| fd46fc80ee | |||
| d26ba3b941 | |||
| 6fa1bb03db | |||
| 8ebd716c57 | |||
| cb94d562df | |||
| d31b3a65b6 | |||
| 5a70888153 | |||
| 3475b19482 | |||
| 00a30fad82 | |||
| 22b669407c | |||
| 99a063f9cb | |||
| 27db9f018e | |||
| 2ed2399d49 | |||
| 9d2de344f5 | |||
| 9c0659ca27 | |||
| 3b9963c54a | |||
| 26db937377 | |||
| 1d0e582b3f | |||
| a6b58019e1 | |||
| 38fd896b74 | |||
| f96d553822 | |||
| f4149b70bc | |||
| 8a8c94c3d5 | |||
| d9de526059 | |||
| 0318761f7a | |||
| 74f7b57823 | |||
| 995ccfc9f6 | |||
| 72c244564a | |||
| 4bfe7e8663 | |||
| 63fe144397 | |||
| 0f551e6109 | |||
| 541f4ba21f | |||
| 6e7d04ddb2 | |||
| 06fb391687 | |||
| 203dd4d1e3 | |||
| c991f93817 | |||
| 52ddc13bee | |||
| 1645924d49 | |||
| 6bee655679 | |||
| acd455181d | |||
| a89b6e27a9 | |||
| 46d559dc8d | |||
| 26212fb204 | |||
| 244cfc7cd5 | |||
| c6074dc34c | |||
| 4930ef2bfe | |||
| 1778d347cd | |||
| 4724d56c93 | |||
| 70fcffc375 | |||
| 181e44019e | |||
| 5ce859bcdd | |||
| fb994e4d90 | |||
| 55f26fc246 | |||
| 1161002857 | |||
| 7ccfe92bed | |||
| a126fcfee3 | |||
| f22af2b874 | |||
| 2ca4170903 | |||
| fd57df1235 | |||
| 3010ed4ee5 | |||
| de59ca7107 | |||
| fa3214cfb8 | |||
| a8cacfe938 | |||
| 1a387ba5dd | |||
| 98e4a220fe | |||
| 9001ae2822 | |||
| c405f88bbc | |||
| 159a68ec7b | |||
| b9a56d588f | |||
| f797f83cd6 | |||
| 6df970eb3c | |||
| f88b4be92f | |||
| a7bcc01581 | |||
| 40ed8094d1 | |||
| 1a722f7b19 | |||
| 4991207c7c | |||
| 33514ec384 | |||
| 28bd20ed30 | |||
| c3bfd7f59d | |||
| 553cccdb85 | |||
| c7dd2c24f4 | |||
| fbf5aebda2 | |||
| ab35c16ccf | |||
| 37b6a71678 | |||
| e79ebff223 | |||
| 36b38e1355 | |||
| 3168d95793 | |||
| 538c63f057 | |||
| a9a1461351 | |||
| 29190f9318 | |||
| ca7d2b3b3f | |||
| 81676f8323 | |||
| 6f9d07d9c7 | |||
| 5201b8146a | |||
| 6aa83d04b7 | |||
| cfbe1a701a | |||
| aa38ded59d | |||
| b03957f004 | |||
| 56f33af890 | |||
| 41bea59eb7 | |||
| 6d0dcca6f1 | |||
| f423dc6b51 | |||
| 9fca87ca5b | |||
| ebbaa4ac5e | |||
| 617137231e | |||
| 71b966ace7 | |||
| 488d5b4288 | |||
| 01b8772cca | |||
| 05ac0ba926 | |||
| 399e872228 | |||
| 3115408be7 | |||
| aea39e9fdc | |||
| 51f6752cec | |||
| db58801a55 | |||
| 2e33d170be | |||
| cc6dcb4bc2 | |||
| 294d6793fd | |||
| cefcc46e1b | |||
| c10dba144e | |||
| f05ffd9bf1 | |||
| e208d81293 | |||
| b51fca1a2b | |||
| 6685043ad4 | |||
| f176a2dbb7 | |||
| 3a366bd42b | |||
| 1c5db02638 | |||
| ffd5308d86 | |||
| aed9de9d37 | |||
| aab6825e85 | |||
| c4fad6ad61 | |||
| 2a7c37cf01 | |||
| 194c3adfed | |||
| 371957d9d5 | |||
| 1e5d36d4b0 | |||
| 3749c85829 | |||
| 886b59d317 | |||
| 2048b6df24 | |||
| 5ec0a50d39 | |||
| 60689afe1c | |||
| 881fddaaba | |||
| fda338e8e2 | |||
| 05c8d88126 | |||
| aa57f57ccb | |||
| 51b78f61f9 | |||
| 739100e8a8 | |||
| 20e0c7f966 | |||
| f34e3413c7 | |||
| 4d28598b3d | |||
| 16d6e89f3b | |||
| 6e220ab612 | |||
| ce14e4a6b7 | |||
| b5dbc9834a | |||
| 57f10251db | |||
| 48cd05a1ad | |||
| 6a71ba17f0 | |||
| cf1b175508 | |||
| 5bba68c264 | |||
| e5a4345aac | |||
| 49ef92041f | |||
| 081ae8bfca | |||
| 4f8aa6f5bb | |||
| d7e888b8c6 | |||
| 491b4af92e | |||
| 5930b8ee27 | |||
| 69d9072d5b | |||
| 9b5de0ac97 | |||
| 21b76aed06 | |||
| 363fb16c10 | |||
| e00f9f62e3 | |||
| 507c666d16 | |||
| 743b33ab9d | |||
| 9f8fa79f25 | |||
| fe3c1d44a5 | |||
| 5ae72dc7af | |||
| 47bc98a1ea | |||
| 10920a2857 | |||
| 90a9270dfa | |||
| d4b05dd13a | |||
| 59802bc790 | |||
| b0a35a794a | |||
| a9545e3963 | |||
| 269c15c74b | |||
| 9f48025733 | |||
| 1d0ccd0d73 | |||
| 03e5164528 | |||
| 3047964712 | |||
| 225afb9eb4 | |||
| b377d6b043 | |||
| ac650cb2e6 | |||
| 926088ba77 | |||
| f94cf634d8 | |||
| 85b3786f55 | |||
| 1116a96df6 | |||
| 1c1c9b27cb | |||
| c5e7a5bc9b | |||
| 7550b7bda8 | |||
| 43b97b211b | |||
| 76405897fc | |||
| bb730704f2 | |||
| 8965d57aa0 | |||
| 951a2743d5 | |||
| a2a907e439 | |||
| 308f22ba9a | |||
| 32e2643d90 | |||
| 3edaf0922f | |||
| 1095596962 | |||
| ee0dac4d1d | |||
| 6f1fae8a91 | |||
| f96485085a | |||
| 147650b3be | |||
| 10c426ffa3 | |||
| 785647eb9d | |||
| a2a6279157 | |||
| b50d2a4a1f | |||
| f539fb1f7c | |||
| 2dcb5acb7b | |||
| 905a8fd4a4 | |||
| df9b57a481 | |||
| fee2077d0b | |||
| 691aafc981 | |||
| da7af937d6 | |||
| 1c9b9e24ed | |||
| 46a5b2c298 | |||
| 28e4707dc4 | |||
| 420b5211da | |||
| 04bccee099 | |||
| a404839795 | |||
| 25d4e5cca4 | |||
| c67112563f | |||
| 2b2ec26a75 | |||
| 41f90e5fb0 | |||
| a85c591d36 | |||
| f276ad0d51 | |||
| 33f817b99c | |||
| 6a4124d0fb | |||
| 26d1b34321 | |||
| 7fba6b603f | |||
| c115b37c33 | |||
| d20ba95e28 | |||
| 7945e5010a | |||
| 21d148aedc | |||
| 4c8aeefb62 | |||
| d384834fde | |||
| f975d8d448 | |||
| 2602daf993 | |||
| 9f681c459a | |||
| d9448dcb9f | |||
| e9c718a465 | |||
| 4dc44f7205 | |||
| 499e1b2adf | |||
| 28c6c4dae2 | |||
| 791148a328 | |||
| 01b1845088 | |||
| 56c861c9e1 | |||
| 451e0f6175 | |||
| aee7f1c72f | |||
| 5fe28a0422 | |||
| f56586d9a9 | |||
| ec0baadcb6 | |||
| 9147d5c04a | |||
| cb801378c9 | |||
| 79604f4628 | |||
| bf6cb8ab0d | |||
| de74b3fd85 | |||
| c7a92d2a9a | |||
| da284fc354 | |||
| 90da3059ce | |||
| 651fd05eca | |||
| 85d7e09bef | |||
| 243a57648b | |||
| 158dec330c | |||
| a1e63c8d4a | |||
| 8cc9978d15 | |||
| 78a404da0e | |||
| f1bb8369b5 | |||
| 76b6941b4c | |||
| e72990dc37 | |||
| f338e96ccc | |||
| 0ad2b70862 | |||
| 5261a374a9 | |||
| 832eba5fc9 | |||
| 2b569fc0b2 | |||
| ee6aeb08bf | |||
| 8d43d8b8e7 | |||
| d08f5c6986 | |||
| 3e7fa19197 | |||
| 5d379db72b | |||
| 514639b585 | |||
| 9cd9956dcb | |||
| c7813e9ebf | |||
| ef91b04cdd | |||
| 1acd97e18f | |||
| 513199ee9f | |||
| 33f3c40e93 | |||
| 696cb95d5e | |||
| 457fd21a1a | |||
| 3c6dfbf67d | |||
| 3277b885c4 | |||
| 48a256d04b | |||
| 0579430799 | |||
| 39ac68dac1 | |||
| 87fb44a5d3 | |||
| 5c76b406f7 | |||
| f665968daf | |||
| 5d1291c29d | |||
| ce7f400011 | |||
| 0fc8516b0c | |||
| 28b2a9b583 | |||
| e8549372fc | |||
| 5a434eb74e | |||
| 318de4db66 | |||
| a6c79bf15d | |||
| c6a10a755e | |||
| 1d7bd5bf4f | |||
| 94572e89c2 | |||
| fee7bac392 | |||
| dbb3b0f561 | |||
| b8bfed6a52 | |||
| 7215a89e7d | |||
| b7cca56091 | |||
| 7338e433f8 | |||
| 119ed07d5a | |||
| 5f98ae8323 | |||
| 8a598b43bb | |||
| e5dff4cfbe | |||
| 6c7a9cdd5f | |||
| 3b34f762fe | |||
| fa167ba747 |
@@ -20,6 +20,3 @@ libpeerconnection.log
|
||||
npm-debug.log
|
||||
/tmp/
|
||||
/scripts/bower/bower-*
|
||||
.vscode
|
||||
*.log
|
||||
*.stackdump
|
||||
+2
-3096
File diff suppressed because it is too large
Load Diff
+5
-13
@@ -29,12 +29,9 @@ If you find a bug in the source code or a mistake in the documentation, you can
|
||||
submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
|
||||
with a fix.
|
||||
|
||||
**Localization Issues:** Angular.js uses the [Google Closure I18N library] to generate
|
||||
its own I18N files (the ngLocale module). This means that any changes to these files would be lost
|
||||
the next time that we import the library.
|
||||
Since the Closure library i18n data is itself auto-generated from the data of the
|
||||
[Common Locale Data Repository (CLDR)] project, errors in the data should
|
||||
be reported there. See also the [Closure guide to i18n changes].
|
||||
***Localization Issue:*** *Angular.js uses the [Google Closure I18N library], to generate its own I18N files. This means that
|
||||
any changes to these files would be lost the next time that we import the library. The recommended
|
||||
approach is to submit a patch to the I18N project directly, instead of submitting it here.*
|
||||
|
||||
**Please see the [Submission Guidelines](#submit) below.**
|
||||
|
||||
@@ -244,7 +241,7 @@ Must be one of the following:
|
||||
semi-colons, etc)
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing or correcting existing tests
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
|
||||
@@ -252,8 +249,6 @@ Must be one of the following:
|
||||
The scope could be anything specifying place of the commit change. For example `$location`,
|
||||
`$browser`, `$compile`, `$rootScope`, `ngHref`, `ngClick`, `ngView`, etc...
|
||||
|
||||
You can use `*` when the change affects more than a single scope.
|
||||
|
||||
### Subject
|
||||
The subject contains succinct description of the change:
|
||||
|
||||
@@ -267,7 +262,7 @@ The body should include the motivation for the change and contrast this with pre
|
||||
|
||||
### Footer
|
||||
The footer should contain any information about **Breaking Changes** and is also the place to
|
||||
[reference GitHub issues that this commit closes][closing-issues].
|
||||
reference GitHub issues that this commit **Closes**.
|
||||
|
||||
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines.
|
||||
The rest of the commit message is then used for this.
|
||||
@@ -291,7 +286,6 @@ You can find out more detailed information about contributing in the
|
||||
|
||||
[Google Closure I18N library]: https://github.com/google/closure-library/tree/master/closure/goog/i18n
|
||||
[angular-dev]: https://groups.google.com/forum/?fromgroups#!forum/angular-dev
|
||||
[closing-issues]: https://help.github.com/articles/closing-issues-via-commit-messages/
|
||||
[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
[contribute]: http://docs.angularjs.org/misc/contribute
|
||||
@@ -310,7 +304,5 @@ You can find out more detailed information about contributing in the
|
||||
[plunker]: http://plnkr.co/edit
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
|
||||
[unit-testing]: https://docs.angularjs.org/guide/unit-testing
|
||||
[Common Locale Data Repository (CLDR)]: http://cldr.unicode.org
|
||||
[Closure guide to i18n changes]: https://github.com/google/closure-library/wiki/Internationalization-%28i18n%29-changes-in-Closure-Library
|
||||
|
||||
[](https://github.com/igrigorik/ga-beacon)
|
||||
|
||||
+3
-3
@@ -70,7 +70,6 @@ var angularFiles = {
|
||||
'src/ng/directive/ngInit.js',
|
||||
'src/ng/directive/ngList.js',
|
||||
'src/ng/directive/ngModel.js',
|
||||
'src/ng/directive/ngModelOptions.js',
|
||||
'src/ng/directive/ngNonBindable.js',
|
||||
'src/ng/directive/ngOptions.js',
|
||||
'src/ng/directive/ngPluralize.js',
|
||||
@@ -140,8 +139,7 @@ var angularFiles = {
|
||||
'src/ngSanitize/filter/linky.js'
|
||||
],
|
||||
'ngMock': [
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'src/ngMock/browserTrigger.js'
|
||||
'src/ngMock/angular-mocks.js'
|
||||
],
|
||||
'ngTouch': [
|
||||
'src/ngTouch/touch.js',
|
||||
@@ -156,6 +154,7 @@ var angularFiles = {
|
||||
|
||||
'angularScenario': [
|
||||
'src/ngScenario/Scenario.js',
|
||||
'src/ngScenario/browserTrigger.js',
|
||||
'src/ngScenario/Application.js',
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Future.js',
|
||||
@@ -214,6 +213,7 @@ var angularFiles = {
|
||||
'build/angular.js',
|
||||
'@angularSrcModules',
|
||||
'test/modules/no_bootstrap.js',
|
||||
'src/ngScenario/browserTrigger.js',
|
||||
'test/helpers/*.js',
|
||||
'test/ngAnimate/*.js',
|
||||
'test/ngMessageFormat/*.js',
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('animationBenchmark', ['ngAnimate'], config)
|
||||
.controller('BenchmarkController', BenchmarkController);
|
||||
|
||||
// Functions - Definitions
|
||||
function config($compileProvider) {
|
||||
$compileProvider
|
||||
.commentDirectivesEnabled(false)
|
||||
.cssClassDirectivesEnabled(false)
|
||||
.debugInfoEnabled(false);
|
||||
}
|
||||
|
||||
function BenchmarkController($scope) {
|
||||
var self = this;
|
||||
var itemCount = 1000;
|
||||
var items = (new Array(itemCount + 1)).join('.').split('');
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'create',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
self.items = items;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$digest',
|
||||
fn: function() {
|
||||
$scope.$root.$digest();
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'destroy',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
self.items = [];
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [
|
||||
{
|
||||
id: 'jquery',
|
||||
src: 'jquery-noop.js'
|
||||
}, {
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
}, {
|
||||
id: 'angular-animate',
|
||||
src: '/build/angular-animate.js'
|
||||
}, {
|
||||
src: 'app.js'
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
-1
@@ -1 +0,0 @@
|
||||
// Override me with ?jquery=/bower_components/jquery/dist/jquery.js
|
||||
@@ -1,28 +0,0 @@
|
||||
<style>
|
||||
[ng-cloak] { display: none !important; }
|
||||
.animation-container .ng-enter,
|
||||
.animation-container .ng-leave {
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
.animation-container .ng-enter,
|
||||
.animation-container .ng-leave.ng-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.animation-container .ng-enter.ng-enter-active,
|
||||
.animation-container .ng-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
<div ng-app="animationBenchmark" ng-cloak ng-controller="BenchmarkController as bm">
|
||||
<div class="container-fluid">
|
||||
<h2>Large collection of elements animated in and out with ngAnimate</h2>
|
||||
|
||||
<div class="animation-container">
|
||||
<div ng-repeat="i in bm.items track by $index">
|
||||
Just a plain ol' element
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,108 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var app = angular.module('ngClassBenchmark', []);
|
||||
|
||||
app.controller('DataController', function DataController($scope) {
|
||||
|
||||
this.init = function() {
|
||||
this.numberOfTodos = 1000;
|
||||
this.implementation = 'tableOptimized';
|
||||
this.completedPeriodicity = 3;
|
||||
this.importantPeriodicity = 13;
|
||||
this.urgentPeriodicity = 29;
|
||||
|
||||
this.createTodos(100);
|
||||
this.setTodosValuesWithSeed(0);
|
||||
};
|
||||
|
||||
this.clearTodos = function() {
|
||||
this.todos = null;
|
||||
};
|
||||
|
||||
this.createTodos = function(count) {
|
||||
var i;
|
||||
this.todos = [];
|
||||
for (i = 0; i < count; i++) {
|
||||
this.todos.push({
|
||||
id: i + 1,
|
||||
completed: false,
|
||||
important: false,
|
||||
urgent: false
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.setTodosValuesWithSeed = function(offset) {
|
||||
var i, todo;
|
||||
for (i = 0; i < this.todos.length; i++) {
|
||||
todo = this.todos[i];
|
||||
todo.completed = 0 === (i + offset) % this.completedPeriodicity;
|
||||
todo.important = 0 === (i + offset) % this.importantPeriodicity;
|
||||
todo.urgent = 0 === (i + offset) % this.urgentPeriodicity;
|
||||
}
|
||||
};
|
||||
|
||||
this.init();
|
||||
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'setup',
|
||||
fn: function() {
|
||||
$scope.$apply();
|
||||
this.clearTodos();
|
||||
this.createTodos(this.numberOfTodos);
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'create',
|
||||
fn: function() {
|
||||
// initialize data for first time that will construct the DOM
|
||||
this.setTodosValuesWithSeed(0);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: '$apply',
|
||||
fn: function() {
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'update',
|
||||
fn: function() {
|
||||
// move everything but completed
|
||||
this.setTodosValuesWithSeed(3);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'unclass',
|
||||
fn: function() {
|
||||
// remove all classes
|
||||
this.setTodosValuesWithSeed(NaN);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'class',
|
||||
fn: function() {
|
||||
// add all classes as the initial state
|
||||
this.setTodosValuesWithSeed(0);
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'destroy',
|
||||
fn: function() {
|
||||
this.clearTodos();
|
||||
$scope.$apply();
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
src: 'app.js'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -1,177 +0,0 @@
|
||||
<style>
|
||||
.gold {
|
||||
background: gold;
|
||||
}
|
||||
.silver {
|
||||
background: silver;
|
||||
}
|
||||
.table tbody tr > td.success {
|
||||
background-color: #dff0d8;
|
||||
}
|
||||
|
||||
.table tbody tr > td.error {
|
||||
background-color: #f2dede;
|
||||
}
|
||||
|
||||
.table tbody tr > td.warning {
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
.table tbody tr > td.info {
|
||||
background-color: #d9edf7;
|
||||
}
|
||||
.completed {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.important {
|
||||
font-weight: bold;
|
||||
}
|
||||
.urgent {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
<div ng-app="ngClassBenchmark" ng-cloak class="container-fluid">
|
||||
<div ng-controller="DataController as benchmark" class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
<div class="well">
|
||||
<h3>Parameters</h3>
|
||||
|
||||
<br>
|
||||
<p>
|
||||
<label>Number of todos</label><br>
|
||||
<input type="number" ng-model="benchmark.numberOfTodos">
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<p>
|
||||
<label>Implementation</label><br>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="tableOptimized"
|
||||
type="radio" name="implementation">
|
||||
Table optimized <br>
|
||||
<code>ng-class="todo.completed && 'success'"</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="table"
|
||||
type="radio" name="implementation">
|
||||
Table <br>
|
||||
<code>ng-class="{success: todo.completed}"</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="list"
|
||||
type="radio" name="implementation">
|
||||
List <br>
|
||||
<code>ng-class="{completed: todo.completed, urgent: todo.urgent, important: todo.important"}</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="singleOptimized"
|
||||
type="radio" name="implementation">
|
||||
Single ngClass optimized <br>
|
||||
<code>
|
||||
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}"
|
||||
</code>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input ng-model="benchmark.implementation" value="single"
|
||||
type="radio" name="implementation">
|
||||
Single ngClass <br>
|
||||
<code>
|
||||
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}"
|
||||
</code>
|
||||
</label>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h3>Example</h3>
|
||||
<div ng-switch="benchmark.implementation">
|
||||
|
||||
<table ng-switch-when="tableOptimized" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>todo #id</th>
|
||||
<th>completed?</th>
|
||||
<th>urgent?</th>
|
||||
<th>important?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="todo.completed && 'active'"
|
||||
ng-class-even="todo.completed && todo.important && 'gold'"
|
||||
ng-class-odd="todo.completed && todo.important && 'silver'"
|
||||
>
|
||||
<td>#{{todo.id}}</td>
|
||||
<td>{{todo.completed}}</td>
|
||||
<td ng-class="todo.urgent && 'danger'">{{todo.urgent}}</td>
|
||||
<td ng-class="todo.important && 'success'">{{todo.important}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table ng-switch-when="table" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>todo #id</th>
|
||||
<th>completed?</th>
|
||||
<th>urgent?</th>
|
||||
<th>important?</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="{active: todo.completed}"
|
||||
ng-class-even="{gold: todo.completed && todo.important}"
|
||||
ng-class-odd="{silver: todo.completed && todo.important}"
|
||||
>
|
||||
<td>#{{todo.id}}</td>
|
||||
<td>{{todo.completed}}</td>
|
||||
<td ng-class="{danger: todo.urgent}">{{todo.urgent}}</td>
|
||||
<td ng-class="{success: todo.important}">{{todo.important}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ul ng-switch-when="list">
|
||||
<li ng-repeat="todo in benchmark.todos track by todo.id"
|
||||
ng-class="{
|
||||
completed: todo.completed,
|
||||
urgent: todo.urgent,
|
||||
important: todo.important
|
||||
}">#{{todo.id}}</li>
|
||||
</ul>
|
||||
|
||||
<div ng-switch-when="singleOptimized"
|
||||
class="panel"
|
||||
ng-class="{'panel-success': !!benchmark.todos, 'panel-danger': !benchmark.todos}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Information</h3>
|
||||
</div>
|
||||
<div class="panel-body"> The title is green because there are todos... </div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="single"
|
||||
class="panel"
|
||||
ng-class="{'panel-success': benchmark.todos, 'panel-danger': !benchmark.todos}">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Information</h3>
|
||||
</div>
|
||||
<div class="panel-body"> The title is green because there are todos... </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br><br><br>
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
@@ -1,104 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* globals angular, benchmarkSteps */
|
||||
|
||||
var app = angular.module('selectBenchmark', []);
|
||||
|
||||
app.config(function($compileProvider) {
|
||||
if ($compileProvider.debugInfoEnabled) {
|
||||
$compileProvider.debugInfoEnabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
app.controller('DataController', function($scope, $element) {
|
||||
$scope.groups = [];
|
||||
$scope.count = 10000;
|
||||
|
||||
function changeOptions() {
|
||||
$scope.groups = [];
|
||||
var i = 0;
|
||||
var group;
|
||||
while (i < $scope.count) {
|
||||
if (i % 100 === 0) {
|
||||
group = {
|
||||
name: 'group-' + $scope.groups.length,
|
||||
items: []
|
||||
};
|
||||
$scope.groups.push(group);
|
||||
}
|
||||
group.items.push({
|
||||
id: i,
|
||||
label: 'item-' + i
|
||||
});
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
var selectElement = $element.find('select');
|
||||
console.log(selectElement);
|
||||
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'add-options',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
$scope.count = 10000;
|
||||
changeOptions();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'set-model-1',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
$scope.x = $scope.groups[10].items[0];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'set-model-2',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
$scope.x = $scope.groups[0].items[10];
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'remove-options',
|
||||
fn: function() {
|
||||
$scope.count = 100;
|
||||
changeOptions();
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'add-options',
|
||||
fn: function() {
|
||||
$scope.$apply(function() {
|
||||
$scope.count = 10000;
|
||||
changeOptions();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'set-view-1',
|
||||
fn: function() {
|
||||
selectElement.val('2000');
|
||||
selectElement.triggerHandler('change');
|
||||
}
|
||||
});
|
||||
|
||||
benchmarkSteps.push({
|
||||
name: 'set-view-2',
|
||||
fn: function() {
|
||||
selectElement.val('1000');
|
||||
selectElement.triggerHandler('change');
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
scripts: [{
|
||||
id: 'angular',
|
||||
src: '/build/angular.js'
|
||||
},
|
||||
{
|
||||
src: 'app.js'
|
||||
}]
|
||||
});
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
<div ng-app="selectBenchmark" ng-cloak>
|
||||
<div ng-controller="DataController">
|
||||
<div class="container-fluid">
|
||||
<p>
|
||||
Tests the execution of a select with ngRepeat'ed options with ngValue for rendering during model
|
||||
and option updates.
|
||||
</p>
|
||||
<select ng-model="x">
|
||||
<optgroup ng-repeat="g in groups track by g.name" label="{{g.name}}">
|
||||
<option ng-repeat="a in g.items track by a.id" ng-value="a">{{a.label}}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -662,10 +662,6 @@ ul.events > li {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.deprecation {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.deprecation .title {
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
|
||||
Regular → Executable
|
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
@@ -4,7 +4,7 @@
|
||||
/* global importScripts, lunr */
|
||||
|
||||
// Load up the lunr library
|
||||
importScripts('../components/lunr-0.7.2/lunr.min.js');
|
||||
importScripts('../components/lunr.js-0.5.12/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
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('service pages', function() {
|
||||
|
||||
browser.get('build/docs/index.html#!/api/ng/service/$q');
|
||||
providerLink = element.all(by.css('ol.api-profile-header-structure li a')).first();
|
||||
expect(providerLink.getText()).not.toEqual('- $compileProvider');
|
||||
expect(providerLink.getText()).not.toEqual('- $qProvider');
|
||||
expect(providerLink.getAttribute('href')).not.toMatch(/api\/ng\/provider\/\$compileProvider/);
|
||||
});
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ angular.module('examples', [])
|
||||
|
||||
ctrl.prepareExampleData = function() {
|
||||
if (ctrl.example.manifest) {
|
||||
return $q.resolve(ctrl.example);
|
||||
return $q.when(ctrl.example);
|
||||
}
|
||||
|
||||
return getExampleData(ctrl.examplePath).then(function(data) {
|
||||
@@ -159,11 +159,10 @@ angular.module('examples', [])
|
||||
|
||||
};
|
||||
|
||||
ctrl.$onInit = function() {
|
||||
// Initialize the example data, so it's ready when clicking the open button.
|
||||
// Otherwise pop-up blockers will prevent a new window from opening
|
||||
ctrl.prepareExampleData(ctrl.example.path);
|
||||
};
|
||||
// Initialize the example data, so it's ready when clicking the open button.
|
||||
// Otherwise pop-up blockers will prevent a new window from opening
|
||||
ctrl.prepareExampleData(ctrl.example.path);
|
||||
|
||||
}]
|
||||
};
|
||||
}])
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "AngularJS-docs-app",
|
||||
"dependencies": {
|
||||
"jquery": "2.2.3",
|
||||
"lunr.js": "0.5.12",
|
||||
"open-sans-fontface": "1.0.4",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"bootstrap": "3.1.1"
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@ module.exports = function debugDeployment(getVersion) {
|
||||
'../angular-sanitize.js',
|
||||
'../angular-touch.js',
|
||||
'../angular-animate.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.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/current-version-data.js',
|
||||
|
||||
@@ -17,9 +17,9 @@ module.exports = function defaultDeployment(getVersion) {
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.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/current-version-data.js',
|
||||
|
||||
+2
-2
@@ -21,9 +21,9 @@ module.exports = function jqueryDeployment(getVersion) {
|
||||
'../angular-sanitize.min.js',
|
||||
'../angular-touch.min.js',
|
||||
'../angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.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/current-version-data.js',
|
||||
|
||||
@@ -1,30 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var versionInfo = require('../../../../lib/versions/version-info');
|
||||
|
||||
var googleCdnUrl = '//ajax.googleapis.com/ajax/libs/angularjs/';
|
||||
var angularCodeUrl = '//code.angularjs.org/';
|
||||
|
||||
var cdnUrl = googleCdnUrl + versionInfo.cdnVersion;
|
||||
|
||||
// The plnkr examples must use the code.angularjs.org repo for the snapshot,
|
||||
// and the cdn for the tagged version and, if the build is not tagged, the currentVersion.
|
||||
//
|
||||
// The currentVersion may not be available on the cdn (e.g. if built locally, or hasn't been pushed
|
||||
// yet). This will lead to a 404, but this is preferable to loading a version with which the example
|
||||
// might not work (possibly in subtle ways).
|
||||
var examplesCdnUrl = versionInfo.currentVersion.isSnapshot ?
|
||||
(angularCodeUrl + 'snapshot') :
|
||||
(googleCdnUrl + (versionInfo.currentVersion.version || versionInfo.currentVersion));
|
||||
var cdnUrl = '//ajax.googleapis.com/ajax/libs/angularjs/' + versionInfo.cdnVersion;
|
||||
|
||||
module.exports = function productionDeployment(getVersion) {
|
||||
return {
|
||||
name: 'production',
|
||||
examples: {
|
||||
commonFiles: {
|
||||
scripts: [examplesCdnUrl + '/angular.min.js']
|
||||
scripts: [cdnUrl + '/angular.min.js']
|
||||
},
|
||||
dependencyPath: examplesCdnUrl + '/'
|
||||
dependencyPath: cdnUrl + '/'
|
||||
},
|
||||
scripts: [
|
||||
cdnUrl + '/angular.min.js',
|
||||
@@ -34,9 +20,9 @@ module.exports = function productionDeployment(getVersion) {
|
||||
cdnUrl + '/angular-sanitize.min.js',
|
||||
cdnUrl + '/angular-touch.min.js',
|
||||
cdnUrl + '/angular-animate.min.js',
|
||||
'components/marked-' + getVersion('marked') + '/lib/marked.js',
|
||||
'components/marked-' + getVersion('marked', 'node_modules', 'package.json') + '/lib/marked.js',
|
||||
'js/angular-bootstrap/dropdown-toggle.min.js',
|
||||
'components/lunr-' + getVersion('lunr') + '/lunr.min.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/current-version-data.js',
|
||||
|
||||
@@ -10,8 +10,8 @@ module.exports = function getVersion(readFilesProcessor) {
|
||||
var basePath = readFilesProcessor.basePath;
|
||||
|
||||
return function(component, sourceFolder, packageFile) {
|
||||
sourceFolder = path.resolve(basePath, sourceFolder || 'node_modules');
|
||||
packageFile = packageFile || 'package.json';
|
||||
sourceFolder = path.resolve(basePath, sourceFolder || 'docs/bower_components');
|
||||
packageFile = packageFile || 'bower.json';
|
||||
return require(path.join(sourceFolder,component,packageFile)).version;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -215,10 +215,11 @@
|
||||
|
||||
<p>
|
||||
Super-powered by Google ©2010-2017
|
||||
(<a id="version"
|
||||
( <a id="version"
|
||||
ng-href="https://github.com/angular/angular.js/blob/master/CHANGELOG.md#{{versionNumber}}"
|
||||
ng-bind-template="v{{version}}" title="Changelog of this version of Angular JS">
|
||||
</a>)
|
||||
</a>
|
||||
)
|
||||
</p>
|
||||
<p>
|
||||
Code licensed under
|
||||
|
||||
@@ -61,12 +61,12 @@
|
||||
</div>
|
||||
{% endblock -%}
|
||||
|
||||
{% include "lib/params.template.html" %}
|
||||
{% include "lib/events.template.html" %}
|
||||
|
||||
{%- if doc.animations %}
|
||||
<h2 id="animations">Animations</h2>
|
||||
{$ doc.animations | marked $}
|
||||
{$ 'module:ngAnimate.$animate' | link('Click here', doc) $} to learn more about the steps involved in the animation.
|
||||
{%- endif -%}
|
||||
|
||||
{% include "lib/params.template.html" %}
|
||||
{% include "lib/events.template.html" %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $compile:multilink
|
||||
@fullName Linking Element Multiple Times
|
||||
@description
|
||||
|
||||
This error occurs when a single element is linked more then once.
|
||||
|
||||
For example, if an element is compiled and linked twice without cloning:
|
||||
```
|
||||
var linker = $compile(template);
|
||||
linker($scope); //=> ok
|
||||
linker($scope); //=> multilink error
|
||||
```
|
||||
|
||||
Linking an element as a clone multiple times is ok:
|
||||
```
|
||||
var linker = $compile(template);
|
||||
linker($scope, function() { ... }); //=> ok
|
||||
linker($scope, function() { ... }); //=> ok
|
||||
```
|
||||
|
||||
However once an element has been linked it can not be re-linked as a clone:
|
||||
```
|
||||
var linker = $compile(template);
|
||||
linker($scope); //=> ok
|
||||
linker($scope, function() { ... }); //=> multilink error
|
||||
```
|
||||
@@ -1,20 +0,0 @@
|
||||
@ngdoc error
|
||||
@name $http:badjsonp
|
||||
@fullName Bad JSONP Request Configuration
|
||||
@description
|
||||
|
||||
This error occurs when the URL generated from the configuration object contains a parameter with the
|
||||
same name as the configured `jsonpCallbackParam` property; or when it contains a parameter whose
|
||||
value is `JSON_CALLBACK`.
|
||||
|
||||
`$http` JSONP requests need to attach a callback query parameter to the URL. The name of this
|
||||
parameter is specified in the configuration object (or in the defaults) via the `jsonpCallbackParam`
|
||||
property. You must not provide your own parameter with this name in the configuratio of the request.
|
||||
|
||||
In previous versions of Angular, you specified where to add the callback parameter value via the
|
||||
`JSON_CALLBACK` placeholder. This is no longer allowed.
|
||||
|
||||
To resolve this error, remove any parameters that have the same name as the `jsonpCallbackParam`;
|
||||
and/or remove any parameters that have a value of `JSON_CALLBACK`.
|
||||
|
||||
For more information, see the {@link ng.$http#jsonp `$http.jsonp()`} method API documentation.
|
||||
@@ -3,11 +3,7 @@
|
||||
@fullName Bad Request Configuration
|
||||
@description
|
||||
|
||||
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not a valid object.
|
||||
`$http` expects a single parameter, the request configuration object, but received a parameter that was not an object or did not contain valid properties.
|
||||
|
||||
The error message should provide additional context such as the actual value of the parameter that was received.
|
||||
If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
|
||||
This error occurs when the request configuration parameter passed to the {@link ng.$http `$http`} service is not an object. `$http` expects a single parameter, the request configuration object, but received a parameter that was not an object. The error message should provide additional context such as the actual value of the parameter that was received. If you passed a string parameter, perhaps you meant to call one of the shorthand methods on `$http` such as `$http.get(…)`, etc.
|
||||
|
||||
To resolve this error, make sure you pass a valid request configuration object to `$http`.
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@ngdoc error
|
||||
@name $http:legacy
|
||||
@fullName The `success` and `error` methods on the promise returned from `$http` have been disabled.
|
||||
@description
|
||||
|
||||
This error occurs when the legacy promise extensions (`success` and `error`)
|
||||
{@link $httpProvider#useLegacyPromiseExtensions legacy `$http` promise extensions} have been disabled.
|
||||
|
||||
To resolve this error, either turn on the legacy extensions by adding
|
||||
`$httpProvider.useLegacyPromiseExtensions(true);` to your application's configuration; or refactor you
|
||||
use of `$http` to use `.then()` rather than `.success()` and `.error()`.
|
||||
|
||||
For example if you code looked like this:
|
||||
|
||||
```js
|
||||
// Simple GET request example :
|
||||
$http.get('/someUrl').
|
||||
success(function(data, status, headers, config) {
|
||||
// This callback will be called asynchronously
|
||||
// when the response is available
|
||||
}).
|
||||
error(function(data, status, headers, config) {
|
||||
// called asynchronously if an error occurs
|
||||
// or server returns response with an error status.
|
||||
});
|
||||
```
|
||||
|
||||
then you would change it to look like:
|
||||
|
||||
```js
|
||||
// Simple GET request example :
|
||||
$http.get('/someUrl').
|
||||
then(function(response) {
|
||||
// (The response object contains the data, status, headers and config properties)
|
||||
// This callback will be called asynchronously
|
||||
// when the response is available.
|
||||
}, function(response) {
|
||||
// called asynchronously if an error occurs
|
||||
// or server returns response with an error status.
|
||||
});
|
||||
```
|
||||
|
||||
For more information, see the
|
||||
{@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`}
|
||||
documentation.
|
||||
@@ -0,0 +1,12 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecaf
|
||||
@fullName Assigning to Fields of Disallowed Context
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to assign a value on a field of any of the `Boolean`, `Number`,
|
||||
`String`, `Array`, `Object`, or `Function` constructors or the corresponding prototypes.
|
||||
|
||||
Angular bans the modification of these constructors or their prototypes from within expressions,
|
||||
since it is a known way to modify the behaviour of existing functions/operations.
|
||||
|
||||
To resolve this error, avoid assigning to fields of constructors or their prototypes in expressions.
|
||||
@@ -0,0 +1,47 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecdom
|
||||
@fullName Referencing a DOM node in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access a DOM node.
|
||||
|
||||
AngularJS restricts access to DOM nodes from within expressions since it's a known way to
|
||||
execute arbitrary Javascript code.
|
||||
|
||||
This check is only performed on object index and function calls in Angular expressions. These are
|
||||
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
|
||||
perform this check - it's up to the developer to not expose such sensitive and powerful objects
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid access to DOM nodes.
|
||||
|
||||
|
||||
# Event Handlers and Return Values
|
||||
|
||||
The `$parse:isecdom` error also occurs when an event handler invokes a function that returns a DOM
|
||||
node.
|
||||
|
||||
```html
|
||||
<button ng-click="iWillReturnDOM()">click me</button>
|
||||
```
|
||||
|
||||
```js
|
||||
$scope.iWillReturnDOM = function() {
|
||||
return someDomNode;
|
||||
}
|
||||
```
|
||||
|
||||
To fix this issue, avoid returning DOM nodes from event handlers.
|
||||
|
||||
*Note: This error often means that you are accessing DOM from your controllers, which is usually
|
||||
a sign of poor coding style that violates separation of concerns.*
|
||||
|
||||
|
||||
# Implicit Returns in CoffeeScript
|
||||
|
||||
This error can occur more frequently when using CoffeeScript, which has a feature called implicit
|
||||
returns. This language feature returns the last dereferenced object in the function when the
|
||||
function has no explicit return statement.
|
||||
|
||||
The solution in this scenario is to add an explicit return statement. For example `return false` to
|
||||
the function.
|
||||
@@ -0,0 +1,17 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecff
|
||||
@fullName Referencing 'call', 'apply' and 'bind' Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to invoke Function's 'call', 'apply' or 'bind'.
|
||||
|
||||
Angular bans the invocation of 'call', 'apply' and 'bind' from within expressions
|
||||
since access is a known way to modify the behaviour of existing functions.
|
||||
|
||||
To resolve this error, avoid using these methods in expressions.
|
||||
|
||||
Example expression that would result in this error:
|
||||
|
||||
```
|
||||
<div>{{user.sendInfo.call({}, true)}}</div>
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecfld
|
||||
@fullName Referencing Disallowed Field in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access one of the following fields:
|
||||
|
||||
* __proto__
|
||||
* __defineGetter__
|
||||
* __defineSetter__
|
||||
* __lookupGetter__
|
||||
* __lookupSetter__
|
||||
|
||||
AngularJS bans access to these fields from within expressions since
|
||||
access is a known way to mess with native objects or
|
||||
to execute arbitrary Javascript code.
|
||||
|
||||
To resolve this error, avoid using these fields in expressions. As a last resort,
|
||||
alias their value and access them through the alias instead.
|
||||
|
||||
Example expressions that would result in this error:
|
||||
|
||||
```
|
||||
<div>{{user.__proto__.hasOwnProperty = $emit}}</div>
|
||||
|
||||
<div>{{user.__defineGetter__('name', noop)}}</div>
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecfn
|
||||
@fullName Referencing Function Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access the 'Function' object (constructor for all functions in JavaScript).
|
||||
|
||||
Angular bans access to Function from within expressions since constructor access is a known way to execute arbitrary Javascript code.
|
||||
|
||||
To resolve this error, avoid Function access.
|
||||
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecobj
|
||||
@fullName Referencing Object Disallowed
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access the 'Object' object (Root object in JavaScript).
|
||||
|
||||
Angular bans access to Object from within expressions since access is a known way to modify
|
||||
the behaviour of existing objects.
|
||||
|
||||
To resolve this error, avoid Object access.
|
||||
@@ -0,0 +1,45 @@
|
||||
@ngdoc error
|
||||
@name $parse:isecwindow
|
||||
@fullName Referencing Window object in Expression
|
||||
@description
|
||||
|
||||
Occurs when an expression attempts to access a Window object.
|
||||
|
||||
AngularJS restricts access to the Window object from within expressions since it's a known way to
|
||||
execute arbitrary Javascript code.
|
||||
|
||||
This check is only performed on object index and function calls in Angular expressions. These are
|
||||
places that are harder for the developer to guard. Dotted member access (such as a.b.c) does not
|
||||
perform this check - it's up to the developer to not expose such sensitive and powerful objects
|
||||
directly on the scope chain.
|
||||
|
||||
To resolve this error, avoid Window access.
|
||||
|
||||
### Common CoffeeScript Issue
|
||||
|
||||
Be aware that if you are using CoffeeScript, it automatically returns the value of the last statement in a
|
||||
function. So for instance
|
||||
|
||||
```coffeescript
|
||||
scope.foo = ->
|
||||
window.open 'https://example.com'
|
||||
```
|
||||
|
||||
compiles to something like
|
||||
|
||||
```js
|
||||
scope.foo = function() {
|
||||
return window.open('https://example.com');
|
||||
};
|
||||
```
|
||||
|
||||
You can see that this function will return the result of calling `window.open`, which is a `Window`
|
||||
object.
|
||||
|
||||
You can avoid this by explicitly returning something else from the function:
|
||||
|
||||
```coffeescript
|
||||
scope.foo = ->
|
||||
window.open 'https://example.com'
|
||||
return true;
|
||||
```
|
||||
@@ -3,7 +3,8 @@
|
||||
@fullName Model is not of type `number`
|
||||
@description
|
||||
|
||||
The `input[number]` and `input[range]` directives require the model to be a `number`.
|
||||
The `input[type="number"]` and `input[type="range"][ng-input-range]` directives require the model to
|
||||
be a `number`.
|
||||
|
||||
If the model is something else, this error will be thrown.
|
||||
|
||||
@@ -17,7 +18,7 @@ pipeline.
|
||||
## Example
|
||||
|
||||
In this example, our model stores the number as a string, so we provide the `stringToNumber`
|
||||
directive to convert it into the format the `input[number]` directive expects.
|
||||
directive to convert it into the format the `input[type="number"]` directive expects.
|
||||
|
||||
|
||||
<example module="numfmt-error-module" name="number-format-error">
|
||||
|
||||
@@ -111,11 +111,11 @@ To configure the `$location` service, retrieve the
|
||||
|
||||
- **hashPrefix(prefix)**: `{string}`<br />
|
||||
Prefix used for Hashbang URLs (used in Hashbang mode or in legacy browsers in HTML5 mode).<br />
|
||||
Default: `'!'`
|
||||
Default: `''`
|
||||
|
||||
### Example configuration
|
||||
```js
|
||||
$locationProvider.html5Mode(true).hashPrefix('*');
|
||||
$locationProvider.html5Mode(true).hashPrefix('!');
|
||||
```
|
||||
|
||||
## Getter and setter methods
|
||||
@@ -232,27 +232,27 @@ than the hash fragment was changed.
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', function() {
|
||||
module(function($locationProvider) {
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5Mode(false);
|
||||
$locationProvider.hashPrefix('!');
|
||||
});
|
||||
inject(function($location) {
|
||||
},
|
||||
function($location) {
|
||||
// open http://example.com/base/index.html#!/a
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/a');
|
||||
expect($location.path()).toBe('/a');
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/a'
|
||||
$location.path() === '/a'
|
||||
|
||||
$location.path('/foo');
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo');
|
||||
$location.path('/foo')
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/foo'
|
||||
|
||||
expect($location.search()).toEqual({});
|
||||
$location.search() === {}
|
||||
$location.search({a: 'b', c: true});
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo?a=b&c');
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/foo?a=b&c'
|
||||
|
||||
$location.path('/new').search('x=y');
|
||||
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/new?x=y');
|
||||
});
|
||||
});
|
||||
$location.absUrl() === 'http://example.com/base/index.html#!/new?x=y'
|
||||
}
|
||||
));
|
||||
```
|
||||
|
||||
## HTML5 mode
|
||||
@@ -274,50 +274,40 @@ and updates the url in a way that never performs a full page reload.
|
||||
### Example
|
||||
|
||||
```js
|
||||
it('should show example', function() {
|
||||
module(function($locationProvider) {
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix('!');
|
||||
});
|
||||
inject(function($location) {
|
||||
},
|
||||
function($location) {
|
||||
// in browser with HTML5 history support:
|
||||
// open http://example.com/#!/a -> rewrite to http://example.com/a
|
||||
// (replacing the http://example.com/#!/a history record)
|
||||
expect($location.path()).toBe('/a');
|
||||
$location.path() === '/a'
|
||||
|
||||
$location.path('/foo');
|
||||
expect($location.absUrl()).toBe('http://example.com/foo');
|
||||
$location.absUrl() === 'http://example.com/foo'
|
||||
|
||||
expect($location.search()).toEqual({});
|
||||
$location.search() === {}
|
||||
$location.search({a: 'b', c: true});
|
||||
expect($location.absUrl()).toBe('http://example.com/foo?a=b&c');
|
||||
$location.absUrl() === 'http://example.com/foo?a=b&c'
|
||||
|
||||
$location.path('/new').search('x=y');
|
||||
expect($location.url()).toBe('/new?x=y');
|
||||
expect($location.absUrl()).toBe('http://example.com/new?x=y');
|
||||
});
|
||||
});
|
||||
$location.url() === 'new?x=y'
|
||||
$location.absUrl() === 'http://example.com/new?x=y'
|
||||
|
||||
it('should show example (when browser doesn\'t support HTML5 mode', function() {
|
||||
module(function($provide, $locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix('!');
|
||||
$provide.value('$sniffer', {history: false});
|
||||
});
|
||||
inject(initBrowser({ url: 'http://example.com/new?x=y', basePath: '/' }),
|
||||
function($location) {
|
||||
// in browser without html5 history support:
|
||||
// open http://example.com/new?x=y -> redirect to http://example.com/#!/new?x=y
|
||||
// (again replacing the http://example.com/new?x=y history item)
|
||||
expect($location.path()).toBe('/new');
|
||||
expect($location.search()).toEqual({x: 'y'});
|
||||
$location.path() === '/new'
|
||||
$location.search() === {x: 'y'}
|
||||
|
||||
$location.path('/foo/bar');
|
||||
expect($location.path()).toBe('/foo/bar');
|
||||
expect($location.url()).toBe('/foo/bar?x=y');
|
||||
expect($location.absUrl()).toBe('http://example.com/#!/foo/bar?x=y');
|
||||
});
|
||||
});
|
||||
$location.path() === '/foo/bar'
|
||||
$location.url() === '/foo/bar?x=y'
|
||||
$location.absUrl() === 'http://example.com/#!/foo/bar?x=y'
|
||||
}
|
||||
));
|
||||
```
|
||||
|
||||
### Fallback for legacy browsers
|
||||
|
||||
@@ -59,133 +59,79 @@ attributes (if they have not been explicitly specified by the developer):
|
||||
* aria-invalid
|
||||
* aria-required
|
||||
* aria-readonly
|
||||
* aria-disabled
|
||||
|
||||
### Example
|
||||
|
||||
<example module="ngAria_ngModelExample" deps="angular-aria.js" name="accessibility-ng-model">
|
||||
<file name="index.html">
|
||||
<form>
|
||||
<custom-checkbox role="checkbox" ng-model="checked" required
|
||||
aria-label="Custom checkbox" show-attrs>
|
||||
Custom checkbox
|
||||
</custom-checkbox>
|
||||
<form ng-controller="formsController">
|
||||
<some-checkbox role="checkbox" ng-model="checked" ng-class="{active: checked}"
|
||||
ng-disabled="isDisabled" ng-click="toggleCheckbox()"
|
||||
aria-label="Custom Checkbox" show-attrs>
|
||||
<span class="icon" aria-hidden="true"></span>
|
||||
Custom Checkbox
|
||||
</some-checkbox>
|
||||
</form>
|
||||
<hr />
|
||||
<b>Is checked:</b> {{ !!checked }}
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.
|
||||
module('ngAria_ngModelExample', ['ngAria']).
|
||||
directive('customCheckbox', customCheckboxDirective).
|
||||
directive('showAttrs', showAttrsDirective);
|
||||
|
||||
function customCheckboxDirective() {
|
||||
angular.module('ngAria_ngModelExample', ['ngAria'])
|
||||
.controller('formsController', function($scope) {
|
||||
$scope.checked = false;
|
||||
$scope.toggleCheckbox = function() {
|
||||
$scope.checked = !$scope.checked;
|
||||
};
|
||||
})
|
||||
.directive('someCheckbox', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: 'ngModel',
|
||||
transclude: true,
|
||||
template:
|
||||
'<span class="icon" aria-hidden="true"></span> ' +
|
||||
'<ng-transclude></ng-transclude>',
|
||||
link: function(scope, elem, attrs, ctrl) {
|
||||
// Overwrite necessary `NgModelController` methods
|
||||
ctrl.$isEmpty = isEmpty;
|
||||
ctrl.$render = render;
|
||||
|
||||
// Bind to events
|
||||
elem.on('click', function(event) {
|
||||
event.preventDefault();
|
||||
scope.$apply(toggleCheckbox);
|
||||
});
|
||||
elem.on('keypress', function(event) {
|
||||
link: function($scope, $el, $attrs) {
|
||||
$el.on('keypress', function(event) {
|
||||
event.preventDefault();
|
||||
if (event.keyCode === 32 || event.keyCode === 13) {
|
||||
scope.$apply(toggleCheckbox);
|
||||
$scope.toggleCheckbox();
|
||||
$scope.$apply();
|
||||
}
|
||||
});
|
||||
|
||||
// Helpers
|
||||
function isEmpty(value) {
|
||||
return !value;
|
||||
}
|
||||
|
||||
function render() {
|
||||
elem[ctrl.$viewValue ? 'addClass' : 'removeClass']('checked');
|
||||
}
|
||||
|
||||
function toggleCheckbox() {
|
||||
ctrl.$setViewValue(!ctrl.$viewValue);
|
||||
ctrl.$render();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function showAttrsDirective($timeout) {
|
||||
return function(scope, elem, attrs) {
|
||||
})
|
||||
.directive('showAttrs', function() {
|
||||
return function($scope, $el, $attrs) {
|
||||
var pre = document.createElement('pre');
|
||||
elem.after(pre);
|
||||
|
||||
scope.$watchCollection(function() {
|
||||
return Array.prototype.slice.call(elem[0].attributes).reduce(function(aggr, attr) {
|
||||
if (attr.name !== attrs.$attr.showAttrs) aggr[attr.name] = attr.value;
|
||||
return aggr;
|
||||
}, {});
|
||||
}, function(newValues) {
|
||||
$timeout(function() {
|
||||
pre.textContent = angular.toJson(newValues, 2);
|
||||
$el.after(pre);
|
||||
$scope.$watch(function() {
|
||||
var $attrs = {};
|
||||
Array.prototype.slice.call($el[0].attributes, 0).forEach(function(item) {
|
||||
if (item.name !== 'show-$attrs') {
|
||||
$attrs[item.name] = item.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
return $attrs;
|
||||
}, function(newAttrs, oldAttrs) {
|
||||
pre.textContent = JSON.stringify(newAttrs, null, 2);
|
||||
}, true);
|
||||
};
|
||||
}
|
||||
});
|
||||
</file>
|
||||
<file name="style.css">
|
||||
custom-checkbox {
|
||||
[role=checkbox] {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
custom-checkbox .icon:before {
|
||||
[role=checkbox] .icon:before {
|
||||
content: '\2610';
|
||||
display: inline-block;
|
||||
font-size: 2em;
|
||||
line-height: 1;
|
||||
speak: none;
|
||||
vertical-align: middle;
|
||||
speak: none;
|
||||
}
|
||||
|
||||
custom-checkbox.checked .icon:before {
|
||||
[role=checkbox].active .icon:before {
|
||||
content: '\2611';
|
||||
}
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
var checkbox = element(by.css('custom-checkbox'));
|
||||
var checkedCheckbox = element(by.css('custom-checkbox.checked'));
|
||||
|
||||
it('should have the `checked` class only when checked', function() {
|
||||
expect(checkbox.isPresent()).toBe(true);
|
||||
expect(checkedCheckbox.isPresent()).toBe(false);
|
||||
|
||||
checkbox.click();
|
||||
expect(checkedCheckbox.isPresent()).toBe(true);
|
||||
|
||||
checkbox.click();
|
||||
expect(checkedCheckbox.isPresent()).toBe(false);
|
||||
});
|
||||
|
||||
it('should have the `aria-checked` attribute set to the appropriate value', function() {
|
||||
expect(checkedCheckbox.isPresent()).toBe(false);
|
||||
expect(checkbox.getAttribute('aria-checked')).toBe('false');
|
||||
|
||||
checkbox.click();
|
||||
expect(checkedCheckbox.isPresent()).toBe(true);
|
||||
expect(checkbox.getAttribute('aria-checked')).toBe('true');
|
||||
|
||||
checkbox.click();
|
||||
expect(checkedCheckbox.isPresent()).toBe(false);
|
||||
expect(checkbox.getAttribute('aria-checked')).toBe('false');
|
||||
});
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ The same approach to animation can be used using JavaScript code (**jQuery is us
|
||||
```js
|
||||
myModule.animation('.repeated-item', function() {
|
||||
return {
|
||||
enter: function(element, done) {
|
||||
enter : function(element, done) {
|
||||
element.css('opacity',0);
|
||||
jQuery(element).animate({
|
||||
opacity: 1
|
||||
@@ -137,7 +137,7 @@ myModule.animation('.repeated-item', function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
leave: function(element, done) {
|
||||
leave : function(element, done) {
|
||||
element.css('opacity', 1);
|
||||
jQuery(element).animate({
|
||||
opacity: 0
|
||||
@@ -152,7 +152,7 @@ myModule.animation('.repeated-item', function() {
|
||||
}
|
||||
}
|
||||
},
|
||||
move: function(element, done) {
|
||||
move : function(element, done) {
|
||||
element.css('opacity', 0);
|
||||
jQuery(element).animate({
|
||||
opacity: 1
|
||||
@@ -169,8 +169,8 @@ myModule.animation('.repeated-item', function() {
|
||||
},
|
||||
|
||||
// you can also capture these animation events
|
||||
addClass: function(element, className, done) {},
|
||||
removeClass: function(element, className, done) {}
|
||||
addClass : function(element, className, done) {},
|
||||
removeClass : function(element, className, done) {}
|
||||
}
|
||||
});
|
||||
```
|
||||
@@ -410,10 +410,12 @@ You can prevent this unwanted behavior by adding CSS to the `.ng-animate` class
|
||||
for the whole duration of an animation. Simply overwrite the transition / animation duration. In the
|
||||
case of the spinner, this would be:
|
||||
|
||||
```css
|
||||
.spinner.ng-animate {
|
||||
transition: 0s none;
|
||||
animation: 0s none;
|
||||
}
|
||||
```
|
||||
|
||||
If you do have CSS transitions / animations defined for the animation events, make sure they have higher priority
|
||||
than any styles that are independent from ngAnimate.
|
||||
|
||||
@@ -115,7 +115,7 @@ Here is an example of manually initializing Angular:
|
||||
$scope.greetMe = 'World';
|
||||
}]);
|
||||
|
||||
angular.element(function() {
|
||||
angular.element(document).ready(function() {
|
||||
angular.bootstrap(document, ['myApp']);
|
||||
});
|
||||
</script>
|
||||
@@ -167,4 +167,4 @@ until `angular.resumeBootstrap()` is called.
|
||||
|
||||
`angular.resumeBootstrap()` takes an optional array of modules that
|
||||
should be added to the original list of modules that the app was
|
||||
about to be bootstrapped with.
|
||||
about to be bootstrapped with.
|
||||
@@ -215,7 +215,7 @@ You can see the complete application running below.
|
||||
|
||||
|
||||
function HeroService($q) {
|
||||
var heroesPromise = $q.resolve([
|
||||
var heroesPromise = $q.when([
|
||||
{ id: 11, name: 'Mr. Nice' },
|
||||
{ id: 12, name: 'Narco' },
|
||||
{ id: 13, name: 'Bombasto' },
|
||||
@@ -308,7 +308,7 @@ You can see the complete application running below.
|
||||
|
||||
|
||||
function CrisisService($q) {
|
||||
var crisesPromise = $q.resolve([
|
||||
var crisesPromise = $q.when([
|
||||
{id: 1, name: 'Princess Held Captive'},
|
||||
{id: 2, name: 'Dragon Burning Cities'},
|
||||
{id: 3, name: 'Giant Asteroid Heading For Earth'},
|
||||
@@ -415,7 +415,7 @@ You can see the complete application running below.
|
||||
|
||||
function DialogService($q) {
|
||||
this.confirm = function(message) {
|
||||
return $q.resolve(window.confirm(message || 'Is it OK?'));
|
||||
return $q.when(window.confirm(message || 'Is it OK?'));
|
||||
};
|
||||
}
|
||||
</file>
|
||||
@@ -713,7 +713,7 @@ making an actual server request, perhaps over HTTP.
|
||||
|
||||
```js
|
||||
function HeroService($q) {
|
||||
var heroesPromise = $q.resolve([
|
||||
var heroesPromise = $q.when([
|
||||
{ id: 11, name: 'Mr. Nice' },
|
||||
...
|
||||
]);
|
||||
@@ -990,7 +990,7 @@ have made. The result of the prompt is a promise that can be used in a `$routerC
|
||||
|
||||
function DialogService($q) {
|
||||
this.confirm = function(message) {
|
||||
return $q.resolve(window.confirm(message || 'Is it OK?'));
|
||||
return $q.when(window.confirm(message || 'Is it OK?'));
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -78,7 +78,6 @@ It's also possible to add components via {@link $compileProvider#component} in a
|
||||
| link functions | Yes | No |
|
||||
| multiElement | Yes | No |
|
||||
| priority | Yes | No |
|
||||
| replace | Yes (deprecated) | No |
|
||||
| require | Yes | Yes |
|
||||
| restrict | Yes | No (restricted to elements only) |
|
||||
| scope | Yes (default: false) | No (scope is always isolate) |
|
||||
|
||||
@@ -141,7 +141,7 @@ different currencies and also pay the invoice.
|
||||
<b>Total:</b>
|
||||
<span ng-repeat="c in invoice.currencies">
|
||||
{{invoice.total(c) | currency:c}}
|
||||
</span><br>
|
||||
</span>
|
||||
<button class="btn" ng-click="invoice.pay()">Pay</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -242,7 +242,7 @@ Let's refactor our example and move the currency conversion into a service in an
|
||||
<b>Total:</b>
|
||||
<span ng-repeat="c in invoice.currencies">
|
||||
{{invoice.total(c) | currency:c}}
|
||||
</span><br>
|
||||
</span>
|
||||
<button class="btn" ng-click="invoice.pay()">Pay</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -326,7 +326,7 @@ The following example shows how this is done with Angular:
|
||||
var YAHOO_FINANCE_URL_PATTERN =
|
||||
'//query.yahooapis.com/v1/public/yql?q=select * from ' +
|
||||
'yahoo.finance.xchange where pair in ("PAIRS")&format=json&' +
|
||||
'env=store://datatables.org/alltableswithkeys';
|
||||
'env=store://datatables.org/alltableswithkeys&callback=JSON_CALLBACK';
|
||||
var currencies = ['USD', 'EUR', 'CNY'];
|
||||
var usdToForeignRates = {};
|
||||
|
||||
@@ -337,7 +337,7 @@ The following example shows how this is done with Angular:
|
||||
var refresh = function() {
|
||||
var url = YAHOO_FINANCE_URL_PATTERN.
|
||||
replace('PAIRS', 'USD' + currencies.join('","USD'));
|
||||
return $http.get(url).then(function(response) {
|
||||
return $http.jsonp(url).then(function(response) {
|
||||
var newUsdToForeignRates = {};
|
||||
angular.forEach(response.data.query.results.rate, function(rate) {
|
||||
var currency = rate.id.substring(3,6);
|
||||
@@ -371,7 +371,7 @@ The following example shows how this is done with Angular:
|
||||
<b>Total:</b>
|
||||
<span ng-repeat="c in invoice.currencies">
|
||||
{{invoice.total(c) | currency:c}}
|
||||
</span><br>
|
||||
</span>
|
||||
<button class="btn" ng-click="invoice.pay()">Pay</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -159,37 +159,19 @@ the end of the name. The `$delegate` provided is dictated by the type of service
|
||||
### module.decorator
|
||||
|
||||
This {@link api/ng/type/angular.Module#decorator function} is the same as the `$provide.decorator` function except it is
|
||||
exposed through the module API. This allows you to separate your decorator patterns from your module config blocks.
|
||||
exposed through the module API. This allows you to separate your decorator patterns from your module config blocks. The
|
||||
main caveat here is that you will need to take note the order in which you create your decorators.
|
||||
|
||||
Like with `$provide.decorator`, the `module.decorator` function runs during the config phase of the app. That means
|
||||
you can define a `module.decorator` before the decorated service is defined.
|
||||
|
||||
Since you can apply multiple decorators, it is noteworthy that decorator application always follows order
|
||||
of declaration:
|
||||
|
||||
- If a service is decorated by both `$provide.decorator` and `module.decorator`, the decorators are applied in order:
|
||||
Unlike in the module config block (which allows configuration of services prior to their creation), the service must be
|
||||
registered prior to the decorator (see {@link guide/providers#provider-recipe Provider Recipe}). For example, the
|
||||
following would not work because you are attempting to decorate outside of the configuration phase and the service
|
||||
hasn't been created yet:
|
||||
|
||||
```js
|
||||
angular
|
||||
.module('theApp', [])
|
||||
.factory('theFactory', theFactoryFn)
|
||||
.config(function($provide) {
|
||||
$provide.decorator('theFactory', provideDecoratorFn); // runs first
|
||||
})
|
||||
.decorator('theFactory', moduleDecoratorFn); // runs seconds
|
||||
```
|
||||
// will cause an error since 'someService' hasn't been registered
|
||||
angular.module('myApp').decorator('someService', ...);
|
||||
|
||||
- If the service has been declared multiple times, a decorator will decorate the service that has been declared
|
||||
last:
|
||||
|
||||
```js
|
||||
angular
|
||||
.module('theApp', [])
|
||||
.factory('theFactory', theFactoryFn)
|
||||
.decorator('theFactory', moduleDecoratorFn)
|
||||
.factory('theFactory', theOtherFactoryFn);
|
||||
|
||||
// `theOtherFactoryFn` is selected as 'theFactory' provider and it is decorated via `moduleDecoratorFn`.
|
||||
angular.module('myApp').factory('someService', ...);
|
||||
```
|
||||
|
||||
## Example Applications
|
||||
|
||||
@@ -42,7 +42,7 @@ Angular expressions are like JavaScript expressions with the following differenc
|
||||
* **No Object Creation With New Operator:** You cannot use `new` operator in an Angular expression.
|
||||
|
||||
* **No Bitwise, Comma, And Void Operators:** You cannot use
|
||||
[Bitwise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators),
|
||||
[Bitwise](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators),
|
||||
`,` or `void` operators in an Angular expression.
|
||||
|
||||
|
||||
@@ -113,11 +113,11 @@ You can try evaluating different expressions here:
|
||||
Angular does not use JavaScript's `eval()` to evaluate expressions. Instead Angular's
|
||||
{@link ng.$parse $parse} service processes these expressions.
|
||||
|
||||
Angular expressions do not have direct access to global variables like `window`, `document` or `location`.
|
||||
Angular expressions do not have access to global variables like `window`, `document` or `location`.
|
||||
This restriction is intentional. It prevents accidental access to the global state – a common source of subtle bugs.
|
||||
|
||||
Instead use services like `$window` and `$location` in functions on controllers, which are then called from expressions.
|
||||
Such services provide mockable access to globals.
|
||||
Instead use services like `$window` and `$location` in functions called from expressions. Such services
|
||||
provide mockable access to globals.
|
||||
|
||||
It is possible to access the context object using the identifier `this` and the locals object using the
|
||||
identifier `$locals`.
|
||||
@@ -241,7 +241,7 @@ An expression that starts with `::` is considered a one-time expression. One-tim
|
||||
will stop recalculating once they are stable, which happens after the first digest if the expression
|
||||
result is a non-undefined value (see value stabilization algorithm below).
|
||||
|
||||
<example module="oneTimeBindingExampleApp" name="expression-one-time">
|
||||
<example module="oneTimeBidingExampleApp" name="expression-one-time">
|
||||
<file name="index.html">
|
||||
<div ng-controller="EventController">
|
||||
<button ng-click="clickMe($event)">Click Me</button>
|
||||
@@ -250,7 +250,7 @@ result is a non-undefined value (see value stabilization algorithm below).
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('oneTimeBindingExampleApp', []).
|
||||
angular.module('oneTimeBidingExampleApp', []).
|
||||
controller('EventController', ['$scope', function($scope) {
|
||||
var counter = 0;
|
||||
var names = ['Igor', 'Misko', 'Chirayu', 'Lucas'];
|
||||
@@ -265,24 +265,24 @@ result is a non-undefined value (see value stabilization algorithm below).
|
||||
</file>
|
||||
<file name="protractor.js" type="protractor">
|
||||
it('should freeze binding after its value has stabilized', function() {
|
||||
var oneTimeBinding = element(by.id('one-time-binding-example'));
|
||||
var oneTimeBiding = element(by.id('one-time-binding-example'));
|
||||
var normalBinding = element(by.id('normal-binding-example'));
|
||||
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding:');
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding:');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding:');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Igor');
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Misko');
|
||||
|
||||
element(by.buttonText('Click Me')).click();
|
||||
element(by.buttonText('Click Me')).click();
|
||||
|
||||
expect(oneTimeBinding.getText()).toEqual('One time binding: Igor');
|
||||
expect(oneTimeBiding.getText()).toEqual('One time binding: Igor');
|
||||
expect(normalBinding.getText()).toEqual('Normal binding: Lucas');
|
||||
});
|
||||
</file>
|
||||
|
||||
@@ -47,7 +47,7 @@ This is a collection of external, 3rd party resources for learning and developin
|
||||
##### Server-Specific
|
||||
|
||||
* **Django:** [Tutorial](http://blog.mourafiq.com/post/55034504632/end-to-end-web-app-with-django-rest-framework), [Integrating AngularJS with Django](http://django-angular.readthedocs.org/en/latest/integration.html), [Getting Started with Django Rest Framework and AngularJS](http://blog.kevinastone.com/getting-started-with-django-rest-framework-and-angularjs.html)
|
||||
* **FireBase:** [AngularFire](http://angularfire.com/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
|
||||
* **FireBase:** [AngularFire](http://angularfire.com/), [Firebase Foundations for AngularJS](http://blog.watchandcode.com/firebase-foundations/), [Realtime Apps with AngularJS and FireBase (video)](http://www.youtube.com/watch?v=C7ZI7z7qnHU)
|
||||
* **Google Cloud Platform: **[with Cloud Endpoints](https://cloud.google.com/developers/articles/angularjs-cloud-endpoints-recipe-for-building-modern-web-applications/), [with Go](https://github.com/GoogleCloudPlatform/appengine-angular-gotodos)
|
||||
* **Hood.ie:** [60 Minutes to Awesome](http://www.roberthorvick.com/2013/06/30/todomvc-angularjs-hood-ie-60-minutes-to-awesome/)
|
||||
* **MEAN Stack: **[Blog post](http://blog.mongodb.org/post/49262866911/the-mean-stack-mongodb-expressjs-angularjs-and), [Setup](http://thecodebarbarian.wordpress.com/2013/07/22/introduction-to-the-mean-stack-part-one-setting-up-your-tools/), [GDL Video](https://developers.google.com/live/shows/913996610)
|
||||
@@ -117,18 +117,16 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
|
||||
## General Learning Resources
|
||||
|
||||
### Books
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [AngularJS Essentials (Free eBook)](https://www.packtpub.com/packt/free-ebook/angularjs-essentials) by Rodrigo Branas
|
||||
* [AngularJS in Action](https://www.manning.com/books/angularjs-in-action) by Lukas Ruebbelke
|
||||
* [AngularJS: Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
|
||||
* [AngularJS: Up and Running](http://www.amazon.com/AngularJS-Running-Enhanced-Productivity-Structured/dp/1491901942) by Brad Green and Shyam Seshadri
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
* [Mastering Web App Development](http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821) by Pawel Kozlowski and Pete Bacon Darwin
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
|
||||
* [AngularJS Directives](http://www.amazon.com/AngularJS-Directives-Alex-Vanston/dp/1783280336) by Alex Vanston
|
||||
* [Recipes With AngularJS](http://www.amazon.co.uk/Recipes-Angular-js-Frederik-Dietz-ebook/dp/B00DK95V48) by Frederik Dietz
|
||||
* [Developing an AngularJS Edge](http://www.amazon.com/Developing-AngularJS-Edge-Christopher-Hiller-ebook/dp/B00CJLFF8K) by Christopher Hiller
|
||||
* [ng-book: The Complete Book on AngularJS](http://ng-book.com/) by Ari Lerner
|
||||
* [AngularJS : Novice to Ninja](http://www.amazon.in/AngularJS-Novice-Ninja-Sandeep-Panda/dp/0992279453) by Sandeep Panda
|
||||
* [AngularJS UI Development](http://www.amazon.com/AngularJS-UI-Development-Amit-Ghart-ebook/dp/B00OXVAK7A) by Amit Gharat and Matthias Nehlsen
|
||||
* [Responsive Web Design with AngularJS](http://www.amazon.com/Responsive-Design-AngularJS-Sandeep-Kumar/dp/178439842X) by Sandeep Kumar Patel
|
||||
* [Professional AngularJS](http://www.amazon.com/Professional-AngularJS-Valeri-Karpov/dp/1118832078/)
|
||||
|
||||
### Videos:
|
||||
* [egghead.io](http://egghead.io/)
|
||||
@@ -139,6 +137,7 @@ You can find a larger list of Angular external libraries at [ngmodules.org](http
|
||||
[CodeAcademy](http://www.codecademy.com/courses/javascript-advanced-en-2hJ3J/0/1),
|
||||
[CodeSchool](https://www.codeschool.com/courses/shaping-up-with-angular-js)
|
||||
* **Paid online:**
|
||||
[The Angular Course (115 videos that show you how to build a full app)](http://watchandcode.com/courses/angular-course/),
|
||||
[Pluralsight (3 courses)](http://www.pluralsight.com/training/Courses/Find?highlight=true&searchTerm=angularjs),
|
||||
[Tuts+](https://tutsplus.com/course/easier-js-apps-with-angular/),
|
||||
[lynda.com](http://www.lynda.com/AngularJS-tutorials/Up-Running-AngularJS/133318-2.html),
|
||||
|
||||
@@ -396,7 +396,7 @@ In the following example we create two directives:
|
||||
|
||||
if (ctrl.$isEmpty(modelValue)) {
|
||||
// consider empty model valid
|
||||
return $q.resolve();
|
||||
return $q.when();
|
||||
}
|
||||
|
||||
var def = $q.defer();
|
||||
|
||||
@@ -26,7 +26,7 @@ directive}. Additionally, you can use {@link guide/i18n#messageformat-extension
|
||||
All localizable Angular components depend on locale-specific rule sets managed by the {@link
|
||||
ng.$locale `$locale` service}.
|
||||
|
||||
There are a few examples that showcase how to use Angular filters with various locale rule sets in the
|
||||
There a few examples that showcase how to use Angular filters with various locale rule sets in the
|
||||
[`i18n/e2e` directory](https://github.com/angular/angular.js/tree/master/i18n/e2e) of the Angular
|
||||
source code.
|
||||
|
||||
@@ -85,7 +85,7 @@ requires German locale, you would serve index_de-de.html which will look somethi
|
||||
|
||||
Both approaches described above require you to prepare different `index.html` pages or JavaScript
|
||||
files for each locale that your app may use. You also need to configure your server to serve
|
||||
the correct file that corresponds to the desired locale.
|
||||
the correct file that correspond to the desired locale.
|
||||
|
||||
The second approach (including the locale JavaScript file in `index.html`) may be slower because
|
||||
an extra script needs to be loaded.
|
||||
|
||||
@@ -26,15 +26,6 @@ normal {@link ng.$rootScope.Scope#$digest digest} cycle.
|
||||
|
||||
Note that the interpolateDirective has a priority of 100 and sets up the watch in the preLink function.
|
||||
|
||||
### How the string representation is computed
|
||||
|
||||
If the interpolated value is not a `String`, it is computed as follows:
|
||||
- `undefined` and `null` are converted to `''`
|
||||
- if the value is an object that is not a `Number`, `Date` or `Array`, $interpolate looks for
|
||||
a custom `toString()` function on the object, and uses that. Custom means that
|
||||
`myObject.toString !== `Object.prototype.toString`.
|
||||
- if the above doesn't apply, `JSON.stringify` is used.
|
||||
|
||||
### Binding to boolean attributes
|
||||
|
||||
Attributes such as `disabled` are called `boolean` attributes, because their presence means `true` and
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -30,55 +30,42 @@ so keeping to AngularJS standards is not just a functionality issue, it's also c
|
||||
facilitate rapid security updates.
|
||||
|
||||
|
||||
## Angular Templates and Expressions
|
||||
## Expression Sandboxing
|
||||
|
||||
**If an attacker has access to control Angular templates or expressions, they can exploit an Angular application
|
||||
via an XSS attack, regardless of the version.**
|
||||
AngularJS's expressions are sandboxed not for security reasons, but instead to maintain a proper
|
||||
separation of application responsibilities. For example, access to `window` is disallowed
|
||||
because it makes it easy to introduce brittle global state into your application.
|
||||
|
||||
There are a number of ways that templates and expressions can be controlled:
|
||||
However, this sandbox is not intended to stop attackers who can edit the template before it's
|
||||
processed by Angular. It may be possible to run arbitrary JavaScript inside double-curly bindings
|
||||
if an attacker can modify them.
|
||||
|
||||
* **Generating Angular templates on the server containing user-provided content**. This is the most common pitfall
|
||||
where you are generating HTML via some server-side engine such as PHP, Java or ASP.NET.
|
||||
* **Passing an expression generated from user-provided content in calls to the following methods on a {@link scope scope}**:
|
||||
* `$watch(userContent, ...)`
|
||||
* `$watchGroup(userContent, ...)`
|
||||
* `$watchCollection(userContent, ...)`
|
||||
* `$eval(userContent)`
|
||||
* `$evalAsync(userContent)`
|
||||
* `$apply(userContent)`
|
||||
* `$applyAsync(userContent)`
|
||||
* **Passing an expression generated from user-provided content in calls to services that parse expressions**:
|
||||
* `$compile(userContent)`
|
||||
* `$parse(userContent)`
|
||||
* `$interpolate(userContent)`
|
||||
* **Passing an expression generated from user provided content as a predicate to `orderBy` pipe**:
|
||||
`{{ value | orderBy : userContent }}`
|
||||
But if an attacker can change arbitrary HTML templates, there's nothing stopping them from doing:
|
||||
|
||||
### Sandbox removal
|
||||
Each version of Angular 1 up to, but not including 1.6, contained an expression sandbox, which reduced the surface area of
|
||||
the vulnerability but never removed it. **In Angular 1.6 we removed this sandbox as developers kept relying upon it as a security
|
||||
feature even though it was always possible to access arbitrary JavaScript code if one could control the Angular templates
|
||||
or expressions of applications.**
|
||||
```html
|
||||
<script>somethingEvil();</script>
|
||||
```
|
||||
|
||||
Control of the Angular templates makes applications vulnerable even if there was a completely secure sandbox:
|
||||
* https://ryhanson.com/stealing-session-tokens-on-plunker-with-an-angular-expression-injection/ in this blog post the author shows
|
||||
a (now closed) vulnerability in the Plunker application due to server-side rendering inside an Angular template.
|
||||
* https://ryhanson.com/angular-expression-injection-walkthrough/ in this blog post the author describes an attack, which does not
|
||||
rely upon an expression sandbox bypass, that can be made because the sample application is rendering a template on the server that
|
||||
contains user entered content.
|
||||
**It's better to design your application in such a way that users cannot change client-side templates.**
|
||||
|
||||
**It's best to design your application in such a way that users cannot change client-side templates.**
|
||||
For instance:
|
||||
|
||||
* Do not mix client and server templates
|
||||
* Do not use user input to generate templates dynamically
|
||||
* Do not run user input through `$scope.$eval` (or any of the other expression parsing functions listed above)
|
||||
* Do not run user input through `$scope.$eval`
|
||||
* Consider using {@link ng.directive:ngCsp CSP} (but don't rely only on CSP)
|
||||
|
||||
**You can use suitably sanitized server-side templating to dynamically generate CSS, URLs, etc, but not for generating templates that are
|
||||
bootstrapped/compiled by Angular.**
|
||||
|
||||
**If you must continue to allow user-provided content in an Angular template then the safest option is to ensure that it is only
|
||||
present in the part of the template that is made inert via the {@link ngNonBindable} directive.**
|
||||
### Mixing client-side and server-side templates
|
||||
|
||||
In general, we recommend against this because it can create unintended XSS vectors.
|
||||
|
||||
However, it's ok to mix server-side templating in the bootstrap template (`index.html`) as long
|
||||
as user input cannot be used on the server to output html that would then be processed by Angular
|
||||
in a way that would allow for arbitrary code execution.
|
||||
|
||||
**For instance, you can use server-side templating to dynamically generate CSS, URLs, etc, but not
|
||||
for generating templates that are bootstrapped/compiled by Angular.**
|
||||
|
||||
|
||||
## HTTP Requests
|
||||
|
||||
@@ -442,7 +442,7 @@ There is also an example of testing promises in the {@link ng.$q#testing `$q` se
|
||||
|
||||
## Using `beforeAll()`
|
||||
|
||||
Jasmine's `beforeAll()` and mocha's `before()` hooks are often useful for sharing test setup - either to reduce test run-time or simply to make for more focused test cases.
|
||||
Jasmine's `beforeAll()` and mocha's `before()` hooks are often useful for sharing test setup - either to reduce test run-time or simply to make for more focussed test cases.
|
||||
|
||||
By default, ngMock will create an injector per test case to ensure your tests do not affect each other. However, if we want to use `beforeAll()`, ngMock will have to create the injector before any test cases are run, and share that injector through all the cases for that `describe`. That is where {@link angular.mock.module.sharedInjector module.sharedInjector()} comes in. When it's called within a `describe` block, a single injector is shared between all hooks and test cases run in that block.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name FAQ
|
||||
@description
|
||||
|
||||
# FAQ
|
||||
#FAQ
|
||||
|
||||
## Questions
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ tutorials.
|
||||
## Subscribe
|
||||
|
||||
* Subscribe to the [mailing list](http://groups.google.com/forum/?fromgroups#!forum/angular). Ask questions here!
|
||||
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angular&source=followbutton&variant=2.0)
|
||||
* Follow us on [Twitter](https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angularjs&source=followbutton&variant=2.0)
|
||||
* Add us to your circles on [Google+](https://plus.google.com/110323587230527980117/posts)
|
||||
|
||||
## Read more
|
||||
|
||||
+19
-7
@@ -1,8 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var log = require('gulp-util').log;
|
||||
var concat = require('gulp-concat');
|
||||
var eslint = require('gulp-eslint');
|
||||
var bower = require('bower');
|
||||
var Dgeni = require('dgeni');
|
||||
var merge = require('event-stream').merge;
|
||||
var path = require('canonical-path');
|
||||
@@ -16,6 +18,7 @@ var rename = require('gulp-rename');
|
||||
// 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 src = 'app/src/**/*.js';
|
||||
var ignoredFiles = '!src/angular.bind.js';
|
||||
@@ -54,14 +57,24 @@ var getMergedEslintConfig = function(filepath) {
|
||||
|
||||
var copyComponent = function(component, pattern, sourceFolder, packageFile) {
|
||||
pattern = pattern || '/**/*';
|
||||
sourceFolder = sourceFolder || '../node_modules';
|
||||
packageFile = packageFile || 'package.json';
|
||||
sourceFolder = sourceFolder || bowerFolder;
|
||||
packageFile = packageFile || 'bower.json';
|
||||
var version = require(path.resolve(sourceFolder, component, packageFile)).version;
|
||||
return gulp
|
||||
.src(sourceFolder + '/' + component + pattern)
|
||||
.pipe(gulp.dest(outputFolder + '/components/' + component + '-' + version));
|
||||
};
|
||||
|
||||
gulp.task('bower', function() {
|
||||
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() {
|
||||
var file = 'docs.js';
|
||||
@@ -78,8 +91,7 @@ gulp.task('build-app', function() {
|
||||
.pipe(gulp.dest(folder));
|
||||
});
|
||||
|
||||
|
||||
gulp.task('assets', function() {
|
||||
gulp.task('assets', ['bower'], function() {
|
||||
var JS_EXT = /\.js$/;
|
||||
return merge(
|
||||
gulp.src(['img/**/*']).pipe(gulp.dest(outputFolder + '/img')),
|
||||
@@ -98,15 +110,15 @@ gulp.task('assets', function() {
|
||||
})),
|
||||
copyComponent('bootstrap', '/dist/**/*'),
|
||||
copyComponent('open-sans-fontface'),
|
||||
copyComponent('lunr', '/*.js'),
|
||||
copyComponent('lunr.js', '/*.js'),
|
||||
copyComponent('google-code-prettify'),
|
||||
copyComponent('jquery', '/dist/*.js'),
|
||||
copyComponent('marked', '/**/*.js')
|
||||
copyComponent('marked', '/**/*.js', '../node_modules', 'package.json')
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
gulp.task('doc-gen', function() {
|
||||
gulp.task('doc-gen', ['bower'], function() {
|
||||
var dgeni = new Dgeni([require('./config')]);
|
||||
return dgeni.generate().catch(function() {
|
||||
process.exit(1);
|
||||
|
||||
@@ -114,7 +114,7 @@ goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
|
||||
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
|
||||
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||
return (currencyCode == info[1]) ? currencyCode :
|
||||
currencyCode + ' ' + info[1];
|
||||
currencyCode + ' ' + info[1];
|
||||
};
|
||||
|
||||
|
||||
@@ -210,13 +210,13 @@ goog.i18n.currency.getCurrencyPattern_ = function(patternNum, sign) {
|
||||
}
|
||||
}
|
||||
if ((patternNum & goog.i18n.currency.POSITION_FLAG_) == 0) {
|
||||
strParts.unshift(
|
||||
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? "' " : "'");
|
||||
strParts.unshift((patternNum & goog.i18n.currency.SPACE_FLAG_) ?
|
||||
"' " : "'");
|
||||
strParts.unshift(sign);
|
||||
strParts.unshift("'");
|
||||
} else {
|
||||
strParts.push(
|
||||
(patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'", sign, "'");
|
||||
strParts.push((patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'",
|
||||
sign, "'");
|
||||
}
|
||||
return strParts.join('');
|
||||
};
|
||||
@@ -281,20 +281,20 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
'CHF': [2, 'CHF', 'CHF'],
|
||||
'CLP': [0, '$', 'CL$'],
|
||||
'CNY': [2, '¥', 'RMB¥'],
|
||||
'COP': [32, '$', 'COL$'],
|
||||
'COP': [0, '$', 'COL$'],
|
||||
'CRC': [0, '\u20a1', 'CR\u20a1'],
|
||||
'CZK': [50, 'K\u010d', 'K\u010d'],
|
||||
'DKK': [50, 'kr.', 'kr.'],
|
||||
'DOP': [2, 'RD$', 'RD$'],
|
||||
'DKK': [18, 'kr', 'kr'],
|
||||
'DOP': [2, '$', 'RD$'],
|
||||
'EGP': [2, '£', 'LE'],
|
||||
'ETB': [2, 'Birr', 'Birr'],
|
||||
'EUR': [2, '€', '€'],
|
||||
'GBP': [2, '£', 'GB£'],
|
||||
'HKD': [2, '$', 'HK$'],
|
||||
'HRK': [2, 'kn', 'kn'],
|
||||
'HUF': [34, 'Ft', 'Ft'],
|
||||
'HUF': [0, 'Ft', 'Ft'],
|
||||
'IDR': [0, 'Rp', 'Rp'],
|
||||
'ILS': [34, '\u20AA', 'IL\u20AA'],
|
||||
'ILS': [2, '\u20AA', 'IL\u20AA'],
|
||||
'INR': [2, '\u20B9', 'Rs'],
|
||||
'IRR': [0, 'Rial', 'IRR'],
|
||||
'ISK': [0, 'kr', 'kr'],
|
||||
@@ -315,18 +315,18 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
'PLN': [50, 'z\u0142', 'z\u0142'],
|
||||
'RON': [2, 'RON', 'RON'],
|
||||
'RSD': [0, 'din', 'RSD'],
|
||||
'RUB': [50, '\u20bd', 'RUB'],
|
||||
'RUB': [50, 'руб.', 'руб.'],
|
||||
'SAR': [2, 'Rial', 'Rial'],
|
||||
'SEK': [50, 'kr', 'kr'],
|
||||
'SEK': [2, 'kr', 'kr'],
|
||||
'SGD': [2, '$', 'S$'],
|
||||
'THB': [2, '\u0e3f', 'THB'],
|
||||
'TRY': [2, 'TL', 'YTL'],
|
||||
'TWD': [2, 'NT$', 'NT$'],
|
||||
'TZS': [0, 'TSh', 'TSh'],
|
||||
'UAH': [2, 'грн.', 'UAH'],
|
||||
'UAH': [2, '\u20B4', 'UAH'],
|
||||
'USD': [2, '$', 'US$'],
|
||||
'UYU': [2, '$', '$U'],
|
||||
'VND': [48, '\u20AB', 'VN\u20AB'],
|
||||
'VND': [0, '\u20AB', 'VN\u20AB'],
|
||||
'YER': [0, 'Rial', 'Rial'],
|
||||
'ZAR': [2, 'R', 'ZAR']
|
||||
};
|
||||
@@ -338,12 +338,12 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [48, 'Af.', 'AFN'],
|
||||
'AMD': [32, 'Dram', 'dram'],
|
||||
'AMD': [0, 'Dram', 'dram'],
|
||||
'ANG': [2, 'NAf.', 'ANG'],
|
||||
'AOA': [2, 'Kz', 'Kz'],
|
||||
'ARS': [34, '$', 'AR$'],
|
||||
'ARS': [2, '$', 'AR$'],
|
||||
'AWG': [2, 'Afl.', 'Afl.'],
|
||||
'AZN': [34, '\u20bc', 'AZN'],
|
||||
'AZN': [2, 'man.', 'man.'],
|
||||
'BAM': [2, 'KM', 'KM'],
|
||||
'BBD': [2, '$', 'Bds$'],
|
||||
'BHD': [3, 'din', 'din'],
|
||||
@@ -354,7 +354,7 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'BSD': [2, '$', 'BS$'],
|
||||
'BTN': [2, 'Nu.', 'Nu.'],
|
||||
'BWP': [2, 'P', 'pula'],
|
||||
'BYR': [48, 'p.', 'BYR'],
|
||||
'BYR': [0, 'BYR', 'BYR'],
|
||||
'BZD': [2, '$', 'BZ$'],
|
||||
'CUC': [1, '$', 'CUC$'],
|
||||
'CUP': [2, '$', 'CU$'],
|
||||
@@ -405,7 +405,7 @@ goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'NZD': [2, '$', 'NZ$'],
|
||||
'OMR': [3, 'Rial', 'OMR'],
|
||||
'PGK': [2, 'PGK', 'PGK'],
|
||||
'PYG': [16, 'Gs.', 'PYG'],
|
||||
'PYG': [0, 'Gs', 'PYG'],
|
||||
'QAR': [2, 'Rial', 'QR'],
|
||||
'RWF': [0, 'RF', 'RF'],
|
||||
'SBD': [2, '$', 'SI$'],
|
||||
|
||||
+293
-392
File diff suppressed because it is too large
Load Diff
+1490
-2979
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
* This file is autogenerated by script:
|
||||
* http://go/generate_number_constants.py
|
||||
* using the --for_closure flag.
|
||||
* File generated from CLDR ver. 29
|
||||
* File generated from CLDR ver. 27.0.1
|
||||
*
|
||||
* To reduce the file size (which may cause issues in some JS
|
||||
* developing environments), this file will only contain locales
|
||||
@@ -34,7 +34,6 @@
|
||||
* removed after those changes land to CLDR.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
goog.provide('goog.i18n.NumberFormatSymbols');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_af');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_af_ZA');
|
||||
@@ -43,7 +42,6 @@ goog.provide('goog.i18n.NumberFormatSymbols_am_ET');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar_001');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar_EG');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ar_XB');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az_Latn');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_az_Latn_AZ');
|
||||
@@ -104,7 +102,6 @@ goog.provide('goog.i18n.NumberFormatSymbols_en_UM');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_US');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_VG');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_VI');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_XA');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_ZA');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_en_ZW');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_es');
|
||||
@@ -171,7 +168,8 @@ goog.provide('goog.i18n.NumberFormatSymbols_ja_JP');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ka');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ka_GE');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_kk');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_kk_KZ');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_kk_Cyrl');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_kk_Cyrl_KZ');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_km');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_km_KH');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_kn');
|
||||
@@ -179,7 +177,8 @@ goog.provide('goog.i18n.NumberFormatSymbols_kn_IN');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ko');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ko_KR');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ky');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ky_KG');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ky_Cyrl');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ky_Cyrl_KG');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ln');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ln_CD');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_lo');
|
||||
@@ -193,11 +192,13 @@ goog.provide('goog.i18n.NumberFormatSymbols_mk_MK');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ml');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ml_IN');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mn');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mn_MN');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mn_Cyrl');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mn_Cyrl_MN');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mr');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mr_IN');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ms');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ms_MY');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ms_Latn');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_ms_Latn_MY');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mt');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_mt_MT');
|
||||
goog.provide('goog.i18n.NumberFormatSymbols_my');
|
||||
@@ -367,13 +368,6 @@ goog.i18n.NumberFormatSymbols_ar_001 = goog.i18n.NumberFormatSymbols_ar;
|
||||
goog.i18n.NumberFormatSymbols_ar_EG = goog.i18n.NumberFormatSymbols_ar;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale ar_XB.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_ar_XB = goog.i18n.NumberFormatSymbols_ar;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale az.
|
||||
* @enum {string}
|
||||
@@ -428,8 +422,8 @@ goog.i18n.NumberFormatSymbols_be = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'BYR'
|
||||
};
|
||||
|
||||
@@ -782,7 +776,7 @@ goog.i18n.NumberFormatSymbols_de = {
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_de_AT = {
|
||||
DECIMAL_SEP: ',',
|
||||
GROUP_SEP: '\u00A0',
|
||||
GROUP_SEP: '.',
|
||||
PERCENT: '%',
|
||||
ZERO_DIGIT: '0',
|
||||
PLUS_SIGN: '+',
|
||||
@@ -823,7 +817,7 @@ goog.i18n.NumberFormatSymbols_de_CH = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
PERCENT_PATTERN: '#,##0\u00A0%',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00;\u00A4-#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'CHF'
|
||||
};
|
||||
@@ -928,7 +922,7 @@ goog.i18n.NumberFormatSymbols_en_AU = {
|
||||
ZERO_DIGIT: '0',
|
||||
PLUS_SIGN: '+',
|
||||
MINUS_SIGN: '-',
|
||||
EXP_SYMBOL: 'e',
|
||||
EXP_SYMBOL: 'E',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
@@ -1146,13 +1140,6 @@ goog.i18n.NumberFormatSymbols_en_VG = goog.i18n.NumberFormatSymbols_en;
|
||||
goog.i18n.NumberFormatSymbols_en_VI = goog.i18n.NumberFormatSymbols_en;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale en_XA.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_en_XA = goog.i18n.NumberFormatSymbols_en;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale en_ZA.
|
||||
* @enum {string}
|
||||
@@ -1306,7 +1293,7 @@ goog.i18n.NumberFormatSymbols_et = {
|
||||
PERCENT: '%',
|
||||
ZERO_DIGIT: '0',
|
||||
PLUS_SIGN: '+',
|
||||
MINUS_SIGN: '\u2212',
|
||||
MINUS_SIGN: '-',
|
||||
EXP_SYMBOL: '\u00D710^',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
@@ -1610,7 +1597,7 @@ goog.i18n.NumberFormatSymbols_gl = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
@@ -1856,8 +1843,8 @@ goog.i18n.NumberFormatSymbols_hy = {
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
|
||||
PERCENT_PATTERN: '#0%',
|
||||
CURRENCY_PATTERN: '#0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'AMD'
|
||||
};
|
||||
|
||||
@@ -2097,10 +2084,17 @@ goog.i18n.NumberFormatSymbols_kk = {
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale kk_KZ.
|
||||
* Number formatting symbols for locale kk_Cyrl.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_kk_KZ = goog.i18n.NumberFormatSymbols_kk;
|
||||
goog.i18n.NumberFormatSymbols_kk_Cyrl = goog.i18n.NumberFormatSymbols_kk;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale kk_Cyrl_KZ.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_kk_Cyrl_KZ = goog.i18n.NumberFormatSymbols_kk;
|
||||
|
||||
|
||||
/**
|
||||
@@ -2217,10 +2211,17 @@ goog.i18n.NumberFormatSymbols_ky = {
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale ky_KG.
|
||||
* Number formatting symbols for locale ky_Cyrl.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_ky_KG = goog.i18n.NumberFormatSymbols_ky;
|
||||
goog.i18n.NumberFormatSymbols_ky_Cyrl = goog.i18n.NumberFormatSymbols_ky;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale ky_Cyrl_KG.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_ky_Cyrl_KG = goog.i18n.NumberFormatSymbols_ky;
|
||||
|
||||
|
||||
/**
|
||||
@@ -2332,7 +2333,7 @@ goog.i18n.NumberFormatSymbols_lv = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '#0.00\u00A0\u00A4',
|
||||
CURRENCY_PATTERN: '\u00A4#0.00',
|
||||
DEF_CURRENCY_CODE: 'EUR'
|
||||
};
|
||||
|
||||
@@ -2428,10 +2429,17 @@ goog.i18n.NumberFormatSymbols_mn = {
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale mn_MN.
|
||||
* Number formatting symbols for locale mn_Cyrl.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_mn_MN = goog.i18n.NumberFormatSymbols_mn;
|
||||
goog.i18n.NumberFormatSymbols_mn_Cyrl = goog.i18n.NumberFormatSymbols_mn;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale mn_Cyrl_MN.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_mn_Cyrl_MN = goog.i18n.NumberFormatSymbols_mn;
|
||||
|
||||
|
||||
/**
|
||||
@@ -2488,10 +2496,17 @@ goog.i18n.NumberFormatSymbols_ms = {
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale ms_MY.
|
||||
* Number formatting symbols for locale ms_Latn.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_ms_MY = goog.i18n.NumberFormatSymbols_ms;
|
||||
goog.i18n.NumberFormatSymbols_ms_Latn = goog.i18n.NumberFormatSymbols_ms;
|
||||
|
||||
|
||||
/**
|
||||
* Number formatting symbols for locale ms_Latn_MY.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.NumberFormatSymbols_ms_Latn_MY = goog.i18n.NumberFormatSymbols_ms;
|
||||
|
||||
|
||||
/**
|
||||
@@ -3297,7 +3312,7 @@ goog.i18n.NumberFormatSymbols_uk = {
|
||||
EXP_SYMBOL: '\u0415',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
NAN: '\u041D\u0435\u00A0\u0447\u0438\u0441\u043B\u043E',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
@@ -3357,7 +3372,7 @@ goog.i18n.NumberFormatSymbols_uz = {
|
||||
EXP_SYMBOL: 'E',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'haqiqiy\u00A0son\u00A0emas',
|
||||
NAN: 'NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
@@ -3398,7 +3413,7 @@ goog.i18n.NumberFormatSymbols_vi = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
|
||||
CURRENCY_PATTERN: '#,##0.00\u00A0\u00A4',
|
||||
DEF_CURRENCY_CODE: 'VND'
|
||||
};
|
||||
|
||||
@@ -3428,7 +3443,7 @@ goog.i18n.NumberFormatSymbols_zh = {
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
CURRENCY_PATTERN: '\u00A4#,##0.00',
|
||||
CURRENCY_PATTERN: '\u00A4\u00A0#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'CNY'
|
||||
};
|
||||
|
||||
@@ -3514,7 +3529,7 @@ goog.i18n.NumberFormatSymbols_zu = {
|
||||
EXP_SYMBOL: 'E',
|
||||
PERMILL: '\u2030',
|
||||
INFINITY: '\u221E',
|
||||
NAN: 'NaN',
|
||||
NAN: 'I-NaN',
|
||||
DECIMAL_PATTERN: '#,##0.###',
|
||||
SCIENTIFIC_PATTERN: '#E0',
|
||||
PERCENT_PATTERN: '#,##0%',
|
||||
@@ -3563,10 +3578,6 @@ if (goog.LOCALE == 'ar_EG' || goog.LOCALE == 'ar-EG') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ar;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ar_XB' || goog.LOCALE == 'ar-XB') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ar;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'az') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_az;
|
||||
}
|
||||
@@ -3807,10 +3818,6 @@ if (goog.LOCALE == 'en_VI' || goog.LOCALE == 'en-VI') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'en_XA' || goog.LOCALE == 'en-XA') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'en_ZA' || goog.LOCALE == 'en-ZA') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_en_ZA;
|
||||
}
|
||||
@@ -4075,7 +4082,11 @@ if (goog.LOCALE == 'kk') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'kk_KZ' || goog.LOCALE == 'kk-KZ') {
|
||||
if (goog.LOCALE == 'kk_Cyrl' || goog.LOCALE == 'kk-Cyrl') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'kk_Cyrl_KZ' || goog.LOCALE == 'kk-Cyrl-KZ') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_kk;
|
||||
}
|
||||
|
||||
@@ -4107,7 +4118,11 @@ if (goog.LOCALE == 'ky') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ky_KG' || goog.LOCALE == 'ky-KG') {
|
||||
if (goog.LOCALE == 'ky_Cyrl' || goog.LOCALE == 'ky-Cyrl') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ky_Cyrl_KG' || goog.LOCALE == 'ky-Cyrl-KG') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ky;
|
||||
}
|
||||
|
||||
@@ -4163,7 +4178,11 @@ if (goog.LOCALE == 'mn') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'mn_MN' || goog.LOCALE == 'mn-MN') {
|
||||
if (goog.LOCALE == 'mn_Cyrl' || goog.LOCALE == 'mn-Cyrl') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'mn_Cyrl_MN' || goog.LOCALE == 'mn-Cyrl-MN') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_mn;
|
||||
}
|
||||
|
||||
@@ -4179,7 +4198,11 @@ if (goog.LOCALE == 'ms') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ms_MY' || goog.LOCALE == 'ms-MY') {
|
||||
if (goog.LOCALE == 'ms_Latn' || goog.LOCALE == 'ms-Latn') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ms_Latn_MY' || goog.LOCALE == 'ms-Latn-MY') {
|
||||
goog.i18n.NumberFormatSymbols = goog.i18n.NumberFormatSymbols_ms;
|
||||
}
|
||||
|
||||
|
||||
+130
-851
File diff suppressed because it is too large
Load Diff
+358
-360
@@ -17,7 +17,7 @@
|
||||
*
|
||||
* This file is autogenerated by script:
|
||||
* http://go/generate_pluralrules.py
|
||||
* File generated from CLDR ver. 29
|
||||
* File generated from CLDR ver. 27.0.1
|
||||
*
|
||||
* Before check in, this file could have been manually edited. This is to
|
||||
* incorporate changes before we could fix CLDR. All manual modification must be
|
||||
@@ -25,8 +25,6 @@
|
||||
* CLDR.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
|
||||
goog.provide('goog.i18n.pluralRules');
|
||||
/**
|
||||
* Plural pattern keyword
|
||||
@@ -71,7 +69,7 @@ goog.i18n.pluralRules.decimals_ = function(n) {
|
||||
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision optional, precision.
|
||||
* @return {!{v:number, f:number}} The v and f.
|
||||
* @return {!Object} The v and f.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.get_vf_ = function(n, opt_precision) {
|
||||
@@ -95,7 +93,7 @@ goog.i18n.pluralRules.get_vf_ = function(n, opt_precision) {
|
||||
* (http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax)
|
||||
* @param {number} v Calculated previously.
|
||||
* @param {number} f Calculated previously.
|
||||
* @return {!{w:number, t:number}} The w and t.
|
||||
* @return {!Object} The w and t.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.get_wt_ = function(v, f) {
|
||||
@@ -112,82 +110,29 @@ goog.i18n.pluralRules.get_wt_ = function(v, f) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for fil locale
|
||||
* Plural select rules for ga locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.filSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && (i == 1 || i == 2 || i == 3) || vf.v == 0 && i % 10 != 4 && i % 10 != 6 && i % 10 != 9 || vf.v != 0 && vf.f % 10 != 4 && vf.f % 10 != 6 && vf.f % 10 != 9) {
|
||||
goog.i18n.pluralRules.gaSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pt_PT locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.pt_PTSelect_ = function(n, opt_precision) {
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (n == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for br locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.brSelect_ = function(n, opt_precision) {
|
||||
if (n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92) {
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if ((n % 10 >= 3 && n % 10 <= 4 || n % 10 == 9) && (n % 100 < 10 || n % 100 > 19) && (n % 100 < 70 || n % 100 > 79) && (n % 100 < 90 || n % 100 > 99)) {
|
||||
if (n >= 3 && n <= 6) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n != 0 && n % 1000000 == 0) {
|
||||
if (n >= 7 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for sr locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.srSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11 || vf.f % 10 == 1 && vf.f % 100 != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14) || vf.f % 10 >= 2 && vf.f % 10 <= 4 && (vf.f % 100 < 12 || vf.f % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ro locale
|
||||
*
|
||||
@@ -209,16 +154,17 @@ goog.i18n.pluralRules.roSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for hi locale
|
||||
* Plural select rules for fil locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.hiSelect_ = function(n, opt_precision) {
|
||||
goog.i18n.pluralRules.filSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (i == 0 || n == 1) {
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && (i == 1 || i == 2 || i == 3) || vf.v == 0 && i % 10 != 4 && i % 10 != 6 && i % 10 != 9 || vf.v != 0 && vf.f % 10 != 4 && vf.f % 10 != 6 && vf.f % 10 != 9) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
@@ -241,127 +187,19 @@ goog.i18n.pluralRules.frSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for cs locale
|
||||
* Plural select rules for en locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.csSelect_ = function(n, opt_precision) {
|
||||
goog.i18n.pluralRules.enSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (i >= 2 && i <= 4 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pl locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.plSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v == 0 && i != 1 && i % 10 >= 0 && i % 10 <= 1 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 12 && i % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for shi locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.shiSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (i == 0 || n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n >= 2 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for lv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.lvSelect_ = function(n, opt_precision) {
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19 || vf.v == 2 && vf.f % 100 >= 11 && vf.f % 100 <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n % 10 == 1 && n % 100 != 11 || vf.v == 2 && vf.f % 10 == 1 && vf.f % 100 != 11 || vf.v != 2 && vf.f % 10 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for iu locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.iuSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for he locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.heSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (i == 2 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && (n < 0 || n > 10) && n % 10 == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
@@ -387,22 +225,49 @@ goog.i18n.pluralRules.mtSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for si locale
|
||||
* Plural select rules for da locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.siSelect_ = function(n, opt_precision) {
|
||||
goog.i18n.pluralRules.daSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if ((n == 0 || n == 1) || i == 0 && vf.f == 1) {
|
||||
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
|
||||
if (n == 1 || wt.t != 0 && (i == 0 || i == 1)) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for gv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gvSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && (i % 100 == 0 || i % 100 == 20 || i % 100 == 40 || i % 100 == 60 || i % 100 == 80)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for cy locale
|
||||
*
|
||||
@@ -431,89 +296,115 @@ goog.i18n.pluralRules.cySelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for da locale
|
||||
* Plural select rules for br locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.daSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
|
||||
if (n == 1 || wt.t != 0 && (i == 0 || i == 1)) {
|
||||
goog.i18n.pluralRules.brSelect_ = function(n, opt_precision) {
|
||||
if (n % 10 == 1 && n % 100 != 11 && n % 100 != 71 && n % 100 != 91) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ru locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.ruSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 == 0 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 11 && i % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for gv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gvSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 == 2) {
|
||||
if (n % 10 == 2 && n % 100 != 12 && n % 100 != 72 && n % 100 != 92) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && (i % 100 == 0 || i % 100 == 20 || i % 100 == 40 || i % 100 == 60 || i % 100 == 80)) {
|
||||
if ((n % 10 >= 3 && n % 10 <= 4 || n % 10 == 9) && (n % 100 < 10 || n % 100 > 19) && (n % 100 < 70 || n % 100 > 79) && (n % 100 < 90 || n % 100 > 99)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v != 0) {
|
||||
if (n != 0 && n % 1000000 == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for be locale
|
||||
* Plural select rules for es locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.beSelect_ = function(n, opt_precision) {
|
||||
if (n % 10 == 1 && n % 100 != 11) {
|
||||
goog.i18n.pluralRules.esSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for si locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.siSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if ((n == 0 || n == 1) || i == 0 && vf.f == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for sl locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.slSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 100 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.v != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n % 10 == 0 || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 11 && n % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for tzm locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.tzmSelect_ = function(n, opt_precision) {
|
||||
if (n >= 0 && n <= 1 || n >= 11 && n <= 99) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for sr locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.srSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11 || vf.f % 10 == 1 && vf.f % 100 != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14) || vf.f % 10 >= 2 && vf.f % 10 <= 4 && (vf.f % 100 < 12 || vf.f % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -536,26 +427,18 @@ goog.i18n.pluralRules.mkSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ga locale
|
||||
* Plural select rules for hi locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gaSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
goog.i18n.pluralRules.hiSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (i == 0 || n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n >= 3 && n <= 6) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n >= 7 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
@@ -574,99 +457,6 @@ goog.i18n.pluralRules.ptSelect_ = function(n, opt_precision) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for es locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.esSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for dsb locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.dsbSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 100 == 1 || vf.f % 100 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 == 2 || vf.f % 100 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.f % 100 >= 3 && vf.f % 100 <= 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for lag locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.lagSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if ((i == 0 || i == 1) && n != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for is locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.isSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
|
||||
if (wt.t == 0 && i % 10 == 1 && i % 100 != 11 || wt.t != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ksh locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.kshSelect_ = function(n, opt_precision) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ar locale
|
||||
*
|
||||
@@ -695,45 +485,219 @@ goog.i18n.pluralRules.arSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for gd locale
|
||||
* Plural select rules for iu locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gdSelect_ = function(n, opt_precision) {
|
||||
if (n == 1 || n == 11) {
|
||||
goog.i18n.pluralRules.iuSelect_ = function(n, opt_precision) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2 || n == 12) {
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for cs locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.csSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (i >= 2 && i <= 4 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pt_PT locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.pt_PTSelect_ = function(n, opt_precision) {
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (n == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for be locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.beSelect_ = function(n, opt_precision) {
|
||||
if (n % 10 == 1 && n % 100 != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n % 10 == 0 || n % 10 >= 5 && n % 10 <= 9 || n % 100 >= 11 && n % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ak locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.akSelect_ = function(n, opt_precision) {
|
||||
if (n >= 0 && n <= 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for pl locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.plSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v == 0 && i != 1 && i % 10 >= 0 && i % 10 <= 1 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 12 && i % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ru locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.ruSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 10 == 1 && i % 100 != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 >= 2 && i % 10 <= 4 && (i % 100 < 12 || i % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (vf.v == 0 && i % 10 == 0 || vf.v == 0 && i % 10 >= 5 && i % 10 <= 9 || vf.v == 0 && i % 100 >= 11 && i % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for lag locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.lagSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if ((i == 0 || i == 1) && n != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for shi locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.shiSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
if (i == 0 || n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n >= 2 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for sl locale
|
||||
* Plural select rules for he locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.slSelect_ = function(n, opt_precision) {
|
||||
goog.i18n.pluralRules.heSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (vf.v == 0 && i % 100 == 1) {
|
||||
if (i == 1 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 == 2) {
|
||||
if (i == 2 && vf.v == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.v != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (vf.v == 0 && (n < 0 || n > 10) && n % 10 == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for is locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.isSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
var wt = goog.i18n.pluralRules.get_wt_(vf.v, vf.f);
|
||||
if (wt.t == 0 && i % 10 == 1 && i % 100 != 11 || wt.t != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -761,47 +725,81 @@ goog.i18n.pluralRules.ltSelect_ = function(n, opt_precision) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for tzm locale
|
||||
* Plural select rules for gd locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.tzmSelect_ = function(n, opt_precision) {
|
||||
if (n >= 0 && n <= 1 || n >= 11 && n <= 99) {
|
||||
goog.i18n.pluralRules.gdSelect_ = function(n, opt_precision) {
|
||||
if (n == 1 || n == 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2 || n == 12) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for en locale
|
||||
* Plural select rules for dsb locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.enSelect_ = function(n, opt_precision) {
|
||||
goog.i18n.pluralRules.dsbSelect_ = function(n, opt_precision) {
|
||||
var i = n | 0;
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (i == 1 && vf.v == 0) {
|
||||
if (vf.v == 0 && i % 100 == 1 || vf.f % 100 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 == 2 || vf.f % 100 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (vf.v == 0 && i % 100 >= 3 && i % 100 <= 4 || vf.f % 100 >= 3 && vf.f % 100 <= 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ak locale
|
||||
* Plural select rules for lv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.akSelect_ = function(n, opt_precision) {
|
||||
if (n >= 0 && n <= 1) {
|
||||
goog.i18n.pluralRules.lvSelect_ = function(n, opt_precision) {
|
||||
var vf = goog.i18n.pluralRules.get_vf_(n, opt_precision);
|
||||
if (n % 10 == 0 || n % 100 >= 11 && n % 100 <= 19 || vf.v == 2 && vf.f % 100 >= 11 && vf.f % 100 <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n % 10 == 1 && n % 100 != 11 || vf.v == 2 && vf.f % 10 == 1 && vf.f % 100 != 11 || vf.v != 2 && vf.f % 10 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
/**
|
||||
* Plural select rules for ksh locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @param {number=} opt_precision Precision for number formatting, if not default.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.kshSelect_ = function(n, opt_precision) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
|
||||
@@ -9,21 +9,21 @@
|
||||
minErr,
|
||||
extend
|
||||
*/
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
function isFunction(value) { return typeof value === 'function'; }
|
||||
function isPromiseLike(obj) { return obj && isFunction(obj.then); }
|
||||
function isObject(value) { return value !== null && typeof value === 'object'; }
|
||||
function isUndefined(value) { return typeof value === 'undefined'; }
|
||||
|
||||
function minErr(module, constructor) {
|
||||
var isFunction = function isFunction(value) {return typeof value === 'function';};
|
||||
var isPromiseLike = function isPromiseLike(obj) {return obj && isFunction(obj.then);};
|
||||
var isObject = function isObject(value) {return value != null && typeof value === 'object';};
|
||||
var isUndefined = function isUndefined(value) {return typeof value === 'undefined';};
|
||||
|
||||
var minErr = function minErr(module, constructor) {
|
||||
return function() {
|
||||
var ErrorConstructor = constructor || Error;
|
||||
throw new ErrorConstructor(module + arguments[0] + arguments[1]);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function extend(dst) {
|
||||
var extend = function extend(dst) {
|
||||
for (var i = 1, ii = arguments.length; i < ii; i++) {
|
||||
var obj = arguments[i];
|
||||
if (obj) {
|
||||
@@ -35,11 +35,18 @@ function extend(dst) {
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
/* eslint-enable */
|
||||
};
|
||||
|
||||
var $q = qFactory(process.nextTick, function noopExceptionHandler() {});
|
||||
|
||||
exports.resolved = $q.resolve;
|
||||
exports.rejected = $q.reject;
|
||||
exports.deferred = $q.defer;
|
||||
exports.deferred = function() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
return {
|
||||
promise: deferred.promise,
|
||||
resolve: deferred.resolve,
|
||||
reject: deferred.reject
|
||||
};
|
||||
};
|
||||
|
||||
@@ -73,11 +73,6 @@ function getBuild() {
|
||||
return 'sha.' + hash;
|
||||
}
|
||||
|
||||
function checkBranchPattern(version, branchPattern) {
|
||||
// check that the version starts with the branch pattern minus its asterisk
|
||||
// e.g. branchPattern = '1.6.*'; version = '1.6.0-rc.0' => '1.6.' === '1.6.'
|
||||
return version.slice(0, branchPattern.length - 1) === branchPattern.replace('*', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current commit is tagged as a version get that version
|
||||
@@ -90,7 +85,7 @@ var getTaggedVersion = function() {
|
||||
var tag = gitTagResult.stdout.trim();
|
||||
var version = semver.parse(tag);
|
||||
|
||||
if (version && checkBranchPattern(version.version, currentPackage.branchPattern)) {
|
||||
if (version && semver.satisfies(version, currentPackage.branchVersion)) {
|
||||
version.codeName = getCodeName(tag);
|
||||
version.full = version.version;
|
||||
version.branch = 'v' + currentPackage.branchPattern.replace('*', 'x');
|
||||
|
||||
+5
-12
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "angularjs",
|
||||
"license": "MIT",
|
||||
"branchVersion": "^1.6.0",
|
||||
"branchPattern": "1.6.*",
|
||||
"distTag": "latest",
|
||||
"branchVersion": "1.5.x",
|
||||
"branchPattern": "1.5.*",
|
||||
"distTag": "previous_1_5",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^6.9.1",
|
||||
"yarn": ">=0.17.9",
|
||||
"yarn": "^0.17.9",
|
||||
"grunt": "^1.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -22,21 +22,17 @@
|
||||
"devDependencies": {
|
||||
"angular-benchpress": "0.x.x",
|
||||
"benchmark": "1.x.x",
|
||||
"bootstrap": "3.1.1",
|
||||
"bower": "~1.3.9",
|
||||
"browserstacktunnel-wrapper": "^1.4.2",
|
||||
"canonical-path": "0.0.2",
|
||||
"changez": "^2.1.1",
|
||||
"changez-angular": "^2.1.2",
|
||||
"cheerio": "^0.17.0",
|
||||
"commitizen": "^2.3.0",
|
||||
"cross-spawn": "^4.0.0",
|
||||
"cz-conventional-changelog": "1.1.4",
|
||||
"dgeni": "^0.4.0",
|
||||
"dgeni-packages": "^0.16.4",
|
||||
"dgeni-packages": "^0.16.0",
|
||||
"event-stream": "~3.1.0",
|
||||
"glob": "^6.0.1",
|
||||
"google-code-prettify": "1.0.1",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt-bump": "^0.8.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
@@ -59,7 +55,6 @@
|
||||
"jasmine-core": "^2.4.0",
|
||||
"jasmine-node": "^2.0.0",
|
||||
"jasmine-reporters": "^2.2.0",
|
||||
"jquery": "^3.1.1",
|
||||
"karma": "^1.1.2",
|
||||
"karma-browserstack-launcher": "^1.0.1",
|
||||
"karma-chrome-launcher": "^1.0.1",
|
||||
@@ -72,11 +67,9 @@
|
||||
"load-grunt-tasks": "^3.5.0",
|
||||
"lodash": "~2.4.1",
|
||||
"log4js": "^0.6.27",
|
||||
"lunr": "^0.7.2",
|
||||
"marked": "~0.3.0",
|
||||
"node-html-encoder": "0.0.2",
|
||||
"npm-run": "^4.1.0",
|
||||
"open-sans-fontface": "^1.4.0",
|
||||
"promises-aplus-tests": "~2.1.0",
|
||||
"protractor": "^4.0.10",
|
||||
"q": "~1.0.0",
|
||||
|
||||
+5
-3
@@ -95,12 +95,12 @@
|
||||
"createMap": false,
|
||||
"VALIDITY_STATE_PROPERTY": false,
|
||||
"reloadWithDebugInfo": false,
|
||||
"stringify": false,
|
||||
|
||||
"NODE_TYPE_ELEMENT": false,
|
||||
"NODE_TYPE_ATTRIBUTE": false,
|
||||
"NODE_TYPE_TEXT": false,
|
||||
"NODE_TYPE_COMMENT": false,
|
||||
"NODE_TYPE_COMMENT": false,
|
||||
"NODE_TYPE_DOCUMENT": false,
|
||||
"NODE_TYPE_DOCUMENT_FRAGMENT": false,
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
"BOOLEAN_ATTR": false,
|
||||
"ALIASED_ATTR": false,
|
||||
"jqNextId": false,
|
||||
"fnCamelCaseReplace": false,
|
||||
"camelCase": false,
|
||||
"jqLitePatchJQueryRemove": false,
|
||||
"JQLite": false,
|
||||
"jqLiteClone": false,
|
||||
@@ -145,12 +145,14 @@
|
||||
"getAliasedAttrName": false,
|
||||
"createEventHandler": false,
|
||||
"JQLitePrototype": false,
|
||||
"addEventListenerFn": false,
|
||||
"removeEventListenerFn": false,
|
||||
"jqLiteIsTextNode": false,
|
||||
"jqLiteDocumentLoaded": false,
|
||||
|
||||
/* apis.js */
|
||||
"hashKey": false,
|
||||
"NgMap": false,
|
||||
"HashMap": false,
|
||||
|
||||
/* urlUtils.js */
|
||||
"urlResolve": false,
|
||||
|
||||
+5
-59
@@ -88,7 +88,6 @@
|
||||
getBlockNodes,
|
||||
hasOwnProperty,
|
||||
createMap,
|
||||
stringify,
|
||||
|
||||
NODE_TYPE_ELEMENT,
|
||||
NODE_TYPE_ATTRIBUTE,
|
||||
@@ -122,41 +121,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
|
||||
// This is used so that it's possible for internal tests to create mock ValidityStates.
|
||||
var VALIDITY_STATE_PROPERTY = 'validity';
|
||||
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.lowercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.5.0"
|
||||
* removeVersion="1.7.0"
|
||||
* Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
|
||||
*
|
||||
* @description Converts the specified string to lowercase.
|
||||
* @param {string} string String to be converted to lowercase.
|
||||
* @returns {string} Lowercased string.
|
||||
*/
|
||||
var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.uppercase
|
||||
* @module ng
|
||||
* @kind function
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="1.5.0"
|
||||
* removeVersion="1.7.0"
|
||||
* Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
|
||||
*
|
||||
* @description Converts the specified string to uppercase.
|
||||
* @param {string} string String to be converted to uppercase.
|
||||
* @returns {string} Uppercased string.
|
||||
*/
|
||||
var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
|
||||
|
||||
|
||||
@@ -201,7 +168,6 @@ var
|
||||
angularModule,
|
||||
uid = 0;
|
||||
|
||||
// Support: IE 9-11 only
|
||||
/**
|
||||
* documentMode is an IE-only property
|
||||
* http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
|
||||
@@ -277,7 +243,9 @@ function forEach(obj, iterator, context) {
|
||||
if (obj) {
|
||||
if (isFunction(obj)) {
|
||||
for (key in obj) {
|
||||
if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
|
||||
// Need to check if hasOwnProperty exists,
|
||||
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
|
||||
if (key !== 'prototype' && key !== 'length' && key !== 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
|
||||
iterator.call(context, obj[key], key, obj);
|
||||
}
|
||||
}
|
||||
@@ -1312,7 +1280,6 @@ function fromJson(json) {
|
||||
|
||||
var ALL_COLONS = /:/g;
|
||||
function timezoneToOffset(timezone, fallback) {
|
||||
// Support: IE 9-11 only, Edge 13-14+
|
||||
// IE/Edge do not "understand" colon (`:`) in timezone
|
||||
timezone = timezone.replace(ALL_COLONS, '');
|
||||
var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
|
||||
@@ -1448,7 +1415,7 @@ function encodeUriSegment(val) {
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
||||
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
||||
* encoded per http://tools.ietf.org/html/rfc3986:
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
@@ -1870,7 +1837,7 @@ function bindJQuery() {
|
||||
extend(jQuery.fn, {
|
||||
scope: JQLitePrototype.scope,
|
||||
isolateScope: JQLitePrototype.isolateScope,
|
||||
controller: /** @type {?} */ (JQLitePrototype).controller,
|
||||
controller: JQLitePrototype.controller,
|
||||
injector: JQLitePrototype.injector,
|
||||
inheritedData: JQLitePrototype.inheritedData
|
||||
});
|
||||
@@ -1996,27 +1963,6 @@ function createMap() {
|
||||
return Object.create(null);
|
||||
}
|
||||
|
||||
function stringify(value) {
|
||||
if (value == null) { // null || undefined
|
||||
return '';
|
||||
}
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
break;
|
||||
case 'number':
|
||||
value = '' + value;
|
||||
break;
|
||||
default:
|
||||
if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
|
||||
value = value.toString();
|
||||
} else {
|
||||
value = toJson(value);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
var NODE_TYPE_ELEMENT = 1;
|
||||
var NODE_TYPE_ATTRIBUTE = 2;
|
||||
var NODE_TYPE_TEXT = 3;
|
||||
|
||||
@@ -64,12 +64,12 @@
|
||||
$ControllerProvider,
|
||||
$DateProvider,
|
||||
$DocumentProvider,
|
||||
$$IsDocumentHiddenProvider,
|
||||
$ExceptionHandlerProvider,
|
||||
$FilterProvider,
|
||||
$$ForceReflowProvider,
|
||||
$InterpolateProvider,
|
||||
$IntervalProvider,
|
||||
$$HashMapProvider,
|
||||
$HttpProvider,
|
||||
$HttpParamSerializerProvider,
|
||||
$HttpParamSerializerJQLikeProvider,
|
||||
@@ -78,7 +78,6 @@
|
||||
$jsonpCallbacksProvider,
|
||||
$LocationProvider,
|
||||
$LogProvider,
|
||||
$$MapProvider,
|
||||
$ParseProvider,
|
||||
$RootScopeProvider,
|
||||
$QProvider,
|
||||
@@ -153,12 +152,9 @@ function publishExternalAPI(angular) {
|
||||
'uppercase': uppercase,
|
||||
'callbacks': {$$counter: 0},
|
||||
'getTestability': getTestability,
|
||||
'reloadWithDebugInfo': reloadWithDebugInfo,
|
||||
'$$minErr': minErr,
|
||||
'$$csp': csp,
|
||||
'$$encodeUriSegment': encodeUriSegment,
|
||||
'$$encodeUriQuery': encodeUriQuery,
|
||||
'$$stringify': stringify
|
||||
'reloadWithDebugInfo': reloadWithDebugInfo
|
||||
});
|
||||
|
||||
angularModule = setupModuleLoader(window);
|
||||
@@ -232,7 +228,6 @@ function publishExternalAPI(angular) {
|
||||
$cacheFactory: $CacheFactoryProvider,
|
||||
$controller: $ControllerProvider,
|
||||
$document: $DocumentProvider,
|
||||
$$isDocumentHidden: $$IsDocumentHiddenProvider,
|
||||
$exceptionHandler: $ExceptionHandlerProvider,
|
||||
$filter: $FilterProvider,
|
||||
$$forceReflow: $$ForceReflowProvider,
|
||||
@@ -260,7 +255,7 @@ function publishExternalAPI(angular) {
|
||||
$window: $WindowProvider,
|
||||
$$rAF: $$RAFProvider,
|
||||
$$jqLite: $$jqLiteProvider,
|
||||
$$Map: $$MapProvider,
|
||||
$$HashMap: $$HashMapProvider,
|
||||
$$cookieReader: $$CookieReaderProvider
|
||||
});
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
if (window.angular.bootstrap) {
|
||||
// AngularJS is already loaded, so we can return here...
|
||||
//AngularJS is already loaded, so we can return here...
|
||||
if (window.console) {
|
||||
console.log('WARNING: Tried to load angular more than once.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// try to bind to jquery now so that one can write jqLite(fn)
|
||||
// but we will rebind on bootstrap again.
|
||||
//try to bind to jquery now so that one can write jqLite(document).ready()
|
||||
//but we will rebind on bootstrap again.
|
||||
bindJQuery();
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
jqLite(function() {
|
||||
jqLite(window.document).ready(function() {
|
||||
angularInit(window.document, bootstrap);
|
||||
});
|
||||
|
||||
|
||||
+37
-56
@@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Computes a hash of an 'obj'.
|
||||
* Hash of a:
|
||||
@@ -32,69 +33,49 @@ function hashKey(obj, nextUidFn) {
|
||||
return key;
|
||||
}
|
||||
|
||||
// A minimal ES2015 Map implementation.
|
||||
// Should be bug/feature equivalent to the native implementations of supported browsers
|
||||
// (for the features required in Angular).
|
||||
// See https://kangax.github.io/compat-table/es6/#test-Map
|
||||
var nanKey = Object.create(null);
|
||||
function NgMapShim() {
|
||||
this._keys = [];
|
||||
this._values = [];
|
||||
this._lastKey = NaN;
|
||||
this._lastIndex = -1;
|
||||
/**
|
||||
* HashMap which can use objects as keys
|
||||
*/
|
||||
function HashMap(array, isolatedUid) {
|
||||
if (isolatedUid) {
|
||||
var uid = 0;
|
||||
this.nextUid = function() {
|
||||
return ++uid;
|
||||
};
|
||||
}
|
||||
forEach(array, this.put, this);
|
||||
}
|
||||
NgMapShim.prototype = {
|
||||
_idx: function(key) {
|
||||
if (key === this._lastKey) {
|
||||
return this._lastIndex;
|
||||
}
|
||||
this._lastKey = key;
|
||||
this._lastIndex = this._keys.indexOf(key);
|
||||
return this._lastIndex;
|
||||
HashMap.prototype = {
|
||||
/**
|
||||
* Store key value pair
|
||||
* @param key key to store can be any type
|
||||
* @param value value to store can be any type
|
||||
*/
|
||||
put: function(key, value) {
|
||||
this[hashKey(key, this.nextUid)] = value;
|
||||
},
|
||||
_transformKey: function(key) {
|
||||
return isNumberNaN(key) ? nanKey : key;
|
||||
},
|
||||
get: function(key) {
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx !== -1) {
|
||||
return this._values[idx];
|
||||
}
|
||||
},
|
||||
set: function(key, value) {
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx === -1) {
|
||||
idx = this._lastIndex = this._keys.length;
|
||||
}
|
||||
this._keys[idx] = key;
|
||||
this._values[idx] = value;
|
||||
|
||||
// Support: IE11
|
||||
// Do not `return this` to simulate the partial IE11 implementation
|
||||
/**
|
||||
* @param key
|
||||
* @returns {Object} the value for the key
|
||||
*/
|
||||
get: function(key) {
|
||||
return this[hashKey(key, this.nextUid)];
|
||||
},
|
||||
delete: function(key) {
|
||||
key = this._transformKey(key);
|
||||
var idx = this._idx(key);
|
||||
if (idx === -1) {
|
||||
return false;
|
||||
}
|
||||
this._keys.splice(idx, 1);
|
||||
this._values.splice(idx, 1);
|
||||
this._lastKey = NaN;
|
||||
this._lastIndex = -1;
|
||||
return true;
|
||||
|
||||
/**
|
||||
* Remove the key/value pair
|
||||
* @param key
|
||||
*/
|
||||
remove: function(key) {
|
||||
var value = this[key = hashKey(key, this.nextUid)];
|
||||
delete this[key];
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
|
||||
// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
|
||||
// implementations get more stable, we can reconsider switching to `window.Map` (when available).
|
||||
var NgMap = NgMapShim;
|
||||
|
||||
var $$MapProvider = [/** @this */function() {
|
||||
var $$HashMapProvider = [/** @this */function() {
|
||||
this.$get = [function() {
|
||||
return NgMap;
|
||||
return HashMap;
|
||||
}];
|
||||
}];
|
||||
|
||||
+12
-12
@@ -71,7 +71,11 @@ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||
var $injectorMinErr = minErr('$injector');
|
||||
|
||||
function stringifyFn(fn) {
|
||||
return Function.prototype.toString.call(fn);
|
||||
// Support: Chrome 50-51 only
|
||||
// Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
|
||||
// (See https://github.com/angular/angular.js/issues/14487.)
|
||||
// TODO (gkalpak): Remove workaround when Chrome v52 is released
|
||||
return Function.prototype.toString.call(fn) + ' ';
|
||||
}
|
||||
|
||||
function extractArgs(fn) {
|
||||
@@ -645,7 +649,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
var INSTANTIATING = {},
|
||||
providerSuffix = 'Provider',
|
||||
path = [],
|
||||
loadedModules = new NgMap(),
|
||||
loadedModules = new HashMap([], true),
|
||||
providerCache = {
|
||||
$provide: {
|
||||
provider: supportObject(provider),
|
||||
@@ -753,7 +757,7 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
var runBlocks = [], moduleFn;
|
||||
forEach(modulesToLoad, function(module) {
|
||||
if (loadedModules.get(module)) return;
|
||||
loadedModules.set(module, true);
|
||||
loadedModules.put(module, true);
|
||||
|
||||
function runInvokeQueue(queue) {
|
||||
var i, ii;
|
||||
@@ -845,18 +849,14 @@ function createInjector(modulesToLoad, strictDi) {
|
||||
}
|
||||
|
||||
function isClass(func) {
|
||||
// Support: IE 9-11 only
|
||||
// IE 9-11 do not support classes and IE9 leaks with the code below.
|
||||
if (msie || typeof func !== 'function') {
|
||||
if (msie <= 11) {
|
||||
return false;
|
||||
}
|
||||
var result = func.$$ngIsClass;
|
||||
if (!isBoolean(result)) {
|
||||
// Support: Edge 12-13 only
|
||||
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
|
||||
result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func));
|
||||
}
|
||||
return result;
|
||||
// Support: Edge 12-13 only
|
||||
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
|
||||
return typeof func === 'function'
|
||||
&& /^(?:class\b|constructor\()/.test(stringifyFn(func));
|
||||
}
|
||||
|
||||
function invoke(fn, self, locals, serviceName) {
|
||||
|
||||
+72
-83
@@ -11,8 +11,9 @@
|
||||
* Or gives undesired access to variables likes document or window? *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* global
|
||||
JQLitePrototype: true,
|
||||
/* global JQLitePrototype: true,
|
||||
addEventListenerFn: true,
|
||||
removeEventListenerFn: true,
|
||||
BOOLEAN_ATTR: true,
|
||||
ALIASED_ATTR: true
|
||||
*/
|
||||
@@ -56,7 +57,7 @@
|
||||
* - [`after()`](http://api.jquery.com/after/)
|
||||
* - [`append()`](http://api.jquery.com/append/)
|
||||
* - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
|
||||
* - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
|
||||
* - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
|
||||
* - [`children()`](http://api.jquery.com/children/) - Does not support selectors
|
||||
* - [`clone()`](http://api.jquery.com/clone/)
|
||||
* - [`contents()`](http://api.jquery.com/contents/)
|
||||
@@ -76,7 +77,7 @@
|
||||
* - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
|
||||
* - [`prepend()`](http://api.jquery.com/prepend/)
|
||||
* - [`prop()`](http://api.jquery.com/prop/)
|
||||
* - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
|
||||
* - [`ready()`](http://api.jquery.com/ready/)
|
||||
* - [`remove()`](http://api.jquery.com/remove/)
|
||||
* - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
|
||||
* - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
|
||||
@@ -85,7 +86,7 @@
|
||||
* - [`text()`](http://api.jquery.com/text/)
|
||||
* - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
|
||||
* - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
|
||||
* - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
|
||||
* - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
|
||||
* - [`val()`](http://api.jquery.com/val/)
|
||||
* - [`wrap()`](http://api.jquery.com/wrap/)
|
||||
*
|
||||
@@ -123,7 +124,13 @@
|
||||
JQLite.expando = 'ng339';
|
||||
|
||||
var jqCache = JQLite.cache = {},
|
||||
jqId = 1;
|
||||
jqId = 1,
|
||||
addEventListenerFn = function(element, type, fn) {
|
||||
element.addEventListener(type, fn, false);
|
||||
},
|
||||
removeEventListenerFn = function(element, type, fn) {
|
||||
element.removeEventListener(type, fn, false);
|
||||
};
|
||||
|
||||
/*
|
||||
* !!! This is an undocumented "private" function !!!
|
||||
@@ -136,31 +143,22 @@ JQLite._data = function(node) {
|
||||
function jqNextId() { return ++jqId; }
|
||||
|
||||
|
||||
var DASH_LOWERCASE_REGEXP = /-([a-z])/g;
|
||||
var MS_HACK_REGEXP = /^-ms-/;
|
||||
var SPECIAL_CHARS_REGEXP = /([:\-_]+(.))/g;
|
||||
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
|
||||
var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
|
||||
var jqLiteMinErr = minErr('jqLite');
|
||||
|
||||
/**
|
||||
* Converts kebab-case to camelCase.
|
||||
* There is also a special case for the ms prefix starting with a lowercase letter.
|
||||
* Converts snake_case to camelCase.
|
||||
* Also there is special case for Moz prefix starting with upper case letter.
|
||||
* @param name Name to normalize
|
||||
*/
|
||||
function cssKebabToCamel(name) {
|
||||
return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-'));
|
||||
}
|
||||
|
||||
function fnCamelCaseReplace(all, letter) {
|
||||
return letter.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts kebab-case to camelCase.
|
||||
* @param name Name to normalize
|
||||
*/
|
||||
function kebabToCamel(name) {
|
||||
return name
|
||||
.replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
|
||||
function camelCase(name) {
|
||||
return name.
|
||||
replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
|
||||
return offset ? letter.toUpperCase() : letter;
|
||||
}).
|
||||
replace(MOZ_HACK_REGEXP, 'Moz$1');
|
||||
}
|
||||
|
||||
var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
|
||||
@@ -297,8 +295,6 @@ function JQLite(element) {
|
||||
|
||||
if (argIsString) {
|
||||
jqLiteAddNodes(this, jqLiteParseHTML(element));
|
||||
} else if (isFunction(element)) {
|
||||
jqLiteReady(element);
|
||||
} else {
|
||||
jqLiteAddNodes(this, element);
|
||||
}
|
||||
@@ -331,7 +327,7 @@ function jqLiteOff(element, type, fn, unsupported) {
|
||||
if (!type) {
|
||||
for (type in events) {
|
||||
if (type !== '$destroy') {
|
||||
element.removeEventListener(type, handle);
|
||||
removeEventListenerFn(element, type, handle);
|
||||
}
|
||||
delete events[type];
|
||||
}
|
||||
@@ -343,7 +339,7 @@ function jqLiteOff(element, type, fn, unsupported) {
|
||||
arrayRemove(listenerFns || [], fn);
|
||||
}
|
||||
if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
|
||||
element.removeEventListener(type, handle);
|
||||
removeEventListenerFn(element, type, handle);
|
||||
delete events[type];
|
||||
}
|
||||
};
|
||||
@@ -394,7 +390,6 @@ function jqLiteExpandoStore(element, createIfNecessary) {
|
||||
|
||||
function jqLiteData(element, key, value) {
|
||||
if (jqLiteAcceptsData(element)) {
|
||||
var prop;
|
||||
|
||||
var isSimpleSetter = isDefined(value);
|
||||
var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
|
||||
@@ -403,18 +398,16 @@ function jqLiteData(element, key, value) {
|
||||
var data = expandoStore && expandoStore.data;
|
||||
|
||||
if (isSimpleSetter) { // data('key', value)
|
||||
data[kebabToCamel(key)] = value;
|
||||
data[key] = value;
|
||||
} else {
|
||||
if (massGetter) { // data()
|
||||
return data;
|
||||
} else {
|
||||
if (isSimpleGetter) { // data('key')
|
||||
// don't force creation of expandoStore if it doesn't exist yet
|
||||
return data && data[kebabToCamel(key)];
|
||||
return data && data[key];
|
||||
} else { // mass-setter: data({key1: val1, key2: val2})
|
||||
for (prop in key) {
|
||||
data[kebabToCamel(prop)] = key[prop];
|
||||
}
|
||||
extend(data, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -533,32 +526,29 @@ function jqLiteDocumentLoaded(action, win) {
|
||||
}
|
||||
}
|
||||
|
||||
function jqLiteReady(fn) {
|
||||
function trigger() {
|
||||
window.document.removeEventListener('DOMContentLoaded', trigger);
|
||||
window.removeEventListener('load', trigger);
|
||||
fn();
|
||||
}
|
||||
|
||||
// check if document is already loaded
|
||||
if (window.document.readyState === 'complete') {
|
||||
window.setTimeout(fn);
|
||||
} else {
|
||||
// We can not use jqLite since we are not done loading and jQuery could be loaded later.
|
||||
|
||||
// Works for modern browsers and IE9
|
||||
window.document.addEventListener('DOMContentLoaded', trigger);
|
||||
|
||||
// Fallback to window.onload for others
|
||||
window.addEventListener('load', trigger);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Functions which are declared directly.
|
||||
//////////////////////////////////////////
|
||||
var JQLitePrototype = JQLite.prototype = {
|
||||
ready: jqLiteReady,
|
||||
ready: function(fn) {
|
||||
var fired = false;
|
||||
|
||||
function trigger() {
|
||||
if (fired) return;
|
||||
fired = true;
|
||||
fn();
|
||||
}
|
||||
|
||||
// check if document is already loaded
|
||||
if (window.document.readyState === 'complete') {
|
||||
window.setTimeout(trigger);
|
||||
} else {
|
||||
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
|
||||
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
|
||||
// eslint-disable-next-line new-cap
|
||||
JQLite(window).on('load', trigger); // fallback to window.onload for others
|
||||
}
|
||||
},
|
||||
toString: function() {
|
||||
var value = [];
|
||||
forEach(this, function(e) { value.push('' + e);});
|
||||
@@ -593,8 +583,7 @@ var ALIASED_ATTR = {
|
||||
'ngMaxlength': 'maxlength',
|
||||
'ngMin': 'min',
|
||||
'ngMax': 'max',
|
||||
'ngPattern': 'pattern',
|
||||
'ngStep': 'step'
|
||||
'ngPattern': 'pattern'
|
||||
};
|
||||
|
||||
function getBooleanAttrName(element, name) {
|
||||
@@ -645,7 +634,7 @@ forEach({
|
||||
hasClass: jqLiteHasClass,
|
||||
|
||||
css: function(element, name, value) {
|
||||
name = cssKebabToCamel(name);
|
||||
name = camelCase(name);
|
||||
|
||||
if (isDefined(value)) {
|
||||
element.style[name] = value;
|
||||
@@ -655,33 +644,33 @@ forEach({
|
||||
},
|
||||
|
||||
attr: function(element, name, value) {
|
||||
var ret;
|
||||
var nodeType = element.nodeType;
|
||||
if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
|
||||
!element.getAttribute) {
|
||||
if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lowercasedName = lowercase(name);
|
||||
var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
|
||||
|
||||
if (isDefined(value)) {
|
||||
// setter
|
||||
|
||||
if (value === null || (value === false && isBooleanAttr)) {
|
||||
element.removeAttribute(name);
|
||||
if (BOOLEAN_ATTR[lowercasedName]) {
|
||||
if (isDefined(value)) {
|
||||
if (value) {
|
||||
element[name] = true;
|
||||
element.setAttribute(name, lowercasedName);
|
||||
} else {
|
||||
element[name] = false;
|
||||
element.removeAttribute(lowercasedName);
|
||||
}
|
||||
} else {
|
||||
element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
|
||||
return (element[name] ||
|
||||
(element.attributes.getNamedItem(name) || noop).specified)
|
||||
? lowercasedName
|
||||
: undefined;
|
||||
}
|
||||
} else {
|
||||
// getter
|
||||
|
||||
ret = element.getAttribute(name);
|
||||
|
||||
if (isBooleanAttr && ret !== null) {
|
||||
ret = lowercasedName;
|
||||
}
|
||||
// Normalize non-existing attributes to undefined (as jQuery).
|
||||
} else if (isDefined(value)) {
|
||||
element.setAttribute(name, value);
|
||||
} else if (element.getAttribute) {
|
||||
// the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
|
||||
// some elements (e.g. Document) don't have get attribute, so return undefined
|
||||
var ret = element.getAttribute(name, 2);
|
||||
// normalize non-existing attributes to undefined (as jQuery)
|
||||
return ret === null ? undefined : ret;
|
||||
}
|
||||
},
|
||||
@@ -716,7 +705,7 @@ forEach({
|
||||
result.push(option.value || option.text);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
return result.length === 0 ? null : result;
|
||||
}
|
||||
return element.value;
|
||||
}
|
||||
@@ -886,7 +875,7 @@ forEach({
|
||||
eventFns = events[type] = [];
|
||||
eventFns.specialHandlerWrapper = specialHandlerWrapper;
|
||||
if (type !== '$destroy' && !noEventListener) {
|
||||
element.addEventListener(type, handle);
|
||||
addEventListenerFn(element, type, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -203,7 +203,7 @@ function setupModuleLoader(window) {
|
||||
* @description
|
||||
* See {@link auto.$provide#decorator $provide.decorator()}.
|
||||
*/
|
||||
decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
|
||||
decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -349,11 +349,10 @@ function setupModuleLoader(window) {
|
||||
* @param {string} method
|
||||
* @returns {angular.Module}
|
||||
*/
|
||||
function invokeLaterAndSetModuleName(provider, method, queue) {
|
||||
if (!queue) queue = invokeQueue;
|
||||
function invokeLaterAndSetModuleName(provider, method) {
|
||||
return function(recipeName, factoryFunction) {
|
||||
if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
|
||||
queue.push([provider, method, arguments]);
|
||||
invokeQueue.push([provider, method, arguments]);
|
||||
return moduleInstance;
|
||||
};
|
||||
}
|
||||
|
||||
+4
-3
@@ -60,7 +60,7 @@ var $$CoreAnimateJsProvider = /** @this */ function() {
|
||||
// this is prefixed with Core since it conflicts with
|
||||
// the animateQueueProvider defined in ngAnimate/animateQueue.js
|
||||
var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
var postDigestQueue = new NgMap();
|
||||
var postDigestQueue = new HashMap();
|
||||
var postDigestElements = [];
|
||||
|
||||
this.$get = ['$$AnimateRunner', '$rootScope',
|
||||
@@ -139,7 +139,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
jqLiteRemoveClass(elm, toRemove);
|
||||
}
|
||||
});
|
||||
postDigestQueue.delete(element);
|
||||
postDigestQueue.remove(element);
|
||||
}
|
||||
});
|
||||
postDigestElements.length = 0;
|
||||
@@ -154,7 +154,7 @@ var $$CoreAnimateQueueProvider = /** @this */ function() {
|
||||
|
||||
if (classesAdded || classesRemoved) {
|
||||
|
||||
postDigestQueue.set(element, data);
|
||||
postDigestQueue.put(element, data);
|
||||
postDigestElements.push(element);
|
||||
|
||||
if (postDigestElements.length === 1) {
|
||||
@@ -252,6 +252,7 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
|
||||
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
|
||||
if (reservedRegex.test(this.$$classNameFilter.toString())) {
|
||||
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
|
||||
};
|
||||
|
||||
var $$AnimateRunnerFactoryProvider = /** @this */ function() {
|
||||
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
|
||||
function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) {
|
||||
this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
|
||||
function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
|
||||
|
||||
var INITIAL_STATE = 0;
|
||||
var DONE_PENDING_STATE = 1;
|
||||
@@ -85,7 +85,11 @@ var $$AnimateRunnerFactoryProvider = /** @this */ function() {
|
||||
|
||||
this._doneCallbacks = [];
|
||||
this._tick = function(fn) {
|
||||
if ($$isDocumentHidden()) {
|
||||
var doc = $document[0];
|
||||
|
||||
// the document may not be ready or attached
|
||||
// to the module for some internal tests
|
||||
if (doc && doc.hidden) {
|
||||
timeoutTick(fn);
|
||||
} else {
|
||||
rafTick(fn);
|
||||
|
||||
+8
-9
@@ -96,6 +96,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
};
|
||||
|
||||
cacheState();
|
||||
lastHistoryState = cachedState;
|
||||
|
||||
/**
|
||||
* @name $browser#url
|
||||
@@ -149,6 +150,8 @@ function Browser(window, document, $log, $sniffer) {
|
||||
if ($sniffer.history && (!sameBase || !sameState)) {
|
||||
history[replace ? 'replaceState' : 'pushState'](state, '', url);
|
||||
cacheState();
|
||||
// Do the assignment again so that those two variables are referentially identical.
|
||||
lastHistoryState = cachedState;
|
||||
} else {
|
||||
if (!sameBase) {
|
||||
pendingLocation = url;
|
||||
@@ -197,7 +200,8 @@ function Browser(window, document, $log, $sniffer) {
|
||||
|
||||
function cacheStateAndFireUrlChange() {
|
||||
pendingLocation = null;
|
||||
fireStateOrUrlChange();
|
||||
cacheState();
|
||||
fireUrlChange();
|
||||
}
|
||||
|
||||
// This variable should be used *only* inside the cacheState function.
|
||||
@@ -211,16 +215,11 @@ function Browser(window, document, $log, $sniffer) {
|
||||
if (equals(cachedState, lastCachedState)) {
|
||||
cachedState = lastCachedState;
|
||||
}
|
||||
|
||||
lastCachedState = cachedState;
|
||||
lastHistoryState = cachedState;
|
||||
}
|
||||
|
||||
function fireStateOrUrlChange() {
|
||||
var prevLastHistoryState = lastHistoryState;
|
||||
cacheState();
|
||||
|
||||
if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
|
||||
function fireUrlChange() {
|
||||
if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -286,7 +285,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
* Needs to be exported to be able to check for changes that have been done in sync,
|
||||
* as hashchange/popstate events fire in async.
|
||||
*/
|
||||
self.$$checkUrlChange = fireStateOrUrlChange;
|
||||
self.$$checkUrlChange = fireUrlChange;
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Misc API
|
||||
|
||||
+36
-75
@@ -128,8 +128,7 @@
|
||||
* * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
|
||||
* `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
|
||||
* object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
|
||||
* component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
|
||||
* also be called when your bindings are initialized.
|
||||
* component such as cloning the bound value to prevent accidental mutation of the outer value.
|
||||
* * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
|
||||
* changes. Any actions that you wish to take in response to the changes that you detect must be
|
||||
* invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
|
||||
@@ -1390,7 +1389,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
*
|
||||
* The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.
|
||||
*/
|
||||
var preAssignBindingsEnabled = false;
|
||||
var preAssignBindingsEnabled = true;
|
||||
this.preAssignBindingsEnabled = function(enabled) {
|
||||
if (isDefined(enabled)) {
|
||||
preAssignBindingsEnabled = enabled;
|
||||
@@ -1852,15 +1851,25 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
// modify it.
|
||||
$compileNodes = jqLite($compileNodes);
|
||||
}
|
||||
|
||||
var NOT_EMPTY = /\S+/;
|
||||
|
||||
// We can not compile top level text elements since text nodes can be merged and we will
|
||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||
for (var i = 0, len = $compileNodes.length; i < len; i++) {
|
||||
var domNode = $compileNodes[i];
|
||||
|
||||
if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
|
||||
jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
|
||||
}
|
||||
}
|
||||
|
||||
var compositeLinkFn =
|
||||
compileNodes($compileNodes, transcludeFn, $compileNodes,
|
||||
maxPriority, ignoreDirective, previousCompileContext);
|
||||
compile.$$addScopeClass($compileNodes);
|
||||
var namespace = null;
|
||||
return function publicLinkFn(scope, cloneConnectFn, options) {
|
||||
if (!$compileNodes) {
|
||||
throw $compileMinErr('multilink', 'This element has already been linked.');
|
||||
}
|
||||
assertArg(scope, 'scope');
|
||||
|
||||
if (previousCompileContext && previousCompileContext.needsNewScope) {
|
||||
@@ -1915,10 +1924,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
|
||||
|
||||
if (!cloneConnectFn) {
|
||||
$compileNodes = compositeLinkFn = null;
|
||||
}
|
||||
return $linkNode;
|
||||
};
|
||||
}
|
||||
@@ -1951,23 +1956,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
|
||||
previousCompileContext) {
|
||||
var linkFns = [],
|
||||
// `nodeList` can be either an element's `.childNodes` (live NodeList)
|
||||
// or a jqLite/jQuery collection or an array
|
||||
notLiveList = isArray(nodeList) || (nodeList instanceof jqLite),
|
||||
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
|
||||
|
||||
|
||||
for (var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// Support: IE 11 only
|
||||
// Workaround for #11781 and #14924
|
||||
if (msie === 11) {
|
||||
mergeConsecutiveTextNodes(nodeList, i, notLiveList);
|
||||
}
|
||||
|
||||
// We must always refer to `nodeList[i]` hereafter,
|
||||
// since the nodes can be replaced underneath us.
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
|
||||
ignoreDirective);
|
||||
|
||||
@@ -2058,32 +2052,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
}
|
||||
|
||||
function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) {
|
||||
var node = nodeList[idx];
|
||||
var parent = node.parentNode;
|
||||
var sibling;
|
||||
|
||||
if (node.nodeType !== NODE_TYPE_TEXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
sibling = parent ? node.nextSibling : nodeList[idx + 1];
|
||||
if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) {
|
||||
break;
|
||||
}
|
||||
|
||||
node.nodeValue = node.nodeValue + sibling.nodeValue;
|
||||
|
||||
if (sibling.parentNode) {
|
||||
sibling.parentNode.removeChild(sibling);
|
||||
}
|
||||
if (notLiveList && sibling === nodeList[idx + 1]) {
|
||||
nodeList.splice(idx + 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
|
||||
function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
|
||||
|
||||
@@ -2147,7 +2115,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
attr = nAttrs[j];
|
||||
name = attr.name;
|
||||
value = attr.value;
|
||||
value = trim(attr.value);
|
||||
|
||||
// support ngAttr attribute binding
|
||||
ngAttrName = directiveNormalize(name);
|
||||
@@ -2203,6 +2171,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
break;
|
||||
case NODE_TYPE_TEXT: /* Text Node */
|
||||
if (msie === 11) {
|
||||
// Workaround for #11781
|
||||
while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
|
||||
node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
|
||||
node.parentNode.removeChild(node.nextSibling);
|
||||
}
|
||||
}
|
||||
addTextInterpolateDirective(directives, node.nodeValue);
|
||||
break;
|
||||
case NODE_TYPE_COMMENT: /* Comment */
|
||||
@@ -2475,9 +2450,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
var slots = createMap();
|
||||
|
||||
if (!isObject(directiveValue)) {
|
||||
$template = jqLite(jqLiteClone(compileNode)).contents();
|
||||
} else {
|
||||
$template = jqLite(jqLiteClone(compileNode)).contents();
|
||||
|
||||
if (isObject(directiveValue)) {
|
||||
|
||||
// We have transclusion slots,
|
||||
// collect them up, compile them and store their transclusion functions
|
||||
@@ -3029,11 +3004,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
forEach(dst, function(value, key) {
|
||||
if (key.charAt(0) !== '$') {
|
||||
if (src[key] && src[key] !== value) {
|
||||
if (value.length) {
|
||||
value += (key === 'style' ? ';' : ' ') + src[key];
|
||||
} else {
|
||||
value = src[key];
|
||||
}
|
||||
value += (key === 'style' ? ';' : ' ') + src[key];
|
||||
}
|
||||
dst.$set(key, value, true, srcAttr[key]);
|
||||
}
|
||||
@@ -3152,10 +3123,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
childBoundTranscludeFn);
|
||||
}
|
||||
linkQueue = null;
|
||||
}).catch(function(error) {
|
||||
if (error instanceof Error) {
|
||||
$exceptionHandler(error);
|
||||
}
|
||||
});
|
||||
|
||||
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
|
||||
@@ -3256,9 +3223,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
// maction[xlink:href] can source SVG. It's not limited to <maction>.
|
||||
} else if (attrNormalizedName === 'xlinkHref' ||
|
||||
(tag === 'form' && attrNormalizedName === 'action') ||
|
||||
// links can be stylesheets or imports, which can run script in the current origin
|
||||
(tag === 'link' && attrNormalizedName === 'href')
|
||||
(tag === 'form' && attrNormalizedName === 'action')
|
||||
) {
|
||||
return $sce.RESOURCE_URL;
|
||||
}
|
||||
@@ -3281,12 +3246,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
startingTag(node));
|
||||
}
|
||||
|
||||
if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
|
||||
throw $compileMinErr('nodomevents',
|
||||
'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
|
||||
'ng- versions (such as ng-click instead of onclick) instead.');
|
||||
}
|
||||
|
||||
directives.push({
|
||||
priority: 100,
|
||||
compile: function() {
|
||||
@@ -3294,6 +3253,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
pre: function attrInterpolatePreLinkFn(scope, element, attr) {
|
||||
var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
|
||||
|
||||
if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
|
||||
throw $compileMinErr('nodomevents',
|
||||
'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
|
||||
'ng- versions (such as ng-click instead of onclick) instead.');
|
||||
}
|
||||
|
||||
// If the attribute has changed since last $interpolate()ed
|
||||
var newValue = attr[name];
|
||||
if (newValue !== value) {
|
||||
@@ -3602,16 +3567,12 @@ SimpleChange.prototype.isFirstChange = function() { return this.previousValue ==
|
||||
|
||||
|
||||
var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
|
||||
var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
|
||||
|
||||
/**
|
||||
* Converts all accepted directives format into proper directive name.
|
||||
* @param name Name to normalize
|
||||
*/
|
||||
function directiveNormalize(name) {
|
||||
return name
|
||||
.replace(PREFIX_REGEXP, '')
|
||||
.replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace);
|
||||
return camelCase(name.replace(PREFIX_REGEXP, ''));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,12 +58,13 @@ function $ControllerProvider() {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $controllerProvider#allowGlobals
|
||||
* @description If called, allows `$controller` to find controller constructors on `window`
|
||||
*
|
||||
* @deprecated
|
||||
* sinceVersion="v1.3.0"
|
||||
* removeVersion="v1.7.0"
|
||||
* This method of finding controllers has been deprecated.
|
||||
*
|
||||
* @description If called, allows `$controller` to find controller constructors on `window` *
|
||||
*/
|
||||
this.allowGlobals = function() {
|
||||
globals = true;
|
||||
@@ -84,7 +85,7 @@ function $ControllerProvider() {
|
||||
* * check if a controller with given name is registered via `$controllerProvider`
|
||||
* * check if evaluating the string on the current scope returns a constructor
|
||||
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
|
||||
* `window` object (deprecated, not recommended)
|
||||
* `window` object (not recommended)
|
||||
*
|
||||
* The string can use the `controller as property` syntax, where the controller instance is published
|
||||
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
|
||||
|
||||
@@ -159,8 +159,7 @@
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* This directive sets the `disabled` attribute on the element (typically a form control,
|
||||
* e.g. `input`, `button`, `select` etc.) if the
|
||||
* This directive sets the `disabled` attribute on the element if the
|
||||
* {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
|
||||
*
|
||||
* A special directive is necessary because we cannot use interpolation inside the `disabled`
|
||||
@@ -427,11 +426,10 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
|
||||
|
||||
attr.$set(name, value);
|
||||
|
||||
// Support: IE 9-11 only
|
||||
// On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
||||
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
||||
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
|
||||
// to set the property as well to achieve the desired effect.
|
||||
// We use attr[attrName] value since $set can sanitize the url.
|
||||
// we use attr[attrName] value since $set can sanitize the url.
|
||||
if (msie && propName) element.prop(propName, attr[name]);
|
||||
});
|
||||
}
|
||||
|
||||
+106
-218
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
/* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS
|
||||
/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
|
||||
*/
|
||||
var nullFormCtrl = {
|
||||
$addControl: noop,
|
||||
@@ -11,7 +11,6 @@ var nullFormCtrl = {
|
||||
$setPristine: noop,
|
||||
$setSubmitted: noop
|
||||
},
|
||||
PENDING_CLASS = 'ng-pending',
|
||||
SUBMITTED_CLASS = 'ng-submitted';
|
||||
|
||||
function nullFormRenameControl(control, name) {
|
||||
@@ -62,28 +61,22 @@ function nullFormRenameControl(control, name) {
|
||||
*/
|
||||
//asks for $scope to fool the BC controller module
|
||||
FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
|
||||
function FormController($element, $attrs, $scope, $animate, $interpolate) {
|
||||
this.$$controls = [];
|
||||
function FormController(element, attrs, $scope, $animate, $interpolate) {
|
||||
var form = this,
|
||||
controls = [];
|
||||
|
||||
// init state
|
||||
this.$error = {};
|
||||
this.$$success = {};
|
||||
this.$pending = undefined;
|
||||
this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope);
|
||||
this.$dirty = false;
|
||||
this.$pristine = true;
|
||||
this.$valid = true;
|
||||
this.$invalid = false;
|
||||
this.$submitted = false;
|
||||
this.$$parentForm = nullFormCtrl;
|
||||
form.$error = {};
|
||||
form.$$success = {};
|
||||
form.$pending = undefined;
|
||||
form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
|
||||
form.$dirty = false;
|
||||
form.$pristine = true;
|
||||
form.$valid = true;
|
||||
form.$invalid = false;
|
||||
form.$submitted = false;
|
||||
form.$$parentForm = nullFormCtrl;
|
||||
|
||||
this.$$element = $element;
|
||||
this.$$animate = $animate;
|
||||
|
||||
setupValidity(this);
|
||||
}
|
||||
|
||||
FormController.prototype = {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$rollbackViewValue
|
||||
@@ -95,11 +88,11 @@ FormController.prototype = {
|
||||
* event defined in `ng-model-options`. This method is typically needed by the reset button of
|
||||
* a form that uses `ng-model-options` to pend updates.
|
||||
*/
|
||||
$rollbackViewValue: function() {
|
||||
forEach(this.$$controls, function(control) {
|
||||
form.$rollbackViewValue = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$rollbackViewValue();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -112,11 +105,11 @@ FormController.prototype = {
|
||||
* event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
|
||||
* usually handles calling this in response to input events.
|
||||
*/
|
||||
$commitViewValue: function() {
|
||||
forEach(this.$$controls, function(control) {
|
||||
form.$commitViewValue = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$commitViewValue();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -139,29 +132,29 @@ FormController.prototype = {
|
||||
* For example, if an input control is added that is already `$dirty` and has `$error` properties,
|
||||
* calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
|
||||
*/
|
||||
$addControl: function(control) {
|
||||
form.$addControl = function(control) {
|
||||
// Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
|
||||
// and not added to the scope. Now we throw an error.
|
||||
assertNotHasOwnProperty(control.$name, 'input');
|
||||
this.$$controls.push(control);
|
||||
controls.push(control);
|
||||
|
||||
if (control.$name) {
|
||||
this[control.$name] = control;
|
||||
form[control.$name] = control;
|
||||
}
|
||||
|
||||
control.$$parentForm = this;
|
||||
},
|
||||
control.$$parentForm = form;
|
||||
};
|
||||
|
||||
// Private API: rename a form control
|
||||
$$renameControl: function(control, newName) {
|
||||
form.$$renameControl = function(control, newName) {
|
||||
var oldName = control.$name;
|
||||
|
||||
if (this[oldName] === control) {
|
||||
delete this[oldName];
|
||||
if (form[oldName] === control) {
|
||||
delete form[oldName];
|
||||
}
|
||||
this[newName] = control;
|
||||
form[newName] = control;
|
||||
control.$name = newName;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -179,26 +172,60 @@ FormController.prototype = {
|
||||
* different from case to case. For example, removing the only `$dirty` control from a form may or
|
||||
* may not mean that the form is still `$dirty`.
|
||||
*/
|
||||
$removeControl: function(control) {
|
||||
if (control.$name && this[control.$name] === control) {
|
||||
delete this[control.$name];
|
||||
form.$removeControl = function(control) {
|
||||
if (control.$name && form[control.$name] === control) {
|
||||
delete form[control.$name];
|
||||
}
|
||||
forEach(this.$pending, function(value, name) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.$setValidity(name, null, control);
|
||||
}, this);
|
||||
forEach(this.$error, function(value, name) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.$setValidity(name, null, control);
|
||||
}, this);
|
||||
forEach(this.$$success, function(value, name) {
|
||||
// eslint-disable-next-line no-invalid-this
|
||||
this.$setValidity(name, null, control);
|
||||
}, this);
|
||||
forEach(form.$pending, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
forEach(form.$error, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
forEach(form.$$success, function(value, name) {
|
||||
form.$setValidity(name, null, control);
|
||||
});
|
||||
|
||||
arrayRemove(this.$$controls, control);
|
||||
arrayRemove(controls, control);
|
||||
control.$$parentForm = nullFormCtrl;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$setValidity
|
||||
*
|
||||
* @description
|
||||
* Sets the validity of a form control.
|
||||
*
|
||||
* This method will also propagate to parent forms.
|
||||
*/
|
||||
addSetValidityMethod({
|
||||
ctrl: this,
|
||||
$element: element,
|
||||
set: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
object[property] = [controller];
|
||||
} else {
|
||||
var index = list.indexOf(controller);
|
||||
if (index === -1) {
|
||||
list.push(controller);
|
||||
}
|
||||
}
|
||||
},
|
||||
unset: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
arrayRemove(list, controller);
|
||||
if (list.length === 0) {
|
||||
delete object[property];
|
||||
}
|
||||
},
|
||||
$animate: $animate
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -210,13 +237,13 @@ FormController.prototype = {
|
||||
* This method can be called to add the 'ng-dirty' class and set the form to a dirty
|
||||
* state (ng-dirty class). This method will also propagate to parent forms.
|
||||
*/
|
||||
$setDirty: function() {
|
||||
this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
|
||||
this.$$animate.addClass(this.$$element, DIRTY_CLASS);
|
||||
this.$dirty = true;
|
||||
this.$pristine = false;
|
||||
this.$$parentForm.$setDirty();
|
||||
},
|
||||
form.$setDirty = function() {
|
||||
$animate.removeClass(element, PRISTINE_CLASS);
|
||||
$animate.addClass(element, DIRTY_CLASS);
|
||||
form.$dirty = true;
|
||||
form.$pristine = false;
|
||||
form.$$parentForm.$setDirty();
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -234,15 +261,15 @@ FormController.prototype = {
|
||||
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
|
||||
* saving or resetting it.
|
||||
*/
|
||||
$setPristine: function() {
|
||||
this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
|
||||
this.$dirty = false;
|
||||
this.$pristine = true;
|
||||
this.$submitted = false;
|
||||
forEach(this.$$controls, function(control) {
|
||||
form.$setPristine = function() {
|
||||
$animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
|
||||
form.$dirty = false;
|
||||
form.$pristine = true;
|
||||
form.$submitted = false;
|
||||
forEach(controls, function(control) {
|
||||
control.$setPristine();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -257,11 +284,11 @@ FormController.prototype = {
|
||||
* Setting a form controls back to their untouched state is often useful when setting the form
|
||||
* back to its pristine state.
|
||||
*/
|
||||
$setUntouched: function() {
|
||||
forEach(this.$$controls, function(control) {
|
||||
form.$setUntouched = function() {
|
||||
forEach(controls, function(control) {
|
||||
control.$setUntouched();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -270,46 +297,12 @@ FormController.prototype = {
|
||||
* @description
|
||||
* Sets the form to its submitted state.
|
||||
*/
|
||||
$setSubmitted: function() {
|
||||
this.$$animate.addClass(this.$$element, SUBMITTED_CLASS);
|
||||
this.$submitted = true;
|
||||
this.$$parentForm.$setSubmitted();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name form.FormController#$setValidity
|
||||
*
|
||||
* @description
|
||||
* Sets the validity of a form control.
|
||||
*
|
||||
* This method will also propagate to parent forms.
|
||||
*/
|
||||
addSetValidityMethod({
|
||||
clazz: FormController,
|
||||
set: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
object[property] = [controller];
|
||||
} else {
|
||||
var index = list.indexOf(controller);
|
||||
if (index === -1) {
|
||||
list.push(controller);
|
||||
}
|
||||
}
|
||||
},
|
||||
unset: function(object, property, controller) {
|
||||
var list = object[property];
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
arrayRemove(list, controller);
|
||||
if (list.length === 0) {
|
||||
delete object[property];
|
||||
}
|
||||
}
|
||||
});
|
||||
form.$setSubmitted = function() {
|
||||
$animate.addClass(element, SUBMITTED_CLASS);
|
||||
form.$submitted = true;
|
||||
form.$$parentForm.$setSubmitted();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
@@ -506,13 +499,13 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
formElement[0].addEventListener('submit', handleFormSubmission);
|
||||
addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
|
||||
|
||||
// unregister the preventDefault listener so that we don't not leak memory but in a
|
||||
// way that will achieve the prevention of the default action.
|
||||
formElement.on('$destroy', function() {
|
||||
$timeout(function() {
|
||||
formElement[0].removeEventListener('submit', handleFormSubmission);
|
||||
removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
|
||||
}, 0, false);
|
||||
});
|
||||
}
|
||||
@@ -556,108 +549,3 @@ var formDirectiveFactory = function(isNgForm) {
|
||||
|
||||
var formDirective = formDirectiveFactory();
|
||||
var ngFormDirective = formDirectiveFactory(true);
|
||||
|
||||
|
||||
|
||||
// helper methods
|
||||
function setupValidity(instance) {
|
||||
instance.$$classCache = {};
|
||||
instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS));
|
||||
}
|
||||
function addSetValidityMethod(context) {
|
||||
var clazz = context.clazz,
|
||||
set = context.set,
|
||||
unset = context.unset;
|
||||
|
||||
clazz.prototype.$setValidity = function(validationErrorKey, state, controller) {
|
||||
if (isUndefined(state)) {
|
||||
createAndSet(this, '$pending', validationErrorKey, controller);
|
||||
} else {
|
||||
unsetAndCleanup(this, '$pending', validationErrorKey, controller);
|
||||
}
|
||||
if (!isBoolean(state)) {
|
||||
unset(this.$error, validationErrorKey, controller);
|
||||
unset(this.$$success, validationErrorKey, controller);
|
||||
} else {
|
||||
if (state) {
|
||||
unset(this.$error, validationErrorKey, controller);
|
||||
set(this.$$success, validationErrorKey, controller);
|
||||
} else {
|
||||
set(this.$error, validationErrorKey, controller);
|
||||
unset(this.$$success, validationErrorKey, controller);
|
||||
}
|
||||
}
|
||||
if (this.$pending) {
|
||||
cachedToggleClass(this, PENDING_CLASS, true);
|
||||
this.$valid = this.$invalid = undefined;
|
||||
toggleValidationCss(this, '', null);
|
||||
} else {
|
||||
cachedToggleClass(this, PENDING_CLASS, false);
|
||||
this.$valid = isObjectEmpty(this.$error);
|
||||
this.$invalid = !this.$valid;
|
||||
toggleValidationCss(this, '', this.$valid);
|
||||
}
|
||||
|
||||
// re-read the state as the set/unset methods could have
|
||||
// combined state in this.$error[validationError] (used for forms),
|
||||
// where setting/unsetting only increments/decrements the value,
|
||||
// and does not replace it.
|
||||
var combinedState;
|
||||
if (this.$pending && this.$pending[validationErrorKey]) {
|
||||
combinedState = undefined;
|
||||
} else if (this.$error[validationErrorKey]) {
|
||||
combinedState = false;
|
||||
} else if (this.$$success[validationErrorKey]) {
|
||||
combinedState = true;
|
||||
} else {
|
||||
combinedState = null;
|
||||
}
|
||||
|
||||
toggleValidationCss(this, validationErrorKey, combinedState);
|
||||
this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
|
||||
};
|
||||
|
||||
function createAndSet(ctrl, name, value, controller) {
|
||||
if (!ctrl[name]) {
|
||||
ctrl[name] = {};
|
||||
}
|
||||
set(ctrl[name], value, controller);
|
||||
}
|
||||
|
||||
function unsetAndCleanup(ctrl, name, value, controller) {
|
||||
if (ctrl[name]) {
|
||||
unset(ctrl[name], value, controller);
|
||||
}
|
||||
if (isObjectEmpty(ctrl[name])) {
|
||||
ctrl[name] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function cachedToggleClass(ctrl, className, switchValue) {
|
||||
if (switchValue && !ctrl.$$classCache[className]) {
|
||||
ctrl.$$animate.addClass(ctrl.$$element, className);
|
||||
ctrl.$$classCache[className] = true;
|
||||
} else if (!switchValue && ctrl.$$classCache[className]) {
|
||||
ctrl.$$animate.removeClass(ctrl.$$element, className);
|
||||
ctrl.$$classCache[className] = false;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleValidationCss(ctrl, validationErrorKey, isValid) {
|
||||
validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
|
||||
|
||||
cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true);
|
||||
cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false);
|
||||
}
|
||||
}
|
||||
|
||||
function isObjectEmpty(obj) {
|
||||
if (obj) {
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+54
-81
@@ -679,17 +679,7 @@ var inputType = {
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
|
||||
* Can be interpolated.
|
||||
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
|
||||
* Can be interpolated.
|
||||
* @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
|
||||
* but does not trigger HTML5 native validation. Takes an expression.
|
||||
* @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
|
||||
* but does not trigger HTML5 native validation. Takes an expression.
|
||||
* @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
|
||||
* Can be interpolated.
|
||||
* @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
|
||||
* but does not trigger HTML5 native validation. Takes an expression.
|
||||
* @param {string=} required Sets `required` validation error key if the value is not entered.
|
||||
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
|
||||
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
|
||||
@@ -1044,6 +1034,28 @@ var inputType = {
|
||||
* @description
|
||||
* Native range input with validation and transformation.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* <p>
|
||||
* In v1.5.9+, in order to avoid interfering with already existing, custom directives for
|
||||
* `input[range]`, you need to let Angular know that you want to enable its built-in support.
|
||||
* You can do this by adding the `ng-input-range` attribute to the input element. E.g.:
|
||||
* `<input type="range" ng-input-range ... />`
|
||||
* </p><br />
|
||||
* <p>
|
||||
* Input elements without the `ng-input-range` attibute will continue to be treated the same
|
||||
* as in previous versions (e.g. their model value will be a string not a number and Angular
|
||||
* will not take `min`/`max`/`step` attributes and properties into account).
|
||||
* </p><br />
|
||||
* <p>
|
||||
* **Note:** From v1.6.x onwards, the support for `input[range]` will be always enabled and
|
||||
* the `ng-input-range` attribute will have no effect.
|
||||
* </p><br />
|
||||
* <p>
|
||||
* This documentation page refers to elements which have the built-in support enabled; i.e.
|
||||
* elements _with_ the `ng-input-range` attribute.
|
||||
* </p>
|
||||
* </div>
|
||||
*
|
||||
* The model for the range input must always be a `Number`.
|
||||
*
|
||||
* IE9 and other browsers that do not support the `range` type fall back
|
||||
@@ -1065,7 +1077,7 @@ var inputType = {
|
||||
*
|
||||
* Since the element value should always reflect the current model value, a range input
|
||||
* will set the bound ngModel expression to the value that the browser has set for the
|
||||
* input element. For example, in the following input `<input type="range" ng-model="model.value">`,
|
||||
* input element. For example, in the following input `<input type="range" ng-input-range ng-model="model.value">`,
|
||||
* if the application sets `model.value = null`, the browser will set the input to `'50'`.
|
||||
* Angular will then set the model to `50`, to prevent input and model value being out of sync.
|
||||
*
|
||||
@@ -1084,10 +1096,12 @@ var inputType = {
|
||||
* instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step`
|
||||
* error on the input, and set the model to `undefined`.
|
||||
*
|
||||
* Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
|
||||
* Note that `input[range]` is not compatible with `ngMax`, `ngMin`, and `ngStep`, because they do
|
||||
* not set the `min` and `max` attributes, which means that the browser won't automatically adjust
|
||||
* the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
|
||||
*
|
||||
* @param ngInputRange The presense of this attribute enables the built-in support for
|
||||
* `input[range]`.
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} min Sets the `min` validation to ensure that the value entered is greater
|
||||
@@ -1115,7 +1129,7 @@ var inputType = {
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
|
||||
Model as range: <input type="range" name="range" ng-model="value" min="{{min}}" max="{{max}}">
|
||||
Model as range: <input type="range" ng-input-range name="range" ng-model="value" min="{{min}}" max="{{max}}">
|
||||
<hr>
|
||||
Model as number: <input type="number" ng-model="value"><br>
|
||||
Min: <input type="number" ng-model="min"><br>
|
||||
@@ -1141,7 +1155,7 @@ var inputType = {
|
||||
}]);
|
||||
</script>
|
||||
<form name="myForm" ng-controller="ExampleController">
|
||||
Model as range: <input type="range" name="range" ng-model="value" ng-min="min" ng-max="max">
|
||||
Model as range: <input type="range" ng-input-range name="range" ng-model="value" ng-min="min" ng-max="max">
|
||||
<hr>
|
||||
Model as number: <input type="number" ng-model="value"><br>
|
||||
Min: <input type="number" ng-model="min"><br>
|
||||
@@ -1427,7 +1441,7 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
|
||||
badInputChecker(scope, element, attr, ctrl);
|
||||
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
||||
var timezone = ctrl && ctrl.$options.getOption('timezone');
|
||||
var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
|
||||
var previousDate;
|
||||
|
||||
ctrl.$$parserName = type;
|
||||
@@ -1565,27 +1579,15 @@ function isValidForStep(viewValue, stepBase, step) {
|
||||
// and `viewValue` is expected to be a valid stringified number.
|
||||
var value = Number(viewValue);
|
||||
|
||||
var isNonIntegerValue = !isNumberInteger(value);
|
||||
var isNonIntegerStepBase = !isNumberInteger(stepBase);
|
||||
var isNonIntegerStep = !isNumberInteger(step);
|
||||
|
||||
// Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
|
||||
// `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
|
||||
if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
|
||||
var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
|
||||
var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
|
||||
var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
|
||||
|
||||
var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
|
||||
if (!isNumberInteger(value) || !isNumberInteger(stepBase) || !isNumberInteger(step)) {
|
||||
var decimalCount = Math.max(countDecimals(value), countDecimals(stepBase), countDecimals(step));
|
||||
var multiplier = Math.pow(10, decimalCount);
|
||||
|
||||
value = value * multiplier;
|
||||
stepBase = stepBase * multiplier;
|
||||
step = step * multiplier;
|
||||
|
||||
if (isNonIntegerValue) value = Math.round(value);
|
||||
if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
|
||||
if (isNonIntegerStep) step = Math.round(step);
|
||||
}
|
||||
|
||||
return (value - stepBase) % step === 0;
|
||||
@@ -1593,8 +1595,8 @@ function isValidForStep(viewValue, stepBase, step) {
|
||||
|
||||
function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
badInputChecker(scope, element, attr, ctrl);
|
||||
numberFormatterParser(ctrl);
|
||||
baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
|
||||
numberFormatterParser(ctrl);
|
||||
|
||||
var minVal;
|
||||
var maxVal;
|
||||
@@ -1622,20 +1624,6 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
ctrl.$validate();
|
||||
});
|
||||
}
|
||||
|
||||
if (isDefined(attr.step) || attr.ngStep) {
|
||||
var stepVal;
|
||||
ctrl.$validators.step = function(modelValue, viewValue) {
|
||||
return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
|
||||
isValidForStep(viewValue, minVal || 0, stepVal);
|
||||
};
|
||||
|
||||
attr.$observe('step', function(val) {
|
||||
stepVal = parseNumberAttrVal(val);
|
||||
// TODO(matsko): implement validateLater to reduce number of validations
|
||||
ctrl.$validate();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
@@ -1799,20 +1787,14 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
|
||||
}
|
||||
|
||||
function radioInputType(scope, element, attr, ctrl) {
|
||||
var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false';
|
||||
// make the name unique, if not defined
|
||||
if (isUndefined(attr.name)) {
|
||||
element.attr('name', nextUid());
|
||||
}
|
||||
|
||||
var listener = function(ev) {
|
||||
var value;
|
||||
if (element[0].checked) {
|
||||
value = attr.value;
|
||||
if (doTrim) {
|
||||
value = trim(value);
|
||||
}
|
||||
ctrl.$setViewValue(value, ev && ev.type);
|
||||
ctrl.$setViewValue(attr.value, ev && ev.type);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1820,10 +1802,9 @@ function radioInputType(scope, element, attr, ctrl) {
|
||||
|
||||
ctrl.$render = function() {
|
||||
var value = attr.value;
|
||||
if (doTrim) {
|
||||
value = trim(value);
|
||||
}
|
||||
element[0].checked = (value === ctrl.$viewValue);
|
||||
// We generally use strict comparison. This is behavior we cannot change without a BC.
|
||||
// eslint-disable-next-line eqeqeq
|
||||
element[0].checked = (value == ctrl.$viewValue);
|
||||
};
|
||||
|
||||
attr.$observe('value', ctrl.$render);
|
||||
@@ -2068,7 +2049,11 @@ var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
|
||||
link: {
|
||||
pre: function(scope, element, attr, ctrls) {
|
||||
if (ctrls[0]) {
|
||||
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
|
||||
var type = lowercase(attr.type);
|
||||
if ((type === 'range') && !attr.hasOwnProperty('ngInputRange')) {
|
||||
type = 'text';
|
||||
}
|
||||
(inputType[type] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
|
||||
$browser, $filter, $parse);
|
||||
}
|
||||
}
|
||||
@@ -2084,19 +2069,21 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
||||
* @name ngValue
|
||||
*
|
||||
* @description
|
||||
* Binds the given expression to the value of the element.
|
||||
* Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
|
||||
* so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
|
||||
* the bound value.
|
||||
*
|
||||
* It is mainly used on {@link input[radio] `input[radio]`} and option elements,
|
||||
* so that when the element is selected, the {@link ngModel `ngModel`} of that element (or its
|
||||
* {@link select `select`} parent element) is set to the bound value. It is especially useful
|
||||
* for dynamically generated lists using {@link ngRepeat `ngRepeat`}, as shown below.
|
||||
* `ngValue` is useful when dynamically generating lists of radio buttons using
|
||||
* {@link ngRepeat `ngRepeat`}, as shown below.
|
||||
*
|
||||
* It can also be used to achieve one-way binding of a given expression to an input element
|
||||
* such as an `input[text]` or a `textarea`, when that element does not use ngModel.
|
||||
* Likewise, `ngValue` can be used to generate `<option>` elements for
|
||||
* the {@link select `select`} element. In that case however, only strings are supported
|
||||
* for the `value `attribute, so the resulting `ngModel` will always be a string.
|
||||
* Support for `select` models with non-string values is available via `ngOptions`.
|
||||
*
|
||||
* @element input
|
||||
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
|
||||
* and `value` property of the element.
|
||||
* of the `input` element
|
||||
*
|
||||
* @example
|
||||
<example name="ngValue-directive" module="valueExample">
|
||||
@@ -2135,36 +2122,22 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
|
||||
</example>
|
||||
*/
|
||||
var ngValueDirective = function() {
|
||||
/**
|
||||
* inputs use the value attribute as their default value if the value property is not set.
|
||||
* Once the value property has been set (by adding input), it will not react to changes to
|
||||
* the value attribute anymore. Setting both attribute and property fixes this behavior, and
|
||||
* makes it possible to use ngValue as a sort of one-way bind.
|
||||
*/
|
||||
function updateElementValue(element, attr, value) {
|
||||
// Support: IE9 only
|
||||
// In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
|
||||
var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
|
||||
element.prop('value', propValue);
|
||||
attr.$set('value', value);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 100,
|
||||
compile: function(tpl, tplAttr) {
|
||||
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
|
||||
return function ngValueConstantLink(scope, elm, attr) {
|
||||
var value = scope.$eval(attr.ngValue);
|
||||
updateElementValue(elm, attr, value);
|
||||
attr.$set('value', scope.$eval(attr.ngValue));
|
||||
};
|
||||
} else {
|
||||
return function ngValueLink(scope, elm, attr) {
|
||||
scope.$watch(attr.ngValue, function valueWatchAction(value) {
|
||||
updateElementValue(elm, attr, value);
|
||||
attr.$set('value', value);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ var ngBindDirective = ['$compile', function($compile) {
|
||||
$compile.$$addBindingInfo(element, attr.ngBind);
|
||||
element = element[0];
|
||||
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
|
||||
element.textContent = stringify(value);
|
||||
element.textContent = isUndefined(value) ? '' : value;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
+87
-136
@@ -8,71 +8,51 @@
|
||||
|
||||
function classDirective(name, selector) {
|
||||
name = 'ngClass' + name;
|
||||
var indexWatchExpression;
|
||||
|
||||
return ['$parse', function($parse) {
|
||||
return ['$animate', function($animate) {
|
||||
return {
|
||||
restrict: 'AC',
|
||||
link: function(scope, element, attr) {
|
||||
var expression = attr[name].trim();
|
||||
var isOneTime = (expression.charAt(0) === ':') && (expression.charAt(1) === ':');
|
||||
var oldVal;
|
||||
|
||||
var watchInterceptor = isOneTime ? toFlatValue : toClassString;
|
||||
var watchExpression = $parse(expression, watchInterceptor);
|
||||
var watchAction = isOneTime ? ngClassOneTimeWatchAction : ngClassWatchAction;
|
||||
attr.$observe('class', function(value) {
|
||||
ngClassWatchAction(scope.$eval(attr[name]));
|
||||
});
|
||||
|
||||
var classCounts = element.data('$classCounts');
|
||||
var oldModulo = true;
|
||||
var oldClassString;
|
||||
|
||||
if (!classCounts) {
|
||||
// Use createMap() to prevent class assumptions involving property
|
||||
// names in Object.prototype
|
||||
classCounts = createMap();
|
||||
element.data('$classCounts', classCounts);
|
||||
}
|
||||
|
||||
if (name !== 'ngClass') {
|
||||
if (!indexWatchExpression) {
|
||||
indexWatchExpression = $parse('$index', function moduloTwo($index) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return $index & 1;
|
||||
});
|
||||
}
|
||||
|
||||
scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
|
||||
scope.$watch('$index', function($index, old$index) {
|
||||
/* eslint-disable no-bitwise */
|
||||
var mod = $index & 1;
|
||||
if (mod !== (old$index & 1)) {
|
||||
var classes = arrayClasses(oldVal);
|
||||
if (mod === selector) {
|
||||
addClasses(classes);
|
||||
} else {
|
||||
removeClasses(classes);
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
});
|
||||
}
|
||||
|
||||
scope.$watch(watchExpression, watchAction, isOneTime);
|
||||
scope.$watch(attr[name], ngClassWatchAction, true);
|
||||
|
||||
function addClasses(classString) {
|
||||
classString = digestClassCounts(split(classString), 1);
|
||||
attr.$addClass(classString);
|
||||
function addClasses(classes) {
|
||||
var newClasses = digestClassCounts(classes, 1);
|
||||
attr.$addClass(newClasses);
|
||||
}
|
||||
|
||||
function removeClasses(classString) {
|
||||
classString = digestClassCounts(split(classString), -1);
|
||||
attr.$removeClass(classString);
|
||||
function removeClasses(classes) {
|
||||
var newClasses = digestClassCounts(classes, -1);
|
||||
attr.$removeClass(newClasses);
|
||||
}
|
||||
|
||||
function updateClasses(oldClassString, newClassString) {
|
||||
var oldClassArray = split(oldClassString);
|
||||
var newClassArray = split(newClassString);
|
||||
|
||||
var toRemoveArray = arrayDifference(oldClassArray, newClassArray);
|
||||
var toAddArray = arrayDifference(newClassArray, oldClassArray);
|
||||
|
||||
var toRemoveString = digestClassCounts(toRemoveArray, -1);
|
||||
var toAddString = digestClassCounts(toAddArray, 1);
|
||||
|
||||
attr.$addClass(toAddString);
|
||||
attr.$removeClass(toRemoveString);
|
||||
}
|
||||
|
||||
function digestClassCounts(classArray, count) {
|
||||
function digestClassCounts(classes, count) {
|
||||
// Use createMap() to prevent class assumptions involving property
|
||||
// names in Object.prototype
|
||||
var classCounts = element.data('$classCounts') || createMap();
|
||||
var classesToUpdate = [];
|
||||
|
||||
forEach(classArray, function(className) {
|
||||
forEach(classes, function(className) {
|
||||
if (count > 0 || classCounts[className]) {
|
||||
classCounts[className] = (classCounts[className] || 0) + count;
|
||||
if (classCounts[className] === +(count > 0)) {
|
||||
@@ -80,106 +60,77 @@ function classDirective(name, selector) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
element.data('$classCounts', classCounts);
|
||||
return classesToUpdate.join(' ');
|
||||
}
|
||||
|
||||
function ngClassIndexWatchAction(newModulo) {
|
||||
// This watch-action should run before the `ngClass[OneTime]WatchAction()`, thus it
|
||||
// adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
|
||||
// `ngClass[OneTime]WatchAction()` will update the classes.
|
||||
if (newModulo === selector) {
|
||||
addClasses(oldClassString);
|
||||
function updateClasses(oldClasses, newClasses) {
|
||||
var toAdd = arrayDifference(newClasses, oldClasses);
|
||||
var toRemove = arrayDifference(oldClasses, newClasses);
|
||||
toAdd = digestClassCounts(toAdd, 1);
|
||||
toRemove = digestClassCounts(toRemove, -1);
|
||||
if (toAdd && toAdd.length) {
|
||||
$animate.addClass(element, toAdd);
|
||||
}
|
||||
if (toRemove && toRemove.length) {
|
||||
$animate.removeClass(element, toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
function ngClassWatchAction(newVal) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if (selector === true || (scope.$index & 1) === selector) {
|
||||
var newClasses = arrayClasses(newVal || []);
|
||||
if (!oldVal) {
|
||||
addClasses(newClasses);
|
||||
} else if (!equals(newVal,oldVal)) {
|
||||
var oldClasses = arrayClasses(oldVal);
|
||||
updateClasses(oldClasses, newClasses);
|
||||
}
|
||||
}
|
||||
if (isArray(newVal)) {
|
||||
oldVal = newVal.map(function(v) { return shallowCopy(v); });
|
||||
} else {
|
||||
removeClasses(oldClassString);
|
||||
oldVal = shallowCopy(newVal);
|
||||
}
|
||||
|
||||
oldModulo = newModulo;
|
||||
}
|
||||
|
||||
function ngClassOneTimeWatchAction(newClassValue) {
|
||||
var newClassString = toClassString(newClassValue);
|
||||
|
||||
if (newClassString !== oldClassString) {
|
||||
ngClassWatchAction(newClassString);
|
||||
}
|
||||
}
|
||||
|
||||
function ngClassWatchAction(newClassString) {
|
||||
if (oldModulo === selector) {
|
||||
updateClasses(oldClassString, newClassString);
|
||||
}
|
||||
|
||||
oldClassString = newClassString;
|
||||
}
|
||||
}
|
||||
};
|
||||
}];
|
||||
|
||||
// Helpers
|
||||
function arrayDifference(tokens1, tokens2) {
|
||||
if (!tokens1 || !tokens1.length) return [];
|
||||
if (!tokens2 || !tokens2.length) return tokens1;
|
||||
function arrayDifference(tokens1, tokens2) {
|
||||
var values = [];
|
||||
|
||||
var values = [];
|
||||
|
||||
outer:
|
||||
for (var i = 0; i < tokens1.length; i++) {
|
||||
var token = tokens1[i];
|
||||
for (var j = 0; j < tokens2.length; j++) {
|
||||
if (token === tokens2[j]) continue outer;
|
||||
}
|
||||
values.push(token);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
function split(classString) {
|
||||
return classString && classString.split(' ');
|
||||
}
|
||||
|
||||
function toClassString(classValue) {
|
||||
var classString = classValue;
|
||||
|
||||
if (isArray(classValue)) {
|
||||
classString = classValue.map(toClassString).join(' ');
|
||||
} else if (isObject(classValue)) {
|
||||
classString = Object.keys(classValue).
|
||||
filter(function(key) { return classValue[key]; }).
|
||||
join(' ');
|
||||
}
|
||||
|
||||
return classString;
|
||||
}
|
||||
|
||||
function toFlatValue(classValue) {
|
||||
var flatValue = classValue;
|
||||
|
||||
if (isArray(classValue)) {
|
||||
flatValue = classValue.map(toFlatValue);
|
||||
} else if (isObject(classValue)) {
|
||||
var hasUndefined = false;
|
||||
|
||||
flatValue = Object.keys(classValue).filter(function(key) {
|
||||
var value = classValue[key];
|
||||
|
||||
if (!hasUndefined && isUndefined(value)) {
|
||||
hasUndefined = true;
|
||||
outer:
|
||||
for (var i = 0; i < tokens1.length; i++) {
|
||||
var token = tokens1[i];
|
||||
for (var j = 0; j < tokens2.length; j++) {
|
||||
if (token === tokens2[j]) continue outer;
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
|
||||
if (hasUndefined) {
|
||||
// Prevent the `oneTimeLiteralWatchInterceptor` from unregistering
|
||||
// the watcher, by including at least one `undefined` value.
|
||||
flatValue.push(undefined);
|
||||
values.push(token);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
return flatValue;
|
||||
}
|
||||
function arrayClasses(classVal) {
|
||||
var classes = [];
|
||||
if (isArray(classVal)) {
|
||||
forEach(classVal, function(v) {
|
||||
classes = classes.concat(arrayClasses(v));
|
||||
});
|
||||
return classes;
|
||||
} else if (isString(classVal)) {
|
||||
return classVal.split(' ');
|
||||
} else if (isObject(classVal)) {
|
||||
forEach(classVal, function(v, k) {
|
||||
if (v) {
|
||||
classes = classes.concat(k.split(' '));
|
||||
}
|
||||
});
|
||||
return classes;
|
||||
}
|
||||
return classVal;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
*
|
||||
* If the current `$controllerProvider` is configured to use globals (via
|
||||
* {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
|
||||
* also be the name of a globally accessible constructor function (deprecated, not recommended).
|
||||
* also be the name of a globally accessible constructor function (not recommended).
|
||||
*
|
||||
* @example
|
||||
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
|
||||
|
||||
@@ -53,15 +53,15 @@ forEach(
|
||||
return {
|
||||
restrict: 'A',
|
||||
compile: function($element, attr) {
|
||||
// NOTE:
|
||||
// We expose the powerful `$event` object on the scope that provides access to the Window,
|
||||
// etc. This is OK, because expressions are not sandboxed any more (and the expression
|
||||
// sandbox was never meant to be a security feature anyway).
|
||||
var fn = $parse(attr[directiveName]);
|
||||
// We expose the powerful $event object on the scope that provides access to the Window,
|
||||
// etc. that isn't protected by the fast paths in $parse. We explicitly request better
|
||||
// checks at the cost of speed since event handler expressions are not executed as
|
||||
// frequently as regular change detection.
|
||||
var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
|
||||
return function ngEventHandler(scope, element) {
|
||||
element.on(eventName, function(event) {
|
||||
var callback = function() {
|
||||
fn(scope, {$event: event});
|
||||
fn(scope, {$event:event});
|
||||
};
|
||||
if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
|
||||
scope.$evalAsync(callback);
|
||||
|
||||
@@ -91,7 +91,9 @@ var ngListDirective = function() {
|
||||
priority: 100,
|
||||
require: 'ngModel',
|
||||
link: function(scope, element, attr, ctrl) {
|
||||
var ngList = attr.ngList || ', ';
|
||||
// We want to control whitespace trimming so we use this convoluted approach
|
||||
// to access the ngList attribute, which doesn't pre-trim the attribute
|
||||
var ngList = element.attr(attr.$attr.ngList) || ', ';
|
||||
var trimValues = attr.ngTrim !== 'false';
|
||||
var separator = trimValues ? trim(ngList) : ngList;
|
||||
|
||||
|
||||
+497
-250
File diff suppressed because it is too large
Load Diff
@@ -1,366 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/* exported defaultModelOptions */
|
||||
var defaultModelOptions;
|
||||
var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
|
||||
|
||||
/**
|
||||
* @ngdoc type
|
||||
* @name ModelOptions
|
||||
* @description
|
||||
* A container for the options set by the {@link ngModelOptions} directive
|
||||
*/
|
||||
function ModelOptions(options) {
|
||||
this.$$options = options;
|
||||
}
|
||||
|
||||
ModelOptions.prototype = {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ModelOptions#getOption
|
||||
* @param {string} name the name of the option to retrieve
|
||||
* @returns {*} the value of the option
|
||||
* @description
|
||||
* Returns the value of the given option
|
||||
*/
|
||||
getOption: function(name) {
|
||||
return this.$$options[name];
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ModelOptions#createChild
|
||||
* @param {Object} options a hash of options for the new child that will override the parent's options
|
||||
* @return {ModelOptions} a new `ModelOptions` object initialized with the given options.
|
||||
*/
|
||||
createChild: function(options) {
|
||||
var inheritAll = false;
|
||||
|
||||
// make a shallow copy
|
||||
options = extend({}, options);
|
||||
|
||||
// Inherit options from the parent if specified by the value `"$inherit"`
|
||||
forEach(options, /* @this */ function(option, key) {
|
||||
if (option === '$inherit') {
|
||||
if (key === '*') {
|
||||
inheritAll = true;
|
||||
} else {
|
||||
options[key] = this.$$options[key];
|
||||
// `updateOn` is special so we must also inherit the `updateOnDefault` option
|
||||
if (key === 'updateOn') {
|
||||
options.updateOnDefault = this.$$options.updateOnDefault;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (key === 'updateOn') {
|
||||
// If the `updateOn` property contains the `default` event then we have to remove
|
||||
// it from the event list and set the `updateOnDefault` flag.
|
||||
options.updateOnDefault = false;
|
||||
options[key] = trim(option.replace(DEFAULT_REGEXP, function() {
|
||||
options.updateOnDefault = true;
|
||||
return ' ';
|
||||
}));
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (inheritAll) {
|
||||
// We have a property of the form: `"*": "$inherit"`
|
||||
delete options['*'];
|
||||
defaults(options, this.$$options);
|
||||
}
|
||||
|
||||
// Finally add in any missing defaults
|
||||
defaults(options, defaultModelOptions.$$options);
|
||||
|
||||
return new ModelOptions(options);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
defaultModelOptions = new ModelOptions({
|
||||
updateOn: '',
|
||||
updateOnDefault: true,
|
||||
debounce: 0,
|
||||
getterSetter: false,
|
||||
allowInvalid: false,
|
||||
timezone: null
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name ngModelOptions
|
||||
*
|
||||
* @description
|
||||
* This directive allows you to modify the behaviour of {@link ngModel} directives within your
|
||||
* application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel}
|
||||
* directives will use the options of their nearest `ngModelOptions` ancestor.
|
||||
*
|
||||
* The `ngModelOptions` settings are found by evaluating the value of the attribute directive as
|
||||
* an Angular expression. This expression should evaluate to an object, whose properties contain
|
||||
* the settings. For example: `<div "ng-model-options"="{ debounce: 100 }"`.
|
||||
*
|
||||
* ## Inheriting Options
|
||||
*
|
||||
* You can specify that an `ngModelOptions` setting should be inherited from a parent `ngModelOptions`
|
||||
* directive by giving it the value of `"$inherit"`.
|
||||
* Then it will inherit that setting from the first `ngModelOptions` directive found by traversing up the
|
||||
* DOM tree. If there is no ancestor element containing an `ngModelOptions` directive then default settings
|
||||
* will be used.
|
||||
*
|
||||
* For example given the following fragment of HTML
|
||||
*
|
||||
*
|
||||
* ```html
|
||||
* <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
* <form ng-model-options="{ updateOn: 'blur', allowInvalid: '$inherit' }">
|
||||
* <input ng-model-options="{ updateOn: 'default', allowInvalid: '$inherit' }" />
|
||||
* </form>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* the `input` element will have the following settings
|
||||
*
|
||||
* ```js
|
||||
* { allowInvalid: true, updateOn: 'default', debounce: 0 }
|
||||
* ```
|
||||
*
|
||||
* Notice that the `debounce` setting was not inherited and used the default value instead.
|
||||
*
|
||||
* You can specify that all undefined settings are automatically inherited from an ancestor by
|
||||
* including a property with key of `"*"` and value of `"$inherit"`.
|
||||
*
|
||||
* For example given the following fragment of HTML
|
||||
*
|
||||
*
|
||||
* ```html
|
||||
* <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
* <form ng-model-options="{ updateOn: 'blur', "*": '$inherit' }">
|
||||
* <input ng-model-options="{ updateOn: 'default', "*": '$inherit' }" />
|
||||
* </form>
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
* the `input` element will have the following settings
|
||||
*
|
||||
* ```js
|
||||
* { allowInvalid: true, updateOn: 'default', debounce: 200 }
|
||||
* ```
|
||||
*
|
||||
* Notice that the `debounce` setting now inherits the value from the outer `<div>` element.
|
||||
*
|
||||
* If you are creating a reusable component then you should be careful when using `"*": "$inherit"`
|
||||
* since you may inadvertently inherit a setting in the future that changes the behavior of your component.
|
||||
*
|
||||
*
|
||||
* ## Triggering and debouncing model updates
|
||||
*
|
||||
* The `updateOn` and `debounce` properties allow you to specify a custom list of events that will
|
||||
* trigger a model update and/or a debouncing delay so that the actual update only takes place when
|
||||
* a timer expires; this timer will be reset after another change takes place.
|
||||
*
|
||||
* Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
|
||||
* be different from the value in the actual model. This means that if you update the model you
|
||||
* should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in
|
||||
* order to make sure it is synchronized with the model and that any debounced action is canceled.
|
||||
*
|
||||
* The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue}
|
||||
* method is by making sure the input is placed inside a form that has a `name` attribute. This is
|
||||
* important because `form` controllers are published to the related scope under the name in their
|
||||
* `name` attribute.
|
||||
*
|
||||
* Any pending changes will take place immediately when an enclosing form is submitted via the
|
||||
* `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
|
||||
* to have access to the updated model.
|
||||
*
|
||||
* The following example shows how to override immediate updates. Changes on the inputs within the
|
||||
* form will update the model only when the control loses focus (blur event). If `escape` key is
|
||||
* pressed while the input field is focused, the value is reset to the value in the current model.
|
||||
*
|
||||
* <example name="ngModelOptions-directive-blur" module="optionsExample">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="userForm">
|
||||
* <label>
|
||||
* Name:
|
||||
* <input type="text" name="userName"
|
||||
* ng-model="user.name"
|
||||
* ng-model-options="{ updateOn: 'blur' }"
|
||||
* ng-keyup="cancel($event)" />
|
||||
* </label><br />
|
||||
* <label>
|
||||
* Other data:
|
||||
* <input type="text" ng-model="user.data" />
|
||||
* </label><br />
|
||||
* </form>
|
||||
* <pre>user.name = <span ng-bind="user.name"></span></pre>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="app.js">
|
||||
* angular.module('optionsExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.user = { name: 'say', data: '' };
|
||||
*
|
||||
* $scope.cancel = function(e) {
|
||||
* if (e.keyCode === 27) {
|
||||
* $scope.userForm.userName.$rollbackViewValue();
|
||||
* }
|
||||
* };
|
||||
* }]);
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
* var model = element(by.binding('user.name'));
|
||||
* var input = element(by.model('user.name'));
|
||||
* var other = element(by.model('user.data'));
|
||||
*
|
||||
* it('should allow custom events', function() {
|
||||
* input.sendKeys(' hello');
|
||||
* input.click();
|
||||
* expect(model.getText()).toEqual('say');
|
||||
* other.click();
|
||||
* expect(model.getText()).toEqual('say hello');
|
||||
* });
|
||||
*
|
||||
* it('should $rollbackViewValue when model changes', function() {
|
||||
* input.sendKeys(' hello');
|
||||
* expect(input.getAttribute('value')).toEqual('say hello');
|
||||
* input.sendKeys(protractor.Key.ESCAPE);
|
||||
* expect(input.getAttribute('value')).toEqual('say');
|
||||
* other.click();
|
||||
* expect(model.getText()).toEqual('say');
|
||||
* });
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* The next example shows how to debounce model changes. Model will be updated only 1 sec after last change.
|
||||
* If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
|
||||
*
|
||||
* <example name="ngModelOptions-directive-debounce" module="optionsExample">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="userForm">
|
||||
* Name:
|
||||
* <input type="text" name="userName"
|
||||
* ng-model="user.name"
|
||||
* ng-model-options="{ debounce: 1000 }" />
|
||||
* <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
|
||||
* </form>
|
||||
* <pre>user.name = <span ng-bind="user.name"></span></pre>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="app.js">
|
||||
* angular.module('optionsExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.user = { name: 'say' };
|
||||
* }]);
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
* ## Model updates and validation
|
||||
*
|
||||
* The default behaviour in `ngModel` is that the model value is set to `undefined` when the
|
||||
* validation determines that the value is invalid. By setting the `allowInvalid` property to true,
|
||||
* the model will still be updated even if the value is invalid.
|
||||
*
|
||||
*
|
||||
* ## Connecting to the scope
|
||||
*
|
||||
* By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression
|
||||
* on the scope refers to a "getter/setter" function rather than the value itself.
|
||||
*
|
||||
* The following example shows how to bind to getter/setters:
|
||||
*
|
||||
* <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="userForm">
|
||||
* <label>
|
||||
* Name:
|
||||
* <input type="text" name="userName"
|
||||
* ng-model="user.name"
|
||||
* ng-model-options="{ getterSetter: true }" />
|
||||
* </label>
|
||||
* </form>
|
||||
* <pre>user.name = <span ng-bind="user.name()"></span></pre>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="app.js">
|
||||
* angular.module('getterSetterExample', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* var _name = 'Brian';
|
||||
* $scope.user = {
|
||||
* name: function(newName) {
|
||||
* return angular.isDefined(newName) ? (_name = newName) : _name;
|
||||
* }
|
||||
* };
|
||||
* }]);
|
||||
* </file>
|
||||
* </example>
|
||||
*
|
||||
*
|
||||
* ## Specifying timezones
|
||||
*
|
||||
* You can specify the timezone that date/time input directives expect by providing its name in the
|
||||
* `timezone` property.
|
||||
*
|
||||
* @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and
|
||||
* and its descendents. Valid keys are:
|
||||
* - `updateOn`: string specifying which event should the input be bound to. You can set several
|
||||
* events using an space delimited list. There is a special event called `default` that
|
||||
* matches the default events belonging to the control.
|
||||
* - `debounce`: integer value which contains the debounce model update value in milliseconds. A
|
||||
* value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
|
||||
* custom value for each event. For example:
|
||||
* ```
|
||||
* ng-model-options="{
|
||||
* updateOn: 'default blur',
|
||||
* debounce: { 'default': 500, 'blur': 0 }
|
||||
* }"
|
||||
* ```
|
||||
* - `allowInvalid`: boolean value which indicates that the model can be set with values that did
|
||||
* not validate correctly instead of the default behavior of setting the model to undefined.
|
||||
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
|
||||
* `ngModel` as getters/setters.
|
||||
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
|
||||
* `<input type="date" />`, `<input type="time" />`, ... . It understands UTC/GMT and the
|
||||
* continental US time zone abbreviations, but for general use, use a time zone offset, for
|
||||
* example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
|
||||
* If not specified, the timezone of the browser will be used.
|
||||
*
|
||||
*/
|
||||
var ngModelOptionsDirective = function() {
|
||||
NgModelOptionsController.$inject = ['$attrs', '$scope'];
|
||||
function NgModelOptionsController($attrs, $scope) {
|
||||
this.$$attrs = $attrs;
|
||||
this.$$scope = $scope;
|
||||
}
|
||||
NgModelOptionsController.prototype = {
|
||||
$onInit: function() {
|
||||
var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions;
|
||||
var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions);
|
||||
|
||||
this.$options = parentOptions.createChild(modelOptionsDefinition);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
// ngModelOptions needs to run before ngModel and input directives
|
||||
priority: 10,
|
||||
require: {parentCtrl: '?^^ngModelOptions'},
|
||||
bindToController: true,
|
||||
controller: NgModelOptionsController
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// shallow copy over values from `src` that are not already specified on `dst`
|
||||
function defaults(dst, src) {
|
||||
forEach(src, function(value, key) {
|
||||
if (!isDefined(dst[key])) {
|
||||
dst[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -17,12 +17,14 @@ var ngOptionsMinErr = minErr('ngOptions');
|
||||
* elements for the `<select>` element using the array or object obtained by evaluating the
|
||||
* `ngOptions` comprehension expression.
|
||||
*
|
||||
* In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements instead of
|
||||
* `ngOptions` to achieve a similar result. However, `ngOptions` provides some benefits:
|
||||
* - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
|
||||
* comprehension expression
|
||||
* - reduced memory consumption by not creating a new scope for each repeated instance
|
||||
* - increased render speed by creating the options in a documentFragment instead of individually
|
||||
* In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements
|
||||
* instead of `ngOptions` to achieve a similar result.
|
||||
* However, `ngOptions` provides some benefits such as reducing memory and
|
||||
* increasing speed by not creating a new scope for each repeated instance, as well as providing
|
||||
* more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
|
||||
* comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
|
||||
* to a non-string value. This is because an option element can only be bound to string values at
|
||||
* present.
|
||||
*
|
||||
* When an item in the `<select>` menu is selected, the array element or object property
|
||||
* represented by the selected option will be bound to the model identified by the `ngModel`
|
||||
@@ -418,15 +420,16 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
|
||||
// The emptyOption allows the application developer to provide their own custom "empty"
|
||||
// option when the viewValue does not match any of the option values.
|
||||
var emptyOption;
|
||||
for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
|
||||
if (children[i].value === '') {
|
||||
selectCtrl.hasEmptyOption = true;
|
||||
selectCtrl.emptyOption = children.eq(i);
|
||||
emptyOption = children.eq(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var providedEmptyOption = !!selectCtrl.emptyOption;
|
||||
var providedEmptyOption = !!emptyOption;
|
||||
var emptyOptionRendered = false;
|
||||
|
||||
var unknownOption = jqLite(optionTemplate.cloneNode(false));
|
||||
unknownOption.val('?');
|
||||
@@ -438,9 +441,34 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
// we only need to create it once.
|
||||
var listFragment = $document[0].createDocumentFragment();
|
||||
|
||||
// Overwrite the implementation. ngOptions doesn't use hashes
|
||||
selectCtrl.generateUnknownOptionValue = function(val) {
|
||||
return '?';
|
||||
var renderEmptyOption = function() {
|
||||
if (!providedEmptyOption) {
|
||||
selectElement.prepend(emptyOption);
|
||||
}
|
||||
selectElement.val('');
|
||||
if (emptyOptionRendered) {
|
||||
emptyOption.prop('selected', true); // needed for IE
|
||||
emptyOption.attr('selected', true);
|
||||
}
|
||||
};
|
||||
|
||||
var removeEmptyOption = function() {
|
||||
if (!providedEmptyOption) {
|
||||
emptyOption.remove();
|
||||
} else if (emptyOptionRendered) {
|
||||
emptyOption.removeAttr('selected');
|
||||
}
|
||||
};
|
||||
|
||||
var renderUnknownOption = function() {
|
||||
selectElement.prepend(unknownOption);
|
||||
selectElement.val('?');
|
||||
unknownOption.prop('selected', true); // needed for IE
|
||||
unknownOption.attr('selected', true);
|
||||
};
|
||||
|
||||
var removeUnknownOption = function() {
|
||||
unknownOption.remove();
|
||||
};
|
||||
|
||||
// Update the controller methods for multiple selectable options
|
||||
@@ -461,8 +489,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
// set always
|
||||
|
||||
if (selectElement[0].value !== option.selectValue) {
|
||||
selectCtrl.removeUnknownOption();
|
||||
selectCtrl.unselectEmptyOption();
|
||||
removeUnknownOption();
|
||||
removeEmptyOption();
|
||||
|
||||
selectElement[0].value = option.selectValue;
|
||||
option.element.selected = true;
|
||||
@@ -470,13 +498,12 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
|
||||
option.element.setAttribute('selected', 'selected');
|
||||
} else {
|
||||
|
||||
if (providedEmptyOption) {
|
||||
selectCtrl.selectEmptyOption();
|
||||
} else if (selectCtrl.unknownOption.parent().length) {
|
||||
selectCtrl.updateUnknownOption(value);
|
||||
if (value === null || providedEmptyOption) {
|
||||
removeUnknownOption();
|
||||
renderEmptyOption();
|
||||
} else {
|
||||
selectCtrl.renderUnknownOption(value);
|
||||
removeEmptyOption();
|
||||
renderUnknownOption();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -486,8 +513,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
var selectedOption = options.selectValueMap[selectElement.val()];
|
||||
|
||||
if (selectedOption && !selectedOption.disabled) {
|
||||
selectCtrl.unselectEmptyOption();
|
||||
selectCtrl.removeUnknownOption();
|
||||
removeEmptyOption();
|
||||
removeUnknownOption();
|
||||
return options.getViewValueFromOption(selectedOption);
|
||||
}
|
||||
return null;
|
||||
@@ -505,17 +532,22 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
|
||||
} else {
|
||||
|
||||
selectCtrl.writeValue = function writeNgOptionsMultiple(values) {
|
||||
// Only set `<option>.selected` if necessary, in order to prevent some browsers from
|
||||
// scrolling to `<option>` elements that are outside the `<select>` element's viewport.
|
||||
ngModelCtrl.$isEmpty = function(value) {
|
||||
return !value || value.length === 0;
|
||||
};
|
||||
|
||||
var selectedOptions = values && values.map(getAndUpdateSelectedOption) || [];
|
||||
|
||||
selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
|
||||
options.items.forEach(function(option) {
|
||||
if (option.element.selected && !includes(selectedOptions, option)) {
|
||||
option.element.selected = false;
|
||||
}
|
||||
option.element.selected = false;
|
||||
});
|
||||
|
||||
if (value) {
|
||||
value.forEach(function(item) {
|
||||
var option = options.getOptionFromViewValue(item);
|
||||
if (option) option.element.selected = true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -548,44 +580,47 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (providedEmptyOption) {
|
||||
|
||||
// we need to remove it before calling selectElement.empty() because otherwise IE will
|
||||
// remove the label from the element. wtf?
|
||||
selectCtrl.emptyOption.remove();
|
||||
emptyOption.remove();
|
||||
|
||||
// compile the element since there might be bindings in it
|
||||
$compile(selectCtrl.emptyOption)(scope);
|
||||
$compile(emptyOption)(scope);
|
||||
|
||||
if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
|
||||
if (emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
|
||||
// This means the empty option has currently no actual DOM node, probably because
|
||||
// it has been modified by a transclusion directive.
|
||||
selectCtrl.hasEmptyOption = false;
|
||||
|
||||
emptyOptionRendered = false;
|
||||
|
||||
// Redefine the registerOption function, which will catch
|
||||
// options that are added by ngIf etc. (rendering of the node is async because of
|
||||
// lazy transclusion)
|
||||
selectCtrl.registerOption = function(optionScope, optionEl) {
|
||||
if (optionEl.val() === '') {
|
||||
selectCtrl.hasEmptyOption = true;
|
||||
selectCtrl.emptyOption = optionEl;
|
||||
selectCtrl.emptyOption.removeClass('ng-scope');
|
||||
emptyOptionRendered = true;
|
||||
emptyOption = optionEl;
|
||||
emptyOption.removeClass('ng-scope');
|
||||
// This ensures the new empty option is selected if previously no option was selected
|
||||
ngModelCtrl.$render();
|
||||
|
||||
optionEl.on('$destroy', function() {
|
||||
selectCtrl.hasEmptyOption = false;
|
||||
selectCtrl.emptyOption = undefined;
|
||||
emptyOption = undefined;
|
||||
emptyOptionRendered = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} else {
|
||||
// remove the class, which is added automatically because we recompile the element and it
|
||||
// becomes the compilation root
|
||||
selectCtrl.emptyOption.removeClass('ng-scope');
|
||||
emptyOption.removeClass('ng-scope');
|
||||
emptyOptionRendered = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
emptyOption = jqLite(optionTemplate.cloneNode(false));
|
||||
}
|
||||
|
||||
selectElement.empty();
|
||||
@@ -605,14 +640,6 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
updateOptionElement(option, optionElement);
|
||||
}
|
||||
|
||||
function getAndUpdateSelectedOption(viewValue) {
|
||||
var option = options.getOptionFromViewValue(viewValue);
|
||||
var element = option && option.element;
|
||||
|
||||
if (element && !element.selected) element.selected = true;
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
function updateOptionElement(option, element) {
|
||||
option.element = element;
|
||||
@@ -655,7 +682,7 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile,
|
||||
|
||||
// Ensure that the empty option is always there if it was explicitly provided
|
||||
if (providedEmptyOption) {
|
||||
selectElement.prepend(selectCtrl.emptyOption);
|
||||
selectElement.prepend(emptyOption);
|
||||
}
|
||||
|
||||
options.items.forEach(function addOption(option) {
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
*
|
||||
* If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
|
||||
* content of this element will be removed before the transcluded content is inserted.
|
||||
* If the transcluded content is empty (or only whitespace), the existing content is left intact. This lets you provide fallback
|
||||
* content in the case that no transcluded content is provided.
|
||||
* If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
|
||||
* that no transcluded content is provided.
|
||||
*
|
||||
* @element ANY
|
||||
*
|
||||
@@ -47,7 +47,7 @@
|
||||
* <div ng-controller="ExampleController">
|
||||
* <input ng-model="title" aria-label="title"> <br/>
|
||||
* <textarea ng-model="text" aria-label="text"></textarea> <br/>
|
||||
* <pane title="{{title}}"><span>{{text}}</span></pane>
|
||||
* <pane title="{{title}}">{{text}}</pane>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="protractor.js" type="protractor">
|
||||
@@ -195,7 +195,7 @@ var ngTranscludeDirective = ['$compile', function($compile) {
|
||||
}
|
||||
|
||||
function ngTranscludeCloneAttachFn(clone, transcludedScope) {
|
||||
if (clone.length && notWhitespace(clone)) {
|
||||
if (clone.length) {
|
||||
$element.append(clone);
|
||||
} else {
|
||||
useFallbackContent();
|
||||
@@ -212,15 +212,6 @@ var ngTranscludeDirective = ['$compile', function($compile) {
|
||||
$element.append(clone);
|
||||
});
|
||||
}
|
||||
|
||||
function notWhitespace(nodes) {
|
||||
for (var i = 0, ii = nodes.length; i < ii; i++) {
|
||||
var node = nodes[i];
|
||||
if (node.nodeType !== NODE_TYPE_TEXT || node.nodeValue.trim()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
+66
-265
@@ -4,6 +4,15 @@
|
||||
|
||||
var noopNgModelController = { $setViewValue: noop, $render: noop };
|
||||
|
||||
function chromeHack(optionElement) {
|
||||
// Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
|
||||
// Adding an <option selected="selected"> element to a <select required="required"> should
|
||||
// automatically select the new element
|
||||
if (optionElement[0].hasAttribute('selected')) {
|
||||
optionElement[0].selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc type
|
||||
* @name select.SelectController
|
||||
@@ -16,13 +25,10 @@ var SelectController =
|
||||
['$element', '$scope', /** @this */ function($element, $scope) {
|
||||
|
||||
var self = this,
|
||||
optionsMap = new NgMap();
|
||||
|
||||
self.selectValueMap = {}; // Keys are the hashed values, values the original values
|
||||
optionsMap = new HashMap();
|
||||
|
||||
// If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
|
||||
self.ngModelCtrl = noopNgModelController;
|
||||
self.multiple = false;
|
||||
|
||||
// The "unknown" option is one that is prepended to the list if the viewValue
|
||||
// does not match any of the options. When it is rendered the value of the unknown
|
||||
@@ -31,94 +37,42 @@ var SelectController =
|
||||
// We can't just jqLite('<option>') since jqLite is not smart enough
|
||||
// to create it in <select> and IE barfs otherwise.
|
||||
self.unknownOption = jqLite(window.document.createElement('option'));
|
||||
|
||||
// The empty option is an option with the value '' that te application developer can
|
||||
// provide inside the select. When the model changes to a value that doesn't match an option,
|
||||
// it is selected - so if an empty option is provided, no unknown option is generated.
|
||||
// However, the empty option is not removed when the model matches an option. It is always selectable
|
||||
// and indicates that a "null" selection has been made.
|
||||
self.hasEmptyOption = false;
|
||||
self.emptyOption = undefined;
|
||||
|
||||
self.renderUnknownOption = function(val) {
|
||||
var unknownVal = self.generateUnknownOptionValue(val);
|
||||
var unknownVal = '? ' + hashKey(val) + ' ?';
|
||||
self.unknownOption.val(unknownVal);
|
||||
$element.prepend(self.unknownOption);
|
||||
setOptionAsSelected(self.unknownOption);
|
||||
$element.val(unknownVal);
|
||||
};
|
||||
|
||||
self.updateUnknownOption = function(val) {
|
||||
var unknownVal = self.generateUnknownOptionValue(val);
|
||||
self.unknownOption.val(unknownVal);
|
||||
setOptionAsSelected(self.unknownOption);
|
||||
$element.val(unknownVal);
|
||||
};
|
||||
|
||||
self.generateUnknownOptionValue = function(val) {
|
||||
return '? ' + hashKey(val) + ' ?';
|
||||
};
|
||||
|
||||
self.removeUnknownOption = function() {
|
||||
if (self.unknownOption.parent()) self.unknownOption.remove();
|
||||
};
|
||||
|
||||
self.selectEmptyOption = function() {
|
||||
if (self.emptyOption) {
|
||||
$element.val('');
|
||||
setOptionAsSelected(self.emptyOption);
|
||||
}
|
||||
};
|
||||
|
||||
self.unselectEmptyOption = function() {
|
||||
if (self.hasEmptyOption) {
|
||||
self.emptyOption.removeAttr('selected');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
// disable unknown option so that we don't do work when the whole select is being destroyed
|
||||
self.renderUnknownOption = noop;
|
||||
});
|
||||
|
||||
self.removeUnknownOption = function() {
|
||||
if (self.unknownOption.parent()) self.unknownOption.remove();
|
||||
};
|
||||
|
||||
|
||||
// Read the value of the select control, the implementation of this changes depending
|
||||
// upon whether the select can have multiple values and whether ngOptions is at work.
|
||||
self.readValue = function readSingleValue() {
|
||||
var val = $element.val();
|
||||
// ngValue added option values are stored in the selectValueMap, normal interpolations are not
|
||||
var realVal = val in self.selectValueMap ? self.selectValueMap[val] : val;
|
||||
|
||||
if (self.hasOption(realVal)) {
|
||||
return realVal;
|
||||
}
|
||||
|
||||
return null;
|
||||
self.removeUnknownOption();
|
||||
return $element.val();
|
||||
};
|
||||
|
||||
|
||||
// Write the value to the select control, the implementation of this changes depending
|
||||
// upon whether the select can have multiple values and whether ngOptions is at work.
|
||||
self.writeValue = function writeSingleValue(value) {
|
||||
// Make sure to remove the selected attribute from the previously selected option
|
||||
// Otherwise, screen readers might get confused
|
||||
var currentlySelectedOption = $element[0].options[$element[0].selectedIndex];
|
||||
if (currentlySelectedOption) currentlySelectedOption.removeAttribute('selected');
|
||||
|
||||
if (self.hasOption(value)) {
|
||||
self.removeUnknownOption();
|
||||
|
||||
var hashedVal = hashKey(value);
|
||||
$element.val(hashedVal in self.selectValueMap ? hashedVal : value);
|
||||
|
||||
// Set selected attribute and property on selected option for screen readers
|
||||
var selectedOption = $element[0].options[$element[0].selectedIndex];
|
||||
setOptionAsSelected(jqLite(selectedOption));
|
||||
$element.val(value);
|
||||
if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
|
||||
} else {
|
||||
if (value == null && self.emptyOption) {
|
||||
self.removeUnknownOption();
|
||||
self.selectEmptyOption();
|
||||
} else if (self.unknownOption.parent().length) {
|
||||
self.updateUnknownOption(value);
|
||||
$element.val('');
|
||||
} else {
|
||||
self.renderUnknownOption(value);
|
||||
}
|
||||
@@ -133,14 +87,12 @@ var SelectController =
|
||||
|
||||
assertNotHasOwnProperty(value, '"option value"');
|
||||
if (value === '') {
|
||||
self.hasEmptyOption = true;
|
||||
self.emptyOption = element;
|
||||
}
|
||||
var count = optionsMap.get(value) || 0;
|
||||
optionsMap.set(value, count + 1);
|
||||
// Only render at the end of a digest. This improves render performance when many options
|
||||
// are added during a digest and ensures all relevant options are correctly marked as selected
|
||||
scheduleRender();
|
||||
optionsMap.put(value, count + 1);
|
||||
self.ngModelCtrl.$render();
|
||||
chromeHack(element);
|
||||
};
|
||||
|
||||
// Tell the select control that an option, with the given value, has been removed
|
||||
@@ -148,13 +100,12 @@ var SelectController =
|
||||
var count = optionsMap.get(value);
|
||||
if (count) {
|
||||
if (count === 1) {
|
||||
optionsMap.delete(value);
|
||||
optionsMap.remove(value);
|
||||
if (value === '') {
|
||||
self.hasEmptyOption = false;
|
||||
self.emptyOption = undefined;
|
||||
}
|
||||
} else {
|
||||
optionsMap.set(value, count - 1);
|
||||
optionsMap.put(value, count - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -165,138 +116,37 @@ var SelectController =
|
||||
};
|
||||
|
||||
|
||||
var renderScheduled = false;
|
||||
function scheduleRender() {
|
||||
if (renderScheduled) return;
|
||||
renderScheduled = true;
|
||||
$scope.$$postDigest(function() {
|
||||
renderScheduled = false;
|
||||
self.ngModelCtrl.$render();
|
||||
});
|
||||
}
|
||||
self.registerOption = function(optionScope, optionElement, optionAttrs, hasDynamicValueAttr, interpolateTextFn) {
|
||||
|
||||
var updateScheduled = false;
|
||||
function scheduleViewValueUpdate(renderAfter) {
|
||||
if (updateScheduled) return;
|
||||
|
||||
updateScheduled = true;
|
||||
|
||||
$scope.$$postDigest(function() {
|
||||
if ($scope.$$destroyed) return;
|
||||
|
||||
updateScheduled = false;
|
||||
self.ngModelCtrl.$setViewValue(self.readValue());
|
||||
if (renderAfter) self.ngModelCtrl.$render();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
|
||||
|
||||
if (optionAttrs.$attr.ngValue) {
|
||||
// The value attribute is set by ngValue
|
||||
var oldVal, hashedVal = NaN;
|
||||
if (hasDynamicValueAttr) {
|
||||
// either "value" is interpolated directly, or set by ngValue
|
||||
var oldVal;
|
||||
optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
|
||||
|
||||
var removal;
|
||||
var previouslySelected = optionElement.prop('selected');
|
||||
|
||||
if (isDefined(hashedVal)) {
|
||||
self.removeOption(oldVal);
|
||||
delete self.selectValueMap[hashedVal];
|
||||
removal = true;
|
||||
}
|
||||
|
||||
hashedVal = hashKey(newVal);
|
||||
oldVal = newVal;
|
||||
self.selectValueMap[hashedVal] = newVal;
|
||||
self.addOption(newVal, optionElement);
|
||||
// Set the attribute directly instead of using optionAttrs.$set - this stops the observer
|
||||
// from firing a second time. Other $observers on value will also get the result of the
|
||||
// ngValue expression, not the hashed value
|
||||
optionElement.attr('value', hashedVal);
|
||||
|
||||
if (removal && previouslySelected) {
|
||||
scheduleViewValueUpdate();
|
||||
}
|
||||
|
||||
});
|
||||
} else if (interpolateValueFn) {
|
||||
// The value attribute is interpolated
|
||||
optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
|
||||
// This method is overwritten in ngOptions and has side-effects!
|
||||
self.readValue();
|
||||
|
||||
var removal;
|
||||
var previouslySelected = optionElement.prop('selected');
|
||||
|
||||
if (isDefined(oldVal)) {
|
||||
self.removeOption(oldVal);
|
||||
removal = true;
|
||||
}
|
||||
oldVal = newVal;
|
||||
self.addOption(newVal, optionElement);
|
||||
|
||||
if (removal && previouslySelected) {
|
||||
scheduleViewValueUpdate();
|
||||
}
|
||||
});
|
||||
} else if (interpolateTextFn) {
|
||||
// The text content is interpolated
|
||||
optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
|
||||
optionAttrs.$set('value', newVal);
|
||||
var previouslySelected = optionElement.prop('selected');
|
||||
if (oldVal !== newVal) {
|
||||
self.removeOption(oldVal);
|
||||
}
|
||||
self.addOption(newVal, optionElement);
|
||||
|
||||
if (oldVal && previouslySelected) {
|
||||
scheduleViewValueUpdate();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// The value attribute is static
|
||||
self.addOption(optionAttrs.value, optionElement);
|
||||
}
|
||||
|
||||
|
||||
optionAttrs.$observe('disabled', function(newVal) {
|
||||
|
||||
// Since model updates will also select disabled options (like ngOptions),
|
||||
// we only have to handle options becoming disabled, not enabled
|
||||
|
||||
if (newVal === 'true' || newVal && optionElement.prop('selected')) {
|
||||
if (self.multiple) {
|
||||
scheduleViewValueUpdate(true);
|
||||
} else {
|
||||
self.ngModelCtrl.$setViewValue(null);
|
||||
self.ngModelCtrl.$render();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
optionElement.on('$destroy', function() {
|
||||
var currentValue = self.readValue();
|
||||
var removeValue = optionAttrs.value;
|
||||
|
||||
self.removeOption(removeValue);
|
||||
scheduleRender();
|
||||
|
||||
if (self.multiple && currentValue && currentValue.indexOf(removeValue) !== -1 ||
|
||||
currentValue === removeValue
|
||||
) {
|
||||
// When multiple (selected) options are destroyed at the same time, we don't want
|
||||
// to run a model update for each of them. Instead, run a single update in the $$postDigest
|
||||
scheduleViewValueUpdate(true);
|
||||
}
|
||||
self.removeOption(optionAttrs.value);
|
||||
self.ngModelCtrl.$render();
|
||||
});
|
||||
};
|
||||
|
||||
function setOptionAsSelected(optionEl) {
|
||||
optionEl.prop('selected', true); // needed for IE
|
||||
optionEl.attr('selected', true);
|
||||
}
|
||||
}];
|
||||
|
||||
/**
|
||||
@@ -305,7 +155,7 @@ var SelectController =
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* HTML `select` element with angular data-binding.
|
||||
* HTML `SELECT` element with angular data-binding.
|
||||
*
|
||||
* The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
|
||||
* between the scope and the `<select>` control (including setting default values).
|
||||
@@ -315,24 +165,16 @@ var SelectController =
|
||||
* When an item in the `<select>` menu is selected, the value of the selected option will be bound
|
||||
* to the model identified by the `ngModel` directive. With static or repeated options, this is
|
||||
* the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
|
||||
* Value and textContent can be interpolated.
|
||||
* For dynamic options, use interpolation inside the `value` attribute or the `textContent`. Using
|
||||
* {@link ngValue ngValue} is also possible (as it sets the `value` attribute), and will take
|
||||
* precedence over `value` and `textContent`.
|
||||
*
|
||||
* ## Matching model and option values
|
||||
*
|
||||
* In general, the match between the model and an option is evaluated by strictly comparing the model
|
||||
* value against the value of the available options.
|
||||
*
|
||||
* If you are setting the option value with the option's `value` attribute, or textContent, the
|
||||
* value will always be a `string` which means that the model value must also be a string.
|
||||
* Otherwise the `select` directive cannot match them correctly.
|
||||
*
|
||||
* To bind the model to a non-string value, you can use one of the following strategies:
|
||||
* - the {@link ng.ngOptions `ngOptions`} directive
|
||||
* ({@link ng.select#using-select-with-ngoptions-and-setting-a-default-value})
|
||||
* - the {@link ng.ngValue `ngValue`} directive, which allows arbitrary expressions to be
|
||||
* option values ({@link ng.select#using-ngvalue-to-bind-the-model-to-an-array-of-objects Example})
|
||||
* - model $parsers / $formatters to convert the string value
|
||||
* ({@link ng.select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting Example})
|
||||
* <div class="alert alert-warning">
|
||||
* Note that the value of a `select` directive used without `ngOptions` is always a string.
|
||||
* When the model needs to be bound to a non-string value, you must either explicitly convert it
|
||||
* using a directive (see example below) or use `ngOptions` to specify the set of options.
|
||||
* This is because an option element can only be bound to string values at present.
|
||||
* </div>
|
||||
*
|
||||
* If the viewValue of `ngModel` does not match any of the options, then the control
|
||||
* will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
|
||||
@@ -341,17 +183,13 @@ var SelectController =
|
||||
* be nested into the `<select>` element. This element will then represent the `null` or "not selected"
|
||||
* option. See example below for demonstration.
|
||||
*
|
||||
* ## Choosing between `ngRepeat` and `ngOptions`
|
||||
*
|
||||
* <div class="alert alert-info">
|
||||
* In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
|
||||
* ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits:
|
||||
* - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
|
||||
* comprehension expression
|
||||
* - reduced memory consumption by not creating a new scope for each repeated instance
|
||||
* - increased render speed by creating the options in a documentFragment instead of individually
|
||||
*
|
||||
* Specifically, select with repeated options slows down significantly starting at 2000 options in
|
||||
* Chrome and Internet Explorer / Edge.
|
||||
* ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
|
||||
* more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
|
||||
* comprehension expression, and additionally in reducing memory and increasing speed by not creating
|
||||
* a new scope for each repeated instance.
|
||||
* </div>
|
||||
*
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
@@ -417,24 +255,24 @@ var SelectController =
|
||||
*</example>
|
||||
*
|
||||
* ### Using `ngRepeat` to generate `select` options
|
||||
* <example name="select-ngrepeat" module="ngrepeatSelect">
|
||||
* <example name="ngrepeat-select" module="ngrepeatSelect">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="myForm">
|
||||
* <label for="repeatSelect"> Repeat select: </label>
|
||||
* <select name="repeatSelect" id="repeatSelect" ng-model="data.model">
|
||||
* <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
|
||||
* <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
|
||||
* </select>
|
||||
* </form>
|
||||
* <hr>
|
||||
* <tt>model = {{data.model}}</tt><br/>
|
||||
* <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="app.js">
|
||||
* angular.module('ngrepeatSelect', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.data = {
|
||||
* model: null,
|
||||
* repeatSelect: null,
|
||||
* availableOptions: [
|
||||
* {id: '1', name: 'Option A'},
|
||||
* {id: '2', name: 'Option B'},
|
||||
@@ -445,37 +283,6 @@ var SelectController =
|
||||
* </file>
|
||||
*</example>
|
||||
*
|
||||
* ### Using `ngValue` to bind the model to an array of objects
|
||||
* <example name="select-ngvalue" module="ngvalueSelect">
|
||||
* <file name="index.html">
|
||||
* <div ng-controller="ExampleController">
|
||||
* <form name="myForm">
|
||||
* <label for="ngvalueselect"> ngvalue select: </label>
|
||||
* <select size="6" name="ngvalueselect" ng-model="data.model" multiple>
|
||||
* <option ng-repeat="option in data.availableOptions" ng-value="option.value">{{option.name}}</option>
|
||||
* </select>
|
||||
* </form>
|
||||
* <hr>
|
||||
* <pre>model = {{data.model | json}}</pre><br/>
|
||||
* </div>
|
||||
* </file>
|
||||
* <file name="app.js">
|
||||
* angular.module('ngvalueSelect', [])
|
||||
* .controller('ExampleController', ['$scope', function($scope) {
|
||||
* $scope.data = {
|
||||
* model: null,
|
||||
* availableOptions: [
|
||||
{value: 'myString', name: 'string'},
|
||||
{value: 1, name: 'integer'},
|
||||
{value: true, name: 'boolean'},
|
||||
{value: null, name: 'null'},
|
||||
{value: {prop: 'value'}, name: 'object'},
|
||||
{value: ['a'], name: 'array'}
|
||||
* ]
|
||||
* };
|
||||
* }]);
|
||||
* </file>
|
||||
*</example>
|
||||
*
|
||||
* ### Using `select` with `ngOptions` and setting a default value
|
||||
* See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
|
||||
@@ -562,16 +369,11 @@ var selectDirective = function() {
|
||||
|
||||
function selectPreLink(scope, element, attr, ctrls) {
|
||||
|
||||
var selectCtrl = ctrls[0];
|
||||
// if ngModel is not defined, we don't need to do anything
|
||||
var ngModelCtrl = ctrls[1];
|
||||
if (!ngModelCtrl) return;
|
||||
|
||||
// if ngModel is not defined, we don't need to do anything but set the registerOption
|
||||
// function to noop, so options don't get added internally
|
||||
if (!ngModelCtrl) {
|
||||
selectCtrl.registerOption = noop;
|
||||
return;
|
||||
}
|
||||
|
||||
var selectCtrl = ctrls[0];
|
||||
|
||||
selectCtrl.ngModelCtrl = ngModelCtrl;
|
||||
|
||||
@@ -579,7 +381,6 @@ var selectDirective = function() {
|
||||
// to the `readValue` method, which can be changed if the select can have multiple
|
||||
// selected values or if the options are being generated by `ngOptions`
|
||||
element.on('change', function() {
|
||||
selectCtrl.removeUnknownOption();
|
||||
scope.$apply(function() {
|
||||
ngModelCtrl.$setViewValue(selectCtrl.readValue());
|
||||
});
|
||||
@@ -590,15 +391,13 @@ var selectDirective = function() {
|
||||
// we have to add an extra watch since ngModel doesn't work well with arrays - it
|
||||
// doesn't trigger rendering if only an item in the array changes.
|
||||
if (attr.multiple) {
|
||||
selectCtrl.multiple = true;
|
||||
|
||||
// Read value now needs to check each option to see if it is selected
|
||||
selectCtrl.readValue = function readMultipleValue() {
|
||||
var array = [];
|
||||
forEach(element.find('option'), function(option) {
|
||||
if (option.selected && !option.disabled) {
|
||||
var val = option.value;
|
||||
array.push(val in selectCtrl.selectValueMap ? selectCtrl.selectValueMap[val] : val);
|
||||
if (option.selected) {
|
||||
array.push(option.value);
|
||||
}
|
||||
});
|
||||
return array;
|
||||
@@ -606,9 +405,9 @@ var selectDirective = function() {
|
||||
|
||||
// Write value now needs to set the selected property of each matching option
|
||||
selectCtrl.writeValue = function writeMultipleValue(value) {
|
||||
var items = new HashMap(value);
|
||||
forEach(element.find('option'), function(option) {
|
||||
option.selected = !!value && (includes(value, option.value) ||
|
||||
includes(value, selectCtrl.selectValueMap[option.value]));
|
||||
option.selected = isDefined(items.get(option.value));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -659,13 +458,15 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
||||
restrict: 'E',
|
||||
priority: 100,
|
||||
compile: function(element, attr) {
|
||||
var interpolateValueFn, interpolateTextFn;
|
||||
var hasDynamicValueAttr, interpolateTextFn;
|
||||
|
||||
if (isDefined(attr.ngValue)) {
|
||||
// Will be handled by registerOption
|
||||
// If ngValue is defined, then the value attr will be set to the result of the expression,
|
||||
// and the selectCtrl must set up an observer
|
||||
hasDynamicValueAttr = true;
|
||||
} else if (isDefined(attr.value)) {
|
||||
// If the value attribute is defined, check if it contains an interpolation
|
||||
interpolateValueFn = $interpolate(attr.value, true);
|
||||
// If the value attr contains an interpolation, the selectCtrl must set up an observer
|
||||
hasDynamicValueAttr = $interpolate(attr.value, true);
|
||||
} else {
|
||||
// If the value attribute is not defined then we fall back to the
|
||||
// text content of the option element, which may be interpolated
|
||||
@@ -684,7 +485,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
||||
parent.parent().data(selectCtrlName); // in case we are in optgroup
|
||||
|
||||
if (selectCtrl) {
|
||||
selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
|
||||
selectCtrl.registerOption(scope, element, attr, hasDynamicValueAttr, interpolateTextFn);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user