Compare commits
369 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
a03e370a09 | ||
|
|
23677d3ddb | ||
|
|
fc781560a3 | ||
|
|
c9199ee663 | ||
|
|
6f18adedef | ||
|
|
6ad894cd58 | ||
|
|
cde2f1a868 | ||
|
|
6a831495de | ||
|
|
6e2c38f54d | ||
|
|
00e7e31418 | ||
|
|
ff4b3e20c1 | ||
|
|
269fb43b36 | ||
|
|
7530654328 | ||
|
|
c7bd464384 | ||
|
|
ef1874d1f3 | ||
|
|
c6d8205fdd | ||
|
|
55150a669a | ||
|
|
1eb9e22d45 | ||
|
|
c0de8fb737 | ||
|
|
557e3894d7 | ||
|
|
38a9695413 | ||
|
|
293e0336b0 | ||
|
|
1f5bc0a1cd | ||
|
|
1fe666192b | ||
|
|
29541e735d | ||
|
|
f5b567d44b | ||
|
|
5ee3bbee90 | ||
|
|
80927c5811 | ||
|
|
ca8b344e20 | ||
|
|
3dab93874d | ||
|
|
7550f90a57 | ||
|
|
d78fea87d1 | ||
|
|
27cee7db0a | ||
|
|
60acba3840 | ||
|
|
51bed36370 | ||
|
|
6d940213ac | ||
|
|
494b527fa7 | ||
|
|
8ce84cb2ea | ||
|
|
d981c2a3ec | ||
|
|
537e20065a | ||
|
|
97578b4dae | ||
|
|
fa12564607 | ||
|
|
54bcb9ae25 | ||
|
|
ad7ce0d402 | ||
|
|
085e0ea8ef | ||
|
|
bb52c4e8d3 | ||
|
|
295af335c1 | ||
|
|
2c2e18c37a | ||
|
|
adfb75e3c6 | ||
|
|
9bff5c60df | ||
|
|
3ba008d4b2 | ||
|
|
4e45a2f8e2 | ||
|
|
4dbd8452eb | ||
|
|
45a8db9c08 | ||
|
|
d930a410fb | ||
|
|
66505ffc40 | ||
|
|
045de959b9 | ||
|
|
3ca11d5235 | ||
|
|
d5d8ac01e3 | ||
|
|
ace81c053c | ||
|
|
1e95c419b8 | ||
|
|
49ed63d26a | ||
|
|
6ff2685668 | ||
|
|
c4573c04aa | ||
|
|
d57abdb3f7 | ||
|
|
4050e89446 | ||
|
|
b6620c737f | ||
|
|
0c8e908841 | ||
|
|
5595e196a8 | ||
|
|
f92e4146d1 | ||
|
|
8b7108e3c9 | ||
|
|
caf702cc88 | ||
|
|
cf2c49ed7f | ||
|
|
ccd52abf5d | ||
|
|
74c574015d | ||
|
|
1f1a6fb6d2 | ||
|
|
8632e893b0 | ||
|
|
c2b6e127fa | ||
|
|
06eceeb09f | ||
|
|
8133d468b9 | ||
|
|
074a354fa9 | ||
|
|
e191582a02 | ||
|
|
6fbe926cda | ||
|
|
ebbc224e09 | ||
|
|
2c6aa4c300 | ||
|
|
f7a8f17fc7 | ||
|
|
191efbb558 | ||
|
|
bf873d6f02 | ||
|
|
e741107c55 | ||
|
|
82f4b99d99 | ||
|
|
7210b7ae1d | ||
|
|
afed23c001 | ||
|
|
1f69cc2989 | ||
|
|
3401833c83 | ||
|
|
06606e2816 | ||
|
|
eba64e1f31 | ||
|
|
81dd1df1b1 | ||
|
|
dbafbb0de5 | ||
|
|
1d0aa7b7c6 | ||
|
|
afd02ca48c | ||
|
|
67db7616ad | ||
|
|
3d7c752e27 | ||
|
|
f02833d634 | ||
|
|
0eb373e0e6 | ||
|
|
fd3071843c | ||
|
|
a631ceb223 | ||
|
|
a713928210 | ||
|
|
05fa20df81 | ||
|
|
125573602f | ||
|
|
ed5dfbcd66 | ||
|
|
d2e52b2376 | ||
|
|
a56aaa9877 | ||
|
|
79bb7b1f0b | ||
|
|
b936e52874 | ||
|
|
0d52ff0f10 | ||
|
|
baf52e902d | ||
|
|
dffea9e2b7 | ||
|
|
4a411b8f82 | ||
|
|
278bfc4bb2 | ||
|
|
18731173f9 | ||
|
|
d43fb404d7 | ||
|
|
da984ad187 | ||
|
|
4015357ce5 | ||
|
|
dc3d11ad19 | ||
|
|
0e1545eb04 | ||
|
|
ec7cabf5c9 | ||
|
|
3051beba2f | ||
|
|
92304323b1 | ||
|
|
c28123a872 | ||
|
|
d798423813 | ||
|
|
2583e77cc7 | ||
|
|
f66836fee4 | ||
|
|
0ccc445d53 | ||
|
|
b7d5fa1cbe | ||
|
|
8bb3942453 | ||
|
|
51a79cebcb | ||
|
|
36bcf64008 | ||
|
|
5c6630605b | ||
|
|
125827406c | ||
|
|
62c21422a6 | ||
|
|
98d489712e | ||
|
|
2cab2d8ef1 | ||
|
|
8fa2bb72bc | ||
|
|
d151f94937 | ||
|
|
5b74b7185b | ||
|
|
4f0be2ae4e | ||
|
|
bb9badeb2a | ||
|
|
c287c8361d | ||
|
|
ade7127c79 | ||
|
|
d341483f1f | ||
|
|
b36acbc857 | ||
|
|
a4fea38b94 | ||
|
|
300c5c0c99 | ||
|
|
152537c4e9 | ||
|
|
8b46bf6bc9 | ||
|
|
aef861eb41 | ||
|
|
f61d36861d | ||
|
|
2af0348cea | ||
|
|
78c5743494 | ||
|
|
2cb9fbd043 | ||
|
|
e9dad5dbf4 | ||
|
|
54895fc2a1 | ||
|
|
60a12b4161 | ||
|
|
cd7e58ba41 | ||
|
|
9391475dc3 | ||
|
|
7840803add | ||
|
|
7d77de2834 | ||
|
|
ab044cada6 | ||
|
|
d010e0cc7d | ||
|
|
40f728b1aa | ||
|
|
23abb26405 | ||
|
|
fd55bc8e1d | ||
|
|
541aaa4e08 | ||
|
|
f22c422547 | ||
|
|
0e461f0c07 | ||
|
|
5074448443 | ||
|
|
8d66af11e6 | ||
|
|
169948bb47 | ||
|
|
58d9469574 | ||
|
|
8d858a2360 | ||
|
|
5540748890 | ||
|
|
f8a52be817 | ||
|
|
3b5f1105f6 | ||
|
|
663ccc5449 | ||
|
|
263f47819f | ||
|
|
6b75475ce3 | ||
|
|
07c354a8c0 | ||
|
|
1391579599 | ||
|
|
5d2bd1d84c | ||
|
|
bf77e212af | ||
|
|
eef2f9c31e | ||
|
|
438627c2c3 |
|
|
@ -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
.gitignore
vendored
|
|
@ -10,6 +10,5 @@ performance/temp*.html
|
||||||
*~
|
*~
|
||||||
angular.js.tmproj
|
angular.js.tmproj
|
||||||
node_modules
|
node_modules
|
||||||
jsTestDriver*.conf
|
|
||||||
angular.xcodeproj
|
angular.xcodeproj
|
||||||
.idea
|
.idea
|
||||||
|
|
|
||||||
47
.project
|
|
@ -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
.travis.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.8
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export DISPLAY=:99.0
|
||||||
|
- sh -e /etc/init.d/xvfb start
|
||||||
|
- npm install -g grunt-cli
|
||||||
|
- grunt package
|
||||||
|
- grunt webserver > /dev/null &
|
||||||
|
|
||||||
|
script:
|
||||||
|
- grunt test --browsers Firefox --reporters=dots
|
||||||
532
CHANGELOG.md
|
|
@ -1,3 +1,535 @@
|
||||||
|
<a name="1.1.3"></a>
|
||||||
|
# 1.1.3 radioactive-gargle (2013-02-20)
|
||||||
|
|
||||||
|
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||||
|
They pass all tests but we reserve the right to change new features/apis in between minor releases. Check them
|
||||||
|
out and please give us feedback._
|
||||||
|
|
||||||
|
_Note: This release also contains all bug fixes available in [1.0.5](#1.0.5)._
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$compile:**
|
||||||
|
- initialize interpolated attributes before directive linking
|
||||||
|
([bb8448c0](https://github.com/angular/angular.js/commit/bb8448c011127306df08c7479b66e5afe7a0fa94))
|
||||||
|
- interpolate @ locals before the link function runs
|
||||||
|
([2ed53087](https://github.com/angular/angular.js/commit/2ed53087d7dd06d728e333a449265f7685275548))
|
||||||
|
- **$http:**
|
||||||
|
- do not encode special characters `@$:,` in params
|
||||||
|
([288b69a3](https://github.com/angular/angular.js/commit/288b69a314e9bd14458b6647532eb62aad5c5cdf))
|
||||||
|
- **$resource:**
|
||||||
|
- params should expand array values properly
|
||||||
|
([2a212344](https://github.com/angular/angular.js/commit/2a2123441c2b749b8f316a24c3ca3f77a9132a01))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$http:** allow overriding the XSRF header and cookie name
|
||||||
|
([8155c3a2](https://github.com/angular/angular.js/commit/8155c3a29ea0eb14806913b8ac08ba7727e1969c))
|
||||||
|
- **$parse:** added `constant` and `literal` properties
|
||||||
|
([1ed63858](https://github.com/angular/angular.js/commit/1ed638582d2f2c7f89384d9712f4cfac52cc5b70))
|
||||||
|
- **$resource:** expose promise based api via $then and $resolved
|
||||||
|
([dba6bc73](https://github.com/angular/angular.js/commit/dba6bc73e802fdae685a9f351d3e23c7efa8568a))
|
||||||
|
- **$routeProvider:** add support to catch-all parameters in routes
|
||||||
|
([7eafbb98](https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5))
|
||||||
|
- **Scope:**
|
||||||
|
- expose transcluded and isolate scope info for batarang
|
||||||
|
([649b8922](https://github.com/angular/angular.js/commit/649b892205615a144dafff9984c0e6ab10ed341d))
|
||||||
|
- only evaluate constant $watch expressions once
|
||||||
|
([1d7a95df](https://github.com/angular/angular.js/commit/1d7a95df565192fc02a18b0b297b39dd615eaeb5))
|
||||||
|
- **angular.noConflict:** added api to restore previous angular namespace reference
|
||||||
|
([12ba6cec](https://github.com/angular/angular.js/commit/12ba6cec4fb79521101744e02a7e09f9fbb591c4))
|
||||||
|
- **Directives:**
|
||||||
|
- **ngSwitch:** support multiple matches on ngSwitchWhen and ngSwitchDefault
|
||||||
|
([0af17204](https://github.com/angular/angular.js/commit/0af172040e03811c59d01682968241e3df226774),
|
||||||
|
[#1074](https://github.com/angular/angular.js/issues/1074))
|
||||||
|
- **Filters:**
|
||||||
|
- **date:** add `[.,]sss` formatter for milliseconds
|
||||||
|
([df744f3a](https://github.com/angular/angular.js/commit/df744f3af46fc227a934f16cb63c7a6038e7133b))
|
||||||
|
- **filter:** add comparison function to filter
|
||||||
|
([ace54ff0](https://github.com/angular/angular.js/commit/ace54ff08c4593195b49eadb04d258e6409d969e))
|
||||||
|
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
- **$http:** due to [288b69a3](https://github.com/angular/angular.js/commit/288b69a314e9bd14458b6647532eb62aad5c5cdf),
|
||||||
|
$http now follows RFC3986 and does not encode special characters like `$@,:` in params.
|
||||||
|
If your application needs to encode these characters, encode them manually, before sending the request.
|
||||||
|
- **$resource:** due to [2a212344](https://github.com/angular/angular.js/commit/2a2123441c2b749b8f316a24c3ca3f77a9132a01),
|
||||||
|
if the server relied on the buggy behavior of serializing arrays as http query arguments then
|
||||||
|
either the backend should be fixed or a simple serialization of the array should be done
|
||||||
|
on the client before calling the resource service.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.5"></a>
|
||||||
|
# 1.0.5 flatulent-propulsion (2013-02-20)
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$compile:**
|
||||||
|
- sanitize values bound to `a[href]`
|
||||||
|
([9532234b](https://github.com/angular/angular.js/commit/9532234bf1c408af9a6fd2c4743fdb585b920531))
|
||||||
|
- rename $compileNote to compileNode
|
||||||
|
([92ca7efa](https://github.com/angular/angular.js/commit/92ca7efaa4bc4f37da3008b234e19343a1fa4207),
|
||||||
|
[#1941](https://github.com/angular/angular.js/issues/1941))
|
||||||
|
- should not leak memory when there are top level empty text nodes
|
||||||
|
([791804bd](https://github.com/angular/angular.js/commit/791804bdbfa6da7a39283623bd05628a01cd8720))
|
||||||
|
- allow startingTag method to handle text / comment nodes
|
||||||
|
([755beb2b](https://github.com/angular/angular.js/commit/755beb2b66ce9f9f9a218f2355bbaf96d94fbc15))
|
||||||
|
- **$cookies:** set cookies on Safari&IE when `base[href]` is undefined
|
||||||
|
([70909245](https://github.com/angular/angular.js/commit/7090924515214752b919b0c5630b3ea5e7c77223),
|
||||||
|
[#1190](https://github.com/angular/angular.js/issues/1190))
|
||||||
|
- **$http:**
|
||||||
|
- patch for Firefox bug w/ CORS and response headers
|
||||||
|
([e19b04c9](https://github.com/angular/angular.js/commit/e19b04c9ec985821edf1269c628cfa261f81d631),
|
||||||
|
[#1468](https://github.com/angular/angular.js/issues/1468))
|
||||||
|
- **$resource:**
|
||||||
|
- update RegExp to allow urlParams with out leading slash
|
||||||
|
([b7e1fb05](https://github.com/angular/angular.js/commit/b7e1fb0515798e1b4f3f2426f6b050951bee2617))
|
||||||
|
- **Directives:**
|
||||||
|
- **a:** workaround IE bug affecting mailto urls
|
||||||
|
([37e8b122](https://github.com/angular/angular.js/commit/37e8b12265291918396bfee65d444a8f63697b73),
|
||||||
|
[#1949](https://github.com/angular/angular.js/issues/1949))
|
||||||
|
- **ngClass:** keep track of old ngClass value manually
|
||||||
|
([5f5d4fea](https://github.com/angular/angular.js/commit/5f5d4feadbfa9d8ecc8150041dfd2bca2b2e9fea),
|
||||||
|
[#1637](https://github.com/angular/angular.js/issues/1637))
|
||||||
|
- **ngSwitch:** make ngSwitch compatible with controller backwards-compatiblity module
|
||||||
|
([9b7c1d0f](https://github.com/angular/angular.js/commit/9b7c1d0f7ce442d4ad2ec587e66d2d335e64fa4e))
|
||||||
|
- **Filters:**
|
||||||
|
- **date:** invert timezone sign and always display sign
|
||||||
|
([b001c8ec](https://github.com/angular/angular.js/commit/b001c8ece5472626bf49cf82753e8ac1aafd2513),
|
||||||
|
[#1261](https://github.com/angular/angular.js/issues/1261))
|
||||||
|
- **number:** fix formatting when "0" passed as fractionSize
|
||||||
|
([f5835963](https://github.com/angular/angular.js/commit/f5835963d5982003a713dd354eefd376ed39ac02))
|
||||||
|
- **scenario runner:** include error messages in XML output
|
||||||
|
([d46fe3c2](https://github.com/angular/angular.js/commit/d46fe3c23fa269dcc10249148f2af14f3db6b066))
|
||||||
|
- **Misc:**
|
||||||
|
- don't use instanceof to detect arrays
|
||||||
|
([3c2aee01](https://github.com/angular/angular.js/commit/3c2aee01b0b299995eb92f4255159585b0f53c10),
|
||||||
|
[#1966](https://github.com/angular/angular.js/issues/1966))
|
||||||
|
- angular.forEach should correctly iterate over objects with length prop
|
||||||
|
([ec54712f](https://github.com/angular/angular.js/commit/ec54712ff3dab1ade44f94fa82d67edeffa79a1d),
|
||||||
|
[#1840](https://github.com/angular/angular.js/issues/1840))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.1.2"></a>
|
||||||
|
# 1.1.2 tofu-animation (2013-01-22)
|
||||||
|
|
||||||
|
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||||
|
They pass all tests but we reserve the right to change new features/apis in between minor releases. Check them
|
||||||
|
out and please give us feedback._
|
||||||
|
|
||||||
|
_Note: This release also contains all bug fixes available in [1.0.4](#1.0.4)._
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$compile:** support modifying the DOM structure in postlink fn
|
||||||
|
([cdf6fb19](https://github.com/angular/angular.js/commit/cdf6fb19c85560b30607e71dc2b19fde54760faa))
|
||||||
|
- **$log:** add $log.debug()
|
||||||
|
([9e991ddb](https://github.com/angular/angular.js/commit/9e991ddb1de13adf520eda459950be5b90b5b6d9),
|
||||||
|
[#1592](https://github.com/angular/angular.js/issues/1592))
|
||||||
|
- **$parse:** allow strict equality in angular expressions
|
||||||
|
([a179a9a9](https://github.com/angular/angular.js/commit/a179a9a96eda5c566bda8a70ac8a75822c936a68),
|
||||||
|
[#908](https://github.com/angular/angular.js/issues/908))
|
||||||
|
- **$resource:**
|
||||||
|
- allow dynamic default parameters
|
||||||
|
([cc42c99b](https://github.com/angular/angular.js/commit/cc42c99bec6a03d6c41b8e1d29ba2b1f5c16b87d))
|
||||||
|
- support all $http.config actions
|
||||||
|
([af89daf4](https://github.com/angular/angular.js/commit/af89daf4641f57b92be6c1f3635f5a3237f20c71))
|
||||||
|
- **$route:** allow using functions as template params in 'when'
|
||||||
|
([faf02f0c](https://github.com/angular/angular.js/commit/faf02f0c4db7962f863b0da2a82c8cafab2c706f))
|
||||||
|
- **$timeout-mock:** add verifyNoPendingTasks method
|
||||||
|
([f0c6ebc0](https://github.com/angular/angular.js/commit/f0c6ebc07653f6267acec898ccef5677884e3081),
|
||||||
|
[#1245](https://github.com/angular/angular.js/issues/1245))
|
||||||
|
- **directive:**
|
||||||
|
- added ngOpen boolean directive
|
||||||
|
([b8bd4d54](https://github.com/angular/angular.js/commit/b8bd4d5460d9952e9a3bb14992636b17859bd457))
|
||||||
|
- ngKeydown, ngKeyup
|
||||||
|
([e03182f0](https://github.com/angular/angular.js/commit/e03182f018f5069acd5e883ce2e9349b83f2d03f),
|
||||||
|
[#1035](https://github.com/angular/angular.js/issues/1035))
|
||||||
|
- **limitTo filter:** limitTo filter accepts strings
|
||||||
|
([9e96d983](https://github.com/angular/angular.js/commit/9e96d983451899ef0cef3e68395c8f6c1ef83bbe),
|
||||||
|
[#653](https://github.com/angular/angular.js/issues/653))
|
||||||
|
- **scenario:**
|
||||||
|
- add mouseover method to the ngScenario dsl
|
||||||
|
([2f437e89](https://github.com/angular/angular.js/commit/2f437e89781cb2b449abb685e36b26ca1cf0fff5))
|
||||||
|
- fail when an option to select does not exist
|
||||||
|
([15183f3e](https://github.com/angular/angular.js/commit/15183f3e1fbee031c9595206163962788f98b298))
|
||||||
|
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
- **date:** due to [cc821502](https://github.com/angular/angular.js/commit/cc821502bca64d15e1c576bf20a62b28b3d9a88a),
|
||||||
|
string input without timezone info is now parsed as local time/date
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.4"></a>
|
||||||
|
# 1.0.4 bewildering-hair (2013-01-22)
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$compile:**
|
||||||
|
- do not wrap empty root text nodes in spans
|
||||||
|
([49f9e4ce](https://github.com/angular/angular.js/commit/49f9e4cef13e68ff85b3c160cf8fac6e7cd042a3),
|
||||||
|
[#1059](https://github.com/angular/angular.js/issues/1059))
|
||||||
|
- safely create transclude comment nodes
|
||||||
|
([74dd2f79](https://github.com/angular/angular.js/commit/74dd2f7980ea8ec434a6e0565d857c910653ed9b),
|
||||||
|
[#1740](https://github.com/angular/angular.js/issues/1740))
|
||||||
|
- **$injector:**
|
||||||
|
- remove bogus fn arg
|
||||||
|
([b6b7c5a1](https://github.com/angular/angular.js/commit/b6b7c5a1d66073937709158da8c2d688cb45c9f6),
|
||||||
|
[#1711](https://github.com/angular/angular.js/issues/1711))
|
||||||
|
- provider can now be defined in the array format
|
||||||
|
([2c405f41](https://github.com/angular/angular.js/commit/2c405f417125c80c387a51baece8bf6e1e0c0a81),
|
||||||
|
[#1452](https://github.com/angular/angular.js/issues/1452))
|
||||||
|
- **$resource:**
|
||||||
|
- HTTP method should be case-insensitive
|
||||||
|
([8991680d](https://github.com/angular/angular.js/commit/8991680d8ab632dda60cd70c780868c803c74509),
|
||||||
|
[#1403](https://github.com/angular/angular.js/issues/1403))
|
||||||
|
- correct leading slash removal in resource URLs
|
||||||
|
([b2f46251](https://github.com/angular/angular.js/commit/b2f46251aca76c8568ee7d4bab54edbc9d7a186a))
|
||||||
|
- **$route:**
|
||||||
|
- support route params not separated with slashes.
|
||||||
|
([c6392616](https://github.com/angular/angular.js/commit/c6392616ea5245bd0d2f77dded0b948d9e2637c8))
|
||||||
|
- correctly extract $routeParams from urls
|
||||||
|
([30a9da5d](https://github.com/angular/angular.js/commit/30a9da5dc159dd1e19b677914356925c7ebdf632))
|
||||||
|
- **Scope:** ensure that a scope is destroyed only once
|
||||||
|
([d6da505f](https://github.com/angular/angular.js/commit/d6da505f4e044f8a487ac27a3ec707c11853ee0a),
|
||||||
|
[#1627](https://github.com/angular/angular.js/issues/1627))
|
||||||
|
- **angular.equals:**
|
||||||
|
- consistently compare undefined object props
|
||||||
|
([5ae63fd3](https://github.com/angular/angular.js/commit/5ae63fd385295d5a7bbdc79466f59727dcab1c85),
|
||||||
|
[3c2e1c5e](https://github.com/angular/angular.js/commit/3c2e1c5e4d12529b1d69a6173c38097527dccc4f),
|
||||||
|
[#1648](https://github.com/angular/angular.js/issues/1648))
|
||||||
|
- **date filter:** parse string input as local time unless TZ is specified
|
||||||
|
([cc821502](https://github.com/angular/angular.js/commit/cc821502bca64d15e1c576bf20a62b28b3d9a88a),
|
||||||
|
[#847](https://github.com/angular/angular.js/issues/847))
|
||||||
|
- **jqLite:**
|
||||||
|
- children() should only return elements
|
||||||
|
([febb4c1c](https://github.com/angular/angular.js/commit/febb4c1c35cf767ae31fc9fef1f4b4f026ac9de0))
|
||||||
|
- make next() ignore non-element nodes
|
||||||
|
([76a6047a](https://github.com/angular/angular.js/commit/76a6047af690781b8238ba7924279470ba76d081))
|
||||||
|
- **scenario:** don't trigger input events on IE9
|
||||||
|
([8b9e6c35](https://github.com/angular/angular.js/commit/8b9e6c3501746edb2c9e2d585e8e0eaeb8ba8327))
|
||||||
|
- **Directives:**
|
||||||
|
- **ngRepeat:** correctly apply $last if repeating over object
|
||||||
|
([7e746015](https://github.com/angular/angular.js/commit/7e746015ea7dec3e9eb81bc4678fa9b6a83bc47c),
|
||||||
|
[#1789](https://github.com/angular/angular.js/issues/1789))
|
||||||
|
- **ngSwitch:** don't leak when destroyed while not attached
|
||||||
|
([a26234f7](https://github.com/angular/angular.js/commit/a26234f7183013e2fcc9b35377e181ad96dc9917),
|
||||||
|
[#1621](https://github.com/angular/angular.js/issues/1621))
|
||||||
|
- **select:** support optgroup + select[multiple] combo
|
||||||
|
([26adeb11](https://github.com/angular/angular.js/commit/26adeb119bc4fafa6286de484626b8de4170abc9),
|
||||||
|
[#1553](https://github.com/angular/angular.js/issues/1553))
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$compile:** support modifying the DOM structure in postlink fn
|
||||||
|
([cdf6fb19](https://github.com/angular/angular.js/commit/cdf6fb19c85560b30607e71dc2b19fde54760faa))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.1.1"></a>
|
||||||
|
# 1.1.1 pathological-kerning (2012-11-26)
|
||||||
|
|
||||||
|
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||||
|
They pass all tests but we reserve the right to change new features/apis in between minor releases. Check them
|
||||||
|
out and please give us feedback._
|
||||||
|
|
||||||
|
_Note: This release also contains all bug fixes available in [1.0.3](#1.0.3)._
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$cacheFactory:** cache.put now returns the added value
|
||||||
|
([168db339](https://github.com/angular/angular.js/commit/168db33985aa025eb48bc21087717ab70da0bd72))
|
||||||
|
- **$http:** Allow setting withCredentials on defaults
|
||||||
|
([209b67df](https://github.com/angular/angular.js/commit/209b67df6a49fe1646ce63c5e7d11ed26e8abbc1),
|
||||||
|
[#1095](https://github.com/angular/angular.js/issues/1095))
|
||||||
|
- **$resource:** support custom headers per action
|
||||||
|
([fbdab513](https://github.com/angular/angular.js/commit/fbdab513dd48f667ad857030cf4b3481ecdd9097),
|
||||||
|
[#736](https://github.com/angular/angular.js/issues/736))
|
||||||
|
- **$sanitize:** support telephone links
|
||||||
|
([04450c48](https://github.com/angular/angular.js/commit/04450c48dfea065e1c9e4ab8adad94993ed1b037))
|
||||||
|
- **FormController:** add ability to reset a form to pristine state
|
||||||
|
([733a97ad](https://github.com/angular/angular.js/commit/733a97adf87bf8f7ec6be22b37c4676cf7b5fc2b),
|
||||||
|
[#856](https://github.com/angular/angular.js/issues/856))
|
||||||
|
- **jqLite:** add triggerHandler()
|
||||||
|
([650fd933](https://github.com/angular/angular.js/commit/650fd933df614ac733cd43fe31d81d622a2ce2bc))
|
||||||
|
- **linky filter:** allow optional 'target' argument
|
||||||
|
([610927d7](https://github.com/angular/angular.js/commit/610927d77b77700c5c61accd503a2af0fa51cfe6),
|
||||||
|
[#1443](https://github.com/angular/angular.js/issues/1443))
|
||||||
|
- **angular-mocks:** support mocha in angular mocks
|
||||||
|
([92558fe4](https://github.com/angular/angular.js/commit/92558fe4119fb1ee793d781de1888abef181c7f6))
|
||||||
|
- **ngModel:** support ngTrim attribute on input
|
||||||
|
([d519953a](https://github.com/angular/angular.js/commit/d519953a4b219035587e3fcb2e9cc52e02b408ca))
|
||||||
|
- **scenario:** add dblclick method to the ngScenario dsl
|
||||||
|
([8cb9c99e](https://github.com/angular/angular.js/commit/8cb9c99ec064fd95567118d29bfa4a19b8613ab3))
|
||||||
|
- **CSP:** update to the latest CSP api
|
||||||
|
([af7e0bd0](https://github.com/angular/angular.js/commit/af7e0bd0a7c286667c526cb7e0c733d3ee5f17fd),
|
||||||
|
[#1577](https://github.com/angular/angular.js/issues/1577))
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$http:**
|
||||||
|
- config.param should expand array values properly (see breaking change notes below)
|
||||||
|
([79af2bad](https://github.com/angular/angular.js/commit/79af2badcb087881e3fd600f6ae5bf3f86a2daf8),
|
||||||
|
[#1363](https://github.com/angular/angular.js/issues/1363))
|
||||||
|
- prevent CORS preflight checks by removing `X-Requested-With` from header defaults (see breaking
|
||||||
|
change notes below)
|
||||||
|
([3a75b112](https://github.com/angular/angular.js/commit/3a75b1124d062f64093a90b26630938558909e8d),
|
||||||
|
[#1004](https://github.com/angular/angular.js/issues/1004))
|
||||||
|
- prevent CORS preflight checks by not setting `X-XSFR-TOKEN` header for cross domain requests (see
|
||||||
|
breaking change notes below)
|
||||||
|
([fce100a4](https://github.com/angular/angular.js/commit/fce100a46c5681562253c3a856d67bbd35fbc2f2),
|
||||||
|
[#1096](https://github.com/angular/angular.js/issues/1096))
|
||||||
|
|
||||||
|
|
||||||
|
## Refactorings
|
||||||
|
|
||||||
|
- **$evalAsync:** have only one global async queue
|
||||||
|
([331cd5a8](https://github.com/angular/angular.js/commit/331cd5a8cb5efdafe8ad7eb386aed4033cfc1bb3))
|
||||||
|
|
||||||
|
|
||||||
|
## Breaking Changes
|
||||||
|
|
||||||
|
- Due to fix for [#1363](https://github.com/angular/angular.js/issues/1363) it's possible but unlikely
|
||||||
|
that $http will start generating different URLs for requests. This affects only cases when a request
|
||||||
|
is made with a parameter, value of which is an array. If the server relied on the buggy behavior then
|
||||||
|
either the backend should be fixed or a simple serialization of the array should be done on the client
|
||||||
|
before calling the $http service.
|
||||||
|
|
||||||
|
- Due to fix for [#1004](https://github.com/angular/angular.js/issues/1004) the `X-Requested-With` header
|
||||||
|
is not set by $http service any more. If anyone actually uses this header it's quite easy to add
|
||||||
|
it back via:
|
||||||
|
|
||||||
|
```
|
||||||
|
myAppModule.config(['$httpProvider', function($httpProvider) {
|
||||||
|
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
|
||||||
|
}]);
|
||||||
|
```
|
||||||
|
|
||||||
|
- Due to fix for [#1096](https://github.com/angular/angular.js/issues/1096) `X-XSFR-TOKEN` header is
|
||||||
|
no longer send for cross domain requests. This shouldn't affect any known production service. If we are
|
||||||
|
wrong, please let us know ;-)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.3"></a>
|
||||||
|
# 1.0.3 bouncy-thunder (2012-11-26)
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$cacheFactory:** return undefined when removing non-existent entry
|
||||||
|
([55d15806](https://github.com/angular/angular.js/commit/55d15806fb14b1d98b5ca2770bbbb59e11548c62),
|
||||||
|
[#1497](https://github.com/angular/angular.js/issues/1497))
|
||||||
|
- **$compile:**
|
||||||
|
- prevent double attr interpolation w/ templateUrl
|
||||||
|
([fc115bfd](https://github.com/angular/angular.js/commit/fc115bfd0d18017f4bcef1e39fb22d97a98f8ab1),
|
||||||
|
[#1166](https://github.com/angular/angular.js/issues/1166))
|
||||||
|
- reference local in isolate scope
|
||||||
|
([8db47ca7](https://github.com/angular/angular.js/commit/8db47ca7d4303e3e45a838219a1f6e9be8770ed4),
|
||||||
|
[#1272](https://github.com/angular/angular.js/issues/1272))
|
||||||
|
- don't look for class directives in empty string
|
||||||
|
([54b3875b](https://github.com/angular/angular.js/commit/54b3875ba5cb6ce8ddac61ace33c1b2f600875ff))
|
||||||
|
- compilation should not recurse into empty nodes
|
||||||
|
([008a782b](https://github.com/angular/angular.js/commit/008a782bc8ed8a7ebcb63d563d1420fd1b312452))
|
||||||
|
- **$injector:** more conservative annotation parsing
|
||||||
|
- **$location:** reset $location.$$replace with every watch call
|
||||||
|
([a32bc40f](https://github.com/angular/angular.js/commit/a32bc40fd75ca46e3581ad7a6e3a24a31df6e266),
|
||||||
|
[#1111](https://github.com/angular/angular.js/issues/1111))
|
||||||
|
([d9eff86e](https://github.com/angular/angular.js/commit/d9eff86ef77dd76208cef21e882239d4db0eac1e))
|
||||||
|
- **$parser:** string concatination with undefined model
|
||||||
|
([42c38b29](https://github.com/angular/angular.js/commit/42c38b29f7dcb3327fe58e630b8e2973676989e0),
|
||||||
|
[#988](https://github.com/angular/angular.js/issues/988))
|
||||||
|
- **$resource:**
|
||||||
|
- prevent default params to be shared between actions
|
||||||
|
([94e1c039](https://github.com/angular/angular.js/commit/94e1c0391c351b6f691fad8abed2828fa20548b2))
|
||||||
|
- allow falsy values in URL parameters
|
||||||
|
([4909d1d3](https://github.com/angular/angular.js/commit/4909d1d39d61d6945a0820a5a7276c1e657ba262))
|
||||||
|
- ignore undefined parameters
|
||||||
|
([10e1c759](https://github.com/angular/angular.js/commit/10e1c759f4602d993a76b0eacf6a2d04c8880017),
|
||||||
|
[#875](https://github.com/angular/angular.js/issues/875),
|
||||||
|
[#782](https://github.com/angular/angular.js/issues/782))
|
||||||
|
- **Scope:**
|
||||||
|
- workaround for Chrome's memleak
|
||||||
|
([bd524fc4](https://github.com/angular/angular.js/commit/bd524fc4e5fc0feffe85632a7a6560da6bd9b762),
|
||||||
|
[#1313](https://github.com/angular/angular.js/issues/1313))
|
||||||
|
- allow removing a listener during event
|
||||||
|
([e6966e05](https://github.com/angular/angular.js/commit/e6966e05f508d1d2633b9ff327fea912b12555ac))
|
||||||
|
- **$route:** support inline annotation on .resolve
|
||||||
|
([b0a05a75](https://github.com/angular/angular.js/commit/b0a05a7531ed7235aa6d2c4e3ea11373e1fc73f1))
|
||||||
|
- **FormController:** propagate dirty state to parent forms
|
||||||
|
([04329151](https://github.com/angular/angular.js/commit/04329151d2df833f803629cefa781aa6409fe6a5))
|
||||||
|
- **a:** prevent Opera from incorrectly navigating on link click
|
||||||
|
([c81d8176](https://github.com/angular/angular.js/commit/c81d8176cc55cd15acae05259ead73f90a01f0b7))
|
||||||
|
- **jqLite:**
|
||||||
|
- support append on document fragment
|
||||||
|
([96ed9ff5](https://github.com/angular/angular.js/commit/96ed9ff59a454486c88bdf92ad9d28ab8864b85e))
|
||||||
|
- fire $destroy event via triggerHandler (this makes AngularJS compatible with **jQuery 1.8.x**)
|
||||||
|
([b9a9f91f](https://github.com/angular/angular.js/commit/b9a9f91fbf99b71cfde434b6277f4c7d2533556f),
|
||||||
|
[#1512](https://github.com/angular/angular.js/issues/1512))
|
||||||
|
- **Filters**
|
||||||
|
- **currency:** Handle not-quite-zero values
|
||||||
|
([bca1604c](https://github.com/angular/angular.js/commit/bca1604c12262b66ce3b8004994fb4841fb8b87d),
|
||||||
|
[#1469](https://github.com/angular/angular.js/issues/1469))
|
||||||
|
- **date:**
|
||||||
|
- make timezone optional
|
||||||
|
([9473780e](https://github.com/angular/angular.js/commit/9473780e77a960ba27644ca76c2413924cc8972e))
|
||||||
|
- support sub-second precision on dateFilter
|
||||||
|
([f299fd51](https://github.com/angular/angular.js/commit/f299fd512248321b426a5ab924a329aa1b691280))
|
||||||
|
- **Directives**
|
||||||
|
- **ngClass:** works with class interpolation
|
||||||
|
([cebd015f](https://github.com/angular/angular.js/commit/cebd015f78c5e21bd37d4bc055dbcdc21dac2ef2),
|
||||||
|
[#1016](https://github.com/angular/angular.js/issues/1016))
|
||||||
|
- **ngClassOdd/ngClassEven:** support shrinking/reordering in repeaters
|
||||||
|
([d859dcec](https://github.com/angular/angular.js/commit/d859dcecea654d1d858cd756c6efb8435a453197),
|
||||||
|
[6c67719d](https://github.com/angular/angular.js/commit/6c67719dfa6ff3f2a15a8e1e7660cf2e6e9155b0),
|
||||||
|
[#1076](https://github.com/angular/angular.js/issues/1076))
|
||||||
|
- **ngModel:** sync ngModel state with scope state
|
||||||
|
([e6d9bea4](https://github.com/angular/angular.js/commit/e6d9bea4f3b2eb28851298d3dc3a30d46062d58a),
|
||||||
|
[#933](https://github.com/angular/angular.js/issues/933))
|
||||||
|
- **ngRepeat:** now works better with primitive types
|
||||||
|
([e6d9bea4](https://github.com/angular/angular.js/commit/e6d9bea4f3b2eb28851298d3dc3a30d46062d58a),
|
||||||
|
[#933](https://github.com/angular/angular.js/issues/933))
|
||||||
|
- **ngSrc:** don't set src if value is empty string
|
||||||
|
([b6e4a711](https://github.com/angular/angular.js/commit/b6e4a71166c7f00f4140fd7ea8f0cd81b4487a3f))
|
||||||
|
- **select:** select option with a label of 0 is not shown
|
||||||
|
([b3cae4f4](https://github.com/angular/angular.js/commit/b3cae4f457f1688346bbd0b08cccc9c504f83406),
|
||||||
|
[#1401](https://github.com/angular/angular.js/issues/1401))
|
||||||
|
- **scenario:**
|
||||||
|
- emit RunnerBegin event
|
||||||
|
([95276a7e](https://github.com/angular/angular.js/commit/95276a7e1047c7a3ac6613d8612c62f544388fc9))
|
||||||
|
- NPE when no angular loaded in test page
|
||||||
|
([84c13d96](https://github.com/angular/angular.js/commit/84c13d96ff6e993b2ee9ff6bf49614fc1d514b04))
|
||||||
|
- support data-ng and x-ng based attributes
|
||||||
|
([249a1d84](https://github.com/angular/angular.js/commit/249a1d84e7ac3b8528d317b8b0a80acb5dd9a271),
|
||||||
|
[#1020](https://github.com/angular/angular.js/issues/1020))
|
||||||
|
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- add plunkr support
|
||||||
|
([7c67b2fb](https://github.com/angular/angular.js/commit/7c67b2fb6afbc18f3593c64a5f339f04f9003f3c))
|
||||||
|
- various small documentation fixes and improvements
|
||||||
|
|
||||||
|
|
||||||
|
## Refactorings
|
||||||
|
|
||||||
|
- name all anonymous watch functions in Angular
|
||||||
|
([ca30fce2](https://github.com/angular/angular.js/commit/ca30fce28ca13284bfa1c926e810ed75cdcde499),
|
||||||
|
[#1119](https://github.com/angular/angular.js/issues/1119))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.1.0"></a>
|
||||||
|
# 1.1.0 increase-gravatas (2012-08-31)
|
||||||
|
|
||||||
|
_Note: 1.1.x releases unlike 1.0.x are considered unstable.
|
||||||
|
[More info](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html)_
|
||||||
|
|
||||||
|
This release also contains all bug fixes available in [1.0.2](#1.0.2).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$http:** support custom reponseType
|
||||||
|
([e0a54f6b](https://github.com/angular/angular.js/commit/e0a54f6b206dc2b6595f2bc3a17c5932e7477545),
|
||||||
|
[#1013](https://github.com/angular/angular.js/issues/1013))
|
||||||
|
- **$interpolate:**
|
||||||
|
- provide contextual error messages
|
||||||
|
([d804bbcd](https://github.com/angular/angular.js/commit/d804bbcd51ec83bee1f4a3ccd42c3bd7eb38a988))
|
||||||
|
- expose start/end symbols in run phase
|
||||||
|
([58f121a5](https://github.com/angular/angular.js/commit/58f121a5c293ed57043e22ed526fdf99642fca81))
|
||||||
|
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
|
||||||
|
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.2"></a>
|
||||||
|
# 1.0.2 debilitating-awesomeness (2012-08-31)
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$compile:** denormalize directive templates
|
||||||
|
([dfe99836](https://github.com/angular/angular.js/commit/dfe99836cd98c2a1b0f9bde6216bd44088de275a))
|
||||||
|
- **$interpolate:** $interpolateProvider.endSymbol() returns startSymbol
|
||||||
|
([20348717](https://github.com/angular/angular.js/commit/20348717640c0ef405c9fdcc8fec5b566efc48b3))
|
||||||
|
- **jqLite:** better support for xhtml
|
||||||
|
([d3fa7a2e](https://github.com/angular/angular.js/commit/d3fa7a2e9e93c9dae13d852b28c878f7d6b7c420),
|
||||||
|
[#1301](https://github.com/angular/angular.js/issues/1301))
|
||||||
|
- **mocks:** free up memory after every spec
|
||||||
|
([1a8642aa](https://github.com/angular/angular.js/commit/1a8642aac2de40dccdab464e58dc164006c300bb))
|
||||||
|
- **e2e test runner:** Adding meta tag to avoid cache issues
|
||||||
|
([5318588d](https://github.com/angular/angular.js/commit/5318588d6e8ee9a31f4002affd6858d25305aabf))
|
||||||
|
- Directives:
|
||||||
|
- **form:** prevent page reload when form destroyed
|
||||||
|
([054d40f3](https://github.com/angular/angular.js/commit/054d40f338f9000cddcf7f0513af37328b88ef41),
|
||||||
|
[#1238](https://github.com/angular/angular.js/issues/1238))
|
||||||
|
- **ngList:** remove data bound flicker
|
||||||
|
([fa62ea81](https://github.com/angular/angular.js/commit/fa62ea810f6c701e898dd07c6c9228f13d5b5e02))
|
||||||
|
- **ngPluralize:** fixes ng-pluralize when using non-standard start/end symbols
|
||||||
|
([e85774f7](https://github.com/angular/angular.js/commit/e85774f709b9f681b0ff8d829b07568b0f844a62),
|
||||||
|
[#1134](https://github.com/angular/angular.js/issues/1134))
|
||||||
|
- **option:** support option elements in datalist
|
||||||
|
([9767f7bd](https://github.com/angular/angular.js/commit/9767f7bdd3e1ce6f65bdea992d67369ead13d813),
|
||||||
|
[#1165](https://github.com/angular/angular.js/issues/1165))
|
||||||
|
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- Conceptual Overview of AngularJS (high level overview of how things work):
|
||||||
|
<http://docs.angularjs.org/guide/concepts>
|
||||||
|
([7a5f25f6](https://github.com/angular/angular.js/commit/7a5f25f6671eb5f51b06615d74a05855ab79f31e))
|
||||||
|
- Lots of spelling, grammar and other fixes:
|
||||||
|
[9a710c78](https://github.com/angular/angular.js/commit/9a710c788d880785d2b02a9c5411eb15e9c278bf),
|
||||||
|
[847d2da0](https://github.com/angular/angular.js/commit/847d2da0f8d1e265eda7b4dd3e7eb52ac86d784e),
|
||||||
|
[dbefd671](https://github.com/angular/angular.js/commit/dbefd671e41c3bda481850bb7e566349e275d759),
|
||||||
|
[cab5e1d9](https://github.com/angular/angular.js/commit/cab5e1d9b363eac6fd31b15c5b86f30993e2f147),
|
||||||
|
[f00b6cca](https://github.com/angular/angular.js/commit/f00b6cca024a9418f353651f29c984f934575bd9),
|
||||||
|
[2e365168](https://github.com/angular/angular.js/commit/2e3651686c2bd84cf464ecc236c8ad77e61179df),
|
||||||
|
[536de148](https://github.com/angular/angular.js/commit/536de148214290f0b4a0595fa16c00da5e527e79),
|
||||||
|
[a1107e81](https://github.com/angular/angular.js/commit/a1107e81ebf2254caf75718de2e3ec773cce0c56),
|
||||||
|
[5ef9ed87](https://github.com/angular/angular.js/commit/5ef9ed87d82b109715a87e9aa1b1d5b63f515d3a),
|
||||||
|
[8c81a0f3](https://github.com/angular/angular.js/commit/8c81a0f3728b9308854ceb9bf392ec467b95d8eb),
|
||||||
|
[bde931af](https://github.com/angular/angular.js/commit/bde931afd5cf2483df236e06992666a0a4182794),
|
||||||
|
[6553fe68](https://github.com/angular/angular.js/commit/6553fe68d17d42ec25e0c592ceaa1077cc0ec4f6),
|
||||||
|
[13b5fd1b](https://github.com/angular/angular.js/commit/13b5fd1b9d60f1a9187da8a89db9272284ccdac4),
|
||||||
|
[17209d5b](https://github.com/angular/angular.js/commit/17209d5b4a579edf8425715b5cdf25bc5cd96711),
|
||||||
|
[31c82560](https://github.com/angular/angular.js/commit/31c825607dd524241c811ca3e401b119c810e977),
|
||||||
|
[ab6937e2](https://github.com/angular/angular.js/commit/ab6937e2518bfd77d9fe42e3d2e11fe4a7a16814),
|
||||||
|
[fbfda241](https://github.com/angular/angular.js/commit/fbfda241f616bcfe8273f501dd49120a3cb35fab),
|
||||||
|
[206371b7](https://github.com/angular/angular.js/commit/206371b7372c242db234ca8da12d1c7a8a322d54),
|
||||||
|
[b6b92bd8](https://github.com/angular/angular.js/commit/b6b92bd866e1d6d066f1c9bf1937496cd3e28664),
|
||||||
|
[79f2d843](https://github.com/angular/angular.js/commit/79f2d843a8458bfdc23fe9f179a1416fe21f7533),
|
||||||
|
[64a9cd8f](https://github.com/angular/angular.js/commit/64a9cd8f4fac1c518869a1c955fe60bd6ef76439),
|
||||||
|
[7f6e1326](https://github.com/angular/angular.js/commit/7f6e1326f3a7a6a2ba2dbd48dd6571ebe929a7c1),
|
||||||
|
[1fd2b3d4](https://github.com/angular/angular.js/commit/1fd2b3d402f36e395a1fe9ea7e3f91a1b2833426),
|
||||||
|
[d56d69cc](https://github.com/angular/angular.js/commit/d56d69cc8319f69135a17a9bb5ae394123b33c51),
|
||||||
|
[01e726b2](https://github.com/angular/angular.js/commit/01e726b2fa3fb0d2584c9bb8df116ff3a9f05879),
|
||||||
|
[16136216](https://github.com/angular/angular.js/commit/161362164532af3578c9e3e8b52cd80b15345add),
|
||||||
|
[92a3d282](https://github.com/angular/angular.js/commit/92a3d2821856c75eb95f8ec6ccf26d6a9b37fdd9),
|
||||||
|
[4c585019](https://github.com/angular/angular.js/commit/4c5850195699b1d982963f25399d24bf8b815f81),
|
||||||
|
[c076fe08](https://github.com/angular/angular.js/commit/c076fe08cf47e8af4b5e8845aed917ebb7dbd593),
|
||||||
|
[2473412b](https://github.com/angular/angular.js/commit/2473412ba55f7c47f2ca24311312ce95ee11949e),
|
||||||
|
[1f2d5000](https://github.com/angular/angular.js/commit/1f2d50000e82630bfce6eb9cf0a8da752fd1e826),
|
||||||
|
[5026315d](https://github.com/angular/angular.js/commit/5026315d6f4495d636d86ae2a022fb55cc0ca211),
|
||||||
|
[f0a090dd](https://github.com/angular/angular.js/commit/f0a090ddf256d0c144e705c0cdf4216d824140f9),
|
||||||
|
[6d9313a6](https://github.com/angular/angular.js/commit/6d9313a68d82654d389c0b2c3e4af148382f14be)) and more!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="1.0.1"></a>
|
<a name="1.0.1"></a>
|
||||||
# 1.0.1 thorium-shielding (2012-06-25)
|
# 1.0.1 thorium-shielding (2012-06-25)
|
||||||
|
|
||||||
|
|
|
||||||
32
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
## Submitting issues
|
||||||
|
|
||||||
|
If you have questions about how to use AngularJS, please direct these to the
|
||||||
|
[Google Group][groups] discussion list or [StackOverflow][stackoverflow]. We are
|
||||||
|
also available on [IRC][irc].
|
||||||
|
|
||||||
|
### Guidelines
|
||||||
|
|
||||||
|
* Search the archive first, it's likely that your question was already answered.
|
||||||
|
* A live example demonstrating your problem or question, will get an answer faster.
|
||||||
|
* Create one using this [template][template]
|
||||||
|
* If you get help, help others. Good karma rulez!
|
||||||
|
|
||||||
|
If your issue appears to be a bug, and hasn't been reported, open a new issue.
|
||||||
|
Help us to maximize the effort we can spend fixing issues and adding new
|
||||||
|
features, by not reporting duplicate issues.
|
||||||
|
|
||||||
|
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
|
||||||
|
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
|
||||||
|
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
|
||||||
|
[template]: http://plnkr.co/edit/gist:3510140
|
||||||
|
|
||||||
|
## Contributing to Source Code
|
||||||
|
|
||||||
|
We'd love for you to contribute to our source code and to make AngularJS even
|
||||||
|
better than it is today!
|
||||||
|
|
||||||
|
Please read the [contribution guidelines][contribute] to learn about how to submit code as well as
|
||||||
|
other useful info like how to build and test AngularJS code.
|
||||||
|
|
||||||
|
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
|
||||||
|
[contribute]: http://docs.angularjs.org/misc/contribute
|
||||||
171
Gruntfile.js
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
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.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,
|
||||||
|
|
||||||
|
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: {}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
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']
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
copy: {
|
||||||
|
i18n: {
|
||||||
|
files: [
|
||||||
|
{ src: 'src/ngLocale/**', dest: 'build/i18n/', expand: true, flatten: true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
compress: {
|
||||||
|
build: {
|
||||||
|
options: {archive: 'build/' + dist +'.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('default', ['package']);
|
||||||
|
};
|
||||||
28
README.md
|
|
@ -1,11 +1,11 @@
|
||||||
AngularJS
|
AngularJS
|
||||||
=========
|
=========
|
||||||
|
|
||||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets use
|
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
|
||||||
good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
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
|
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
|
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
|
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
|
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:
|
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
|
||||||
|
|
@ -13,17 +13,27 @@ it makes development fun!
|
||||||
|
|
||||||
* Web site: http://angularjs.org
|
* Web site: http://angularjs.org
|
||||||
* Tutorial: http://docs.angularjs.org/tutorial
|
* Tutorial: http://docs.angularjs.org/tutorial
|
||||||
* API Docs: http://docs.angularjs.org
|
* API Docs: http://docs.angularjs.org/api
|
||||||
* Developer Guide: http://docs.angularjs.org/guide
|
* Developer Guide: http://docs.angularjs.org/guide
|
||||||
|
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
|
||||||
|
|
||||||
Compiling
|
Building AngularJS
|
||||||
---------
|
---------
|
||||||
rake compile
|
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
|
||||||
|
|
||||||
|
grunt package
|
||||||
|
|
||||||
|
|
||||||
Running Tests
|
Running Tests
|
||||||
-------------
|
-------------
|
||||||
./server.sh # start the server
|
To execute all unit tests, use:
|
||||||
open http://localhost:9876/capture # capture browser
|
|
||||||
./test.sh # run all unit tests
|
|
||||||
|
|
||||||
|
grunt test:unit
|
||||||
|
|
||||||
|
To execute end-to-end (e2e) tests, use:
|
||||||
|
|
||||||
|
grunt package
|
||||||
|
grunt test:e2e
|
||||||
|
|
||||||
|
To learn more about the grunt tasks, run `grunt --help` and also read our
|
||||||
|
[contribution guidelines](http://docs.angularjs.org/misc/contribute).
|
||||||
|
|
|
||||||
328
Rakefile
|
|
@ -1,328 +0,0 @@
|
||||||
require 'yaml'
|
|
||||||
include FileUtils
|
|
||||||
|
|
||||||
content = File.open('angularFiles.js', 'r') {|f| f.read }
|
|
||||||
files = eval(content.gsub(/\};(\s|\S)*/, '}').
|
|
||||||
gsub(/angularFiles = /, '').
|
|
||||||
gsub(/:/, '=>').
|
|
||||||
gsub(/\/\//, '#'));
|
|
||||||
|
|
||||||
BUILD_DIR = 'build'
|
|
||||||
|
|
||||||
task :default => [:compile, :test]
|
|
||||||
|
|
||||||
|
|
||||||
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).
|
|
||||||
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'])
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Clean Generated Files'
|
|
||||||
task :clean do
|
|
||||||
FileUtils.rm_r(BUILD_DIR, :force => true)
|
|
||||||
FileUtils.mkdir(BUILD_DIR)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Compile Scenario'
|
|
||||||
task :compile_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 'Compile JSTD Scenario Adapter'
|
|
||||||
task :compile_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 'Compile JavaScript'
|
|
||||||
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] 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')
|
|
||||||
|
|
||||||
closure_compile('angular.js')
|
|
||||||
closure_compile('angular-cookies.js')
|
|
||||||
closure_compile('angular-loader.js')
|
|
||||||
closure_compile('angular-resource.js')
|
|
||||||
closure_compile('angular-sanitize.js')
|
|
||||||
closure_compile('angular-bootstrap.js')
|
|
||||||
closure_compile('angular-bootstrap-prettify.js')
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Generate docs'
|
|
||||||
task :docs => [:init] do
|
|
||||||
`node docs/src/gen-docs.js`
|
|
||||||
rewrite_file(path_to('docs/.htaccess')) do |content|
|
|
||||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Create angular distribution'
|
|
||||||
task :package => [:clean, :compile, :docs] do
|
|
||||||
tarball = "angular-#{NG_VERSION.full}.tgz"
|
|
||||||
|
|
||||||
pkg_dir = path_to("pkg/angular-#{NG_VERSION.full}")
|
|
||||||
FileUtils.rm_r(path_to('pkg'), :force => true)
|
|
||||||
FileUtils.mkdir_p(pkg_dir)
|
|
||||||
|
|
||||||
[ path_to('angular.js'),
|
|
||||||
path_to('angular.min.js'),
|
|
||||||
path_to('angular-loader.js'),
|
|
||||||
path_to('angular-loader.min.js'),
|
|
||||||
path_to('angular-bootstrap.js'),
|
|
||||||
path_to('angular-bootstrap.min.js'),
|
|
||||||
path_to('angular-bootstrap-prettify.js'),
|
|
||||||
path_to('angular-bootstrap-prettify.min.js'),
|
|
||||||
path_to('angular-mocks.js'),
|
|
||||||
path_to('angular-cookies.js'),
|
|
||||||
path_to('angular-cookies.min.js'),
|
|
||||||
path_to('angular-resource.js'),
|
|
||||||
path_to('angular-resource.min.js'),
|
|
||||||
path_to('angular-sanitize.js'),
|
|
||||||
path_to('angular-sanitize.min.js'),
|
|
||||||
path_to('angular-scenario.js'),
|
|
||||||
path_to('jstd-scenario-adapter.js'),
|
|
||||||
path_to('jstd-scenario-adapter-config.js'),
|
|
||||||
].each do |src|
|
|
||||||
dest = src.gsub(/^.*\//, '').gsub(/((\.min)?\.js)$/, "-#{NG_VERSION.full}\\1")
|
|
||||||
FileUtils.cp(src, pkg_dir + '/' + dest)
|
|
||||||
end
|
|
||||||
|
|
||||||
FileUtils.cp_r path_to('i18n'), "#{pkg_dir}/i18n-#{NG_VERSION.full}"
|
|
||||||
FileUtils.cp_r path_to('docs'), "#{pkg_dir}/docs-#{NG_VERSION.full}"
|
|
||||||
|
|
||||||
rewrite_file("#{pkg_dir}/angular-mocks-#{NG_VERSION.full}.js") do |content|
|
|
||||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/index.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-nocache.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-nocache.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-debug.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-debug.html"
|
|
||||||
].each do |src|
|
|
||||||
rewrite_file(src) do |content|
|
|
||||||
content.gsub!(/'angular(.*)\.js/, '\'angular\1-' + NG_VERSION.full + '.js')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
rewrite_file("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html") do |content|
|
|
||||||
content.sub!('angular-scenario.js', "angular-scenario-#{NG_VERSION.full}.js")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/appcache.manifest",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest"
|
|
||||||
].each do |src|
|
|
||||||
rewrite_file(src) do |content|
|
|
||||||
content.sub!('../angular.min.js', "angular-#{NG_VERSION.full}.min.js").
|
|
||||||
sub!('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
%x(tar -czf #{path_to(tarball)} -C #{path_to('pkg')} .)
|
|
||||||
|
|
||||||
FileUtils.cp path_to(tarball), pkg_dir
|
|
||||||
FileUtils.mv pkg_dir, path_to(['pkg', NG_VERSION.full])
|
|
||||||
|
|
||||||
puts "Package created: #{path_to(tarball)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
namespace :server do
|
|
||||||
|
|
||||||
desc 'Run JsTestDriver Server'
|
|
||||||
task :start do
|
|
||||||
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'Run JavaScript tests against the server'
|
|
||||||
task :test do
|
|
||||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Run JavaScript tests'
|
|
||||||
task :test do
|
|
||||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'Lint'
|
|
||||||
task :lint do
|
|
||||||
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
|
|
||||||
print out
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
desc 'push_angularjs'
|
|
||||||
task :push_angularjs => :compile do
|
|
||||||
sh %(cat angularjs.ftp | ftp -N angularjs.netrc angularjs.org)
|
|
||||||
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 "Compiling #{filename} ..."
|
|
||||||
|
|
||||||
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
|
|
||||||
|
|
||||||
%x(java -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 "Building #{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
|
|
||||||
55
angularFiles.js
vendored
|
|
@ -79,7 +79,6 @@ angularFiles = {
|
||||||
'src/ngScenario/Describe.js',
|
'src/ngScenario/Describe.js',
|
||||||
'src/ngScenario/Future.js',
|
'src/ngScenario/Future.js',
|
||||||
'src/ngScenario/ObjectModel.js',
|
'src/ngScenario/ObjectModel.js',
|
||||||
'src/ngScenario/Describe.js',
|
|
||||||
'src/ngScenario/Runner.js',
|
'src/ngScenario/Runner.js',
|
||||||
'src/ngScenario/SpecRunner.js',
|
'src/ngScenario/SpecRunner.js',
|
||||||
'src/ngScenario/dsl.js',
|
'src/ngScenario/dsl.js',
|
||||||
|
|
@ -196,36 +195,30 @@ angularFiles = {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute only in slim-jim
|
if (exports) {
|
||||||
if (typeof JASMINE_ADAPTER !== 'undefined') {
|
exports.files = angularFiles
|
||||||
// Testacular config
|
exports.mergeFiles = function mergeFiles() {
|
||||||
var mergedFiles = [];
|
var files = [];
|
||||||
angularFiles.jstd.forEach(function(file) {
|
|
||||||
// replace @ref
|
[].splice.call(arguments, 0).forEach(function(file) {
|
||||||
var match = file.match(/^\@(.*)/);
|
if (file.match(/karma/)) {
|
||||||
if (match) {
|
files.push(file);
|
||||||
var deps = angularFiles[match[1]];
|
} else {
|
||||||
if (!deps) {
|
angularFiles[file].forEach(function(f) {
|
||||||
console.log('No dependency:' + file)
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
mergedFiles = mergedFiles.concat(deps);
|
});
|
||||||
} else {
|
|
||||||
mergedFiles.push(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
files = [JASMINE, JASMINE_ADAPTER];
|
return files;
|
||||||
|
}
|
||||||
mergedFiles.forEach(function(file){
|
|
||||||
if (/jstd|jasmine/.test(file)) return;
|
|
||||||
files.push(file);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
exclude = angularFiles.jstdExclude;
|
|
||||||
|
|
||||||
autoWatch = true;
|
|
||||||
autoWatchInterval = 1;
|
|
||||||
logLevel = LOG_INFO;
|
|
||||||
logColors = true;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
bin
|
|
||||||
cd angularjs.org/ng
|
|
||||||
put angular-debug.js js/angular-debug.js
|
|
||||||
put angular-minified.js js/angular-minified.js
|
|
||||||
put angular-scenario.js js/angular-scenario.js
|
|
||||||
49
changelog.js
|
|
@ -36,16 +36,15 @@ var parseRawCommit = function(raw) {
|
||||||
msg.breaks = [];
|
msg.breaks = [];
|
||||||
|
|
||||||
lines.forEach(function(line) {
|
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]));
|
if (match) msg.closes.push(parseInt(match[1]));
|
||||||
});
|
});
|
||||||
|
|
||||||
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
|
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
|
||||||
if (match) {
|
if (match) {
|
||||||
console.log('found!!!')
|
msg.breaking = match[1];
|
||||||
msg.breaks.push(match[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
msg.body = lines.join('\n');
|
msg.body = lines.join('\n');
|
||||||
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
|
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();
|
var components = Object.getOwnPropertyNames(section).sort();
|
||||||
|
|
||||||
if (!components.length) return;
|
if (!components.length) return;
|
||||||
|
|
@ -109,11 +109,15 @@ var printSection = function(stream, title, section) {
|
||||||
}
|
}
|
||||||
|
|
||||||
section[name].forEach(function(commit) {
|
section[name].forEach(function(commit) {
|
||||||
stream.write(util.format('%s %s (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
if (printCommitLinks) {
|
||||||
if (commit.closes.length) {
|
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||||
stream.write(', closes ' + commit.closes.map(linkToIssue).join(', '));
|
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 readGitLog = function(grep, from) {
|
||||||
var deffered = q.defer();
|
var deferred = q.defer();
|
||||||
|
|
||||||
// TODO(vojta): if it's slow, use spawn and stream it instead
|
// 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) {
|
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);
|
if (commit) commits.push(commit);
|
||||||
});
|
});
|
||||||
|
|
||||||
deffered.resolve(commits);
|
deferred.resolve(commits);
|
||||||
});
|
});
|
||||||
|
|
||||||
return deffered.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -158,29 +162,30 @@ var writeChangelog = function(stream, commits, version) {
|
||||||
section[component].push(commit);
|
section[component].push(commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
commit.breaks.forEach(function(breakMsg) {
|
if (commit.breaking) {
|
||||||
sections.breaks[EMPTY_COMPONENT].push({
|
sections.breaks[component] = sections.breaks[component] || [];
|
||||||
subject: breakMsg,
|
sections.breaks[component].push({
|
||||||
|
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
|
||||||
hash: commit.hash,
|
hash: commit.hash,
|
||||||
closes: []
|
closes: []
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||||
printSection(stream, 'Bug Fixes', sections.fix);
|
printSection(stream, 'Bug Fixes', sections.fix);
|
||||||
printSection(stream, 'Features', sections.feat);
|
printSection(stream, 'Features', sections.feat);
|
||||||
printSection(stream, 'Breaking Changes', sections.breaks);
|
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var getPreviousTag = function() {
|
var getPreviousTag = function() {
|
||||||
var deffered = q.defer();
|
var deferred = q.defer();
|
||||||
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
|
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
|
||||||
if (code) deffered.reject('Cannot get the previous tag.');
|
if (code) deferred.reject('Cannot get the previous tag.');
|
||||||
else deffered.resolve(stdout.replace('\n', ''));
|
else deferred.resolve(stdout.replace('\n', ''));
|
||||||
});
|
});
|
||||||
return deffered.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ describe('changelog.js', function() {
|
||||||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
||||||
'feat(ng-list): Allow custom separator\n' +
|
'feat(ng-list): Allow custom separator\n' +
|
||||||
'bla bla bla\n\n' +
|
'bla bla bla\n\n' +
|
||||||
'Breaks first breaking change\nsomething else\n' +
|
'BREAKING CHANGE: first breaking change\nsomething else\n' +
|
||||||
'Breaks another breaking change\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,5 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
rake compile
|
grunt minify
|
||||||
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
||||||
ls -l build/angular.min.*
|
ls -l build/angular.min.*
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@
|
||||||
@name API Reference
|
@name API Reference
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Use the API Refference documentation when you need more information about a specific feature. Check out
|
Use the API Reference documentation when you need more information about a specific feature. Check out
|
||||||
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the
|
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
|
||||||
{@link tutorial/ Tutorial}.
|
{@link tutorial/ Tutorial}.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
External resources are URLs that provide JSON data, which are then rendered with the help of
|
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
|
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
|
{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz
|
||||||
API}
|
API}
|
||||||
|
|
@ -21,12 +21,12 @@ to retrieve Buzz activity and comments.
|
||||||
{ get: {method: 'JSONP', params: {visibility: '@self'}},
|
{ get: {method: 'JSONP', params: {visibility: '@self'}},
|
||||||
replies: {method: 'JSONP', params: {visibility: '@self', comments: '@comments'}}
|
replies: {method: 'JSONP', params: {visibility: '@self', comments: '@comments'}}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
BuzzController.prototype = {
|
$scope.fetch = function() {
|
||||||
fetch: function() {
|
|
||||||
$scope.activities = $scope.Activity.get({userId:this.userId});
|
$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});
|
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
|
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.
|
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.
|
which make the common case described here very easy to implement.
|
||||||
|
|
||||||
# Assumptions
|
# Assumptions
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@name Cookbook: Form
|
@name Cookbook: Form
|
||||||
@description
|
@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
|
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.
|
allow a user to enter data.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@
|
||||||
|
|
||||||
Take a look through the source and note:
|
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
|
* The text {@link api/ng.directive:input input form control} which is
|
||||||
bound to the greeting name text.
|
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 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 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
|
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@name Cookbook
|
@name Cookbook
|
||||||
@description
|
@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
|
# Hello World
|
||||||
|
|
@ -45,7 +45,7 @@ allowing you to send links to specific screens in your app.
|
||||||
# Services
|
# Services
|
||||||
|
|
||||||
{@link api/ng Services}: Services are long lived objects in your applications that are
|
{@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
|
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
|
order of initialization. This safeguards you from the perils of global state (a common way to
|
||||||
implement long lived objects).
|
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
|
{@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
|
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
|
@name Cookbook: MVC
|
||||||
@description
|
@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
|
(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.
|
view. This makes it very easy for the controller and the view to share the model.
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ view.
|
||||||
# Things to notice
|
# Things to notice
|
||||||
|
|
||||||
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
* 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.
|
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
||||||
This makes it very testable.
|
This makes it very testable.
|
||||||
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ initialization.
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
* Place the `script` tag at the buttom of the page. Placing script tags at the end of the page
|
* Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
|
||||||
improves app load time becouse the HTML loading is not blocked by loading of the `angular.js`
|
improves app load time because the HTML loading is not blocked by loading of the `angular.js`
|
||||||
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
|
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
|
||||||
your production code to this URL, as it will expose a security hole on your site. For
|
your production code to this URL, as it will expose a security hole on your site. For
|
||||||
experimental development linking to our site is fine.
|
experimental development linking to our site is fine.
|
||||||
|
|
@ -34,12 +34,12 @@ initialization.
|
||||||
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
|
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
|
||||||
production.
|
production.
|
||||||
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
||||||
anugular to auto-bootstrap your application.
|
angular to auto-bootstrap your application.
|
||||||
|
|
||||||
<html ng-app>
|
<html ng-app>
|
||||||
|
|
||||||
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
* 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 resons, and we no longer recomend use of
|
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
|
||||||
`ng:`.)
|
`ng:`.)
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
|
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
|
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 element or attributes with custom behavior. Angular calls these behavior
|
||||||
extensions {@link api/ng.$compileProvider.directive directives}.
|
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
|
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
|
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
|
center needs to be aligned with the text's center. Simply add `align="center"` attribute to any
|
||||||
|
|
@ -37,7 +37,7 @@ process happens into two phases.
|
||||||
|
|
||||||
2. **Link:** combine the directives with a scope and produce a live view. Any changes in the
|
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
|
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
|
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
|
`ng-repeat`} clone DOM elements once for each item in collection. Having a compile and link phase
|
||||||
|
|
@ -47,9 +47,9 @@ once for each clone instance.
|
||||||
|
|
||||||
# Directive
|
# Directive
|
||||||
|
|
||||||
Directive is a behavior which should be triggered when specific HTML constructs are encountered in
|
A 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
|
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 {@link
|
well as comments. Here are some equivalent examples of invoking the {@link
|
||||||
api/ng.directive:ngBind `ng-bind`} directive.
|
api/ng.directive:ngBind `ng-bind`} directive.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -59,8 +59,8 @@ api/ng.directive:ngBind `ng-bind`} directive.
|
||||||
<!-- directive: ng-bind exp -->
|
<!-- directive: ng-bind exp -->
|
||||||
</pre>
|
</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
|
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
|
||||||
to write directives.
|
to write directives.
|
||||||
|
|
||||||
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
|
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
|
||||||
|
|
@ -107,9 +107,9 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||||
</example>
|
</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
|
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.
|
principles.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -122,7 +122,7 @@ an element.
|
||||||
<img src="img/One_Way_Data_Binding.png">
|
<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
|
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
|
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
|
||||||
expressiveness.
|
expressiveness.
|
||||||
|
|
||||||
|
|
|
||||||
467
docs/content/guide/concepts.ngdoc
Normal file
|
|
@ -0,0 +1,467 @@
|
||||||
|
@ngdoc overview
|
||||||
|
@name Conceptual Overview
|
||||||
|
@description
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
This document gives a quick overview of the main angular components and how they work together.
|
||||||
|
These are:
|
||||||
|
|
||||||
|
* {@link concepts#startup startup} - bring up hello world
|
||||||
|
* {@link concepts#runtime runtime} - overview of angular runtime
|
||||||
|
* {@link concepts#scope scope} - the glue between the view and the controller
|
||||||
|
* {@link concepts#controller controller} - application behavior
|
||||||
|
* {@link concepts#model model} - your application data
|
||||||
|
* {@link concepts#view view} - what the user sees
|
||||||
|
* {@link concepts#directives directives} - extend HTML vocabulary
|
||||||
|
* {@link concepts#filters filters} - format the data in user locale
|
||||||
|
* {@link concepts#injector injector} - assembles your application
|
||||||
|
* {@link concepts#module module} - configures the injector
|
||||||
|
* {@link concepts#angular_namespace `$`} - angular namespace
|
||||||
|
|
||||||
|
<a name="startup"></a>
|
||||||
|
# Startup
|
||||||
|
|
||||||
|
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. 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 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. 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. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||||
|
it with {@link api/ng.$rootScope $rootScope}
|
||||||
|
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
|
||||||
|
`Hello World!`
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<p ng-init=" name='World' ">Hello {{name}}!</p>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="runtime"></a>
|
||||||
|
# Runtime
|
||||||
|
|
||||||
|
<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 the browser's event loop.
|
||||||
|
|
||||||
|
1. The browser's event-loop waits for an event to arrive. An event is a user interactions, timer event,
|
||||||
|
or network event (response from a server).
|
||||||
|
2. The event's callback gets executed. This enters the JavaScript context. The callback can
|
||||||
|
modify the DOM structure.
|
||||||
|
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 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... 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 a 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
|
||||||
|
the work you wish to do in Angular execution context.
|
||||||
|
2. Angular executes the `stimulusFn()`, which typically modifies application state.
|
||||||
|
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
|
||||||
|
loop is made up of two smaller loops which process {@link
|
||||||
|
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
|
||||||
|
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
|
||||||
|
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
|
||||||
|
stabilizes, which means that the {@link api/ng.$rootScope.Scope#$evalAsync
|
||||||
|
$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'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 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
|
||||||
|
user enters text into the text field.
|
||||||
|
|
||||||
|
1. During the compilation phase:
|
||||||
|
1. the {@link api/ng.directive:ngModel ng-model} and {@link
|
||||||
|
api/ng.directive:input input} {@link guide/directive
|
||||||
|
directive} set up a `keydown` listener on the `<input>` control.
|
||||||
|
2. the {@link api/ng.$interpolate {{name}} } interpolation
|
||||||
|
sets up a {@link api/ng.$rootScope.Scope#$watch $watch} to be notified of
|
||||||
|
`name` changes.
|
||||||
|
2. During the runtime phase:
|
||||||
|
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
|
||||||
|
2. The {@link api/ng.directive:input input} directive
|
||||||
|
captures the change to the input's value and calls {@link
|
||||||
|
api/ng.$rootScope.Scope#$apply $apply}`("name = 'X';")` to update the
|
||||||
|
application model inside the Angular execution context.
|
||||||
|
3. Angular applies the `name = 'X';` to the model.
|
||||||
|
4. The {@link api/ng.$rootScope.Scope#$digest $digest} loop begins
|
||||||
|
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
|
||||||
|
on the `name` property and notifies the {@link api/ng.$interpolate
|
||||||
|
{{name}} } interpolation, which in turn updates the DOM.
|
||||||
|
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
|
||||||
|
the JavaScript execution context.
|
||||||
|
7. The browser re-renders the view with update text.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<input ng-model="name">
|
||||||
|
<p>Hello {{name}}!</p>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<a name="scope"></a>
|
||||||
|
#Scope
|
||||||
|
|
||||||
|
The {@link guide/scope scope} is responsible for detecting changes to the model section and
|
||||||
|
provides the execution context for expressions. The scopes are nested in a hierarchical structure
|
||||||
|
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
|
||||||
|
a diagram depicting the scope boundaries.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<div class="show-scope">
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="GreetCtrl">
|
||||||
|
Hello {{name}}!
|
||||||
|
</div>
|
||||||
|
<div ng-controller="ListCtrl">
|
||||||
|
<ol>
|
||||||
|
<li ng-repeat="name in names">{{name}}</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
function GreetCtrl($scope) {
|
||||||
|
$scope.name = 'World';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListCtrl($scope) {
|
||||||
|
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
<file name="style.css">
|
||||||
|
.show-scope .doc-example-live.ng-scope,
|
||||||
|
.show-scope .doc-example-live .ng-scope {
|
||||||
|
border: 1px solid red;
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="center" src="img/guide/concepts-scope.png">
|
||||||
|
|
||||||
|
|
||||||
|
<a name="controller"></a>
|
||||||
|
# Controller
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The separation of the controller and the view is important because:
|
||||||
|
|
||||||
|
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
|
||||||
|
for specifying application behavior. The controller should not contain any rendering
|
||||||
|
information (DOM references or HTML fragments).
|
||||||
|
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
|
||||||
|
specifying UI. The View should not contain any behavior.
|
||||||
|
* Since the controller is unaware of the view, there could be many views for the same
|
||||||
|
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
|
||||||
|
and testability.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="MyCtrl">
|
||||||
|
Hello {{name}}!
|
||||||
|
<button ng-click="action()">
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
function MyCtrl($scope) {
|
||||||
|
$scope.action = function() {
|
||||||
|
$scope.name = 'OK';
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.name = 'World';
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="model"></a>
|
||||||
|
# Model
|
||||||
|
|
||||||
|
<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 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.
|
||||||
|
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="view"></a>
|
||||||
|
# View
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
||||||
|
|
||||||
|
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 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
|
||||||
|
edited by an HTML editor. The template string is then parsed by the template engine, and
|
||||||
|
merged with the data. The result of the merge is an HTML string. The HTML string is then
|
||||||
|
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
|
||||||
|
When the model changes the whole process needs to be repeated. The granularity of the template
|
||||||
|
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 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
|
||||||
|
the single source-of-truth for your view.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
||||||
|
<input ng-model="list" ng-list> <br>
|
||||||
|
<input ng-model="list" ng-list> <br>
|
||||||
|
<pre>list={{list}}</pre> <br>
|
||||||
|
<ol>
|
||||||
|
<li ng-repeat="item in list">
|
||||||
|
{{item}}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="directives"></a>
|
||||||
|
# Directives
|
||||||
|
|
||||||
|
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
|
||||||
|
element name, or a class name. 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.
|
||||||
|
|
||||||
|
<example module="directive">
|
||||||
|
<file name="script.js">
|
||||||
|
angular.module('directive', []).directive('contenteditable', function() {
|
||||||
|
return {
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function(scope, elm, attrs, ctrl) {
|
||||||
|
// view -> model
|
||||||
|
elm.bind('blur', function() {
|
||||||
|
scope.$apply(function() {
|
||||||
|
ctrl.$setViewValue(elm.html());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// model -> view
|
||||||
|
ctrl.$render = function(value) {
|
||||||
|
elm.html(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// load init value from DOM
|
||||||
|
ctrl.$setViewValue(elm.html());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</file>
|
||||||
|
<file name="index.html">
|
||||||
|
<div contentEditable="true" ng-model="content">Edit Me</div>
|
||||||
|
<pre>model = {{content}}</pre>
|
||||||
|
</file>
|
||||||
|
<file name="style.css">
|
||||||
|
div[contentEditable] {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #D0D0D0;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<a name="filters"></a>
|
||||||
|
# Filters
|
||||||
|
|
||||||
|
{@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).
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
||||||
|
Number formatting: {{ 1234567890 | number }} <br>
|
||||||
|
array filtering <input ng-model="predicate">
|
||||||
|
{{ list | filter:predicate | json }}
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="module"></a>
|
||||||
|
<a name="injector"></a>
|
||||||
|
# Modules and the Injector
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||||
|
|
||||||
|
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
|
||||||
|
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
|
||||||
|
object name result in the same instance. If the object does not exist, then the {@link
|
||||||
|
api/AUTO.$injector injector} asks the instance factory to create a new instance.
|
||||||
|
|
||||||
|
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
|
||||||
|
as a {@link api/AUTO.$provide provider}.
|
||||||
|
|
||||||
|
<div class='clear'></div>
|
||||||
|
<pre>
|
||||||
|
// Create a module
|
||||||
|
var myModule = angular.module('myModule', [])
|
||||||
|
|
||||||
|
// Configure the injector
|
||||||
|
myModule.factory('serviceA', function() {
|
||||||
|
return {
|
||||||
|
// instead of {}, put your object creation here
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// create an injector and configure it from 'myModule'
|
||||||
|
var $injector = angular.injector(['myModule']);
|
||||||
|
|
||||||
|
// retrieve an object from the injector by name
|
||||||
|
var serviceA = $injector.get('serviceA');
|
||||||
|
|
||||||
|
// always true because of instance cache
|
||||||
|
$injector.get('serviceA') === $injector.get('serviceA');
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
|
||||||
|
used to {@link api/AUTO.$injector#invoke call} methods and {@link
|
||||||
|
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
|
||||||
|
allows the methods and types to ask for their dependencies instead of having to look for them.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// You write functions such as this one.
|
||||||
|
function doSomething(serviceA, serviceB) {
|
||||||
|
// do something here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angular provides the injector for your application
|
||||||
|
var $injector = ...;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// the old-school way of getting dependencies.
|
||||||
|
var serviceA = $injector.get('serviceA');
|
||||||
|
var serviceB = $injector.get('serviceB');
|
||||||
|
|
||||||
|
// now call the function
|
||||||
|
doSomething(serviceA, serviceB);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// the cool way of getting dependencies.
|
||||||
|
// the $injector will supply the arguments to the function automatically
|
||||||
|
$injector.invoke(doSomething); // This is how the framework calls your functions
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Notice that the only thing you needed to write was the function, and list the dependencies in the
|
||||||
|
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
|
||||||
|
{@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.
|
||||||
|
|
||||||
|
<example module="timeExampleModule">
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="ClockCtrl">
|
||||||
|
Current time is: {{ time.now }}
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
angular.module('timeExampleModule', []).
|
||||||
|
// Declare new object called time,
|
||||||
|
// which will be available for injection
|
||||||
|
factory('time', function($timeout) {
|
||||||
|
var time = {};
|
||||||
|
|
||||||
|
(function tick() {
|
||||||
|
time.now = new Date().toString();
|
||||||
|
$timeout(tick, 1000);
|
||||||
|
})();
|
||||||
|
return time;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notice that you can simply ask for time
|
||||||
|
// and it will be provided. No need to look for it.
|
||||||
|
function ClockCtrl($scope, time) {
|
||||||
|
$scope.time = time;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="angular_namespace"></a>
|
||||||
|
# Angular Namespace
|
||||||
|
|
||||||
|
To prevent accidental name collision, Angular prefixes names of objects which could potentially
|
||||||
|
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
|
||||||
|
with Angular code.
|
||||||
|
|
@ -11,7 +11,7 @@ that will help you verify the health of your Angular application.
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
You will write scenario tests in JavaScript, which describe how your application should behave,
|
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
|
(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
|
**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
|
(such as navigate to a page or click on a button), and expectations tell the Runner to assert
|
||||||
|
|
@ -122,7 +122,7 @@ Returns the current value of an input field with the given `name`.
|
||||||
|
|
||||||
## repeater(selector, label).count()
|
## repeater(selector, label).count()
|
||||||
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
|
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
|
||||||
used for test ouput.
|
used for test output.
|
||||||
|
|
||||||
## repeater(selector, label).row(index)
|
## repeater(selector, label).row(index)
|
||||||
Returns an array with the bindings in the row at the given `index` in the repeater matching the
|
Returns an array with the bindings in the row at the given `index` in the repeater matching the
|
||||||
|
|
@ -175,4 +175,4 @@ 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
|
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
|
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
|
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.
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
|
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
|
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
||||||
building client-side web applications.
|
building client-side web applications.
|
||||||
|
|
||||||
The MVC pattern greatly summarized:
|
The MVC pattern summarized:
|
||||||
|
|
||||||
* Separate applications into distinct presentation, data, and logic components
|
* Separate applications into distinct presentation, data, and logic components
|
||||||
* Encourage loose coupling between these components
|
* Encourage loose coupling between these components
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
||||||
@description
|
@description
|
||||||
|
|
||||||
In angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
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
|
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
|
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
|
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.
|
controller with the new scope and to augment its behavior.
|
||||||
|
|
||||||
Use controllers to:
|
Use controllers to:
|
||||||
|
|
@ -15,10 +15,10 @@ Use controllers to:
|
||||||
|
|
||||||
# Setting up the initial state of a scope object
|
# 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
|
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
|
creates instances of the controller type (by invoking the `new` operator on the controller
|
||||||
constructor). Constructors are always applied to an existing scope object.
|
constructor). Constructors are always applied to an existing scope object.
|
||||||
|
|
||||||
|
|
@ -30,9 +30,23 @@ function GreetingCtrl($scope) {
|
||||||
|
|
||||||
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
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:
|
||||||
|
|
||||||
|
var myApp = angular.module('myApp',[]);
|
||||||
|
|
||||||
|
myApp.controller('GreetingCtrl', ['$scope', function(scope) {
|
||||||
|
scope.greeting = 'Hola!';
|
||||||
|
}]);
|
||||||
|
|
||||||
|
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
|
# 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.
|
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
|
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
||||||
|
|
@ -55,14 +69,14 @@ Do not use controllers for:
|
||||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
- 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.
|
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
|
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
|
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||||
{@link guide/directive directives}.
|
{@link guide/directive directives}.
|
||||||
- Input formatting — Use {@link forms angular form controls} instead.
|
- Input formatting — Use {@link forms angular form controls} instead.
|
||||||
- Output filtering — Use {@link dev_guide.templates.filters angular filters} 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
|
- To run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
|
||||||
services} instead.
|
services} instead.
|
||||||
- Instantiate or manage the life-cycle of other components (for example, to create service
|
- To instantiate or manage the life-cycle of other components (for example, to create service
|
||||||
instances).
|
instances).
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -157,15 +171,16 @@ input box) in the second button.
|
||||||
|
|
||||||
## Controller Inheritance Example
|
## 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:
|
have a look at an example:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<body ng-controller="MainCtrl">
|
<body ng-controller="MainCtrl">
|
||||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||||
<div ng-controller="ChildCtrl">
|
<div ng-controller="ChildCtrl">
|
||||||
<p>Good {{timeOfDay}}, {{name}}!</p>
|
<p>Good {{timeOfDay}}, {{name}}!</p>
|
||||||
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
function MainCtrl($scope) {
|
function MainCtrl($scope) {
|
||||||
|
|
@ -197,7 +212,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.
|
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,
|
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.
|
are applied to the scope object.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -241,8 +256,8 @@ describe('myController function', function() {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
If you need to test a nested controller one needs to create the same scope hierarchy
|
If you need to test a nested controller you need to create the same scope hierarchy
|
||||||
in your test as exist in the DOM.
|
in your test that exists in the DOM.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
describe('state', function() {
|
describe('state', function() {
|
||||||
|
|
@ -253,7 +268,7 @@ describe('state', function() {
|
||||||
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
||||||
childScope = mainScope.$new();
|
childScope = mainScope.$new();
|
||||||
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
||||||
babyScope = $rootScope.$new();
|
babyScope = childCtrl.$new();
|
||||||
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
||||||
@description
|
@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
|
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).
|
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
|
scope Scope} object. The name of the property is the model identifier and the value is
|
||||||
any JavaScript object (including arrays and primitives).
|
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
|
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
|
referenced by an Angular scope as a property of that scope object. This property reference can be
|
||||||
created explicitly or implicitly.
|
created explicitly or implicitly.
|
||||||
|
|
||||||
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
||||||
|
|
@ -52,11 +52,11 @@ cloud".
|
||||||
The code above creates one child scope for each item in the "phones" array and creates a "phone"
|
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.
|
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.
|
garbage collection.
|
||||||
|
|
||||||
The following illustration shows a simple data model created implicitly from a simple template:
|
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
|
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
||||||
@description
|
@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.
|
the DOM based on information in the template, controller and model.
|
||||||
|
|
||||||
<img src="img/guide/about_view_final.png">
|
<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
|
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:
|
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
|
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
|
||||||
controller function.
|
controller function.
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
|
||||||
|
|
||||||
## Comparing $location to window.location
|
## Comparing $location to window.location
|
||||||
|
|
||||||
<table>
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="empty-corner-lt"></td>
|
<th class="empty-corner-lt"></th>
|
||||||
<td>window.location</td>
|
<th>window.location</th>
|
||||||
<td>$location service</td>
|
<th>$location service</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -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.
|
the current URL in the browser.
|
||||||
|
|
||||||
## What does it not do?
|
## 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`.
|
changing the URL, use the lower-level API, `$window.location.href`.
|
||||||
|
|
||||||
|
|
||||||
# General overview of the API
|
# General overview of the API
|
||||||
|
|
||||||
The `$location` service can behave differently, depending on the configuration that was provided to
|
The `$location` service can behave differently, depending on the configuration that was provided to
|
||||||
|
|
@ -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();
|
// or you can chain these as: $location.path('/someNewPath').replace();
|
||||||
</pre>
|
</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`
|
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
|
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
|
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
|
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,
|
resets the flag set by `replace()` method and future mutations will create new history records,
|
||||||
unless `replace()` is called again.
|
unless `replace()` is called again.
|
||||||
|
|
||||||
|
|
@ -165,13 +164,13 @@ facilitate the browser URL change and history management.
|
||||||
|
|
||||||
<img src="img/guide/hashbang_vs_regular_url.jpg">
|
<img src="img/guide/hashbang_vs_regular_url.jpg">
|
||||||
|
|
||||||
<table>
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="empty-corner-lt"></td>
|
<th class="empty-corner-lt"></th>
|
||||||
<td>Hashbang mode</td>
|
<th>Hashbang mode</th>
|
||||||
<td>HTML5 mode</td>
|
<th>HTML5 mode</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -212,7 +211,7 @@ In this mode, `$location` uses Hashbang URLs in all browsers.
|
||||||
<pre>
|
<pre>
|
||||||
it('should show example', inject(
|
it('should show example', inject(
|
||||||
function($locationProvider) {
|
function($locationProvider) {
|
||||||
$locationProvider.html5mode = false;
|
$locationProvider.html5Mode(false);
|
||||||
$locationProvider.hashPrefix = '!';
|
$locationProvider.hashPrefix = '!';
|
||||||
},
|
},
|
||||||
function($location) {
|
function($location) {
|
||||||
|
|
@ -261,7 +260,7 @@ having to worry about whether the browser displaying your app supports the histo
|
||||||
<pre>
|
<pre>
|
||||||
it('should show example', inject(
|
it('should show example', inject(
|
||||||
function($locationProvider) {
|
function($locationProvider) {
|
||||||
$locationProvider.html5mode = true;
|
$locationProvider.html5Mode(true);
|
||||||
$locationProvider.hashPrefix = '!';
|
$locationProvider.hashPrefix = '!';
|
||||||
},
|
},
|
||||||
function($location) {
|
function($location) {
|
||||||
|
|
@ -304,7 +303,7 @@ history API or not; the `$location` service makes this transparent to you.
|
||||||
|
|
||||||
### Html link rewriting
|
### 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>`
|
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||||
|
|
||||||
When a user clicks on this link,
|
When a user clicks on this link,
|
||||||
|
|
@ -331,11 +330,11 @@ to entry point of your application (e.g. index.html)
|
||||||
|
|
||||||
### Crawling your app
|
### Crawling your app
|
||||||
|
|
||||||
If you want your AJAX application to be indexed by web crawlers, you rill need to add the following
|
If you want your AJAX application to be indexed by web crawlers, you will need to add the following
|
||||||
meta tag to the HEAD section of your document:
|
meta tag to the HEAD section of your document:
|
||||||
<pre><meta name="fragment" content="!" /></pre>
|
<pre><meta name="fragment" content="!" /></pre>
|
||||||
|
|
||||||
This statement causes a crawler to request links with empty `_escaped_fragment_` parameter so that
|
This statement causes a crawler to request links with an empty `_escaped_fragment_` parameter so that
|
||||||
your server can recognize the crawler and serve it HTML snapshots. For more information about this
|
your server can recognize the crawler and serve it HTML snapshots. For more information about this
|
||||||
technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX
|
technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX
|
||||||
Applications Crawlable}.
|
Applications Crawlable}.
|
||||||
|
|
@ -543,69 +542,73 @@ then uses the information it obtains to compose hashbang URLs (such as
|
||||||
|
|
||||||
## Changes to your code
|
## Changes to your code
|
||||||
|
|
||||||
<table>
|
<table class="table">
|
||||||
<tr class="head">
|
<thead>
|
||||||
<td>Navigation inside the app</td>
|
<tr class="head">
|
||||||
<td>Change to</td>
|
<th>Navigation inside the app</th>
|
||||||
</tr>
|
<th>Change to</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
<tr>
|
<tbody>
|
||||||
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
|
<tr>
|
||||||
|
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
|
||||||
/>$location.updateHash(value)</td>
|
/>$location.updateHash(value)</td>
|
||||||
<td>$location.path(path).search(search)</td>
|
<td>$location.path(path).search(search)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.hashPath = path</td>
|
<td>$location.hashPath = path</td>
|
||||||
<td>$location.path(path)</td>
|
<td>$location.path(path)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.hashSearch = search</td>
|
<td>$location.hashSearch = search</td>
|
||||||
<td>$location.search(search)</td>
|
<td>$location.search(search)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="head">
|
<tr class="head">
|
||||||
<td>Navigation outside the app</td>
|
<td>Navigation outside the app</td>
|
||||||
<td>Use lower level API</td>
|
<td>Use lower level API</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.href = value<br />$location.update(value)</td>
|
<td>$location.href = value<br />$location.update(value)</td>
|
||||||
<td>$window.location.href = value</td>
|
<td>$window.location.href = value</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location[protocol | host | port | path | search]</td>
|
<td>$location[protocol | host | port | path | search]</td>
|
||||||
<td>$window.location[protocol | host | port | path | search]</td>
|
<td>$window.location[protocol | host | port | path | search]</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="head">
|
<tr class="head">
|
||||||
<td>Read access</td>
|
<td>Read access</td>
|
||||||
<td>Change to</td>
|
<td>Change to</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.hashPath</td>
|
<td>$location.hashPath</td>
|
||||||
<td>$location.path()</td>
|
<td>$location.path()</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.hashSearch</td>
|
<td>$location.hashSearch</td>
|
||||||
<td>$location.search()</td>
|
<td>$location.search()</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
|
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
|
||||||
/>$location.hash</td>
|
/>$location.hash</td>
|
||||||
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
|
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
|
||||||
/>$location.path() + $location.search()</td>
|
/>$location.path() + $location.search()</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>$location.path<br />$location.search</td>
|
<td>$location.path<br />$location.search</td>
|
||||||
<td>$window.location.path<br />$window.location.search</td>
|
<td>$window.location.path<br />$window.location.search</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## Two-way binding to $location
|
## Two-way binding to $location
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
@name Developer Guide: Angular Services: Creating Services
|
@name Developer Guide: Angular Services: Creating Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
While angular offers several useful services, for any nontrivial application you'll find it useful
|
While Angular offers several useful services, for any nontrivial application you'll find it useful
|
||||||
to write your own custom services. To do this you begin by registering a service factory function
|
to write your own custom services. To do this you begin by registering a service factory function
|
||||||
with a module either via the {@link api/angular.module Module#factory api} or directly
|
with a module either via the {@link api/angular.module Module#factory api} or directly
|
||||||
via the {@link api/AUTO.$provide $provide} api inside of module config function.
|
via the {@link api/AUTO.$provide $provide} api inside of module config function.
|
||||||
|
|
||||||
All angular services participate in {@link di dependency injection (DI)} by registering
|
All Angular services participate in {@link di dependency injection (DI)} by registering
|
||||||
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||||
dependencies which need to be provided for the factory function of the registered service. The
|
dependencies which need to be provided for the factory function of the registered service. The
|
||||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||||
|
|
@ -48,9 +48,9 @@ create this instance when called.
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
Services can not only be depended upon, but also have its own dependencies. These can be specified
|
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 the DI
|
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
|
||||||
in Angular and the use of array notation and $inject property to make DI annotation
|
in Angular and the use of array notation and the $inject property to make DI annotation
|
||||||
minification-proof.
|
minification-proof.
|
||||||
|
|
||||||
Following is an example of a very simple service. This service depends on the `$window` service
|
Following is an example of a very simple service. This service depends on the `$window` service
|
||||||
|
|
@ -76,17 +76,17 @@ angular.module('myModule', [], function($provide) {
|
||||||
|
|
||||||
# Instantiating Angular Services
|
# Instantiating Angular Services
|
||||||
|
|
||||||
All services in Angular are instantiates services lazily, this means that a service will be created
|
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.
|
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.
|
indirectly by the application.
|
||||||
|
|
||||||
|
|
||||||
# Services as singletons
|
# Services as singletons
|
||||||
|
|
||||||
Lastly, it is important to realize that all angular services are application singletons. This means
|
Lastly, it is important to realize that all Angular services are application singletons. This means
|
||||||
that there is only one instance of a given service per injector. Since angular is lethally allergic
|
that there is only one instance of a given service per injector. Since Angular is lethally allergic
|
||||||
to the global state, it is possible to create multiple injectors, each with its own instance of a
|
to global state, it is possible to create multiple injectors, each with its own instance of a
|
||||||
given service, but that is rarely needed, except in tests where this property is crucially
|
given service, but that is rarely needed, except in tests where this property is crucially
|
||||||
important.
|
important.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ function myModuleCfgFn($provide) {
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
Here is an example of two services that depend on each other, as well as on other services that are
|
Here is an example of two services, one of which depends on the other and both
|
||||||
provided by Angular's web framework:
|
of which depend on other services that are provided by the Angular framework:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
@name Developer Guide: Angular Services
|
@name Developer Guide: Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Services are a feature that angular brings to client-side web apps from the server side, where
|
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
|
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
|
objects that are wired together using {@link di dependency injection (DI)}.
|
||||||
most often used with {@link di dependency injection}, also a key feature of angular apps.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@name Developer Guide: Angular Services: Testing Angular Services
|
@name Developer Guide: Angular Services: Testing Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Following is a unit test for the service in the example in {@link
|
The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link
|
||||||
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
|
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
|
||||||
spy (mock) instead of a real browser alert.
|
spy (mock) instead of a real browser alert.
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ it('should clear messages after alert', function() {
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
{@link api/ng.$http $http service} that provides low level access to the browser's
|
||||||
`XMLHttpRequest` object.
|
`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
|
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.
|
dependencies, and provision of dependencies to factory functions as requested.
|
||||||
|
|
||||||
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
|
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'];
|
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
|
variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
|
||||||
above). You can also create your own custom services.
|
above). You can also create your own custom services.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
||||||
|
|
||||||
* `ng-invalid`, `ng-valid`
|
* `ng-invalid`, `ng-valid`
|
||||||
- **Usage:** angular applies this class to an input widget element if that element's input does
|
- **Usage:** angular applies this class to an input widget element if that element's input does
|
||||||
notpass validation. (see {@link api/ng.directive:input input} directive).
|
not pass validation. (see {@link api/ng.directive:input input} directive).
|
||||||
|
|
||||||
* `ng-pristine`, `ng-dirty`
|
* `ng-pristine`, `ng-dirty`
|
||||||
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
|
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
@name Developer Guide: Templates: Data Binding in Angular
|
@name Developer Guide: Templates: Data Binding in Angular
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Data-binding in angular web apps is the automatic syncing of data between the model and view
|
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
|
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.
|
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.
|
When the model changes, the view reflects the change, and vice versa.
|
||||||
|
|
||||||
|
|
@ -19,12 +19,12 @@ to write code that constantly syncs the view with the model and the model with t
|
||||||
## Data Binding in Angular Templates
|
## Data Binding in Angular Templates
|
||||||
|
|
||||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
<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
|
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
|
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
|
say live because any changes to the view are immediately reflected in the model, and any changes in
|
||||||
the model are propagated to the view. This makes the model always the single-source-of-truth for
|
the model are propagated to the view. This makes the model always the single-source-of-truth for
|
||||||
the application state, greatly simplifying the programing model for the developer. You can think of
|
the application state, greatly simplifying the programming model for the developer. You can think of
|
||||||
the view as simply an instant projection of your model.
|
the view as simply an instant projection of your model.
|
||||||
|
|
||||||
Because the view is just a projection of the model, the controller is completely separated from the
|
Because the view is just a projection of the model, the controller is completely separated from the
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
@name Developer Guide: Templates: Understanding Angular Filters
|
@name Developer Guide: Templates: Understanding Angular Filters
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Angular filters format data for display to the user. In addition to formatting data, filters can
|
Angular filters format data for display to the user.
|
||||||
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
|
|
||||||
to filtered output.
|
|
||||||
|
|
||||||
For example, you might have a data object that needs to be formatted according to the locale before
|
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:
|
displaying it to the user. You can pass expressions through a chain of filters like this:
|
||||||
|
|
@ -14,9 +12,6 @@ displaying it to the user. You can pass expressions through a chain of filters l
|
||||||
The expression evaluator simply passes the value of name to
|
The expression evaluator simply passes the value of name to
|
||||||
{@link api/ng.filter:uppercase uppercase filter}.
|
{@link api/ng.filter:uppercase uppercase filter}.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
@name Developer Guide: Understanding Angular Templates
|
@name Developer Guide: Understanding Angular Templates
|
||||||
@description
|
@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,
|
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
|
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.
|
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
|
* {@link guide/directive Directive} — An attribute or element that
|
||||||
augments an existing DOM element or represents a reusable DOM component - a widget.
|
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
|
Note: In addition to declaring the elements above in templates, you can also access these elements
|
||||||
in JavaScript code.
|
in JavaScript code.
|
||||||
|
|
||||||
The following code snippet shows a simple angular template made up of standard HTML tags along with
|
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
|
Angular {@link guide/directive directives} and curly-brace bindings
|
||||||
with {@link expression expressions}:
|
with {@link expression expressions}:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
|
||||||
|
|
@ -5,35 +5,47 @@
|
||||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
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
|
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
|
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
|
# It is all about NOT mixing concerns
|
||||||
|
|
||||||
Unit testing as the name implies is about testing individual units of code. Unit tests try to
|
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
|
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 it.
|
in the right order?"
|
||||||
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
|
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
|
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
|
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.
|
||||||
provide dependency injection for your XHR (which you can mock out) and we crated abstraction which
|
|
||||||
|
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,
|
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,
|
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
|
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
|
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
|
DOM in the right way.
|
||||||
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.
|
|
||||||
|
|
||||||
## 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:
|
There are several ways in which you can get a hold of a dependency:
|
||||||
1. You could create it using the `new` operator.
|
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
|
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)
|
the registry? Most likely by looking it up in a well known place. See #2)
|
||||||
4. You could expect that the it be handed to you.
|
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
|
### Using the `new` operator
|
||||||
|
|
||||||
|
|
@ -52,10 +64,10 @@ function MyClass() {
|
||||||
}
|
}
|
||||||
</pre>
|
</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
|
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
|
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 is outside the scope of this document.
|
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:
|
The class above is hard to test since we have to resort to monkey patching:
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -69,7 +81,7 @@ XHR = oldXHR; // if you forget this bad things will happen
|
||||||
|
|
||||||
|
|
||||||
### Global look-up:
|
### 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>
|
<pre>
|
||||||
function MyClass() {
|
function MyClass() {
|
||||||
|
|
@ -83,7 +95,7 @@ function MyClass() {
|
||||||
}
|
}
|
||||||
</pre>
|
</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
|
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 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
|
order to replace it with call to a mock method. For further explanation why this is bad see: {@link
|
||||||
|
|
@ -119,7 +131,7 @@ function MyClass() {
|
||||||
}
|
}
|
||||||
</pre>
|
</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
|
* `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
|
* 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).
|
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.
|
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.
|
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
@ -173,7 +185,7 @@ for your application is mixed in with DOM manipulation, it will be hard to test
|
||||||
below:
|
below:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function PasswordController() {
|
function PasswordCtrl() {
|
||||||
// get references to DOM elements
|
// get references to DOM elements
|
||||||
var msg = $('.ex1 span');
|
var msg = $('.ex1 span');
|
||||||
var input = $('.ex1 input');
|
var input = $('.ex1 input');
|
||||||
|
|
@ -197,7 +209,7 @@ function PasswordController() {
|
||||||
}
|
}
|
||||||
</pre>
|
</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:
|
of DOM present when the code executes. The test would look like this:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -207,7 +219,7 @@ $('body').html('<div class="ex1">')
|
||||||
.find('div')
|
.find('div')
|
||||||
.append(input)
|
.append(input)
|
||||||
.append(span);
|
.append(span);
|
||||||
var pc = new PasswordController();
|
var pc = new PasswordCtrl();
|
||||||
input.val('abc');
|
input.val('abc');
|
||||||
pc.grade();
|
pc.grade();
|
||||||
expect(span.text()).toEqual('weak');
|
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:
|
a much easier testability story as can be seen in this example:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
function PasswordCntrl($scope) {
|
function PasswordCtrl($scope) {
|
||||||
$scope.password = '';
|
$scope.password = '';
|
||||||
$scope.grade = function() {
|
$scope.grade = function() {
|
||||||
var size = $scope.password.length;
|
var size = $scope.password.length;
|
||||||
|
|
@ -233,19 +245,18 @@ function PasswordCntrl($scope) {
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
and the tests is straight forward
|
and the test is straight forward
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var pc = new PasswordController();
|
var pc = new PasswordCtrl();
|
||||||
pc.password('abc');
|
pc.password('abc');
|
||||||
pc.grade();
|
pc.grade();
|
||||||
expect(span.strength).toEqual('weak');
|
expect(pc.strength).toEqual('weak');
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
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.
|
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||||
|
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
{@link api/ng.$filter Filters} are functions which transform the data into user readable
|
{@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
|
format. They are important because they remove the formatting responsibility from the application
|
||||||
|
|
@ -266,16 +277,20 @@ expect(length('abc')).toEqual(3);
|
||||||
## Directives
|
## Directives
|
||||||
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
||||||
|
|
||||||
|
|
||||||
## Mocks
|
## Mocks
|
||||||
oue
|
oue
|
||||||
|
|
||||||
## Global State Isolation
|
## Global State Isolation
|
||||||
oue
|
oue
|
||||||
|
|
||||||
# Preferred way of Testing
|
# Preferred way of Testing
|
||||||
uo
|
uo
|
||||||
|
|
||||||
## JavaScriptTestDriver
|
## JavaScriptTestDriver
|
||||||
ou
|
ou
|
||||||
|
|
||||||
## Jasmine
|
## Jasmine
|
||||||
ou
|
ou
|
||||||
|
|
||||||
## Sample project
|
## Sample project
|
||||||
uoe
|
uoe
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ is simply handed the `greeter` at runtime.
|
||||||
This is desirable, but it puts the responsibility of getting hold of the dependency onto the
|
This is desirable, but it puts the responsibility of getting hold of the dependency onto the
|
||||||
code responsible for the construction of `SomeClass`.
|
code responsible for the construction of `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
|
api/angular.injector injector}. The injector is a service locator that is responsible for
|
||||||
construction and lookup of dependencies.
|
construction and lookup of dependencies.
|
||||||
|
|
||||||
|
|
@ -67,11 +67,11 @@ Here is an example of using the injector service.
|
||||||
$window.alert(text);
|
$window.alert(text);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}).
|
});
|
||||||
|
|
||||||
// New injector is created from the module.
|
// New injector is created from the module.
|
||||||
// (This is usually done automatically by angular bootstrap)
|
// (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
|
// Request any dependency from the injector
|
||||||
var greeter = injector.get('greeter');
|
var greeter = injector.get('greeter');
|
||||||
|
|
@ -92,7 +92,7 @@ dependency lookup responsibility to the injector by declaring the dependencies a
|
||||||
// And this controller definition
|
// And this controller definition
|
||||||
function MyController($scope, greeter) {
|
function MyController($scope, greeter) {
|
||||||
$scope.sayHello = function() {
|
$scope.sayHello = function() {
|
||||||
greeter('Hello World');
|
greeter.greet('Hello World');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ deal with the injector. This setup does not break the Law of Demeter.
|
||||||
|
|
||||||
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
|
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
|
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
|
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
|
the function. Below are three equivalent ways of annotating your code with service name
|
||||||
|
|
@ -165,7 +165,7 @@ For example:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Results in code bloat do to the need of temporary variable:
|
Results in code bloat due to the need of temporary variable:
|
||||||
<pre>
|
<pre>
|
||||||
var greeterFactory = function(renamed$window) {
|
var greeterFactory = function(renamed$window) {
|
||||||
...;
|
...;
|
||||||
|
|
@ -186,36 +186,34 @@ For this reason the third annotation style is provided as well.
|
||||||
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||||
where injection is supported.
|
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 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
|
Controllers are classes which are responsible for application behavior. The recommended way of
|
||||||
declaring controllers is:
|
declaring controllers is:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
var MyController = function(dep1, dep2) {
|
var MyController = function($scope, dep1, dep2) {
|
||||||
...
|
|
||||||
}
|
|
||||||
MyController.$inject = ['dep1', 'dep2'];
|
|
||||||
|
|
||||||
MyController.prototype.aMethod = function() {
|
|
||||||
...
|
...
|
||||||
|
$scope.aMethod = function() {
|
||||||
|
...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
MyController.$inject = ['$scope', 'dep1', 'dep2'];
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Factory methods
|
## Factory methods
|
||||||
|
|
||||||
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
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:
|
of declaring factories is:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
angualar.module('myModule', []).
|
angular.module('myModule', []).
|
||||||
config(['depProvider', function(depProvider){
|
config(['depProvider', function(depProvider){
|
||||||
...
|
...
|
||||||
}]).
|
}]).
|
||||||
|
|
@ -231,4 +229,4 @@ of declaring factories is:
|
||||||
run(['depService', function(depService) {
|
run(['depService', function(depService) {
|
||||||
...
|
...
|
||||||
}]);
|
}]);
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ can be extended such that HTML can be turned into a declarative domain specific
|
||||||
|
|
||||||
# Invoking directives from HTML
|
# Invoking directives from HTML
|
||||||
|
|
||||||
Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating
|
Directives have camel cased names such as `ngBind`. The directive can be invoked by translating
|
||||||
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
|
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
|
||||||
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
|
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
|
||||||
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
|
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
|
||||||
|
|
@ -39,11 +39,11 @@ the following example.
|
||||||
</script>
|
</script>
|
||||||
<div ng-controller="Ctrl1">
|
<div ng-controller="Ctrl1">
|
||||||
Hello <input ng-model='name'> <hr/>
|
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 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 data-ng-bind="name"> <span data-ng-bind="name"></span> <br/>
|
||||||
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
<doc:scenario>
|
||||||
|
|
@ -63,7 +63,7 @@ api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is sh
|
||||||
here:
|
here:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
|
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
# Compilation process, and directive matching
|
# Compilation process, and directive matching
|
||||||
|
|
@ -74,7 +74,7 @@ Compilation of HTML happens in three phases:
|
||||||
realize because the templates must be parsable HTML. This is in contrast to most templating
|
realize because the templates must be parsable HTML. This is in contrast to most templating
|
||||||
systems that operate on strings, rather than on DOM elements.
|
systems that operate on strings, rather than on DOM elements.
|
||||||
|
|
||||||
2. The compilation of the DOM is performed by the call to {@link api/ng.$compile
|
2. The compilation of the DOM is performed by the call to the {@link api/ng.$compile
|
||||||
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
|
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
|
||||||
it is added to the list of directives associated with the given DOM element. Once all directives
|
it is added to the list of directives associated with the given DOM element. Once all directives
|
||||||
for a given DOM element have been identified they are sorted by priority and their `compile()`
|
for a given DOM element have been identified they are sorted by priority and their `compile()`
|
||||||
|
|
@ -95,7 +95,7 @@ Compilation of HTML happens in three phases:
|
||||||
var $compile = ...; // injected into your code
|
var $compile = ...; // injected into your code
|
||||||
var scope = ...;
|
var scope = ...;
|
||||||
|
|
||||||
var html = '<div ng-bind='exp'></div>';
|
var html = '<div ng-bind="exp"></div>';
|
||||||
|
|
||||||
// Step 1: parse HTML into DOM element
|
// Step 1: parse HTML into DOM element
|
||||||
var template = angular.element(html);
|
var template = angular.element(html);
|
||||||
|
|
@ -109,8 +109,8 @@ Compilation of HTML happens in three phases:
|
||||||
|
|
||||||
## Reasons behind the compile/link separation
|
## Reasons behind the compile/link separation
|
||||||
|
|
||||||
At this point you may wonder why is the compile process broken down to a compile and link phase.
|
At this point you may wonder why the compile process is broken down to a compile and link phase.
|
||||||
To understand this, lets look at a real world example with repeater:
|
To understand this, let's look at a real world example with a repeater:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
Hello {{user}}, you have these actions:
|
Hello {{user}}, you have these actions:
|
||||||
|
|
@ -125,7 +125,7 @@ The short answer is that compile and link separation is needed any time a change
|
||||||
a change in DOM structure such as in repeaters.
|
a change in DOM structure such as in repeaters.
|
||||||
|
|
||||||
When the above example is compiled, the compiler visits every node and looks for directives. The
|
When the above example is compiled, the compiler visits every node and looks for directives. The
|
||||||
`{{user}}` is an example of {@link api/ng.$interpolate interpolation} directive. {@link
|
`{{user}}` is an example of an {@link api/ng.$interpolate interpolation} directive. {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
|
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
|
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
|
||||||
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
|
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
|
||||||
|
|
@ -138,16 +138,16 @@ But compiling on every `li` element clone would be slow, since the compilation r
|
||||||
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
||||||
repeater which needs to unroll 100 items we would quickly run into performance problems.
|
repeater which needs to unroll 100 items we would quickly run into performance problems.
|
||||||
|
|
||||||
The solution is to break the compilation process into two phases the compile phase where all of
|
The solution is to break the compilation process into two phases; the compile phase where all of
|
||||||
the directives are identified and sorted by priority, and a linking phase where any work which
|
the directives are identified and sorted by priority, and a linking phase where any work which
|
||||||
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
|
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
|
||||||
instance of an `li` is performed.
|
instance of an `li` is performed.
|
||||||
|
|
||||||
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
||||||
compilation process form descending into `li` element. Instead the {@link
|
compilation process from descending into the `li` element. Instead the {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
|
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 `li`
|
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}
|
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
|
watches the expression and as items are added to the array it clones the `li` element, creates a
|
||||||
new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the
|
new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the
|
||||||
|
|
@ -156,18 +156,18 @@ link function on the cloned `li`.
|
||||||
Summary:
|
Summary:
|
||||||
|
|
||||||
* *compile function* - The compile function is relatively rare in directives, since most
|
* *compile function* - The compile function is relatively rare in directives, since most
|
||||||
directives are concerned with working with a specific DOM element instance rather then
|
directives are concerned with working with a specific DOM element instance rather than
|
||||||
transforming the template DOM element. Any operation which can be shared among the instance of
|
transforming the template DOM element. Any operation which can be shared among the instance of
|
||||||
directives should be moved to the compile function for performance reasons.
|
directives should be moved to the compile function for performance reasons.
|
||||||
|
|
||||||
* *link function* - It is rare for the directive not to have a link function. Link function
|
* *link function* - It is rare for the directive not to have a link function. A link function
|
||||||
allows the directive to register listeners to the specific cloned DOM element instance as well
|
allows the directive to register listeners to the specific cloned DOM element instance as well
|
||||||
as to copy content into the DOM from the scope.
|
as to copy content into the DOM from the scope.
|
||||||
|
|
||||||
|
|
||||||
# Writing directives (short version)
|
# Writing directives (short version)
|
||||||
|
|
||||||
In this example we will build a directive which displays the current time.
|
In this example we will build a directive that displays the current time.
|
||||||
|
|
||||||
<doc:example module="time">
|
<doc:example module="time">
|
||||||
<doc:source>
|
<doc:source>
|
||||||
|
|
@ -206,22 +206,20 @@ In this example we will build a directive which displays the current time.
|
||||||
}
|
}
|
||||||
|
|
||||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
// 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() {
|
element.bind('$destroy', function() {
|
||||||
$timeout.cancel(timeoutId);
|
$timeout.cancel(timeoutId);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateLater(); // kick of the UI update process.
|
updateLater(); // kick off the UI update process.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div ng-controller="Ctrl2">
|
<div ng-controller="Ctrl2">
|
||||||
Date format: <input ng-model='format'> <hr/>
|
Date format: <input ng-model="format"> <hr/>
|
||||||
Current time is: <span my-current-time="format"></span>
|
Current time is: <span my-current-time="format"></span>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -255,9 +253,9 @@ An example skeleton of the directive is shown here, for the complete list see be
|
||||||
|
|
||||||
In most cases you will not need such fine control and so the above can be simplified. All of the
|
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
|
different parts of this skeleton are explained in following sections. In this section we are
|
||||||
interested only isomers of this skeleton.
|
interested only in some of this skeleton.
|
||||||
|
|
||||||
The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be
|
The first step in simplyfing the code is to rely on the default values. Therefore the above can be
|
||||||
simplified as:
|
simplified as:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -273,7 +271,7 @@ simplified as:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Most directives concern themselves only with instances not with template transformations allowing
|
Most directives concern themselves only with instances, not with template transformations, allowing
|
||||||
further simplification:
|
further simplification:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -290,7 +288,7 @@ further simplification:
|
||||||
The factory method is responsible for creating the directive. It is invoked only once, when the
|
The factory method is responsible for creating the directive. It is invoked only once, when the
|
||||||
{@link api/ng.$compile compiler} matches the directive for the first time. You can
|
{@link api/ng.$compile compiler} matches the directive for the first time. You can
|
||||||
perform any initialization work here. The method is invoked using the {@link
|
perform any initialization work here. The method is invoked using the {@link
|
||||||
http://localhost:8000/build/docs/api/AUTO.$injector#invoke $injector.invoke} which
|
api/AUTO.$injector#invoke $injector.invoke} which
|
||||||
makes it injectable following all of the rules of injection annotation.
|
makes it injectable following all of the rules of injection annotation.
|
||||||
|
|
||||||
## Directive Definition Object
|
## Directive Definition Object
|
||||||
|
|
@ -298,7 +296,7 @@ makes it injectable following all of the rules of injection annotation.
|
||||||
The directive definition object provides instructions to the {@link api/ng.$compile
|
The directive definition object provides instructions to the {@link api/ng.$compile
|
||||||
compiler}. The attributes are:
|
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
|
* `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
|
is necessary to specify the order in which the directives are applied. The `priority` is used
|
||||||
|
|
@ -312,50 +310,52 @@ compiler}. The attributes are:
|
||||||
* `scope` - If set to:
|
* `scope` - If set to:
|
||||||
|
|
||||||
* `true` - then a new scope will be created for this directive. If multiple directives on the
|
* `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.
|
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
|
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
|
||||||
normal scope that it does not prototypically inherit from the parent scope. This is useful
|
normal scope in that it does not prototypically inherit from the parent scope. This is useful
|
||||||
when creating reusable components, which should not accidentally read or modify data in
|
when creating reusable components, which should not accidentally read or modify data in the
|
||||||
parent scope. <br/>
|
parent scope. <br/>
|
||||||
The 'isolate' scope takes an object hash which defines a set of local scope properties
|
The 'isolate' scope takes an object hash which defines a set of local scope properties
|
||||||
derived from the parent scope. These local properties are useful for aliasing values for
|
derived from the parent scope. These local properties are useful for aliasing values for
|
||||||
templates. Locals definition is a hash of local scope property to its source:
|
templates. Locals definition is a hash of local scope property to its source:
|
||||||
|
|
||||||
* `@` or `@attr` - bind a local scope property to the DOM attribute. The result is always a
|
* `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
|
||||||
string since DOM attributes are strings. If no `attr` name is specified then the local name
|
always a string since DOM attributes are strings. If no `attr` name is specified then the
|
||||||
and attribute name are same. Given `<widget my-attr="hello {{name}}">` and widget definition
|
attribute name is assumed to be the same as the local name.
|
||||||
|
Given `<widget my-attr="hello {{name}}">` and widget definition
|
||||||
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
|
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
|
||||||
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
|
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
|
||||||
`localName` property on the widget scope. The `name` is read from the parent scope (not
|
`localName` property on the widget scope. The `name` is read from the parent scope (not
|
||||||
component scope).
|
component scope).
|
||||||
|
|
||||||
* `=` or `=expression` - set up bi-directional binding between a local scope property and the
|
* `=` or `=attr` - set up bi-directional binding between a local scope property and the
|
||||||
parent scope property. If no `attr` name is specified then the local name and attribute
|
parent scope property of name defined via the value of the `attr` attribute. If no `attr`
|
||||||
name are same. Given `<widget my-attr="parentModel">` and widget definition of
|
name is specified then the attribute name is assumed to be the same as the local name.
|
||||||
`scope: { localModel:'=myAttr' }`, then widget scope property `localName` will reflect the
|
Given `<widget my-attr="parentModel">` and widget definition of
|
||||||
|
`scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
|
||||||
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
|
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
|
||||||
in `localModel` and any changes in `localModel` will reflect in `parentModel`.
|
in `localModel` and any changes in `localModel` will reflect in `parentModel`.
|
||||||
|
|
||||||
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
|
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
|
||||||
If no `attr` name is specified then the local name and attribute name are same.
|
If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||||
Given `<widget my-attr="count = count + value">` and widget definition of
|
local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
||||||
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
|
`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
|
a function wrapper for the `count = count + value` expression. Often it's desirable to
|
||||||
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
pass data from the isolated scope via an expression and to the parent scope, this can be
|
||||||
map of local variable names and values into the expression wrapper fn. For example if the
|
done by passing a map of local variable names and values into the expression wrapper fn.
|
||||||
expression is `increment(amount)` then we can specify the amount value by calling the
|
For example, if the expression is `increment(amount)` then we can specify the amount value
|
||||||
`localFn` as `localFn({amount: 22})`.
|
by calling the `localFn` as `localFn({amount: 22})`.
|
||||||
|
|
||||||
* `controller` - Controller constructor function. The controller is instantiated before the
|
* `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
|
pre-linking phase and it is shared with other directives if they request it by name (see
|
||||||
`require` attribute). This allows the directives to communicate with each other and augment
|
`require` attribute). This allows the directives to communicate with each other and augment
|
||||||
each other behavior. The controller is injectable with the following locals:
|
each other's behavior. The controller is injectable with the following locals:
|
||||||
|
|
||||||
* `$scope` - Current scope associated with the element
|
* `$scope` - Current scope associated with the element
|
||||||
* `$element` - Current 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:
|
* `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
|
||||||
`function(cloneLinkingFn)`.
|
`function(cloneLinkingFn)`.
|
||||||
|
|
||||||
|
|
@ -376,14 +376,14 @@ compiler}. The attributes are:
|
||||||
* `M` - Comment: `<!-- directive: my-directive exp -->`
|
* `M` - Comment: `<!-- directive: my-directive exp -->`
|
||||||
|
|
||||||
* `template` - replace the current element with the contents of the HTML. The replacement process
|
* `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
|
migrates all of the attributes / classes from the old element to the new one. See the
|
||||||
Widgets section below for more information.
|
{@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
|
* `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
|
the template loading is asynchronous the compilation/linking is suspended until the template
|
||||||
is loaded.
|
is loaded.
|
||||||
|
|
||||||
* `replace` - if set to `true` then the template will replace the current element, rather then
|
* `replace` - if set to `true` then the template will replace the current element, rather than
|
||||||
append the template to the element.
|
append the template to the element.
|
||||||
|
|
||||||
* `transclude` - compile the content of the element and make it available to the directive.
|
* `transclude` - compile the content of the element and make it available to the directive.
|
||||||
|
|
@ -409,24 +409,24 @@ compiler}. The attributes are:
|
||||||
function compile(tElement, tAttrs, transclude) { ... }
|
function compile(tElement, tAttrs, transclude) { ... }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Compile function deals with transforming the template DOM. Since most directives do not do
|
The compile function deals with transforming the template DOM. Since most directives do not do
|
||||||
template transformation, it is not used often. Examples which require compile functions are
|
template transformation, it is not used often. Examples that require compile functions are
|
||||||
directives which transform template DOM such as {@link
|
directives that transform template DOM, such as {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} or load the contents
|
api/ng.directive:ngRepeat ngRepeat}, or load the contents
|
||||||
asynchronously such as {@link api/ng.directive:ngView ngView}. The
|
asynchronously, such as {@link api/ng.directive:ngView ngView}. The
|
||||||
compile functions takes the following arguments.
|
compile function takes the following arguments.
|
||||||
|
|
||||||
* `tElement` - template element - The element where the directive has been declared. It is
|
* `tElement` - template element - The element where the directive has been declared. It is
|
||||||
safe to do template transformation on the element and child elements only.
|
safe to do template transformation on the element and child elements only.
|
||||||
|
|
||||||
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
|
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
|
||||||
between all directive compile functions. See {@link
|
between all directive compile functions. See {@link
|
||||||
#Attributes Attributes}
|
guide/directive#Attributes Attributes}.
|
||||||
|
|
||||||
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
|
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
|
||||||
|
|
||||||
NOTE: The template instance and the link instance may not be the same objects if the template has
|
NOTE: The template instance and the link instance may not be the same objects if the template has
|
||||||
been cloned. For this reason it is not safe in the compile function to do anything other the DOM
|
been cloned. For this reason it is not safe in the compile function to do anything other than DOM
|
||||||
transformation that applies to all DOM clones. Specifically, DOM listener registration should be
|
transformation that applies to all DOM clones. Specifically, DOM listener registration should be
|
||||||
done in a linking function rather than in a compile function.
|
done in a linking function rather than in a compile function.
|
||||||
|
|
||||||
|
|
@ -446,7 +446,7 @@ A compile function can have a return value which can be either a function or an
|
||||||
function link(scope, iElement, iAttrs, controller) { ... }
|
function link(scope, iElement, iAttrs, controller) { ... }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Link function is responsible for registering DOM listeners as well as updating the DOM. It is
|
The link function is responsible for registering DOM listeners as well as updating the DOM. It is
|
||||||
executed after the template has been cloned. This is where most of the directive logic will be
|
executed after the template has been cloned. This is where most of the directive logic will be
|
||||||
put.
|
put.
|
||||||
|
|
||||||
|
|
@ -458,7 +458,8 @@ put.
|
||||||
already been linked.
|
already been linked.
|
||||||
|
|
||||||
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
||||||
between all directive linking functions. See {@link #Attributes Attributes}
|
between all directive linking functions. See {@link
|
||||||
|
guide/directive#Attributes Attributes}.
|
||||||
|
|
||||||
* `controller` - a controller instance - A controller instance if at least one directive on the
|
* `controller` - a controller instance - A controller instance if at least one directive on the
|
||||||
element defines a controller. The controller is shared among all the directives, which allows
|
element defines a controller. The controller is shared among all the directives, which allows
|
||||||
|
|
@ -473,16 +474,16 @@ compiler linking function will fail to locate the correct elements for linking.
|
||||||
|
|
||||||
### Post-linking function
|
### 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>
|
<a name="Attributes"></a>
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
The attributes object - passed as a parameter in the link() or compile() functions - is a way of
|
The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
||||||
accessing:
|
link() or compile() functions - is a way of accessing:
|
||||||
|
|
||||||
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
||||||
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to
|
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
|
||||||
the attributes.
|
the attributes.
|
||||||
|
|
||||||
* *directive inter-communication:* All directives share the same instance of the attributes
|
* *directive inter-communication:* All directives share the same instance of the attributes
|
||||||
|
|
@ -527,6 +528,7 @@ dialog component may work.
|
||||||
on-ok="show = false; doSomething()">
|
on-ok="show = false; doSomething()">
|
||||||
Body goes here: {{username}} is {{title}}.
|
Body goes here: {{username}} is {{title}}.
|
||||||
</dialog>
|
</dialog>
|
||||||
|
</div>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
|
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
|
||||||
|
|
@ -536,7 +538,7 @@ into the dialog.
|
||||||
Here is an example of what the template definition for the `dialog` widget may look like.
|
Here is an example of what the template definition for the `dialog` widget may look like.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<div ng-show="show()">
|
<div ng-show="visible">
|
||||||
<h3>{{title}}</h3>
|
<h3>{{title}}</h3>
|
||||||
<div class="body" ng-transclude></div>
|
<div class="body" ng-transclude></div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|
@ -548,18 +550,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.
|
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 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 `onOk`
|
the place of instantiation would like to bind to `username`. Furthermore the buttons expect the
|
||||||
as well as `onCancel` functions to be present in the scope. This limits the usefulness of 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
|
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||||
expects as follows:
|
expects as follows:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
scope: {
|
scope: {
|
||||||
title: 'bind', // set up title to accept data-binding
|
title: '@', // the title uses the data-binding from the parent scope
|
||||||
onOk: 'expression', // create a delegate onOk function
|
onOk: '&', // create a delegate onOk function
|
||||||
onCancel: 'expression', // create a delegate onCancel function
|
onCancel: '&', // create a delegate onCancel function
|
||||||
show: 'accessor' // create a getter/setter function for visibility.
|
visible: '=' // set up visible to accept data-binding
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
@ -577,12 +579,12 @@ To solve the issue of lack of isolation, the directive declares a new `isolated`
|
||||||
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
||||||
to worry about accidentally clobbering any properties.
|
to worry about accidentally clobbering any properties.
|
||||||
|
|
||||||
However 'isolated' scope creates a new problem: if a transcluded DOM is a child of the widget
|
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
|
||||||
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
|
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
|
||||||
is a child of the original scope, before the widget created an isolated scope for its local
|
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.
|
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.
|
surprise.
|
||||||
|
|
||||||
Therefore the final directive definition looks something like this:
|
Therefore the final directive definition looks something like this:
|
||||||
|
|
@ -590,13 +592,16 @@ Therefore the final directive definition looks something like this:
|
||||||
<pre>
|
<pre>
|
||||||
transclude: true,
|
transclude: true,
|
||||||
scope: {
|
scope: {
|
||||||
title: 'bind', // set up title to accept data-binding
|
title: '@', // the title uses the data-binding from the parent scope
|
||||||
onOk: 'expression', // create a delegate onOk function
|
onOk: '&', // create a delegate onOk function
|
||||||
onCancel: 'expression', // create a delegate onCancel function
|
onCancel: '&', // create a delegate onCancel function
|
||||||
show: 'accessor' // create a getter/setter function for visibility.
|
visible: '=' // set up visible to accept data-binding
|
||||||
}
|
},
|
||||||
|
restrict: 'E',
|
||||||
|
replace: true
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<a name="Components"></a>
|
||||||
# Creating Components
|
# Creating Components
|
||||||
|
|
||||||
It is often desirable to replace a single directive with a more complex DOM structure. This
|
It is often desirable to replace a single directive with a more complex DOM structure. This
|
||||||
|
|
@ -605,7 +610,6 @@ can be built.
|
||||||
|
|
||||||
Following is an example of building a reusable widget.
|
Following is an example of building a reusable widget.
|
||||||
|
|
||||||
|
|
||||||
<doc:example module="zippyModule">
|
<doc:example module="zippyModule">
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
||||||
expression }}`. Expressions are process by the {@link api/ng.$parse $parse}
|
expression }}`. Expressions are processed by {@link api/ng.$parse $parse}
|
||||||
service.
|
service.
|
||||||
|
|
||||||
For example, these are all valid expressions in angular:
|
For example, these are all valid expressions in angular:
|
||||||
|
|
@ -15,10 +15,9 @@ For example, these are all valid expressions in angular:
|
||||||
|
|
||||||
## Angular Expressions vs. JS Expressions
|
## Angular Expressions vs. JS Expressions
|
||||||
|
|
||||||
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
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.
|
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
|
You can think of Angular expressions as JavaScript expressions with following differences:
|
||||||
differences:
|
|
||||||
|
|
||||||
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
|
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
|
||||||
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
||||||
|
|
@ -92,9 +91,9 @@ You can try evaluating different expressions here:
|
||||||
# Property Evaluation
|
# Property Evaluation
|
||||||
|
|
||||||
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
|
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
|
`$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).
|
prevent accidental access to the global state (a common source of subtle bugs).
|
||||||
|
|
||||||
<doc:example>
|
<doc:example>
|
||||||
|
|
@ -148,7 +147,7 @@ Similarly, invoking a function `a.b.c()` on undefined or null simply returns und
|
||||||
## No Control Flow Statements
|
## No Control Flow Statements
|
||||||
|
|
||||||
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
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.
|
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
|
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.
|
`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
|
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
|
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
|
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
|
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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ Server-side validation is still necessary for a secure application.
|
||||||
|
|
||||||
|
|
||||||
# Simple form
|
# 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.
|
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:example>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
|
|
@ -63,7 +63,7 @@ To allow styling of form as well as controls, `ngModel` add these CSS classes:
|
||||||
- `ng-pristine`
|
- `ng-pristine`
|
||||||
- `ng-dirty`
|
- `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.
|
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.
|
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
|
||||||
|
|
||||||
|
|
@ -190,18 +190,18 @@ The validation can occur in two places:
|
||||||
|
|
||||||
* **View to Model update** -
|
* **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}.
|
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.
|
In the following example we create two directives.
|
||||||
|
|
||||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
* 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.
|
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.
|
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`.
|
* The second directive is a `smart-float`.
|
||||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
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">
|
<doc:example module="form-example1">
|
||||||
|
|
@ -272,13 +272,13 @@ In the following example we create two directives.
|
||||||
</doc:example>
|
</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.
|
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.
|
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:
|
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.
|
- 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.
|
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
|
// model -> view
|
||||||
ctrl.render = function(value) {
|
ctrl.$render = function() {
|
||||||
elm.html(value);
|
elm.html(ctrl.$viewValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
// load init value from DOM
|
// load init value from DOM
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,21 @@
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
This document describes the Internet Explorer (IE) idiosyncrasies when dealing with custom HTML
|
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.
|
on IE v8.0 or earlier.
|
||||||
|
|
||||||
# Short Version
|
# 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 **do not** use custom element tags such as `<ng:view>` (use the attribute version `<div
|
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
|
||||||
ng-view>` instead), or
|
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||||
|
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
|
||||||
|
|
||||||
2. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
2. 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>
|
<pre>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
@ -25,7 +29,7 @@ To make your angular application work on IE please make sure that:
|
||||||
document.createElement('ng-include');
|
document.createElement('ng-include');
|
||||||
document.createElement('ng-pluralize');
|
document.createElement('ng-pluralize');
|
||||||
document.createElement('ng-view');
|
document.createElement('ng-view');
|
||||||
|
|
||||||
// Optionally these for CSS
|
// Optionally these for CSS
|
||||||
document.createElement('ng:include');
|
document.createElement('ng:include');
|
||||||
document.createElement('ng:pluralize');
|
document.createElement('ng:pluralize');
|
||||||
|
|
@ -52,7 +56,7 @@ The **important** parts are:
|
||||||
|
|
||||||
# Long Version
|
# Long Version
|
||||||
|
|
||||||
IE has an issues with element tag names which are not standard HTML tag names. These fall into two
|
IE has issues with element tag names which are not standard HTML tag names. These fall into two
|
||||||
categories, and each category has its own fix.
|
categories, and each category has its own fix.
|
||||||
|
|
||||||
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
|
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
|
||||||
|
|
@ -61,13 +65,13 @@ categories, and each category has its own fix.
|
||||||
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
|
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
|
||||||
`document.createElement('my-tag')`
|
`document.createElement('my-tag')`
|
||||||
|
|
||||||
* If you have are planning on styling the custom tag with CSS selectors, then it must be
|
* If you are planning on styling the custom tag with CSS selectors, then it must be
|
||||||
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
|
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
|
||||||
|
|
||||||
|
|
||||||
## The Good News
|
## The Good News
|
||||||
|
|
||||||
The good news is that these restrictions only apply to element tag names, and not to element
|
The good news is that these restrictions only apply to element tag names, and not to element
|
||||||
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
|
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,7 +88,7 @@ result):
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
It should pares into the following DOM:
|
It should parse into the following DOM:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
#document
|
#document
|
||||||
|
|
@ -118,12 +122,12 @@ In IE, the behavior is that the `BODY` element has three children:
|
||||||
|
|
||||||
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
|
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
|
||||||
the `/` character. Furthermore this closing element should not be part of the DOM since it is
|
the `/` character. Furthermore this closing element should not be part of the DOM since it is
|
||||||
only used to delimitate the structure of the DOM.
|
only used to delineate the structure of the DOM.
|
||||||
|
|
||||||
|
|
||||||
## CSS Styling of Custom Tag Names
|
## CSS Styling of Custom Tag Names
|
||||||
|
|
||||||
The to make CSS selector work with custom elements the custom element name must be shived with the
|
To make CSS selectors work with custom elements, the custom element name must be pre-created with
|
||||||
`document.createElement('my-tag')` regardless of XML namespace.
|
`document.createElement('my-tag')` regardless of XML namespace.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -133,7 +137,7 @@ The to make CSS selector work with custom elements the custom element name must
|
||||||
<script>
|
<script>
|
||||||
// needed to make ng-include parse properly
|
// needed to make ng-include parse properly
|
||||||
document.createElement('ng-include');
|
document.createElement('ng-include');
|
||||||
|
|
||||||
// needed to enable CSS reference
|
// needed to enable CSS reference
|
||||||
document.createElement('ng:view');
|
document.createElement('ng:view');
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -10,33 +10,3 @@ of the following documents before returning here to the Developer Guide:
|
||||||
|
|
||||||
* {@link misc/started Getting Started}
|
* {@link misc/started Getting Started}
|
||||||
* {@link tutorial/index Angular Tutorial}
|
* {@link tutorial/index Angular Tutorial}
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
## {@link overview Overview of Angular}
|
|
||||||
|
|
||||||
## {@link bootstrap Initializing Angular}
|
|
||||||
|
|
||||||
## {@link dev_guide.mvc About MVC in Angular}
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
|
||||||
|
|
||||||
## {@link scope Angular Scope Objects}
|
|
||||||
|
|
||||||
## {@link compiler Angular HTML Compiler}
|
|
||||||
|
|
||||||
## {@link dev_guide.templates Angular Templates}
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
|
||||||
* {@link forms Understanding Angular Forms}
|
|
||||||
|
|
||||||
## {@link dev_guide.services Angular Services}
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
|
||||||
|
|
||||||
## {@link di About Dependency Injection}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of
|
||||||
web apps easier and faster than ever before.
|
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
|
between the developer and most low-level web app development tasks. Angular automatically takes
|
||||||
care of many of these tasks, including:
|
care of many of these tasks, including:
|
||||||
|
|
||||||
|
|
@ -14,10 +14,10 @@ care of many of these tasks, including:
|
||||||
* Setting Up Listeners and Notifiers
|
* Setting Up Listeners and Notifiers
|
||||||
* Input Validation
|
* 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.
|
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:
|
sophisticated techniques to the client-side, including:
|
||||||
|
|
||||||
* Separation of data, application logic, and presentation components
|
* 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
|
## 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
|
primarily for developing single-page apps. Angular supports browser history, forward and back
|
||||||
buttons, and bookmarking in single-page apps.
|
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
|
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 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
|
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
|
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.
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@
|
||||||
# What is a Module?
|
# What is a Module?
|
||||||
|
|
||||||
Most applications have a main method which instantiates, wires, and bootstraps the application.
|
Most applications have a main method which instantiates, wires, and bootstraps the application.
|
||||||
Angular apps don't have a main method, instead modules serve the purpose of declaratively
|
Angular apps don't have a main method. Instead modules declaratively specify how an application
|
||||||
specifying how an application should be bootstrapped. There are several advantages to this
|
should be bootstrapped. There are several advantages to this approach:
|
||||||
approach:
|
|
||||||
|
|
||||||
* The process is more declarative which is easier to understand
|
* The process is more declarative which is easier to understand
|
||||||
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
|
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
|
||||||
|
|
@ -27,15 +26,15 @@ Important things to notice:
|
||||||
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
|
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
|
||||||
bootstraps the app using your module.
|
bootstraps the app using your module.
|
||||||
|
|
||||||
<doc:example module='simpleApp'>
|
<doc:example module='myApp'>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
// declare a module
|
// declare a module
|
||||||
var simpleAppModule = angular.module('simpleApp', []);
|
var myAppModule = angular.module('myApp', []);
|
||||||
|
|
||||||
// configure the module.
|
// configure the module.
|
||||||
// in this example we will create a greeting filter
|
// in this example we will create a greeting filter
|
||||||
simpleAppModule.filter('greet', function() {
|
myAppModule.filter('greet', function() {
|
||||||
return function(name) {
|
return function(name) {
|
||||||
return 'Hello, ' + name + '!';
|
return 'Hello, ' + name + '!';
|
||||||
};
|
};
|
||||||
|
|
@ -139,7 +138,7 @@ angular.module('myModule', []).
|
||||||
// This is an example of a run block.
|
// This is an example of a run block.
|
||||||
// You can have as many of these as you want.
|
// You can have as many of these as you want.
|
||||||
// You can only inject instances (not Providers)
|
// You can only inject instances (not Providers)
|
||||||
// int the run blocks
|
// into the run blocks
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
@ -159,9 +158,9 @@ angular.module('myModule', []).
|
||||||
|
|
||||||
angular.module('myModule', []).
|
angular.module('myModule', []).
|
||||||
config(function($provide, $compileProvider, $filterProvider) {
|
config(function($provide, $compileProvider, $filterProvider) {
|
||||||
$provide.value('a', 123)
|
$provide.value('a', 123);
|
||||||
$provide.factory('a', function() { return 123; })
|
$provide.factory('a', function() { return 123; });
|
||||||
$compileProvider.directive('directiveName', ...).
|
$compileProvider.directive('directiveName', ...);
|
||||||
$filterProvider.register('filterName', ...);
|
$filterProvider.register('filterName', ...);
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
@ -195,7 +194,7 @@ and thus script loaders can take advantage of this property and parallelize the
|
||||||
|
|
||||||
# Unit Testing
|
# 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
|
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
|
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
|
injector, which means that the modules are loaded multiple times per VM. Properly structured
|
||||||
|
|
@ -223,8 +222,8 @@ In all of these examples we are going to assume this module definition:
|
||||||
Let's write some tests:
|
Let's write some tests:
|
||||||
<pre>
|
<pre>
|
||||||
describe('myApp', function() {
|
describe('myApp', function() {
|
||||||
// load the application relevant modules then load a special
|
// load the relevant application modules then load a special
|
||||||
// test module which overrides the $window with mock version,
|
// test module which overrides the $window with a mock version,
|
||||||
// so that calling window.alert() will not block the test
|
// so that calling window.alert() will not block the test
|
||||||
// runner with a real alert box. This is an example of overriding
|
// runner with a real alert box. This is an example of overriding
|
||||||
// configuration information in tests.
|
// configuration information in tests.
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ declarative language for static documents. It does not contain much in the way o
|
||||||
applications, and as a result building web applications is an exercise in *what do I have to do, so
|
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.*
|
that I trick the browser in to 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 as:
|
||||||
|
|
||||||
* **library** - a collection of functions which are useful when writing web apps. Your code is
|
* **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`.
|
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
|
||||||
|
|
@ -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
|
Try out the Live Preview above, and then let's walk through the example and describe what's going
|
||||||
on.
|
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
|
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
|
||||||
bootstrap auto initialize} your application.
|
bootstrap auto initialize} your application.
|
||||||
|
|
||||||
|
|
@ -119,9 +119,9 @@ bootstrap auto initialize} your application.
|
||||||
|
|
||||||
We load Angular using the `<script>` tag:
|
We load Angular using the `<script>` tag:
|
||||||
|
|
||||||
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
|
<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:
|
binding, and we also demonstrate some easy input validation:
|
||||||
|
|
||||||
Quantity: <input type="integer" min="0" ng-model="qty" required >
|
Quantity: <input type="integer" min="0" ng-model="qty" required >
|
||||||
|
|
@ -129,7 +129,7 @@ binding, and we also demonstrate some easy input validation:
|
||||||
|
|
||||||
These input widgets look normal enough, but consider these points:
|
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
|
variables of the same name. Think of those variables as the "Model" component of the
|
||||||
Model-View-Controller design pattern.
|
Model-View-Controller design pattern.
|
||||||
* Note that the HTML widget {@link api/ng.directive:input input}
|
* Note that the HTML widget {@link api/ng.directive:input input}
|
||||||
|
|
@ -193,7 +193,7 @@ Angular frees you from the following pain:
|
||||||
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
|
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.
|
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
|
* **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
|
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
|
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
|
to get started developing features quickly. As a bonus, you get full control over the
|
||||||
|
|
@ -202,7 +202,6 @@ Angular frees you from the following pain:
|
||||||
|
|
||||||
# Watch a Presentation About Angular
|
# Watch a Presentation About Angular
|
||||||
|
|
||||||
Here is an early presentation on angular, but note that substantial development has occurred since
|
Here is a presentation on Angular from May 2012.
|
||||||
the talk was given in July of 2010.
|
|
||||||
|
|
||||||
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ watch {@link guide/expression expressions} and propagate events.
|
||||||
## Scope as Data-Model
|
## Scope as Data-Model
|
||||||
|
|
||||||
Scope is the glue between application controller and the view. During the template {@link compiler
|
Scope is the glue between application controller and the view. During the template {@link compiler
|
||||||
linking} phase the {@link api/ng.$compileProvider.directive directives} set up
|
linking} phase the {@link api/ng.$compileProvider#directive directives} set up
|
||||||
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
|
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
|
||||||
`$watch` allows the directives to be notified of property changes, which allows the directive to
|
`$watch` allows the directives to be notified of property changes, which allows the directive to
|
||||||
render the updated value to the DOM.
|
render the updated value to the DOM.
|
||||||
|
|
@ -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
|
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.
|
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.
|
to test the behavior without being distracted by the rendering details.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -151,7 +151,7 @@ This example illustrates scopes in application, and prototypical inheritance of
|
||||||
</file>
|
</file>
|
||||||
</example>
|
</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
|
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
|
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
|
depending on which scope the expression is evaluated it produces different result. Similarly the
|
||||||
|
|
@ -166,7 +166,7 @@ purposes. (It is unlikely that one would need to retrieve scopes in this way ins
|
||||||
application.) The location where the root scope is attached to the DOM is defined by the location
|
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
|
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,
|
`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.
|
for example, only a portion of the view needs to be controlled by Angular.
|
||||||
|
|
||||||
To examine the scope in the debugger:
|
To examine the scope in the debugger:
|
||||||
|
|
||||||
|
|
@ -218,11 +218,11 @@ api/ng.$rootScope.Scope#$emit emitted} to scope parents.
|
||||||
|
|
||||||
## Scope Life Cycle
|
## 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
|
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
|
||||||
more events.
|
more events.
|
||||||
|
|
||||||
When the browser calls into JavaScript the code executes outside they Angular execution context,
|
When the browser calls into JavaScript the code executes outside the Angular execution context,
|
||||||
which means that Angular is unaware of model modifications. To properly process model
|
which means that Angular is unaware of model modifications. To properly process model
|
||||||
modifications the execution has to enter the Angular execution context using the {@link
|
modifications the execution has to enter the Angular execution context using the {@link
|
||||||
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
|
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
|
||||||
|
|
@ -231,9 +231,9 @@ directive listens on DOM events, such as {@link
|
||||||
api/ng.directive:ngClick `ng-click`} it must evaluate the
|
api/ng.directive:ngClick `ng-click`} it must evaluate the
|
||||||
expression inside the `$apply` method.
|
expression inside the `$apply` method.
|
||||||
|
|
||||||
After evaluating the expression `$apply` method performs a {@link
|
After evaluating the expression, the `$apply` method performs a {@link
|
||||||
api/ng.$rootScope.Scope#$digest `$digest`}. In $digest phase the scope examines all
|
api/ng.$rootScope.Scope#$digest `$digest`}. In the $digest phase the scope examines all
|
||||||
of the `$watch` expressions and compares them with previous value. This dirty checking, is done
|
of the `$watch` expressions and compares them with the previous value. This dirty checking is done
|
||||||
asynchronously. This means that assignment such as `$scope.username="angular"` will not
|
asynchronously. This means that assignment such as `$scope.username="angular"` will not
|
||||||
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
|
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
|
||||||
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
|
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
|
||||||
|
|
@ -250,13 +250,13 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||||
2. **Watcher registration**
|
2. **Watcher registration**
|
||||||
|
|
||||||
During template linking directives register {@link
|
During template linking directives register {@link
|
||||||
api/ng.$rootScope.Scope#$watch watches} on the scope. This watches will be
|
api/ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
|
||||||
used to propagate model values to the DOM.
|
used to propagate model values to the DOM.
|
||||||
|
|
||||||
3. **Model mutation**
|
3. **Model mutation**
|
||||||
|
|
||||||
For mutations to be properly observed, you should make them only within the {@link
|
For mutations to be properly observed, you should make them only within the {@link
|
||||||
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular apis do this
|
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
|
||||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||||
or asynchronous work with {@link api/ng.$http $http} or {@link
|
or asynchronous work with {@link api/ng.$http $http} or {@link
|
||||||
api/ng.$timeout $timeout} services.
|
api/ng.$timeout $timeout} services.
|
||||||
|
|
@ -279,10 +279,10 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||||
### Scopes and Directives
|
### Scopes and Directives
|
||||||
|
|
||||||
During the compilation phase, the {@link compiler compiler} matches {@link
|
During the compilation phase, the {@link compiler compiler} matches {@link
|
||||||
api/ng.$compileProvider.directive directives} against the DOM template. The directives
|
api/ng.$compileProvider#directive directives} against the DOM template. The directives
|
||||||
usually fall into one of two categories:
|
usually fall into one of two categories:
|
||||||
|
|
||||||
- Observing {@link api/ng.$compileProvider.directive directives}, such as
|
- Observing {@link api/ng.$compileProvider#directive directives}, such as
|
||||||
double-curly expressions `{{expression}}`, register listeners using the {@link
|
double-curly expressions `{{expression}}`, register listeners using the {@link
|
||||||
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
|
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
|
||||||
to be notified whenever the expression changes so that it can update the view.
|
to be notified whenever the expression changes so that it can update the view.
|
||||||
|
|
@ -299,7 +299,7 @@ correctly.
|
||||||
|
|
||||||
### Directives that Create Scopes
|
### Directives that Create Scopes
|
||||||
|
|
||||||
In most cases, {@link api/ng.$compileProvider.directive directives} and scopes interact
|
In most cases, {@link api/ng.$compileProvider#directive directives} and scopes interact
|
||||||
but do not create new instances of scope. However, some directives, such as {@link
|
but do not create new instances of scope. However, some directives, such as {@link
|
||||||
api/ng.directive:ngController ng-controller} and {@link
|
api/ng.directive:ngController ng-controller} and {@link
|
||||||
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,19 @@
|
||||||
<a name="H1_1"></a>
|
<a name="H1_1"></a>
|
||||||
# License
|
# License
|
||||||
|
|
||||||
`Angular` is an open source project licensed under the {@link
|
AngularJS is an open source project licensed under the {@link
|
||||||
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
|
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
|
||||||
always welcome. When working with `angular` source base, please follow the guidelines provided on
|
always welcome. When working with AngularJS code base, please follow the guidelines provided on
|
||||||
this page.
|
this page.
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_2"></a>
|
<a name="H1_2"></a>
|
||||||
# Contributing to Source Code
|
# Contributing to Source Code
|
||||||
|
|
||||||
We'd love for you to contribute to our source code and to make `angular` even better than it is
|
We'd love for you to contribute to our source code and to make AngularJS even better than it is
|
||||||
today! Here are the guidelines we'd like you to use:
|
today! Here are the guidelines we'd like you to follow:
|
||||||
|
|
||||||
* Major changes that you intend to contribute to the project must be discussed first on our {@link
|
* Major changes that you intend to contribute to the project should be discussed first on our {@link
|
||||||
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
|
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
|
||||||
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
|
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
|
||||||
is successfully accepted upstream.
|
is successfully accepted upstream.
|
||||||
|
|
@ -64,46 +64,40 @@ inheritance only when absolutely necessary.
|
||||||
external API. See our existing code to see what we mean.
|
external API. See our existing code to see what we mean.
|
||||||
|
|
||||||
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
|
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
|
||||||
that is used throughout `angular`. The best guidance is to do what makes the most sense.
|
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
|
||||||
|
|
||||||
|
|
||||||
<a name="H1_4"></a>
|
<a name="H1_4"></a>
|
||||||
# Checking Out and Building Angular
|
# Checking Out and Building Angular
|
||||||
|
|
||||||
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
|
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
|
||||||
accept code contributions. Several steps are needed to check out and build `angular`:
|
accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
|
||||||
|
|
||||||
|
Several steps are needed to check out and build AngularJS:
|
||||||
|
|
||||||
|
|
||||||
## Installation Dependencies
|
## Installation Dependencies
|
||||||
|
|
||||||
Before you can build `angular`, you must install or configure the following dependencies on your
|
Before you can build AngularJS, you must install or configure the following dependencies on your
|
||||||
machine:
|
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.
|
|
||||||
|
|
||||||
* {@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
|
|
||||||
pre-packaged bundle.
|
|
||||||
|
|
||||||
You'll also need npm and the following npm modules:
|
|
||||||
|
|
||||||
* install npm: `curl http://npmjs.org/install.sh | sh`
|
|
||||||
* install q: `npm install q`
|
|
||||||
* install qq: `npm install qq`
|
|
||||||
* install q-fs: `npm install q-fs`
|
|
||||||
* install jasmine-node: `npm install jasmine`
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
|
|
||||||
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
|
|
||||||
`angular` source base, which means there is no need to install or configure it separately.
|
|
||||||
|
|
||||||
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
||||||
quite a good source for information on Git.
|
quite a good source for information on Git.
|
||||||
|
|
||||||
|
* {@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.
|
||||||
|
|
||||||
|
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
|
## Creating a Github Account and Forking Angular
|
||||||
|
|
||||||
|
|
@ -112,31 +106,39 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
|
||||||
https://github.com/angular/angular.js main angular repository}.
|
https://github.com/angular/angular.js main angular repository}.
|
||||||
|
|
||||||
|
|
||||||
## Building `Angular`
|
## Building AngularJS
|
||||||
|
|
||||||
To build `angular`, 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 `angular` files:
|
minified AngularJS files:
|
||||||
|
|
||||||
1. To clone your Github repository, run:
|
1. To clone your Github repository, run:
|
||||||
|
|
||||||
git clone git@github.com:<github username>/angular.js.git
|
git clone git@github.com:<github username>/angular.js.git
|
||||||
|
|
||||||
2. To go to the `angular` directory, run:
|
2. To go to the AngularJS directory, run:
|
||||||
|
|
||||||
cd angular.js
|
cd angular.js
|
||||||
|
|
||||||
3. To add the main `angular` repository as an upstream remote to your repository, run:
|
3. To add the main AngularJS repository as an upstream remote to your repository, run:
|
||||||
|
|
||||||
git remote add upstream https://github.com/angular/angular.js.git
|
git remote add upstream https://github.com/angular/angular.js.git
|
||||||
|
|
||||||
4. To build `angular`, 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
|
The build output can be located under the `build` directory. It consists of the following files and
|
||||||
directories:
|
directories:
|
||||||
|
|
||||||
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
|
* `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
|
||||||
artifacts.
|
artifacts.
|
||||||
|
|
||||||
* `angular.js` — The non-minified `angular` script.
|
* `angular.js` — The non-minified `angular` script.
|
||||||
|
|
@ -145,8 +147,6 @@ artifacts.
|
||||||
|
|
||||||
* `angular-scenario.js` — The `angular` End2End test runner.
|
* `angular-scenario.js` — The `angular` End2End test runner.
|
||||||
|
|
||||||
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
|
|
||||||
|
|
||||||
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
|
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
|
||||||
|
|
||||||
* `docs/index.html` — The main page for the documentation.
|
* `docs/index.html` — The main page for the documentation.
|
||||||
|
|
@ -154,60 +154,78 @@ artifacts.
|
||||||
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
|
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
|
||||||
|
|
||||||
|
|
||||||
|
<a name="webserver"></a>
|
||||||
## Running a Local Development Web Server
|
## Running a Local Development Web Server
|
||||||
|
|
||||||
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
|
To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
|
||||||
made available a local web server based on Node.js.
|
made available a local web server based on Node.js.
|
||||||
|
|
||||||
1. To start the web server, run:
|
1. To start the web server, run:
|
||||||
|
|
||||||
./nodeserver.sh
|
grunt webserver
|
||||||
|
|
||||||
2. To access the local server, go to this website:
|
2. To access the local server, go to this website:
|
||||||
|
|
||||||
http://localhost:8000/
|
http://localhost:8000/
|
||||||
|
|
||||||
By default, it serves the contents of the `angular` project directory.
|
By default, it serves the contents of the AngularJS project directory.
|
||||||
|
|
||||||
|
|
||||||
<a name="unit-tests"></a>
|
<a name="unit-tests"></a>
|
||||||
## Running the Unit Test Suite
|
## Running the Unit Test Suite
|
||||||
|
|
||||||
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
|
Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
|
||||||
tests:
|
tests once on Chrome run:
|
||||||
|
|
||||||
1. To start the JSTD server, run:
|
grunt test:unit
|
||||||
|
|
||||||
./server.sh
|
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
|
||||||
|
|
||||||
2. To capture one or more browsers, go to this website:
|
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:
|
||||||
|
|
||||||
|
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):
|
||||||
|
|
||||||
http://localhost:9876/
|
http://localhost:9876/
|
||||||
|
|
||||||
3. To trigger a test execution, run:
|
3. To re-run tests just change any source or test file.
|
||||||
|
|
||||||
./test.sh
|
|
||||||
|
|
||||||
4. To automatically run the test suite each time one or more of the files in the project directory
|
|
||||||
is changed, you can install `watchr` and then run:
|
|
||||||
|
|
||||||
watchr watchr.rb
|
|
||||||
|
|
||||||
5. To view the output of each test run, you can tail this log file:
|
|
||||||
|
|
||||||
./logs/jstd.log
|
|
||||||
|
|
||||||
|
|
||||||
## Running the End2End Test Suite
|
To learn more about all of the preconfigured Grunt tasks run:
|
||||||
|
|
||||||
To run the End2End test suite:
|
grunt --help
|
||||||
|
|
||||||
|
|
||||||
|
## Running the end-to-end Test Suite
|
||||||
|
|
||||||
|
To run the E2E test suite:
|
||||||
|
|
||||||
|
1. Start the local web server if it's not running already.
|
||||||
|
|
||||||
|
grunt webserver
|
||||||
|
|
||||||
1. Start the local web server.
|
|
||||||
2. In a browser, go to:
|
2. In a browser, go to:
|
||||||
|
|
||||||
http://localhost:8000/build/docs/docs-scenario.html
|
http://localhost:8000/build/docs/docs-scenario.html
|
||||||
|
|
||||||
The tests are executed automatically.
|
or in terminal run:
|
||||||
|
|
||||||
|
grunt test:end2end
|
||||||
|
|
||||||
|
For convenience you can also simply run:
|
||||||
|
|
||||||
|
grunt test:e2e
|
||||||
|
|
||||||
|
This will start the webserver for you and run the tests.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -216,30 +234,39 @@ To run the End2End test suite:
|
||||||
|
|
||||||
To create and submit a change:
|
To create and submit a change:
|
||||||
|
|
||||||
1. Create a new branch off the master for your changes:
|
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
|
||||||
|
corporations we'll need you to
|
||||||
|
[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:
|
||||||
|
|
||||||
git branch my-fix-branch
|
git branch my-fix-branch
|
||||||
|
|
||||||
2. Check out the branch:
|
3. Check out the branch:
|
||||||
|
|
||||||
git checkout my-fix-branch
|
git checkout my-fix-branch
|
||||||
|
|
||||||
3. Create your patch, make sure to have plenty of tests (that pass).
|
4. Create your patch, make sure to have plenty of tests (that pass).
|
||||||
|
|
||||||
4. Commit your changes:
|
5. 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
|
git commit -a
|
||||||
|
|
||||||
5. Run JavaScript Lint and be sure to address all new warnings and errors:
|
|
||||||
|
|
||||||
rake lint
|
|
||||||
|
|
||||||
6. Push your branch to Github:
|
6. Push your branch to Github:
|
||||||
|
|
||||||
git push origin my-fix-branch
|
git push origin my-fix-branch
|
||||||
|
|
||||||
7. In Github, send a pull request to `angular:master`.
|
7. 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
|
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
|
||||||
from the main (upstream) repository:
|
from the main (upstream) repository:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
@name Downloading
|
@name Downloading
|
||||||
@description
|
@description
|
||||||
|
|
||||||
# Including angular scripts from the angular server
|
# Including angular scripts from the Google CDN
|
||||||
The quickest way to get started is to point your html `<script>` tag to a
|
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
|
||||||
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
This way, you don't have to download anything or maintain a local copy.
|
||||||
local copy.
|
|
||||||
|
|
||||||
There are two types of angular script URLs you can point to, one for development and one for
|
There are two types of angular script URLs you can point to, one for development and one for
|
||||||
production:
|
production:
|
||||||
|
|
@ -15,21 +14,25 @@ development.
|
||||||
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
||||||
production.
|
production.
|
||||||
|
|
||||||
To point your code to an angular script on the angular server, use the following template. This
|
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||||
example points to (non-minified) version 0.10.6:
|
example points to the minified version 1.0.2:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html ng-app>
|
<html ng-app>
|
||||||
<head>
|
<head>
|
||||||
<title>My Angular App</title>
|
<title>My Angular App</title>
|
||||||
<script src="http://code.angularjs.org/angular-0.10.6.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</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
|
# 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
|
This option is for those who want to work with angular offline, or those who want to host the
|
||||||
|
|
@ -42,29 +45,31 @@ Download the version you want and have fun.
|
||||||
|
|
||||||
Each directory under <http://code.angularjs.org/> includes the following set of files:
|
Each directory under <http://code.angularjs.org/> includes the following set of files:
|
||||||
|
|
||||||
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
|
* __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
|
||||||
opening it it any editor or browser. In order to get better error messages during development, you
|
opening it it any editor or browser. In order to get better error messages during development, you
|
||||||
should always use this non-minified angular script.
|
should always use this non-minified angular script.
|
||||||
|
|
||||||
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
|
* __`angular.min.js`__ — This is a minified and obfuscated version of
|
||||||
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
|
`angular.js` created with the Closure compiler. Use this version for production in order
|
||||||
to minimize the size of the application that is downloaded by your user's browser.
|
to minimize the size of the application that is downloaded by your user's browser.
|
||||||
|
|
||||||
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
|
* __`angular.zip`__ — This is a zip archive that contains all of the files released
|
||||||
for this angular version. Use this file to get everything in a single download.
|
for this angular version. Use this file to get everything in a single download.
|
||||||
|
|
||||||
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
|
* __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
|
||||||
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
|
|
||||||
of angular files, make sure that this file is available for download, and that it resides under the
|
|
||||||
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
|
|
||||||
|
|
||||||
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
|
|
||||||
testing angular apps even easier. Your unit/integration test harness should load this file after
|
testing angular apps even easier. Your unit/integration test harness should load this file after
|
||||||
`angular-<version>.js` is loaded.
|
`angular-<version>.js` is loaded.
|
||||||
|
|
||||||
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
|
* __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
|
||||||
to write and execute end-to-end tests for angular applications.
|
to write and execute end-to-end tests for angular applications.
|
||||||
|
|
||||||
* __`docs-<version>`__ — this directory contains all the files that compose the
|
* __`angular-loader.min.js`__ — Module loader for Angular modules. If you are loading multiple script files containing
|
||||||
|
Angular modules, you can load them asynchronosuly and in any order as long as you load this file first. Often the
|
||||||
|
contents of this file are copy&pasted into the `index.html` to avoid even the inial request to `angular-loader.min.js`.
|
||||||
|
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
|
||||||
|
|
||||||
|
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
|
||||||
|
|
||||||
|
* __`docs`__ — this directory contains all the files that compose the
|
||||||
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
|
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
|
||||||
our docs, or even more importantly, view the docs offline.
|
our docs, or even more importantly, view the docs offline.
|
||||||
|
|
|
||||||
|
|
@ -4,78 +4,217 @@
|
||||||
|
|
||||||
#FAQ
|
#FAQ
|
||||||
|
|
||||||
### Why is this project called "angular"? Why is the namespace called "ng"?
|
## Questions
|
||||||
|
|
||||||
Because HTML has angular brackets and "ng" sounds like "angular".
|
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
|
||||||
|
|
||||||
### Is <angular/> an HTML5 tag?
|
Because HTML has Angular brackets and "ng" sounds like "Angular".
|
||||||
|
|
||||||
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
|
|
||||||
together.
|
|
||||||
|
|
||||||
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}?
|
### Is AngularJS a library, framework, plugin or a browser extension?
|
||||||
|
|
||||||
No, angular is none of these. You don't call its functions, it does not call your functions,
|
AngularJS fits the definition of a framework the best, even though it's much more lightweight than
|
||||||
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections
|
a typical framework and that's why many confuse it with a library.
|
||||||
of your data. There are lots of existing widget libraries which you can integrate with angular.
|
|
||||||
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
|
||||||
|
|
||||||
### Do I need to worry about security holes in angular?
|
AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
||||||
|
So it's definitely not a plugin or some other native browser extension.
|
||||||
|
|
||||||
Like with any technology, angular is not impervious to attack. angular does, however, provide
|
|
||||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
|
||||||
attacks. angular does round-trip escaping on all strings for you.
|
|
||||||
|
|
||||||
### Can I download the source, build, and host the angular environment locally?
|
### Is AngularJS a templating system?
|
||||||
|
|
||||||
Yes. See instructions in {@link downloading}.
|
At the highest level, Angular does look like a just another templating system. But there is one
|
||||||
|
important reason why the Angular templating system is different, that makes it very good fit for
|
||||||
### Is angular a templating system?
|
application development: bidirectional data binding. The template is compiled in the browser and
|
||||||
|
the compilation step produces a live view. This means you, the developers, don't need to write
|
||||||
At the highest level, angular does look like a just another templating system. But there is one
|
|
||||||
important reason why angular templating system is different and makes it very good fit for
|
|
||||||
application development: bidirectional data binding. The template is compiled on the browser and
|
|
||||||
the compilation step produces a live view. This means you, the developer, don't need to write
|
|
||||||
code to constantly sync the view with the model and the model with the view as in other
|
code to constantly sync the view with the model and the model with the view as in other
|
||||||
templating systems.
|
templating systems.
|
||||||
|
|
||||||
### What browsers does angular work with?
|
|
||||||
|
|
||||||
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and
|
### Do I need to worry about security holes in AngularJS?
|
||||||
above. Note that CSS only works on IE7 and above.
|
|
||||||
|
|
||||||
### What's angular's performance like?
|
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.
|
||||||
|
|
||||||
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your
|
AngularJS was designed to be compatible with other security measures like Content Security Policy
|
||||||
app's performance will vary depending on how many bindings you use.
|
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
|
||||||
|
possible attack vectors and we highly recommended their use.
|
||||||
|
|
||||||
### How big is the angular bootstrap JS file that I need to include?
|
|
||||||
|
|
||||||
The size of the library itself is < 50KB compressed and obfuscated.
|
### Can I download the source, build, and host the AngularJS environment locally?
|
||||||
|
|
||||||
### Can I use the open-source Closure Library with angular?
|
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).
|
||||||
|
|
||||||
|
|
||||||
|
### What's Angular's performance like?
|
||||||
|
|
||||||
|
The startup time heavily depends on your network connection, state of the cache, browser used and
|
||||||
|
available hardware, but typically we measure bootstrap time in tens or hundreds of milliseconds.
|
||||||
|
|
||||||
|
The runtime performance will vary depending on the number and complexity of bindings on the page
|
||||||
|
as well as the speed of your backend (for apps that fetch data from the backend). Just for an
|
||||||
|
illustration we typically build snappy apps with hundreds or thousands of active bindings.
|
||||||
|
|
||||||
|
|
||||||
|
### How big is the angular.js file that I need to include?
|
||||||
|
|
||||||
|
The size of the file is < 29KB compressed and minified.
|
||||||
|
|
||||||
|
|
||||||
|
### Can I use the open-source Closure Library with Angular?
|
||||||
|
|
||||||
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
|
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
|
||||||
in angular.
|
in Angular.
|
||||||
|
|
||||||
### Does angular use the jQuery library?
|
### Does Angular use the jQuery library?
|
||||||
|
|
||||||
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library.
|
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
|
||||||
If jQuery is not present in your script path, angular falls back on its own implementation of
|
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
|
||||||
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to
|
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
|
||||||
manipulate the DOM.
|
|
||||||
|
|
||||||
### What is testability like in angular?
|
|
||||||
|
|
||||||
Very testable. It has an integrated dependency injection framework. See
|
### What is testability like in Angular?
|
||||||
|
|
||||||
|
Very testable and designed this way from ground up. It has an integrated dependency injection
|
||||||
|
framework, provides mocks for many heavy dependencies (server-side communication). See
|
||||||
{@link api/ng service} for details.
|
{@link api/ng service} for details.
|
||||||
|
|
||||||
### How can I learn more about angular?
|
|
||||||
|
|
||||||
Watch the July 28, 2010 talk
|
### How can I learn more about Angular?
|
||||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
|
||||||
AJAX Apps}".
|
|
||||||
|
|
||||||
### How is angular licensed?
|
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.
|
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.
|
||||||
|
|
||||||
|
**T-shirts**
|
||||||
|
Contact sales at {@link http://www.customink.com www.customink.com} and tell them you want some shirts with design name "angularjs",
|
||||||
|
just like past order #2106371. You'll have to give them your own info for billing and shipping.
|
||||||
|
|
||||||
|
As long as the design stays exactly the same, CustomInk won't charge for any set up fees, and they'll give you a reorder discount.
|
||||||
|
|
||||||
|
## Common Pitfalls
|
||||||
|
|
||||||
|
The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into.
|
||||||
|
This document aims to point them out before you discover them the hard way.
|
||||||
|
|
||||||
|
### DOM Manipulation
|
||||||
|
|
||||||
|
Stop trying to use jQuery to modify the DOM in controllers. Really.
|
||||||
|
That includes adding elements, removing elements, retrieving their contents, showing and hiding them.
|
||||||
|
Use built-in directives, or write your own where necessary, to do your DOM manipulation.
|
||||||
|
See below about duplicating functionality.
|
||||||
|
|
||||||
|
If you're struggling to break the habit, consider removing jQuery from your app.
|
||||||
|
Really. Angular has the $http service and powerful directives that make it almost always unnecessary.
|
||||||
|
Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events.
|
||||||
|
|
||||||
|
### Trying to duplicate functionality that already exists
|
||||||
|
|
||||||
|
There's a good chance that your app isn't the first to require certain functionality.
|
||||||
|
There are a few pieces of Angular that are particularly likely to be reimplemented out of old habits.
|
||||||
|
|
||||||
|
**ng-repeat**
|
||||||
|
|
||||||
|
`ng-repeat` gets this a lot.
|
||||||
|
People try to use jQuery (see above) to add more elements to some container as they're fetched from the server.
|
||||||
|
No, bad dog.
|
||||||
|
This is what `ng-repeat` is for, and it does its job very well.
|
||||||
|
Store the data from the server in an array on your `$scope`, and bind it to the DOM with `ng-repeat`.
|
||||||
|
|
||||||
|
**ng-show**
|
||||||
|
|
||||||
|
`ng-show` gets this frequently too.
|
||||||
|
Conditionally showing and hiding things using jQuery is a common pattern in other apps, but Angular has a better way.
|
||||||
|
`ng-show` (and `ng-hide`) conditionally show and hide elements based on boolean expressions.
|
||||||
|
Describe the conditions for showing and hiding an element in terms of `$scope` variables:
|
||||||
|
|
||||||
|
<div ng-show="!loggedIn">Click <a href="#/login">here</a> to log in</div>
|
||||||
|
|
||||||
|
Note also the counterpart `ng-hide` and similar `ng-disabled`.
|
||||||
|
Note especially the powerful `ng-switch` that should be used instead of several mutually exclusive `ng-show`s.
|
||||||
|
|
||||||
|
**ng-class**
|
||||||
|
|
||||||
|
`ng-class` is the last of the big three.
|
||||||
|
Conditionally applying classes to elements is another thing commonly done manually using jQuery.
|
||||||
|
Angular, of course, has a better way.
|
||||||
|
You can give `ng-class` a whitespace-separated set of class names, and then it's identical to ordinary `class`.
|
||||||
|
That's not very exciting, so there's a second syntax:
|
||||||
|
|
||||||
|
<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>
|
||||||
|
|
||||||
|
Where you give `ng-class` an object, whose keys are CSS class names and whose values are conditional expressions using `$scope` variables.
|
||||||
|
The element will then have all the classes whose conditions are truthy, and none of those whose conditions are falsy.
|
||||||
|
|
||||||
|
Note also the handy `ng-class-even` and `ng-class-odd`, and the related though somewhat different `ng-style`.
|
||||||
|
|
||||||
|
|
||||||
|
### `$watch` and `$apply`
|
||||||
|
|
||||||
|
Angular's two-way data binding is the root of all awesome in Angular.
|
||||||
|
However, it's not magic, and there are some situations where you need to give it a nudge in the right direction.
|
||||||
|
|
||||||
|
When you bind a value to an element in Angular using `ng-model`, `ng-repeat`, etc., Angular creates a `$watch` on that value.
|
||||||
|
Then whenever a value on a scope changes, all `$watch`es observing that element are executed, and everything updates.
|
||||||
|
|
||||||
|
Sometimes, usually when you're writing a custom directive, you will have to define your own `$watch` on a scope value to make the directive react to changes.
|
||||||
|
|
||||||
|
On the flip side, sometimes you change a scope value in some code but the app doesn't react to it.
|
||||||
|
Angular checks for scope variable changes after pieces of your code have finished running; for example, when `ng-click` calls a function on your scope, Angular will check for changes and react.
|
||||||
|
However, some code is outside of Angular and you'll have to call `scope.$apply()` yourself to trigger the update.
|
||||||
|
This is most commonly seen in event handlers in custom directives.
|
||||||
|
|
||||||
|
### Combining `ng-repeat` with other directives
|
||||||
|
|
||||||
|
`ng-repeat` is extremely useful, one of the most powerful directives in Angular.
|
||||||
|
However the transformation it applies to the DOM is substantial.
|
||||||
|
Therefore applying other directives (such as `ng-show`, `ng-controller` and others) to the same element as `ng-repeat` generally leads to problems.
|
||||||
|
|
||||||
|
If you want to apply a directive to the whole repeat, wrap the repeat in a parent element and put it there.
|
||||||
|
If you want to apply a directive to each inner piece of the repeat, put it on a child of the element with `ng-repeat`.
|
||||||
|
|
||||||
|
### `$rootScope` exists, but it can be used for evil
|
||||||
|
|
||||||
|
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
|
||||||
|
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
|
||||||
|
|
||||||
|
Occasionally there are pieces of data that you want to make global to the whole app.
|
||||||
|
For these, you can inject `$rootScope` and set values on it like any other scope.
|
||||||
|
Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like `ng-show` just like values on your local `$scope`.
|
||||||
|
|
||||||
|
Of course, global state sucks and you should use `$rootScope` sparingly, like you would (hopefully) use with global variables in any language.
|
||||||
|
In particular, don't use it for code, only data.
|
||||||
|
If you're tempted to put a function on `$rootScope`, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
|
||||||
|
|
||||||
|
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
|
||||||
|
|
|
||||||
|
|
@ -2,142 +2,37 @@
|
||||||
@name Getting Started
|
@name Getting Started
|
||||||
@description
|
@description
|
||||||
|
|
||||||
# Hello World!
|
We want you to have an easy time while starting to use Angular. We've put together the following steps on your path to
|
||||||
|
becoming an Angular expert.
|
||||||
|
|
||||||
A great way for you to get started with AngularJS is to create the tradtional
|
1. Read the {@link guide/concepts conceptual overview}.<br/>Understand Angular's vocabulary and how all the Angular
|
||||||
"Hello World!" app:
|
components work together.
|
||||||
|
1. Do the {@link tutorial/ AngularJS Tutorial}.<br/>Walk end-to-end through building and application complete with tests
|
||||||
1. In your favorite text editor, create an HTML file
|
on top of a node.js web server. Covers every major AngularJS feature and show you how to set up your development
|
||||||
(for example, `helloworld.html`).
|
environment.
|
||||||
2. From the __Source__ box below, copy and paste the code into your HTML file.
|
1. Download or clone the {@link https://github.com/angular/angular-seed Seed App project template}.<br/>Gives you a
|
||||||
(Double-click on the source to easily select all.)
|
starter app with a directory layout, test harness, and scripts to begin building your application.
|
||||||
3. Open the file in your web browser.
|
|
||||||
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
Hello {{'World'}}!
|
|
||||||
</doc:source>
|
|
||||||
</doc:example>
|
|
||||||
|
|
||||||
The resulting web page should look something like the following:
|
|
||||||
|
|
||||||
<img class="center" src="img/helloworld.png" border="1">
|
|
||||||
|
|
||||||
Now let's take a closer look at that code, and see what is going on behind
|
|
||||||
the scenes.
|
|
||||||
|
|
||||||
The `ng-app` tags tells angular to process the entire HTML page and bootstrap the app when the page
|
|
||||||
is loaded:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<html ng-app>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The next line downloads the angular script:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
(For details on what happens when angular processes an HTML page,
|
|
||||||
see {@link guide/bootstrap Bootstrap}.)
|
|
||||||
|
|
||||||
Finally, this line in the `<body>` of the page is the template that describes
|
|
||||||
how to display our greeting in the UI:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
Hello {{'World'}}!
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
|
|
||||||
the greeting text. Here the expression is the string literal 'World'.
|
|
||||||
|
|
||||||
Next let's look at a more interesting example, that uses AngularJS to
|
|
||||||
bind a dynamic expression to our greeting text.
|
|
||||||
|
|
||||||
# Hello AngularJS World!
|
|
||||||
|
|
||||||
This example demonstrates angular's two-way data binding:
|
|
||||||
|
|
||||||
1. Edit the HTML file you created in the "Hello World!" example above.
|
|
||||||
2. Replace the contents of `<body>` with the code from the __Source__ box below.
|
|
||||||
3. Refresh your browser window.
|
|
||||||
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
Your name: <input type="text" ng-model="yourname" placeholder="World">
|
|
||||||
<hr>
|
|
||||||
Hello {{yourname || 'World'}}!
|
|
||||||
</doc:source>
|
|
||||||
</doc:example>
|
|
||||||
|
|
||||||
After the refresh, the page should look something like this:
|
|
||||||
|
|
||||||
<img class="left" src="img/helloworld_2way.png" border="1" >
|
|
||||||
|
|
||||||
These are some of the important points to note from this example:
|
|
||||||
|
|
||||||
* The text input {@link guide/directive directive}
|
|
||||||
is bound to a model variable called `yourname`.
|
|
||||||
* The double curly braces notation binds the `yourname` model to the greeting text.
|
|
||||||
|
|
||||||
* You did not need to explicitly register an event listener or define an event handler for events!
|
|
||||||
|
|
||||||
Now try typing your name into the input box, and notice the immediate change to
|
|
||||||
the displayed greeting. This demonstrates the concept of angular's
|
|
||||||
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
|
|
||||||
field are immediately
|
|
||||||
reflected in the model (one direction), and any changes to the model are
|
|
||||||
reflected in the greeting text (the other direction).
|
|
||||||
|
|
||||||
|
|
||||||
# Anatomy Of An Angular App
|
#Further Steps
|
||||||
|
|
||||||
This section describes the 3 parts of an angular app, and explains how they map to the
|
##Watch Videos
|
||||||
Model-View-Controller design pattern:
|
|
||||||
|
|
||||||
## Templates
|
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}
|
||||||
|
|
||||||
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and
|
And visit our {@link http://www.youtube.com/user/angularjs YouTube channel} for more AngularJS video presentations and
|
||||||
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully
|
tutorials.
|
||||||
extensible, meaning that with angular you can build your own declarative language on top of HTML!
|
|
||||||
|
|
||||||
|
##Subscribe
|
||||||
|
|
||||||
## Application Logic and Behavior
|
* Subscribe to the {@link http://groups.google.com/forum/?fromgroups#!forum/angular mailing list}. Ask questions here!
|
||||||
|
* Follow us on {@link https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angularjs&source=followbutton&variant=2.0 Twitter}
|
||||||
|
* Add us to your circles on {@link https://plus.google.com/110323587230527980117/posts Google+}
|
||||||
|
|
||||||
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With
|
##Read more
|
||||||
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
|
|
||||||
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
|
|
||||||
write, test, maintain, and understand.
|
|
||||||
|
|
||||||
|
The AngularJS documentation includes the {@link guide/index Developer Guide} covering concepts and the
|
||||||
## Data
|
{@link api/ API Reference} for syntax and usage.
|
||||||
|
|
||||||
The Model is referenced from properties on {@link guide/scope angular scope objects}.
|
|
||||||
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
|
|
||||||
matters is that these are all referenced by the scope object.
|
|
||||||
|
|
||||||
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
|
|
||||||
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
|
|
||||||
|
|
||||||
The following illustration shows the parts of an angular application and how they work together:
|
|
||||||
|
|
||||||
<img class="left" src="img/angular_parts.png" border="0" />
|
|
||||||
|
|
||||||
In addition, angular comes with a set of Services, which have the following properties:
|
|
||||||
|
|
||||||
* The services provided are very useful for building web applications.
|
|
||||||
* You can extend and add application-specific behavior to services.
|
|
||||||
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
|
|
||||||
|
|
||||||
|
|
||||||
# Where To Go Next
|
|
||||||
|
|
||||||
* If you like what you've learned so far, you should definitely check out our awesome {@link
|
|
||||||
tutorial/ Tutorial}, which walks you through the process of building real apps with AngularJS.
|
|
||||||
|
|
||||||
* For further explanations and examples of the AngularJS concepts presented on this page, see the
|
|
||||||
{@link guide/index Developer Guide}.
|
|
||||||
|
|
||||||
* For additional hands-on examples of using AngularJS, including more source code that you can
|
|
||||||
copy and paste into your own pages, take a look through the {@link cookbook/ Cookbook}.
|
|
||||||
|
|
|
||||||
|
|
@ -47,20 +47,23 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
|
||||||
# Working with the code
|
# Working with the code
|
||||||
|
|
||||||
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
|
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
|
||||||
environment. Options for working with the tutorial are to use the Git versioning system for source
|
environment. The tutorial relies on the use of Git versioning system for source code management.
|
||||||
code management or to use scripts that copy snapshots of project files into your workspace
|
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
|
||||||
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your
|
and follow the instructions for setting up your computer.
|
||||||
computer for your preferred option.
|
|
||||||
|
|
||||||
<div class="tabbable" show="true">
|
<div class="tabbable" show="true">
|
||||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
|
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||||
following command in a terminal window:</p>
|
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||||
<pre>java -version</pre>
|
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||||
<p>You will need Java to run unit tests.</p></li>
|
command in a terminal window:</p>
|
||||||
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p>
|
<pre>node --version</pre>
|
||||||
<p>You can build Git from source or use the pre-compiled package.</p></li>
|
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||||
|
don't have it already:</p>
|
||||||
|
<pre>npm install -g testacular</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
|
<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>
|
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>
|
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
|
||||||
|
|
@ -71,77 +74,41 @@ directory.</p></li>
|
||||||
<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 angular-phonecat
|
||||||
directory.</p></li>
|
directory.</p></li>
|
||||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
<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 <a
|
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||||
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run
|
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
||||||
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>You will need Java to run unit tests, so run the following command to verify that you
|
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||||
have <a href="http://java.com/">Java</a> installed and that the <code>java</code> executable is on
|
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||||
your <code>PATH</code>.</p>
|
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||||
<pre>java -version</pre>
|
command in a terminal window:</p>
|
||||||
<p></p></li>
|
<pre>node --version</pre>
|
||||||
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li>
|
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||||
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a
|
don't have it already:</p>
|
||||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
<pre>npm install -g testacular</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>
|
<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>
|
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
|
||||||
<li><p>Change your current directory to angular-phonecat.</p>
|
<li><p>Change your current directory to angular-phonecat.</p>
|
||||||
<pre>cd angular-phonecat</pre>
|
<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 angular-phonecat
|
||||||
directory.</p>
|
directory.</p>
|
||||||
<p>You should run all <code>git</code> commands from msysGit bash.</p>
|
<p>You should run all <code>git</code> commands from Git bash.</p>
|
||||||
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be
|
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
|
||||||
executed from the Windows command line.</li>
|
executed from the Windows command line.</li>
|
||||||
<li><p>You need an http server running on your system, but if you don't already have one
|
<li><p>You need an http server running on your system, but if you don't already have one
|
||||||
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
|
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
|
||||||
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
|
bundled http server.</p></li>
|
||||||
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux">
|
|
||||||
<ol>
|
|
||||||
<li><p>You need Java to run unit tests, so verify that you have <a
|
|
||||||
href="http://java.com/">Java</a> installed by running the following command in a terminal
|
|
||||||
window:</p>
|
|
||||||
<pre>java -version</pre>
|
|
||||||
<li><p>Download the <a href="http://code.angularjs.org/angular-phonecat/">zip archive</a>
|
|
||||||
containing all of the files and unzip them into the [tutorial-dir] directory</p>.</li>
|
|
||||||
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
|
|
||||||
<pre>cd [tutorial-dir]/sandbox</pre>
|
|
||||||
<p>The tutorial instructions assume you are running all commands from your
|
|
||||||
<code>sandbox</code> directory.</p></li>
|
|
||||||
<li><p>You need an http server running on your system and Mac and Linux machines typically
|
|
||||||
have Apache pre-installed. If you don't have an http server installed, you can <a
|
|
||||||
href="http://nodejs.org/#download">install node.js</a> and use it to run
|
|
||||||
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows">
|
|
||||||
<ol>
|
|
||||||
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
|
|
||||||
<code>java</code> executable is on your <code>PATH</code> by running the following command in the
|
|
||||||
Windows command line:</p>
|
|
||||||
<pre>java -version</pre>
|
|
||||||
<p>You need Java to run unit tests, so download the <a
|
|
||||||
href="http://code.angularjs.org/angular-phonecat/">zip archive</a> that contains all of the files
|
|
||||||
and unzip the files into the [tutorial-dir] directory</p></li>
|
|
||||||
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
|
|
||||||
<pre>cd [tutorial-dir]/sandbox</pre>
|
|
||||||
<p>The tutorial instructions assume you are running all commands from this directory.</p></li>
|
|
||||||
<li><p>You need an http server running on your system, but if you don't already have one
|
|
||||||
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
|
|
||||||
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
|
|
||||||
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</divs>
|
|
||||||
|
|
||||||
The last thing to do is to make sure your computer has a web browser and a good text editor
|
The last thing to do is to make sure your computer has a web browser and a good text editor
|
||||||
installed. Now, let's get some cool stuff done!
|
installed. Now, let's get some cool stuff done!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ directory.</li>
|
||||||
|
|
||||||
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
|
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
|
||||||
<ol>
|
<ol>
|
||||||
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
|
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
|
||||||
<pre>git checkout -f step-0</pre>
|
<pre>git checkout -f step-0</pre>
|
||||||
<p>This resets your workspace to step 0 of the tutorial app.</p>
|
<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
|
<p>You must repeat this for every future step in the tutorial and change the number to
|
||||||
|
|
@ -74,70 +74,6 @@ directory.</li>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux" value="snapshotUnix">
|
|
||||||
<ol>
|
|
||||||
<li><p>In the angular-phonecat directory, run this command:</p>
|
|
||||||
<pre>./goto_step.sh 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
|
|
||||||
the number of the step you are on. This will cause any changes you made within
|
|
||||||
your working directory to be lost.</p></li>
|
|
||||||
<li>To see the app running in a browser, do one of the following:
|
|
||||||
<ul>
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
</li>
|
|
||||||
<li><b>For other http servers:</b>
|
|
||||||
<ol>
|
|
||||||
<li>Configure the server to serve the files in the angular-phonecat
|
|
||||||
<code>sandbox</code> directory.</li>
|
|
||||||
<li>Navigate in your browser to
|
|
||||||
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows" value="snapshotWin">
|
|
||||||
<ol>
|
|
||||||
<li><p>Open windows command line and run this command (in the angular-phonecat directory):</p>
|
|
||||||
<pre>goto_step.bat 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
|
|
||||||
the number of the step you are on. This will cause any changes you made within
|
|
||||||
your working directory to be lost.</p></li>
|
|
||||||
<li>To see the app running in a browser, do one of the following:
|
|
||||||
<ul>
|
|
||||||
<li><b>For node.js users:</b>
|
|
||||||
<ol>
|
|
||||||
<li>In a <i>separate</i> terminal tab or window, run <code>node
|
|
||||||
scripts\web-server.js</code> to start the web server.</li>
|
|
||||||
<li>Open a browser window for the app and navigate to <a
|
|
||||||
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
<li><b>For other http servers:</b>
|
|
||||||
<ol>
|
|
||||||
<li>Configure the server to serve the files in the angular-phonecat
|
|
||||||
<code>sandbox</code> directory.</li>
|
|
||||||
<li>Navigate in your browser to
|
|
||||||
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
|
|
||||||
</ol>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -173,10 +109,11 @@ __`app/index.html`:__
|
||||||
|
|
||||||
<html ng-app>
|
<html ng-app>
|
||||||
|
|
||||||
The `ng-app` attribute is represents an Angular directive used to flag an element which Angular
|
The `ng-app` attribute represents an Angular directive (named `ngApp`; Angular uses
|
||||||
should consider to be the root element of our application. This gives application developers the
|
`name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
|
||||||
freedom to tell Angular if the entire html page or only a portion of it should be treated as the
|
used to flag an element which Angular should consider to be the root element of our application.
|
||||||
Angular application.
|
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||||
|
portion of it should be treated as the Angular application.
|
||||||
|
|
||||||
* AngularJS script tag:
|
* AngularJS script tag:
|
||||||
|
|
||||||
|
|
@ -190,12 +127,12 @@ being the element on which the `ngApp` directive was defined.
|
||||||
|
|
||||||
* Double-curly binding with an expression:
|
* 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
|
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.
|
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
||||||
|
|
||||||
The binding tells Angular, that it should evaluate an expression and insert the result into the
|
The binding tells Angular that it should evaluate an expression and insert the result into the
|
||||||
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
||||||
binding will result in efficient continuous updates whenever the result of the expression
|
binding will result in efficient continuous updates whenever the result of the expression
|
||||||
evaluation changes.
|
evaluation changes.
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
<ul doc-tutorial-nav="1"></ul>
|
<ul doc-tutorial-nav="1"></ul>
|
||||||
|
|
||||||
|
|
||||||
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
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
|
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.
|
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.
|
In this step you will add some basic information about two cell phones to an HTML page.
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ repeater tells Angular to create a `<li>` element for each phone in the list usi
|
||||||
tag as the template.
|
tag as the template.
|
||||||
|
|
||||||
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
|
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
|
||||||
bindings. As opposed to evaluating constants, these expression are refering to our application
|
bindings. As opposed to evaluating constants, these expressions are referring to our application
|
||||||
model, which was set up in our `PhoneListCtrl` controller.
|
model, which was set up in our `PhoneListCtrl` controller.
|
||||||
|
|
||||||
<img class="diagram" src="img/tutorial/tutorial_02.png">
|
<img class="diagram" src="img/tutorial/tutorial_02.png">
|
||||||
|
|
@ -146,31 +146,25 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
|
||||||
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
|
||||||
|
|
||||||
The angular-seed project is pre-configured to run all unit tests using {@link
|
The angular-seed project is pre-configured to run all unit tests using {@link
|
||||||
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
|
http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the following:
|
||||||
|
|
||||||
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
|
||||||
`./scripts/test-server.sh` to start the test web server.
|
`./scripts/test.sh` to start the Testacular server.
|
||||||
|
|
||||||
2. Open a new browser window and navigate to {@link http://localhost:9876}.
|
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.
|
||||||
|
|
||||||
3. Choose "Capture this browser in strict mode".
|
3. You should see the following or similar output in the terminal:
|
||||||
|
|
||||||
At this point, you can leave this window open and forget about it. JsTestDriver will use it to
|
info: Testacular server started at http://localhost:9876/
|
||||||
execute the tests and report the results in the terminal.
|
info (launcher): Starting browser "Chrome"
|
||||||
|
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
|
||||||
4. Execute the test by running `./scripts/test.sh`
|
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
|
||||||
|
|
||||||
You should see the following or similar output:
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
|
||||||
.
|
|
||||||
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
|
|
||||||
|
|
||||||
Yay! The test passed! Or not...
|
Yay! The test passed! Or not...
|
||||||
|
|
||||||
Note: If you see errors after you run the test, close the browser window and go back to the
|
4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
|
||||||
terminal and kill the script, then repeat the procedure above.
|
and will rerun the tests for you. Now isn't that sweet?
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
@ -198,8 +192,7 @@ execute the tests and report the results in the terminal.
|
||||||
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
|
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
|
||||||
`./scripts/test.sh` script.
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ __`app/index.html`:__
|
||||||
</div>
|
</div>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
We added a standard HTML `<input>` tag and used angular's
|
We added a standard HTML `<input>` tag and used Angular's
|
||||||
{@link api/ng.filter:filter $filter} function to process the input for the
|
{@link api/ng.filter:filter $filter} function to process the input for the
|
||||||
`ngRepeat` directive.
|
{@link api/ng.directive:ngRepeat ngRepeat} directive.
|
||||||
|
|
||||||
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
||||||
list. This new code demonstrates the following:
|
list. This new code demonstrates the following:
|
||||||
|
|
@ -122,6 +122,11 @@ 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`
|
`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}
|
* 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
|
||||||
|
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
|
||||||
|
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
|
This test verifies that the search box and the repeater are correctly wired together. Notice how
|
||||||
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
|
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
|
||||||
really is that easy to set up any functional, readable, end-to-end test.
|
really is that easy to set up any functional, readable, end-to-end test.
|
||||||
|
|
@ -176,12 +181,14 @@ ngBindTemplate} directives, which are invisible to the user while the page is lo
|
||||||
|
|
||||||
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
|
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
|
||||||
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
|
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
|
||||||
with the `query` binding.
|
with the `query` binding, prefixed by "Current filter:". For instance:
|
||||||
|
|
||||||
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pause; this
|
<div id="status">Current filter: {{query}}</div>
|
||||||
gives you the opportunity to explore the state of your application while it is displayed in the
|
|
||||||
browser. The app is live! You can change the search query to prove it. Notice how useful this is
|
* Add a `pause()` statement inside of an end-to-end test and rerun it. You'll see the runner pause;
|
||||||
for troubleshooting end-to-end tests.
|
this gives you the opportunity to explore the state of your application while it is displayed in
|
||||||
|
the browser. The app is live! You can change the search query to prove it. Notice how useful this
|
||||||
|
is for troubleshooting end-to-end tests.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ necessary!
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneListCtrl($scope) {
|
function PhoneListCtrl($scope) {
|
||||||
$scope.phones = [
|
$scope.phones = [
|
||||||
|
|
@ -103,7 +103,7 @@ to the model.
|
||||||
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
||||||
the unit test first.
|
the unit test first.
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
@ -134,13 +134,9 @@ 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
|
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.
|
shared by all tests in the parent `describe` block.
|
||||||
|
|
||||||
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
|
You should now see the following output in the Testacular tab:
|
||||||
following output.
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
|
||||||
..
|
|
||||||
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
|
||||||
|
|
||||||
|
|
||||||
Let's turn our attention to the end-to-end test.
|
Let's turn our attention to the end-to-end test.
|
||||||
|
|
@ -168,8 +164,8 @@ __`test/e2e/scenarios.js`:__
|
||||||
|
|
||||||
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
|
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||||
can see them running on {@link
|
`runner.html` to see the tests run, or you can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
|
||||||
Angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ GitHub}:
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones
|
The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
|
||||||
stored in the JSON format.
|
stored in the JSON format.
|
||||||
|
|
||||||
Following is a sample of the file:
|
Following is a sample of the file:
|
||||||
|
|
@ -104,7 +104,7 @@ to avoid any possible naming collisions.
|
||||||
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
||||||
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
||||||
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
||||||
minified as well, and the dependency injector would be able to identify services correctly.
|
minified as well, and the dependency injector would not be able to identify services correctly.
|
||||||
|
|
||||||
To overcome issues caused by minification, just assign an array with service identifier strings
|
To overcome issues caused by minification, just assign an array with service identifier strings
|
||||||
into the `$inject` property of the controller function, just like the last line in the snippet
|
into the `$inject` property of the controller function, just like the last line in the snippet
|
||||||
|
|
@ -164,8 +164,8 @@ isolated from the work done in other tests.
|
||||||
|
|
||||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||||
|
|
||||||
* We called `scope.$new(PhoneListCtrl)` to get Angular to create the child scope associated with
|
* We called the injected `$controller` function passing the `PhoneListCtrl` function and the created
|
||||||
the `PhoneListCtrl` controller.
|
scope as parameters.
|
||||||
|
|
||||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||||
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
||||||
|
|
@ -208,13 +208,10 @@ Finally, we verify that the default value of `orderProp` is set correctly:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
You should now see the following output in the Testacular tab:
|
||||||
output.
|
|
||||||
|
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
|
||||||
|
|
||||||
Chrome: Runner reset.
|
|
||||||
..
|
|
||||||
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
|
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ api/ng.directive:ngSrc ngSrc} directive. That directive prevents the
|
||||||
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
|
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
|
||||||
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
||||||
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
|
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
|
||||||
Using `ngSrc` (`ng-src`) prevents the browser from making an http request to an invalid location.
|
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
@ -84,10 +84,11 @@ __`test/e2e/scenarios.js`__:
|
||||||
We added a new end-to-end test to verify that the app is generating correct links to the phone
|
We added a new end-to-end test to verify that the app is generating correct links to the phone
|
||||||
views that we will implement in the upcoming steps.
|
views that we will implement in the upcoming steps.
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||||
can see them running on {@link
|
runner to see the tests run, or you can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
@ -96,11 +97,15 @@ or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that
|
||||||
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
||||||
`/app/{{phone.imageUrl}}`).
|
`/app/{{phone.imageUrl}}`).
|
||||||
|
|
||||||
|
The issue here is that the browser will fire a request for that invalid image address as soon as
|
||||||
|
it hits the `img` tag, which is before Angular has a chance to evaluate the expression and inject
|
||||||
|
the valid address.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about angular
|
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about Angular
|
||||||
layout templates and how angular makes it easy to create applications that have multiple views.
|
layout templates and how Angular makes it easy to create applications that have multiple views.
|
||||||
|
|
||||||
|
|
||||||
<ul doc-tutorial-nav="6"></ul>
|
<ul doc-tutorial-nav="6"></ul>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ detail page is displayed.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-6...step-7
|
https://github.com/angular/angular-phonecat/compare/step-6...step-7
|
||||||
GitHub}:
|
GitHub}.
|
||||||
|
|
||||||
|
|
||||||
## Multiple Views, Routing and Layout Template
|
## Multiple Views, Routing and Layout Template
|
||||||
|
|
@ -46,7 +46,7 @@ history (back and forward navigation) and bookmarks.
|
||||||
|
|
||||||
### A Note About DI, Injector and Providers
|
### 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.
|
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
|
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
|
||||||
|
|
@ -79,7 +79,7 @@ angular.module('phonecat', []).
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
In order to configure our application with routes, we need to create a module for our application.
|
In order to configure our application with routes, we need to create a module for our application.
|
||||||
We call this module `phonecatApp` and using the `config` API we request the `$routeProvider` to be
|
We call this module `phonecat` and using the `config` API we request the `$routeProvider` to be
|
||||||
injected into our config function and use `$routeProvider.when` API to define our routes.
|
injected into our config function and use `$routeProvider.when` API to define our routes.
|
||||||
|
|
||||||
Note that during the injector configuration phase, the providers can be injected as well, but they
|
Note that during the injector configuration phase, the providers can be injected as well, but they
|
||||||
|
|
@ -114,14 +114,14 @@ directive:
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html ng-app="phonecat">
|
<html lang="en" ng-app="phonecat">
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
function PhoneDetailCtrl($scope, $routeParams) {
|
function PhoneDetailCtrl($scope, $routeParams) {
|
||||||
|
|
@ -140,11 +140,12 @@ route into the layout template, which makes it a perfect fit for our `index.html
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<html ng-app="phonecat">
|
<html lang="en" ng-app="phonecat">
|
||||||
<head>
|
<head>
|
||||||
...
|
...
|
||||||
<script src="lib/angular/angular.js"></script>
|
<script src="lib/angular/angular.js"></script>
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
|
<script src="js/controllers.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -231,10 +232,10 @@ to various URLs and verify that the correct view was rendered.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||||
can see them running on {@link
|
runner to see the tests run, or you can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Now when you click on a phone on the list, the phone details page with phone-spe
|
||||||
is displayed.
|
is displayed.
|
||||||
|
|
||||||
To implement the phone details view we will use {@link api/ng.$http $http} to fetch
|
To implement the phone details view we will use {@link api/ng.$http $http} to fetch
|
||||||
our data, and we'll flesh out the `phone-details.html` view template.
|
our data, and we'll flesh out the `phone-detail.html` view template.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
||||||
|
|
@ -59,7 +59,7 @@ show this data in the phone detail view.
|
||||||
We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works
|
We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works
|
||||||
the same way as the phone list controller.
|
the same way as the phone list controller.
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
||||||
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
||||||
|
|
@ -81,7 +81,7 @@ Note where we use the angular `{{expression}}` markup and `ngRepeat` to project
|
||||||
our model into the view.
|
our model into the view.
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-details.html`:__
|
__`app/partials/phone-detail.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<img ng-src="{{phone.images[0]}}" class="phone">
|
<img ng-src="{{phone.images[0]}}" class="phone">
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ TODO!
|
||||||
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
||||||
step 5.
|
step 5.
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
describe('PhoneDetailCtrl', function(){
|
describe('PhoneDetailCtrl', function(){
|
||||||
|
|
@ -147,13 +147,9 @@ __`test/unit/controllerSpec.js`:__
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
You should now see the following output in the Testacular tab:
|
||||||
output.
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
|
||||||
...
|
|
||||||
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
|
|
||||||
|
|
||||||
|
|
||||||
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
||||||
|
|
@ -177,10 +173,11 @@ __`test/e2e/scenarios.js`:__
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||||
can see them running on {@link
|
runner to see the tests run, or you can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ Navigate to one of the detail pages.
|
||||||
|
|
||||||
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
||||||
certain phone features were present or not. We have used a custom filter to convert those text
|
certain phone features were present or not. We have used a custom filter to convert those text
|
||||||
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see, what the filter code looks like.
|
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see what the filter code looks like.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
||||||
|
|
@ -110,13 +110,9 @@ describe('filter', function() {
|
||||||
Note that you need to configure our test injector with the `phonecatFilters` module before any of
|
Note that you need to configure our test injector with the `phonecatFilters` module before any of
|
||||||
our filter tests execute.
|
our filter tests execute.
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
You should now see the following output in the Testacular tab:
|
||||||
output.
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
|
||||||
....
|
|
||||||
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
|
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ In this step, you will add a clickable phone image swapper to the phone details
|
||||||
|
|
||||||
The phone details view displays one large image of the current phone and several smaller thumbnail
|
The phone details view displays one large image of the current phone and several smaller thumbnail
|
||||||
images. It would be great if we could replace the large image with any of the thumbnails just by
|
images. It would be great if we could replace the large image with any of the thumbnails just by
|
||||||
clicking on the desired thumbnail image. Let's have a look at how we can do this with angular.
|
clicking on the desired thumbnail image. Let's have a look at how we can do this with Angular.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
||||||
|
|
@ -102,10 +102,10 @@ __`test/e2e/scenarios.js`:__
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||||
can see them running on {@link
|
runner to see the tests run, or you can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ In this step, you will improve the way our app fetches data.
|
||||||
|
|
||||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||||
can make xhr requests for data in an easier way, without having to deal with the lower-level {@link
|
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||||
api/ng.$http $http} API, HTTP methods and URLs.
|
api/ng.$http $http} API, HTTP methods and URLs.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
|
|
@ -57,13 +57,22 @@ The {@link api/ngResource.$resource `$resource`} service makes it easy to create
|
||||||
lines of code. This client can then be used in our application, instead of the lower-level {@link
|
lines of code. This client can then be used in our application, instead of the lower-level {@link
|
||||||
api/ng.$http $http} service.
|
api/ng.$http $http} service.
|
||||||
|
|
||||||
|
__`app/js/app.js`.__
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
We need to add 'phonecatServices' to 'phonecat' application's requires array.
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
||||||
lower-level {@link api/ng.$http $http} service, replacing it with a new service called
|
lower-level {@link api/ng.$http $http} service, replacing it with a new service called
|
||||||
`Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to
|
`Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to
|
||||||
use than `$http for interacting with data sources exposed as RESTful resources. It is also easier
|
use than `$http` for interacting with data sources exposed as RESTful resources. It is also easier
|
||||||
now to understand what the code in our controllers is doing.
|
now to understand what the code in our controllers is doing.
|
||||||
|
|
||||||
__`app/js/controllers.js`.__
|
__`app/js/controllers.js`.__
|
||||||
|
|
@ -107,8 +116,8 @@ This is a simple statement that we want to query for all phones.
|
||||||
An important thing to notice in the code above is that we don't pass any callback functions when
|
An important thing to notice in the code above is that we don't pass any callback functions when
|
||||||
invoking methods of our Phone service. Although it looks as if the result were returned
|
invoking methods of our Phone service. Although it looks as if the result were returned
|
||||||
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
||||||
object, which will be filled with data when the xhr response returns. Because of the data-binding
|
object, which will be filled with data when the XHR response returns. Because of the data-binding
|
||||||
in angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
in Angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
||||||
view will automatically update.
|
view will automatically update.
|
||||||
|
|
||||||
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
||||||
|
|
@ -205,13 +214,9 @@ describe('PhoneCat controllers', function() {
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
You should now see the following output in the Testacular tab:
|
||||||
output.
|
|
||||||
|
|
||||||
Chrome: Runner reset.
|
Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
|
||||||
....
|
|
||||||
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
|
|
||||||
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
|
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||||
previous steps using the `git checkout` or `goto_step.sh` commands.
|
previous steps using the `git checkout` command.
|
||||||
|
|
||||||
For more details and examples of the Angular concepts we touched on in this tutorial, see the
|
For more details and examples of the Angular concepts we touched on in this tutorial, see the
|
||||||
{@link guide/ Developer Guide}.
|
{@link guide/ Developer Guide}.
|
||||||
|
|
@ -11,7 +11,7 @@ For more details and examples of the Angular concepts we touched on in this tuto
|
||||||
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
||||||
|
|
||||||
When you are ready to start developing a project using Angular, we recommend that you bootstrap
|
When you are ready to start developing a project using Angular, we recommend that you bootstrap
|
||||||
your development with the {@link https://github.com/angular/angular-seed angular seed} project.
|
your development with the {@link https://github.com/angular/angular-seed angular-seed} project.
|
||||||
|
|
||||||
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
|
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
|
||||||
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
|
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
|
||||||
|
|
|
||||||
BIN
docs/img/guide/concepts-controller.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
docs/img/guide/concepts-directive.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
docs/img/guide/concepts-model.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/img/guide/concepts-module-injector.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/img/guide/concepts-runtime.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/img/guide/concepts-scope.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
docs/img/guide/concepts-startup.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/img/guide/concepts-view.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
|
@ -55,12 +55,15 @@ describe('ngdoc', function() {
|
||||||
'@name a\n' +
|
'@name a\n' +
|
||||||
'@param {*} a short\n' +
|
'@param {*} a short\n' +
|
||||||
'@param {Type} b med\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();
|
doc.parse();
|
||||||
expect(doc.param).toEqual([
|
expect(doc.param).toEqual([
|
||||||
{name:'a', description:'<p>short</p>', type:'*', optional:false, 'default':undefined},
|
{name:'a', description:'<p>short</p>', type:'*', optional:false, 'default':undefined},
|
||||||
{name:'b', description:'<p>med</p>', type:'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:'c', description:'<p>long\nline</p>', type:'Class', optional:true, 'default':'2'},
|
||||||
|
{name:'d', description:'<p>fn with optional arguments</p>',
|
||||||
|
type: 'function(number, string=)', optional: false, 'default':undefined}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -318,9 +321,9 @@ describe('ngdoc', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not parse @property without a type', 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(); }).
|
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() {
|
it('should parse @property with type', function() {
|
||||||
|
|
@ -350,15 +353,30 @@ describe('ngdoc', function() {
|
||||||
describe('@returns', function() {
|
describe('@returns', function() {
|
||||||
it('should not parse @returns without type', function() {
|
it('should not parse @returns without type', function() {
|
||||||
var doc = new Doc("@returns lala");
|
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() {
|
it('should parse @returns with type and description', function() {
|
||||||
var doc = new Doc("@name a\n@returns {string} descrip tion");
|
var doc = new Doc("@name a\n@returns {string} descrip tion");
|
||||||
doc.parse();
|
doc.parse();
|
||||||
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip tion</p>'});
|
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip tion</p>'});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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: '<p>description</p>'});
|
||||||
|
});
|
||||||
|
|
||||||
it('should transform description of @returns with markdown', function() {
|
it('should transform description of @returns with markdown', function() {
|
||||||
var doc = new Doc("@name a\n@returns {string} descrip *tion*");
|
var doc = new Doc("@name a\n@returns {string} descrip *tion*");
|
||||||
doc.parse();
|
doc.parse();
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ exports.Example.prototype.addSource = function(name, content) {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Example.prototype.toHtml = function() {
|
exports.Example.prototype.toHtml = function() {
|
||||||
return '<h1>Source</h1>\n' +
|
return '<h2>Source</h2>\n' +
|
||||||
this.toHtmlEdit() +
|
this.toHtmlEdit() +
|
||||||
this.toHtmlTabs() +
|
this.toHtmlTabs() +
|
||||||
'<h1>Demo</h1>\n' +
|
'<h2>Demo</h2>\n' +
|
||||||
this.toHtmlEmbed();
|
this.toHtmlEmbed();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,13 @@ var reader = require('./reader.js'),
|
||||||
appCache = require('./appCache.js').appCache,
|
appCache = require('./appCache.js').appCache,
|
||||||
Q = require('qq');
|
Q = require('qq');
|
||||||
|
|
||||||
process.on('uncaughtException', function(err) {
|
|
||||||
console.error(err.stack || err);
|
|
||||||
});
|
|
||||||
|
|
||||||
var start = now();
|
var start = now();
|
||||||
var docs;
|
var docs;
|
||||||
|
|
||||||
writer.makeDir('build/docs/syntaxhighlighter').then(function() {
|
writer.makeDir('build/docs/', true).then(function() {
|
||||||
console.log('Generating Angular Reference Documentation...');
|
return writer.makeDir('build/docs/partials/');
|
||||||
|
}).then(function() {
|
||||||
|
console.log('Generating AngularJS Reference Documentation...');
|
||||||
return reader.collect();
|
return reader.collect();
|
||||||
}).then(function generateHtmlDocPartials(docs_) {
|
}).then(function generateHtmlDocPartials(docs_) {
|
||||||
docs = docs_;
|
docs = docs_;
|
||||||
|
|
@ -34,14 +32,16 @@ writer.makeDir('build/docs/syntaxhighlighter').then(function() {
|
||||||
});
|
});
|
||||||
}).then(function printStats() {
|
}).then(function printStats() {
|
||||||
console.log('DONE. Generated ' + docs.length + ' pages in ' + (now()-start) + 'ms.' );
|
console.log('DONE. Generated ' + docs.length + ' pages in ' + (now()-start) + 'ms.' );
|
||||||
}).end();
|
});
|
||||||
|
|
||||||
|
|
||||||
function writeTheRest(writesFuture) {
|
function writeTheRest(writesFuture) {
|
||||||
var metadata = ngdoc.metadata(docs);
|
var metadata = ngdoc.metadata(docs);
|
||||||
|
|
||||||
writesFuture.push(writer.copyDir('img'));
|
writesFuture.push(writer.symlinkTemplate('css', 'dir'));
|
||||||
writesFuture.push(writer.copyDir('font'));
|
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"';
|
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ function writeTheRest(writesFuture) {
|
||||||
|
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html',
|
||||||
writer.replace, {'doc:manifest': manifest}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html',
|
||||||
writer.replace, {'doc:manifest': ''}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
@ -65,27 +65,24 @@ function writeTheRest(writesFuture) {
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html',
|
||||||
writer.replace, {'doc:manifest': ''}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
||||||
writesFuture.push(writer.copyTpl('offline.html'));
|
writesFuture.push(writer.symlinkTemplate('offline.html'));
|
||||||
writesFuture.push(writer.copyTpl('docs-scenario.html'));
|
|
||||||
writesFuture.push(writer.copyTpl('js/jquery.min.js'));
|
|
||||||
writesFuture.push(writer.copyTpl('js/jquery.js'));
|
|
||||||
|
|
||||||
writesFuture.push(writer.output('js/docs-keywords.js',
|
writesFuture.push(writer.copyTemplate('docs-scenario.html')); // will be rewritten, don't symlink
|
||||||
|
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
|
||||||
|
|
||||||
|
writesFuture.push(writer.output('docs-keywords.js',
|
||||||
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
|
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
|
||||||
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));
|
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));
|
||||||
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
|
|
||||||
writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
|
writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
|
||||||
writesFuture.push(writer.output('appcache.manifest',appCache()));
|
writesFuture.push(writer.output('appcache.manifest',appCache()));
|
||||||
writesFuture.push(writer.copyTpl('.htaccess'));
|
writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/js/docs.js', 'js/docs.js'));
|
writesFuture.push(writer.symlinkTemplate('favicon.ico'));
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/bootstrap.min.css', 'css/bootstrap.min.css'));
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/docs.css', 'css/docs.css'));
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/font-awesome.css', 'css/font-awesome.css'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function now() { return new Date().getTime(); }
|
function now() { return new Date().getTime(); }
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,9 +201,9 @@ Doc.prototype = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
flush();
|
flush();
|
||||||
this.shortName = this.name.split(/[\.:#]/).pop();
|
this.shortName = this.name.split(/[\.:#]/).pop().trim();
|
||||||
this.id = this.id || // if we have an id just use it
|
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.name; // default to name
|
||||||
this.description = this.markdown(this.description);
|
this.description = this.markdown(this.description);
|
||||||
this.example = this.markdown(this.example);
|
this.example = this.markdown(this.example);
|
||||||
|
|
@ -214,23 +214,25 @@ Doc.prototype = {
|
||||||
if (atName) {
|
if (atName) {
|
||||||
var text = trim(atText.join('\n')), match;
|
var text = trim(atText.join('\n')), match;
|
||||||
if (atName == 'param') {
|
if (atName == 'param') {
|
||||||
match = text.match(/^\{([^}=]+)(=)?\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
match = text.match(/^\{([^}]+)\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||||
// 1 12 2 34 4 5 5 6 6 3 7 7
|
// 1 1 23 3 4 4 5 5 2 6 6
|
||||||
if (!match) {
|
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 = {
|
var param = {
|
||||||
name: match[5] || match[4],
|
name: match[4] || match[3],
|
||||||
description:self.markdown(text.replace(match[0], match[7])),
|
description:self.markdown(text.replace(match[0], match[6])),
|
||||||
type: match[1],
|
type: optional ? match[1].substring(0, match[1].length-1) : match[1],
|
||||||
optional: !!match[2],
|
optional: optional,
|
||||||
'default':match[6]
|
'default':match[5]
|
||||||
};
|
};
|
||||||
self.param.push(param);
|
self.param.push(param);
|
||||||
} else if (atName == 'returns' || atName == 'return') {
|
} else if (atName == 'returns' || atName == 'return') {
|
||||||
match = text.match(/^\{([^}=]+)\}\s+(.*)/);
|
match = text.match(/^\{([^}]+)\}\s+(.*)/);
|
||||||
if (!match) {
|
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 = {
|
self.returns = {
|
||||||
type: match[1],
|
type: match[1],
|
||||||
|
|
@ -245,7 +247,7 @@ Doc.prototype = {
|
||||||
} else if(atName == 'property') {
|
} else if(atName == 'property') {
|
||||||
match = text.match(/^\{(\S+)\}\s+(\S+)(\s+(.*))?/);
|
match = text.match(/^\{(\S+)\}\s+(\S+)(\s+(.*))?/);
|
||||||
if (!match) {
|
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({
|
var property = new Doc({
|
||||||
type: match[1],
|
type: match[1],
|
||||||
|
|
@ -270,8 +272,9 @@ Doc.prototype = {
|
||||||
self = this;
|
self = this;
|
||||||
|
|
||||||
dom.h(title(this.name), function() {
|
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') {
|
if (self.ngdoc != 'overview') {
|
||||||
dom.h('Description', self.description, dom.html);
|
dom.h('Description', self.description, dom.html);
|
||||||
}
|
}
|
||||||
|
|
@ -383,40 +386,53 @@ Doc.prototype = {
|
||||||
var self = this;
|
var self = this;
|
||||||
dom.h('Usage', function() {
|
dom.h('Usage', function() {
|
||||||
var restrict = self.restrict || 'AC';
|
var restrict = self.restrict || 'AC';
|
||||||
|
|
||||||
if (restrict.match(/E/)) {
|
if (restrict.match(/E/)) {
|
||||||
dom.text('as element (see ');
|
dom.text('This directive can be used as custom element, but we aware of ');
|
||||||
dom.tag('a', {href:'guide/ie'}, 'IE restrictions');
|
dom.tag('a', {href:'guide/ie'}, 'IE restrictions');
|
||||||
dom.text(')');
|
dom.text('.');
|
||||||
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';
|
if (self.usage) {
|
||||||
dom.text('as attribute');
|
dom.tag('pre', function() {
|
||||||
dom.code(function() {
|
dom.tag('code', function() {
|
||||||
dom.text('<' + element + ' ');
|
dom.text(self.usage);
|
||||||
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 + '>');
|
|
||||||
});
|
});
|
||||||
|
} 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_directiveInfo(dom);
|
||||||
self.html_usage_parameters(dom);
|
self.html_usage_parameters(dom);
|
||||||
|
|
@ -451,12 +467,16 @@ Doc.prototype = {
|
||||||
dom.h('Usage', function() {
|
dom.h('Usage', function() {
|
||||||
dom.h('In HTML Template Binding', function() {
|
dom.h('In HTML Template Binding', function() {
|
||||||
dom.tag('code', function() {
|
dom.tag('code', function() {
|
||||||
dom.text('{{ ');
|
if (self.usage) {
|
||||||
dom.text(self.shortName);
|
dom.text(self.usage);
|
||||||
dom.text('_expression | ');
|
} else {
|
||||||
dom.text(self.shortName);
|
dom.text('{{ ');
|
||||||
self.parameters(dom, ':', true);
|
dom.text(self.shortName);
|
||||||
dom.text(' }}');
|
dom.text('_expression | ');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
self.parameters(dom, ':', true);
|
||||||
|
dom.text(' }}');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -733,7 +753,7 @@ function metadata(docs){
|
||||||
for ( var i = 1; i < path.length; i++) {
|
for ( var i = 1; i < path.length; i++) {
|
||||||
path.splice(i, 1);
|
path.splice(i, 1);
|
||||||
}
|
}
|
||||||
var shortName = path.pop();
|
var shortName = path.pop().trim();
|
||||||
|
|
||||||
if (path.pop() == 'input') {
|
if (path.pop() == 'input') {
|
||||||
shortName = 'input [' + shortName + ']';
|
shortName = 'input [' + shortName + ']';
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ exports.collect = collect;
|
||||||
|
|
||||||
var ngdoc = require('./ngdoc.js'),
|
var ngdoc = require('./ngdoc.js'),
|
||||||
Q = require('qq'),
|
Q = require('qq'),
|
||||||
qfs = require('q-fs');
|
qfs = require('q-fs'),
|
||||||
|
PATH = require('path');
|
||||||
|
|
||||||
var NEW_LINE = /\n\r?/;
|
var NEW_LINE = /\n\r?/;
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ function collect() {
|
||||||
var work2;
|
var work2;
|
||||||
if (file.match(/\.ngdoc$/)) {
|
if (file.match(/\.ngdoc$/)) {
|
||||||
work2 = Q.when(qfs.read(file, 'b'), function(content){
|
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());
|
allDocs.push(new ngdoc.Doc(section + content.toString(),file, 1).parse());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
# current angular version. If this rule matches the appcache-offline.manifest will be served for
|
# current angular version. If this rule matches the appcache-offline.manifest will be served for
|
||||||
# requests to appcache.manifest
|
# 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
|
RewriteEngine on
|
||||||
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
|
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
|
||||||
RewriteRule appcache.manifest appcache-offline.manifest
|
RewriteRule appcache.manifest appcache-offline.manifest
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,11 @@ img.AngularJS-small {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon-cog {
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
/* =============================== */
|
/* =============================== */
|
||||||
|
|
||||||
.form-search .dropdown-menu {
|
.form-search .dropdown-menu {
|
||||||
|
|
@ -81,6 +86,10 @@ img.AngularJS-small {
|
||||||
/* Content */
|
/* Content */
|
||||||
/* =============================== */
|
/* =============================== */
|
||||||
|
|
||||||
|
.improve-docs {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
font-size: .7em;
|
font-size: .7em;
|
||||||
color: #c0c0c0;
|
color: #c0c0c0;
|
||||||
|
|
@ -140,6 +149,11 @@ ul.events > li > h3 {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
display: block;
|
||||||
|
margin: 2em auto;
|
||||||
|
}
|
||||||
|
|
||||||
.diagram {
|
.diagram {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 2em auto;
|
margin: 2em auto;
|
||||||
|
|
@ -170,3 +184,7 @@ ul.events > li > h3 {
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,42 @@
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
<head>
|
<head>
|
||||||
<title>AngularJS Docs E2E Test Runner</title>
|
<title>AngularJS Docs E2E Test Runner</title>
|
||||||
<script type="text/javascript" src="../angular-scenario.js" ng:autotest></script>
|
<script>
|
||||||
<script type="text/javascript" src="docs-scenario.js"></script>
|
var production = location.hostname === 'docs.angularjs.org',
|
||||||
|
headEl = document.head,
|
||||||
|
angularVersion = {
|
||||||
|
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||||
|
stable: '"NG_VERSION_STABLE"'
|
||||||
|
};
|
||||||
|
|
||||||
|
addTag('script', {src: path('angular-scenario.js')}, function() {
|
||||||
|
addTag('script', {src: 'docs-scenario.js'}, function() {
|
||||||
|
angular.scenario.setUpAndRun();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function addTag(name, attributes, callback) {
|
||||||
|
var el = document.createElement(name),
|
||||||
|
attrName;
|
||||||
|
|
||||||
|
for (attrName in attributes) {
|
||||||
|
el.setAttribute(attrName, attributes[attrName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
el.onload = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
headEl.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function path(name) {
|
||||||
|
return production
|
||||||
|
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
|
||||||
|
: '../' + name;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
|
@ -22,8 +22,13 @@
|
||||||
baseUrl = location.href.replace(rUrl, indexFile),
|
baseUrl = location.href.replace(rUrl, indexFile),
|
||||||
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
|
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
|
||||||
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
|
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
|
||||||
|
production = location.hostname === 'docs.angularjs.org',
|
||||||
headEl = document.getElementsByTagName('head')[0],
|
headEl = document.getElementsByTagName('head')[0],
|
||||||
sync = true;
|
sync = true,
|
||||||
|
angularVersion = {
|
||||||
|
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||||
|
stable: '"NG_VERSION_STABLE"'
|
||||||
|
};
|
||||||
|
|
||||||
addTag('base', {href: baseUrl});
|
addTag('base', {href: baseUrl});
|
||||||
addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'});
|
addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'});
|
||||||
|
|
@ -37,9 +42,23 @@
|
||||||
addTag('script', {src: path('angular-bootstrap.js') }, sync);
|
addTag('script', {src: path('angular-bootstrap.js') }, sync);
|
||||||
addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync);
|
addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync);
|
||||||
addTag('script', {src: 'js/docs.js'}, sync);
|
addTag('script', {src: 'js/docs.js'}, sync);
|
||||||
addTag('script', {src: 'js/docs-keywords.js'}, sync);
|
addTag('script', {src: 'docs-keywords.js'}, sync);
|
||||||
|
|
||||||
function path(name) {
|
function path(name) {
|
||||||
|
if (production) {
|
||||||
|
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
|
||||||
|
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
|
||||||
|
angularVersion.stable +
|
||||||
|
'/' +
|
||||||
|
name.replace(/\.js$/, '.min.js');
|
||||||
|
} else {
|
||||||
|
name = 'http://code.angularjs.org/' +
|
||||||
|
angularVersion.stable +
|
||||||
|
'/' +
|
||||||
|
name.replace(/\.js$/, '.min.js');
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js');
|
return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,14 +122,14 @@
|
||||||
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
||||||
<li class="divider-vertical"></li>
|
<li class="divider-vertical"></li>
|
||||||
<li class="dropdown">
|
<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>
|
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li class="disabled"><a href="">Why AngularJS?</a></li>
|
<li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
|
||||||
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
|
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
|
||||||
<li><a href="tutorial">Tutorial</a></li>
|
<li><a href="tutorial">Tutorial</a></li>
|
||||||
<li><a href="https://github.com/angular/angular.js/wiki/Projects-using-AngularJS">Case Studies</a></li>
|
<li><a href="http://builtwith.angularjs.org/">Case Studies</a></li>
|
||||||
<li><a href="misc/faq">FAQ</a></li>
|
<li><a href="misc/faq">FAQ</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -120,16 +139,16 @@
|
||||||
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="tutorial">Tutorial</a></li>
|
<li><a href="http://docs.angularjs.org/tutorial">Tutorial</a></li>
|
||||||
<li><a href="guide/">Developer Guide</a></li>
|
<li><a href="http://docs.angularjs.org/guide/">Developer Guide</a></li>
|
||||||
<li><a href="api/">API Reference</a></li>
|
<li><a href="http://docs.angularjs.org/api/">API Reference</a></li>
|
||||||
<li><a href="misc/contribute">Contribute</a></li>
|
<li><a href="http://docs.angularjs.org/misc/contribute">Contribute</a></li>
|
||||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="divider-vertical"></li>
|
<li class="divider-vertical"></li>
|
||||||
<li class="dropdown">
|
<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>
|
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,17 @@ docsApp.directive.code = function() {
|
||||||
|
|
||||||
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||||
return {
|
return {
|
||||||
template: '<button ng-click="fiddle($event)" class="btn btn-primary pull-right"><i class="icon-pencil icon-white"></i> Edit</button>\n',
|
template: '<div class="btn-group pull-right">' +
|
||||||
|
'<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
|
||||||
|
' <i class="icon-pencil icon-white"></i> Edit<span class="caret"></span>' +
|
||||||
|
'</a>' +
|
||||||
|
'<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>' +
|
||||||
|
'</div>',
|
||||||
scope: true,
|
scope: true,
|
||||||
controller: function($scope, $attrs, openJsFiddle) {
|
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
|
||||||
var sources = {
|
var sources = {
|
||||||
module: $attrs.sourceEdit,
|
module: $attrs.sourceEdit,
|
||||||
deps: read($attrs.sourceEditDeps),
|
deps: read($attrs.sourceEditDeps),
|
||||||
|
|
@ -45,14 +53,19 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||||
$scope.fiddle = function(e) {
|
$scope.fiddle = function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
openJsFiddle(sources);
|
openJsFiddle(sources);
|
||||||
}
|
};
|
||||||
|
$scope.plunkr = function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
openPlunkr(sources);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function read(text) {
|
function read(text) {
|
||||||
var files = [];
|
var files = [];
|
||||||
angular.forEach(text ? text.split(' ') : [], function(refId) {
|
angular.forEach(text ? text.split(' ') : [], function(refId) {
|
||||||
files.push({name: refId.split('-')[0], content: getEmbeddedTemplate(refId)});
|
// refId is index.html-343, so we need to strip the unique ID when exporting the name
|
||||||
|
files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
|
||||||
});
|
});
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +109,7 @@ docsApp.directive.docTutorialReset = function() {
|
||||||
' <ol>\n' +
|
' <ol>\n' +
|
||||||
' <li><p>Reset the workspace to step ' + step + '.</p>' +
|
' <li><p>Reset the workspace to step ' + step + '.</p>' +
|
||||||
' <pre>' + command + '</pre></li>\n' +
|
' <pre>' + command + '</pre></li>\n' +
|
||||||
' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{{docTutorialReset}}/app">angular\'s server</a>.</p></li>\n' +
|
' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-' + step + '/app">Angular\'s server</a>.</p></li>\n' +
|
||||||
' </ol>\n' +
|
' </ol>\n' +
|
||||||
' </div>\n';
|
' </div>\n';
|
||||||
}
|
}
|
||||||
|
|
@ -111,8 +124,6 @@ docsApp.directive.docTutorialReset = function() {
|
||||||
'<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' +
|
'<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' +
|
||||||
tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) +
|
tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) +
|
||||||
tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) +
|
tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) +
|
||||||
tab('Snapshots on Mac/Linux', './goto_step.sh ' + step, 'snapshotUnix', step) +
|
|
||||||
tab('Snapshots on on Windows', './goto_step.bat ' + step, 'snapshotWin', step) +
|
|
||||||
'</div>\n');
|
'</div>\n');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -147,8 +158,49 @@ docsApp.serviceFactory.formPostData = function($document) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angularUrls) {
|
||||||
|
return function(content) {
|
||||||
|
var allFiles = [].concat(content.js, content.css, content.html);
|
||||||
|
var indexHtmlContent = '<!doctype html>\n' +
|
||||||
|
'<html ng-app>\n' +
|
||||||
|
' <head>\n' +
|
||||||
|
' <script src="{{angularJSUrl}}"></script>\n' +
|
||||||
|
'{{scriptDeps}}\n' +
|
||||||
|
' </head>\n' +
|
||||||
|
' <body>\n\n' +
|
||||||
|
'{{indexContents}}' +
|
||||||
|
'\n\n </body>\n' +
|
||||||
|
'</html>\n';
|
||||||
|
var scriptDeps = '';
|
||||||
|
angular.forEach(content.deps, function(file) {
|
||||||
|
if (file.name !== 'angular.js') {
|
||||||
|
scriptDeps += ' <script src="' + file.name + '"></script>\n'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
indexProp = {
|
||||||
|
angularJSUrl: angularUrls['angular.js'],
|
||||||
|
scriptDeps: scriptDeps,
|
||||||
|
indexContents: content.html[0].content
|
||||||
|
};
|
||||||
|
var postData = {};
|
||||||
|
angular.forEach(allFiles, function(file, index) {
|
||||||
|
if (file.content && file.name != 'index.html') {
|
||||||
|
postData['files[' + file.name + ']'] = file.content;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
docsApp.serviceFactory.openJsFiddle = function(templateMerge, formPostData, angularUrls) {
|
||||||
|
|
||||||
docsApp.serviceFactory.openJsFiddle = function(templateMerge, getEmbeddedTemplate, formPostData, angularUrls) {
|
|
||||||
var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
|
var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
|
||||||
CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
|
CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
|
||||||
'{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}',
|
'{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}',
|
||||||
|
|
@ -297,7 +349,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||||
tutorial: 'Tutorial',
|
tutorial: 'Tutorial',
|
||||||
cookbook: 'Examples'
|
cookbook: 'Examples'
|
||||||
};
|
};
|
||||||
$scope.$watch(function() {return $location.path(); }, function(path) {
|
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
|
||||||
// ignore non-doc links which are used in examples
|
// ignore non-doc links which are used in examples
|
||||||
if (DOCS_PATH.test(path)) {
|
if (DOCS_PATH.test(path)) {
|
||||||
var parts = path.split('/'),
|
var parts = path.split('/'),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
var qfs = require('q-fs');
|
var qfs = require('q-fs');
|
||||||
var Q = require('qq');
|
var Q = require('qq');
|
||||||
var OUTPUT_DIR = "build/docs/";
|
var OUTPUT_DIR = 'build/docs/';
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
exports.output = output;
|
exports.output = output;
|
||||||
|
|
@ -17,29 +17,27 @@ function output(file, content) {
|
||||||
};
|
};
|
||||||
|
|
||||||
//recursively create directory
|
//recursively create directory
|
||||||
exports.makeDir = function(path) {
|
exports.makeDir = function(p) {
|
||||||
var parts = path.split(/\//);
|
var parts = p.split(/\//);
|
||||||
var path = ".";
|
var path = ".";
|
||||||
//Sequentially create directories
|
|
||||||
var done = Q.defer();
|
|
||||||
(function createPart() {
|
|
||||||
|
|
||||||
if(!parts.length) {
|
// Recursively rebuild directory structure
|
||||||
done.resolve();
|
return qfs.exists(p).
|
||||||
} else {
|
then(function createPart(exists) {
|
||||||
path += "/" + parts.shift();
|
if(!exists && parts.length) {
|
||||||
qfs.isDirectory(path).then(function(isDir) {
|
path += "/" + parts.shift();
|
||||||
if(!isDir) {
|
return qfs.exists(path).then(function(exists) {
|
||||||
qfs.makeDirectory(path);
|
if (!exists) {
|
||||||
|
return qfs.makeDirectory(path).then(createPart, createPart);
|
||||||
|
} else {
|
||||||
|
return createPart();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
createPart();
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})();
|
|
||||||
return done.promise;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.copyTpl = function(filename) {
|
exports.copyTemplate = function(filename) {
|
||||||
return exports.copy('docs/src/templates/' + filename, filename);
|
return exports.copy('docs/src/templates/' + filename, filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -59,8 +57,28 @@ exports.copy = function(from, to, transform) {
|
||||||
}
|
}
|
||||||
return output(to, content);
|
return output(to, content);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.symlink = symlink;
|
||||||
|
function symlink(from, to, type) {
|
||||||
|
return qfs.exists(to).then(function(exists) {
|
||||||
|
if (!exists) {
|
||||||
|
return qfs.symbolicLink(to, from, type);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.symlinkTemplate = symlinkTemplate;
|
||||||
|
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, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Replace placeholders in content accordingly
|
/* Replace placeholders in content accordingly
|
||||||
* @param content{string} content to be modified
|
* @param content{string} content to be modified
|
||||||
* @param replacements{obj} key and value pairs in which key will be replaced with value in content
|
* @param replacements{obj} key and value pairs in which key will be replaced with value in content
|
||||||
|
|
@ -132,3 +150,4 @@ exports.toString = function toString(obj) {
|
||||||
|
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Personal Log Scenario Runner</title>
|
<title>Personal Log Scenario Runner</title>
|
||||||
|
<meta http-equiv="expires" content="0">
|
||||||
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
||||||
<script type="text/javascript" src="personalLogScenario.js"></script>
|
<script type="text/javascript" src="personalLogScenario.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
21
gen_docs.sh
|
|
@ -1,4 +1,19 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
if [ ! -e gen_docs.disable ]; then
|
|
||||||
./node_modules/.bin/jasmine-node docs/spec --noColor && node docs/src/gen-docs.js
|
JASMINE_NODE='jasmine-node'
|
||||||
|
local_jasmine='./node_modules/.bin/jasmine-node'
|
||||||
|
|
||||||
|
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
|
||||||
|
if [[ -x "$local_jasmine" ]];then
|
||||||
|
JASMINE_NODE="$local_jasmine"
|
||||||
|
else
|
||||||
|
echo 'Could not find a locally or globally installed executable of' \
|
||||||
|
'jasmine-node. Try: `npm install jasmine-node`.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e gen_docs.disable ]]; then
|
||||||
|
echo 'Testing, then building documentation...'
|
||||||
|
"$JASMINE_NODE" docs/spec --noColor && node docs/src/gen-docs.js
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
/* This file reads in list of files from angularFiles.js and generate various jstd config files */
|
|
||||||
|
|
||||||
var fs = require('fs'),
|
|
||||||
angularSrc,
|
|
||||||
angularScenario;
|
|
||||||
|
|
||||||
fs.readFile('angularFiles.js', function(err, data) {
|
|
||||||
eval(data.toString());
|
|
||||||
var prefix = 'server: http://localhost:9876\n\n',
|
|
||||||
prefixScenario = 'server: http://localhost:9877\n\n';
|
|
||||||
|
|
||||||
angularSrc = angularFiles.angularSrc.join('\n- ');
|
|
||||||
angularScenario = angularFiles.angularScenario.join('\n- ');
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver.conf', prefix + combine(angularFiles.jstd,
|
|
||||||
angularFiles.jstdExclude));
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver-modules.conf', prefix + combine(angularFiles.jstdModules));
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver-scenario.conf', prefixScenario +
|
|
||||||
combine(angularFiles.jstdScenario) +
|
|
||||||
'\n\nproxy:\n- {matcher: "*", server: "http://localhost:8000"}');
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver-perf.conf', prefix + combine(angularFiles.jstdPerf,
|
|
||||||
angularFiles.jstdPerfExclude));
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver-jquery.conf', prefix + combine(angularFiles.jstdJquery,
|
|
||||||
angularFiles.jstdJqueryExclude));
|
|
||||||
|
|
||||||
fs.writeFile('./jsTestDriver-coverage.conf', prefix +
|
|
||||||
combine(angularFiles.jstd, angularFiles.jstdExclude) +
|
|
||||||
'\n\nplugin:\n- name: "coverage"\n' +
|
|
||||||
'jar: "lib/jstestdriver/coverage.jar"\n' +
|
|
||||||
'module: "com.google.jstestdriver.coverage.CoverageModule"');
|
|
||||||
});
|
|
||||||
|
|
||||||
function combine(load, exclude) {
|
|
||||||
var fileList = 'load:\n- ' + load.join('\n- ');
|
|
||||||
if (exclude) fileList += ('\n\nexclude:\n- ' + exclude.join('\n- '));
|
|
||||||
|
|
||||||
//Replace placeholders for src list before returning
|
|
||||||
return fileList.replace(/@(.*)/g, function(all, alias) {
|
|
||||||
return angularFiles[alias].join('\n- ');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -16,14 +16,14 @@
|
||||||
/**
|
/**
|
||||||
* @fileoverview A utility to get better currency format pattern.
|
* @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
|
* provides 3 currency representation forms: global, portable and local. Local
|
||||||
* format is the most popular format people use to represent currency in its
|
* format is the most popular format people use to represent currency in its
|
||||||
* circulating country without worrying about how it should be distinguished
|
* circulating country without worrying about how it should be distinguished
|
||||||
* from other currencies. Global format is a formal representation in context
|
* from other currencies. Global format is a formal representation in context
|
||||||
* of multiple currencies in same page, it is ISO 4217 currency code. Portable
|
* 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
|
* 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
|
* media. While at the same time, it should be distinguishable to world's
|
||||||
* popular currencies (like USD, EUR) and currencies somewhat relevant in the
|
* 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
|
* 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
|
* Whether the currency sign should be positioned after the number.
|
||||||
* number.
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.POSITION_FLAG_ = 0x08;
|
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
|
* @private
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.SPACE_FLAG_ = 0x20;
|
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
|
* This function will add tier2 currency support. Be default, only tier1
|
||||||
* (most popular currencies) are supportted. If an application really need
|
* (most popular currencies) are supported. If an application really needs
|
||||||
* to support some of the rarely used currency, it should call this function
|
* to support some of the rarely used currencies, it should call this function
|
||||||
* before any other functions in this namespace.
|
* before any other functions in this namespace.
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.addTier2Support = function() {
|
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
|
* 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
|
* 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
|
* 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
|
* some countries as people normally do not use it. Local currency sign
|
||||||
* alleviate the problem, but also make it a little verbose.
|
* alleviates the problem, but also makes it a little verbose.
|
||||||
*
|
*
|
||||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||||
* @return {string} Global currency pattern string for given currency.
|
* @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 info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||||
var patternNum = info[0];
|
var patternNum = info[0];
|
||||||
if (currencyCode == info[1]) {
|
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 goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
|
||||||
}
|
}
|
||||||
return currencyCode + ' ' +
|
return currencyCode + ' ' +
|
||||||
|
|
@ -104,10 +100,8 @@ goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
|
goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
|
||||||
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
var info = goog.i18n.currency.CurrencyInfo[currencyCode];
|
||||||
if (currencyCode == info[1]) {
|
return (currencyCode == info[1]) ? currencyCode :
|
||||||
return currencyCode;
|
currencyCode + ' ' + info[1];
|
||||||
}
|
|
||||||
return currencyCode + ' ' + info[1];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -128,6 +122,7 @@ goog.i18n.currency.getLocalCurrencyPattern = function(currencyCode) {
|
||||||
/**
|
/**
|
||||||
* Returns local currency sign string for those applications that need to
|
* Returns local currency sign string for those applications that need to
|
||||||
* handle currency sign separately.
|
* handle currency sign separately.
|
||||||
|
*
|
||||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||||
* @return {string} Local currency sign for given currency.
|
* @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
|
* Return portable currency sign string for those applications that need to
|
||||||
* handle currency sign themselves.
|
* handle currency sign themselves.
|
||||||
|
*
|
||||||
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||||
* @return {string} Portable currency sign for given currency.
|
* @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
|
* may want to handle currency sign and currency amount separately. This
|
||||||
* function can be used in such situation to position the currency sign
|
* function can be used in such situations to correctly position the currency
|
||||||
* relative to amount field correctly.
|
* 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.
|
* @param {string} currencyCode ISO-4217 3-letter currency code.
|
||||||
* @return {boolean} true if currency should be positioned before amount field.
|
* @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.
|
* pattern information is encoded in patternNum.
|
||||||
*
|
*
|
||||||
* @param {number} patternNum Encoded pattern number that has
|
* @param {number} patternNum Encoded pattern number that has
|
||||||
* currency pattern information.
|
* 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.
|
* @return {string} currency pattern string.
|
||||||
* @private
|
* @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.
|
* 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>}
|
* @type {!Object.<!Array>}
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.CurrencyInfo = {
|
goog.i18n.currency.CurrencyInfo = {
|
||||||
'AED': [2, '\u062F\u002e\u0625', 'DH'],
|
'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
|
||||||
'ARS': [2, '$', 'AR$'],
|
|
||||||
'AUD': [2, '$', 'AU$'],
|
'AUD': [2, '$', 'AU$'],
|
||||||
'BDT': [2, '\u09F3', 'Tk'],
|
'BDT': [2, '\u09F3', 'Tk'],
|
||||||
'BRL': [2, 'R$', 'R$'],
|
'BRL': [2, 'R$', 'R$'],
|
||||||
'CAD': [2, '$', 'C$'],
|
'CAD': [2, '$', 'C$'],
|
||||||
'CHF': [2, 'Fr.', 'CHF'],
|
'CHF': [2, 'CHF', 'CHF'],
|
||||||
'CLP': [0, '$', 'CL$'],
|
'CLP': [0, '$', 'CL$'],
|
||||||
'CNY': [2, '¥', 'RMB¥'],
|
'CNY': [2, '¥', 'RMB¥'],
|
||||||
'COP': [2, '$', 'COL$'],
|
'COP': [0, '$', 'COL$'],
|
||||||
'CRC': [2, '\u20a1', 'CR₡'],
|
'CRC': [0, '\u20a1', 'CR\u20a1'],
|
||||||
'CUP': [2, '$', '$MN'],
|
'CZK': [2, 'K\u010d', 'K\u010d'],
|
||||||
'CZK': [10, 'Kč', 'Kč'],
|
'DKK': [18, 'kr', 'kr'],
|
||||||
'DKK': [26, 'kr', 'kr'],
|
|
||||||
'DOP': [2, '$', 'RD$'],
|
'DOP': [2, '$', 'RD$'],
|
||||||
'EGP': [2, '£', 'LE'],
|
'EGP': [2, '£', 'LE'],
|
||||||
'EUR': [26, '€', '€'],
|
'EUR': [18, '€', '€'],
|
||||||
'GBP': [2, '£', 'GB£'],
|
'GBP': [2, '£', 'GB£'],
|
||||||
'HKD': [2, '$', 'HK$'],
|
'HKD': [2, '$', 'HK$'],
|
||||||
'ILS': [10, '\u20AA', 'IL₪'],
|
'ILS': [2, '\u20AA', 'IL\u20AA'],
|
||||||
'INR': [2, 'Rs', 'Rs'],
|
'INR': [2, '\u20B9', 'Rs'],
|
||||||
'ISK': [10, 'kr', 'kr'],
|
'ISK': [0, 'kr', 'kr'],
|
||||||
'JMD': [2, '$', 'JA$'],
|
'JMD': [2, '$', 'JA$'],
|
||||||
'JPY': [0, '¥', 'JP¥'],
|
'JPY': [0, '¥', 'JP¥'],
|
||||||
'KRW': [0, '\u20A9', 'KR₩'],
|
'KRW': [0, '\u20A9', 'KR₩'],
|
||||||
'LKR': [2, 'Rs', 'SLRs'],
|
'LKR': [2, 'Rs', 'SLRs'],
|
||||||
'MNT': [2, '\u20AE', 'MN₮'],
|
'MNT': [0, '\u20AE', 'MN₮'],
|
||||||
'MXN': [2, '$', 'Mex$'],
|
'MXN': [2, '$', 'Mex$'],
|
||||||
'MYR': [2, 'RM', 'RM'],
|
'MYR': [2, 'RM', 'RM'],
|
||||||
'NOK': [26, 'kr', 'NOkr'],
|
'NOK': [18, 'kr', 'NOkr'],
|
||||||
'PAB': [2, 'B/.', 'B/.'],
|
'PAB': [2, 'B/.', 'B/.'],
|
||||||
'PEN': [2, 'S/.', 'S/.'],
|
'PEN': [2, 'S/.', 'S/.'],
|
||||||
'PHP': [2, 'P', 'PHP'],
|
'PHP': [2, '\u20B1', 'Php'],
|
||||||
'PKR': [2, 'Rs.', 'PKRs.'],
|
'PKR': [0, 'Rs', 'PKRs.'],
|
||||||
'RUB': [10, 'руб', 'руб'],
|
'RUB': [42, 'руб.', 'руб.'],
|
||||||
'SAR': [2, '\u0633\u002E\u0631', 'SR'],
|
'SAR': [2, 'Rial', 'Rial'],
|
||||||
'SEK': [10, 'kr', 'kr'],
|
'SEK': [2, 'kr', 'kr'],
|
||||||
'SGD': [2, '$', 'S$'],
|
'SGD': [2, '$', 'S$'],
|
||||||
'THB': [2, '\u0e3f', 'THB'],
|
'THB': [2, '\u0e3f', 'THB'],
|
||||||
'TRY': [2, 'YTL', 'YTL'],
|
'TRY': [2, 'TL', 'YTL'],
|
||||||
'TWD': [2, 'NT$', 'NT$'],
|
'TWD': [2, 'NT$', 'NT$'],
|
||||||
'USD': [2, '$', 'US$'],
|
'USD': [2, '$', 'US$'],
|
||||||
'UYU': [2, '$', 'UY$'],
|
'UYU': [2, '$', 'UY$'],
|
||||||
'VND': [10, '\u20AB', 'VN₫'],
|
'VND': [0, '\u20AB', 'VN\u20AB'],
|
||||||
'YER': [2, 'YER', 'YER'],
|
'YER': [0, 'Rial', 'Rial'],
|
||||||
'ZAR': [2, 'R', 'ZAR']
|
'ZAR': [2, 'R', 'ZAR']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -270,116 +309,114 @@ goog.i18n.currency.CurrencyInfo = {
|
||||||
* @type {!Object.<!Array>}
|
* @type {!Object.<!Array>}
|
||||||
*/
|
*/
|
||||||
goog.i18n.currency.CurrencyInfoTier2 = {
|
goog.i18n.currency.CurrencyInfoTier2 = {
|
||||||
'AFN': [18, '\u060b', 'AFN'],
|
'AFN': [16, 'Af.', 'AFN'],
|
||||||
'ALL': [2, 'Lek', 'Lek'],
|
'ALL': [0, 'Lek', 'Lek'],
|
||||||
'AMD': [10, '\u0564\u0580\u002e', 'dram'],
|
'AMD': [0, 'Dram', 'dram'],
|
||||||
'ANG': [2, '\u0083', 'NAƒ'],
|
|
||||||
'AOA': [2, 'Kz', 'Kz'],
|
'AOA': [2, 'Kz', 'Kz'],
|
||||||
'AWG': [2, 'ƒ', 'Afl.'],
|
'ARS': [2, '$', 'AR$'],
|
||||||
'AZN': [2, 'm', 'man'],
|
'AWG': [2, 'Afl.', 'Afl.'],
|
||||||
'BAM': [18, 'КМ', 'KM'],
|
'AZN': [2, 'man.', 'man.'],
|
||||||
|
'BAM': [18, 'KM', 'KM'],
|
||||||
'BBD': [2, '$', 'Bds$'],
|
'BBD': [2, '$', 'Bds$'],
|
||||||
'BGN': [10, '\u043b\u0432', 'лв'],
|
'BGN': [2, 'lev', 'lev'],
|
||||||
'BHD': [3, '\u0628\u002e\u062f\u002e', 'BD'],
|
'BHD': [3, 'din', 'din'],
|
||||||
'BIF': [0, 'FBu', 'FBu'],
|
'BIF': [0, 'FBu', 'FBu'],
|
||||||
'BMD': [2, '$', 'BD$'],
|
'BMD': [2, '$', 'BD$'],
|
||||||
'BND': [2, '$', 'B$'],
|
'BND': [2, '$', 'B$'],
|
||||||
'BOB': [2, 'B$', 'B$'],
|
'BOB': [2, 'Bs', 'Bs'],
|
||||||
'BSD': [2, '$', 'B$'],
|
'BSD': [2, '$', 'BS$'],
|
||||||
'BTN': [2, 'Nu.', 'Nu.'],
|
'BTN': [2, 'Nu.', 'Nu.'],
|
||||||
'BWP': [2, 'P', 'pula'],
|
'BWP': [2, 'P', 'pula'],
|
||||||
'BYR': [0, 'Br', 'Br'],
|
'BYR': [0, 'BYR', 'BYR'],
|
||||||
'BZD': [2, '$', 'BZ$'],
|
'BZD': [2, '$', 'BZ$'],
|
||||||
'CDF': [2, 'F', 'CDF'],
|
'CDF': [2, 'FrCD', 'CDF'],
|
||||||
'CVE': [2, '$', 'Esc'],
|
'CUC': [1, '$', 'CUC$'],
|
||||||
|
'CUP': [2, '$', 'CU$'],
|
||||||
|
'CVE': [2, 'CVE', 'Esc'],
|
||||||
'DJF': [0, 'Fdj', 'Fdj'],
|
'DJF': [0, 'Fdj', 'Fdj'],
|
||||||
'DZD': [2, '\u062f\u062C', 'DA'],
|
'DZD': [2, 'din', 'din'],
|
||||||
'EEK': [10, 'EEK', 'EEK'],
|
|
||||||
'ERN': [2, 'Nfk', 'Nfk'],
|
'ERN': [2, 'Nfk', 'Nfk'],
|
||||||
'ETB': [2, 'Br', 'Br'],
|
'ETB': [2, 'Birr', 'Birr'],
|
||||||
'FJD': [2, '$', 'FJ$'],
|
'FJD': [2, '$', 'FJ$'],
|
||||||
'FKP': [2, '£', 'FK£'],
|
'FKP': [2, '£', 'FK£'],
|
||||||
'GEL': [2, 'GEL', 'GEL'],
|
'GEL': [2, 'GEL', 'GEL'],
|
||||||
'GHS': [2, '\u20B5', 'GHS¢'],
|
'GHS': [2, 'GHS', 'GHS'],
|
||||||
'GIP': [2, '£', 'GI£'],
|
'GIP': [2, '£', 'GI£'],
|
||||||
'GMD': [2, 'D', 'GMD'],
|
'GMD': [2, 'GMD', 'GMD'],
|
||||||
'GNF': [0, 'FG', 'FG'],
|
'GNF': [0, 'FG', 'FG'],
|
||||||
'GTQ': [2, 'Q', 'GTQ'],
|
'GTQ': [2, 'Q', 'GTQ'],
|
||||||
'GYD': [2, '$', 'GY$'],
|
'GYD': [0, '$', 'GY$'],
|
||||||
'HNL': [2, 'L', 'HNL'],
|
'HNL': [2, 'L', 'HNL'],
|
||||||
'HRK': [2, 'kn', 'kn'],
|
'HRK': [2, 'kn', 'kn'],
|
||||||
'HTG': [2, 'G', 'HTG'],
|
'HTG': [2, 'HTG', 'HTG'],
|
||||||
'HUF': [10, 'Ft', 'Ft'],
|
'HUF': [0, 'Ft', 'Ft'],
|
||||||
'IDR': [2, 'Rp', 'Rp'],
|
'IDR': [0, 'Rp', 'Rp'],
|
||||||
'IQD': [3, '\u0639\u062F', 'IQD'],
|
'IQD': [0, 'din', 'IQD'],
|
||||||
'IRR': [2, '\ufdfc', 'IRR'],
|
'IRR': [0, 'Rial', 'IRR'],
|
||||||
'JOD': [3, 'JOD', 'JOD'],
|
'JOD': [3, 'din', 'JOD'],
|
||||||
'KES': [2, 'KSh', 'KSh'],
|
'KES': [2, 'Ksh', 'Ksh'],
|
||||||
'KGS': [2, 'som', 'som'],
|
'KGS': [2, 'KGS', 'KGS'],
|
||||||
'KHR': [10, '\u17DB', 'KHR'],
|
'KHR': [2, 'Riel', 'KHR'],
|
||||||
'KMF': [0, 'KMF', 'KMF'],
|
'KMF': [0, 'CF', 'KMF'],
|
||||||
'KPW': [2, '\u20A9', 'KPW'],
|
'KPW': [0, '\u20A9KP', 'KPW'],
|
||||||
'KWD': [3, '\u062F\u002e\u0643', 'KWD'],
|
'KWD': [3, 'din', 'KWD'],
|
||||||
'KYD': [2, '$', 'CI$'],
|
'KYD': [2, '$', 'KY$'],
|
||||||
'KZT': [10, 'KZT', 'KZT'],
|
'KZT': [2, '\u20B8', 'KZT'],
|
||||||
'LAK': [2, '\u20AD', 'LA₭'],
|
'LAK': [0, '\u20AD', '\u20AD'],
|
||||||
'LBP': [2, '\u0644\u002e\u0644', 'LBP'],
|
'LBP': [0, 'L£', 'LBP'],
|
||||||
'LRD': [2, '$', 'L$'],
|
'LRD': [2, '$', 'L$'],
|
||||||
'LSL': [2, 'L', 'LSL'],
|
'LSL': [2, 'LSL', 'LSL'],
|
||||||
'LTL': [10, 'Lt', 'Lt'],
|
'LTL': [2, 'Lt', 'Lt'],
|
||||||
'LVL': [10, 'Ls', 'Ls'],
|
'LVL': [2, 'Ls', 'Ls'],
|
||||||
'LYD': [3, '\u0644\u002e\u062F', 'LD'],
|
'LYD': [3, 'din', 'LD'],
|
||||||
'MAD': [2, '\u0645\u002E\u062F\u002E', 'MAD'],
|
'MAD': [2, 'dh', 'MAD'],
|
||||||
'MDL': [2, 'MDL', 'MDL'],
|
'MDL': [2, 'MDL', 'MDL'],
|
||||||
'MGA': [1, 'MGA', 'MGA'],
|
'MGA': [0, 'Ar', 'MGA'],
|
||||||
'MKD': [2, 'MKD', 'MKD'],
|
'MKD': [2, 'din', 'MKD'],
|
||||||
'MMK': [2, 'K', 'MMK'],
|
'MMK': [0, 'K', 'MMK'],
|
||||||
'MOP': [2, 'MOP$', 'MOP$'],
|
'MOP': [2, 'MOP', 'MOP$'],
|
||||||
'MRO': [1, 'UM', 'UM'],
|
'MRO': [0, 'MRO', 'MRO'],
|
||||||
'MUR': [2, 'Rs', 'MURs'],
|
'MUR': [0, 'MURs', 'MURs'],
|
||||||
'MVR': [2, 'Rf', 'MRF'],
|
'MWK': [2, 'MWK', 'MWK'],
|
||||||
'MWK': [2, 'MK', 'MK'],
|
|
||||||
'MZN': [2, 'MTn', 'MTn'],
|
'MZN': [2, 'MTn', 'MTn'],
|
||||||
'NAD': [2, '$', 'N$'],
|
'NAD': [2, '$', 'N$'],
|
||||||
'NGN': [2, '\u20A6', 'NG₦'],
|
'NGN': [2, '\u20A6', 'NG\u20A6'],
|
||||||
'NIO': [2, 'C$', 'C$'],
|
'NIO': [2, 'C$', 'C$'],
|
||||||
'NPR': [2, 'Rs', 'NPRs'],
|
'NPR': [2, 'Rs', 'NPRs'],
|
||||||
'NZD': [2, '$', 'NZ$'],
|
'NZD': [2, '$', 'NZ$'],
|
||||||
'OMR': [3, '\u0639\u002E\u062F\u002E', 'OMR'],
|
'OMR': [3, 'Rial', 'OMR'],
|
||||||
'PGK': [2, 'K', 'PGK'],
|
'PGK': [2, 'PGK', 'PGK'],
|
||||||
'PLN': [10, 'zł', 'zł'],
|
'PLN': [2, 'z\u0142', 'z\u0142'],
|
||||||
'PYG': [0, '\u20b2', 'PYG'],
|
'PYG': [0, 'Gs', 'PYG'],
|
||||||
'QAR': [2, '\u0642\u002E\u0631', 'QR'],
|
'QAR': [2, 'Rial', 'QR'],
|
||||||
'RON': [2, 'L', 'RON'],
|
'RON': [2, 'RON', 'RON'],
|
||||||
'RSD': [2, 'РС\u0414', 'RSD'],
|
'RSD': [0, 'din', 'RSD'],
|
||||||
'RWF': [0, 'RF', 'RF'],
|
'RWF': [0, 'RF', 'RF'],
|
||||||
'SBD': [2, '$', 'SI$'],
|
'SBD': [2, '$', 'SI$'],
|
||||||
'SCR': [2, 'SR', 'SCR'],
|
'SCR': [2, 'SCR', 'SCR'],
|
||||||
'SDG': [2, 'SDG', 'SDG'],
|
'SDG': [2, 'SDG', 'SDG'],
|
||||||
'SHP': [2, '£', 'SH£'],
|
'SHP': [2, '£', 'SH£'],
|
||||||
'SKK': [10, 'Sk', 'Sk'],
|
'SLL': [0, 'SLL', 'SLL'],
|
||||||
'SLL': [2, 'Le', 'Le'],
|
'SOS': [0, 'SOS', 'SOS'],
|
||||||
'SOS': [2, 'So. Sh.', 'So. Sh.'],
|
|
||||||
'SRD': [2, '$', 'SR$'],
|
'SRD': [2, '$', 'SR$'],
|
||||||
'STD': [2, 'Db', 'Db'],
|
'STD': [0, 'Db', 'Db'],
|
||||||
'SYP': [18, 'SYP', 'SYP'],
|
'SYP': [16, '£', 'SY£'],
|
||||||
'SZL': [2, 'L', 'SZL'],
|
'SZL': [2, 'SZL', 'SZL'],
|
||||||
'TJS': [2, 'TJS', 'TJS'],
|
'TJS': [2, 'Som', 'TJS'],
|
||||||
'TMM': [2, 'm', 'TMM'],
|
'TND': [3, 'din', 'DT'],
|
||||||
'TND': [3, '\u062F\u002e\u062A ', 'DT'],
|
|
||||||
'TOP': [2, 'T$', 'T$'],
|
'TOP': [2, 'T$', 'T$'],
|
||||||
'TTD': [2, '$', 'TT$'],
|
'TTD': [2, '$', 'TT$'],
|
||||||
'TZS': [10, 'TZS', 'TZS'],
|
'TZS': [0, 'TSh', 'TSh'],
|
||||||
'UAH': [10, '\u20B4', 'грн'],
|
'UAH': [2, '\u20B4', 'UAH'],
|
||||||
'UGX': [2, 'USh', 'USh'],
|
'UGX': [0, 'UGX', 'UGX'],
|
||||||
'UZS': [2, 'UZS', 'UZS'],
|
'UYU': [1, '$', '$U'],
|
||||||
'VEF': [2, 'Bs.F', 'Bs.F'],
|
'UZS': [0, 'so\u02bcm', 'UZS'],
|
||||||
'VUV': [0, 'Vt', 'Vt'],
|
'VEF': [2, 'Bs', 'Bs'],
|
||||||
'WST': [2, 'WS$', 'WS$'],
|
'VUV': [0, 'VUV', 'VUV'],
|
||||||
|
'WST': [2, 'WST', 'WST'],
|
||||||
'XAF': [0, 'FCFA', 'FCFA'],
|
'XAF': [0, 'FCFA', 'FCFA'],
|
||||||
'XCD': [2, '$', 'EC$'],
|
'XCD': [2, '$', 'EC$'],
|
||||||
'XOF': [0, 'CFA', 'CFA'],
|
'XOF': [0, 'CFA', 'CFA'],
|
||||||
'XPF': [0, 'F', 'XPF'],
|
'XPF': [0, 'FCFP', 'FCFP'],
|
||||||
'ZMK': [2, 'ZK', 'ZK'],
|
'ZMK': [0, 'ZMK', 'ZMK']
|
||||||
'ZWL': [2, '$', 'ZW$']
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||