Compare commits
464 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56817e9faa | |||
| e87fb8a8e1 | |||
| 5be0fc40ed | |||
| a98337b359 | |||
| 143d016899 | |||
| 3d70e55d72 | |||
| dbcc44dc80 | |||
| db87fd52ca | |||
| 792509e987 | |||
| 166e0d63d0 | |||
| 0d7f19bb62 | |||
| 607045d592 | |||
| 51d32243fe | |||
| 1c1a1bc9ed | |||
| 553fdb318f | |||
| 607ed4ee46 | |||
| ec1cece270 | |||
| 4656e386fb | |||
| f29f2f99b1 | |||
| cc27f08588 | |||
| 99fe398b59 | |||
| cb89e02432 | |||
| ac69392cd7 | |||
| a5fb372e1e | |||
| da720712f3 | |||
| 0cb3dc8782 | |||
| dfd95f0115 | |||
| 7636670a77 | |||
| fe6247a7f8 | |||
| 2b90ef1694 | |||
| 099138fb9a | |||
| cbe31d8dfd | |||
| 06b0930b6a | |||
| 7b7be341b6 | |||
| 751c77f87b | |||
| 634ac03c5e | |||
| 8cab53c64d | |||
| edef295b11 | |||
| 64e447354e | |||
| da1f7c762d | |||
| 89366bdbf9 | |||
| 78efa0e36c | |||
| 3a8b3db174 | |||
| 1a01e80b9c | |||
| d59027c40e | |||
| c197c2aa27 | |||
| 01cd34957e | |||
| 864517e5a2 | |||
| 1dd5d2ec1f | |||
| 6da835f4bc | |||
| 5cca077e4a | |||
| e290aa8c13 | |||
| 9c51d50318 | |||
| 1c3a46adda | |||
| 4407e81c61 | |||
| ad76e77fce | |||
| ac5b9055f6 | |||
| c18074a310 | |||
| ed703d8e2c | |||
| 9c53d0769e | |||
| 90532f5e3c | |||
| 2bc04d23fb | |||
| 7f6da764e1 | |||
| 6926ef8f67 | |||
| bba2b7cfce | |||
| dc1e55ce1a | |||
| 408e868237 | |||
| 97abb12473 | |||
| d26bffbc3f | |||
| 2f3bd9dae7 | |||
| 256e5dff55 | |||
| acb6b75fe9 | |||
| 683fd713c4 | |||
| 3591ae0103 | |||
| 5fedfd79a5 | |||
| bdde40e755 | |||
| 88c4963328 | |||
| 67a81eff42 | |||
| add43e91dc | |||
| b3c7a6d566 | |||
| 424bd49ede | |||
| 6a58404507 | |||
| d4ce8362b1 | |||
| caa12dbc57 | |||
| 1122b3c14d | |||
| a357649da5 | |||
| 332a3c7984 | |||
| fcd761b9d7 | |||
| b0d5f062e3 | |||
| 2c0753225a | |||
| 3b898664ee | |||
| 61fb5863df | |||
| a4ec297925 | |||
| 93d7e60d43 | |||
| 338264b5f6 | |||
| 19b51caa2c | |||
| 8c08b4373c | |||
| 0b38882a91 | |||
| 3364d69a3b | |||
| e6c9bfa4a9 | |||
| 7a3e182e9c | |||
| 2471f6b01c | |||
| 1fefafd09f | |||
| 8a63dc3151 | |||
| 403008816c | |||
| 62d552ffe2 | |||
| bcaa4217bc | |||
| 0823f6dfab | |||
| 87bb554aec | |||
| 36447cb2b5 | |||
| 3b2c6f09cb | |||
| 63414b9653 | |||
| 5f24bb0267 | |||
| 52519d45b9 | |||
| 78728df099 | |||
| 732db27cd6 | |||
| 3cad63fbd8 | |||
| d2be5939dc | |||
| 9a77d03047 | |||
| 8efcec67cc | |||
| 4fbd4bbd8d | |||
| 2fae296cbc | |||
| cef8466419 | |||
| 083159ebbe | |||
| 32e440cffc | |||
| 89c8c93b9a | |||
| 296074f548 | |||
| 2ccfaffa74 | |||
| 192672a162 | |||
| 7f4e658d3d | |||
| ff57695855 | |||
| ae8deb1246 | |||
| b9dcb35e9b | |||
| 25d9f5a804 | |||
| 1b234cb7af | |||
| d219442945 | |||
| 2b33be47cb | |||
| 499baced12 | |||
| 7aa9fecab8 | |||
| 9b6c82d804 | |||
| c3117b7544 | |||
| 67744384e8 | |||
| 17c401d09a | |||
| 488aea15f4 | |||
| 43df853ee3 | |||
| 28d5dcb578 | |||
| 7eb15c46a2 | |||
| 1fac36e2cb | |||
| 4b6c87b6e7 | |||
| ce6c2b2072 | |||
| 3e94a2c54d | |||
| b1e488f5d7 | |||
| 03d867160f | |||
| 9870e65c5f | |||
| aa839b9ff0 | |||
| fdb66aa237 | |||
| e0ca5fdd51 | |||
| 681c1c53e4 | |||
| 631c4863d8 | |||
| 944bda12c7 | |||
| bc36c4dea4 | |||
| 722766958b | |||
| 73fd3ca2eb | |||
| efe8ad51ed | |||
| d5b62465f0 | |||
| bc76e7255b | |||
| 8dd23ad2f2 | |||
| bce75d7c68 | |||
| 815053e403 | |||
| 6173abe20b | |||
| 6fcf0afa35 | |||
| 05521e276f | |||
| 38ffbbd7dd | |||
| 47e1878e4c | |||
| dc6f149973 | |||
| 420f6bfccb | |||
| ae33e11694 | |||
| 4d8b0282b4 | |||
| 00845fca88 | |||
| 84fe86c7fd | |||
| 5e1ed9d5d2 | |||
| 2ba668732a | |||
| 2cb73b71d1 | |||
| 16a2ce2b13 | |||
| 18e87a7544 | |||
| f81431dd72 | |||
| 04bdb9f813 | |||
| 1cfe281a76 | |||
| 6165bd7d1e | |||
| 0135564ad9 | |||
| 6847cbeff8 | |||
| 84daf33c03 | |||
| 86cbdb893a | |||
| 11ee680d38 | |||
| 4c5b382b69 | |||
| 39f4a776d6 | |||
| a250116694 | |||
| 9a73d71f47 | |||
| 73aaca05f8 | |||
| a993112098 | |||
| 9145d5ec3e | |||
| efc863844c | |||
| cc260e7864 | |||
| 42ce8f7f55 | |||
| 661390aef3 | |||
| ed4a70e765 | |||
| 1866968310 | |||
| 5fbf98ec23 | |||
| 5d2bb2c1b9 | |||
| 9039ddbb56 | |||
| 8f8510fc22 | |||
| 1e99ea6a51 | |||
| 016e1e675e | |||
| 1240641f76 | |||
| f1a34f0908 | |||
| 01bda54e05 | |||
| bc04afe183 | |||
| ac086ae616 | |||
| f75a2b093f | |||
| 4dba7b0203 | |||
| d3cd3c0a9b | |||
| e351874a0a | |||
| dcdf4fc78b | |||
| cf38d8c55b | |||
| b0233a33a1 | |||
| c3235db9ee | |||
| 738113bac8 | |||
| 6613ee40e6 | |||
| ce6035d953 | |||
| 2bc4793ee8 | |||
| 9c6e34bfc1 | |||
| 4e65ff31a8 | |||
| 15461c7883 | |||
| de5352cfcf | |||
| ae26ed994e | |||
| 94745f6274 | |||
| dbfa0d88bb | |||
| cf3b5cb2fc | |||
| 192a225854 | |||
| 3508f76719 | |||
| a7d081fac0 | |||
| ee774f6e5b | |||
| 80f34598f8 | |||
| 7e168c8ad2 | |||
| 3ebc2c2442 | |||
| 631d86f723 | |||
| 3ac97f2b3d | |||
| ed55346be7 | |||
| e31ec1f7ed | |||
| 70e4fd2865 | |||
| 7898490779 | |||
| 0893e83c92 | |||
| ef334d0070 | |||
| 9f08d03978 | |||
| 3ca6c4bfb9 | |||
| cfea2095ca | |||
| 171bec3b0e | |||
| 93891ad2e9 | |||
| eece726651 | |||
| dc6665caed | |||
| 5b592cbaf4 | |||
| 348138d7cd | |||
| 6a34a4ebeb | |||
| 5ca247c749 | |||
| b16bffbf76 | |||
| b2aec3706d | |||
| d577c5def1 | |||
| a4dd14952e | |||
| 8879b3733e | |||
| 35b02226ca | |||
| 814feaa2ab | |||
| aa2e66dcaf | |||
| 7b7b12e477 | |||
| 187cd0a058 | |||
| 0c690af2fe | |||
| 40ecd2d8e5 | |||
| 484286d536 | |||
| d56b62dcda | |||
| b94125ac14 | |||
| 3f34319398 | |||
| ba076a29b9 | |||
| 13000c7350 | |||
| fd2649fc65 | |||
| 437b09c155 | |||
| b2b015a53b | |||
| 5bea4c5692 | |||
| 1b527b7acf | |||
| 4b8629b6b8 | |||
| ed81d19ce9 | |||
| 3497bf2d82 | |||
| afcf03fd2c | |||
| 582612b000 | |||
| 7bf32ccadb | |||
| f5c18861b6 | |||
| 4acd75b904 | |||
| cd6dd22b19 | |||
| 139c532019 | |||
| e5b57bf01c | |||
| 5ecd6d4e0a | |||
| 03bbe9aab1 | |||
| 0ef9d54ccd | |||
| 6ade77efa2 | |||
| 91fa865bf2 | |||
| 10ae76673c | |||
| 9497757842 | |||
| bb5abe0e9c | |||
| 76c0ddfc0b | |||
| 36b888e781 | |||
| a476972e2e | |||
| 866d3fb573 | |||
| 70cf0a389f | |||
| 7d4ccea579 | |||
| 654dd1d5e8 | |||
| bf114f6ee3 | |||
| 5727eaf767 | |||
| 346e98330c | |||
| 2b1f10266a | |||
| fc7970fdf0 | |||
| 65957e99ba | |||
| 7f9a94f8bc | |||
| cb560e2441 | |||
| 55856565c2 | |||
| 13968343d4 | |||
| 4c428121b9 | |||
| 4816f7ee5c | |||
| ce53fbde50 | |||
| 1516a69cd2 | |||
| 7a77fdae4f | |||
| b13da18e11 | |||
| f98f8a3892 | |||
| 77c4a7fd66 | |||
| e281413919 | |||
| 2007ddd3f8 | |||
| d8922fe3e9 | |||
| 6c611df8f0 | |||
| 6be24df5bc | |||
| 4759aacba9 | |||
| 802bfc259c | |||
| 64db8d166e | |||
| d2a769e196 | |||
| 68a8c8907d | |||
| 701d61080a | |||
| a8cc449706 | |||
| 2aa212b19c | |||
| 1f23cfe9c7 | |||
| 0fa8e47fb5 | |||
| 8043784fd7 | |||
| 526a6b31e5 | |||
| 14fd064a62 | |||
| 3178afbf0c | |||
| ce3b616432 | |||
| 54a761905d | |||
| aa531d7bd1 | |||
| d7e9ae1215 | |||
| 6cf9ede88e | |||
| 6092291bd7 | |||
| 3d0f11212f | |||
| 6194e002e2 | |||
| 75545d4d1c | |||
| d67eb2f2db | |||
| 6b8153ff0f | |||
| fb132732f1 | |||
| 336b157497 | |||
| d16975a9de | |||
| 87f6b36bab | |||
| 43fccf5617 | |||
| a5b3bcf41c | |||
| 8801d9c286 | |||
| a8e114f351 | |||
| 9a3a9b46e5 | |||
| 934204ec18 | |||
| 7cb8f8fb44 | |||
| 8d34bf2fea | |||
| 8801e69dba | |||
| f4afa398a1 | |||
| 32063278bd | |||
| 92208d2f85 | |||
| ab7c74b4b9 | |||
| e283abe171 | |||
| d7620f68bb | |||
| 971d97e2ec | |||
| 559d5efc04 | |||
| 85042820fb | |||
| 24a2eec815 | |||
| d987a79ab1 | |||
| eba09353e6 | |||
| 297660c9a3 | |||
| 8343c05fd8 | |||
| 7c3d064786 | |||
| c2ccc1cbdf | |||
| 04e080660a | |||
| f3cca88384 | |||
| 978bbd2d49 | |||
| 652feebd86 | |||
| 16ccbc4f61 | |||
| 072d45fd01 | |||
| 4439e39319 | |||
| b49c3a1a1e | |||
| c7addd4886 | |||
| 6df60aff52 | |||
| e7a080d6e6 | |||
| 661a728764 | |||
| 89303fd2dc | |||
| 1f8be1ca66 | |||
| cbc2024092 | |||
| f0ff7023c3 | |||
| 6e8728a364 | |||
| f179a63dd4 | |||
| 3a71c1e595 | |||
| ef7a61a67e | |||
| a6b2ee785b | |||
| d5a1336e6b | |||
| d4312b731a | |||
| 66f051386e | |||
| 8b3f9684e0 | |||
| 331f32deac | |||
| bb80c96754 | |||
| 0d8e19c26f | |||
| ed2fd2d0ca | |||
| 7c60151cb8 | |||
| 965308a32c | |||
| 92c612a9de | |||
| a7b53abcad | |||
| d575e1f613 | |||
| 2ba458387d | |||
| 98489a1d0c | |||
| 51d501aab2 | |||
| 841bdf1c07 | |||
| 86cac55c7c | |||
| c0995399d4 | |||
| de6cc287e5 | |||
| afd6771163 | |||
| 4cda028609 | |||
| 8ecce7642b | |||
| d1d5761232 | |||
| 759cba1a8d | |||
| 23cd40a8ec | |||
| f3188c1d09 | |||
| 2f4967f100 | |||
| 4fe4e7457c | |||
| d4e7274d4b | |||
| cffa015554 | |||
| 1104c7d75b | |||
| 4c6b4447db | |||
| 741a37b338 | |||
| 1157c5d341 | |||
| e48adebfb7 | |||
| 0a61dcb486 | |||
| 4b51eaadf8 | |||
| e2457ca16d | |||
| bd62790080 | |||
| 53fdcafa44 | |||
| af6f2483be | |||
| d8522aa349 | |||
| bae3121683 | |||
| 54c0d464b0 | |||
| cf89e8653c | |||
| 0c3500f532 | |||
| c12f525df4 | |||
| e7ba830691 | |||
| 4eb0716711 | |||
| ed90f3b7ea | |||
| 14b19ecf5e | |||
| 644432a14c |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet editPageId="org.eclipse.ui.resourceWorkingSetPage" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1262905463390_2" label="workingSet" name="workingSet"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/test" type="2"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/src" type="2"/> </launchConfigurationWorkingSet>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/perf" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/perf.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/build" type="2"/> </resources>}"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/lib/jsl/jsl}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-conf lib/jsl/jsl.default.conf"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,14 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
@@ -12,3 +12,5 @@ angular.js.tmproj
|
||||
node_modules
|
||||
angular.xcodeproj
|
||||
.idea
|
||||
libpeerconnection.log
|
||||
npm-debug.log
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>angular.js</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>auto,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/docs.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>auto,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/JSTD_Tests.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>auto,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/JSTD_perf.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry excluding="test/" kind="src" path="src"/>
|
||||
<classpathentry excluding="docs-data.js|docs-scenario.js" kind="src" path="docs"/>
|
||||
<classpathentry excluding="test/" kind="src" path="test"/>
|
||||
<classpathentry kind="src" path="test/test"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
|
||||
<classpathentry kind="output" path=""/>
|
||||
</classpath>
|
||||
@@ -1,16 +0,0 @@
|
||||
#Mon Jan 24 10:31:47 PST 2011
|
||||
activeContentFilterList=*.makefile,makefile,*.Makefile,Makefile,Makefile.*,*.mk,MANIFEST.MF
|
||||
addNewLine=true
|
||||
convertActionOnSaave=AnyEdit.CnvrtTabToSpaces
|
||||
eclipse.preferences.version=1
|
||||
inActiveContentFilterList=
|
||||
javaTabWidthForJava=true
|
||||
org.eclipse.jdt.ui.editor.tab.width=2
|
||||
projectPropsEnabled=false
|
||||
removeTrailingSpaces=true
|
||||
replaceAllSpaces=false
|
||||
replaceAllTabs=false
|
||||
saveAndAddLine=true
|
||||
saveAndConvert=true
|
||||
saveAndTrim=true
|
||||
useModulo4Tabs=false
|
||||
@@ -1 +0,0 @@
|
||||
org.eclipse.wst.jsdt.launching.JRE_CONTAINER
|
||||
@@ -1 +0,0 @@
|
||||
Global
|
||||
+13
-7
@@ -1,13 +1,19 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
- 0.10
|
||||
|
||||
env:
|
||||
global:
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
|
||||
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm install -g testacular@canary
|
||||
- rake package
|
||||
- ./nodeserver.sh > /dev/null &
|
||||
- export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
|
||||
- ./lib/sauce/sauce_connect_setup.sh
|
||||
- npm install -g grunt-cli
|
||||
- grunt ci-checks package
|
||||
- ./lib/sauce/sauce_connect_block.sh
|
||||
|
||||
script:
|
||||
- rake test[Firefox,"--reporters=dots"]
|
||||
- grunt parallel:travis --reporters dots --browsers SL_Chrome
|
||||
|
||||
+1245
-1
File diff suppressed because it is too large
Load Diff
+228
@@ -0,0 +1,228 @@
|
||||
var files = require('./angularFiles').files;
|
||||
var util = require('./lib/grunt/utils.js');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
//grunt plugins
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
grunt.loadNpmTasks('grunt-ddescribe-iit');
|
||||
grunt.loadNpmTasks('grunt-merge-conflict');
|
||||
grunt.loadNpmTasks('grunt-parallel');
|
||||
grunt.loadTasks('lib/grunt');
|
||||
|
||||
var NG_VERSION = util.getVersion();
|
||||
var dist = 'angular-'+ NG_VERSION.full;
|
||||
|
||||
|
||||
//global beforeEach
|
||||
util.init();
|
||||
|
||||
|
||||
//config
|
||||
grunt.initConfig({
|
||||
NG_VERSION: NG_VERSION,
|
||||
|
||||
parallel: {
|
||||
travis: {
|
||||
options: {
|
||||
stream: true,
|
||||
},
|
||||
tasks: [
|
||||
util.parallelTask('test:modules'),
|
||||
util.parallelTask('test:jquery'),
|
||||
util.parallelTask('test:jqlite'),
|
||||
util.parallelTask('test:e2e')
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
connect: {
|
||||
devserver: {
|
||||
options: {
|
||||
port: 8000,
|
||||
hostname: '0.0.0.0',
|
||||
base: '.',
|
||||
keepalive: true,
|
||||
middleware: function(connect, options){
|
||||
return [
|
||||
//uncomment to enable CSP
|
||||
// util.csp(),
|
||||
util.rewrite(),
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base),
|
||||
connect.directory(options.base)
|
||||
];
|
||||
}
|
||||
}
|
||||
},
|
||||
testserver: {
|
||||
options: {
|
||||
// We use end2end task (which does not start the webserver)
|
||||
// and start the webserver as a separate process (in travis_build.sh)
|
||||
// to avoid https://github.com/joyent/libuv/issues/826
|
||||
port: 8000,
|
||||
hostname: '0.0.0.0',
|
||||
middleware: function(connect, options){
|
||||
return [
|
||||
function(req, resp, next) {
|
||||
// cache get requests to speed up tests on travis
|
||||
if (req.method === 'GET') {
|
||||
resp.setHeader('Cache-control', 'public, max-age=3600');
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
connect.favicon('images/favicon.ico'),
|
||||
connect.static(options.base)
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
test: {
|
||||
jqlite: 'karma-jqlite.conf.js',
|
||||
jquery: 'karma-jquery.conf.js',
|
||||
modules: 'karma-modules.conf.js',
|
||||
//NOTE run grunt test:e2e instead and it will start a webserver for you
|
||||
end2end: 'karma-e2e.conf.js'
|
||||
},
|
||||
|
||||
|
||||
autotest: {
|
||||
jqlite: 'karma-jqlite.conf.js',
|
||||
jquery: 'karma-jquery.conf.js'
|
||||
},
|
||||
|
||||
|
||||
clean: {build: ['build']},
|
||||
|
||||
|
||||
build: {
|
||||
scenario: {
|
||||
dest: 'build/angular-scenario.js',
|
||||
src: [
|
||||
'lib/jquery/jquery.js',
|
||||
util.wrap([files['angularSrc'], files['angularScenario']], 'ngScenario/angular')
|
||||
],
|
||||
styles: {
|
||||
css: ['css/angular.css', 'css/angular-scenario.css']
|
||||
}
|
||||
},
|
||||
angular: {
|
||||
dest: 'build/angular.js',
|
||||
src: util.wrap([files['angularSrc']], 'angular'),
|
||||
styles: {
|
||||
css: ['css/angular.css'],
|
||||
minify: true
|
||||
}
|
||||
},
|
||||
loader: {
|
||||
dest: 'build/angular-loader.js',
|
||||
src: util.wrap(['src/loader.js'], 'loader')
|
||||
},
|
||||
mocks: {
|
||||
dest: 'build/angular-mocks.js',
|
||||
src: ['src/ngMock/angular-mocks.js'],
|
||||
strict: false
|
||||
},
|
||||
sanitize: {
|
||||
dest: 'build/angular-sanitize.js',
|
||||
src: util.wrap([
|
||||
'src/ngSanitize/sanitize.js',
|
||||
'src/ngSanitize/directive/ngBindHtml.js',
|
||||
'src/ngSanitize/filter/linky.js',
|
||||
], 'module')
|
||||
},
|
||||
resource: {
|
||||
dest: 'build/angular-resource.js',
|
||||
src: util.wrap(['src/ngResource/resource.js'], 'module')
|
||||
},
|
||||
cookies: {
|
||||
dest: 'build/angular-cookies.js',
|
||||
src: util.wrap(['src/ngCookies/cookies.js'], 'module')
|
||||
},
|
||||
bootstrap: {
|
||||
dest: 'build/angular-bootstrap.js',
|
||||
src: util.wrap(['src/bootstrap/bootstrap.js'], 'module')
|
||||
},
|
||||
bootstrapPrettify: {
|
||||
dest: 'build/angular-bootstrap-prettify.js',
|
||||
src: util.wrap(['src/bootstrap/bootstrap-prettify.js', 'src/bootstrap/google-prettify/prettify.js'], 'module'),
|
||||
styles: {
|
||||
css: ['src/bootstrap/google-prettify/prettify.css'],
|
||||
minify: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
min: {
|
||||
angular: 'build/angular.js',
|
||||
cookies: 'build/angular-cookies.js',
|
||||
loader: 'build/angular-loader.js',
|
||||
resource: 'build/angular-resource.js',
|
||||
sanitize: 'build/angular-sanitize.js',
|
||||
bootstrap: 'build/angular-bootstrap.js',
|
||||
bootstrapPrettify: 'build/angular-bootstrap-prettify.js',
|
||||
},
|
||||
|
||||
|
||||
docs: {
|
||||
process: ['build/docs/*.html', 'build/docs/.htaccess']
|
||||
},
|
||||
|
||||
|
||||
"ddescribe-iit": {
|
||||
files: [
|
||||
'test/**/*.js',
|
||||
'!test/ngScenario/DescribeSpec.js'
|
||||
]
|
||||
},
|
||||
|
||||
"merge-conflict": {
|
||||
files: [
|
||||
'src/**/*',
|
||||
'test/**/*',
|
||||
'docs/**/*',
|
||||
'css/**/*'
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
copy: {
|
||||
i18n: {
|
||||
files: [
|
||||
{ src: 'src/ngLocale/**', dest: 'build/i18n/', expand: true, flatten: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
compress: {
|
||||
build: {
|
||||
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
|
||||
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
write: {
|
||||
versionTXT: {file: 'build/version.txt', val: NG_VERSION.full},
|
||||
versionJSON: {file: 'build/version.json', val: JSON.stringify(NG_VERSION)}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//alias tasks
|
||||
grunt.registerTask('test:unit', ['test:jqlite', 'test:jquery', 'test:modules']);
|
||||
grunt.registerTask('minify', ['clean', 'build', 'minall']);
|
||||
grunt.registerTask('test:e2e', ['connect:testserver', 'test:end2end']);
|
||||
grunt.registerTask('webserver', ['connect:devserver']);
|
||||
grunt.registerTask('package', ['clean', 'buildall', 'minall', 'docs', 'copy', 'write', 'compress']);
|
||||
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict']);
|
||||
grunt.registerTask('default', ['package']);
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
AngularJS
|
||||
=========
|
||||
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets use
|
||||
good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
|
||||
use good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
||||
syntax to express your application’s components clearly and succinctly. It automatically
|
||||
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
|
||||
binding. To help you structure your application better and make it easy to test AngularJS teaches
|
||||
binding. To help you structure your application better and make it easy to test, AngularJS teaches
|
||||
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
|
||||
server-side communication, taming async callbacks with promises and deferreds; and make client-side
|
||||
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
|
||||
@@ -21,25 +21,19 @@ Building AngularJS
|
||||
---------
|
||||
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
|
||||
|
||||
rake package
|
||||
grunt package
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
|
||||
|
||||
sudo npm install -g testacular
|
||||
|
||||
To execute all unit tests, use:
|
||||
|
||||
rake test:unit
|
||||
grunt test:unit
|
||||
|
||||
To execute end-to-end (e2e) tests, use:
|
||||
|
||||
rake package
|
||||
rake webserver &
|
||||
rake test:e2e
|
||||
grunt package
|
||||
grunt test:e2e
|
||||
|
||||
To learn more about the rake tasks, run `rake -T` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute) and instructions in this
|
||||
[commit message](https://github.com/angular/angular.js/commit/9d168f058f9c6d7eeae0daa7cb72ea4e02a0003a).
|
||||
To learn more about the grunt tasks, run `grunt --help` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
require 'yaml'
|
||||
include FileUtils
|
||||
|
||||
|
||||
## High level flow of the build:
|
||||
##
|
||||
## clean -> init -> concat -> minify -> package
|
||||
##
|
||||
|
||||
|
||||
content = File.open('angularFiles.js', 'r') {|f| f.read }
|
||||
files = eval(content.gsub(/\};(\s|\S)*/, '}').
|
||||
gsub(/angularFiles = /, '').
|
||||
gsub(/:/, '=>').
|
||||
gsub(/\/\//, '#'));
|
||||
|
||||
BUILD_DIR = 'build'
|
||||
|
||||
task :default => [:package]
|
||||
|
||||
|
||||
desc 'Init the build workspace'
|
||||
task :init do
|
||||
FileUtils.mkdir(BUILD_DIR) unless File.directory?(BUILD_DIR)
|
||||
|
||||
v = YAML::load( File.open( 'version.yaml' ) )
|
||||
match = v['version'].match(/^([^-]*)(-snapshot)?$/)
|
||||
|
||||
NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename, :stable).
|
||||
new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''),
|
||||
match[1].split('.')[0],
|
||||
match[1].split('.')[1],
|
||||
match[1].split('.')[2].sub(/\D+.*$/, ''),
|
||||
v['codename'],
|
||||
v['stable'])
|
||||
end
|
||||
|
||||
|
||||
desc 'Clean Generated Files'
|
||||
task :clean do
|
||||
FileUtils.rm_r(BUILD_DIR, :force => true)
|
||||
FileUtils.mkdir(BUILD_DIR)
|
||||
FileUtils.rm_r('test_out', :force => true)
|
||||
end
|
||||
|
||||
|
||||
desc 'Concat Scenario'
|
||||
task :concat_scenario => :init do
|
||||
|
||||
concat_file('angular-scenario.js', [
|
||||
'lib/jquery/jquery.js',
|
||||
'src/ngScenario/angular.prefix',
|
||||
files['angularSrc'],
|
||||
files['angularScenario'],
|
||||
'src/ngScenario/angular.suffix',
|
||||
], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css'))
|
||||
end
|
||||
|
||||
|
||||
desc 'Concat JSTD Scenario Adapter'
|
||||
task :concat_jstd_scenario_adapter => :init do
|
||||
|
||||
concat_file('jstd-scenario-adapter.js', [
|
||||
'src/ngScenario/jstd-scenario-adapter/angular.prefix',
|
||||
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
|
||||
'src/ngScenario/jstd-scenario-adapter/angular.suffix',
|
||||
])
|
||||
|
||||
# TODO(vojta) use jstd configuration when implemented
|
||||
# (instead of including jstd-adapter-config.js)
|
||||
File.open(path_to('jstd-scenario-adapter-config.js'), 'w') do |f|
|
||||
f.write("/**\r\n" +
|
||||
" * Configuration for jstd scenario adapter \n */\n" +
|
||||
"var jstdScenarioAdapter = {\n relativeUrlPrefix: '/build/docs/'\n};\n")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
desc 'Concat AngularJS files'
|
||||
task :concat => :init do
|
||||
concat_file('angular.js', [
|
||||
'src/angular.prefix',
|
||||
files['angularSrc'],
|
||||
'src/angular.suffix',
|
||||
], gen_css('css/angular.css', true))
|
||||
|
||||
FileUtils.cp_r 'src/ngLocale', path_to('i18n')
|
||||
|
||||
concat_file('angular-loader.js', [
|
||||
'src/loader.prefix',
|
||||
'src/loader.js',
|
||||
'src/loader.suffix'])
|
||||
|
||||
|
||||
concat_module('sanitize', [
|
||||
'src/ngSanitize/sanitize.js',
|
||||
'src/ngSanitize/directive/ngBindHtml.js',
|
||||
'src/ngSanitize/filter/linky.js'])
|
||||
|
||||
concat_module('resource', ['src/ngResource/resource.js'])
|
||||
concat_module('cookies', ['src/ngCookies/cookies.js'])
|
||||
concat_module('bootstrap', ['src/bootstrap/bootstrap.js'])
|
||||
concat_module('bootstrap-prettify', ['src/bootstrap/bootstrap-prettify.js',
|
||||
'src/bootstrap/google-prettify/prettify.js'],
|
||||
gen_css('src/bootstrap/google-prettify/prettify.css', true))
|
||||
|
||||
|
||||
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
|
||||
|
||||
rewrite_file(path_to('angular-mocks.js')) do |content|
|
||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'Minify JavaScript'
|
||||
task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter] do
|
||||
[ 'angular.js',
|
||||
'angular-cookies.js',
|
||||
'angular-loader.js',
|
||||
'angular-resource.js',
|
||||
'angular-sanitize.js',
|
||||
'angular-bootstrap.js',
|
||||
'angular-bootstrap-prettify.js'
|
||||
].each do |file|
|
||||
fork { closure_compile(file) }
|
||||
end
|
||||
|
||||
Process.waitall
|
||||
end
|
||||
|
||||
|
||||
desc 'Generate version.txt file'
|
||||
task :version => [:init] do
|
||||
`echo #{NG_VERSION.full} > #{path_to('version.txt')}`
|
||||
end
|
||||
|
||||
|
||||
desc 'Generate docs'
|
||||
task :docs => [:init] do
|
||||
`node docs/src/gen-docs.js`
|
||||
|
||||
[ path_to('docs/.htaccess'),
|
||||
path_to('docs/index.html'),
|
||||
path_to('docs/index-debug.html'),
|
||||
path_to('docs/index-nocache.html'),
|
||||
path_to('docs/index-jq.html'),
|
||||
path_to('docs/index-jq-debug.html'),
|
||||
path_to('docs/index-jq-nocache.html'),
|
||||
path_to('docs/docs-scenario.html')
|
||||
].each do |src|
|
||||
rewrite_file(src) do |content|
|
||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full).
|
||||
sub('"NG_VERSION_STABLE"', NG_VERSION.stable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'Create angular distribution'
|
||||
task :package => [:clean, :minify, :version, :docs] do
|
||||
zip_dir = "angular-#{NG_VERSION.full}"
|
||||
zip_file = "#{zip_dir}.zip"
|
||||
|
||||
FileUtils.ln_s BUILD_DIR, zip_dir
|
||||
%x(zip -r #{zip_file} #{zip_dir})
|
||||
FileUtils.rm zip_dir
|
||||
|
||||
FileUtils.mv zip_file, path_to(zip_file)
|
||||
|
||||
puts "Package created: #{path_to(zip_file)}"
|
||||
end
|
||||
|
||||
|
||||
desc 'Start development webserver'
|
||||
task :webserver, :port do |t, args|
|
||||
exec "node lib/nodeserver/server.js #{args[:port]}"
|
||||
end
|
||||
|
||||
|
||||
desc 'Run all AngularJS tests'
|
||||
task :test, :browsers, :misc_options do |t, args|
|
||||
[ 'test:jqlite',
|
||||
'test:jquery',
|
||||
'test:modules',
|
||||
'test:e2e'
|
||||
].each do |task|
|
||||
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
namespace :test do
|
||||
|
||||
desc 'Run all unit tests (single run)'
|
||||
task :unit, :browsers, :misc_options do |t, args|
|
||||
[ 'test:jqlite',
|
||||
'test:jquery',
|
||||
'test:modules'
|
||||
].each do |task|
|
||||
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'Run jqLite-based unit test suite (single run)'
|
||||
task :jqlite, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jqlite.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run jQuery-based unit test suite (single run)'
|
||||
task :jquery, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jquery.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run bundled modules unit test suite (single run)'
|
||||
task :modules, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-modules.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run e2e test suite (single run)'
|
||||
task :e2e, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-e2e.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
namespace :autotest do
|
||||
|
||||
desc 'Run jqLite-based unit test suite (autowatch)'
|
||||
task :jqlite, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jqlite.conf.js', false, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run jQuery-based unit test suite (autowatch)'
|
||||
task :jquery, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jquery.conf.js', false, args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
###################
|
||||
# utility methods #
|
||||
###################
|
||||
|
||||
|
||||
##
|
||||
# generates css snippet from a given files and optionally applies simple minification rules
|
||||
#
|
||||
def gen_css(cssFile, minify = false)
|
||||
css = ''
|
||||
File.open(cssFile, 'r') do |f|
|
||||
css = f.read
|
||||
end
|
||||
|
||||
if minify
|
||||
css.gsub! /\n/, ''
|
||||
css.gsub! /\/\*.*?\*\//, ''
|
||||
css.gsub! /:\s+/, ':'
|
||||
css.gsub! /\s*\{\s*/, '{'
|
||||
css.gsub! /\s*\}\s*/, '}'
|
||||
css.gsub! /\s*\,\s*/, ','
|
||||
css.gsub! /\s*\;\s*/, ';'
|
||||
end
|
||||
|
||||
#escape for js
|
||||
css.gsub! /\\/, "\\\\\\"
|
||||
css.gsub! /'/, "\\\\'"
|
||||
css.gsub! /\n/, "\\n"
|
||||
|
||||
return %Q{angular.element(document).find('head').append('<style type="text/css">#{css}</style>');}
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# returns path to the file in the build directory
|
||||
#
|
||||
def path_to(filename)
|
||||
return File.join(BUILD_DIR, *filename)
|
||||
end
|
||||
|
||||
|
||||
def closure_compile(filename)
|
||||
puts "Minifying #{filename} ..."
|
||||
|
||||
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
|
||||
|
||||
%x(java \
|
||||
-client \
|
||||
-d32 \
|
||||
-jar lib/closure-compiler/compiler.jar \
|
||||
--compilation_level SIMPLE_OPTIMIZATIONS \
|
||||
--language_in ECMASCRIPT5_STRICT \
|
||||
--js #{path_to(filename)} \
|
||||
--js_output_file #{min_path})
|
||||
|
||||
rewrite_file(min_path) do |content|
|
||||
content.sub!("'use strict';", "").
|
||||
sub!(/\(function\([^)]*\)\{/, "\\0'use strict';")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def concat_file(filename, deps, footer='')
|
||||
puts "Creating #{filename} ..."
|
||||
File.open(path_to(filename), 'w') do |f|
|
||||
concat = 'cat ' + deps.flatten.join(' ')
|
||||
|
||||
content = %x{#{concat}}.
|
||||
gsub('"NG_VERSION_FULL"', NG_VERSION.full).
|
||||
gsub('"NG_VERSION_MAJOR"', NG_VERSION.major).
|
||||
gsub('"NG_VERSION_MINOR"', NG_VERSION.minor).
|
||||
gsub('"NG_VERSION_DOT"', NG_VERSION.dot).
|
||||
gsub('"NG_VERSION_CODENAME"', NG_VERSION.codename).
|
||||
gsub(/^\s*['"]use strict['"];?\s*$/, ''). # remove all file-specific strict mode flags
|
||||
sub(/\(function\([^)]*\)\s*\{/, "\\0\n'use strict';") # add single strict mode flag
|
||||
|
||||
f.write(content)
|
||||
f.write(footer)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def concat_module(name, files, footer='')
|
||||
concat_file('angular-' + name + '.js', ['src/module.prefix'] + files + ['src/module.suffix'], footer)
|
||||
end
|
||||
|
||||
|
||||
def rewrite_file(filename)
|
||||
File.open(filename, File::RDWR) do |f|
|
||||
content = f.read
|
||||
|
||||
content = yield content
|
||||
|
||||
raise "File rewrite failed - No content!" unless content
|
||||
|
||||
f.truncate 0
|
||||
f.rewind
|
||||
f.write content
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def start_testacular(config, singleRun, browsers, misc_options)
|
||||
sh "./node_modules/testacular/bin/testacular start " +
|
||||
"#{config} " +
|
||||
"#{'--single-run=true' if singleRun} " +
|
||||
"#{'--browsers=' + browsers.gsub('+', ',') if browsers} " +
|
||||
"#{(misc_options || '').gsub('+', ',')}"
|
||||
end
|
||||
Vendored
+19
-54
@@ -79,7 +79,6 @@ angularFiles = {
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Future.js',
|
||||
'src/ngScenario/ObjectModel.js',
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Runner.js',
|
||||
'src/ngScenario/SpecRunner.js',
|
||||
'src/ngScenario/dsl.js',
|
||||
@@ -95,7 +94,6 @@ angularFiles = {
|
||||
'test/matchers.js',
|
||||
'test/ngScenario/*.js',
|
||||
'test/ngScenario/output/*.js',
|
||||
'test/ngScenario/jstd-scenario-adapter/*.js',
|
||||
'test/*.js',
|
||||
'test/auto/*.js',
|
||||
'test/bootstrap/*.js',
|
||||
@@ -110,37 +108,30 @@ angularFiles = {
|
||||
'test/ngMock/*.js'
|
||||
],
|
||||
|
||||
'jstd': [
|
||||
'lib/jasmine/jasmine.js',
|
||||
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
|
||||
'karma': [
|
||||
'lib/jquery/jquery.js',
|
||||
'test/jquery_remove.js',
|
||||
'@angularSrc',
|
||||
'src/publishExternalApis.js',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
|
||||
'@angularTest',
|
||||
'example/personalLog/*.js',
|
||||
'example/personalLog/test/*.js'
|
||||
],
|
||||
|
||||
'jstdExclude': [
|
||||
'karmaExclude': [
|
||||
'test/jquery_alias.js',
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js'
|
||||
],
|
||||
|
||||
'jstdScenario': [
|
||||
'karmaScenario': [
|
||||
'build/angular-scenario.js',
|
||||
'build/jstd-scenario-adapter-config.js',
|
||||
'build/jstd-scenario-adapter.js',
|
||||
'build/docs/docs-scenario.js'
|
||||
],
|
||||
|
||||
"jstdModules": [
|
||||
'lib/jasmine/jasmine.js',
|
||||
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
|
||||
"karmaModules": [
|
||||
'build/angular.js',
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'src/ngCookies/cookies.js',
|
||||
@@ -157,39 +148,20 @@ angularFiles = {
|
||||
'test/ngSanitize/filter/*.js'
|
||||
],
|
||||
|
||||
'jstdPerf': [
|
||||
'lib/jasmine/jasmine.js',
|
||||
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
|
||||
'@angularSrc',
|
||||
'@angularSrcModules',
|
||||
'src/ngMock/angular-mocks.js',
|
||||
'perf/data/*.js',
|
||||
'perf/testUtils.js',
|
||||
'perf/*.js'
|
||||
],
|
||||
|
||||
'jstdPerfExclude': [
|
||||
'src/ng/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js'
|
||||
],
|
||||
|
||||
'jstdJquery': [
|
||||
'lib/jasmine/jasmine.js',
|
||||
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
|
||||
'karmaJquery': [
|
||||
'lib/jquery/jquery.js',
|
||||
'test/jquery_alias.js',
|
||||
'@angularSrc',
|
||||
'src/publishExternalApis.js',
|
||||
'@angularSrcModules',
|
||||
'@angularScenario',
|
||||
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
|
||||
'@angularTest',
|
||||
'example/personalLog/*.js',
|
||||
|
||||
'example/personalLog/test/*.js'
|
||||
],
|
||||
|
||||
'jstdJqueryExclude': [
|
||||
'karmaJqueryExclude': [
|
||||
'src/angular-bootstrap.js',
|
||||
'src/ngScenario/angular-bootstrap.js',
|
||||
'test/jquery_remove.js'
|
||||
@@ -197,29 +169,22 @@ angularFiles = {
|
||||
};
|
||||
|
||||
if (exports) {
|
||||
exports.files = angularFiles
|
||||
exports.mergeFiles = function mergeFiles() {
|
||||
exports.files = angularFiles;
|
||||
exports.mergeFilesFor = function() {
|
||||
var files = [];
|
||||
|
||||
[].splice.call(arguments, 0).forEach(function(file) {
|
||||
if (file.match(/testacular/)) {
|
||||
files.push(file);
|
||||
} else {
|
||||
angularFiles[file].forEach(function(f) {
|
||||
// replace @ref
|
||||
var match = f.match(/^\@(.*)/);
|
||||
if (match) {
|
||||
var deps = angularFiles[match[1]];
|
||||
files = files.concat(deps);
|
||||
} else {
|
||||
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
|
||||
files.push(f);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {
|
||||
angularFiles[filegroup].forEach(function(file) {
|
||||
// replace @ref
|
||||
var match = file.match(/^\@(.*)/);
|
||||
if (match) {
|
||||
files = files.concat(angularFiles[match[1]]);
|
||||
} else {
|
||||
files.push(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+28
-23
@@ -36,16 +36,15 @@ var parseRawCommit = function(raw) {
|
||||
msg.breaks = [];
|
||||
|
||||
lines.forEach(function(line) {
|
||||
match = line.match(/Closes\s#(\d+)/);
|
||||
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
|
||||
if (match) msg.closes.push(parseInt(match[1]));
|
||||
});
|
||||
|
||||
|
||||
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
|
||||
if (match) {
|
||||
console.log('found!!!')
|
||||
msg.breaks.push(match[1]);
|
||||
msg.breaking = match[1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
msg.body = lines.join('\n');
|
||||
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
|
||||
@@ -88,7 +87,8 @@ var currentDate = function() {
|
||||
};
|
||||
|
||||
|
||||
var printSection = function(stream, title, section) {
|
||||
var printSection = function(stream, title, section, printCommitLinks) {
|
||||
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
|
||||
var components = Object.getOwnPropertyNames(section).sort();
|
||||
|
||||
if (!components.length) return;
|
||||
@@ -109,11 +109,15 @@ var printSection = function(stream, title, section) {
|
||||
}
|
||||
|
||||
section[name].forEach(function(commit) {
|
||||
stream.write(util.format('%s %s (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||
if (commit.closes.length) {
|
||||
stream.write(', closes ' + commit.closes.map(linkToIssue).join(', '));
|
||||
if (printCommitLinks) {
|
||||
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||
if (commit.closes.length) {
|
||||
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
|
||||
}
|
||||
stream.write(')\n');
|
||||
} else {
|
||||
stream.write(util.format('%s %s', prefix, commit.subject));
|
||||
}
|
||||
stream.write(')\n');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -122,7 +126,7 @@ var printSection = function(stream, title, section) {
|
||||
|
||||
|
||||
var readGitLog = function(grep, from) {
|
||||
var deffered = q.defer();
|
||||
var deferred = q.defer();
|
||||
|
||||
// TODO(vojta): if it's slow, use spawn and stream it instead
|
||||
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
|
||||
@@ -133,10 +137,10 @@ var readGitLog = function(grep, from) {
|
||||
if (commit) commits.push(commit);
|
||||
});
|
||||
|
||||
deffered.resolve(commits);
|
||||
deferred.resolve(commits);
|
||||
});
|
||||
|
||||
return deffered.promise;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
@@ -158,36 +162,37 @@ var writeChangelog = function(stream, commits, version) {
|
||||
section[component].push(commit);
|
||||
}
|
||||
|
||||
commit.breaks.forEach(function(breakMsg) {
|
||||
sections.breaks[EMPTY_COMPONENT].push({
|
||||
subject: breakMsg,
|
||||
if (commit.breaking) {
|
||||
sections.breaks[component] = sections.breaks[component] || [];
|
||||
sections.breaks[component].push({
|
||||
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
|
||||
hash: commit.hash,
|
||||
closes: []
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||
printSection(stream, 'Bug Fixes', sections.fix);
|
||||
printSection(stream, 'Features', sections.feat);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||
}
|
||||
|
||||
|
||||
var getPreviousTag = function() {
|
||||
var deffered = q.defer();
|
||||
var deferred = q.defer();
|
||||
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
|
||||
if (code) deffered.reject('Cannot get the previous tag.');
|
||||
else deffered.resolve(stdout.replace('\n', ''));
|
||||
if (code) deferred.reject('Cannot get the previous tag.');
|
||||
else deferred.resolve(stdout.replace('\n', ''));
|
||||
});
|
||||
return deffered.promise;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
var generate = function(version, file) {
|
||||
getPreviousTag().then(function(tag) {
|
||||
console.log('Reading git log since', tag);
|
||||
readGitLog('^fix|^feat|Breaks', tag).then(function(commits) {
|
||||
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
|
||||
console.log('Parsed', commits.length, 'commits');
|
||||
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
|
||||
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
|
||||
|
||||
+3
-3
@@ -34,10 +34,10 @@ describe('changelog.js', function() {
|
||||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
||||
'feat(ng-list): Allow custom separator\n' +
|
||||
'bla bla bla\n\n' +
|
||||
'Breaks first breaking change\nsomething else\n' +
|
||||
'Breaks another breaking change\n');
|
||||
'BREAKING CHANGE: first breaking change\nsomething else\n' +
|
||||
'another line with more info\n');
|
||||
|
||||
expect(msg.breaks).toEqual(['first breaking change', 'another breaking change']);
|
||||
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
rake minify
|
||||
grunt minify
|
||||
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
||||
ls -l build/angular.min.*
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
|
||||
.ng-cloak, .x-ng-cloak {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
ng\:form {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
External resources are URLs that provide JSON data, which are then rendered with the help of
|
||||
templates. angular has a resource factory that can be used to give names to the URLs and then
|
||||
templates. Angular has a resource factory that can be used to give names to the URLs and then
|
||||
attach behavior to them. For example you can use the
|
||||
{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz
|
||||
API}
|
||||
@@ -21,12 +21,12 @@ to retrieve Buzz activity and comments.
|
||||
{ get: {method: 'JSONP', params: {visibility: '@self'}},
|
||||
replies: {method: 'JSONP', params: {visibility: '@self', comments: '@comments'}}
|
||||
});
|
||||
}
|
||||
BuzzController.prototype = {
|
||||
fetch: function() {
|
||||
|
||||
$scope.fetch = function() {
|
||||
$scope.activities = $scope.Activity.get({userId:this.userId});
|
||||
},
|
||||
expandReplies: function(activity) {
|
||||
}
|
||||
|
||||
$scope.expandReplies = function(activity) {
|
||||
activity.replies = $scope.Activity.replies({userId: this.userId, activityId: activity.id});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Deep linking allows you to encode the state of the application in the URL so that it can be
|
||||
bookmarked and the application can be restored from the URL to the same state.
|
||||
|
||||
While angular does not force you to deal with bookmarks in any particular way, it has services
|
||||
While Angular does not force you to deal with bookmarks in any particular way, it has services
|
||||
which make the common case described here very easy to implement.
|
||||
|
||||
# Assumptions
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook: Form
|
||||
@description
|
||||
|
||||
A web application's main purpose is to present and gather data. For this reason angular strives
|
||||
A web application's main purpose is to present and gather data. For this reason Angular strives
|
||||
to make both of these operations trivial. This example shows off how you can build a simple form to
|
||||
allow a user to enter data.
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="HelloCntl">
|
||||
Your name: <input type="text" ng-model="name" value="World"/>
|
||||
Your name: <input type="text" ng-model="name"/>
|
||||
<hr/>
|
||||
Hello {{name}}!
|
||||
Hello {{name || "World"}}!
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
Take a look through the source and note:
|
||||
|
||||
* The script tag that {@link guide/bootstrap bootstraps} the angular environment.
|
||||
* The script tag that {@link guide/bootstrap bootstraps} the Angular environment.
|
||||
* The text {@link api/ng.directive:input input form control} which is
|
||||
bound to the greeting name text.
|
||||
* No need for listener registration and event firing on change events.
|
||||
* There is no need for listener registration and event firing on change events.
|
||||
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
|
||||
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
|
||||
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook
|
||||
@description
|
||||
|
||||
Welcome to the angular cookbook. Here we will show you typical uses of angular by example.
|
||||
Welcome to the Angular cookbook. Here we will show you typical uses of Angular by example.
|
||||
|
||||
|
||||
# Hello World
|
||||
@@ -45,7 +45,7 @@ allowing you to send links to specific screens in your app.
|
||||
# Services
|
||||
|
||||
{@link api/ng Services}: Services are long lived objects in your applications that are
|
||||
available across controllers. A collection of useful services are pre-bundled with angular but you
|
||||
available across controllers. A collection of useful services are pre-bundled with Angular but you
|
||||
will likely add your own. Services are initialized using dependency injection, which resolves the
|
||||
order of initialization. This safeguards you from the perils of global state (a common way to
|
||||
implement long lived objects).
|
||||
@@ -55,4 +55,4 @@ implement long lived objects).
|
||||
|
||||
{@link buzz Resources}: Web applications must be able to communicate with the external
|
||||
services to get and update data. Resources are the abstractions of external URLs which are
|
||||
specially tailored to angular data binding.
|
||||
specially tailored to Angular data binding.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook: MVC
|
||||
@description
|
||||
|
||||
MVC allows for a clean an testable separation between the behavior (controller) and the view
|
||||
MVC allows for a clean and testable separation between the behavior (controller) and the view
|
||||
(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
|
||||
view. This makes it very easy for the controller and the view to share the model.
|
||||
|
||||
@@ -115,7 +115,7 @@ view.
|
||||
# Things to notice
|
||||
|
||||
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
||||
* The controller is instantiated by <angular/> and injected into the view.
|
||||
* The controller is instantiated by Angular and injected into the view.
|
||||
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
||||
This makes it very testable.
|
||||
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
This page explains the Angular initialization process and how you can manually initialize Angular
|
||||
if necessary.
|
||||
|
||||
|
||||
# Angular `<script>` Tag
|
||||
## Angular `<script>` Tag
|
||||
|
||||
This example shows the recommended path for integrating Angular with what we call automatic
|
||||
initialization.
|
||||
@@ -38,6 +37,10 @@ initialization.
|
||||
|
||||
<html ng-app>
|
||||
|
||||
* If IE7 support is required add `id="ng-app"`
|
||||
|
||||
<html ng-app id="ng-app">
|
||||
|
||||
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
|
||||
`ng:`.)
|
||||
@@ -46,7 +49,7 @@ initialization.
|
||||
|
||||
|
||||
|
||||
# Automatic Initialization
|
||||
## Automatic Initialization
|
||||
|
||||
Angular initializes automatically upon `DOMContentLoaded` event, at which point Angular looks for
|
||||
the {@link api/ng.directive:ngApp `ng-app`} directive which
|
||||
@@ -73,16 +76,14 @@ will:
|
||||
|
||||
|
||||
|
||||
# Manual Initialization
|
||||
## Manual Initialization
|
||||
|
||||
|
||||
If you need to have more control over the initialization process, you can use a manual
|
||||
bootstrapping method instead. Examples of when you'd need to do this include using script loaders
|
||||
or the need to perform an operation before Angular compiles a page.
|
||||
|
||||
|
||||
Here is an example of manually initializing Angular. The example is equivalent to using the {@link
|
||||
api/ng.directive:ngApp ng-app} directive.
|
||||
Here is an example of manually initializing Angular:
|
||||
|
||||
<pre>
|
||||
<!doctype html>
|
||||
@@ -92,17 +93,22 @@ api/ng.directive:ngApp ng-app} directive.
|
||||
<script src="http://code.angularjs.org/angular.js"></script>
|
||||
<script>
|
||||
angular.element(document).ready(function() {
|
||||
angular.bootstrap(document);
|
||||
angular.bootstrap(document, ['optionalModuleName']);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
Note that we have provided the name of our application module to be loaded into the injector as the second
|
||||
parameter of the {@link api/angular.bootstrap} function. This example is equivalent to using the
|
||||
{@link api/ng.directive:ngApp ng-app} directive, with `ng-app="optionalModuleName"`, as in the automatic
|
||||
initialization example above.
|
||||
|
||||
This is the sequence that your code should follow:
|
||||
|
||||
1. After the page and all of the code is loaded, find the root of the HTML template, which is
|
||||
typically the root of the document.
|
||||
1. After the page and all of the code is loaded, find the root element of your AngularJS
|
||||
application, which is typically the root of the document.
|
||||
|
||||
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the template into an
|
||||
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the element into an
|
||||
executable, bi-directionally bound application.
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
|
||||
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
|
||||
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
|
||||
and even create new HTML elements or attributes with custom behavior. Angular calls these behavior
|
||||
extensions {@link api/ng.$compileProvider#directive directives}.
|
||||
|
||||
HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion.
|
||||
HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion.
|
||||
For example if something needs to be centered, there is no need to provide instructions to the
|
||||
browser how the window size needs to be divided in half so that center is found, and that this
|
||||
center needs to be aligned with the text's center. Simply add `align="center"` attribute to any
|
||||
browser how the window size needs to be divided in half so that the center is found, and that this
|
||||
center needs to be aligned with the text's center. Simply add an `align="center"` attribute to any
|
||||
element to achieve the desired behavior. Such is the power of declarative language.
|
||||
|
||||
But the declarative language is also limited, since it does not allow you to teach the browser new
|
||||
syntax. For example there is no easy way to get the browser to align the text at 1/3 the position
|
||||
instead of 1/2. What is needed is a way to teach browser new HTML syntax.
|
||||
instead of 1/2. What is needed is a way to teach the browser new HTML syntax.
|
||||
|
||||
Angular comes pre-bundled with common directives which are useful for building any app. We also
|
||||
expect that you will create directives that are specific to your app. These extension become a
|
||||
expect that you will create directives that are specific to your app. These extensions become a
|
||||
Domain Specific Language for building your application.
|
||||
|
||||
All of this compilation takes place in the web browser; no server side or pre-compilation step is
|
||||
@@ -30,26 +30,25 @@ involved.
|
||||
# Compiler
|
||||
|
||||
Compiler is an angular service which traverses the DOM looking for attributes. The compilation
|
||||
process happens into two phases.
|
||||
process happens in two phases.
|
||||
|
||||
1. **Compile:** traverse the DOM and collect all of the directives. The result is a linking
|
||||
function.
|
||||
|
||||
2. **Link:** combine the directives with a scope and produce a live view. Any changes in the
|
||||
scope model are reflected in the view, and any user interactions with the view are reflected
|
||||
in the scope model. Making the scope model a single source of truth.
|
||||
in the scope model. This makes the scope model the single source of truth.
|
||||
|
||||
Some directives such {@link api/ng.directive:ngRepeat
|
||||
`ng-repeat`} clone DOM elements once for each item in collection. Having a compile and link phase
|
||||
improves performance since the cloned template only needs to be compiled once, and then linked
|
||||
once for each clone instance.
|
||||
Some directives such as {@link api/ng.directive:ngRepeat `ng-repeat`} clone DOM elements once
|
||||
for each item in a collection. Having a compile and link phase improves performance since the
|
||||
cloned template only needs to be compiled once, and then linked once for each clone instance.
|
||||
|
||||
|
||||
# Directive
|
||||
|
||||
Directive is a behavior which should be triggered when specific HTML constructs are encountered in
|
||||
compilation process. The directives can be placed in element names, attributes, class names, as
|
||||
well as comments. Here are some equivalent examples of invoking {@link
|
||||
A directive is a behavior which should be triggered when specific HTML constructs are encountered
|
||||
during the compilation process. The directives can be placed in element names, attributes, class
|
||||
names, as well as comments. Here are some equivalent examples of invoking the {@link
|
||||
api/ng.directive:ngBind `ng-bind`} directive.
|
||||
|
||||
<pre>
|
||||
@@ -59,7 +58,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
|
||||
<!-- directive: ng-bind exp -->
|
||||
</pre>
|
||||
|
||||
Directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
||||
A directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
||||
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
|
||||
to write directives.
|
||||
|
||||
@@ -70,8 +69,8 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||
<file name="script.js">
|
||||
angular.module('drag', []).
|
||||
directive('draggable', function($document) {
|
||||
var startX=0, startY=0, x = 0, y = 0;
|
||||
return function(scope, element, attr) {
|
||||
var startX = 0, startY = 0, x = 0, y = 0;
|
||||
element.css({
|
||||
position: 'relative',
|
||||
border: '1px solid red',
|
||||
@@ -79,6 +78,8 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||
cursor: 'pointer'
|
||||
});
|
||||
element.bind('mousedown', function(event) {
|
||||
// Prevent default dragging of selected content
|
||||
event.preventDefault();
|
||||
startX = event.screenX - x;
|
||||
startY = event.screenY - y;
|
||||
$document.bind('mousemove', mousemove);
|
||||
@@ -107,9 +108,9 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||
</example>
|
||||
|
||||
|
||||
The presence of `draggable` attribute on any element gives the element new behavior. The beauty of
|
||||
The presence of the `draggable` attribute on any element gives the element new behavior. The beauty of
|
||||
this approach is that we have taught the browser a new trick. We have extended the vocabulary of
|
||||
what the browser understands in a way, which is natural to anyone who is familiar with HTML
|
||||
what the browser understands in a way which is natural to anyone who is familiar with HTML
|
||||
principles.
|
||||
|
||||
|
||||
@@ -122,7 +123,7 @@ an element.
|
||||
<img src="img/One_Way_Data_Binding.png">
|
||||
|
||||
This means that any changes to the data need to be re-merged with the template and then
|
||||
`innerHTML`ed into the DOM. Some of the issues are: reading user input and merging it with data,
|
||||
`innerHTML`ed into the DOM. Some of the issues with this approach are: reading user input and merging it with data,
|
||||
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
|
||||
expressiveness.
|
||||
|
||||
|
||||
@@ -26,20 +26,20 @@ This is how we get the ball rolling (refer to the diagram and example below):
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
|
||||
|
||||
1. Browser loads the HTML and parses it into a DOM
|
||||
2. Browser loads `angular.js` script
|
||||
1. The browser loads the HTML and parses it into a DOM
|
||||
2. The browser loads `angular.js` script
|
||||
3. Angular waits for `DOMContentLoaded` event
|
||||
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
|
||||
{@link guide/directive directive}, which designates application boundary
|
||||
5. {@link guide/module Module} specified in {@link
|
||||
{@link guide/directive directive}, which designates the application boundary
|
||||
5. The {@link guide/module Module} specified in {@link
|
||||
api/ng.directive:ngApp ng-app} (if any) is used to configure
|
||||
the {@link api/AUTO.$injector $injector}
|
||||
6. {@link api/AUTO.$injector $injector} is used to create the {@link
|
||||
6. The {@link api/AUTO.$injector $injector} is used to create the {@link
|
||||
api/ng.$compile $compile} service as well as {@link
|
||||
api/ng.$rootScope $rootScope}
|
||||
7. {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||
7. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||
it with {@link api/ng.$rootScope $rootScope}
|
||||
8. {@link api/ng.directive:ngInit ng-init} {@link
|
||||
8. The {@link api/ng.directive:ngInit ng-init} {@link
|
||||
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
|
||||
scope}
|
||||
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
|
||||
@@ -59,22 +59,22 @@ This is how we get the ball rolling (refer to the diagram and example below):
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
|
||||
|
||||
The diagram and the example below describe how Angular interacts with browser's event loop.
|
||||
The diagram and the example below describe how Angular interacts with the browser's event loop.
|
||||
|
||||
1. Browsers event-loop waits for an event to arrive. Event is a user interactions, timer event,
|
||||
1. The browser's event-loop waits for an event to arrive. An event is a user interaction, timer event,
|
||||
or network event (response from a server).
|
||||
2. The events callback gets executed. This enters the JavaScript context. The callback can
|
||||
2. The event's callback gets executed. This enters the JavaScript context. The callback can
|
||||
modify the DOM structure.
|
||||
3. Once the callback finishes execution, the browser leaves the JavaScript context and
|
||||
3. Once the callback executes, the browser leaves the JavaScript context and
|
||||
re-renders the view based on DOM changes.
|
||||
|
||||
Angular modifies the normal JavaScript flow by providing it's own event processing loop. This
|
||||
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
|
||||
splits the JavaScript into classical and Angular execution context. Only operations which are
|
||||
applied in Angular execution context will benefit from angular data-binding, exception handling,
|
||||
property watching, etc... Use $apply() to enter Angular execution context from JavaScript. Keep in
|
||||
mind that in most places (controllers, services) the $apply has already been called for you by the
|
||||
directive which is handling the event. The need to call $apply is reserved only when
|
||||
implementing custom event callbacks, or when working with a third-party library callbacks.
|
||||
applied in Angular execution context will benefit from Angular data-binding, exception handling,
|
||||
property watching, etc... You can also use $apply() to enter Angular execution context from JavaScript. Keep in
|
||||
mind that in most places (controllers, services) $apply has already been called for you by the
|
||||
directive which is handling the event. An explicit call to $apply is needed only when
|
||||
implementing custom event callbacks, or when working with third-party library callbacks.
|
||||
|
||||
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
|
||||
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
|
||||
@@ -89,19 +89,19 @@ implementing custom event callbacks, or when working with a third-party library
|
||||
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
|
||||
$watch} list does not detect any changes.
|
||||
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
|
||||
schedule work which needs to occur outside of current stack frame, but before the browser
|
||||
schedule work which needs to occur outside of current stack frame, but before the browser's
|
||||
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
|
||||
suffers from slowness and may cause view flickering since the browser renders the view after
|
||||
each event.
|
||||
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
|
||||
which may have changed since last iteration. If a change is detected then the `$watch`
|
||||
function is called which typically updates the DOM with the new value.
|
||||
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
|
||||
6. Once the Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
|
||||
the execution leaves the Angular and JavaScript context. This is followed by the browser
|
||||
re-rendering the DOM to reflect any changes.
|
||||
|
||||
|
||||
Here is the explanation of how the `Hello wold` example achieves the data-binding effect when the
|
||||
Here is the explanation of how the `Hello world` example achieves the data-binding effect when the
|
||||
user enters text into the text field.
|
||||
|
||||
1. During the compilation phase:
|
||||
@@ -143,8 +143,8 @@ provides the execution context for expressions. The scopes are nested in a hiera
|
||||
which closely follow the DOM structure. (See individual directive documentation to see which
|
||||
directives cause a creation of new scopes.)
|
||||
|
||||
The following example demonstrates how `name` {@link guide/expression expression} will evaluate
|
||||
into different value depending on which scope it is evaluated in. The example is followed by
|
||||
The following example demonstrates how the `name` {@link guide/expression expression} will evaluate
|
||||
into a different value depending on which scope it is evaluated in. The example is followed by
|
||||
a diagram depicting the scope boundaries.
|
||||
|
||||
<div class="clear">
|
||||
@@ -188,7 +188,7 @@ a diagram depicting the scope boundaries.
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
|
||||
|
||||
Controller is the code behind the view. Its job is to construct the model and publish it to the
|
||||
A controller is the code behind the view. Its job is to construct the model and publish it to the
|
||||
view along with callback methods. The view is a projection of the scope onto the template (the
|
||||
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
|
||||
controller.
|
||||
@@ -232,9 +232,9 @@ The separation of the controller and the view is important because:
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
|
||||
|
||||
The model is the data which is used merged with the template to produce the view. To be able to
|
||||
render the model into the view, the model has to be referenceable from the scope. Unlike many
|
||||
other frameworks Angular makes no restrictions or requirements an the model. There are no classes
|
||||
The model is the data which is merged with the template to produce the view. To be able to
|
||||
render the model into the view, the model has to be able to be referenced from the scope. Unlike many
|
||||
other frameworks Angular makes no restrictions or requirements on the model. There are no classes
|
||||
to inherit from or special accessor methods for accessing or changing the model. The model can be
|
||||
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
|
||||
|
||||
@@ -248,9 +248,9 @@ primitive, object hash, or a full object Type. In short the model is a plain Jav
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
||||
|
||||
The view is what the users sees. The view begins its life as a template, it is merged with the
|
||||
The view is what the user sees. The view begins its life as a template, is merged with the
|
||||
model and finally rendered into the browser DOM. Angular takes a very different approach to
|
||||
rendering the view, to most other templating systems.
|
||||
rendering the view compared to most other templating systems.
|
||||
|
||||
* **Others** - Most templating systems begin as an HTML string with special templating markup.
|
||||
Often the template markup breaks the HTML syntax which means that the template can not be
|
||||
@@ -261,9 +261,9 @@ rendering the view, to most other templating systems.
|
||||
is the granularity of the DOM updates. The key here is that the templating system manipulates
|
||||
strings.
|
||||
* **Angular** - Angular is different, since its templating system works on DOM objects not on
|
||||
strings. The template is still written in HTML string, but it is HTML (not HTML with
|
||||
template sprinkled in.) The browser parses the HTML into DOM, and the DOM becomes the input to
|
||||
the template engine know as the {@link api/ng.$compile compiler}. The compiler
|
||||
strings. The template is still written in an HTML string, but it is HTML (not HTML with
|
||||
template sprinkled in.) The browser parses the HTML into the DOM, and the DOM becomes the input to
|
||||
the template engine known as the {@link api/ng.$compile compiler}. The compiler
|
||||
looks for {@link guide/directive directives} which in turn set up {@link
|
||||
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
|
||||
continuously updating view which does not need template model re-merging. Your model becomes
|
||||
@@ -291,8 +291,8 @@ rendering the view, to most other templating systems.
|
||||
<a name="directives"></a>
|
||||
# Directives
|
||||
|
||||
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute,
|
||||
element name, or a class name. A directive allows you to extend the HTML vocabulary in a
|
||||
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
|
||||
element name, class name or comment. A directive allows you to extend the HTML vocabulary in a
|
||||
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
|
||||
in HTML.
|
||||
|
||||
@@ -310,7 +310,7 @@ in HTML.
|
||||
});
|
||||
|
||||
// model -> view
|
||||
ctrl.render = function(value) {
|
||||
ctrl.$render = function(value) {
|
||||
elm.html(value);
|
||||
};
|
||||
|
||||
@@ -337,7 +337,7 @@ in HTML.
|
||||
<a name="filters"></a>
|
||||
# Filters
|
||||
|
||||
{@link api/ng.$filter Filters} perform data transformation roles. Typically
|
||||
{@link api/ng.$filter Filters} perform data transformation. Typically
|
||||
they are used in conjunction with the locale to format the data in locale specific output.
|
||||
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
|
||||
|
||||
@@ -358,7 +358,7 @@ They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||
|
||||
An {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
The {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
{@link api/AUTO.$injector injector} per Angular {@link
|
||||
api/ng.directive:ngApp application}. The {@link
|
||||
api/AUTO.$injector injector} provides a way to look up an object instance by its
|
||||
@@ -425,7 +425,7 @@ function arguments. When angular calls the function, it will use the {@link
|
||||
api/AUTO.$injector#invoke call} which will automatically fill the function
|
||||
arguments.
|
||||
|
||||
Examine the `ClockCtrl` bellow, and notice how it lists the dependencies in the constructor. When the
|
||||
Examine the `ClockCtrl` below, and notice how it lists the dependencies in the constructor. When the
|
||||
{@link api/ng.directive:ngController ng-controller} instantiates
|
||||
the controller it automatically provides the dependencies. There is no need to create
|
||||
dependencies, look for dependencies, or even get a reference to the injector.
|
||||
@@ -438,7 +438,7 @@ dependencies, look for dependencies, or even get a reference to the injector.
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('timeExampleModule', []).
|
||||
// Declare new object call time,
|
||||
// Declare new object called time,
|
||||
// which will be available for injection
|
||||
factory('time', function($timeout) {
|
||||
var time = {};
|
||||
|
||||
@@ -11,7 +11,7 @@ that will help you verify the health of your Angular application.
|
||||
|
||||
# Overview
|
||||
You will write scenario tests in JavaScript, which describe how your application should behave,
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more it blocks
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more `it` blocks
|
||||
(you can think of these as the requirements of your application), which in turn are made of
|
||||
**commands** and **expectations**. Commands tell the Runner to do something with the application
|
||||
(such as navigate to a page or click on a button), and expectations tell the Runner to assert
|
||||
@@ -97,7 +97,8 @@ the test frame.
|
||||
Asserts the value of the given `future` satisfies the `matcher`. All API statements return a
|
||||
`future` object, which get a `value` assigned after they are executed. Matchers are defined using
|
||||
`angular.scenario.matcher`, and they use the value of futures to run the expectation. For example:
|
||||
`expect(browser().location().href()).toEqual('http://www.google.com')`
|
||||
`expect(browser().location().href()).toEqual('http://www.google.com')`. Available matchers
|
||||
are presented further down this document.
|
||||
|
||||
## expect(future).not().{matcher}
|
||||
Asserts the value of the given `future` satisfies the negation of the `matcher`.
|
||||
@@ -109,16 +110,16 @@ Scopes the next DSL element selection.
|
||||
Returns the value of the first binding matching the given `name`.
|
||||
|
||||
## input(name).enter(value)
|
||||
Enters the given `value` in the text field with the given `name`.
|
||||
Enters the given `value` in the text field with the corresponding ng-model `name`.
|
||||
|
||||
## input(name).check()
|
||||
Checks/unchecks the checkbox with the given `name`.
|
||||
Checks/unchecks the checkbox with the corresponding ng-model `name`.
|
||||
|
||||
## input(name).select(value)
|
||||
Selects the given `value` in the radio button with the given `name`.
|
||||
Selects the given `value` in the radio button with the corresponding ng-model `name`.
|
||||
|
||||
## input(name).val()
|
||||
Returns the current value of an input field with the given `name`.
|
||||
Returns the current value of an input field with the corresponding ng-model `name`.
|
||||
|
||||
## repeater(selector, label).count()
|
||||
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
|
||||
@@ -135,7 +136,7 @@ the given jQuery `selector`. The `label` is used for test output.
|
||||
## select(name).option(value)
|
||||
Picks the option with the given `value` on the select with the given `name`.
|
||||
|
||||
## select(name).option(value1, value2...)
|
||||
## select(name).options(value1, value2...)
|
||||
Picks the options with the given `values` on the multi select with the given `name`.
|
||||
|
||||
## element(selector, label).count()
|
||||
@@ -175,4 +176,133 @@ Executes the `method` passing in `key` and `value` on the element matching the g
|
||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
||||
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not do it.
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
# Matchers
|
||||
|
||||
Matchers are used in combination with the `expect(...)` function as described above and can
|
||||
be negated with `not()`. For instance: `expect(element('h1').text()).not().toEqual('Error')`.
|
||||
|
||||
Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js}
|
||||
|
||||
<pre>
|
||||
// value and Object comparison following the rules of angular.equals().
|
||||
expect(value).toEqual(value)
|
||||
|
||||
// a simpler value comparison using ===
|
||||
expect(value).toBe(value)
|
||||
|
||||
// checks that the value is defined by checking its type.
|
||||
expect(value).toBeDefined()
|
||||
|
||||
// the following two matchers are using JavaScript's standard truthiness rules
|
||||
expect(value).toBeTruthy()
|
||||
expect(value).toBeFalsy()
|
||||
|
||||
// verify that the value matches the given regular expression. The regular
|
||||
// expression may be passed in form of a string or a regular expression
|
||||
// object.
|
||||
expect(value).toMatch(expectedRegExp)
|
||||
|
||||
// a check for null using ===
|
||||
expect(value).toBeNull()
|
||||
|
||||
// Array.indexOf(...) is used internally to check whether the element is
|
||||
// contained within the array.
|
||||
expect(value).toContain(expected)
|
||||
|
||||
// number comparison using < and >
|
||||
expect(value).toBeLessThan(expected)
|
||||
expect(value).toBeGreaterThan(expected)
|
||||
</pre>
|
||||
|
||||
# Example
|
||||
See the {@link https://github.com/angular/angular-seed angular-seed} project for more examples.
|
||||
|
||||
## Conditional actions with element(...).query(fn)
|
||||
|
||||
E2E testing with angular scenario is highly asynchronous and hides a lot of complexity by
|
||||
queueing actions and expectations that can handle futures. From time to time, you might need
|
||||
conditional assertions or element selection. Even though you should generally try to avoid this
|
||||
(as it is can be sign for unstable tests), you can add conditional behavior with
|
||||
`element(...).query(fn)`. The following code listing shows how this function can be used to delete
|
||||
added entries (where an entry is some domain object) using the application's web interface.
|
||||
|
||||
Imagine the application to be structured into two views:
|
||||
|
||||
1. *Overview view* which lists all the added entries in a table and
|
||||
2. a *detail view* which shows the entries' details and contains a delete button. When clicking the
|
||||
delete button, the user is redirected back to the *overview page*.
|
||||
|
||||
<pre>
|
||||
beforeEach(function () {
|
||||
var deleteEntry = function () {
|
||||
browser().navigateTo('/entries');
|
||||
|
||||
// we need to select the <tbody> element as it might be the case that there
|
||||
// are no entries (and therefore no rows). When the selector does not
|
||||
// result in a match, the test would be marked as a failure.
|
||||
element('table tbody').query(function (tbody, done) {
|
||||
// ngScenario gives us a jQuery lite wrapped element. We call the
|
||||
// `children()` function to retrieve the table body's rows
|
||||
var children = tbody.children();
|
||||
|
||||
if (children.length > 0) {
|
||||
// if there is at least one entry in the table, click on the link to
|
||||
// the entry's detail view
|
||||
element('table tbody a').click();
|
||||
// and, after a route change, click the delete button
|
||||
element('.btn-danger').click();
|
||||
}
|
||||
|
||||
// if there is more than one entry shown in the table, queue another
|
||||
// delete action.
|
||||
if (children.length > 1) {
|
||||
deleteEntry();
|
||||
}
|
||||
|
||||
// remember to call `done()` so that ngScenario can continue
|
||||
// test execution.
|
||||
done();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// start deleting entries
|
||||
deleteEntry();
|
||||
});
|
||||
</pre>
|
||||
|
||||
In order to understand what is happening, we should emphasize that ngScenario calls are not
|
||||
immediately executed, but queued (in ngScenario terms, we would be talking about adding
|
||||
future actions). If we had only one entry in our table, than the following future actions
|
||||
would be queued:
|
||||
|
||||
<pre>
|
||||
// delete entry 1
|
||||
browser().navigateTo('/entries');
|
||||
element('table tbody').query(function (tbody, done) { ... });
|
||||
element('table tbody a');
|
||||
element('.btn-danger').click();
|
||||
</pre>
|
||||
|
||||
For two entries, ngScenario would have to work on the following queue:
|
||||
|
||||
<pre>
|
||||
// delete entry 1
|
||||
browser().navigateTo('/entries');
|
||||
element('table tbody').query(function (tbody, done) { ... });
|
||||
element('table tbody a');
|
||||
element('.btn-danger').click();
|
||||
|
||||
// delete entry 2
|
||||
// indented to represent "recursion depth"
|
||||
browser().navigateTo('/entries');
|
||||
element('table tbody').query(function (tbody, done) { ... });
|
||||
element('table tbody a');
|
||||
element('.btn-danger').click();
|
||||
</pre>
|
||||
|
||||
# Caveats
|
||||
|
||||
ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
@description
|
||||
|
||||
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
|
||||
first appeared, angular incorporates the basic principles behind the original {@link
|
||||
first appeared, Angular incorporates the basic principles behind the original {@link
|
||||
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
||||
building client-side web applications.
|
||||
|
||||
The MVC pattern greatly summarized:
|
||||
The MVC pattern summarized:
|
||||
|
||||
* Separate applications into distinct presentation, data, and logic components
|
||||
* Encourage loose coupling between these components
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
||||
@description
|
||||
|
||||
In angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
||||
angular {@link scope Scope}, excluding the root scope. When you or angular create a new
|
||||
child scope object via the {@link api/ng.$rootScope.Scope#$new scope.$new} API , there is an
|
||||
option to pass in a controller as a method argument. This will tell angular to associate the
|
||||
controller with the new scope and to augment its behavior.
|
||||
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
||||
angular {@link scope Scope}, excluding the root scope.
|
||||
|
||||
Use controllers to:
|
||||
|
||||
@@ -15,24 +12,42 @@ Use controllers to:
|
||||
|
||||
# Setting up the initial state of a scope object
|
||||
|
||||
Typically, when you create an application you need to set up an initial state for an angular scope.
|
||||
Typically, when you create an application you need to set up an initial state for an Angular scope.
|
||||
|
||||
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
|
||||
to a new angular scope object, which sets up an initial scope state. This means that angular never
|
||||
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
|
||||
creates instances of the controller type (by invoking the `new` operator on the controller
|
||||
constructor). Constructors are always applied to an existing scope object.
|
||||
|
||||
You set up the initial state of a scope by creating model properties. For example:
|
||||
|
||||
function GreetingCtrl($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
<pre>
|
||||
function GreetingCtrl($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
</pre>
|
||||
|
||||
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
||||
|
||||
**NOTE**: Many of the examples in the documentation show the creation of functions
|
||||
in the global scope. This is only for demonstration purposes - in a real
|
||||
application you should use the `.controller` method of your Angular module for
|
||||
your application as follows:
|
||||
|
||||
<pre>
|
||||
var myApp = angular.module('myApp',[]);
|
||||
|
||||
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
Note also that we use the array notation to explicitly specify the dependency
|
||||
of the controller on the `$scope` service provided by Angular.
|
||||
|
||||
# Adding Behavior to a Scope Object
|
||||
|
||||
Behavior on an angular scope object is in the form of scope method properties available to the
|
||||
Behavior on an Angular scope object is in the form of scope method properties available to the
|
||||
template/view. This behavior interacts with and modifies the application model.
|
||||
|
||||
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
||||
@@ -55,21 +70,19 @@ Do not use controllers for:
|
||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
||||
manipulation—the presentation logic of an application—is well known for being hard to test.
|
||||
Putting any presentation logic into controllers significantly affects testability of the business
|
||||
logic. Angular offers {@link dev_guide.templates.databinding} for automatic DOM manipulation. If
|
||||
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
|
||||
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||
{@link guide/directive directives}.
|
||||
- Input formatting — Use {@link forms angular form controls} instead.
|
||||
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
|
||||
- Run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
|
||||
- Sharing stateless or stateful code across controllers — Use {@link dev_guide.services angular
|
||||
services} instead.
|
||||
- Instantiate or manage the life-cycle of other components (for example, to create service
|
||||
instances).
|
||||
- Managing the life-cycle of other components (for example, to create service instances).
|
||||
|
||||
|
||||
# Associating Controllers with Angular Scope Objects
|
||||
|
||||
You can associate controllers with scope objects explicitly via the {@link api/ng.$rootScope.Scope#$new
|
||||
scope.$new} api or implicitly via the {@link api/ng.directive:ngController ngController
|
||||
You can associate controllers with scope objects implicitly via the {@link api/ng.directive:ngController ngController
|
||||
directive} or {@link api/ng.$route $route service}.
|
||||
|
||||
|
||||
@@ -157,15 +170,16 @@ input box) in the second button.
|
||||
|
||||
## Controller Inheritance Example
|
||||
|
||||
Controller inheritance in angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
|
||||
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
|
||||
have a look at an example:
|
||||
|
||||
<pre>
|
||||
<body ng-controller="MainCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
<div ng-controller="ChildCtrl">
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
function MainCtrl($scope) {
|
||||
@@ -197,7 +211,7 @@ Inheritance works between controllers in the same way as it does with models. So
|
||||
examples, all of the models could be replaced with controller methods that return string values.
|
||||
|
||||
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
|
||||
because as we mentioned earlier, controllers are not instantiated directly by angular, but rather
|
||||
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
|
||||
are applied to the scope object.
|
||||
|
||||
|
||||
@@ -241,8 +255,8 @@ describe('myController function', function() {
|
||||
</pre>
|
||||
|
||||
|
||||
If you need to test a nested controller one needs to create the same scope hierarchy
|
||||
in your test as exist in the DOM.
|
||||
If you need to test a nested controller you need to create the same scope hierarchy
|
||||
in your test that exists in the DOM.
|
||||
|
||||
<pre>
|
||||
describe('state', function() {
|
||||
@@ -253,7 +267,7 @@ describe('state', function() {
|
||||
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
||||
childScope = mainScope.$new();
|
||||
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
||||
babyScope = childCtrl.$new();
|
||||
babyScope = childScope.$new();
|
||||
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
||||
}));
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
||||
@description
|
||||
|
||||
Depending on the context of the discussion in angular documentation, the term _model_ can refer to
|
||||
Depending on the context of the discussion in the Angular documentation, the term _model_ can refer to
|
||||
either a single object representing one entity (for example, a model called "phones" with its value
|
||||
being an array of phones) or the entire data model for the application (all entities).
|
||||
|
||||
In angular, a model is any data that is reachable as a property of an angular {@link
|
||||
In Angular, a model is any data that is reachable as a property of an angular {@link
|
||||
scope Scope} object. The name of the property is the model identifier and the value is
|
||||
any JavaScript object (including arrays and primitives).
|
||||
|
||||
The only requirement for a JavaScript object to be a model in angular is that the object must be
|
||||
referenced by an angular scope as a property of that scope object. This property reference can be
|
||||
The only requirement for a JavaScript object to be a model in Angular is that the object must be
|
||||
referenced by an Angular scope as a property of that scope object. This property reference can be
|
||||
created explicitly or implicitly.
|
||||
|
||||
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
||||
@@ -28,7 +28,7 @@ occurs in controllers:
|
||||
|
||||
* Use an {@link expression angular expression} with an assignment operator in templates:
|
||||
|
||||
<button ng-click="{{foos='ball'}}">Click me</button>
|
||||
<button ng-click="{{foo='bar'}}">Click me</button>
|
||||
|
||||
* Use {@link api/ng.directive:ngInit ngInit directive} in templates (for toy/example apps
|
||||
only, not recommended for real applications):
|
||||
@@ -52,11 +52,11 @@ cloud".
|
||||
The code above creates one child scope for each item in the "phones" array and creates a "phone"
|
||||
object (model) on each of these scopes with its value set to the value of "phone" in the array.
|
||||
|
||||
In angular, a JavaScript object stops being a model when:
|
||||
In Angular, a JavaScript object stops being a model when:
|
||||
|
||||
* No angular scope contains a property that references the object.
|
||||
* No Angular scope contains a property that references the object.
|
||||
|
||||
* All angular scopes that contain a property referencing the object become stale and eligible for
|
||||
* All Angular scopes that contain a property referencing the object become stale and eligible for
|
||||
garbage collection.
|
||||
|
||||
The following illustration shows a simple data model created implicitly from a simple template:
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
||||
@description
|
||||
|
||||
In angular, the view is the DOM loaded and rendered in the browser, after angular has transformed
|
||||
In Angular, the view is the DOM loaded and rendered in the browser, after Angular has transformed
|
||||
the DOM based on information in the template, controller and model.
|
||||
|
||||
<img src="img/guide/about_view_final.png">
|
||||
|
||||
In the angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||
In the Angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
|
||||
controller through angular directives, such as {@link api/ng.directive:ngController
|
||||
controller through Angular directives, such as {@link api/ng.directive:ngController
|
||||
ngController} and {@link api/ng.directive:ngView ngView}, and through bindings of this form:
|
||||
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
|
||||
controller function.
|
||||
|
||||
@@ -73,10 +73,9 @@ Any time your application needs to react to a change in the current URL or if yo
|
||||
the current URL in the browser.
|
||||
|
||||
## What does it not do?
|
||||
Does not cause a full page reload when the browser URL is changed. To reload the page after
|
||||
It does not cause a full page reload when the browser URL is changed. To reload the page after
|
||||
changing the URL, use the lower-level API, `$window.location.href`.
|
||||
|
||||
|
||||
# General overview of the API
|
||||
|
||||
The `$location` service can behave differently, depending on the configuration that was provided to
|
||||
@@ -99,7 +98,7 @@ To configure the `$location` service, retrieve the
|
||||
|
||||
- **hashPrefix(prefix)**: {string}<br />
|
||||
prefix used for Hashbang URLs (used in Hashbang mode or in legacy browser in Html5 mode)<br />
|
||||
default: `'!'`
|
||||
default: `""`
|
||||
|
||||
### Example configuration
|
||||
<pre>
|
||||
@@ -133,12 +132,12 @@ current URL without creating a new browser history record you can call:
|
||||
// or you can chain these as: $location.path('/someNewPath').replace();
|
||||
</pre>
|
||||
|
||||
Note that the setters don't update `window.location` immediately. Instead, `$location` service is
|
||||
Note that the setters don't update `window.location` immediately. Instead, the `$location` service is
|
||||
aware of the {@link api/ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location`
|
||||
mutations into one "commit" to the `window.location` object during the scope `$digest` phase. Since
|
||||
multiple changes to the $location's state will be pushed to the browser as a single change, it's
|
||||
enough to call the `replace()` method just once to make the entire "commit" a replace operation
|
||||
rather than addition to the browser history. Once the browser is updated, the $location service
|
||||
rather than an addition to the browser history. Once the browser is updated, the $location service
|
||||
resets the flag set by `replace()` method and future mutations will create new history records,
|
||||
unless `replace()` is called again.
|
||||
|
||||
@@ -212,8 +211,8 @@ In this mode, `$location` uses Hashbang URLs in all browsers.
|
||||
<pre>
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5mode = false;
|
||||
$locationProvider.hashPrefix = '!';
|
||||
$locationProvider.html5Mode(false);
|
||||
$locationProvider.hashPrefix('!');
|
||||
},
|
||||
function($location) {
|
||||
// open http://host.com/base/index.html#!/a
|
||||
@@ -261,8 +260,8 @@ having to worry about whether the browser displaying your app supports the histo
|
||||
<pre>
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5mode = true;
|
||||
$locationProvider.hashPrefix = '!';
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix('!');
|
||||
},
|
||||
function($location) {
|
||||
// in browser with HTML5 history support:
|
||||
@@ -304,7 +303,7 @@ history API or not; the `$location` service makes this transparent to you.
|
||||
|
||||
### Html link rewriting
|
||||
|
||||
When you use the history API mode, you will need different links in different browser, but all you
|
||||
When you use HTML5 history API mode, you will need different links in different browsers, but all you
|
||||
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||
|
||||
When a user clicks on this link,
|
||||
@@ -620,21 +619,25 @@ to the $location object (using {@link api/ng.directive:input.text
|
||||
ngModel} directive on an input field), you will need to specify an extra model property
|
||||
(e.g. `locationPath`) with two watchers which push $location updates in both directions. For
|
||||
example:
|
||||
<pre>
|
||||
<!-- html -->
|
||||
<input type="text" ng-model="locationPath" />
|
||||
</pre>
|
||||
<pre>
|
||||
// js - controller
|
||||
$scope.$watch('locationPath', function(path) {
|
||||
$location.path(path);
|
||||
});
|
||||
|
||||
$scope.$watch('$location.path()', function(path) {
|
||||
scope.locationPath = path;
|
||||
});
|
||||
</pre>
|
||||
|
||||
<example>
|
||||
<file name="index.html">
|
||||
<div ng-controller="LocationController">
|
||||
<input type="text" ng-model="locationPath" />
|
||||
</div>
|
||||
</file>
|
||||
<file name="script.js">
|
||||
function LocationController($scope, $location) {
|
||||
$scope.$watch('locationPath', function(path) {
|
||||
$location.path(path);
|
||||
});
|
||||
$scope.$watch(function() {
|
||||
return $location.path();
|
||||
}, function(path) {
|
||||
$scope.locationPath = path;
|
||||
});
|
||||
}
|
||||
</file>
|
||||
</example>
|
||||
|
||||
# Related API
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ create this instance when called.
|
||||
|
||||
# Dependencies
|
||||
|
||||
Services can not only be depended upon, but also have its own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about the DI
|
||||
in Angular and the use of array notation and $inject property to make DI annotation
|
||||
Services can not only be depended upon, but can also have their own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
|
||||
in Angular and the use of array notation and the $inject property to make DI annotation
|
||||
minification-proof.
|
||||
|
||||
Following is an example of a very simple service. This service depends on the `$window` service
|
||||
@@ -78,7 +78,7 @@ angular.module('myModule', [], function($provide) {
|
||||
|
||||
All services in Angular are instantiated lazily. This means that a service will be created
|
||||
only when it is needed for instantiation of a service or an application component that depends on it.
|
||||
In other words, Angular won't instantiate lazy services unless they are requested directly or
|
||||
In other words, Angular won't instantiate services unless they are requested directly or
|
||||
indirectly by the application.
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ myController.$inject = ['$scope','notify'];
|
||||
<p>Let's try this simple notify service, injected into the controller...</p>
|
||||
<input ng-init="message='test'" ng-model="message" >
|
||||
<button ng-click="callNotify(message);">NOTIFY</button>
|
||||
<p>(you have to click 3 times to see an alert)</p>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
@@ -98,6 +99,7 @@ function myController($scope, notify) {
|
||||
<p>Let's try the notify service, that is implicitly injected into the controller...</p>
|
||||
<input ng-init="message='test'" ng-model="message">
|
||||
<button ng-click="callNotify(message);">NOTIFY</button>
|
||||
<p>(you have to click 3 times to see an alert)</p>
|
||||
</div>
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
|
||||
@@ -39,8 +39,8 @@ function myModuleCfgFn($provide) {
|
||||
</pre>
|
||||
|
||||
|
||||
Here is an example of two services that depend on each other, as well as on other services that are
|
||||
provided by Angular's web framework:
|
||||
Here is an example of two services, one of which depends on the other and both
|
||||
of which depend on other services that are provided by the Angular framework:
|
||||
|
||||
<pre>
|
||||
/**
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
@name Developer Guide: Angular Services
|
||||
@description
|
||||
|
||||
Services are a feature that angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}. Services are
|
||||
most often used with {@link di dependency injection}, also a key feature of angular apps.
|
||||
Services are a feature that Angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in Angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
@@ -6,9 +6,9 @@ Angular services are singletons that carry out specific tasks common to web apps
|
||||
{@link api/ng.$http $http service} that provides low level access to the browser's
|
||||
`XMLHttpRequest` object.
|
||||
|
||||
To use an angular service, you identify it as a dependency for the dependent (a controller, or
|
||||
To use an Angular service, you identify it as a dependency for the dependent (a controller, or
|
||||
another service) that depends on the service. Angular's dependency injection subsystem takes care
|
||||
of the rest. The angular injector subsystem is in charge of service instantiation, resolution of
|
||||
of the rest. The Angular injector subsystem is in charge of service instantiation, resolution of
|
||||
dependencies, and provision of dependencies to factory functions as requested.
|
||||
|
||||
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
|
||||
@@ -18,7 +18,7 @@ must explicitly define its dependencies by using the `$inject` property. For ex
|
||||
|
||||
myController.$inject = ['$location'];
|
||||
|
||||
The angular web framework provides a set of services for common operations. Like other core angular
|
||||
The Angular web framework provides a set of services for common operations. Like other core Angular
|
||||
variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
|
||||
above). You can also create your own custom services.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
@name Developer Guide: Templates: Data Binding in Angular
|
||||
@description
|
||||
|
||||
Data-binding in angular web apps is the automatic syncing of data between the model and view
|
||||
components. The way that angular implements data-binding lets you treat the model as the
|
||||
Data-binding in Angular web apps is the automatic syncronization of data between the model and view
|
||||
components. The way that Angular implements data-binding lets you treat the model as the
|
||||
single-source-of-truth in your application. The view is a projection of the model at all times.
|
||||
When the model changes, the view reflects the change, and vice versa.
|
||||
|
||||
@@ -19,7 +19,7 @@ to write code that constantly syncs the view with the model and the model with t
|
||||
## Data Binding in Angular Templates
|
||||
|
||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
||||
The way angular templates works is different, as illustrated in the diagram. They are different
|
||||
The way Angular templates works is different, as illustrated in the diagram. They are different
|
||||
because first the template (which is the uncompiled HTML along with any additional markup or
|
||||
directives) is compiled on the browser, and second, the compilation step produces a live view. We
|
||||
say live because any changes to the view are immediately reflected in the model, and any changes in
|
||||
|
||||
@@ -8,7 +8,7 @@ as the first argument. Any filter arguments are passed in as additional argument
|
||||
function.
|
||||
|
||||
The following sample filter reverses a text string. In addition, it conditionally makes the
|
||||
text upper-case and assigns color.
|
||||
text upper-case.
|
||||
|
||||
<doc:example module="MyReverseModule">
|
||||
<doc:source>
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
@name Developer Guide: Templates: Understanding Angular Filters
|
||||
@description
|
||||
|
||||
Angular filters format data for display to the user. In addition to formatting data, filters can
|
||||
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
|
||||
to filtered output.
|
||||
Angular filters format data for display to the user.
|
||||
|
||||
For example, you might have a data object that needs to be formatted according to the locale before
|
||||
displaying it to the user. You can pass expressions through a chain of filters like this:
|
||||
|
||||
@@ -19,6 +19,10 @@ You can also pass colon-delimited arguments to filters, for example, to display
|
||||
|
||||
123 | number:2
|
||||
|
||||
Use the same syntax for multiple arguments:
|
||||
|
||||
myArray | orderBy:'timestamp':true
|
||||
|
||||
Here are some examples that show values before and after applying different filters to an
|
||||
expression in a binding:
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
@name Developer Guide: Understanding Angular Templates
|
||||
@description
|
||||
|
||||
An angular template is the declarative specification that, along with information from the model
|
||||
An Angular template is the declarative specification that, along with information from the model
|
||||
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
|
||||
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
|
||||
angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||
Angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||
the dynamic view DOM.
|
||||
|
||||
These are the types of angular elements and element attributes you can use in a template:
|
||||
These are the types of Angular elements and element attributes you can use in a template:
|
||||
|
||||
* {@link guide/directive Directive} — An attribute or element that
|
||||
augments an existing DOM element or represents a reusable DOM component - a widget.
|
||||
@@ -20,8 +20,8 @@ curly brace notation `{{ }}` to bind expressions to elements is built-in angular
|
||||
Note: In addition to declaring the elements above in templates, you can also access these elements
|
||||
in JavaScript code.
|
||||
|
||||
The following code snippet shows a simple angular template made up of standard HTML tags along with
|
||||
angular {@link guide/directive directives} and curly-brace bindings
|
||||
The following code snippet shows a simple Angular template made up of standard HTML tags along with
|
||||
Angular {@link guide/directive directives} and curly-brace bindings
|
||||
with {@link expression expressions}:
|
||||
|
||||
<pre>
|
||||
|
||||
@@ -3,37 +3,49 @@
|
||||
@description
|
||||
|
||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
||||
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
||||
comes with almost no help from the compiler. For this reason we feel very strongly that any code
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not do it.
|
||||
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
# It is all about NOT mixing concerns
|
||||
|
||||
Unit testing as the name implies is about testing individual units of code. Unit tests try to
|
||||
answer the question: Did I think about the logic correctly. Does the sort function order the list
|
||||
in the right order. In order to answer such question it is very important that we can isolate it.
|
||||
That is because when we are testing the sort function we don't want to be forced into crating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort. While
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order the list
|
||||
in the right order?"
|
||||
|
||||
In order to answer such question it is very important that we can isolate the unit of code under test.
|
||||
That is because when we are testing the sort function we don't want to be forced into creating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.
|
||||
|
||||
While
|
||||
this may seem obvious it usually is very difficult to be able to call an individual function on a
|
||||
typical project. The reason is that the developers often time mix concerns, and they end up with a
|
||||
typical project. The reason is that the developers often mix concerns, and they end up with a
|
||||
piece of code which does everything. It reads the data from XHR, it sorts it and then it
|
||||
manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we
|
||||
manipulates the DOM.
|
||||
|
||||
With Angular we try to make it easy for you to do the right thing, and so we
|
||||
provide dependency injection for your XHR (which you can mock out) and we created abstraction which
|
||||
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
||||
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
||||
apply the function, and assert that the resulting model is in the correct order. The test does not
|
||||
have to wait for XHR, or create the right kind of DOM, or assert that your function has mutated the
|
||||
DOM in the right way. Angular is written with testability in mind, but it still requires that you
|
||||
do the right thing. We tried to make the right thing easy, but angular is not magic, which means if
|
||||
you don't follow these, you may very well end up with an untestable application.
|
||||
DOM in the right way.
|
||||
|
||||
## Dependency Inject
|
||||
## With great power comes great responsibility
|
||||
|
||||
Angular is written with testability in mind, but it still requires that you
|
||||
do the right thing. We tried to make the right thing easy, but Angular is not magic, which means if
|
||||
you don't follow these guidelines you may very well end up with an untestable application.
|
||||
|
||||
## Dependency Injection
|
||||
There are several ways in which you can get a hold of a dependency:
|
||||
1. You could create it using the `new` operator.
|
||||
2. You could look for it in a well know place, also known as global singleton.
|
||||
2. You could look for it in a well known place, also known as global singleton.
|
||||
3. You could ask a registry (also known as service registry) for it. (But how do you get a hold of
|
||||
the registry? Must likely by looking it up in a well know place. See #2)
|
||||
4. You could expect that the it be handed to you.
|
||||
the registry? Most likely by looking it up in a well known place. See #2)
|
||||
4. You could expect that it be handed to you.
|
||||
|
||||
Out of the list above only the last of is testable. Lets look at why:
|
||||
Out of the four options in the list above, only the last one is testable. Let's look at why:
|
||||
|
||||
### Using the `new` operator
|
||||
|
||||
@@ -52,10 +64,10 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||
The issue becomes that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
||||
permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey
|
||||
patching, that is a bad idea for many reasons, which is outside the scope of this document.
|
||||
permanently bound to the actual XHR, and there is no good way to replace it. Yes there is monkey
|
||||
patching. That is a bad idea for many reasons which are outside the scope of this document.
|
||||
|
||||
The class above is hard to test since we have to resort to monkey patching:
|
||||
<pre>
|
||||
@@ -69,7 +81,7 @@ XHR = oldXHR; // if you forget this bad things will happen
|
||||
|
||||
|
||||
### Global look-up:
|
||||
Another way to approach the problem is look for the service in a well known location.
|
||||
Another way to approach the problem is to look for the service in a well known location.
|
||||
|
||||
<pre>
|
||||
function MyClass() {
|
||||
@@ -83,9 +95,9 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
While no new instance of dependency is being created, it is fundamentally the same as `new`, in
|
||||
While no new instance of the dependency is being created, it is fundamentally the same as `new`, in
|
||||
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
|
||||
through monkey patching. The basic issue for testing is that global variable needs to be mutated in
|
||||
through monkey patching. The basic issue for testing is that a global variable needs to be mutated in
|
||||
order to replace it with call to a mock method. For further explanation why this is bad see: {@link
|
||||
http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global
|
||||
State & Singletons}
|
||||
@@ -119,7 +131,7 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
However, where dose the serviceRegistry come from? if it is:
|
||||
However, where does the serviceRegistry come from? if it is:
|
||||
* `new`-ed up, the the test has no chance to reset the services for testing
|
||||
* global look-up, then the service returned is global as well (but resetting is easier, since
|
||||
there is only one global variable to be reset).
|
||||
@@ -164,7 +176,7 @@ myClass.doWork();
|
||||
|
||||
Notice that no global variables were harmed in the writing of this test.
|
||||
|
||||
Angular comes with {@link di dependency-injection} built in which makes the right thing
|
||||
Angular comes with {@link di dependency injection} built in which makes the right thing
|
||||
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||
|
||||
## Controllers
|
||||
@@ -173,7 +185,7 @@ for your application is mixed in with DOM manipulation, it will be hard to test
|
||||
below:
|
||||
|
||||
<pre>
|
||||
function PasswordController() {
|
||||
function PasswordCtrl() {
|
||||
// get references to DOM elements
|
||||
var msg = $('.ex1 span');
|
||||
var input = $('.ex1 input');
|
||||
@@ -197,7 +209,7 @@ function PasswordController() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The code above is problematic from testability, since it requires your test to have the right kind
|
||||
The code above is problematic from a testability point of view, since it requires your test to have the right kind
|
||||
of DOM present when the code executes. The test would look like this:
|
||||
|
||||
<pre>
|
||||
@@ -207,7 +219,7 @@ $('body').html('<div class="ex1">')
|
||||
.find('div')
|
||||
.append(input)
|
||||
.append(span);
|
||||
var pc = new PasswordController();
|
||||
var pc = new PasswordCtrl();
|
||||
input.val('abc');
|
||||
pc.grade();
|
||||
expect(span.text()).toEqual('weak');
|
||||
@@ -218,7 +230,7 @@ In angular the controllers are strictly separated from the DOM manipulation logi
|
||||
a much easier testability story as can be seen in this example:
|
||||
|
||||
<pre>
|
||||
function PasswordCntrl($scope) {
|
||||
function PasswordCtrl($scope) {
|
||||
$scope.password = '';
|
||||
$scope.grade = function() {
|
||||
var size = $scope.password.length;
|
||||
@@ -233,19 +245,19 @@ function PasswordCntrl($scope) {
|
||||
}
|
||||
</pre>
|
||||
|
||||
and the tests is straight forward
|
||||
and the test is straight forward
|
||||
|
||||
<pre>
|
||||
var pc = new PasswordController();
|
||||
pc.password('abc');
|
||||
pc.grade();
|
||||
expect(span.strength).toEqual('weak');
|
||||
var $scope = {};
|
||||
var pc = $controller('PasswordCtrl', { $scope: $scope });
|
||||
$scope.password = 'abc';
|
||||
$scope.grade();
|
||||
expect($scope.strength).toEqual('weak');
|
||||
</pre>
|
||||
|
||||
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
||||
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||
|
||||
|
||||
## Filters
|
||||
{@link api/ng.$filter Filters} are functions which transform the data into user readable
|
||||
format. They are important because they remove the formatting responsibility from the application
|
||||
@@ -264,18 +276,66 @@ expect(length('abc')).toEqual(3);
|
||||
</pre>
|
||||
|
||||
## Directives
|
||||
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
||||
Directives in angular are responsible for encapsulating complex functionality within custom HTML tags,
|
||||
attributes, classes or comments. Unit tests are very important for directives because the components
|
||||
you create with directives may be used throughout your application and in many different contexts.
|
||||
|
||||
### Simple HTML Element Directive
|
||||
|
||||
Lets start with an angular app with no dependencies.
|
||||
|
||||
<pre>
|
||||
var app = angular.module('myApp', []);
|
||||
</pre>
|
||||
|
||||
Now we can add a directive to our app.
|
||||
|
||||
<pre>
|
||||
app.directive('aGreatEye', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
This directive is used as a tag `<a-great-eye></a-great-eye>`. It replaces the entire tag with the
|
||||
template `<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>`. Now we are going to write a jasmine unit test to
|
||||
verify this functionality. Note that the expression `{{1 + 1}}` times will also be evaluated in the rendered content.
|
||||
|
||||
<pre>
|
||||
describe('Unit testing great quotes', function() {
|
||||
var $compile;
|
||||
var $rootScope;
|
||||
|
||||
// Load the myApp module, which contains the directive
|
||||
beforeEach(module('myApp'));
|
||||
|
||||
// Store references to $rootScope and $compile
|
||||
// so they are available to all tests in this describe block
|
||||
beforeEach(inject(function(_$compile_, _$rootScope_){
|
||||
// The injector unwraps the underscores (_) from around the parameter names when matching
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
}));
|
||||
|
||||
it('Replaces the element with the appropriate content', function() {
|
||||
// Compile a piece of HTML containing the directive
|
||||
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
|
||||
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
|
||||
$rootScope.$digest();
|
||||
// Check that the compiled element contains the templated content
|
||||
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
We inject the $compile service and $rootScope before each jasmine test. The $compile service is used
|
||||
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
|
||||
replaced the content and "lidless, wreathed in flame, 2 times" is present.
|
||||
|
||||
|
||||
## Mocks
|
||||
oue
|
||||
## Global State Isolation
|
||||
oue
|
||||
# Preferred way of Testing
|
||||
uo
|
||||
## JavaScriptTestDriver
|
||||
ou
|
||||
## Jasmine
|
||||
ou
|
||||
## Sample project
|
||||
uoe
|
||||
See the {@link https://github.com/angular/angular-seed angular-seed} project for an example.
|
||||
|
||||
|
||||
+45
-42
@@ -14,7 +14,7 @@ book.
|
||||
|
||||
## DI in a nutshell
|
||||
|
||||
There are only three ways how an object or a function can get a hold of its dependencies:
|
||||
There are only three ways an object or a function can get a hold of its dependencies:
|
||||
|
||||
1. The dependency can be created, typically using the `new` operator.
|
||||
|
||||
@@ -23,8 +23,8 @@ There are only three ways how an object or a function can get a hold of its depe
|
||||
3. The dependency can be passed in to where it is needed.
|
||||
|
||||
|
||||
The first two option of creating or looking up dependencies are not optimal, because they hard
|
||||
code the dependency, making it difficult, if not impossible, to modify the dependencies.
|
||||
The first two options of creating or looking up dependencies are not optimal because they hard
|
||||
code the dependency. This makes it difficult, if not impossible, to modify the dependencies.
|
||||
This is especially problematic in tests, where it is often desirable to provide mock dependencies
|
||||
for test isolation.
|
||||
|
||||
@@ -33,7 +33,7 @@ dependency from the component. The dependency is simply handed to the component.
|
||||
|
||||
<pre>
|
||||
function SomeClass(greeter) {
|
||||
this.greeter = greeter
|
||||
this.greeter = greeter;
|
||||
}
|
||||
|
||||
SomeClass.prototype.doSomething = function(name) {
|
||||
@@ -41,18 +41,18 @@ dependency from the component. The dependency is simply handed to the component.
|
||||
}
|
||||
</pre>
|
||||
|
||||
In the above example the `SomeClass` is not concerned with locating the `greeter` dependency, it
|
||||
In the above example `SomeClass` is not concerned with locating the `greeter` dependency, it
|
||||
is simply handed the `greeter` at runtime.
|
||||
|
||||
This is desirable, but it puts the responsibility of getting hold of the dependency onto the
|
||||
code responsible for the construction of `SomeClass`.
|
||||
This is desirable, but it puts the responsibility of getting hold of the dependency on the
|
||||
code that constructs `SomeClass`.
|
||||
|
||||
To manage the responsibility of dependency creation, each angular application has an {@link
|
||||
To manage the responsibility of dependency creation, each Angular application has an {@link
|
||||
api/angular.injector injector}. The injector is a service locator that is responsible for
|
||||
construction and lookup of dependencies.
|
||||
|
||||
Here is an example of using the injector service:
|
||||
|
||||
Here is an example of using the injector service.
|
||||
<pre>
|
||||
// Provide the wiring information in a module
|
||||
angular.module('myModule', []).
|
||||
@@ -67,11 +67,11 @@ Here is an example of using the injector service.
|
||||
$window.alert(text);
|
||||
}
|
||||
};
|
||||
}).
|
||||
|
||||
});
|
||||
|
||||
// New injector is created from the module.
|
||||
// (This is usually done automatically by angular bootstrap)
|
||||
var injector = angular.injector('myModule');
|
||||
var injector = angular.injector(['myModule', 'ng']);
|
||||
|
||||
// Request any dependency from the injector
|
||||
var greeter = injector.get('greeter');
|
||||
@@ -92,7 +92,7 @@ dependency lookup responsibility to the injector by declaring the dependencies a
|
||||
// And this controller definition
|
||||
function MyController($scope, greeter) {
|
||||
$scope.sayHello = function() {
|
||||
greeter('Hello World');
|
||||
greeter.greet('Hello World');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,21 +101,21 @@ dependency lookup responsibility to the injector by declaring the dependencies a
|
||||
</pre>
|
||||
|
||||
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
|
||||
dependencies of the `MyController` without the controller ever knowing about the injector. This is
|
||||
the best outcome. The application code simply ask for the dependencies it needs, without having to
|
||||
dependencies of `MyController` without the controller ever knowing about the injector. This is
|
||||
the best outcome. The application code simply asks for the dependencies it needs, without having to
|
||||
deal with the injector. This setup does not break the Law of Demeter.
|
||||
|
||||
# Dependency Annotation
|
||||
## Dependency Annotation
|
||||
|
||||
How does the injector know what service needs to be injected?
|
||||
How does the injector know what service needs to be injected?
|
||||
|
||||
The application developer needs to provide annotation information, that the injector uses in order
|
||||
to resolve the dependencies. Throughout Angular certain API functions are invoked using the
|
||||
The application developer needs to provide annotation information that the injector uses in order
|
||||
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
|
||||
injector, as per the API documentation. The injector needs to know what services to inject into
|
||||
the function. Below are three equivalent ways of annotating your code with service name
|
||||
information. These can be used interchangeably as you see fit and are equivalent.
|
||||
|
||||
# Inferring Dependencies
|
||||
### Inferring Dependencies
|
||||
|
||||
The simplest way to get hold of the dependencies, is to assume that the function parameter names
|
||||
are the names of the dependencies.
|
||||
@@ -134,10 +134,10 @@ While straightforward, this method will not work with JavaScript minifiers/obfus
|
||||
rename the method parameter names. This makes this way of annotating only useful for {@link
|
||||
http://www.pretotyping.org/ pretotyping}, and demo applications.
|
||||
|
||||
# `$inject` Annotation
|
||||
### `$inject` Annotation
|
||||
|
||||
To allow the minifers to rename the function parameters and still be able to inject right services
|
||||
the function needs to be annotate with the `$inject` property. The `$inject` property is an array
|
||||
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
|
||||
of service names to inject.
|
||||
|
||||
<pre>
|
||||
@@ -153,22 +153,24 @@ function declaration.
|
||||
This method of annotation is useful for controller declarations since it assigns the annotation
|
||||
information with the function.
|
||||
|
||||
# Inline Annotation
|
||||
### Inline Annotation
|
||||
|
||||
Sometimes using the `$inject` annotation style is not convenient such as when annotating
|
||||
directives.
|
||||
|
||||
For example:
|
||||
|
||||
<pre>
|
||||
someModule.factory('greeter', function($window) {
|
||||
...;
|
||||
...
|
||||
});
|
||||
</pre>
|
||||
|
||||
Results in code bloat due to the need of temporary variable:
|
||||
Results in code bloat due to needing a temporary variable:
|
||||
|
||||
<pre>
|
||||
var greeterFactory = function(renamed$window) {
|
||||
...;
|
||||
...
|
||||
};
|
||||
|
||||
greeterFactory.$inject = ['$window'];
|
||||
@@ -177,45 +179,46 @@ Results in code bloat due to the need of temporary variable:
|
||||
</pre>
|
||||
|
||||
For this reason the third annotation style is provided as well.
|
||||
|
||||
<pre>
|
||||
someModule.factory('greeter', ['$window', function(renamed$window) {
|
||||
...;
|
||||
...
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||
where injection is supported.
|
||||
|
||||
|
||||
# Where can I use DI?
|
||||
## Where can I use DI?
|
||||
|
||||
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
|
||||
|
||||
## DI in controllers
|
||||
### DI in controllers
|
||||
|
||||
Controllers are classes which are responsible for application behavior. Recommended way of
|
||||
declaring controllers is:
|
||||
Controllers are classes which are responsible for application behavior. The recommended way of
|
||||
declaring controllers is using the array notation:
|
||||
|
||||
<pre>
|
||||
var MyController = function(dep1, dep2) {
|
||||
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
|
||||
...
|
||||
}
|
||||
MyController.$inject = ['dep1', 'dep2'];
|
||||
|
||||
MyController.prototype.aMethod = function() {
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
}]);
|
||||
</pre>
|
||||
|
||||
This avoids the creation of global functions for controllers and also protects against minification.
|
||||
|
||||
## Factory methods
|
||||
|
||||
### Factory methods
|
||||
|
||||
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
||||
services, and filters. The factory methods are register with the module, and the recommended way
|
||||
services, and filters. The factory methods are registered with the module, and the recommended way
|
||||
of declaring factories is:
|
||||
|
||||
<pre>
|
||||
angualar.module('myModule', []).
|
||||
angular.module('myModule', []).
|
||||
config(['depProvider', function(depProvider){
|
||||
...
|
||||
}]).
|
||||
@@ -231,4 +234,4 @@ of declaring factories is:
|
||||
run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
</pre>
|
||||
</pre>
|
||||
|
||||
@@ -39,11 +39,11 @@ the following example.
|
||||
</script>
|
||||
<div ng-controller="Ctrl1">
|
||||
Hello <input ng-model='name'> <hr/>
|
||||
<span ng:bind="name"> <span ng:bind="name"></span> <br/>
|
||||
<span ng_bind="name"> <span ng_bind="name"></span> <br/>
|
||||
<span ng-bind="name"> <span ng-bind="name"></span> <br/>
|
||||
<span data-ng-bind="name"> <span data-ng-bind="name"></span> <br/>
|
||||
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
||||
<span ng:bind="name"> <span ng:bind="name"></span> <br/>
|
||||
<span ng_bind="name"> <span ng_bind="name"></span> <br/>
|
||||
<span ng-bind="name"> <span ng-bind="name"></span> <br/>
|
||||
<span data-ng-bind="name"> <span data-ng-bind="name"></span> <br/>
|
||||
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
@@ -95,7 +95,7 @@ Compilation of HTML happens in three phases:
|
||||
var $compile = ...; // injected into your code
|
||||
var scope = ...;
|
||||
|
||||
var html = '<div ng-bind='exp'></div>';
|
||||
var html = '<div ng-bind="exp"></div>';
|
||||
|
||||
// Step 1: parse HTML into DOM element
|
||||
var template = angular.element(html);
|
||||
@@ -110,7 +110,7 @@ Compilation of HTML happens in three phases:
|
||||
## Reasons behind the compile/link separation
|
||||
|
||||
At this point you may wonder why the compile process is broken down to a compile and link phase.
|
||||
To understand this, let's look at a real world example with repeater:
|
||||
To understand this, let's look at a real world example with a repeater:
|
||||
|
||||
<pre>
|
||||
Hello {{user}}, you have these actions:
|
||||
@@ -132,7 +132,7 @@ able to quickly stamp out new `li`s for every `action` in `user.actions`. This m
|
||||
to save a clean copy of the `li` element for cloning purposes and as new `action`s are inserted,
|
||||
the template `li` element needs to be cloned and inserted into `ul`. But cloning the `li` element
|
||||
is not enough. It also needs to compile the `li` so that its directives such as
|
||||
`{{action.descriptions}}` evaluate against the right {@link api/ng.$rootScope.Scope
|
||||
`{{action.description}}` evaluate against the right {@link api/ng.$rootScope.Scope
|
||||
scope}. A naive method would be to simply insert a copy of the `li` element and then compile it.
|
||||
But compiling on every `li` element clone would be slow, since the compilation requires that we
|
||||
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
||||
@@ -144,9 +144,9 @@ links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the s
|
||||
instance of an `li` is performed.
|
||||
|
||||
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
||||
compilation process form descending into the `li` element. Instead the {@link
|
||||
compilation process from descending into the `li` element. Instead the {@link
|
||||
api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
|
||||
separately. The result of of the `li` element compilation is a linking function which contains all
|
||||
separately. The result of the `li` element compilation is a linking function which contains all
|
||||
of the directives contained in the `li` element, ready to be attached to a specific clone of the `li`
|
||||
element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat}
|
||||
watches the expression and as items are added to the array it clones the `li` element, creates a
|
||||
@@ -206,7 +206,7 @@ In this example we will build a directive that displays the current time.
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
// to prevent updating time after the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$timeout.cancel(timeoutId);
|
||||
});
|
||||
@@ -225,7 +225,12 @@ In this example we will build a directive that displays the current time.
|
||||
|
||||
# Writing directives (long version)
|
||||
|
||||
An example skeleton of the directive is shown here, for the complete list see below.
|
||||
There are different ways to declare a directive. The difference resides in the return
|
||||
value of the factory function. You can either return a Directive Definition Object
|
||||
(see below) that defines the directive properties, or just the postLink function
|
||||
of such an object (all other properties will have the default values).
|
||||
|
||||
Here's an example directive declared with a Directive Definition Object:
|
||||
|
||||
<pre>
|
||||
var myModule = angular.module(...);
|
||||
@@ -239,6 +244,8 @@ An example skeleton of the directive is shown here, for the complete list see be
|
||||
transclude: false,
|
||||
restrict: 'A',
|
||||
scope: false,
|
||||
controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
|
||||
function($scope, $element, $attrs, $transclude, otherInjectables) { ... }],
|
||||
compile: function compile(tElement, tAttrs, transclude) {
|
||||
return {
|
||||
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
|
||||
@@ -251,12 +258,11 @@ An example skeleton of the directive is shown here, for the complete list see be
|
||||
});
|
||||
</pre>
|
||||
|
||||
In most cases you will not need such fine control and so the above can be simplified. All of the
|
||||
different parts of this skeleton are explained in following sections. In this section we are
|
||||
interested only in some of this skeleton.
|
||||
In most cases you will not need such fine control and so the above can be simplified. You can still
|
||||
return a Directive Definition Object, but only setting the 'compile' function property of the Object,
|
||||
and rely on the default values for other properties.
|
||||
|
||||
The first step in simplyfing the code is to rely on the default values. Therefore the above can be
|
||||
simplified as:
|
||||
Therefore the above can be simplified as:
|
||||
|
||||
<pre>
|
||||
var myModule = angular.module(...);
|
||||
@@ -271,8 +277,10 @@ simplified as:
|
||||
});
|
||||
</pre>
|
||||
|
||||
Most directives concern themselves only with instances, not with template transformations, allowing
|
||||
further simplification:
|
||||
Finally, most directives concern themselves only with instances, not with template transformations, allowing
|
||||
further simplification.
|
||||
|
||||
Here we only define the postLink function:
|
||||
|
||||
<pre>
|
||||
var myModule = angular.module(...);
|
||||
@@ -296,12 +304,13 @@ makes it injectable following all of the rules of injection annotation.
|
||||
The directive definition object provides instructions to the {@link api/ng.$compile
|
||||
compiler}. The attributes are:
|
||||
|
||||
* `name` - Name of the current scope. Optional defaults to the name at registration.
|
||||
* `name` - Name of the current scope. Optional and defaults to the name at registration.
|
||||
|
||||
* `priority` - When there are multiple directives defined on a single DOM element, sometimes it
|
||||
is necessary to specify the order in which the directives are applied. The `priority` is used
|
||||
to sort the directives before their `compile` functions get called. Higher `priority` goes
|
||||
first. The order of directives within the same priority is undefined.
|
||||
to sort the directives before their `compile` functions get called. Priority is defined as a
|
||||
number. Directives with greater numerical `priority` are compiled first. The order of directives with
|
||||
the same priority is undefined. The default priority is `0`.
|
||||
|
||||
* `terminal` - If set to true then the current `priority` will be the last set of directives
|
||||
which will execute (any directives at the current priority will still execute
|
||||
@@ -310,7 +319,7 @@ compiler}. The attributes are:
|
||||
* `scope` - If set to:
|
||||
|
||||
* `true` - then a new scope will be created for this directive. If multiple directives on the
|
||||
same element request new scope, only one new scope is created. The new scope rule does not
|
||||
same element request a new scope, only one new scope is created. The new scope rule does not
|
||||
apply for the root of the template since the root of the template always gets a new scope.
|
||||
|
||||
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
|
||||
@@ -342,11 +351,11 @@ compiler}. The attributes are:
|
||||
If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||
local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
||||
`scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
|
||||
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
|
||||
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
||||
map of local variable names and values into the expression wrapper fn. For example, if the
|
||||
expression is `increment(amount)` then we can specify the amount value by calling the
|
||||
`localFn` as `localFn({amount: 22})`.
|
||||
a function wrapper for the `count = count + value` expression. Often it's desirable to
|
||||
pass data from the isolated scope via an expression and to the parent scope, this can be
|
||||
done by passing a map of local variable names and values into the expression wrapper fn.
|
||||
For example, if the expression is `increment(amount)` then we can specify the amount value
|
||||
by calling the `localFn` as `localFn({amount: 22})`.
|
||||
|
||||
* `controller` - Controller constructor function. The controller is instantiated before the
|
||||
pre-linking phase and it is shared with other directives if they request it by name (see
|
||||
@@ -355,10 +364,16 @@ compiler}. The attributes are:
|
||||
|
||||
* `$scope` - Current scope associated with the element
|
||||
* `$element` - Current element
|
||||
* `$attrs` - Current attributes obeject for the element
|
||||
* `$attrs` - Current attributes object for the element
|
||||
* `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
|
||||
`function(cloneLinkingFn)`.
|
||||
|
||||
To avoid errors after minification the bracket notation should be used:
|
||||
|
||||
<pre>
|
||||
controller: ['$scope', '$element', '$attrs', '$transclude', function($scope, $element, $attrs, $transclude) { ... }]
|
||||
</pre>
|
||||
|
||||
* `require` - Require another controller be passed into current directive linking function. The
|
||||
`require` takes a name of the directive controller to pass in. If no such controller can be
|
||||
found an error is raised. The name can be prefixed with:
|
||||
@@ -376,8 +391,8 @@ compiler}. The attributes are:
|
||||
* `M` - Comment: `<!-- directive: my-directive exp -->`
|
||||
|
||||
* `template` - replace the current element with the contents of the HTML. The replacement process
|
||||
migrates all of the attributes / classes from the old element to the new one. See Creating
|
||||
Widgets section below for more information.
|
||||
migrates all of the attributes / classes from the old element to the new one. See the
|
||||
{@link guide/directive#Components Creating Components} section below for more information.
|
||||
|
||||
* `templateUrl` - Same as `template` but the template is loaded from the specified URL. Because
|
||||
the template loading is asynchronous the compilation/linking is suspended until the template
|
||||
@@ -432,8 +447,8 @@ done in a linking function rather than in a compile function.
|
||||
|
||||
A compile function can have a return value which can be either a function or an object.
|
||||
|
||||
* returning a function - is equivalent to registering the linking function via the `link` property
|
||||
of the config object when the compile function is empty.
|
||||
* returning a (post-link) function - is equivalent to registering the linking function via the
|
||||
`link` property of the config object when the compile function is empty.
|
||||
|
||||
* returning an object with function(s) registered via `pre` and `post` properties - allows you to
|
||||
control when a linking function should be called during the linking phase. See info about
|
||||
@@ -474,7 +489,7 @@ compiler linking function will fail to locate the correct elements for linking.
|
||||
|
||||
### Post-linking function
|
||||
|
||||
Executed after the child elements are linked. Safe to do DOM transformation in here.
|
||||
Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
|
||||
|
||||
<a name="Attributes"></a>
|
||||
## Attributes
|
||||
@@ -483,7 +498,7 @@ The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a
|
||||
link() or compile() functions - is a way of accessing:
|
||||
|
||||
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
||||
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
|
||||
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized access to
|
||||
the attributes.
|
||||
|
||||
* *directive inter-communication:* All directives share the same instance of the attributes
|
||||
@@ -528,6 +543,7 @@ dialog component may work.
|
||||
on-ok="show = false; doSomething()">
|
||||
Body goes here: {{username}} is {{title}}.
|
||||
</dialog>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
|
||||
@@ -537,7 +553,7 @@ into the dialog.
|
||||
Here is an example of what the template definition for the `dialog` widget may look like.
|
||||
|
||||
<pre>
|
||||
<div ng-show="show">
|
||||
<div ng-show="visible">
|
||||
<h3>{{title}}</h3>
|
||||
<div class="body" ng-transclude></div>
|
||||
<div class="footer">
|
||||
@@ -549,18 +565,18 @@ Here is an example of what the template definition for the `dialog` widget may l
|
||||
|
||||
This will not render properly, unless we do some scope magic.
|
||||
|
||||
The first issue we have to solve is that the dialog box template expect `title` to be defined, but
|
||||
the place of instantiation would like to bind to `username`. Furthermore the buttons expect `onOk`
|
||||
as well as `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
The first issue we have to solve is that the dialog box template expects `title` to be defined, but
|
||||
the place of instantiation would like to bind to `username`. Furthermore the buttons expect the
|
||||
`onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||
expects as follows:
|
||||
|
||||
<pre>
|
||||
scope: {
|
||||
title: '=', // set up title to accept data-binding
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
show: '='
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -583,7 +599,7 @@ isolated scope then it will not be able to bind to anything. For this reason the
|
||||
is a child of the original scope, before the widget created an isolated scope for its local
|
||||
variables. This makes the transcluded and widget isolated scope siblings.
|
||||
|
||||
This may seem as unexpected complexity, but it gives the widget user and developer the least
|
||||
This may seem to be unexpected complexity, but it gives the widget user and developer the least
|
||||
surprise.
|
||||
|
||||
Therefore the final directive definition looks something like this:
|
||||
@@ -591,13 +607,16 @@ Therefore the final directive definition looks something like this:
|
||||
<pre>
|
||||
transclude: true,
|
||||
scope: {
|
||||
title: 'bind', // set up title to accept data-binding
|
||||
onOk: 'expression', // create a delegate onOk function
|
||||
onCancel: 'expression', // create a delegate onCancel function
|
||||
show: 'accessor' // create a getter/setter function for visibility.
|
||||
}
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
},
|
||||
restrict: 'E',
|
||||
replace: true
|
||||
</pre>
|
||||
|
||||
<a name="Components"></a>
|
||||
# Creating Components
|
||||
|
||||
It is often desirable to replace a single directive with a more complex DOM structure. This
|
||||
@@ -606,7 +625,6 @@ can be built.
|
||||
|
||||
Following is an example of building a reusable widget.
|
||||
|
||||
|
||||
<doc:example module="zippyModule">
|
||||
<doc:source>
|
||||
<script>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
||||
expression }}`. Expressions are processed by {@link api/ng.$parse $parse}
|
||||
expression }}`. Expressions are processed by the {@link api/ng.$parse $parse}
|
||||
service.
|
||||
|
||||
For example, these are all valid expressions in angular:
|
||||
@@ -15,17 +15,16 @@ For example, these are all valid expressions in angular:
|
||||
|
||||
## Angular Expressions vs. JS Expressions
|
||||
|
||||
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct, since angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of angular expressions as JavaScript expressions with following differences
|
||||
differences:
|
||||
It might be tempting to think of Angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of Angular expressions as JavaScript expressions with following differences:
|
||||
|
||||
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
|
||||
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
||||
`window`.
|
||||
|
||||
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript,
|
||||
where such evaluations generate `NullPointerExceptions`.
|
||||
* **Forgiving:** expression evaluation is forgiving to `undefined` and `null`, unlike in JavaScript,
|
||||
where trying to evaluate undefined properties can generate `ReferenceError` or `TypeError`.
|
||||
|
||||
* **No Control Flow Statements:** you cannot do any of the following in angular expression:
|
||||
conditionals, loops, or throw.
|
||||
@@ -92,9 +91,9 @@ You can try evaluating different expressions here:
|
||||
# Property Evaluation
|
||||
|
||||
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
|
||||
to global window properties, angular expressions have to use {@link api/ng.$window
|
||||
to global window properties, Angular expressions have to use {@link api/ng.$window
|
||||
`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is
|
||||
defined on `window`, in an expression must use `$window.alert()`. This is done intentionally to
|
||||
defined on `window`, in an expression you must use `$window.alert()`. This is done intentionally to
|
||||
prevent accidental access to the global state (a common source of subtle bugs).
|
||||
|
||||
<doc:example>
|
||||
@@ -148,7 +147,7 @@ Similarly, invoking a function `a.b.c()` on undefined or null simply returns und
|
||||
## No Control Flow Statements
|
||||
|
||||
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
||||
angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||
Angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.
|
||||
|
||||
|
||||
@@ -179,9 +178,9 @@ You might be wondering, what is the significance of the $ prefix? It is simply a
|
||||
angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating
|
||||
`a.length()` would return undefined because neither a nor angular define such a property.
|
||||
|
||||
Consider that in a future version of angular we might choose to add a length method, in which case
|
||||
the behavior of the expression would change. Worse yet, you the developer could create a length
|
||||
property and then we would have a collision. This problem exists because angular augments existing
|
||||
Consider that in a future version of Angular we might choose to add a length method, in which case
|
||||
the behavior of the expression would change. Worse yet, you, the developer, could create a length
|
||||
property and then we would have a collision. This problem exists because Angular augments existing
|
||||
objects with additional behavior. By prefixing its additions with $ we are reserving our namespace
|
||||
so that angular developers and developers who use angular can develop in harmony without collisions.
|
||||
so that angular developers and developers who use Angular can develop in harmony without collisions.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
@name Forms
|
||||
@description
|
||||
|
||||
Controls (`input`, `select`, `textarea`) are a way for user to enter data.
|
||||
Form is a collection of controls for the purpose of grouping related controls together.
|
||||
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
|
||||
A Form is a collection of controls for the purpose of grouping related controls together.
|
||||
|
||||
Form and controls provide validation services, so that the user can be notified of invalid input.
|
||||
This provides a better user experience, because the user gets instant feedback on how to correct the error.
|
||||
@@ -12,9 +12,9 @@ Server-side validation is still necessary for a secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
|
||||
The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
|
||||
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
|
||||
In addition it provides {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
In addition it provides an {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -63,7 +63,7 @@ To allow styling of form as well as controls, `ngModel` add these CSS classes:
|
||||
- `ng-pristine`
|
||||
- `ng-dirty`
|
||||
|
||||
Following example uses the CSS to display validity of each form control.
|
||||
The following example uses the CSS to display validity of each form control.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
|
||||
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
|
||||
|
||||
@@ -93,10 +93,10 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
|
||||
<script>
|
||||
function Controller($scope) {
|
||||
$scope.master= {};
|
||||
$scope.master = {};
|
||||
|
||||
$scope.update = function(user) {
|
||||
$scope.master= angular.copy(user);
|
||||
$scope.master = angular.copy(user);
|
||||
};
|
||||
|
||||
$scope.reset = function() {
|
||||
@@ -113,7 +113,7 @@ This ensures that the user is not distracted with an error until after interacti
|
||||
|
||||
# Binding to form and control state
|
||||
|
||||
A form is in instance of {@link api/ng.directive:form.FormController FormController}.
|
||||
A form is an instance of {@link api/ng.directive:form.FormController FormController}.
|
||||
The form instance can optionally be published into the scope using the `name` attribute.
|
||||
Similarly control is an instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
|
||||
The control instance can similarly be published into the form instance using the `name` attribute.
|
||||
@@ -190,18 +190,18 @@ The validation can occur in two places:
|
||||
|
||||
* **View to Model update** -
|
||||
In a similar way, whenever a user interacts with a control it calls {@link api/ng.directive:ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
|
||||
This in turn pipelines all functions in {@link api/ng.directive:ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
This in turn pipelines all functions in the {@link api/ng.directive:ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
|
||||
In the following example we create two directives.
|
||||
|
||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
||||
For example `1.23` is an invalid value, since it contains a fraction.
|
||||
Note, that we unshift the array instead of pushing.
|
||||
Note that we unshift the array instead of pushing.
|
||||
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
|
||||
* The second directive is a `smart-float`.
|
||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
||||
Note that, we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
Note that we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
|
||||
|
||||
<doc:example module="form-example1">
|
||||
@@ -272,13 +272,13 @@ In the following example we create two directives.
|
||||
</doc:example>
|
||||
|
||||
|
||||
# Implementing custom form control (using `ngModel`)
|
||||
# Implementing custom form controls (using `ngModel`)
|
||||
Angular implements all of the basic HTML form controls ({@link api/ng.directive:input input}, {@link api/ng.directive:select select}, {@link api/ng.directive:textarea textarea}), which should be sufficient for most cases.
|
||||
However, if you need more flexibility, you can write your own form control as a directive.
|
||||
|
||||
In order for custom control to work with `ngModel` and to achieve two-way data-binding it needs to:
|
||||
|
||||
- implement `render` method, which is responsible for rendering the data after it passed the {@link api/ng.directive:ngModel.NgModelController#$formatters NgModelController#$formatters},
|
||||
- implement `$render` method, which is responsible for rendering the data after it passed the {@link api/ng.directive:ngModel.NgModelController#$formatters NgModelController#$formatters},
|
||||
- call `$setViewValue` method, whenever the user interacts with the control and model needs to be updated. This is usually done inside a DOM Event listener.
|
||||
|
||||
See {@link guide/directive $compileProvider.directive} for more info.
|
||||
@@ -300,8 +300,8 @@ The following example shows how to add two-way data-binding to contentEditable e
|
||||
});
|
||||
|
||||
// model -> view
|
||||
ctrl.$render = function(value) {
|
||||
elm.html(value);
|
||||
ctrl.$render = function() {
|
||||
elm.html(ctrl.$viewValue);
|
||||
};
|
||||
|
||||
// load init value from DOM
|
||||
|
||||
@@ -53,7 +53,7 @@ There are two approaches to providing locale rules to Angular:
|
||||
You can pre-bundle the desired locale file with Angular by concatenating the content of the
|
||||
locale-specific file to the end of `angular.js` or `angular.min.js` file.
|
||||
|
||||
For example on *nix, to create a an angular.js file that contains localization rules for german
|
||||
For example on *nix, to create an angular.js file that contains localization rules for german
|
||||
locale, you can do the following:
|
||||
|
||||
`cat angular.js i18n/angular-locale_de-ge.js > angular_de-ge.js`
|
||||
|
||||
+47
-26
@@ -5,43 +5,64 @@
|
||||
# Overview
|
||||
|
||||
This document describes the Internet Explorer (IE) idiosyncrasies when dealing with custom HTML
|
||||
attributes and tags. Read this document if you are planning on deploying your angular application
|
||||
attributes and tags. Read this document if you are planning on deploying your Angular application
|
||||
on IE v8.0 or earlier.
|
||||
|
||||
# Short Version
|
||||
|
||||
To make your angular application work on IE please make sure that:
|
||||
To make your Angular application work on IE please make sure that:
|
||||
|
||||
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
|
||||
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<!--[if lte IE 8]>
|
||||
<script src="/path/to/json2.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
...
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
2. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
|
||||
2. add `id="ng-app"` to the root element in conjunction with `ng-app` attribute
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
|
||||
...
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
3. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
|
||||
`<div ng-view>` instead), or
|
||||
|
||||
3. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
||||
|
||||
<pre>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<!--[if lte IE 8]>
|
||||
<script>
|
||||
document.createElement('ng-include');
|
||||
document.createElement('ng-pluralize');
|
||||
document.createElement('ng-view');
|
||||
|
||||
// Optionally these for CSS
|
||||
document.createElement('ng:include');
|
||||
document.createElement('ng:pluralize');
|
||||
document.createElement('ng:view');
|
||||
</script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
...
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
4. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="optionalModuleName">
|
||||
<head>
|
||||
<!--[if lte IE 8]>
|
||||
<script>
|
||||
document.createElement('ng-include');
|
||||
document.createElement('ng-pluralize');
|
||||
document.createElement('ng-view');
|
||||
|
||||
// Optionally these for CSS
|
||||
document.createElement('ng:include');
|
||||
document.createElement('ng:pluralize');
|
||||
document.createElement('ng:view');
|
||||
</script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
...
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
The **important** parts are:
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Angular is pure client-side technology, written entirely in JavaScript. It works
|
||||
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of
|
||||
web apps easier and faster than ever before.
|
||||
|
||||
One important way that angular simplifies web development is by increasing the level of abstraction
|
||||
One important way that Angular simplifies web development is by increasing the level of abstraction
|
||||
between the developer and most low-level web app development tasks. Angular automatically takes
|
||||
care of many of these tasks, including:
|
||||
|
||||
@@ -14,10 +14,10 @@ care of many of these tasks, including:
|
||||
* Setting Up Listeners and Notifiers
|
||||
* Input Validation
|
||||
|
||||
Because angular handles much of the work involved in these tasks, developers can concentrate more
|
||||
Because Angular handles much of the work involved in these tasks, developers can concentrate more
|
||||
on application logic and less on repetitive, error-prone, lower-level coding.
|
||||
|
||||
At the same time that angular simplifies the development of web apps, it brings relatively
|
||||
At the same time that Angular simplifies the development of web apps, it brings relatively
|
||||
sophisticated techniques to the client-side, including:
|
||||
|
||||
* Separation of data, application logic, and presentation components
|
||||
@@ -31,12 +31,12 @@ These techniques have been for the most part absent from the client-side for far
|
||||
|
||||
## Single-page / Round-trip Applications
|
||||
|
||||
You can use angular to develop both single-page and round-trip apps, but angular is designed
|
||||
You can use Angular to develop both single-page and round-trip apps, but Angular is designed
|
||||
primarily for developing single-page apps. Angular supports browser history, forward and back
|
||||
buttons, and bookmarking in single-page apps.
|
||||
|
||||
You normally wouldn't want to load angular with every page change, as would be the case with using
|
||||
angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
||||
angular's features (for example, templates to leverage angular's data-binding feature) to an
|
||||
You normally wouldn't want to load Angular with every page change, as would be the case with using
|
||||
Angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
||||
Angular's features (for example, templates to leverage angular's data-binding feature) to an
|
||||
existing round-trip app. You might follow this course of action if you were migrating an older app
|
||||
to a single-page angular app.
|
||||
to a single-page Angular app.
|
||||
|
||||
@@ -158,9 +158,9 @@ angular.module('myModule', []).
|
||||
|
||||
angular.module('myModule', []).
|
||||
config(function($provide, $compileProvider, $filterProvider) {
|
||||
$provide.value('a', 123)
|
||||
$provide.factory('a', function() { return 123; })
|
||||
$compileProvider.directive('directiveName', ...).
|
||||
$provide.value('a', 123);
|
||||
$provide.factory('a', function() { return 123; });
|
||||
$compileProvider.directive('directiveName', ...);
|
||||
$filterProvider.register('filterName', ...);
|
||||
});
|
||||
</pre>
|
||||
@@ -180,7 +180,7 @@ ignored in the unit-tests.
|
||||
|
||||
Modules can list other modules as their dependencies. Depending on a module implies that required
|
||||
module needs to be loaded before the requiring module is loaded. In other words the configuration
|
||||
blocks of the required modules execute before the configuration blocks or the requiring module.
|
||||
blocks of the required modules execute before the configuration blocks of the requiring module.
|
||||
The same is true for the run blocks. Each module can only be loaded once, even if multiple other
|
||||
modules require it.
|
||||
|
||||
@@ -191,10 +191,28 @@ scripts into a VM. There are existing projects which deal with script loading, w
|
||||
with Angular. Because modules do nothing at load time they can be loaded into the VM in any order
|
||||
and thus script loaders can take advantage of this property and parallelize the loading process.
|
||||
|
||||
## Creation versus Retrieval
|
||||
|
||||
Beware that using `angular.module('myModule', [])` will create the module `myModule` and overwrite any
|
||||
existing module named `myModule`. Use `angular.module('myModule')` to retrieve an existing module.
|
||||
|
||||
<pre>
|
||||
var myModule = angular.module('myModule', []);
|
||||
|
||||
// add some directives and services
|
||||
myModule.service('myService', ...);
|
||||
myModule.directive('myDirective', ...);
|
||||
|
||||
// overwrites both myService and myDirective by creating a new module
|
||||
var myModule = angular.module('myModule', []);
|
||||
|
||||
// throws an error because myOtherModule has yet to be defined
|
||||
var myModule = angular.module('myOtherModule');
|
||||
</pre>
|
||||
|
||||
# Unit Testing
|
||||
|
||||
In its simplest form a unit-test is a way of instantiating a subset of the application in test and
|
||||
In its simplest form a unit test is a way of instantiating a subset of the application in test and
|
||||
then applying a stimulus to it. It is important to realize that each module can only be loaded
|
||||
once per injector. Typically an app has only one injector. But in tests, each test has its own
|
||||
injector, which means that the modules are loaded multiple times per VM. Properly structured
|
||||
@@ -222,8 +240,8 @@ In all of these examples we are going to assume this module definition:
|
||||
Let's write some tests:
|
||||
<pre>
|
||||
describe('myApp', function() {
|
||||
// load the application relevant modules then load a special
|
||||
// test module which overrides the $window with mock version,
|
||||
// load the relevant application modules then load a special
|
||||
// test module which overrides the $window with a mock version,
|
||||
// so that calling window.alert() will not block the test
|
||||
// runner with a real alert box. This is an example of overriding
|
||||
// configuration information in tests.
|
||||
|
||||
@@ -8,28 +8,28 @@
|
||||
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
|
||||
language and lets you extend HTML's syntax to express your application's components clearly and
|
||||
succinctly. Out of the box, it eliminates much of the code you currently write through data
|
||||
binding and dependency injection. And it all happens in JavaScript within the browser making it an
|
||||
ideal partner with any server technology.
|
||||
binding and dependency injection. And it all happens in JavaScript within the browser, making it
|
||||
an ideal partner with any server technology.
|
||||
|
||||
Angular is what HTML would have been had it been designed for applications. HTML is a great
|
||||
declarative language for static documents. It does not contain much in the way of creating
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do, so
|
||||
that I trick the browser in to doing what I want.*
|
||||
applications, and as a result building web applications is an exercise in *what do I have to do
|
||||
to trick the browser into doing what I want.*
|
||||
|
||||
Impedance mismatch between dynamic applications and static documents are often solved as:
|
||||
The impedance mismatch between dynamic applications and static documents is often solved with:
|
||||
|
||||
* **library** - a collection of functions which are useful when writing web apps. Your code is
|
||||
* **a library** - a collection of functions which are useful when writing web apps. Your code is
|
||||
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
|
||||
* **frameworks** - a particular implementation of a web application, where your code fills in
|
||||
the details. The framework is in charge and it calls into your code when it needs something
|
||||
app specific. E.g., `knockout`, `sproutcore`, etc.
|
||||
app specific. E.g., `knockout`, `ember`, etc.
|
||||
|
||||
|
||||
Angular takes another approach. It attempts to minimize the impedance mismatch between document
|
||||
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
|
||||
browser new syntax through a construct we call directives. Examples include:
|
||||
|
||||
* Data binding as in `{{}}`.
|
||||
* Data binding, as in `{{}}`.
|
||||
* DOM control structures for repeating/hiding DOM fragments.
|
||||
* Support for forms and form validation.
|
||||
* Attaching code-behind to DOM elements.
|
||||
@@ -37,13 +37,13 @@ browser new syntax through a construct we call directives. Examples include:
|
||||
|
||||
|
||||
|
||||
## End-to-end solution
|
||||
## A complete client-side solution
|
||||
|
||||
Angular tries to be an end-to-end solution, when building a web application. This means it is
|
||||
not a single piece in an overall puzzle of building a web application, but an end-to-end solution.
|
||||
This makes Angular opinionated about how a CRUD application should be built. But while it is
|
||||
opinionated, it also tries to make sure that its opinion is just a starting point, which you can
|
||||
easily change. Angular comes with the following out-of-the-box:
|
||||
Angular is not a single piece in the overall puzzle of building the client-side of a web
|
||||
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
|
||||
well-defined structure. This makes Angular opinionated about how a CRUD application should be
|
||||
built. But while it is opinionated, it also tries to make sure that its opinion is just a
|
||||
starting point you can easily change. Angular comes with the following out-of-the-box:
|
||||
|
||||
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
|
||||
directives, form validation, routing, deep-linking, reusable components, dependency injection.
|
||||
@@ -90,7 +90,7 @@ concepts which the application developer may face:
|
||||
<table>
|
||||
<tr><td>Quantity</td><td>Cost</td></tr>
|
||||
<tr>
|
||||
<td><input type="integer" min="0" ng-model="qty" required ></td>
|
||||
<td><input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required ></td>
|
||||
<td><input type="number" ng-model="cost" required ></td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -111,7 +111,7 @@ concepts which the application developer may face:
|
||||
Try out the Live Preview above, and then let's walk through the example and describe what's going
|
||||
on.
|
||||
|
||||
In the `<html>` tag, we specify that it is an angular
|
||||
In the `<html>` tag, we specify that it is an Angular
|
||||
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
|
||||
bootstrap auto initialize} your application.
|
||||
|
||||
@@ -121,20 +121,20 @@ We load Angular using the `<script>` tag:
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
|
||||
|
||||
From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data
|
||||
From the `ng-model` attribute of the `<input>` tags, Angular automatically sets up two-way data
|
||||
binding, and we also demonstrate some easy input validation:
|
||||
|
||||
Quantity: <input type="integer" min="0" ng-model="qty" required >
|
||||
Quantity: <input type="number" ng-pattern="/\d+/" step="1" min="0" ng-model="qty" required >
|
||||
Cost: <input type="number" ng-model="cost" required >
|
||||
|
||||
These input widgets look normal enough, but consider these points:
|
||||
|
||||
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
|
||||
* When this page loaded, Angular bound the names of the input widgets (`qty` and `cost`) to
|
||||
variables of the same name. Think of those variables as the "Model" component of the
|
||||
Model-View-Controller design pattern.
|
||||
* Note that the HTML widget {@link api/ng.directive:input input}
|
||||
has special powers. The input invalidates itself by turning red when you enter invalid data or
|
||||
leave the the input fields blank. These new widget behaviors make it easier to implement field
|
||||
leave the input fields blank. These new widget behaviors make it easier to implement field
|
||||
validation common in CRUD applications.
|
||||
|
||||
And finally, the mysterious `{{ double curly braces }}`:
|
||||
@@ -193,7 +193,7 @@ Angular frees you from the following pain:
|
||||
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
|
||||
overall flow of the application rather than all of the implementation details.
|
||||
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
|
||||
of plumbing just to get a basic "Hello World" AJAX app working. With angular you can bootstrap
|
||||
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
|
||||
your app easily using services, which are auto-injected into your application in a {@link
|
||||
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
|
||||
to get started developing features quickly. As a bonus, you get full control over the
|
||||
@@ -202,6 +202,6 @@ Angular frees you from the following pain:
|
||||
|
||||
# Watch a Presentation About Angular
|
||||
|
||||
Here is a presentation on Angular from May 2012.
|
||||
Here is a presentation on Angular from May 2012. The {@link http://mhevery.github.io/angular-demo-slides/index.html#/list corresponding slides} are also available.
|
||||
|
||||
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
||||
|
||||
@@ -81,7 +81,7 @@ Logically the rendering of `{{greeting}}` involves:
|
||||
You can think of the scope and its properties as the data which is used to render the view. The
|
||||
scope is the single source-of-truth for all things view related.
|
||||
|
||||
From testability, the separation of the controller and the view is desirable, because it allows us
|
||||
From a testability point of view, the separation of the controller and the view is desirable, because it allows us
|
||||
to test the behavior without being distracted by the rendering details.
|
||||
|
||||
<pre>
|
||||
@@ -151,7 +151,7 @@ This example illustrates scopes in application, and prototypical inheritance of
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Notice that the Angular automatically places `ng-scope` class on elements where scopes are
|
||||
Notice that Angular automatically places `ng-scope` class on elements where scopes are
|
||||
attached. The `<style>` definition in this example highlights in red the new scope locations. The
|
||||
child scopes are necessary because the repeater evaluates `{{employee.name}}` expression, but
|
||||
depending on which scope the expression is evaluated it produces different result. Similarly the
|
||||
@@ -165,8 +165,8 @@ Scopes are attached to the DOM as `$scope` data property, and can be retrieved f
|
||||
purposes. (It is unlikely that one would need to retrieve scopes in this way inside the
|
||||
application.) The location where the root scope is attached to the DOM is defined by the location
|
||||
of {@link api/ng.directive:ngApp `ng-app`} directive. Typically
|
||||
`ng-app` is placed an the `<html>` element, but it can be placed on other elements as well, if,
|
||||
for example, only a portion of the view needs to be controlled by angular.
|
||||
`ng-app` is placed on the `<html>` element, but it can be placed on other elements as well, if,
|
||||
for example, only a portion of the view needs to be controlled by Angular.
|
||||
|
||||
To examine the scope in the debugger:
|
||||
|
||||
@@ -218,7 +218,7 @@ api/ng.$rootScope.Scope#$emit emitted} to scope parents.
|
||||
|
||||
## Scope Life Cycle
|
||||
|
||||
The normal flow of browser receiving an event is that it executes a corresponding JavaScript
|
||||
The normal flow of a browser receiving an event is that it executes a corresponding JavaScript
|
||||
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
|
||||
more events.
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Type
|
||||
@description
|
||||
@@ -81,23 +81,27 @@ Several steps are needed to check out and build AngularJS:
|
||||
Before you can build AngularJS, you must install or configure the following dependencies on your
|
||||
machine:
|
||||
|
||||
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
|
||||
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
|
||||
Rake website.
|
||||
|
||||
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
||||
quite a good source for information on Git.
|
||||
|
||||
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
|
||||
development web server. Depending on your system, you can install Node either from source or as a
|
||||
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation, run a
|
||||
development web server, run tests, and generate a build. Depending on your system, you can install Node either from source or as a
|
||||
pre-packaged bundle.
|
||||
|
||||
* {@link http://www.java.com Java}: JavaScript is minified using
|
||||
{@link https://developers.google.com/closure/ Closure Tools} jar. Make sure you have Java (version 6 or higher) installed
|
||||
and included in your {@link http://docs.oracle.com/javase/tutorial/essential/environment/paths.html PATH} variable.
|
||||
|
||||
Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
|
||||
of the Angular repository (see below) with:
|
||||
|
||||
* `cd angular.js`
|
||||
* `npm install`
|
||||
|
||||
* {@link http://gruntjs.com Grunt}: We use Grunt as our build system. Install the grunt command-line tool globally with:
|
||||
|
||||
* `sudo npm install -g grunt-cli`
|
||||
|
||||
|
||||
## Creating a Github Account and Forking Angular
|
||||
|
||||
@@ -108,7 +112,7 @@ https://github.com/angular/angular.js main angular repository}.
|
||||
|
||||
## Building AngularJS
|
||||
|
||||
To build AngularJS, you check out the source code and use Rake to generate the non-minified and
|
||||
To build AngularJS, you check out the source code and use Grunt to generate the non-minified and
|
||||
minified AngularJS files:
|
||||
|
||||
1. To clone your Github repository, run:
|
||||
@@ -123,9 +127,17 @@ minified AngularJS files:
|
||||
|
||||
git remote add upstream https://github.com/angular/angular.js.git
|
||||
|
||||
4. To build AngularJS, run:
|
||||
4. To add node.js dependencies
|
||||
|
||||
npm install
|
||||
|
||||
5. To build AngularJS, run:
|
||||
|
||||
grunt package
|
||||
|
||||
NOTE: If you're using Windows you must run your command line with administrative privileges (right click, run as
|
||||
Administrator).
|
||||
|
||||
rake package
|
||||
|
||||
The build output can be located under the `build` directory. It consists of the following files and
|
||||
directories:
|
||||
@@ -154,7 +166,7 @@ made available a local web server based on Node.js.
|
||||
|
||||
1. To start the web server, run:
|
||||
|
||||
rake webserver
|
||||
grunt webserver
|
||||
|
||||
2. To access the local server, go to this website:
|
||||
|
||||
@@ -166,33 +178,35 @@ made available a local web server based on Node.js.
|
||||
<a name="unit-tests"></a>
|
||||
## Running the Unit Test Suite
|
||||
|
||||
Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
|
||||
Our unit and integration tests are written with Jasmine and executed with Karma. To run all of the
|
||||
tests once on Chrome run:
|
||||
|
||||
rake test:unit
|
||||
grunt test:unit
|
||||
|
||||
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
|
||||
|
||||
rake test:unit[Opera+Firefox]
|
||||
grunt test:unit --browsers Opera,Firefox
|
||||
|
||||
Note there should be _no spaces between browsers_. `Opera, Firefox` is INVALID.
|
||||
|
||||
During development it's however more productive to continuously run unit tests every time the source or test files
|
||||
change. To execute tests in this mode run:
|
||||
|
||||
1. To start the Testacular server, capture Chrome browser and run unit tests, run:
|
||||
1. To start the Karma server, capture Chrome browser and run unit tests, run:
|
||||
|
||||
rake autotest:jqlite
|
||||
grunt autotest:jqlite
|
||||
|
||||
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
|
||||
of Testacular running, read Testacular's console output for the correct url):
|
||||
of Karma running, read Karma's console output for the correct url):
|
||||
|
||||
http://localhost:9876/
|
||||
|
||||
3. To re-run tests just change any source or test file.
|
||||
|
||||
|
||||
To learn more about all of the preconfigured Rake tasks run:
|
||||
To learn more about all of the preconfigured Grunt tasks run:
|
||||
|
||||
rake -T
|
||||
grunt --help
|
||||
|
||||
|
||||
## Running the end-to-end Test Suite
|
||||
@@ -201,7 +215,7 @@ To run the E2E test suite:
|
||||
|
||||
1. Start the local web server if it's not running already.
|
||||
|
||||
rake webserver
|
||||
grunt webserver
|
||||
|
||||
2. In a browser, go to:
|
||||
|
||||
@@ -209,7 +223,13 @@ To run the E2E test suite:
|
||||
|
||||
or in terminal run:
|
||||
|
||||
rake test:e2e
|
||||
grunt test:end2end
|
||||
|
||||
For convenience you can also simply run:
|
||||
|
||||
grunt test:e2e
|
||||
|
||||
This will start the webserver for you and run the tests.
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +238,8 @@ To run the E2E test suite:
|
||||
|
||||
To create and submit a change:
|
||||
|
||||
1. Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
|
||||
1. <a name="CLA"></a>
|
||||
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
|
||||
accepted, the CLA must be signed. It's a quick process, we promise!
|
||||
|
||||
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
|
||||
@@ -226,31 +247,27 @@ To create and submit a change:
|
||||
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
|
||||
|
||||
|
||||
2. Create a new branch off the master for your changes:
|
||||
2. Create and checkout a new branch off the master branch for your changes:
|
||||
|
||||
git branch my-fix-branch
|
||||
git checkout -b my-fix-branch master
|
||||
|
||||
3. Check out the branch:
|
||||
3. Create your patch, make sure to have plenty of tests (that pass).
|
||||
|
||||
git checkout my-fix-branch
|
||||
|
||||
4. Create your patch, make sure to have plenty of tests (that pass).
|
||||
|
||||
5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
|
||||
4. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
|
||||
please check out our
|
||||
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
|
||||
and our commit message presubmit hook `validate-commit-msg.js`):
|
||||
|
||||
git commit -a
|
||||
|
||||
6. Push your branch to Github:
|
||||
5. Push your branch to Github:
|
||||
|
||||
git push origin my-fix-branch
|
||||
|
||||
7. In Github, send a pull request to `angular:master`.
|
||||
6. In Github, send a pull request to `angular:master`.
|
||||
|
||||
|
||||
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
|
||||
7. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
|
||||
from the main (upstream) repository:
|
||||
|
||||
1. To delete the branch in Github, run:
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
@name Downloading
|
||||
@description
|
||||
|
||||
# Including angular scripts from the angular server
|
||||
The quickest way to get started is to point your html `<script>` tag to a
|
||||
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
||||
local copy.
|
||||
# Including angular scripts from the Google CDN
|
||||
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
|
||||
This way, you don't have to download anything or maintain a local copy.
|
||||
|
||||
There are two types of angular script URLs you can point to, one for development and one for
|
||||
production:
|
||||
@@ -15,21 +14,25 @@ development.
|
||||
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
||||
production.
|
||||
|
||||
To point your code to an angular script on the angular server, use the following template. This
|
||||
example points to (non-minified) version 1.0.2:
|
||||
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||
example points to the minified version 1.0.2:
|
||||
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<head>
|
||||
<title>My Angular App</title>
|
||||
<script src="http://code.angularjs.org/1.0.2/angular.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
Note that only versions 1.0.1 and above are available on the CDN, if you need an earlier version
|
||||
you can use the <http://code.angularjs.org/> URL which was the previous recommended location for
|
||||
hosted code source. If you're still using the angular server you should switch to the CDN version
|
||||
for even faster loading times.
|
||||
|
||||
# Downloading and hosting angular files locally
|
||||
This option is for those who want to work with angular offline, or those who want to host the
|
||||
|
||||
@@ -32,7 +32,7 @@ templating systems.
|
||||
|
||||
### Do I need to worry about security holes in AngularJS?
|
||||
|
||||
Like with any technology, AngularJS is not impervious to attack. Angular does, however, provide
|
||||
Like any other technology, AngularJS is not impervious to attack. Angular does, however, provide
|
||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
||||
attacks. AngularJS does round-trip escaping on all strings for you and even offers XSRF protection
|
||||
for server-side communication.
|
||||
@@ -51,7 +51,8 @@ Yes. See instructions in {@link downloading}.
|
||||
### What browsers does Angular work with?
|
||||
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
|
||||
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
|
||||
Explorer Compatibility} for more details in supporting legacy IE browsers.
|
||||
|
||||
|
||||
### What's Angular's performance like?
|
||||
@@ -90,15 +91,33 @@ framework, provides mocks for many heavy dependencies (server-side communication
|
||||
|
||||
### How can I learn more about Angular?
|
||||
|
||||
Watch the July 28, 2010 talk
|
||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
||||
AJAX Apps}".
|
||||
Watch the July 17, 2012 talk
|
||||
"{@link http://www.youtube.com/watch?v=1CpiB3Wk25U AngularJS Intro + Dependency Injection}".
|
||||
|
||||
|
||||
### How is Angular licensed?
|
||||
|
||||
The MIT License.
|
||||
|
||||
### Can I download and use the Angular logo artwork?
|
||||
|
||||
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
|
||||
angular.js/images/logo}"
|
||||
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
|
||||
Creative Commons Attribution-ShareAlike 3.0 Unported License}". If you have some other use in mind, contact us.
|
||||
|
||||
### How can I get some AngularJS schwag?
|
||||
|
||||
We often bring a few t-shirts and stickers to events where we're presenting. If you want to order your own, the folks who
|
||||
make our schwag will be happy to do a custom run for you, based on our existing template. By using the design they have on file,
|
||||
they'll waive the setup costs, and you can order any quantity you need.
|
||||
|
||||
**Stickers**
|
||||
Contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
|
||||
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
|
||||
|
||||
As long as the design stays exactly the same, {@link http://www.stickergiant.com StickerGiant} will give you a reorder discount.
|
||||
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ becoming an Angular expert.
|
||||
##Watch Videos
|
||||
|
||||
If you haven’t had a chance to watch the videos from the homepage, please check out:
|
||||
|
||||
* {@link http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Introduction to AngularJS}
|
||||
* {@link http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Creating Directives}
|
||||
* {@link http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Communicating with Servers}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@ngdoc overview
|
||||
@name Tutorial
|
||||
@name Tutorial: Index
|
||||
@description
|
||||
|
||||
A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
|
||||
@@ -54,24 +54,24 @@ and follow the instructions for setting up your computer.
|
||||
<div class="tabbable" show="true">
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
|
||||
don't have it already:</p>
|
||||
<pre>npm install -g testacular</pre>
|
||||
<pre>npm install -g karma</pre>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<li><p>Clone the angular-phonecat repository located at
|
||||
<a href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current
|
||||
directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre>cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p></li>
|
||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
@@ -81,24 +81,24 @@ to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></l
|
||||
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<ol>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
<p>Additionally install <a href="http://karma-runner.github.io/">Karma</a> if you
|
||||
don't have it already:</p>
|
||||
<pre>npm install -g testacular</pre>
|
||||
<pre>npm install -g karma</pre>
|
||||
</li>
|
||||
<li><p>You'll also need Git, which you can get from
|
||||
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
|
||||
<li><p>Clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
|
||||
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to angular-phonecat.</p>
|
||||
<p>This command creates the <code>angular-phonecat</code> directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
|
||||
<pre>cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
|
||||
directory.</p>
|
||||
<p>You should run all <code>git</code> commands from Git bash.</p>
|
||||
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
|
||||
|
||||
@@ -13,7 +13,7 @@ angular-seed, and run the application in the browser.
|
||||
<div class="tabbable" show="true" ng-model="$cookies.platformPreference">
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux" value="gitUnix">
|
||||
<ol>
|
||||
<li><p>In angular-phonecat directory, run this command:</p>
|
||||
<li><p>In <code>angular-phonecat</code> directory, run this command:</p>
|
||||
<pre>git checkout -f step-0</pre>
|
||||
<p>This resets your workspace to step 0 of the tutorial app.</p>
|
||||
<p>You must repeat this for every future step in the tutorial and change the number to
|
||||
@@ -25,7 +25,7 @@ angular-seed, and run the application in the browser.
|
||||
<li><b>For node.js users:</b>
|
||||
<ol>
|
||||
<li>In a <i>separate</i> terminal tab or window, run
|
||||
<code>./scripts/web-server.js</code> to start the web server.</li>
|
||||
<code>node ./scripts/web-server.js</code> to start the web server.</li>
|
||||
<li>Open a browser window for the app and navigate to <a
|
||||
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
||||
</ol>
|
||||
@@ -46,7 +46,7 @@ directory.</li>
|
||||
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
|
||||
<ol>
|
||||
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
|
||||
<li><p>Open Git bash and run this command (in <code>angular-phonecat</code> directory):</p>
|
||||
<pre>git checkout -f step-0</pre>
|
||||
<p>This resets your workspace to step 0 of the tutorial app.</p>
|
||||
<p>You must repeat this for every future step in the tutorial and change the number to
|
||||
@@ -109,7 +109,7 @@ __`app/index.html`:__
|
||||
|
||||
<html ng-app>
|
||||
|
||||
The `ng-app` attribute is represents an Angular directive (named `ngApp`; Angular uses
|
||||
The `ng-app` attribute represents an Angular directive (named `ngApp`; Angular uses
|
||||
`name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
|
||||
used to flag an element which Angular should consider to be the root element of our application.
|
||||
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||
@@ -127,7 +127,7 @@ being the element on which the `ngApp` directive was defined.
|
||||
|
||||
* Double-curly binding with an expression:
|
||||
|
||||
Nothing here {{'yet' + '!'}}`
|
||||
Nothing here {{'yet' + '!'}}
|
||||
|
||||
This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<ul doc-tutorial-nav="1"></ul>
|
||||
|
||||
|
||||
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that angular will use to
|
||||
In order to illustrate how Angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that Angular will use to
|
||||
dynamically display the same result with any set of data.
|
||||
|
||||
In this step you will add some basic information about two cell phones to an HTML page.
|
||||
|
||||
@@ -134,10 +134,10 @@ describe('PhoneCat controllers', function() {
|
||||
});
|
||||
</pre>
|
||||
|
||||
The test verifies that we have three records in the phones array and the example demonstrates how
|
||||
easy it is to create a unit test for code in Angular. Since testing is such a critical part of
|
||||
software development, we make it easy to create tests in Angular so that developers are encouraged
|
||||
to write them.
|
||||
The test instantiates our PhoneListCtrl and verifies that its phones array property contains three
|
||||
records. This example demonstrates how easy it is to create a unit test for code in Angular. Since
|
||||
testing is such a critical part of software development, we make it easy to create tests in Angular
|
||||
so that developers are encouraged to write them.
|
||||
|
||||
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
|
||||
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
|
||||
@@ -146,24 +146,25 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
|
||||
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
||||
|
||||
The angular-seed project is pre-configured to run all unit tests using {@link
|
||||
http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the following:
|
||||
http://karma-runner.github.io/ Karma}. To run the test, do the following:
|
||||
|
||||
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
||||
`./scripts/test.sh` to start the Testacular server.
|
||||
`./scripts/test.sh` to start the Karma server (the config file necessary to start the server
|
||||
is located at `./config/karma.conf.js`).
|
||||
|
||||
2. Testacular will start a new instance of Chrome browser automatically. Just ignore it and let it run in
|
||||
the background. Testacular will use this browser for test execution.
|
||||
2. Karma will start a new instance of Chrome browser automatically. Just ignore it and let it run in
|
||||
the background. Karma will use this browser for test execution.
|
||||
|
||||
3. You should see the following or similar output in the terminal:
|
||||
|
||||
info: Testacular server started at http://localhost:9876/
|
||||
info: Karma server started at http://localhost:9876/
|
||||
info (launcher): Starting browser "Chrome"
|
||||
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
|
||||
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
|
||||
|
||||
Yay! The test passed! Or not...
|
||||
|
||||
4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
|
||||
4. To rerun the tests, just change any of the source or test files. Karma will notice the change
|
||||
and will rerun the tests for you. Now isn't that sweet?
|
||||
|
||||
# Experiments
|
||||
|
||||
@@ -122,9 +122,9 @@ To run the end-to-end test, open one of the following in a new browser tab:
|
||||
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
|
||||
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
|
||||
|
||||
Previously we've seen how Testacular can be used to execute unit tests. Well, it can also run the
|
||||
Previously we've seen how Karma can be used to execute unit tests. Well, it can also run the
|
||||
end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests are slow, so unlike
|
||||
with unit tests, Testacular will exit after the test run and will not automatically rerun the test
|
||||
with unit tests, Karma will exit after the test run and will not automatically rerun the test
|
||||
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
|
||||
|
||||
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||
@@ -138,12 +138,12 @@ really is that easy to set up any functional, readable, end-to-end test.
|
||||
|
||||
* Let's see how we can get the current value of the `query` model to appear in the HTML page title.
|
||||
|
||||
You might think you could just add the {{query}} to the title tag element as follows:
|
||||
You might think you could just add the `{{query}}` to the title tag element as follows:
|
||||
|
||||
<title>Google Phone Gallery: {{query}}</title>
|
||||
|
||||
However, when you reload the page, you won't see the expected result. This is because the "query"
|
||||
model lives in the scope defined by the body element:
|
||||
model lives in the scope, defined by the `ng-controller="PhoneListCtrl"` directive, on the body element:
|
||||
|
||||
<body ng-controller="PhoneListCtrl">
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ The unit test now verifies that the default ordering property is set.
|
||||
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
|
||||
shared by all tests in the parent `describe` block.
|
||||
|
||||
You should now see the following output in the Testacular tab:
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
|
||||
|
||||
@@ -178,6 +178,8 @@ ordering will default to unordered/natural order.
|
||||
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
|
||||
text.
|
||||
|
||||
* Reverse the sort order by adding a `-` symbol before the sorting value: `<option value="-age">Oldest</option>`
|
||||
|
||||
# Summary
|
||||
|
||||
Now that you have added list sorting and tested the app, go to {@link step_05 step 5} to learn
|
||||
|
||||
@@ -44,7 +44,7 @@ Following is a sample of the file:
|
||||
|
||||
We'll use angular's {@link api/ng.$http $http} service in our controller to make an HTTP
|
||||
request to your web server to fetch the data in the `app/phones/phones.json` file. `$http` is just
|
||||
one of several built-in {@link api/ng angular services} that handle common operations
|
||||
one of several built-in {@link guide/dev_guide.services angular services} that handle common operations
|
||||
in web apps. Angular injects these services for you where you need them.
|
||||
|
||||
Services are managed by angular's {@link guide/di DI subsystem}. Dependency injection
|
||||
@@ -138,6 +138,9 @@ describe('PhoneCat controllers', function() {
|
||||
describe('PhoneListCtrl', function(){
|
||||
var scope, ctrl, $httpBackend;
|
||||
|
||||
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
|
||||
// This allows us to inject a service but then attach it to a variable
|
||||
// with the same name as the service.
|
||||
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.expectGET('phones/phones.json').
|
||||
@@ -204,11 +207,9 @@ Finally, we verify that the default value of `orderProp` is set correctly:
|
||||
it('should set the default value of orderProp model', function() {
|
||||
expect(scope.orderProp).toBe('age');
|
||||
});
|
||||
});
|
||||
});
|
||||
</pre>
|
||||
|
||||
You should now see the following output in the Testacular tab:
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
|
||||
|
||||
|
||||
@@ -46,14 +46,14 @@ history (back and forward navigation) and bookmarks.
|
||||
|
||||
### A Note About DI, Injector and Providers
|
||||
|
||||
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} is the core feature of
|
||||
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} (DI) is the core feature of
|
||||
AngularJS, so it's important for you to understand a thing or two about how it works.
|
||||
|
||||
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
|
||||
this app. The injector itself doesn't know anything about what `$http` or `$route` services do, in
|
||||
fact it doesn't even know about the existence of these services unless it is configured with proper
|
||||
module definitions. The sole responsibilities of the injector are to load specified module
|
||||
definition(s), register all service providers defined in these modules and when asked inject
|
||||
definition(s), register all service providers defined in these modules, and when asked, inject
|
||||
a specified function with dependencies (services) that it lazily instantiates via their providers.
|
||||
|
||||
Providers are objects that provide (create) instances of services and expose configuration APIs
|
||||
|
||||
@@ -147,7 +147,7 @@ __`test/unit/controllersSpec.js`:__
|
||||
...
|
||||
</pre>
|
||||
|
||||
You should now see the following output in the Testacular tab:
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ angular.module('phonecatFilters', []).filter('checkmark', function() {
|
||||
</pre>
|
||||
|
||||
The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
|
||||
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
|
||||
`\u2718`).
|
||||
return one of the two unicode characters we have chosen to represent true (`\u2713` -> ✓) or false (`\u2718` -> ✘).
|
||||
|
||||
Now that our filter is ready, we need to register the `phonecatFilters` module as a dependency for
|
||||
our main `phonecat` module.
|
||||
@@ -110,7 +109,7 @@ describe('filter', function() {
|
||||
Note that you need to configure our test injector with the `phonecatFilters` module before any of
|
||||
our filter tests execute.
|
||||
|
||||
You should now see the following output in the Testacular tab:
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@ describe('PhoneCat controllers', function() {
|
||||
});
|
||||
</pre>
|
||||
|
||||
You should now see the following output in the Testacular tab:
|
||||
You should now see the following output in the Karma tab:
|
||||
|
||||
Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||
previous steps using the `git checkout` commandx.
|
||||
previous steps using the `git checkout` command.
|
||||
|
||||
For more details and examples of the Angular concepts we touched on in this tutorial, see the
|
||||
{@link guide/ Developer Guide}.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0px" y="0px" width="687px" height="176px" viewBox="0 0 687 176" overflow="visible" enable-background="new 0 0 687 176"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#FFFFFF" d="M179.011,125.328V54.527h9.158l43.322,57.035V54.527h8.666v70.801h-9.158l-43.326-57.536v57.536H179.011z
|
||||
M179.011,125.328"/>
|
||||
<path fill="#FFFFFF" d="M310.46,122.554c-5.708,2.182-11.864,3.269-18.467,3.269c-25.644,0-38.469-12.294-38.469-36.887
|
||||
c0-23.27,12.378-34.908,37.134-34.908c7.096,0,13.7,0.994,19.802,2.976v7.921c-6.103-2.311-12.378-3.468-18.813-3.468
|
||||
c-19.306,0-28.96,9.162-28.96,27.479c0,19.639,9.504,29.463,28.517,29.463c3.034,0,6.404-0.396,10.103-1.193V93.145h9.154V122.554z
|
||||
M310.46,122.554"/>
|
||||
<path fill="#FFFFFF" d="M325.067,97.996V54.523h9.154v43.473c0,13.598,6.768,20.4,20.303,20.4c13.531,0,20.301-6.803,20.301-20.4
|
||||
V54.523h9.158v43.473c0,18.556-9.82,27.825-29.459,27.825C334.886,125.821,325.067,116.552,325.067,97.996L325.067,97.996z
|
||||
M325.067,97.996"/>
|
||||
<path fill="#FFFFFF" d="M409.48,54.523v63.376h37.037v7.425h-46.191V54.523H409.48z M409.48,54.523"/>
|
||||
<path fill="#FFFFFF" d="M459.736,125.327h-9.504l35.201-80.146l35.199,80.146h-10.15l-9.158-22.282h-23.418l2.527-7.424h17.82
|
||||
l-13.217-32.088L459.736,125.327z M459.736,125.327"/>
|
||||
<path fill="#FFFFFF" d="M530.289,125.328V54.527h30.203c13.469,0,20.197,5.659,20.197,16.982c0,9.207-6.578,16.028-19.75,20.445
|
||||
l24.309,33.374h-12.086l-22.521-31.835v-5.992c13.531-2.151,20.301-7.344,20.301-15.598c0-6.533-3.766-9.801-11.293-9.801h-20.201
|
||||
v63.226H530.289z M530.289,125.328"/>
|
||||
<path fill="#B52E31" d="M619.561,54.523v50.405c0,13.603-8.006,20.396-24.016,20.396V117.9c9.902,0,14.857-4.329,14.857-12.973
|
||||
V54.523H619.561z M619.561,54.523"/>
|
||||
<path fill="#B52E31" d="M635.896,122.849v-8.418c7.428,2.639,15.447,3.965,24.064,3.965c12.178,0,18.271-4.457,18.271-13.372
|
||||
c0-7.584-4.492-11.385-13.469-11.385h-9.113c-14.818,0-22.234-6.435-22.234-19.31c0-13.531,9.492-20.303,28.479-20.303
|
||||
c8.25,0,15.922,0.998,23.021,2.976v8.418c-7.1-2.644-14.771-3.965-23.021-3.965c-12.875,0-19.311,4.293-19.311,12.875
|
||||
c0,7.588,4.352,11.385,13.066,11.385h9.113c15.08,0,22.627,6.439,22.627,19.31c0,13.864-9.141,20.796-27.43,20.796
|
||||
C651.344,125.819,643.324,124.826,635.896,122.849L635.896,122.849z M635.896,122.849"/>
|
||||
<path fill="#B2B2B2" d="M82.688,0L0,29.1l13.066,108.335l69.71,38.314l70.069-38.834l13.062-108.331L82.688,0z M82.688,0"/>
|
||||
<path fill="#B52E31" d="M157.66,34.846L82.496,9.214v157.381l62.991-34.861L157.66,34.846z M157.66,34.846"/>
|
||||
<path fill="#E23237" d="M9.279,35.308l11.196,96.889l62.019,34.398V9.211L9.279,35.308z M9.279,35.308"/>
|
||||
<path fill="#F2F2F2" d="M99.918,87.493L82.632,51.396L67.415,87.493H99.918z M106.508,102.672h-45.82l-10.251,25.64l-19.067,0.352
|
||||
L82.496,14.929l52.908,113.734h-17.673L106.508,102.672z M106.508,102.672"/>
|
||||
<path fill="#B2B2B2" d="M82.496,14.929l0.136,36.467l17.268,36.125H82.534l-0.039,15.127l24.012,0.023l11.223,25.996l18.245,0.339
|
||||
L82.496,14.929z M82.496,14.929"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
+62
-30
@@ -55,12 +55,15 @@ describe('ngdoc', function() {
|
||||
'@name a\n' +
|
||||
'@param {*} a short\n' +
|
||||
'@param {Type} b med\n' +
|
||||
'@param {Class=} [c=2] long\nline');
|
||||
'@param {Class=} [c=2] long\nline\n' +
|
||||
'@param {function(number, string=)} d fn with optional arguments');
|
||||
doc.parse();
|
||||
expect(doc.param).toEqual([
|
||||
{name:'a', description:'<p>short</p>', type:'*', optional:false, 'default':undefined},
|
||||
{name:'b', description:'<p>med</p>', type:'Type', optional:false, 'default':undefined},
|
||||
{name:'c', description:'<p>long\nline</p>', type:'Class', optional:true, 'default':'2'}
|
||||
{name:'a', description:'<div class="a-page"><p>short</p></div>', type:'*', optional:false, 'default':undefined},
|
||||
{name:'b', description:'<div class="a-page"><p>med</p></div>', type:'Type', optional:false, 'default':undefined},
|
||||
{name:'c', description:'<div class="a-page"><p>long\nline</p></div>', type:'Class', optional:true, 'default':'2'},
|
||||
{name:'d', description:'<div class="a-page"><p>fn with optional arguments</p></div>',
|
||||
type: 'function(number, string=)', optional: false, 'default':undefined}
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -69,7 +72,7 @@ describe('ngdoc', function() {
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({
|
||||
type: 'Type',
|
||||
description: '<p>text <em>bold</em>.</p>'
|
||||
description: '<div class="a-page"><p>text <em>bold</em>.</p></div>'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -135,16 +138,30 @@ describe('ngdoc', function() {
|
||||
it('should not replace anything in <pre>, but escape the html escape the content', function() {
|
||||
expect(new Doc().markdown('bah x\n<pre>\n<b>angular</b>.k\n</pre>\n asdf x')).
|
||||
toEqual(
|
||||
'<p>bah x\n' +
|
||||
'<div class="docs-page"><p>bah x\n' +
|
||||
'<pre class="prettyprint linenums">\n' +
|
||||
'<b>angular</b>.k\n' +
|
||||
'</pre>\n' +
|
||||
' asdf x</p>');
|
||||
' asdf x</p></div>');
|
||||
});
|
||||
|
||||
it('should wrap everything inside a container tag', function() {
|
||||
var doc = new Doc('@name superman').parse();
|
||||
var content = doc.markdown('hello');
|
||||
|
||||
expect(content).toMatch('<div class="superman-page"><p>hello</p></div>');
|
||||
});
|
||||
|
||||
it('should use the content before a colon as the name prefix for the className of the tag container', function() {
|
||||
var doc = new Doc('@name super: man').parse();
|
||||
var content = doc.markdown('hello');
|
||||
|
||||
expect(content).toMatch('<div class="super-page super-man-page"><p>hello</p></div>');
|
||||
});
|
||||
|
||||
it('should replace text between two <pre></pre> tags', function() {
|
||||
expect(new Doc().markdown('<pre>x</pre>\n# One\n<pre>b</pre>')).
|
||||
toMatch('</pre>\n\n<h1>One</h1>\n\n<pre');
|
||||
toMatch('</pre>\n\n<h1 id="one">One</h1>\n\n<pre');
|
||||
});
|
||||
|
||||
it('should ignore nested doc widgets', function() {
|
||||
@@ -154,11 +171,11 @@ describe('ngdoc', function() {
|
||||
'\ngit bla bla\n</doc:tutorial-instruction>\n' +
|
||||
'</doc:tutorial-instructions>')).toEqual(
|
||||
|
||||
'<p>before<div class="tabbable">\n' +
|
||||
'<div class="docs-page"><p>before<div class="tabbable">\n' +
|
||||
'<div class="tab-pane well" id="git-mac" ng:model="Git on Mac/Linux">\n' +
|
||||
'git bla bla\n' +
|
||||
'</doc:tutorial-instruction>\n' +
|
||||
'</doc:tutorial-instructions></p>');
|
||||
'</doc:tutorial-instructions></p></div>');
|
||||
});
|
||||
|
||||
it('should unindent text before processing based on the second line', function() {
|
||||
@@ -260,7 +277,7 @@ describe('ngdoc', function() {
|
||||
name : 'number',
|
||||
optional: false,
|
||||
'default' : undefined,
|
||||
description : '<p>Number \nto format.</p>' }]);
|
||||
description : '<div class="a-page"><p>Number \nto format.</p></div>' }]);
|
||||
});
|
||||
|
||||
it('should parse with default and optional', function() {
|
||||
@@ -271,7 +288,7 @@ describe('ngdoc', function() {
|
||||
name : 'fractionSize',
|
||||
optional: true,
|
||||
'default' : '2',
|
||||
description : '<p>desc</p>' }]);
|
||||
description : '<div class="a-page"><p>desc</p></div>' }]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -281,8 +298,8 @@ describe('ngdoc', function() {
|
||||
doc.ngdoc = 'service';
|
||||
doc.parse();
|
||||
expect(doc.requires).toEqual([
|
||||
{name:'$service', text:'<p>for \n<code>A</code></p>'},
|
||||
{name:'$another', text:'<p>for <code>B</code></p>'}]);
|
||||
{name:'$service', text:'<div class="a-page"><p>for \n<code>A</code></p></div>'},
|
||||
{name:'$another', text:'<div class="a-page"><p>for <code>B</code></p></div>'}]);
|
||||
expect(doc.html()).toContain('<a href="api/ng.$service">$service</a>');
|
||||
expect(doc.html()).toContain('<a href="api/ng.$another">$another</a>');
|
||||
expect(doc.html()).toContain('<p>for \n<code>A</code></p>');
|
||||
@@ -318,9 +335,9 @@ describe('ngdoc', function() {
|
||||
});
|
||||
|
||||
it('should not parse @property without a type', function() {
|
||||
var doc = new Doc("@property fake");
|
||||
var doc = new Doc("@property fake", 'test.js', '44');
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow(new Error("Not a valid 'property' format: fake"));
|
||||
toThrow(new Error("Not a valid 'property' format: fake (found in: test.js:44)"));
|
||||
});
|
||||
|
||||
it('should parse @property with type', function() {
|
||||
@@ -334,7 +351,7 @@ describe('ngdoc', function() {
|
||||
var doc = new Doc("@name a\n@property {string} name desc rip tion");
|
||||
doc.parse();
|
||||
expect(doc.properties[0].name).toEqual('name');
|
||||
expect(doc.properties[0].description).toEqual('<p>desc rip tion</p>');
|
||||
expect(doc.properties[0].description).toEqual('<div class="a-page"><p>desc rip tion</p></div>');
|
||||
});
|
||||
|
||||
it('should parse @property with type and description both', function() {
|
||||
@@ -342,7 +359,7 @@ describe('ngdoc', function() {
|
||||
doc.parse();
|
||||
expect(doc.properties[0].name).toEqual('name');
|
||||
expect(doc.properties[0].type).toEqual('bool');
|
||||
expect(doc.properties[0].description).toEqual('<p>desc rip tion</p>');
|
||||
expect(doc.properties[0].description).toEqual('<div class="a-page"><p>desc rip tion</p></div>');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -350,26 +367,41 @@ describe('ngdoc', function() {
|
||||
describe('@returns', function() {
|
||||
it('should not parse @returns without type', function() {
|
||||
var doc = new Doc("@returns lala");
|
||||
expect(doc.parse).toThrow();
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should not parse @returns with invalid type', function() {
|
||||
var doc = new Doc("@returns {xx}x} lala", 'test.js', 34);
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow(new Error("Not a valid 'returns' format: {xx}x} lala (found in: test.js:34)"));
|
||||
});
|
||||
|
||||
|
||||
it('should parse @returns with type and description', function() {
|
||||
var doc = new Doc("@name a\n@returns {string} descrip tion");
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip tion</p>'});
|
||||
expect(doc.returns).toEqual({type: 'string', description: '<div class="a-page"><p>descrip tion</p></div>'});
|
||||
});
|
||||
|
||||
it('should parse @returns with complex type and description', function() {
|
||||
var doc = new Doc("@name a\n@returns {function(string, number=)} description");
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({type: 'function(string, number=)', description: '<div class="a-page"><p>description</p></div>'});
|
||||
});
|
||||
|
||||
it('should transform description of @returns with markdown', function() {
|
||||
var doc = new Doc("@name a\n@returns {string} descrip *tion*");
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip <em>tion</em></p>'});
|
||||
expect(doc.returns).toEqual({type: 'string', description: '<div class="a-page"><p>descrip <em>tion</em></p></div>'});
|
||||
});
|
||||
|
||||
it('should support multiline content', function() {
|
||||
var doc = new Doc("@name a\n@returns {string} description\n new line\n another line");
|
||||
doc.parse();
|
||||
expect(doc.returns).
|
||||
toEqual({type: 'string', description: '<p>description\nnew line\nanother line</p>'});
|
||||
toEqual({type: 'string', description: '<div class="a-page"><p>description\nnew line\nanother line</p></div>'});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -378,18 +410,18 @@ describe('ngdoc', function() {
|
||||
var doc = new Doc("@name a\n@description <pre><b>abc</b></pre>");
|
||||
doc.parse();
|
||||
expect(doc.description).
|
||||
toBe('<pre class="prettyprint linenums"><b>abc</b></pre>');
|
||||
toBe('<div class="a-page"><pre class="prettyprint linenums"><b>abc</b></pre></div>');
|
||||
});
|
||||
|
||||
it('should support multiple pre blocks', function() {
|
||||
var doc = new Doc("@name a\n@description foo \n<pre>abc</pre>\n#bah\nfoo \n<pre>cba</pre>");
|
||||
doc.parse();
|
||||
expect(doc.description).
|
||||
toBe('<p>foo \n' +
|
||||
toBe('<div class="a-page"><p>foo \n' +
|
||||
'<pre class="prettyprint linenums">abc</pre>\n\n' +
|
||||
'<h1>bah</h1>\n\n' +
|
||||
'<h1 id="bah">bah</h1>\n\n' +
|
||||
'<p>foo \n' +
|
||||
'<pre class="prettyprint linenums">cba</pre>');
|
||||
'<pre class="prettyprint linenums">cba</pre></div>');
|
||||
|
||||
});
|
||||
|
||||
@@ -432,7 +464,7 @@ describe('ngdoc', function() {
|
||||
it('should not remove {{}}', function() {
|
||||
var doc = new Doc('@name a\n@example text {{ abc }}');
|
||||
doc.parse();
|
||||
expect(doc.example).toEqual('<p>text {{ abc }}</p>');
|
||||
expect(doc.example).toEqual('<div class="a-page"><p>text {{ abc }}</p></div>');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -451,10 +483,10 @@ describe('ngdoc', function() {
|
||||
doc.parse();
|
||||
expect(doc.html()).toContain('<h3>Method\'s <code>this</code></h3>\n' +
|
||||
'<div>' +
|
||||
'<p>I am self.</p>' +
|
||||
'<div class="a-page"><p>I am self.</p></div>' +
|
||||
'</div>\n');
|
||||
expect(doc.html()).toContain('<h3>Method\'s <code>this</code></h3>\n' +
|
||||
'<div><p>I am self.</p></div>');
|
||||
'<div><div class="a-page"><p>I am self.</p></div></div>');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -465,7 +497,7 @@ describe('ngdoc', function() {
|
||||
var doc = new Doc('@ngdoc overview\n@name angular\n@description\n#heading\ntext');
|
||||
doc.parse();
|
||||
expect(doc.html()).toContain('text');
|
||||
expect(doc.html()).toContain('<h2>heading</h2>');
|
||||
expect(doc.html()).toContain('<h1 id="heading">heading</h2>');
|
||||
expect(doc.html()).not.toContain('Description');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,10 +5,6 @@ var reader = require('./reader.js'),
|
||||
appCache = require('./appCache.js').appCache,
|
||||
Q = require('qq');
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
console.error(err.stack || err);
|
||||
});
|
||||
|
||||
var start = now();
|
||||
var docs;
|
||||
|
||||
@@ -36,16 +32,16 @@ writer.makeDir('build/docs/', true).then(function() {
|
||||
});
|
||||
}).then(function printStats() {
|
||||
console.log('DONE. Generated ' + docs.length + ' pages in ' + (now()-start) + 'ms.' );
|
||||
}).end();
|
||||
}).done();
|
||||
|
||||
|
||||
function writeTheRest(writesFuture) {
|
||||
var metadata = ngdoc.metadata(docs);
|
||||
|
||||
writesFuture.push(writer.symlinkTemplate('css'));
|
||||
writesFuture.push(writer.symlinkTemplate('font'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img'));
|
||||
writesFuture.push(writer.symlinkTemplate('js'));
|
||||
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('font', 'dir'));
|
||||
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img', 'dir'));
|
||||
writesFuture.push(writer.symlinkTemplate('js', 'dir'));
|
||||
|
||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||
|
||||
|
||||
+80
-45
@@ -2,7 +2,7 @@
|
||||
* All parsing/transformation code goes here. All code here should be sync to ease testing.
|
||||
*/
|
||||
|
||||
var Showdown = require('../../lib/showdown').Showdown;
|
||||
var Showdown = require('showdown');
|
||||
var DOM = require('./dom.js').DOM;
|
||||
var htmlEscape = require('./dom.js').htmlEscape;
|
||||
var Example = require('./example.js').Example;
|
||||
@@ -173,8 +173,27 @@ Doc.prototype = {
|
||||
'</a>';
|
||||
});
|
||||
});
|
||||
|
||||
text = parts.join('');
|
||||
text = new Showdown.converter().makeHtml(text);
|
||||
|
||||
function prepareClassName(text) {
|
||||
return text.toLowerCase().replace(/[_\W]+/g, '-');
|
||||
};
|
||||
|
||||
var pageClassName, suffix = '-page';
|
||||
if(this.name) {
|
||||
var split = this.name.match(/^\s*(.+?)\s*:\s*(.+)/);
|
||||
if(split && split.length > 1) {
|
||||
var before = prepareClassName(split[1]);
|
||||
var after = prepareClassName(split[2]);
|
||||
pageClassName = before + suffix + ' ' + before + '-' + after + suffix;
|
||||
}
|
||||
}
|
||||
pageClassName = pageClassName || prepareClassName(this.name || 'docs') + suffix;
|
||||
|
||||
text = '<div class="' + pageClassName + '">' +
|
||||
(new Showdown.converter({ extensions : ['table'] }).makeHtml(text)) +
|
||||
'</div>';
|
||||
text = text.replace(/(?:<p>)?(REPLACEME\d+)(?:<\/p>)?/g, function(_, id) {
|
||||
return placeholderMap[id];
|
||||
});
|
||||
@@ -203,7 +222,7 @@ Doc.prototype = {
|
||||
flush();
|
||||
this.shortName = this.name.split(/[\.:#]/).pop().trim();
|
||||
this.id = this.id || // if we have an id just use it
|
||||
(((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) || // try to extract it from file name
|
||||
(((this.file||'').match(/.*(\/|\\)([^(\/|\\)]*)\.ngdoc/)||{})[2]) || // try to extract it from file name
|
||||
this.name; // default to name
|
||||
this.description = this.markdown(this.description);
|
||||
this.example = this.markdown(this.example);
|
||||
@@ -214,23 +233,25 @@ Doc.prototype = {
|
||||
if (atName) {
|
||||
var text = trim(atText.join('\n')), match;
|
||||
if (atName == 'param') {
|
||||
match = text.match(/^\{([^}=]+)(=)?\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||
// 1 12 2 34 4 5 5 6 6 3 7 7
|
||||
match = text.match(/^\{([^}]+)\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||
// 1 1 23 3 4 4 5 5 2 6 6
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'param' format: " + text);
|
||||
throw new Error("Not a valid 'param' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
|
||||
var optional = (match[1].slice(-1) === '=');
|
||||
var param = {
|
||||
name: match[5] || match[4],
|
||||
description:self.markdown(text.replace(match[0], match[7])),
|
||||
type: match[1],
|
||||
optional: !!match[2],
|
||||
'default':match[6]
|
||||
name: match[4] || match[3],
|
||||
description:self.markdown(text.replace(match[0], match[6])),
|
||||
type: optional ? match[1].substring(0, match[1].length-1) : match[1],
|
||||
optional: optional,
|
||||
'default':match[5]
|
||||
};
|
||||
self.param.push(param);
|
||||
} else if (atName == 'returns' || atName == 'return') {
|
||||
match = text.match(/^\{([^}=]+)\}\s+(.*)/);
|
||||
match = text.match(/^\{([^}]+)\}\s+(.*)/);
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'returns' format: " + text + ' in ' + self.file + ':' + self.line);
|
||||
throw new Error("Not a valid 'returns' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
self.returns = {
|
||||
type: match[1],
|
||||
@@ -245,7 +266,7 @@ Doc.prototype = {
|
||||
} else if(atName == 'property') {
|
||||
match = text.match(/^\{(\S+)\}\s+(\S+)(\s+(.*))?/);
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'property' format: " + text);
|
||||
throw new Error("Not a valid 'property' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
var property = new Doc({
|
||||
type: match[1],
|
||||
@@ -270,8 +291,9 @@ Doc.prototype = {
|
||||
self = this;
|
||||
|
||||
dom.h(title(this.name), function() {
|
||||
notice('deprecated', 'Deprecated API', self.deprecated);
|
||||
|
||||
notice('deprecated', 'Deprecated API', self.deprecated);
|
||||
dom.tag('a', {href: 'http://github.com/angular/angular.js/edit/master/' + self.file, class: 'improve-docs btn btn-primary'}, 'Improve this doc');
|
||||
if (self.ngdoc != 'overview') {
|
||||
dom.h('Description', self.description, dom.html);
|
||||
}
|
||||
@@ -383,40 +405,53 @@ Doc.prototype = {
|
||||
var self = this;
|
||||
dom.h('Usage', function() {
|
||||
var restrict = self.restrict || 'AC';
|
||||
|
||||
if (restrict.match(/E/)) {
|
||||
dom.text('as element (see ');
|
||||
dom.text('This directive can be used as custom element, but be aware of ');
|
||||
dom.tag('a', {href:'guide/ie'}, 'IE restrictions');
|
||||
dom.text(')');
|
||||
dom.code(function() {
|
||||
dom.text('<');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"');
|
||||
dom.text('>\n</');
|
||||
dom.text(dashCase(self.shortName));
|
||||
dom.text('>');
|
||||
});
|
||||
dom.text('.');
|
||||
}
|
||||
if (restrict.match(/A/)) {
|
||||
var element = self.element || 'ANY';
|
||||
dom.text('as attribute');
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' ');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"', true);
|
||||
dom.text('>\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/C/)) {
|
||||
dom.text('as class');
|
||||
var element = self.element || 'ANY';
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' class="');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams(' ', ': ', ';', true);
|
||||
dom.text('">\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
|
||||
if (self.usage) {
|
||||
dom.tag('pre', function() {
|
||||
dom.tag('code', function() {
|
||||
dom.text(self.usage);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (restrict.match(/E/)) {
|
||||
dom.text('as element:');
|
||||
dom.code(function() {
|
||||
dom.text('<');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"');
|
||||
dom.text('>\n</');
|
||||
dom.text(dashCase(self.shortName));
|
||||
dom.text('>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/A/)) {
|
||||
var element = self.element || 'ANY';
|
||||
dom.text('as attribute');
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' ');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"', true);
|
||||
dom.text('>\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/C/)) {
|
||||
dom.text('as class');
|
||||
var element = self.element || 'ANY';
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' class="');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams(' ', ': ', ';', true);
|
||||
dom.text('">\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
}
|
||||
self.html_usage_directiveInfo(dom);
|
||||
self.html_usage_parameters(dom);
|
||||
|
||||
+3
-2
@@ -7,7 +7,8 @@ exports.collect = collect;
|
||||
|
||||
var ngdoc = require('./ngdoc.js'),
|
||||
Q = require('qq'),
|
||||
qfs = require('q-fs');
|
||||
qfs = require('q-fs'),
|
||||
PATH = require('path');
|
||||
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
@@ -43,7 +44,7 @@ function collect() {
|
||||
var work2;
|
||||
if (file.match(/\.ngdoc$/)) {
|
||||
work2 = Q.when(qfs.read(file, 'b'), function(content){
|
||||
var section = '@section ' + file.split('/')[2] + '\n';
|
||||
var section = '@section ' + file.split(PATH.sep)[2] + '\n';
|
||||
allDocs.push(new ngdoc.Doc(section + content.toString(),file, 1).parse());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# current angular version. If this rule matches the appcache-offline.manifest will be served for
|
||||
# requests to appcache.manifest
|
||||
#
|
||||
# This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version.
|
||||
# This file must be processed by Grunt in order to replace %ANGULAR_VERSION% with the actual version.
|
||||
|
||||
Options -Indexes
|
||||
RewriteEngine on
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
img.AngularJS-small {
|
||||
width: 95px;
|
||||
height: 25px;
|
||||
/* Logo */
|
||||
|
||||
.header .brand {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.header .brand img {
|
||||
height: 25px;
|
||||
width: 92px;
|
||||
}
|
||||
|
||||
/* end: Logo */
|
||||
|
||||
|
||||
.clear-navbar {
|
||||
margin-top: 60px;
|
||||
@@ -86,6 +95,15 @@ img.AngularJS-small {
|
||||
/* Content */
|
||||
/* =============================== */
|
||||
|
||||
.improve-docs {
|
||||
float: right;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.improve-docs {
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: .7em;
|
||||
color: #c0c0c0;
|
||||
@@ -184,3 +202,18 @@ ul.events > li > h3 {
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tutorial-index-page,
|
||||
.tutorial-the-end-page {
|
||||
padding-top:50px;
|
||||
}
|
||||
|
||||
.tutorial-page {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.tutorial-page .improve-docs {
|
||||
position:absolute;
|
||||
top:0;
|
||||
right:0;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
headEl = document.head,
|
||||
angularVersion = {
|
||||
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||
stable: '"NG_VERSION_STABLE"'
|
||||
cdn: '"NG_VERSION_CDN"'
|
||||
};
|
||||
|
||||
addTag('script', {src: path('angular-scenario.js')}, function() {
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
function path(name) {
|
||||
return production
|
||||
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
|
||||
? 'http://code.angularjs.org/' + angularVersion.cdn + '/' + name
|
||||
: '../' + name;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
sync = true,
|
||||
angularVersion = {
|
||||
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||
stable: '"NG_VERSION_STABLE"'
|
||||
cdn: '"NG_VERSION_CDN"'
|
||||
};
|
||||
|
||||
addTag('base', {href: baseUrl});
|
||||
@@ -48,12 +48,12 @@
|
||||
if (production) {
|
||||
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
|
||||
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
|
||||
angularVersion.stable +
|
||||
angularVersion.cdn +
|
||||
'/' +
|
||||
name.replace(/\.js$/, '.min.js');
|
||||
} else {
|
||||
name = 'http://code.angularjs.org/' +
|
||||
angularVersion.stable +
|
||||
angularVersion.cdn +
|
||||
'/' +
|
||||
name.replace(/\.js$/, '.min.js');
|
||||
}
|
||||
@@ -114,15 +114,15 @@
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="http://angularjs.org" style="padding-top: 6px; padding-bottom: 0px;">
|
||||
<img class="AngularJS-small" src="http://angularjs.org/img/AngularJS-small.png">
|
||||
<a class="brand" href="http://angularjs.org">
|
||||
<img class="logo" src="img/angularjs-for-header-only.svg">
|
||||
</a>
|
||||
<ul class="nav">
|
||||
<li class="divider-vertical"></li>
|
||||
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@@ -130,6 +130,7 @@
|
||||
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="http://builtwith.angularjs.org/">Case Studies</a></li>
|
||||
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
|
||||
<li><a href="misc/faq">FAQ</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -139,16 +140,16 @@
|
||||
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://docs.angularjs.org/tutorial">Tutorial</a></li>
|
||||
<li><a href="http://docs.angularjs.org/guide/">Developer Guide</a></li>
|
||||
<li><a href="http://docs.angularjs.org/api/">API Reference</a></li>
|
||||
<li><a href="./tutorial/">Tutorial</a></li>
|
||||
<li><a href="./guide/">Developer Guide</a></li>
|
||||
<li><a href="./api/">API Reference</a></li>
|
||||
<li><a href="http://docs.angularjs.org/misc/contribute">Contribute</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
@@ -203,7 +204,7 @@
|
||||
<div class="dropdown search"
|
||||
ng-class="{open: focused && bestMatch.rank > 0 && bestMatch.page != currentPage}">
|
||||
<input type="text" ng-model="search" placeholder="search the docs"
|
||||
tabindex="1" accesskey="s" class="input-medium search-query" focused="focused">
|
||||
tabindex="1" accesskey="s" class="input-medium search-query" />
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="{{bestMatch.page.url}}">{{bestMatch.page.shortName}}</a>
|
||||
|
||||
@@ -18,8 +18,8 @@ docsApp.directive.focused = function($timeout) {
|
||||
scope.$eval(attrs.focused + '=false');
|
||||
});
|
||||
});
|
||||
scope.$eval(attrs.focused + '=true')
|
||||
}
|
||||
scope.$eval(attrs.focused + '=true');
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||
'<ul class="dropdown-menu">' +
|
||||
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
|
||||
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
|
||||
'</ul>',
|
||||
'</ul>' +
|
||||
'</div>',
|
||||
scope: true,
|
||||
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
|
||||
var sources = {
|
||||
@@ -58,7 +59,7 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||
openPlunkr(sources);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function read(text) {
|
||||
var files = [];
|
||||
@@ -126,7 +127,7 @@ docsApp.directive.docTutorialReset = function() {
|
||||
'</div>\n');
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
docsApp.serviceFactory.angularUrls = function($document) {
|
||||
@@ -140,7 +141,7 @@ docsApp.serviceFactory.angularUrls = function($document) {
|
||||
});
|
||||
|
||||
return urls;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
docsApp.serviceFactory.formPostData = function($document) {
|
||||
@@ -173,7 +174,7 @@ docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angula
|
||||
var scriptDeps = '';
|
||||
angular.forEach(content.deps, function(file) {
|
||||
if (file.name !== 'angular.js') {
|
||||
scriptDeps += ' <script src="' + file.name + '"></script>\n'
|
||||
scriptDeps += ' <script src="' + file.name + '"></script>\n';
|
||||
}
|
||||
});
|
||||
indexProp = {
|
||||
@@ -189,7 +190,9 @@ docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angula
|
||||
});
|
||||
|
||||
postData['files[index.html]'] = templateMerge(indexHtmlContent, indexProp);
|
||||
|
||||
postData['tags[]'] = "angularjs";
|
||||
|
||||
postData.private = true;
|
||||
postData.description = 'AngularJS Example Plunkr';
|
||||
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
@@ -307,7 +310,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
last: this.$last,
|
||||
active: page1 && this.currentPage == page1 || page2 && this.currentPage == page2
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
$scope.submitForm = function() {
|
||||
$scope.bestMatch && $location.path($scope.bestMatch.page.url);
|
||||
@@ -506,7 +509,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
},
|
||||
types: [],
|
||||
filters: []
|
||||
}
|
||||
};
|
||||
modules.push(module);
|
||||
}
|
||||
return module;
|
||||
@@ -557,7 +560,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
|
||||
angular.element(document.getElementById('disqus_thread')).html('');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
angular.module('docsApp', ['ngResource', 'ngCookies', 'ngSanitize', 'bootstrap', 'bootstrapPrettify']).
|
||||
|
||||
+4
-5
@@ -61,22 +61,21 @@ exports.copy = function(from, to, transform) {
|
||||
|
||||
|
||||
exports.symlink = symlink;
|
||||
function symlink(from, to) {
|
||||
function symlink(from, to, type) {
|
||||
return qfs.exists(to).then(function(exists) {
|
||||
if (!exists) {
|
||||
return qfs.symbolicLink(to, from);
|
||||
return qfs.symbolicLink(to, from, type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
exports.symlinkTemplate = symlinkTemplate;
|
||||
function symlinkTemplate(filename) {
|
||||
function symlinkTemplate(filename, type) {
|
||||
var dest = OUTPUT_DIR + filename,
|
||||
dirDepth = dest.split('/').length,
|
||||
src = Array(dirDepth).join('../') + 'docs/src/templates/' + filename;
|
||||
|
||||
return symlink(src, dest);
|
||||
return symlink(src, dest, type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<html ng-app="personalLog">
|
||||
<head>
|
||||
<title>Personal Log</title>
|
||||
<script src="../../src/loader.js"></script>
|
||||
|
||||
+158
-121
@@ -16,14 +16,14 @@
|
||||
/**
|
||||
* @fileoverview A utility to get better currency format pattern.
|
||||
*
|
||||
* This module implement a new currency format representation model. It
|
||||
* This module implements a new currency format representation model. It
|
||||
* provides 3 currency representation forms: global, portable and local. Local
|
||||
* format is the most popular format people use to represent currency in its
|
||||
* circulating country without worrying about how it should be distinguished
|
||||
* from other currencies. Global format is a formal representation in context
|
||||
* of multiple currencies in same page, it is ISO 4217 currency code. Portable
|
||||
* format is a compromise between global and local. It looks similar to how
|
||||
* people would like to see how their currencies is being represented in other
|
||||
* people would like to see how their currency is being represented in other
|
||||
* media. While at the same time, it should be distinguishable to world's
|
||||
* popular currencies (like USD, EUR) and currencies somewhat relevant in the
|
||||
* area (like CNY in HK, though native currency is HKD). There is no guarantee
|
||||
@@ -43,15 +43,14 @@ goog.i18n.currency.PRECISION_MASK_ = 0x07;
|
||||
|
||||
|
||||
/**
|
||||
* If this flag is set, it means the currency sign should position before
|
||||
* number.
|
||||
* Whether the currency sign should be positioned after the number.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.currency.POSITION_FLAG_ = 0x08;
|
||||
|
||||
|
||||
/**
|
||||
* Should a space to inserted between number and currency sign.
|
||||
* Whether a space should be inserted between the number and currency sign.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.currency.SPACE_FLAG_ = 0x20;
|
||||
@@ -59,8 +58,8 @@ goog.i18n.currency.SPACE_FLAG_ = 0x20;
|
||||
|
||||
/**
|
||||
* This function will add tier2 currency support. Be default, only tier1
|
||||
* (most popular currencies) are supportted. If an application really need
|
||||
* to support some of the rarely used currency, it should call this function
|
||||
* (most popular currencies) are supported. If an application really needs
|
||||
* to support some of the rarely used currencies, it should call this function
|
||||
* before any other functions in this namespace.
|
||||
*/
|
||||
goog.i18n.currency.addTier2Support = function() {
|
||||
@@ -75,8 +74,8 @@ goog.i18n.currency.addTier2Support = function() {
|
||||
* Global currency pattern always uses ISO-4217 currency code as prefix. Local
|
||||
* currency sign is added if it is different from currency code. Each currency
|
||||
* is unique in this form. The negative side is that ISO code looks weird in
|
||||
* some countries as poeple normally do not use it. Local currency sign
|
||||
* alleviate the problem, but also make it a little verbose.
|
||||
* some countries as people normally do not use it. Local currency sign
|
||||
* alleviates the problem, but also makes it a little verbose.
|
||||
*
|
||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||
* @return {string} Global currency pattern string for given currency.
|
||||
@@ -85,9 +84,6 @@ goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
|
||||
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||
var patternNum = info[0];
|
||||
if (currencyCode == info[1]) {
|
||||
if ((patternNum & goog.i18n.currency.POSITION_FLAG_) == 0) {
|
||||
patternNum |= goog.i18n.currency.SPACE_FLAG_;
|
||||
}
|
||||
return goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
|
||||
}
|
||||
return currencyCode + ' ' +
|
||||
@@ -104,10 +100,8 @@ goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
|
||||
*/
|
||||
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
|
||||
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||
if (currencyCode == info[1]) {
|
||||
return currencyCode;
|
||||
}
|
||||
return currencyCode + ' ' + info[1];
|
||||
return (currencyCode == info[1]) ? currencyCode :
|
||||
currencyCode + ' ' + info[1];
|
||||
};
|
||||
|
||||
|
||||
@@ -128,6 +122,7 @@ goog.i18n.currency.getLocalCurrencyPattern = function(currencyCode) {
|
||||
/**
|
||||
* Returns local currency sign string for those applications that need to
|
||||
* handle currency sign separately.
|
||||
*
|
||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||
* @return {string} Local currency sign for given currency.
|
||||
*/
|
||||
@@ -156,6 +151,7 @@ goog.i18n.currency.getPortableCurrencyPattern = function(currencyCode) {
|
||||
/**
|
||||
* Return portable currency sign string for those applications that need to
|
||||
* handle currency sign themselves.
|
||||
*
|
||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||
* @return {string} Portable currency sign for given currency.
|
||||
*/
|
||||
@@ -165,10 +161,13 @@ goog.i18n.currency.getPortableCurrencySign = function(currencyCode) {
|
||||
|
||||
|
||||
/**
|
||||
* This function returns the default currency sign position. Some application
|
||||
* This function returns the default currency sign position. Some applications
|
||||
* may want to handle currency sign and currency amount separately. This
|
||||
* function can be used in such situation to position the currency sign
|
||||
* relative to amount field correctly.
|
||||
* function can be used in such situations to correctly position the currency
|
||||
* sign relative to the amount.
|
||||
*
|
||||
* To match the behavior of ICU, position is not determined by display locale.
|
||||
*
|
||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||
* @return {boolean} true if currency should be positioned before amount field.
|
||||
*/
|
||||
@@ -179,13 +178,12 @@ goog.i18n.currency.isPrefixSignPosition = function(currencyCode) {
|
||||
|
||||
|
||||
/**
|
||||
* This function construct the currency pattern. Currency sign is provided. The
|
||||
* This function constructs the currency pattern. Currency sign is provided. The
|
||||
* pattern information is encoded in patternNum.
|
||||
*
|
||||
* @param {number} patternNum Encoded pattern number that has
|
||||
* currency pattern information.
|
||||
* @param {string} sign the currency sign that will be used in pattern.
|
||||
*
|
||||
* @param {string} sign The currency sign that will be used in pattern.
|
||||
* @return {string} currency pattern string.
|
||||
* @private
|
||||
*/
|
||||
@@ -211,56 +209,97 @@ goog.i18n.currency.getCurrencyPattern_ = function(patternNum, sign) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Modify currency pattern string by adjusting precision for given currency.
|
||||
* Standard currency pattern will have 2 digit after decimal point.
|
||||
* Examples:
|
||||
* $#,##0.00 -> $#,##0 (precision == 0)
|
||||
* $#,##0.00 -> $#,##0.0 (precision == 1)
|
||||
* $#,##0.00 -> $#,##0.000 (precision == 3)
|
||||
*
|
||||
* @param {string} pattern currency pattern string.
|
||||
* @param {string} currencyCode 3-letter currency code.
|
||||
* @return {string} modified currency pattern string.
|
||||
*/
|
||||
goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
|
||||
var strParts = ['0'];
|
||||
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||
var precision = info[0] & goog.i18n.currency.PRECISION_MASK_;
|
||||
if (precision > 0) {
|
||||
strParts.push('.');
|
||||
for (var i = 0; i < precision; i++) {
|
||||
strParts.push('0');
|
||||
}
|
||||
}
|
||||
return pattern.replace(/0.00/g, strParts.join(''));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tier 1 currency information.
|
||||
*
|
||||
* The first number in the array is a combination of the precision mask and
|
||||
* other flags. The precision mask indicates how many decimal places to show for
|
||||
* the currency. Valid values are [0..7]. The position flag indicates whether
|
||||
* the currency sign should be positioned after the number. Valid values are 0
|
||||
* (before the number) or 16 (after the number). The space flag indicates
|
||||
* whether a space should be inserted between the currency sign and number.
|
||||
* Valid values are 0 (no space) and 24 (space).
|
||||
*
|
||||
* The number in the array is calculated by adding together the mask and flag
|
||||
* values. For example:
|
||||
*
|
||||
* 0: no precision (0), currency sign first (0), no space (0)
|
||||
* 2: two decimals precision (2), currency sign first (0), no space (0)
|
||||
* 18: two decimals precision (2), currency sign last (16), no space (0)
|
||||
* 42: two decimals precision (2), currency sign last (16), space (24)
|
||||
*
|
||||
* @type {!Object.<!Array>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfo = {
|
||||
'AED': [2, '\u062F\u002e\u0625', 'DH'],
|
||||
'ARS': [2, '$', 'AR$'],
|
||||
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||
'AUD': [2, '$', 'AU$'],
|
||||
'BDT': [2, '\u09F3', 'Tk'],
|
||||
'BRL': [2, 'R$', 'R$'],
|
||||
'CAD': [2, '$', 'C$'],
|
||||
'CHF': [2, 'Fr.', 'CHF'],
|
||||
'CHF': [2, 'CHF', 'CHF'],
|
||||
'CLP': [0, '$', 'CL$'],
|
||||
'CNY': [2, '¥', 'RMB¥'],
|
||||
'COP': [2, '$', 'COL$'],
|
||||
'CRC': [2, '\u20a1', 'CR₡'],
|
||||
'CUP': [2, '$', '$MN'],
|
||||
'CZK': [10, 'Kč', 'Kč'],
|
||||
'DKK': [26, 'kr', 'kr'],
|
||||
'COP': [0, '$', 'COL$'],
|
||||
'CRC': [0, '\u20a1', 'CR\u20a1'],
|
||||
'CZK': [2, 'K\u010d', 'K\u010d'],
|
||||
'DKK': [18, 'kr', 'kr'],
|
||||
'DOP': [2, '$', 'RD$'],
|
||||
'EGP': [2, '£', 'LE'],
|
||||
'EUR': [26, '€', '€'],
|
||||
'EUR': [18, '€', '€'],
|
||||
'GBP': [2, '£', 'GB£'],
|
||||
'HKD': [2, '$', 'HK$'],
|
||||
'ILS': [10, '\u20AA', 'IL₪'],
|
||||
'INR': [2, 'Rs', 'Rs'],
|
||||
'ISK': [10, 'kr', 'kr'],
|
||||
'ILS': [2, '\u20AA', 'IL\u20AA'],
|
||||
'INR': [2, '\u20B9', 'Rs'],
|
||||
'ISK': [0, 'kr', 'kr'],
|
||||
'JMD': [2, '$', 'JA$'],
|
||||
'JPY': [0, '¥', 'JP¥'],
|
||||
'KRW': [0, '\u20A9', 'KR₩'],
|
||||
'LKR': [2, 'Rs', 'SLRs'],
|
||||
'MNT': [2, '\u20AE', 'MN₮'],
|
||||
'MNT': [0, '\u20AE', 'MN₮'],
|
||||
'MXN': [2, '$', 'Mex$'],
|
||||
'MYR': [2, 'RM', 'RM'],
|
||||
'NOK': [26, 'kr', 'NOkr'],
|
||||
'NOK': [18, 'kr', 'NOkr'],
|
||||
'PAB': [2, 'B/.', 'B/.'],
|
||||
'PEN': [2, 'S/.', 'S/.'],
|
||||
'PHP': [2, 'P', 'PHP'],
|
||||
'PKR': [2, 'Rs.', 'PKRs.'],
|
||||
'RUB': [10, 'руб', 'руб'],
|
||||
'SAR': [2, '\u0633\u002E\u0631', 'SR'],
|
||||
'SEK': [10, 'kr', 'kr'],
|
||||
'PHP': [2, '\u20B1', 'Php'],
|
||||
'PKR': [0, 'Rs', 'PKRs.'],
|
||||
'RUB': [42, 'руб.', 'руб.'],
|
||||
'SAR': [2, 'Rial', 'Rial'],
|
||||
'SEK': [2, 'kr', 'kr'],
|
||||
'SGD': [2, '$', 'S$'],
|
||||
'THB': [2, '\u0e3f', 'THB'],
|
||||
'TRY': [2, 'YTL', 'YTL'],
|
||||
'TRY': [2, 'TL', 'YTL'],
|
||||
'TWD': [2, 'NT$', 'NT$'],
|
||||
'USD': [2, '$', 'US$'],
|
||||
'UYU': [2, '$', 'UY$'],
|
||||
'VND': [10, '\u20AB', 'VN₫'],
|
||||
'YER': [2, 'YER', 'YER'],
|
||||
'VND': [0, '\u20AB', 'VN\u20AB'],
|
||||
'YER': [0, 'Rial', 'Rial'],
|
||||
'ZAR': [2, 'R', 'ZAR']
|
||||
};
|
||||
|
||||
@@ -270,116 +309,114 @@ goog.i18n.currency.CurrencyInfo = {
|
||||
* @type {!Object.<!Array>}
|
||||
*/
|
||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||
'AFN': [18, '\u060b', 'AFN'],
|
||||
'ALL': [2, 'Lek', 'Lek'],
|
||||
'AMD': [10, '\u0564\u0580\u002e', 'dram'],
|
||||
'ANG': [2, '\u0083', 'NAƒ'],
|
||||
'AFN': [16, 'Af.', 'AFN'],
|
||||
'ALL': [0, 'Lek', 'Lek'],
|
||||
'AMD': [0, 'Dram', 'dram'],
|
||||
'AOA': [2, 'Kz', 'Kz'],
|
||||
'AWG': [2, 'ƒ', 'Afl.'],
|
||||
'AZN': [2, 'm', 'man'],
|
||||
'BAM': [18, 'КМ', 'KM'],
|
||||
'ARS': [2, '$', 'AR$'],
|
||||
'AWG': [2, 'Afl.', 'Afl.'],
|
||||
'AZN': [2, 'man.', 'man.'],
|
||||
'BAM': [18, 'KM', 'KM'],
|
||||
'BBD': [2, '$', 'Bds$'],
|
||||
'BGN': [10, '\u043b\u0432', 'лв'],
|
||||
'BHD': [3, '\u0628\u002e\u062f\u002e', 'BD'],
|
||||
'BGN': [2, 'lev', 'lev'],
|
||||
'BHD': [3, 'din', 'din'],
|
||||
'BIF': [0, 'FBu', 'FBu'],
|
||||
'BMD': [2, '$', 'BD$'],
|
||||
'BND': [2, '$', 'B$'],
|
||||
'BOB': [2, 'B$', 'B$'],
|
||||
'BSD': [2, '$', 'B$'],
|
||||
'BOB': [2, 'Bs', 'Bs'],
|
||||
'BSD': [2, '$', 'BS$'],
|
||||
'BTN': [2, 'Nu.', 'Nu.'],
|
||||
'BWP': [2, 'P', 'pula'],
|
||||
'BYR': [0, 'Br', 'Br'],
|
||||
'BYR': [0, 'BYR', 'BYR'],
|
||||
'BZD': [2, '$', 'BZ$'],
|
||||
'CDF': [2, 'F', 'CDF'],
|
||||
'CVE': [2, '$', 'Esc'],
|
||||
'CDF': [2, 'FrCD', 'CDF'],
|
||||
'CUC': [1, '$', 'CUC$'],
|
||||
'CUP': [2, '$', 'CU$'],
|
||||
'CVE': [2, 'CVE', 'Esc'],
|
||||
'DJF': [0, 'Fdj', 'Fdj'],
|
||||
'DZD': [2, '\u062f\u062C', 'DA'],
|
||||
'EEK': [10, 'EEK', 'EEK'],
|
||||
'DZD': [2, 'din', 'din'],
|
||||
'ERN': [2, 'Nfk', 'Nfk'],
|
||||
'ETB': [2, 'Br', 'Br'],
|
||||
'ETB': [2, 'Birr', 'Birr'],
|
||||
'FJD': [2, '$', 'FJ$'],
|
||||
'FKP': [2, '£', 'FK£'],
|
||||
'GEL': [2, 'GEL', 'GEL'],
|
||||
'GHS': [2, '\u20B5', 'GHS¢'],
|
||||
'GHS': [2, 'GHS', 'GHS'],
|
||||
'GIP': [2, '£', 'GI£'],
|
||||
'GMD': [2, 'D', 'GMD'],
|
||||
'GMD': [2, 'GMD', 'GMD'],
|
||||
'GNF': [0, 'FG', 'FG'],
|
||||
'GTQ': [2, 'Q', 'GTQ'],
|
||||
'GYD': [2, '$', 'GY$'],
|
||||
'GYD': [0, '$', 'GY$'],
|
||||
'HNL': [2, 'L', 'HNL'],
|
||||
'HRK': [2, 'kn', 'kn'],
|
||||
'HTG': [2, 'G', 'HTG'],
|
||||
'HUF': [10, 'Ft', 'Ft'],
|
||||
'IDR': [2, 'Rp', 'Rp'],
|
||||
'IQD': [3, '\u0639\u062F', 'IQD'],
|
||||
'IRR': [2, '\ufdfc', 'IRR'],
|
||||
'JOD': [3, 'JOD', 'JOD'],
|
||||
'KES': [2, 'KSh', 'KSh'],
|
||||
'KGS': [2, 'som', 'som'],
|
||||
'KHR': [10, '\u17DB', 'KHR'],
|
||||
'KMF': [0, 'KMF', 'KMF'],
|
||||
'KPW': [2, '\u20A9', 'KPW'],
|
||||
'KWD': [3, '\u062F\u002e\u0643', 'KWD'],
|
||||
'KYD': [2, '$', 'CI$'],
|
||||
'KZT': [10, 'KZT', 'KZT'],
|
||||
'LAK': [2, '\u20AD', 'LA₭'],
|
||||
'LBP': [2, '\u0644\u002e\u0644', 'LBP'],
|
||||
'HTG': [2, 'HTG', 'HTG'],
|
||||
'HUF': [0, 'Ft', 'Ft'],
|
||||
'IDR': [0, 'Rp', 'Rp'],
|
||||
'IQD': [0, 'din', 'IQD'],
|
||||
'IRR': [0, 'Rial', 'IRR'],
|
||||
'JOD': [3, 'din', 'JOD'],
|
||||
'KES': [2, 'Ksh', 'Ksh'],
|
||||
'KGS': [2, 'KGS', 'KGS'],
|
||||
'KHR': [2, 'Riel', 'KHR'],
|
||||
'KMF': [0, 'CF', 'KMF'],
|
||||
'KPW': [0, '\u20A9KP', 'KPW'],
|
||||
'KWD': [3, 'din', 'KWD'],
|
||||
'KYD': [2, '$', 'KY$'],
|
||||
'KZT': [2, '\u20B8', 'KZT'],
|
||||
'LAK': [0, '\u20AD', '\u20AD'],
|
||||
'LBP': [0, 'L£', 'LBP'],
|
||||
'LRD': [2, '$', 'L$'],
|
||||
'LSL': [2, 'L', 'LSL'],
|
||||
'LTL': [10, 'Lt', 'Lt'],
|
||||
'LVL': [10, 'Ls', 'Ls'],
|
||||
'LYD': [3, '\u0644\u002e\u062F', 'LD'],
|
||||
'MAD': [2, '\u0645\u002E\u062F\u002E', 'MAD'],
|
||||
'LSL': [2, 'LSL', 'LSL'],
|
||||
'LTL': [2, 'Lt', 'Lt'],
|
||||
'LVL': [2, 'Ls', 'Ls'],
|
||||
'LYD': [3, 'din', 'LD'],
|
||||
'MAD': [2, 'dh', 'MAD'],
|
||||
'MDL': [2, 'MDL', 'MDL'],
|
||||
'MGA': [1, 'MGA', 'MGA'],
|
||||
'MKD': [2, 'MKD', 'MKD'],
|
||||
'MMK': [2, 'K', 'MMK'],
|
||||
'MOP': [2, 'MOP$', 'MOP$'],
|
||||
'MRO': [1, 'UM', 'UM'],
|
||||
'MUR': [2, 'Rs', 'MURs'],
|
||||
'MVR': [2, 'Rf', 'MRF'],
|
||||
'MWK': [2, 'MK', 'MK'],
|
||||
'MGA': [0, 'Ar', 'MGA'],
|
||||
'MKD': [2, 'din', 'MKD'],
|
||||
'MMK': [0, 'K', 'MMK'],
|
||||
'MOP': [2, 'MOP', 'MOP$'],
|
||||
'MRO': [0, 'MRO', 'MRO'],
|
||||
'MUR': [0, 'MURs', 'MURs'],
|
||||
'MWK': [2, 'MWK', 'MWK'],
|
||||
'MZN': [2, 'MTn', 'MTn'],
|
||||
'NAD': [2, '$', 'N$'],
|
||||
'NGN': [2, '\u20A6', 'NG₦'],
|
||||
'NGN': [2, '\u20A6', 'NG\u20A6'],
|
||||
'NIO': [2, 'C$', 'C$'],
|
||||
'NPR': [2, 'Rs', 'NPRs'],
|
||||
'NZD': [2, '$', 'NZ$'],
|
||||
'OMR': [3, '\u0639\u002E\u062F\u002E', 'OMR'],
|
||||
'PGK': [2, 'K', 'PGK'],
|
||||
'PLN': [10, 'zł', 'zł'],
|
||||
'PYG': [0, '\u20b2', 'PYG'],
|
||||
'QAR': [2, '\u0642\u002E\u0631', 'QR'],
|
||||
'RON': [2, 'L', 'RON'],
|
||||
'RSD': [2, 'РС\u0414', 'RSD'],
|
||||
'OMR': [3, 'Rial', 'OMR'],
|
||||
'PGK': [2, 'PGK', 'PGK'],
|
||||
'PLN': [2, 'z\u0142', 'z\u0142'],
|
||||
'PYG': [0, 'Gs', 'PYG'],
|
||||
'QAR': [2, 'Rial', 'QR'],
|
||||
'RON': [2, 'RON', 'RON'],
|
||||
'RSD': [0, 'din', 'RSD'],
|
||||
'RWF': [0, 'RF', 'RF'],
|
||||
'SBD': [2, '$', 'SI$'],
|
||||
'SCR': [2, 'SR', 'SCR'],
|
||||
'SCR': [2, 'SCR', 'SCR'],
|
||||
'SDG': [2, 'SDG', 'SDG'],
|
||||
'SHP': [2, '£', 'SH£'],
|
||||
'SKK': [10, 'Sk', 'Sk'],
|
||||
'SLL': [2, 'Le', 'Le'],
|
||||
'SOS': [2, 'So. Sh.', 'So. Sh.'],
|
||||
'SLL': [0, 'SLL', 'SLL'],
|
||||
'SOS': [0, 'SOS', 'SOS'],
|
||||
'SRD': [2, '$', 'SR$'],
|
||||
'STD': [2, 'Db', 'Db'],
|
||||
'SYP': [18, 'SYP', 'SYP'],
|
||||
'SZL': [2, 'L', 'SZL'],
|
||||
'TJS': [2, 'TJS', 'TJS'],
|
||||
'TMM': [2, 'm', 'TMM'],
|
||||
'TND': [3, '\u062F\u002e\u062A ', 'DT'],
|
||||
'STD': [0, 'Db', 'Db'],
|
||||
'SYP': [16, '£', 'SY£'],
|
||||
'SZL': [2, 'SZL', 'SZL'],
|
||||
'TJS': [2, 'Som', 'TJS'],
|
||||
'TND': [3, 'din', 'DT'],
|
||||
'TOP': [2, 'T$', 'T$'],
|
||||
'TTD': [2, '$', 'TT$'],
|
||||
'TZS': [10, 'TZS', 'TZS'],
|
||||
'UAH': [10, '\u20B4', 'грн'],
|
||||
'UGX': [2, 'USh', 'USh'],
|
||||
'UZS': [2, 'UZS', 'UZS'],
|
||||
'VEF': [2, 'Bs.F', 'Bs.F'],
|
||||
'VUV': [0, 'Vt', 'Vt'],
|
||||
'WST': [2, 'WS$', 'WS$'],
|
||||
'TZS': [0, 'TSh', 'TSh'],
|
||||
'UAH': [2, '\u20B4', 'UAH'],
|
||||
'UGX': [0, 'UGX', 'UGX'],
|
||||
'UYU': [1, '$', '$U'],
|
||||
'UZS': [0, 'so\u02bcm', 'UZS'],
|
||||
'VEF': [2, 'Bs', 'Bs'],
|
||||
'VUV': [0, 'VUV', 'VUV'],
|
||||
'WST': [2, 'WST', 'WST'],
|
||||
'XAF': [0, 'FCFA', 'FCFA'],
|
||||
'XCD': [2, '$', 'EC$'],
|
||||
'XOF': [0, 'CFA', 'CFA'],
|
||||
'XPF': [0, 'F', 'XPF'],
|
||||
'ZMK': [2, 'ZK', 'ZK'],
|
||||
'ZWL': [2, '$', 'ZW$']
|
||||
'XPF': [0, 'FCFP', 'FCFP'],
|
||||
'ZMK': [0, 'ZMK', 'ZMK']
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+497
-296
File diff suppressed because it is too large
Load Diff
+358
-181
File diff suppressed because it is too large
Load Diff
+213
-146
@@ -1,4 +1,4 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -7,35 +7,24 @@
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations under
|
||||
// the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Plural rules.
|
||||
*
|
||||
* This file is autogenerated by script:
|
||||
* http://go/generate_pluralrules.py
|
||||
* using the --for_closure flag.
|
||||
* http://go/generate_pluralrules.py
|
||||
*
|
||||
* To reduce the file size (which may cause issues in some JS
|
||||
* developing environments), this file will only contain locales
|
||||
* that are usually supported by google products. This is defined as
|
||||
* closure_tier1_locales and will change (most likely addition)
|
||||
* over time. Rest of the data can be found in another file named
|
||||
* "pluralrulesext.js", which will be generated at the
|
||||
* same time together with this file.
|
||||
*
|
||||
* Before checkin, this file could have been manually edited. This is
|
||||
* to incorporate changes before we could fix CLDR. All manual
|
||||
* modification must be documented in this section, and should be
|
||||
* removed after those changes land to CLDR.
|
||||
* 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
|
||||
* documented in this section, and should be removed after those changes land to
|
||||
* CLDR.
|
||||
*/
|
||||
|
||||
goog.provide('goog.i18n.pluralRules');
|
||||
|
||||
|
||||
/**
|
||||
* Plural pattern keyword
|
||||
* @enum {string}
|
||||
@@ -53,7 +42,7 @@ goog.i18n.pluralRules.Keyword = {
|
||||
/**
|
||||
* Default plural select rule.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Default plural value.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Default value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.defaultSelect_ = function(n) {
|
||||
@@ -64,25 +53,25 @@ goog.i18n.pluralRules.defaultSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for ar locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.arSelect_ = function(n) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if ((n % 100) >= 3 && (n % 100) <= 10 && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && n % 100 >= 3 && n % 100 <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if ((n % 100) >= 11 && (n % 100) <= 99 && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
if (n == (n | 0) && n % 100 >= 11 && n % 100 <= 99) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -91,13 +80,13 @@ goog.i18n.pluralRules.arSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for en locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.enSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -106,13 +95,13 @@ goog.i18n.pluralRules.enSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for fil locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.filSelect_ = function(n) {
|
||||
if (n == 0 || n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -121,13 +110,13 @@ goog.i18n.pluralRules.filSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for fr locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.frSelect_ = function(n) {
|
||||
if (n >= 0 && n < 2) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n >= 0 && n <= 2 && n != 2) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -136,16 +125,34 @@ goog.i18n.pluralRules.frSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for lv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.lvSelect_ = function(n) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if ((n % 10) == 1 && (n % 100) != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n % 10 == 1 && n % 100 != 11) {
|
||||
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.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.iuSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -154,16 +161,22 @@ goog.i18n.pluralRules.lvSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for ga locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gaSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n == (n | 0) && n >= 3 && n <= 6) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n == (n | 0) && n >= 7 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -172,17 +185,16 @@ goog.i18n.pluralRules.gaSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for ro locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.roSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 0 || n != 1 && (n % 100) >= 1 &&
|
||||
(n % 100) <= 19 && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == 0 || n != 1 && n == (n | 0) && n % 100 >= 1 && n % 100 <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -191,40 +203,37 @@ goog.i18n.pluralRules.roSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for lt locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.ltSelect_ = function(n) {
|
||||
if ((n % 10) == 1 && ((n % 100) < 11 || (n % 100) > 19)) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n % 10 == 1 && (n % 100 < 11 || n % 100 > 19)) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if ((n % 10) >= 2 && (n % 10) <= 9 &&
|
||||
((n % 100) < 11 || (n % 100) > 19) && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Plural select rules for hr locale
|
||||
* Plural select rules for be locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.hrSelect_ = function(n) {
|
||||
if ((n % 10) == 1 && (n % 100) != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
goog.i18n.pluralRules.beSelect_ = function(n) {
|
||||
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) && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && 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) && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
if (n % 10 == 0 || n == (n | 0) && n % 10 >= 5 && n % 10 <= 9 || n == (n | 0) && n % 100 >= 11 && n % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -233,16 +242,16 @@ goog.i18n.pluralRules.hrSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for cs locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.csSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2 || n == 3 || n == 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && n >= 2 && n <= 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -251,22 +260,19 @@ goog.i18n.pluralRules.csSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for pl locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.plSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if ((n % 10) >= 2 && (n % 10) <= 4 &&
|
||||
((n % 100) < 12 || (n % 100) > 14) && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if ((n % 10) == 0 || n != 1 && (n % 10) == 1 ||
|
||||
((n % 10) >= 5 && (n % 10) <= 9 || (n % 100) >= 12 && (n % 100) <= 14) &&
|
||||
n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
if (n != 1 && (n % 10 == 0 || n % 10 == 1) || n == (n | 0) && n % 10 >= 5 && n % 10 <= 9 || n == (n | 0) && n % 100 >= 12 && n % 100 <= 14) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -275,19 +281,19 @@ goog.i18n.pluralRules.plSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for sl locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.slSelect_ = function(n) {
|
||||
if ((n % 100) == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n % 100 == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if ((n % 100) == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
if (n % 100 == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if ((n % 100) == 3 || (n % 100) == 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n % 100 == 3 || n % 100 == 4) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -296,19 +302,19 @@ goog.i18n.pluralRules.slSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for mt locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.mtSelect_ = function(n) {
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 0 || ((n % 100) >= 2 && (n % 100) <= 4 && n == Math.floor(n))) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == 0 || n == (n | 0) && n % 100 >= 2 && n % 100 <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if ((n % 100) >= 11 && (n % 100) <= 19 && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
if (n == (n | 0) && n % 100 >= 11 && n % 100 <= 19) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -317,13 +323,13 @@ goog.i18n.pluralRules.mtSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for mk locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.mkSelect_ = function(n) {
|
||||
if ((n % 10) == 1 && n != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n % 10 == 1 && n != 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -332,25 +338,25 @@ goog.i18n.pluralRules.mkSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for cy locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.cySelect_ = function(n) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n == 3) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n == 6) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -359,16 +365,16 @@ goog.i18n.pluralRules.cySelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for lag locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.lagSelect_ = function(n) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n > 0 && n < 2) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
if (n >= 0 && n <= 2 && n != 0 && n != 2) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -377,16 +383,16 @@ goog.i18n.pluralRules.lagSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for shi locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.shiSelect_ = function(n) {
|
||||
if (n >= 0 && n <= 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n >= 2 && n <= 10 && n == Math.floor(n)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
if (n == (n | 0) && n >= 2 && n <= 10) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -395,25 +401,91 @@ goog.i18n.pluralRules.shiSelect_ = function(n) {
|
||||
/**
|
||||
* Plural select rules for br locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale specific plural value.
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.brSelect_ = function(n) {
|
||||
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) {
|
||||
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))) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
if (n % 1000000 == 0 && n != 0) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Plural select rules for ksh locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.kshSelect_ = function(n) {
|
||||
if (n == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
return goog.i18n.pluralRules.Keyword.ZERO;
|
||||
}
|
||||
if (n == 1) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
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 tzm locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.tzmSelect_ = function(n) {
|
||||
if (n == 0 || n == 1 || n == (n | 0) && n >= 11 && n <= 99) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 3) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Plural select rules for gv locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gvSelect_ = function(n) {
|
||||
if (n % 10 == 1 || n % 10 == 2 || n % 20 == 0) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 6) {
|
||||
return goog.i18n.pluralRules.Keyword.MANY;
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Plural select rules for gd locale
|
||||
*
|
||||
* @param {number} n The count of items.
|
||||
* @return {goog.i18n.pluralRules.Keyword} Locale-specific plural value.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.pluralRules.gdSelect_ = function(n) {
|
||||
if (n == 1 || n == 11) {
|
||||
return goog.i18n.pluralRules.Keyword.ONE;
|
||||
}
|
||||
if (n == 2 || n == 12) {
|
||||
return goog.i18n.pluralRules.Keyword.TWO;
|
||||
}
|
||||
if (n == (n | 0) && (n >= 3 && n <= 10 || n >= 13 && n <= 19)) {
|
||||
return goog.i18n.pluralRules.Keyword.FEW;
|
||||
}
|
||||
return goog.i18n.pluralRules.Keyword.OTHER;
|
||||
};
|
||||
@@ -423,7 +495,6 @@ goog.i18n.pluralRules.brSelect_ = function(n) {
|
||||
* Selected plural rules by locale.
|
||||
*/
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
|
||||
if (goog.LOCALE == 'am') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.filSelect_;
|
||||
}
|
||||
@@ -557,7 +628,7 @@ if (goog.LOCALE == 'hi') {
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'hr') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.hrSelect_;
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.beSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'hu') {
|
||||
@@ -581,7 +652,7 @@ if (goog.LOCALE == 'it') {
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'iw') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.defaultSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ja') {
|
||||
@@ -612,10 +683,6 @@ if (goog.LOCALE == 'ml') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'mo') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.roSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'mr') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.enSelect_;
|
||||
}
|
||||
@@ -661,7 +728,7 @@ if (goog.LOCALE == 'ro') {
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ru') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.hrSelect_;
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.beSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'sk') {
|
||||
@@ -677,7 +744,7 @@ if (goog.LOCALE == 'sq') {
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'sr') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.hrSelect_;
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.beSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'sv') {
|
||||
@@ -709,7 +776,7 @@ if (goog.LOCALE == 'tr') {
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'uk') {
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.hrSelect_;
|
||||
goog.i18n.pluralRules.select = goog.i18n.pluralRules.beSelect_;
|
||||
}
|
||||
|
||||
if (goog.LOCALE == 'ur') {
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
PARENT_DIR="$(dirname "$0")"
|
||||
jasmine-node "$PARENT_DIR"/spec/
|
||||
@@ -0,0 +1,266 @@
|
||||
var closureI18nExtractor = require('../src/closureI18nExtractor.js');
|
||||
var converter = require('../src/converter.js');
|
||||
findLocaleId = closureI18nExtractor.findLocaleId;
|
||||
extractNumberSymbols = closureI18nExtractor.extractNumberSymbols;
|
||||
extractCurrencySymbols = closureI18nExtractor.extractCurrencySymbols;
|
||||
extractDateTimeSymbols = closureI18nExtractor.extractDateTimeSymbols;
|
||||
|
||||
|
||||
function newTestLocaleInfo() {
|
||||
return { fr_CA: {
|
||||
DATETIME_FORMATS: {
|
||||
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
|
||||
'octobre', 'novembre', 'décembre'],
|
||||
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
|
||||
'nov.', 'déc.'],
|
||||
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
|
||||
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
|
||||
AMPMS: ['AM', 'PM'],
|
||||
medium: 'yyyy-MM-dd HH:mm:ss',
|
||||
short: 'yy-MM-dd HH:mm',
|
||||
fullDate: 'EEEE d MMMM y',
|
||||
longDate: 'd MMMM y',
|
||||
mediumDate: 'yyyy-MM-dd',
|
||||
shortDate: 'yy-MM-dd',
|
||||
mediumTime: 'HH:mm:ss',
|
||||
shortTime: 'HH:mm'
|
||||
},
|
||||
NUMBER_FORMATS: {
|
||||
"DECIMAL_SEP": ".",
|
||||
"GROUP_SEP": ",",
|
||||
"PATTERNS": [{
|
||||
"minInt": 1,
|
||||
"minFrac": 0,
|
||||
"macFrac": 0,
|
||||
"posPre": "",
|
||||
"posSuf": "",
|
||||
"negPre": "-",
|
||||
"negSuf": "",
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 3
|
||||
}, {
|
||||
"minInt": 1,
|
||||
"minFrac": 2,
|
||||
"macFrac": 0,
|
||||
"posPre": "¤",
|
||||
"posSuf": "",
|
||||
"negPre": "¤-",
|
||||
"negSuf": "",
|
||||
"gSize": 3,
|
||||
"lgSize": 3,
|
||||
"maxFrac": 2
|
||||
}],
|
||||
"CURRENCY_SYM": "£"
|
||||
}}};
|
||||
}
|
||||
|
||||
|
||||
describe("findLocaleId", function () {
|
||||
it("should find the id from numbers", function() {
|
||||
expect(findLocaleId("NumberFormatSymbols_en_GB", "num")).toEqual("en_GB");
|
||||
});
|
||||
|
||||
|
||||
it("should find the id from datetime", function() {
|
||||
expect(findLocaleId("DateTimeSymbols_en_ISO", "datetime")).toEqual("en_ISO");
|
||||
});
|
||||
|
||||
|
||||
it("should throw an error otherwise", function() {
|
||||
expect(function() {
|
||||
findLocaleId("str", "otherwise")
|
||||
}).toThrow("unknown type in findLocaleId: otherwise");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractNumberSymbols", function () {
|
||||
it("should extract number data", function() {
|
||||
var CONTENT = [
|
||||
"goog.provide('goog.i18n.NumberFormatSymbols_en_GB');",
|
||||
"goog.i18n.NumberFormatSymbols_en_GB = {",
|
||||
"DECIMAL_SEP: '.',",
|
||||
"GROUP_SEP: ',',",
|
||||
"PERCENT: '%',",
|
||||
"ZERO_DIGIT: '0',",
|
||||
"PLUS_SIGN: '+',",
|
||||
"MINUS_SIGN: '-',",
|
||||
"EXP_SYMBOL: 'E',",
|
||||
"PERMILL: '\u2030',",
|
||||
"INFINITY: '\u221E',",
|
||||
"NAN: 'NaN',",
|
||||
"DECIMAL_PATTERN: '#,##0.###',",
|
||||
"SCIENTIFIC_PATTERN: '#E0',",
|
||||
"PERCENT_PATTERN: '#,##0%',",
|
||||
"CURRENCY_PATTERN: '\u00A4#,##0.00',",
|
||||
"DEF_CURRENCY_CODE: 'GBP' };"
|
||||
].join('\n');
|
||||
|
||||
var currencySymbols = {'GBP':[2, '£', 'GB£']};
|
||||
|
||||
var expectedNumberFormats = converter.convertNumberData(
|
||||
{
|
||||
DECIMAL_SEP:'.',
|
||||
GROUP_SEP:',',
|
||||
DECIMAL_PATTERN:'#,##0.###',
|
||||
CURRENCY_PATTERN:'\u00A4#,##0.00',
|
||||
DEF_CURRENCY_CODE: 'GBP'
|
||||
}, currencySymbols
|
||||
);
|
||||
|
||||
var localeInfo = {};
|
||||
extractNumberSymbols(CONTENT, localeInfo, currencySymbols);
|
||||
|
||||
expect(localeInfo).toEqual({
|
||||
'en_GB': { NUMBER_FORMATS: expectedNumberFormats }
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe("extractCurrencySymbols", function () {
|
||||
it("should extract currency data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.currency.CurrencyInfo = {",
|
||||
" 'GBP':[2, '£', 'GB£'],",
|
||||
"};",
|
||||
"goog.i18n.currency.CurrencyInfoTier2 = {",
|
||||
" 'AOA':[2, 'Kz', 'Kz'],",
|
||||
"};"
|
||||
].join('\n');
|
||||
|
||||
var localeInfo = {};
|
||||
expect(extractCurrencySymbols(CONTENT)).toEqual({
|
||||
'GBP':[2, '£', 'GB£'],
|
||||
'AOA':[2, 'Kz', 'Kz']
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("extractDateTimeSymbols", function () {
|
||||
it("should extract date time data", function() {
|
||||
var CONTENT = [
|
||||
"goog.i18n.DateTimeSymbols_fr_CA = {",
|
||||
" ERAS: ['av. J.-C.', 'ap. J.-C.'],",
|
||||
" ERANAMES: ['avant Jésus-Christ', 'après Jésus-Christ'],",
|
||||
" NARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O', 'N', 'D'],",
|
||||
" STANDALONENARROWMONTHS: ['J', 'F', 'M', 'A', 'M', 'J', 'J', 'A', 'S', 'O',",
|
||||
" 'N', 'D'],",
|
||||
" MONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',",
|
||||
" 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" STANDALONEMONTHS: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',",
|
||||
" 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],",
|
||||
" SHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.',",
|
||||
" 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" STANDALONESHORTMONTHS: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',",
|
||||
" 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],",
|
||||
" WEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi',",
|
||||
" 'samedi'],",
|
||||
" STANDALONEWEEKDAYS: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi',",
|
||||
" 'vendredi', 'samedi'],",
|
||||
" SHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],",
|
||||
" STANDALONESHORTWEEKDAYS: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.',",
|
||||
" 'sam.'],",
|
||||
" NARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" STANDALONENARROWWEEKDAYS: ['D', 'L', 'M', 'M', 'J', 'V', 'S'],",
|
||||
" SHORTQUARTERS: ['T1', 'T2', 'T3', 'T4'],",
|
||||
" QUARTERS: ['1er trimestre', '2e trimestre', '3e trimestre', '4e trimestre'],",
|
||||
" AMPMS: ['AM', 'PM'],",
|
||||
" DATEFORMATS: ['EEEE d MMMM y', 'd MMMM y', 'yyyy-MM-dd', 'yy-MM-dd'],",
|
||||
" TIMEFORMATS: ['HH \\'h\\' mm \\'min\\' ss \\'s\\' zzzz', 'HH:mm:ss z',",
|
||||
" 'HH:mm:ss', 'HH:mm'],",
|
||||
" FIRSTDAYOFWEEK: 6,",
|
||||
" WEEKENDRANGE: [5, 6],",
|
||||
" FIRSTWEEKCUTOFFDAY: 2",
|
||||
"};"
|
||||
].join('\n');
|
||||
var localeInfo = {};
|
||||
var expectedLocaleInfo = {
|
||||
fr_CA: {
|
||||
DATETIME_FORMATS: {
|
||||
MONTH: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre',
|
||||
'octobre', 'novembre', 'décembre'],
|
||||
SHORTMONTH: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.',
|
||||
'nov.', 'déc.'],
|
||||
DAY: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
|
||||
SHORTDAY: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
|
||||
AMPMS: ['AM', 'PM'],
|
||||
medium: 'yyyy-MM-dd HH:mm:ss',
|
||||
short: 'yy-MM-dd HH:mm',
|
||||
fullDate: 'EEEE d MMMM y',
|
||||
longDate: 'd MMMM y',
|
||||
mediumDate: 'yyyy-MM-dd',
|
||||
shortDate: 'yy-MM-dd',
|
||||
mediumTime: 'HH:mm:ss',
|
||||
shortTime: 'HH:mm'
|
||||
}
|
||||
}
|
||||
};
|
||||
extractDateTimeSymbols(CONTENT, localeInfo);
|
||||
expect(localeInfo).toEqual(expectedLocaleInfo);
|
||||
})
|
||||
});
|
||||
|
||||
describe("pluralExtractor", function() {
|
||||
it("should output PLURAL_CAT in the output string code", function() {
|
||||
var localeIds = ["fr_CA"];
|
||||
var content = (
|
||||
"goog.provide('goog.i18n.pluralRules');\n" +
|
||||
"\n" +
|
||||
"goog.i18n.pluralRules.Keyword = {\n" +
|
||||
" ZERO: 'zero',\n" +
|
||||
" ONE: 'one',\n" +
|
||||
" TWO: 'two',\n" +
|
||||
" FEW: 'few',\n" +
|
||||
" MANY: 'many',\n" +
|
||||
" OTHER: 'other'\n" +
|
||||
"};\n" +
|
||||
"\n" +
|
||||
"goog.i18n.pluralRules.frSelect_ = function(n) {\n" +
|
||||
" if (n >= 0 && n < 2) {\n" +
|
||||
" return goog.i18n.pluralRules.Keyword.ONE;\n" +
|
||||
" }\n" +
|
||||
" return goog.i18n.pluralRules.Keyword.OTHER;\n" +
|
||||
"};\n" +
|
||||
"\n" +
|
||||
"if (goog.LOCALE == 'fr') {\n" +
|
||||
" goog.i18n.pluralRules.select = goog.i18n.pluralRules.frSelect_;\n" +
|
||||
"}"
|
||||
);
|
||||
var localeInfo = newTestLocaleInfo();
|
||||
closureI18nExtractor.pluralExtractor(content, localeInfo);
|
||||
var pluralCat = localeInfo["fr_CA"].pluralCat;
|
||||
expect(pluralCat).toBeDefined();
|
||||
// pluralCat is the source text for the pluralCat and contains @@
|
||||
// placeholders that need to be stripped before evaluation.
|
||||
// Ref: closureI18nExtractor.pluralExtractor.
|
||||
pluralCat = pluralCat.replace(/^@@|@@$/g, '');
|
||||
// pluralCat requires these constants to exist.
|
||||
var PLURAL_CATEGORY = {
|
||||
ZERO: "zero", ONE: "one", TWO: "two",
|
||||
FEW: "few", MANY: "many", OTHER: "other"
|
||||
};
|
||||
// Obtain the function by evaluating the source text.
|
||||
pluralCat = eval("(" + pluralCat + ")");
|
||||
// Confirm some expectations for pluralCat in fr_CA.
|
||||
expect(pluralCat(0)).toEqual("one");
|
||||
expect(pluralCat(3)).toEqual("other");
|
||||
})
|
||||
});
|
||||
|
||||
describe("serializeContent", function() {
|
||||
it("should not make any modifications to the content of the locale", function() {
|
||||
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo());
|
||||
expect(eval("(" + serializedContent + ")")).toEqual(newTestLocaleInfo());
|
||||
});
|
||||
it("should only have ascii characters", function() {
|
||||
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo());
|
||||
expect((/[^\u0001-\u007f]/).test(serializedContent)).toBe(false);
|
||||
});
|
||||
it("should not transform arrays into objects", function() {
|
||||
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo().fr_CA);
|
||||
var deserializedLocale = eval("(" + serializedContent + ")");
|
||||
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,6 +24,8 @@ describe('parsePattern', function() {
|
||||
parseAndExpect('#,##,##0.###', '', '-', '', '', 1, 0, 3, 2, 3);
|
||||
parseAndExpect("#,##0.###;\'\u202A\'-#,##0.###\'\u202C\'",
|
||||
'', '\u202A-', '', '\u202C', 1, 0, 3, 3, 3);
|
||||
parseAndExpect('#0.###;#0.###-', '', '', '', '-', 1, 0, 3, 0, 0);
|
||||
|
||||
});
|
||||
|
||||
it('should parse CURRENCY patterns', function() {
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
'use strict';
|
||||
|
||||
var converter = require('./converter.js');
|
||||
|
||||
exports.extractNumberSymbols = extractNumberSymbols;
|
||||
exports.extractCurrencySymbols = extractCurrencySymbols;
|
||||
exports.extractDateTimeSymbols = extractDateTimeSymbols;
|
||||
exports.pluralExtractor = pluralExtractor;
|
||||
exports.outputLocale = outputLocale;
|
||||
exports.correctedLocaleId = correctedLocaleId;
|
||||
exports.findLocaleId = findLocaleId;
|
||||
exports.serializeContent = serializeContent;
|
||||
|
||||
var goog = { provide: function() {},
|
||||
require: function() {},
|
||||
i18n: {currency: {}, pluralRules: {}} };
|
||||
|
||||
function findLocaleId(str, type) {
|
||||
if (type === 'num') {
|
||||
return (str.match(/^NumberFormatSymbols_(.+)$/) || [])[1];
|
||||
}
|
||||
|
||||
if (type != 'datetime') { throw new Error('unknown type in findLocaleId: ' + type); }
|
||||
|
||||
return (str.match(/^DateTimeSymbols_(.+)$/) || [])[1];
|
||||
}
|
||||
|
||||
|
||||
function getInfoForLocale(localeInfo, localeID) {
|
||||
if (!localeInfo[localeID]) {
|
||||
localeInfo[localeID] = {};
|
||||
//localeIds.push(localeID);
|
||||
}
|
||||
return localeInfo[localeID];
|
||||
}
|
||||
|
||||
function extractNumberSymbols(content, localeInfo, currencySymbols) {
|
||||
//eval script in the current context so that we get access to all the symbols
|
||||
eval(content.toString());
|
||||
for (var propName in goog.i18n) {
|
||||
var localeID = findLocaleId(propName, 'num');
|
||||
if (localeID) {
|
||||
var info = getInfoForLocale(localeInfo, localeID);
|
||||
info.NUMBER_FORMATS =
|
||||
converter.convertNumberData(goog.i18n[propName], currencySymbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractCurrencySymbols(content) {
|
||||
//eval script in the current context so that we get access to all the symbols
|
||||
eval(content.toString());
|
||||
var currencySymbols = goog.i18n.currency.CurrencyInfo;
|
||||
currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
|
||||
|
||||
return currencySymbols;
|
||||
}
|
||||
|
||||
function extractDateTimeSymbols(content, localeInfo) {
|
||||
//eval script in the current context so that we get access to all the symbols
|
||||
eval(content.toString());
|
||||
for (var propName in goog.i18n) {
|
||||
var localeID = findLocaleId(propName, 'datetime');
|
||||
if (localeID) {
|
||||
var info = getInfoForLocale(localeInfo, localeID);
|
||||
localeInfo[localeID].DATETIME_FORMATS =
|
||||
converter.convertDatetimeData(goog.i18n[propName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pluralExtractor(content, localeInfo) {
|
||||
var contentText = content.toString();
|
||||
var localeIds = Object.keys(localeInfo);
|
||||
for (var i = 0; i < localeIds.length; i++) {
|
||||
//We don't need to care about country ID because the plural rules in more specific id are
|
||||
//always the same as those in its language ID.
|
||||
// e.g. plural rules for en_SG is the same as those for en.
|
||||
goog.LOCALE = localeIds[i].match(/[^_]+/)[0];
|
||||
try {
|
||||
eval(contentText);
|
||||
} catch(e) {
|
||||
console.log("Error in eval(contentText): " + e.stack);
|
||||
}
|
||||
if (!goog.i18n.pluralRules.select) {
|
||||
console.log('No select for lang [' + goog.LOCALE + ']');
|
||||
continue;
|
||||
}
|
||||
var temp = goog.i18n.pluralRules.select.toString().
|
||||
replace(/goog.i18n.pluralRules.Keyword/g, 'PLURAL_CATEGORY').replace(/\n/g, '');
|
||||
|
||||
///@@ is a crazy place holder to be replaced before writing to file
|
||||
localeInfo[localeIds[i]].pluralCat = "@@" + temp + "@@";
|
||||
}
|
||||
}
|
||||
|
||||
function correctedLocaleId(localeID) {
|
||||
// e.g. from zh_CN to zh-CN, from en_US to en-US
|
||||
return localeID.replace(/_/g, '-').toLowerCase();
|
||||
}
|
||||
|
||||
function canonicalizeForJsonStringify(unused_key, object) {
|
||||
// This function is intended to be called as the 2nd argument to
|
||||
// JSON.stringify. The goal here is to ensure that the generated JSON has
|
||||
// objects with their keys in ascending order. Without this, it's much
|
||||
// harder to diff the generated files in src/ngLocale as the order isn't
|
||||
// exactly consistent. We've gotten lucky in the past.
|
||||
//
|
||||
// Iteration order, for string keys, ends up being the same as insertion
|
||||
// order. Refer :-
|
||||
// 1. http://ejohn.org/blog/javascript-in-chrome/
|
||||
// (search for "for loop order").
|
||||
// Currently all major browsers loop over the properties of an object
|
||||
// in the order in which they were defined.
|
||||
// - John Resig
|
||||
// 2. https://code.google.com/p/v8/issues/detail?id=164
|
||||
// ECMA-262 does not specify enumeration order. The de facto standard
|
||||
// is to match insertion order, which V8 also does ...
|
||||
if (typeof object != "object" || Object.prototype.toString.apply(object) === '[object Array]') {
|
||||
return object;
|
||||
}
|
||||
var result = {};
|
||||
Object.keys(object).sort().forEach(function(key) {
|
||||
result[key] = object[key];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function serializeContent(localeObj) {
|
||||
return JSON.stringify(localeObj, canonicalizeForJsonStringify, ' ')
|
||||
.replace(new RegExp('[\\u007f-\\uffff]', 'g'), function(c) { return '\\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4); })
|
||||
.replace(/"@@|@@"/g, '');
|
||||
}
|
||||
|
||||
function outputLocale(localeInfo, localeID) {
|
||||
var fallBackID = localeID.match(/[A-Za-z]+/)[0],
|
||||
localeObj = localeInfo[localeID],
|
||||
fallBackObj = localeInfo[fallBackID];
|
||||
|
||||
// fallBack to language formats when country format is missing
|
||||
// e.g. if NUMBER_FORMATS of en_xyz is not present, use the NUMBER_FORMATS of en instead
|
||||
if (!localeObj.NUMBER_FORMATS) {
|
||||
localeObj.NUMBER_FORMATS = fallBackObj.NUMBER_FORMATS;
|
||||
}
|
||||
|
||||
// datetimesymbolsext.js provides more top level locales than the other
|
||||
// files. We process datetimesymbolsext.js because we want the country
|
||||
// specific formats that are missing from datetimesymbols.js. However, we
|
||||
// don't want to write locale files that only have dateformat (i.e. missing
|
||||
// number formats.) So we skip them.
|
||||
if (!localeObj.NUMBER_FORMATS) {
|
||||
console.log("Skipping locale %j: Don't have any number formats", localeID);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!localeObj.DATETIME_FORMATS) {
|
||||
localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS;
|
||||
}
|
||||
localeObj.id = correctedLocaleId(localeID);
|
||||
|
||||
var prefix =
|
||||
'angular.module("ngLocale", [], ["$provide", function($provide) {\n' +
|
||||
'var PLURAL_CATEGORY = {' +
|
||||
'ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"' +
|
||||
'};\n' +
|
||||
'$provide.value("$locale", ';
|
||||
|
||||
var suffix = ');\n}]);';
|
||||
|
||||
localeObj = {
|
||||
DATETIME_FORMATS: localeObj.DATETIME_FORMATS,
|
||||
NUMBER_FORMATS: localeObj.NUMBER_FORMATS,
|
||||
pluralCat: localeObj.pluralCat,
|
||||
id: localeObj.id
|
||||
};
|
||||
|
||||
var content = serializeContent(localeInfo[localeID]);
|
||||
|
||||
return prefix + content + suffix;
|
||||
}
|
||||
+57
-102
@@ -1,130 +1,85 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var Q = require('qq'),
|
||||
var Q = require('q'),
|
||||
qfs = require('q-fs'),
|
||||
converter = require('./converter.js'),
|
||||
util = require('./util.js'),
|
||||
closureI18nExtractor = require('./closureI18nExtractor.js'),
|
||||
localeInfo = {},
|
||||
localeIds = [],
|
||||
currencySymbols,
|
||||
goog = { provide: function() {},
|
||||
require: function() {},
|
||||
i18n: {currency: {}, pluralRules: {}} };
|
||||
|
||||
createFolder('../../src/ngLocale/').then(function() {
|
||||
var promiseA = Q.defer(),
|
||||
promiseB = Q.defer();
|
||||
|
||||
qfs.read(__dirname + '/../closure/currencySymbols.js', 'b').then(function(content) {
|
||||
eval(content.toString());
|
||||
currencySymbols = goog.i18n.currency.CurrencyInfo;
|
||||
currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
|
||||
var NG_LOCALE_DIR = '../src/ngLocale/';
|
||||
|
||||
qfs.read(__dirname + '/../closure/numberSymbols.js', 'b').then(function(content) {
|
||||
//eval script in the current context so that we get access to all the symbols
|
||||
eval(content.toString());
|
||||
for (var propName in goog.i18n) {
|
||||
var localeID = util.findLocaleId(propName, 'num');
|
||||
if (localeID) {
|
||||
if (!localeInfo[localeID]) {
|
||||
localeInfo[localeID] = {};
|
||||
localeIds.push(localeID);
|
||||
}
|
||||
var convertedData = converter.convertNumberData(goog.i18n[propName], currencySymbols);
|
||||
localeInfo[localeID].NUMBER_FORMATS = convertedData;
|
||||
}
|
||||
}
|
||||
|
||||
promiseA.resolve();
|
||||
function readSymbols() {
|
||||
console.log("Processing currency and number symbols ...");
|
||||
var numericStagePromise = qfs.read(__dirname + '/../closure/currencySymbols.js', 'b')
|
||||
.then(function(content) {
|
||||
var currencySymbols = closureI18nExtractor.extractCurrencySymbols(content);
|
||||
return qfs.read(__dirname + '/../closure/numberSymbols.js', 'b').then(function(content) {
|
||||
closureI18nExtractor.extractNumberSymbols(content, localeInfo, currencySymbols);
|
||||
});
|
||||
});
|
||||
|
||||
console.log("Processing datetime symbols ...");
|
||||
var datetimeStagePromise = qfs.read(__dirname + '/../closure/datetimeSymbols.js', 'b')
|
||||
.then(function(content) {
|
||||
closureI18nExtractor.extractDateTimeSymbols(content, localeInfo);
|
||||
return qfs.read(__dirname + '/../closure/datetimeSymbolsExt.js', 'b').then(function(content) {
|
||||
closureI18nExtractor.extractDateTimeSymbols(content, localeInfo);
|
||||
});
|
||||
});
|
||||
|
||||
return Q.all([numericStagePromise, datetimeStagePromise]);
|
||||
}
|
||||
|
||||
function extractPlurals() {
|
||||
console.log('Extracting Plurals ...');
|
||||
return qfs.read(__dirname + '/../closure/pluralRules.js').then(function(content) {
|
||||
closureI18nExtractor.pluralExtractor(content, localeInfo);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
qfs.read(__dirname + '/../closure/datetimeSymbols.js', 'b').then(function(content) {
|
||||
eval(content.toString());
|
||||
for (var propName in goog.i18n) {
|
||||
var localeID = util.findLocaleId(propName, 'datetime');
|
||||
if (localeID) {
|
||||
if (!localeInfo[localeID]) {
|
||||
localeInfo[localeID] = {};
|
||||
localeIds.push(localeID);
|
||||
}
|
||||
var convertedData = converter.convertDatetimeData(goog.i18n[propName]);
|
||||
localeInfo[localeID].DATETIME_FORMATS = convertedData;
|
||||
}
|
||||
}
|
||||
|
||||
promiseB.resolve();
|
||||
});
|
||||
|
||||
return Q.join(promiseA.promise, promiseB.promise, noop);
|
||||
}).then(function() {
|
||||
var promise = Q.defer();
|
||||
|
||||
qfs.read(__dirname + '/../closure/pluralRules.js').then(function(content) {
|
||||
for(var i = 0; i < localeIds.length; i++) {
|
||||
//We don't need to care about country ID because the plural rules in more specific id are
|
||||
//always the same as those in its language ID.
|
||||
// e.g. plural rules for en_SG is the same as those for en.
|
||||
goog.LOCALE = localeIds[i].match(/[^_]+/)[0];
|
||||
eval(content);
|
||||
var temp = goog.i18n.pluralRules.select.toString().
|
||||
replace(/goog.i18n.pluralRules.Keyword/g, 'PLURAL_CATEGORY').replace(/\n/g, '');
|
||||
|
||||
///@@ is a crazy place holder to be replaced before writing to file
|
||||
localeInfo[localeIds[i]].pluralCat = "@@" + temp + "@@";
|
||||
}
|
||||
promise.resolve();
|
||||
});
|
||||
|
||||
return promise.promise;
|
||||
}).then(function() {
|
||||
function writeLocaleFiles() {
|
||||
console.log('Final stage: Writing angular locale files to directory: %j', NG_LOCALE_DIR);
|
||||
var writePromises = [];
|
||||
var localeIds = Object.keys(localeInfo);
|
||||
var num_files = 0;
|
||||
localeIds.forEach(function(localeID) {
|
||||
var fallBackID = localeID.match(/[A-Za-z]+/)[0],
|
||||
localeObj = localeInfo[localeID],
|
||||
fallBackObj = localeInfo[fallBackID];
|
||||
|
||||
// fallBack to language formats when country format is missing
|
||||
// e.g. if NUMBER_FORMATS of en_xyz is not present, use the NUMBER_FORMATS of en instead
|
||||
if (!localeObj.NUMBER_FORMATS) {
|
||||
localeObj.NUMBER_FORMATS = fallBackObj.NUMBER_FORMATS;
|
||||
}
|
||||
|
||||
if (!localeObj.DATETIME_FORMATS) {
|
||||
localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS;
|
||||
}
|
||||
|
||||
// e.g. from zh_CN to zh-CN, from en_US to en-US
|
||||
var correctedLocaleId = localeID.replace(/_/g, '-').toLowerCase();
|
||||
localeObj.id = correctedLocaleId;
|
||||
|
||||
var prefix =
|
||||
'angular.module("ngLocale", [], ["$provide", function($provide) {\n' +
|
||||
'var PLURAL_CATEGORY = {' +
|
||||
'ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"' +
|
||||
'};\n' +
|
||||
'$provide.value("$locale", ';
|
||||
|
||||
var suffix = ');\n}]);';
|
||||
|
||||
var content = JSON.stringify(localeInfo[localeID]).replace(/\¤/g,'\\u00A4').
|
||||
replace(/"@@|@@"/g, '');
|
||||
|
||||
var toWrite = prefix + content + suffix;
|
||||
qfs.write(__dirname + '/../locale/' + 'angular-locale_' + correctedLocaleId + '.js', toWrite);
|
||||
var content = closureI18nExtractor.outputLocale(localeInfo, localeID);
|
||||
if (!content) return;
|
||||
var correctedLocaleId = closureI18nExtractor.correctedLocaleId(localeID);
|
||||
var filename = NG_LOCALE_DIR + 'angular-locale_' + correctedLocaleId + '.js'
|
||||
writePromises.push(
|
||||
qfs.write(filename, content)
|
||||
.then(function () {
|
||||
console.log('Wrote ' + filename);
|
||||
++num_files;
|
||||
}));
|
||||
console.log('Writing ' + filename);
|
||||
});
|
||||
console.log('Generated ' + localeIds.length + ' locale files!');
|
||||
}).end();
|
||||
|
||||
function noop() {};
|
||||
console.log('Generated %j locale files.', localeIds.length);
|
||||
return Q.all(writePromises).then(function() { return num_files });
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a folder under current directory.
|
||||
* @param folder {string} name of the folder to be made
|
||||
*/
|
||||
function createFolder(folder) {
|
||||
return qfs.isDirectory(__dirname + '/' + folder).then(function(isDir) {
|
||||
if (!isDir) return qfs.makeDirectory(__dirname + '/' + folder);
|
||||
return qfs.isDirectory(folder).then(function(isDir) {
|
||||
if (!isDir) return qfs.makeDirectory(folder).then(function() {
|
||||
console.log('Created directory %j', folder); });
|
||||
});
|
||||
}
|
||||
|
||||
createFolder(NG_LOCALE_DIR)
|
||||
.then(readSymbols)
|
||||
.then(extractPlurals)
|
||||
.then(writeLocaleFiles)
|
||||
.done(function(num_files) { console.log("Wrote %j files.\nAll Done!", num_files); });
|
||||
|
||||
+2
-2
@@ -45,8 +45,8 @@ function parsePattern(pattern) {
|
||||
}
|
||||
|
||||
var groups = integer.split(GROUP_SEP);
|
||||
p.gSize = groups[1].length;
|
||||
p.lgSize = (groups[2] || groups[1]).length;
|
||||
p.gSize = groups[1] ? groups[1].length : 0;
|
||||
p.lgSize = (groups[2] || groups[1]) ? (groups[2] || groups[1]).length : 0;
|
||||
|
||||
if (negative) {
|
||||
var trunkLen = positive.length - p.posPre.length - p.posSuf.length,
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e # Exit on error.
|
||||
|
||||
BASE_DIR=`dirname $0`
|
||||
cd $BASE_DIR
|
||||
|
||||
set -x # Trace commands as they're executed.
|
||||
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/currency.js > closure/currencySymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbols.js > closure/datetimeSymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbolsext.js > closure/datetimeSymbolsExt.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/numberformatsymbols.js > closure/numberSymbols.js
|
||||
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/pluralrules.js > closure/pluralRules.js
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user