Compare commits
192 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet editPageId="org.eclipse.ui.resourceWorkingSetPage" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1262905463390_2" label="workingSet" name="workingSet"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/test" type="2"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/src" type="2"/> </launchConfigurationWorkingSet>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/perf" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/perf.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/build" type="2"/> </resources>}"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/lib/jsl/jsl}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-conf lib/jsl/jsl.default.conf"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,14 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
@@ -10,6 +10,5 @@ performance/temp*.html
|
||||
*~
|
||||
angular.js.tmproj
|
||||
node_modules
|
||||
jsTestDriver*.conf
|
||||
angular.xcodeproj
|
||||
.idea
|
||||
|
||||
@@ -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
@@ -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 testacular@canary
|
||||
- rake package
|
||||
- ./nodeserver.sh > /dev/null &
|
||||
|
||||
script:
|
||||
- rake test[Firefox,"--reporters=dots"]
|
||||
+317
-2
@@ -1,9 +1,326 @@
|
||||
<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))
|
||||
- **$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))
|
||||
- **ngResource:** correct leading slash removal.
|
||||
([b2f46251](https://github.com/angular/angular.js/commit/b2f46251aca76c8568ee7d4bab54edbc9d7a186a))
|
||||
- **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
|
||||
@@ -17,8 +334,6 @@ _Note: 1.1.x releases unlike 1.0.x are considered unstable.
|
||||
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
|
||||
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
|
||||
|
||||
This release also contains all bug fixes available in [1.0.2](#1.0.2).
|
||||
|
||||
|
||||
|
||||
<a name="1.0.2"></a>
|
||||
|
||||
@@ -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
|
||||
@@ -1,11 +1,11 @@
|
||||
AngularJS
|
||||
=========
|
||||
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets use
|
||||
good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
||||
AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you
|
||||
use good old HTML (or HAML, Jade and friends!) as your template language and lets you extend HTML’s
|
||||
syntax to express your application’s components clearly and succinctly. It automatically
|
||||
synchronizes data from your UI (view) with your JavaScript objects (model) through 2-way data
|
||||
binding. To help you structure your application better and make it easy to test AngularJS teaches
|
||||
binding. To help you structure your application better and make it easy to test, AngularJS teaches
|
||||
the browser how to do dependency injection and inversion of control. Oh yeah and it also helps with
|
||||
server-side communication, taming async callbacks with promises and deferreds; and make client-side
|
||||
navigation and deeplinking with hashbang urls or HTML5 pushState a piece of cake. The best of all:
|
||||
@@ -13,17 +13,33 @@ it makes development fun!
|
||||
|
||||
* Web site: http://angularjs.org
|
||||
* 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
|
||||
* 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:
|
||||
|
||||
rake package
|
||||
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
./server.sh # start the server
|
||||
open http://localhost:9876/capture # capture browser
|
||||
./test.sh # run all unit tests
|
||||
Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
|
||||
|
||||
sudo npm install -g testacular
|
||||
|
||||
To execute all unit tests, use:
|
||||
|
||||
rake test:unit
|
||||
|
||||
To execute end-to-end (e2e) tests, use:
|
||||
|
||||
rake package
|
||||
rake webserver &
|
||||
rake test:e2e
|
||||
|
||||
To learn more about the rake tasks, run `rake -T` and also read our
|
||||
[contribution guidelines](http://docs.angularjs.org/misc/contribute) and instructions in this
|
||||
[commit message](https://github.com/angular/angular.js/commit/9d168f058f9c6d7eeae0daa7cb72ea4e02a0003a).
|
||||
|
||||
@@ -40,6 +40,7 @@ desc 'Clean Generated Files'
|
||||
task :clean do
|
||||
FileUtils.rm_r(BUILD_DIR, :force => true)
|
||||
FileUtils.mkdir(BUILD_DIR)
|
||||
FileUtils.rm_r('test_out', :force => true)
|
||||
end
|
||||
|
||||
|
||||
@@ -123,8 +124,26 @@ task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter
|
||||
'angular-bootstrap.js',
|
||||
'angular-bootstrap-prettify.js'
|
||||
].each do |file|
|
||||
closure_compile(file)
|
||||
unless ENV['TRAVIS']
|
||||
fork { closure_compile(file) }
|
||||
else
|
||||
closure_compile(file)
|
||||
end
|
||||
end
|
||||
|
||||
Process.waitall
|
||||
end
|
||||
|
||||
|
||||
desc 'Generate version.txt and version.json files'
|
||||
task :version => [:init] do
|
||||
`echo #{NG_VERSION.full} > #{path_to('version.txt')}`
|
||||
`echo '{
|
||||
"full": "#{NG_VERSION.full}",
|
||||
"major": "#{NG_VERSION.major}",
|
||||
"minor": "#{NG_VERSION.minor}",
|
||||
"dot": "#{NG_VERSION.dot}",
|
||||
"codename": "#{NG_VERSION.codename}"\n}' > #{path_to('version.json')}`
|
||||
end
|
||||
|
||||
|
||||
@@ -150,7 +169,7 @@ end
|
||||
|
||||
|
||||
desc 'Create angular distribution'
|
||||
task :package => [:clean, :minify, :docs] do
|
||||
task :package => [:clean, :minify, :version, :docs] do
|
||||
zip_dir = "angular-#{NG_VERSION.full}"
|
||||
zip_file = "#{zip_dir}.zip"
|
||||
|
||||
@@ -164,37 +183,74 @@ task :package => [:clean, :minify, :docs] do
|
||||
end
|
||||
|
||||
|
||||
namespace :server do
|
||||
desc 'Start development webserver'
|
||||
task :webserver, :port do |t, args|
|
||||
exec "node lib/nodeserver/server.js #{args[:port]}"
|
||||
end
|
||||
|
||||
desc 'Run JsTestDriver Server'
|
||||
task :start do
|
||||
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
|
||||
|
||||
desc 'Run all AngularJS tests'
|
||||
task :test, :browsers, :misc_options do |t, args|
|
||||
[ 'test:jqlite',
|
||||
'test:jquery',
|
||||
'test:modules',
|
||||
'test:e2e'
|
||||
].each do |task|
|
||||
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
namespace :test do
|
||||
|
||||
desc 'Run all unit tests (single run)'
|
||||
task :unit, :browsers, :misc_options do |t, args|
|
||||
[ 'test:jqlite',
|
||||
'test:jquery',
|
||||
'test:modules'
|
||||
].each do |task|
|
||||
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Run JavaScript tests against the server'
|
||||
task :test do
|
||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
|
||||
|
||||
desc 'Run jqLite-based unit test suite (single run)'
|
||||
task :jqlite, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jqlite.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run jQuery-based unit test suite (single run)'
|
||||
task :jquery, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jquery.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run bundled modules unit test suite (single run)'
|
||||
task :modules, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-modules.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc 'Run e2e test suite (single run)'
|
||||
task :e2e, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-e2e.conf.js', true, args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'Run JavaScript tests'
|
||||
task :test do
|
||||
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
|
||||
end
|
||||
namespace :autotest do
|
||||
|
||||
desc 'Run jqLite-based unit test suite (autowatch)'
|
||||
task :jqlite, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jqlite.conf.js', false, args[:browsers], args[:misc_options])
|
||||
end
|
||||
|
||||
|
||||
desc '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)
|
||||
desc 'Run jQuery-based unit test suite (autowatch)'
|
||||
task :jquery, :browsers, :misc_options do |t, args|
|
||||
start_testacular('testacular-jquery.conf.js', false, args[:browsers], args[:misc_options])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -240,12 +296,23 @@ def path_to(filename)
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# returns the 32-bit mode force flags for java compiler if supported, this makes the build much
|
||||
# faster
|
||||
#
|
||||
def java32flags
|
||||
return '-d32 -client' unless Rake::Win32.windows? || `java -version -d32 2>&1`.match(/Error/i)
|
||||
end
|
||||
|
||||
|
||||
def closure_compile(filename)
|
||||
puts "Minifying #{filename} ..."
|
||||
|
||||
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
|
||||
|
||||
%x(java -jar lib/closure-compiler/compiler.jar \
|
||||
%x(java \
|
||||
#{java32flags()} \
|
||||
-jar lib/closure-compiler/compiler.jar \
|
||||
--compilation_level SIMPLE_OPTIMIZATIONS \
|
||||
--language_in ECMASCRIPT5_STRICT \
|
||||
--js #{path_to(filename)} \
|
||||
@@ -296,3 +363,12 @@ def rewrite_file(filename)
|
||||
f.write content
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def start_testacular(config, singleRun, browsers, misc_options)
|
||||
sh "./node_modules/testacular/bin/testacular start " +
|
||||
"#{config} " +
|
||||
"#{'--single-run=true' if singleRun} " +
|
||||
"#{'--browsers=' + browsers.gsub('+', ',') if browsers} " +
|
||||
"#{(misc_options || '').gsub('+', ',')}"
|
||||
end
|
||||
|
||||
Vendored
+24
-31
@@ -79,7 +79,6 @@ angularFiles = {
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Future.js',
|
||||
'src/ngScenario/ObjectModel.js',
|
||||
'src/ngScenario/Describe.js',
|
||||
'src/ngScenario/Runner.js',
|
||||
'src/ngScenario/SpecRunner.js',
|
||||
'src/ngScenario/dsl.js',
|
||||
@@ -196,36 +195,30 @@ angularFiles = {
|
||||
]
|
||||
};
|
||||
|
||||
// Execute only in slim-jim
|
||||
if (typeof JASMINE_ADAPTER !== 'undefined') {
|
||||
// Testacular config
|
||||
var mergedFiles = [];
|
||||
angularFiles.jstd.forEach(function(file) {
|
||||
// replace @ref
|
||||
var match = file.match(/^\@(.*)/);
|
||||
if (match) {
|
||||
var deps = angularFiles[match[1]];
|
||||
if (!deps) {
|
||||
console.log('No dependency:' + file)
|
||||
if (exports) {
|
||||
exports.files = angularFiles
|
||||
exports.mergeFiles = function mergeFiles() {
|
||||
var files = [];
|
||||
|
||||
[].splice.call(arguments, 0).forEach(function(file) {
|
||||
if (file.match(/testacular/)) {
|
||||
files.push(file);
|
||||
} else {
|
||||
angularFiles[file].forEach(function(f) {
|
||||
// replace @ref
|
||||
var match = f.match(/^\@(.*)/);
|
||||
if (match) {
|
||||
var deps = angularFiles[match[1]];
|
||||
files = files.concat(deps);
|
||||
} else {
|
||||
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
|
||||
files.push(f);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
mergedFiles = mergedFiles.concat(deps);
|
||||
} else {
|
||||
mergedFiles.push(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
files = [JASMINE, JASMINE_ADAPTER];
|
||||
|
||||
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;
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+27
-22
@@ -36,16 +36,15 @@ var parseRawCommit = function(raw) {
|
||||
msg.breaks = [];
|
||||
|
||||
lines.forEach(function(line) {
|
||||
match = line.match(/Closes\s#(\d+)/);
|
||||
match = line.match(/(?:Closes|Fixes)\s#(\d+)/);
|
||||
if (match) msg.closes.push(parseInt(match[1]));
|
||||
});
|
||||
|
||||
|
||||
match = raw.match(/BREAKING CHANGE:([\s\S]*)/);
|
||||
if (match) {
|
||||
console.log('found!!!')
|
||||
msg.breaks.push(match[1]);
|
||||
msg.breaking = match[1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
msg.body = lines.join('\n');
|
||||
match = msg.subject.match(/^(.*)\((.*)\)\:\s(.*)$/);
|
||||
@@ -88,7 +87,8 @@ var currentDate = function() {
|
||||
};
|
||||
|
||||
|
||||
var printSection = function(stream, title, section) {
|
||||
var printSection = function(stream, title, section, printCommitLinks) {
|
||||
printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks;
|
||||
var components = Object.getOwnPropertyNames(section).sort();
|
||||
|
||||
if (!components.length) return;
|
||||
@@ -109,11 +109,15 @@ var printSection = function(stream, title, section) {
|
||||
}
|
||||
|
||||
section[name].forEach(function(commit) {
|
||||
stream.write(util.format('%s %s (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||
if (commit.closes.length) {
|
||||
stream.write(', closes ' + commit.closes.map(linkToIssue).join(', '));
|
||||
if (printCommitLinks) {
|
||||
stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash)));
|
||||
if (commit.closes.length) {
|
||||
stream.write(',\n ' + commit.closes.map(linkToIssue).join(', '));
|
||||
}
|
||||
stream.write(')\n');
|
||||
} else {
|
||||
stream.write(util.format('%s %s', prefix, commit.subject));
|
||||
}
|
||||
stream.write(')\n');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -122,7 +126,7 @@ var printSection = function(stream, title, section) {
|
||||
|
||||
|
||||
var readGitLog = function(grep, from) {
|
||||
var deffered = q.defer();
|
||||
var deferred = q.defer();
|
||||
|
||||
// TODO(vojta): if it's slow, use spawn and stream it instead
|
||||
child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) {
|
||||
@@ -133,10 +137,10 @@ var readGitLog = function(grep, from) {
|
||||
if (commit) commits.push(commit);
|
||||
});
|
||||
|
||||
deffered.resolve(commits);
|
||||
deferred.resolve(commits);
|
||||
});
|
||||
|
||||
return deffered.promise;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
@@ -158,29 +162,30 @@ var writeChangelog = function(stream, commits, version) {
|
||||
section[component].push(commit);
|
||||
}
|
||||
|
||||
commit.breaks.forEach(function(breakMsg) {
|
||||
sections.breaks[EMPTY_COMPONENT].push({
|
||||
subject: breakMsg,
|
||||
if (commit.breaking) {
|
||||
sections.breaks[component] = sections.breaks[component] || [];
|
||||
sections.breaks[component].push({
|
||||
subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking),
|
||||
hash: commit.hash,
|
||||
closes: []
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
stream.write(util.format(HEADER_TPL, version, version, currentDate()));
|
||||
printSection(stream, 'Bug Fixes', sections.fix);
|
||||
printSection(stream, 'Features', sections.feat);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks);
|
||||
printSection(stream, 'Breaking Changes', sections.breaks, false);
|
||||
}
|
||||
|
||||
|
||||
var getPreviousTag = function() {
|
||||
var deffered = q.defer();
|
||||
var deferred = q.defer();
|
||||
child.exec(GIT_TAG_CMD, function(code, stdout, stderr) {
|
||||
if (code) deffered.reject('Cannot get the previous tag.');
|
||||
else deffered.resolve(stdout.replace('\n', ''));
|
||||
if (code) deferred.reject('Cannot get the previous tag.');
|
||||
else deferred.resolve(stdout.replace('\n', ''));
|
||||
});
|
||||
return deffered.promise;
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -34,10 +34,10 @@ describe('changelog.js', function() {
|
||||
'13f31602f396bc269076ab4d389cfd8ca94b20ba\n' +
|
||||
'feat(ng-list): Allow custom separator\n' +
|
||||
'bla bla bla\n\n' +
|
||||
'Breaks first breaking change\nsomething else\n' +
|
||||
'Breaks another breaking change\n');
|
||||
'BREAKING CHANGE: first breaking change\nsomething else\n' +
|
||||
'another line with more info\n');
|
||||
|
||||
expect(msg.breaks).toEqual(['first breaking change', 'another breaking change']);
|
||||
expect(msg.breaking).toEqual(' first breaking change\nsomething else\nanother line with more info\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
rake compile
|
||||
rake minify
|
||||
gzip -c < build/angular.min.js > build/angular.min.js.gzip
|
||||
ls -l build/angular.min.*
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
@description
|
||||
|
||||
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}.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
External resources are URLs that provide JSON data, which are then rendered with the help of
|
||||
templates. angular has a resource factory that can be used to give names to the URLs and then
|
||||
templates. Angular has a resource factory that can be used to give names to the URLs and then
|
||||
attach behavior to them. For example you can use the
|
||||
{@link http://code.google.com/apis/buzz/v1/getting_started.html#background-operations| Google Buzz
|
||||
API}
|
||||
@@ -21,12 +21,12 @@ to retrieve Buzz activity and comments.
|
||||
{ get: {method: 'JSONP', params: {visibility: '@self'}},
|
||||
replies: {method: 'JSONP', params: {visibility: '@self', comments: '@comments'}}
|
||||
});
|
||||
}
|
||||
BuzzController.prototype = {
|
||||
fetch: function() {
|
||||
|
||||
$scope.fetch = function() {
|
||||
$scope.activities = $scope.Activity.get({userId:this.userId});
|
||||
},
|
||||
expandReplies: function(activity) {
|
||||
}
|
||||
|
||||
$scope.expandReplies = function(activity) {
|
||||
activity.replies = $scope.Activity.replies({userId: this.userId, activityId: activity.id});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Deep linking allows you to encode the state of the application in the URL so that it can be
|
||||
bookmarked and the application can be restored from the URL to the same state.
|
||||
|
||||
While angular does not force you to deal with bookmarks in any particular way, it has services
|
||||
While Angular does not force you to deal with bookmarks in any particular way, it has services
|
||||
which make the common case described here very easy to implement.
|
||||
|
||||
# Assumptions
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook: Form
|
||||
@description
|
||||
|
||||
A web application's main purpose is to present and gather data. For this reason angular strives
|
||||
A web application's main purpose is to present and gather data. For this reason Angular strives
|
||||
to make both of these operations trivial. This example shows off how you can build a simple form to
|
||||
allow a user to enter data.
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
|
||||
Take a look through the source and note:
|
||||
|
||||
* The script tag that {@link guide/bootstrap bootstraps} the angular environment.
|
||||
* The script tag that {@link guide/bootstrap bootstraps} the Angular environment.
|
||||
* The text {@link api/ng.directive:input input form control} which is
|
||||
bound to the greeting name text.
|
||||
* No need for listener registration and event firing on change events.
|
||||
* There is no need for listener registration and event firing on change events.
|
||||
* The implicit presence of the `name` variable which is in the root {@link api/ng.$rootScope.Scope scope}.
|
||||
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
|
||||
* The concept of {@link guide/dev_guide.templates.databinding data binding}, which reflects any
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook
|
||||
@description
|
||||
|
||||
Welcome to the angular cookbook. Here we will show you typical uses of angular by example.
|
||||
Welcome to the Angular cookbook. Here we will show you typical uses of Angular by example.
|
||||
|
||||
|
||||
# Hello World
|
||||
@@ -45,7 +45,7 @@ allowing you to send links to specific screens in your app.
|
||||
# Services
|
||||
|
||||
{@link api/ng Services}: Services are long lived objects in your applications that are
|
||||
available across controllers. A collection of useful services are pre-bundled with angular but you
|
||||
available across controllers. A collection of useful services are pre-bundled with Angular but you
|
||||
will likely add your own. Services are initialized using dependency injection, which resolves the
|
||||
order of initialization. This safeguards you from the perils of global state (a common way to
|
||||
implement long lived objects).
|
||||
@@ -55,4 +55,4 @@ implement long lived objects).
|
||||
|
||||
{@link buzz Resources}: Web applications must be able to communicate with the external
|
||||
services to get and update data. Resources are the abstractions of external URLs which are
|
||||
specially tailored to angular data binding.
|
||||
specially tailored to Angular data binding.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@name Cookbook: MVC
|
||||
@description
|
||||
|
||||
MVC allows for a clean an testable separation between the behavior (controller) and the view
|
||||
MVC allows for a clean and testable separation between the behavior (controller) and the view
|
||||
(HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
|
||||
view. This makes it very easy for the controller and the view to share the model.
|
||||
|
||||
@@ -115,7 +115,7 @@ view.
|
||||
# Things to notice
|
||||
|
||||
* The controller is defined in JavaScript and has no reference to the rendering logic.
|
||||
* The controller is instantiated by <angular/> and injected into the view.
|
||||
* The controller is instantiated by Angular and injected into the view.
|
||||
* The controller can be instantiated in isolation (without a view) and the code will still execute.
|
||||
This makes it very testable.
|
||||
* The HTML view is a projection of the model. In the above example, the model is stored in the
|
||||
|
||||
@@ -9,7 +9,7 @@ browser new HTML syntax. The compiler allows you to attach behavior to any HTML
|
||||
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
|
||||
extensions {@link api/ng.$compileProvider#directive directives}.
|
||||
|
||||
HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion.
|
||||
HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion.
|
||||
For example if something needs to be centered, there is no need to provide instructions to the
|
||||
browser how the window size needs to be divided in half so that center is found, and that this
|
||||
center needs to be aligned with the text's center. Simply add `align="center"` attribute to any
|
||||
@@ -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
|
||||
scope model are reflected in the view, and any user interactions with the view are reflected
|
||||
in the scope model. Making the scope model a single source of truth.
|
||||
in the scope model. This makes the scope model the single source of truth.
|
||||
|
||||
Some directives such {@link api/ng.directive:ngRepeat
|
||||
`ng-repeat`} clone DOM elements once for each item in collection. Having a compile and link phase
|
||||
@@ -47,9 +47,9 @@ once for each clone instance.
|
||||
|
||||
# Directive
|
||||
|
||||
Directive is a behavior which should be triggered when specific HTML constructs are encountered in
|
||||
compilation process. The directives can be placed in element names, attributes, class names, as
|
||||
well as comments. Here are some equivalent examples of invoking {@link
|
||||
A directive is a behavior which should be triggered when specific HTML constructs are encountered in
|
||||
the compilation process. The directives can be placed in element names, attributes, class names, as
|
||||
well as comments. Here are some equivalent examples of invoking the {@link
|
||||
api/ng.directive:ngBind `ng-bind`} directive.
|
||||
|
||||
<pre>
|
||||
@@ -59,7 +59,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
|
||||
<!-- directive: ng-bind exp -->
|
||||
</pre>
|
||||
|
||||
Directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
||||
A directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
||||
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
|
||||
to write directives.
|
||||
|
||||
@@ -107,9 +107,9 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
||||
</example>
|
||||
|
||||
|
||||
The presence of `draggable` attribute on any element gives the element new behavior. The beauty of
|
||||
The presence of the `draggable` attribute on any element gives the element new behavior. The beauty of
|
||||
this approach is that we have taught the browser a new trick. We have extended the vocabulary of
|
||||
what the browser understands in a way, which is natural to anyone who is familiar with HTML
|
||||
what the browser understands in a way which is natural to anyone who is familiar with HTML
|
||||
principles.
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ an element.
|
||||
<img src="img/One_Way_Data_Binding.png">
|
||||
|
||||
This means that any changes to the data need to be re-merged with the template and then
|
||||
`innerHTML`ed into the DOM. Some of the issues are: reading user input and merging it with data,
|
||||
`innerHTML`ed into the DOM. Some of the issues with this approach are: reading user input and merging it with data,
|
||||
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
|
||||
expressiveness.
|
||||
|
||||
|
||||
@@ -26,20 +26,20 @@ This is how we get the ball rolling (refer to the diagram and example below):
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
|
||||
|
||||
1. Browser loads the HTML and parses it into a DOM
|
||||
2. Browser loads `angular.js` script
|
||||
1. The browser loads the HTML and parses it into a DOM
|
||||
2. The browser loads `angular.js` script
|
||||
3. Angular waits for `DOMContentLoaded` event
|
||||
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
|
||||
{@link guide/directive directive}, which designates application boundary
|
||||
5. {@link guide/module Module} specified in {@link
|
||||
api/ng.directive:ngApp ng-app} (if any) is used to configure
|
||||
{@link guide/directive directive}, which designates the application boundary
|
||||
5. The {@link guide/module Module} specified in {@link
|
||||
api/ng.directive:ngApp ng-app} (if any) is used to configure
|
||||
the {@link api/AUTO.$injector $injector}
|
||||
6. {@link api/AUTO.$injector $injector} is used to create the {@link
|
||||
6. The {@link api/AUTO.$injector $injector} is used to create the {@link
|
||||
api/ng.$compile $compile} service as well as {@link
|
||||
api/ng.$rootScope $rootScope}
|
||||
7. {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||
7. The {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||
it with {@link api/ng.$rootScope $rootScope}
|
||||
8. {@link api/ng.directive:ngInit ng-init} {@link
|
||||
8. The {@link api/ng.directive:ngInit ng-init} {@link
|
||||
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
|
||||
scope}
|
||||
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
|
||||
@@ -59,29 +59,29 @@ This is how we get the ball rolling (refer to the diagram and example below):
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
|
||||
|
||||
The diagram and the example below describe how Angular interacts with browser's event loop.
|
||||
The diagram and the example below describe how Angular interacts with the browser's event loop.
|
||||
|
||||
1. Browsers event-loop waits for an event to arrive. Event is a user interactions, timer event,
|
||||
1. The browser's event-loop waits for an event to arrive. An event is a user interactions, timer event,
|
||||
or network event (response from a server).
|
||||
2. The events callback gets executed. This enters the JavaScript context. The callback can
|
||||
2. The event's callback gets executed. This enters the JavaScript context. The callback can
|
||||
modify the DOM structure.
|
||||
3. Once the callback finishes execution, the browser leaves the JavaScript context and
|
||||
3. Once the callback executes, the browser leaves the JavaScript context and
|
||||
re-renders the view based on DOM changes.
|
||||
|
||||
Angular modifies the normal JavaScript flow by providing it's own event processing loop. This
|
||||
Angular modifies the normal JavaScript flow by providing its own event processing loop. This
|
||||
splits the JavaScript into classical and Angular execution context. Only operations which are
|
||||
applied in Angular execution context will benefit from angular data-binding, exception handling,
|
||||
property watching, etc... Use $apply() to enter Angular execution context from JavaScript. Keep in
|
||||
mind that in most places (controllers, services) the $apply has already been called for you by the
|
||||
directive which is handling the event. The need to call $apply is reserved only when
|
||||
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
|
||||
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
|
||||
@@ -89,14 +89,14 @@ implementing custom event callbacks, or when working with a third-party library
|
||||
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
|
||||
$watch} list does not detect any changes.
|
||||
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
|
||||
schedule work which needs to occur outside of current stack frame, but before the browser
|
||||
schedule work which needs to occur outside of current stack frame, but before the browser's
|
||||
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
|
||||
suffers from slowness and may cause view flickering since the browser renders the view after
|
||||
each event.
|
||||
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
|
||||
which may have changed since last iteration. If a change is detected then the `$watch`
|
||||
function is called which typically updates the DOM with the new value.
|
||||
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
|
||||
6. Once the Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
|
||||
the execution leaves the Angular and JavaScript context. This is followed by the browser
|
||||
re-rendering the DOM to reflect any changes.
|
||||
|
||||
@@ -122,7 +122,7 @@ user enters text into the text field.
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -165,7 +165,7 @@ a diagram depicting the scope boundaries.
|
||||
function GreetCtrl($scope) {
|
||||
$scope.name = 'World';
|
||||
}
|
||||
|
||||
|
||||
function ListCtrl($scope) {
|
||||
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||
}
|
||||
@@ -188,7 +188,7 @@ a diagram depicting the scope boundaries.
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
|
||||
|
||||
Controller is the code behind the view. Its job is to construct the model and publish it to the
|
||||
A controller is the code behind the view. Its job is to construct the model and publish it to the
|
||||
view along with callback methods. The view is a projection of the scope onto the template (the
|
||||
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
|
||||
controller.
|
||||
@@ -196,7 +196,7 @@ 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
|
||||
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.
|
||||
@@ -220,7 +220,7 @@ The separation of the controller and the view is important because:
|
||||
$scope.action = function() {
|
||||
$scope.name = 'OK';
|
||||
}
|
||||
|
||||
|
||||
$scope.name = 'World';
|
||||
}
|
||||
</file>
|
||||
@@ -233,7 +233,7 @@ The separation of the controller and the view is important because:
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
|
||||
|
||||
The model is the data which is used merged with the template to produce the view. To be able to
|
||||
render the model into the view, the model has to be referenceable from the scope. Unlike many
|
||||
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 an 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.
|
||||
@@ -249,8 +249,8 @@ primitive, object hash, or a full object Type. In short the model is a plain Jav
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
||||
|
||||
The view is what the users sees. The view begins its life as a template, it is merged with the
|
||||
model and finally rendered into the browser DOM. Angular takes a very different approach to
|
||||
rendering the view, to most other templating systems.
|
||||
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
|
||||
@@ -260,13 +260,13 @@ rendering the view, to most other templating systems.
|
||||
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 HTML string, but it is HTML (not HTML with
|
||||
template sprinkled in.) The browser parses the HTML into DOM, and the DOM becomes the input to
|
||||
the template engine know as the {@link api/ng.$compile compiler}. The compiler
|
||||
* **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
|
||||
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">
|
||||
@@ -291,7 +291,7 @@ rendering the view, to most other templating systems.
|
||||
<a name="directives"></a>
|
||||
# Directives
|
||||
|
||||
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute,
|
||||
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.
|
||||
@@ -310,7 +310,7 @@ in HTML.
|
||||
});
|
||||
|
||||
// model -> view
|
||||
ctrl.render = function(value) {
|
||||
ctrl.$render = function(value) {
|
||||
elm.html(value);
|
||||
};
|
||||
|
||||
@@ -337,15 +337,15 @@ in HTML.
|
||||
<a name="filters"></a>
|
||||
# Filters
|
||||
|
||||
{@link api/ng.$filter Filters} perform data transformation roles. Typically
|
||||
{@link api/ng.$filter Filters} perform data transformation. Typically
|
||||
they are used in conjunction with the locale to format the data in locale specific output.
|
||||
They are follow the spirit of UNIX filters and follow similar syntax `|` (pipe).
|
||||
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">
|
||||
array filtering <input ng-model="predicate">
|
||||
{{ list | filter:predicate | json }}
|
||||
</div>
|
||||
</file>
|
||||
@@ -358,11 +358,11 @@ They are follow the spirit of UNIX filters and follow similar syntax `|` (pipe).
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||
|
||||
An {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
The {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
{@link api/AUTO.$injector injector} per Angular {@link
|
||||
api/ng.directive:ngApp application}. The {@link
|
||||
api/AUTO.$injector injector} provides a way to look up an object instance by its
|
||||
name. The injector keeps on internal cache of all objects so that repeated calls to get the same
|
||||
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.
|
||||
|
||||
@@ -373,20 +373,20 @@ as a {@link api/AUTO.$provide provider}.
|
||||
<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');
|
||||
|
||||
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>
|
||||
@@ -395,7 +395,7 @@ as a {@link api/AUTO.$provide provider}.
|
||||
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 rather then to look for them.
|
||||
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.
|
||||
@@ -405,12 +405,12 @@ allows the methods and types to ask for their dependencies rather then to look f
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -425,7 +425,7 @@ function arguments. When angular calls the function, it will use the {@link
|
||||
api/AUTO.$injector#invoke call} which will automatically fill the function
|
||||
arguments.
|
||||
|
||||
Examine the `ClockCtrl` bellow, and notice how it list the dependencies in constructor. When the
|
||||
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.
|
||||
@@ -438,19 +438,19 @@ dependencies, look for dependencies, or even get a reference to the injector.
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('timeExampleModule', []).
|
||||
// Declare new object call time,
|
||||
// Declare new object called time,
|
||||
// which will be available for injection
|
||||
factory('time', function($timeout) {
|
||||
var time = {};
|
||||
|
||||
|
||||
(function tick() {
|
||||
time.now = new Date().toString();
|
||||
$timeout(tick, 1000);
|
||||
})();
|
||||
return time;
|
||||
});
|
||||
|
||||
// Notice that you can simply ask for 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;
|
||||
|
||||
@@ -11,7 +11,7 @@ that will help you verify the health of your Angular application.
|
||||
|
||||
# Overview
|
||||
You will write scenario tests in JavaScript, which describe how your application should behave,
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more it blocks
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more `it` blocks
|
||||
(you can think of these as the requirements of your application), which in turn are made of
|
||||
**commands** and **expectations**. Commands tell the Runner to do something with the application
|
||||
(such as navigate to a page or click on a button), and expectations tell the Runner to assert
|
||||
@@ -122,7 +122,7 @@ Returns the current value of an input field with the given `name`.
|
||||
|
||||
## repeater(selector, label).count()
|
||||
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)
|
||||
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
|
||||
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not do it.
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
@description
|
||||
|
||||
While Model-View-Controller (MVC) has acquired different shades of meaning over the years since it
|
||||
first appeared, angular incorporates the basic principles behind the original {@link
|
||||
first appeared, Angular incorporates the basic principles behind the original {@link
|
||||
http://en.wikipedia.org/wiki/Model–view–controller MVC} software design pattern into its way of
|
||||
building client-side web applications.
|
||||
|
||||
The MVC pattern greatly summarized:
|
||||
The MVC pattern summarized:
|
||||
|
||||
* Separate applications into distinct presentation, data, and logic components
|
||||
* Encourage loose coupling between these components
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
|
||||
@description
|
||||
|
||||
In angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
||||
angular {@link scope Scope}, excluding the root scope. When you or angular create a new
|
||||
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
|
||||
angular {@link scope Scope}, excluding the root scope. When you or Angular create a new
|
||||
child scope object via the {@link api/ng.$rootScope.Scope#$new scope.$new} API , there is an
|
||||
option to pass in a controller as a method argument. This will tell angular to associate the
|
||||
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.
|
||||
|
||||
Use controllers to:
|
||||
@@ -15,10 +15,10 @@ Use controllers to:
|
||||
|
||||
# Setting up the initial state of a scope object
|
||||
|
||||
Typically, when you create an application you need to set up an initial state for an angular scope.
|
||||
Typically, when you create an application you need to set up an initial state for an Angular scope.
|
||||
|
||||
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
|
||||
to a new angular scope object, which sets up an initial scope state. This means that angular never
|
||||
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
|
||||
creates instances of the controller type (by invoking the `new` operator on the controller
|
||||
constructor). Constructors are always applied to an existing scope object.
|
||||
|
||||
@@ -30,9 +30,23 @@ function GreetingCtrl($scope) {
|
||||
|
||||
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
|
||||
|
||||
Behavior on an angular scope object is in the form of scope method properties available to the
|
||||
Behavior on an Angular scope object is in the form of scope method properties available to the
|
||||
template/view. This behavior interacts with and modifies the application model.
|
||||
|
||||
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
|
||||
@@ -55,14 +69,14 @@ Do not use controllers for:
|
||||
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
|
||||
manipulation—the presentation logic of an application—is well known for being hard to test.
|
||||
Putting any presentation logic into controllers significantly affects testability of the business
|
||||
logic. Angular offers {@link dev_guide.templates.databinding} for automatic DOM manipulation. If
|
||||
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
|
||||
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
|
||||
{@link guide/directive directives}.
|
||||
- Input formatting — Use {@link forms angular form controls} instead.
|
||||
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
|
||||
- Run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
|
||||
- To run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
|
||||
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).
|
||||
|
||||
|
||||
@@ -157,7 +171,7 @@ input box) in the second button.
|
||||
|
||||
## Controller Inheritance Example
|
||||
|
||||
Controller inheritance in angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
|
||||
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
|
||||
have a look at an example:
|
||||
|
||||
<pre>
|
||||
@@ -197,7 +211,7 @@ Inheritance works between controllers in the same way as it does with models. So
|
||||
examples, all of the models could be replaced with controller methods that return string values.
|
||||
|
||||
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
|
||||
because as we mentioned earlier, controllers are not instantiated directly by angular, but rather
|
||||
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
|
||||
are applied to the scope object.
|
||||
|
||||
|
||||
@@ -241,8 +255,8 @@ describe('myController function', function() {
|
||||
</pre>
|
||||
|
||||
|
||||
If you need to test a nested controller one needs to create the same scope hierarchy
|
||||
in your test as exist in the DOM.
|
||||
If you need to test a nested controller you need to create the same scope hierarchy
|
||||
in your test that exists in the DOM.
|
||||
|
||||
<pre>
|
||||
describe('state', function() {
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the Model Component
|
||||
@description
|
||||
|
||||
Depending on the context of the discussion in angular documentation, the term _model_ can refer to
|
||||
Depending on the context of the discussion in the Angular documentation, the term _model_ can refer to
|
||||
either a single object representing one entity (for example, a model called "phones" with its value
|
||||
being an array of phones) or the entire data model for the application (all entities).
|
||||
|
||||
In angular, a model is any data that is reachable as a property of an angular {@link
|
||||
In Angular, a model is any data that is reachable as a property of an angular {@link
|
||||
scope Scope} object. The name of the property is the model identifier and the value is
|
||||
any JavaScript object (including arrays and primitives).
|
||||
|
||||
The only requirement for a JavaScript object to be a model in angular is that the object must be
|
||||
referenced by an angular scope as a property of that scope object. This property reference can be
|
||||
The only requirement for a JavaScript object to be a model in Angular is that the object must be
|
||||
referenced by an Angular scope as a property of that scope object. This property reference can be
|
||||
created explicitly or implicitly.
|
||||
|
||||
You can create models by explicitly creating scope properties referencing JavaScript objects in the
|
||||
@@ -52,11 +52,11 @@ cloud".
|
||||
The code above creates one child scope for each item in the "phones" array and creates a "phone"
|
||||
object (model) on each of these scopes with its value set to the value of "phone" in the array.
|
||||
|
||||
In angular, a JavaScript object stops being a model when:
|
||||
In Angular, a JavaScript object stops being a model when:
|
||||
|
||||
* No angular scope contains a property that references the object.
|
||||
* No Angular scope contains a property that references the object.
|
||||
|
||||
* All angular scopes that contain a property referencing the object become stale and eligible for
|
||||
* All Angular scopes that contain a property referencing the object become stale and eligible for
|
||||
garbage collection.
|
||||
|
||||
The following illustration shows a simple data model created implicitly from a simple template:
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
@name Developer Guide: About MVC in Angular: Understanding the View Component
|
||||
@description
|
||||
|
||||
In angular, the view is the DOM loaded and rendered in the browser, after angular has transformed
|
||||
In Angular, the view is the DOM loaded and rendered in the browser, after Angular has transformed
|
||||
the DOM based on information in the template, controller and model.
|
||||
|
||||
<img src="img/guide/about_view_final.png">
|
||||
|
||||
In the angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||
In the Angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
|
||||
controller through angular directives, such as {@link api/ng.directive:ngController
|
||||
controller through Angular directives, such as {@link api/ng.directive:ngController
|
||||
ngController} and {@link api/ng.directive:ngView ngView}, and through bindings of this form:
|
||||
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
|
||||
controller function.
|
||||
|
||||
@@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
|
||||
|
||||
## Comparing $location to window.location
|
||||
|
||||
<table>
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
<td class="empty-corner-lt"></td>
|
||||
<td>window.location</td>
|
||||
<td>$location service</td>
|
||||
<th class="empty-corner-lt"></th>
|
||||
<th>window.location</th>
|
||||
<th>$location service</th>
|
||||
</tr>
|
||||
|
||||
</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.
|
||||
|
||||
## What does it not do?
|
||||
Does not cause a full page reload when the browser URL is changed. To reload the page after
|
||||
It does not cause a full page reload when the browser URL is changed. To reload the page after
|
||||
changing the URL, use the lower-level API, `$window.location.href`.
|
||||
|
||||
|
||||
# General overview of the API
|
||||
|
||||
The `$location` service can behave differently, depending on the configuration that was provided to
|
||||
@@ -133,12 +132,12 @@ current URL without creating a new browser history record you can call:
|
||||
// or you can chain these as: $location.path('/someNewPath').replace();
|
||||
</pre>
|
||||
|
||||
Note that the setters don't update `window.location` immediately. Instead, `$location` service is
|
||||
Note that the setters don't update `window.location` immediately. Instead, the `$location` service is
|
||||
aware of the {@link api/ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location`
|
||||
mutations into one "commit" to the `window.location` object during the scope `$digest` phase. Since
|
||||
multiple changes to the $location's state will be pushed to the browser as a single change, it's
|
||||
enough to call the `replace()` method just once to make the entire "commit" a replace operation
|
||||
rather than addition to the browser history. Once the browser is updated, the $location service
|
||||
rather than an addition to the browser history. Once the browser is updated, the $location service
|
||||
resets the flag set by `replace()` method and future mutations will create new history records,
|
||||
unless `replace()` is called again.
|
||||
|
||||
@@ -165,13 +164,13 @@ facilitate the browser URL change and history management.
|
||||
|
||||
<img src="img/guide/hashbang_vs_regular_url.jpg">
|
||||
|
||||
<table>
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
<td class="empty-corner-lt"></td>
|
||||
<td>Hashbang mode</td>
|
||||
<td>HTML5 mode</td>
|
||||
<th class="empty-corner-lt"></th>
|
||||
<th>Hashbang mode</th>
|
||||
<th>HTML5 mode</th>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
@@ -212,7 +211,7 @@ In this mode, `$location` uses Hashbang URLs in all browsers.
|
||||
<pre>
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5mode = false;
|
||||
$locationProvider.html5Mode(false);
|
||||
$locationProvider.hashPrefix = '!';
|
||||
},
|
||||
function($location) {
|
||||
@@ -261,7 +260,7 @@ having to worry about whether the browser displaying your app supports the histo
|
||||
<pre>
|
||||
it('should show example', inject(
|
||||
function($locationProvider) {
|
||||
$locationProvider.html5mode = true;
|
||||
$locationProvider.html5Mode(true);
|
||||
$locationProvider.hashPrefix = '!';
|
||||
},
|
||||
function($location) {
|
||||
@@ -304,7 +303,7 @@ history API or not; the `$location` service makes this transparent to you.
|
||||
|
||||
### Html link rewriting
|
||||
|
||||
When you use the history API mode, you will need different links in different browser, but all you
|
||||
When you use HTML5 history API mode, you will need different links in different browsers, but all you
|
||||
have to do is specify regular URL links, such as: `<a href="/some?foo=bar">link</a>`
|
||||
|
||||
When a user clicks on this link,
|
||||
@@ -543,69 +542,73 @@ then uses the information it obtains to compose hashbang URLs (such as
|
||||
|
||||
## Changes to your code
|
||||
|
||||
<table>
|
||||
<tr class="head">
|
||||
<td>Navigation inside the app</td>
|
||||
<td>Change to</td>
|
||||
</tr>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr class="head">
|
||||
<th>Navigation inside the app</th>
|
||||
<th>Change to</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
|
||||
/>$location.updateHash(value)</td>
|
||||
<td>$location.path(path).search(search)</td>
|
||||
</tr>
|
||||
<td>$location.path(path).search(search)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashPath = path</td>
|
||||
<td>$location.path(path)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.hashPath = path</td>
|
||||
<td>$location.path(path)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashSearch = search</td>
|
||||
<td>$location.search(search)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.hashSearch = search</td>
|
||||
<td>$location.search(search)</td>
|
||||
</tr>
|
||||
|
||||
<tr class="head">
|
||||
<td>Navigation outside the app</td>
|
||||
<td>Use lower level API</td>
|
||||
</tr>
|
||||
<tr class="head">
|
||||
<td>Navigation outside the app</td>
|
||||
<td>Use lower level API</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.update(value)</td>
|
||||
<td>$window.location.href = value</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.href = value<br />$location.update(value)</td>
|
||||
<td>$window.location.href = value</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location[protocol | host | port | path | search]</td>
|
||||
<td>$window.location[protocol | host | port | path | search]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location[protocol | host | port | path | search]</td>
|
||||
<td>$window.location[protocol | host | port | path | search]</td>
|
||||
</tr>
|
||||
|
||||
<tr class="head">
|
||||
<td>Read access</td>
|
||||
<td>Change to</td>
|
||||
</tr>
|
||||
<tr class="head">
|
||||
<td>Read access</td>
|
||||
<td>Change to</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashPath</td>
|
||||
<td>$location.path()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.hashPath</td>
|
||||
<td>$location.path()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.hashSearch</td>
|
||||
<td>$location.search()</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.hashSearch</td>
|
||||
<td>$location.search()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
|
||||
<tr>
|
||||
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
|
||||
/>$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>
|
||||
</tr>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>$location.path<br />$location.search</td>
|
||||
<td>$window.location.path<br />$window.location.search</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$location.path<br />$location.search</td>
|
||||
<td>$window.location.path<br />$window.location.search</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
## Two-way binding to $location
|
||||
|
||||
@@ -48,9 +48,9 @@ create this instance when called.
|
||||
|
||||
# Dependencies
|
||||
|
||||
Services can not only be depended upon, but also have its own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about the DI
|
||||
in Angular and the use of array notation and $inject property to make DI annotation
|
||||
Services can not only be depended upon, but can also have their own dependencies. These can be specified
|
||||
as arguments of the factory function. {@link di Read more} about dependency injection (DI)
|
||||
in Angular and the use of array notation and the $inject property to make DI annotation
|
||||
minification-proof.
|
||||
|
||||
Following is an example of a very simple service. This service depends on the `$window` service
|
||||
@@ -78,7 +78,7 @@ angular.module('myModule', [], function($provide) {
|
||||
|
||||
All services in Angular are instantiated lazily. This means that a service will be created
|
||||
only when it is needed for instantiation of a service or an application component that depends on it.
|
||||
In other words, Angular won't instantiate lazy services unless they are requested directly or
|
||||
In other words, Angular won't instantiate services unless they are requested directly or
|
||||
indirectly by the application.
|
||||
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ function myModuleCfgFn($provide) {
|
||||
</pre>
|
||||
|
||||
|
||||
Here is an example of two services that depend on each other, as well as on other services that are
|
||||
provided by Angular's web framework:
|
||||
Here is an example of two services, one of which depends on the other and both
|
||||
of which depend on other services that are provided by the Angular framework:
|
||||
|
||||
<pre>
|
||||
/**
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
@name Developer Guide: Angular Services
|
||||
@description
|
||||
|
||||
Services are a feature that angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}. Services are
|
||||
most often used with {@link di dependency injection}, also a key feature of angular apps.
|
||||
Services are a feature that Angular brings to client-side web apps from the server side, where
|
||||
services have been commonly used for a long time. Services in Angular apps are substitutable
|
||||
objects that are wired together using {@link di dependency injection (DI)}.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
@@ -6,9 +6,9 @@ Angular services are singletons that carry out specific tasks common to web apps
|
||||
{@link api/ng.$http $http service} that provides low level access to the browser's
|
||||
`XMLHttpRequest` object.
|
||||
|
||||
To use an angular service, you identify it as a dependency for the dependent (a controller, or
|
||||
To use an Angular service, you identify it as a dependency for the dependent (a controller, or
|
||||
another service) that depends on the service. Angular's dependency injection subsystem takes care
|
||||
of the rest. The angular injector subsystem is in charge of service instantiation, resolution of
|
||||
of the rest. The Angular injector subsystem is in charge of service instantiation, resolution of
|
||||
dependencies, and provision of dependencies to factory functions as requested.
|
||||
|
||||
Angular injects dependencies using "constructor" injection (the service is passed in via a factory
|
||||
@@ -18,7 +18,7 @@ must explicitly define its dependencies by using the `$inject` property. For ex
|
||||
|
||||
myController.$inject = ['$location'];
|
||||
|
||||
The angular web framework provides a set of services for common operations. Like other core angular
|
||||
The Angular web framework provides a set of services for common operations. Like other core Angular
|
||||
variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned
|
||||
above). You can also create your own custom services.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
@name Developer Guide: Templates: Data Binding in Angular
|
||||
@description
|
||||
|
||||
Data-binding in angular web apps is the automatic syncing of data between the model and view
|
||||
components. The way that angular implements data-binding lets you treat the model as the
|
||||
Data-binding in Angular web apps is the automatic syncronization of data between the model and view
|
||||
components. The way that Angular implements data-binding lets you treat the model as the
|
||||
single-source-of-truth in your application. The view is a projection of the model at all times.
|
||||
When the model changes, the view reflects the change, and vice versa.
|
||||
|
||||
@@ -19,7 +19,7 @@ to write code that constantly syncs the view with the model and the model with t
|
||||
## Data Binding in Angular Templates
|
||||
|
||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
||||
The way angular templates works is different, as illustrated in the diagram. They are different
|
||||
The way Angular templates works is different, as illustrated in the diagram. They are different
|
||||
because first the template (which is the uncompiled HTML along with any additional markup or
|
||||
directives) is compiled on the browser, and second, the compilation step produces a live view. We
|
||||
say live because any changes to the view are immediately reflected in the model, and any changes in
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
@name Developer Guide: Understanding Angular Templates
|
||||
@description
|
||||
|
||||
An angular template is the declarative specification that, along with information from the model
|
||||
An Angular template is the declarative specification that, along with information from the model
|
||||
and controller, becomes the rendered view that a user sees in the browser. It is the static DOM,
|
||||
containing HTML, CSS, and angular-specific elements and angular-specific element attributes. The
|
||||
angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||
Angular elements and attributes direct angular to add behavior and transform the template DOM into
|
||||
the dynamic view DOM.
|
||||
|
||||
These are the types of angular elements and element attributes you can use in a template:
|
||||
These are the types of Angular elements and element attributes you can use in a template:
|
||||
|
||||
* {@link guide/directive Directive} — An attribute or element that
|
||||
augments an existing DOM element or represents a reusable DOM component - a widget.
|
||||
@@ -20,8 +20,8 @@ curly brace notation `{{ }}` to bind expressions to elements is built-in angular
|
||||
Note: In addition to declaring the elements above in templates, you can also access these elements
|
||||
in JavaScript code.
|
||||
|
||||
The following code snippet shows a simple angular template made up of standard HTML tags along with
|
||||
angular {@link guide/directive directives} and curly-brace bindings
|
||||
The following code snippet shows a simple Angular template made up of standard HTML tags along with
|
||||
Angular {@link guide/directive directives} and curly-brace bindings
|
||||
with {@link expression expressions}:
|
||||
|
||||
<pre>
|
||||
|
||||
@@ -5,35 +5,47 @@
|
||||
JavaScript is a dynamically typed language which comes with great power of expression, but it also
|
||||
come with almost no-help from the compiler. For this reason we feel very strongly that any code
|
||||
written in JavaScript needs to come with a strong set of tests. We have built many features into
|
||||
angular which makes testing your angular applications easy. So there is no excuse for not do it.
|
||||
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
|
||||
|
||||
# It is all about NOT mixing concerns
|
||||
|
||||
Unit testing as the name implies is about testing individual units of code. Unit tests try to
|
||||
answer the question: Did I think about the logic correctly. Does the sort function order the list
|
||||
in the right order. In order to answer such question it is very important that we can isolate it.
|
||||
That is because when we are testing the sort function we don't want to be forced into crating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort. While
|
||||
answer questions such as "Did I think about the logic correctly?" or "Does the sort function order the list
|
||||
in the right order?"
|
||||
|
||||
In order to answer such question it is very important that we can isolate the unit of code under test.
|
||||
That is because when we are testing the sort function we don't want to be forced into creating
|
||||
related pieces such as the DOM elements, or making any XHR calls in getting the data to sort.
|
||||
|
||||
While
|
||||
this may seem obvious it usually is very difficult to be able to call an individual function on a
|
||||
typical project. The reason is that the developers often time mix concerns, and they end up with a
|
||||
typical project. The reason is that the developers often mix concerns, and they end up with a
|
||||
piece of code which does everything. It reads the data from XHR, it sorts it and then it
|
||||
manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we
|
||||
manipulates the DOM.
|
||||
|
||||
With Angular we try to make it easy for you to do the right thing, and so we
|
||||
provide dependency injection for your XHR (which you can mock out) and we created abstraction which
|
||||
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
||||
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
||||
apply the function, and assert that the resulting model is in the correct order. The test does not
|
||||
have to wait for XHR, or create the right kind of DOM, or assert that your function has mutated the
|
||||
DOM in the right way. Angular is written with testability in mind, but it still requires that you
|
||||
do the right thing. We tried to make the right thing easy, but angular is not magic, which means if
|
||||
you don't follow these, you may very well end up with an untestable application.
|
||||
DOM in the right way.
|
||||
|
||||
## Dependency Inject
|
||||
## With great power comes great responsibility
|
||||
|
||||
Angular is written with testability in mind, but it still requires that you
|
||||
do the right thing. We tried to make the right thing easy, but Angular is not magic, which means if
|
||||
you don't follow these guidelines you may very well end up with an untestable application.
|
||||
|
||||
## Dependency Injection
|
||||
There are several ways in which you can get a hold of a dependency:
|
||||
1. You could create it using the `new` operator.
|
||||
2. You could look for it in a well know place, also known as global singleton.
|
||||
2. You could look for it in a well known place, also known as global singleton.
|
||||
3. You could ask a registry (also known as service registry) for it. (But how do you get a hold of
|
||||
the registry? Must likely by looking it up in a well know place. See #2)
|
||||
4. You could expect that the it be handed to you.
|
||||
the registry? Most likely by looking it up in a well known place. See #2)
|
||||
4. You could expect that it be handed to you.
|
||||
|
||||
Out of the list above only the last of is testable. Lets look at why:
|
||||
Out of the four options in the list above, only the last one is testable. Let's look at why:
|
||||
|
||||
### Using the `new` operator
|
||||
|
||||
@@ -52,10 +64,10 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The issue becomes, that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||
The issue becomes that in tests, we would very much like to instantiate a `MockXHR` which would
|
||||
allow us to return fake data and simulate network failures. By calling `new XHR()` we are
|
||||
permanently bound to the actual one, and there is no good way to replace it. Yes there is monkey
|
||||
patching, that is a bad idea for many reasons, which is outside the scope of this document.
|
||||
permanently bound to the actual XHR, and there is no good way to replace it. Yes there is monkey
|
||||
patching. That is a bad idea for many reasons which are outside the scope of this document.
|
||||
|
||||
The class above is hard to test since we have to resort to monkey patching:
|
||||
<pre>
|
||||
@@ -69,7 +81,7 @@ XHR = oldXHR; // if you forget this bad things will happen
|
||||
|
||||
|
||||
### Global look-up:
|
||||
Another way to approach the problem is look for the service in a well known location.
|
||||
Another way to approach the problem is to look for the service in a well known location.
|
||||
|
||||
<pre>
|
||||
function MyClass() {
|
||||
@@ -83,7 +95,7 @@ function MyClass() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
While no new instance of dependency is being created, it is fundamentally the same as `new`, in
|
||||
While no new instance of the dependency is being created, it is fundamentally the same as `new`, in
|
||||
that there is no good way to intercept the call to `global.xhr` for testing purposes, other then
|
||||
through monkey patching. The basic issue for testing is that global variable needs to be mutated in
|
||||
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>
|
||||
|
||||
However, where dose the serviceRegistry come from? if it is:
|
||||
However, where does the serviceRegistry come from? if it is:
|
||||
* `new`-ed up, the the test has no chance to reset the services for testing
|
||||
* global look-up, then the service returned is global as well (but resetting is easier, since
|
||||
there is only one global variable to be reset).
|
||||
@@ -164,7 +176,7 @@ myClass.doWork();
|
||||
|
||||
Notice that no global variables were harmed in the writing of this test.
|
||||
|
||||
Angular comes with {@link di dependency-injection} built in which makes the right thing
|
||||
Angular comes with {@link di dependency injection} built in which makes the right thing
|
||||
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||
|
||||
## Controllers
|
||||
@@ -173,7 +185,7 @@ for your application is mixed in with DOM manipulation, it will be hard to test
|
||||
below:
|
||||
|
||||
<pre>
|
||||
function PasswordController() {
|
||||
function PasswordCtrl() {
|
||||
// get references to DOM elements
|
||||
var msg = $('.ex1 span');
|
||||
var input = $('.ex1 input');
|
||||
@@ -197,7 +209,7 @@ function PasswordController() {
|
||||
}
|
||||
</pre>
|
||||
|
||||
The code above is problematic from testability, since it requires your test to have the right kind
|
||||
The code above is problematic from a testability point of view, since it requires your test to have the right kind
|
||||
of DOM present when the code executes. The test would look like this:
|
||||
|
||||
<pre>
|
||||
@@ -207,7 +219,7 @@ $('body').html('<div class="ex1">')
|
||||
.find('div')
|
||||
.append(input)
|
||||
.append(span);
|
||||
var pc = new PasswordController();
|
||||
var pc = new PasswordCtrl();
|
||||
input.val('abc');
|
||||
pc.grade();
|
||||
expect(span.text()).toEqual('weak');
|
||||
@@ -218,7 +230,7 @@ In angular the controllers are strictly separated from the DOM manipulation logi
|
||||
a much easier testability story as can be seen in this example:
|
||||
|
||||
<pre>
|
||||
function PasswordCntrl($scope) {
|
||||
function PasswordCtrl($scope) {
|
||||
$scope.password = '';
|
||||
$scope.grade = function() {
|
||||
var size = $scope.password.length;
|
||||
@@ -233,19 +245,18 @@ function PasswordCntrl($scope) {
|
||||
}
|
||||
</pre>
|
||||
|
||||
and the tests is straight forward
|
||||
and the test is straight forward
|
||||
|
||||
<pre>
|
||||
var pc = new PasswordController();
|
||||
var pc = new PasswordCtrl();
|
||||
pc.password('abc');
|
||||
pc.grade();
|
||||
expect(span.strength).toEqual('weak');
|
||||
expect(pc.strength).toEqual('weak');
|
||||
</pre>
|
||||
|
||||
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
|
||||
that such a test tells a story, rather then asserting random bits which don't seem to be related.
|
||||
|
||||
|
||||
## Filters
|
||||
{@link api/ng.$filter Filters} are functions which transform the data into user readable
|
||||
format. They are important because they remove the formatting responsibility from the application
|
||||
@@ -266,16 +277,20 @@ expect(length('abc')).toEqual(3);
|
||||
## Directives
|
||||
Directives in angular are responsible for updating the DOM when the state of the model changes.
|
||||
|
||||
|
||||
## Mocks
|
||||
oue
|
||||
|
||||
## Global State Isolation
|
||||
oue
|
||||
|
||||
# Preferred way of Testing
|
||||
uo
|
||||
|
||||
## JavaScriptTestDriver
|
||||
ou
|
||||
|
||||
## Jasmine
|
||||
ou
|
||||
|
||||
## Sample project
|
||||
uoe
|
||||
|
||||
+14
-16
@@ -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
|
||||
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
|
||||
construction and lookup of dependencies.
|
||||
|
||||
@@ -67,11 +67,11 @@ Here is an example of using the injector service.
|
||||
$window.alert(text);
|
||||
}
|
||||
};
|
||||
}).
|
||||
|
||||
});
|
||||
|
||||
// New injector is created from the module.
|
||||
// (This is usually done automatically by angular bootstrap)
|
||||
var injector = angular.injector('myModule');
|
||||
var injector = angular.injector(['myModule', 'ng']);
|
||||
|
||||
// Request any dependency from the injector
|
||||
var greeter = injector.get('greeter');
|
||||
@@ -92,7 +92,7 @@ dependency lookup responsibility to the injector by declaring the dependencies a
|
||||
// And this controller definition
|
||||
function MyController($scope, greeter) {
|
||||
$scope.sayHello = function() {
|
||||
greeter('Hello World');
|
||||
greeter.greet('Hello World');
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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?
|
||||
|
||||
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
|
||||
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
|
||||
@@ -186,32 +186,30 @@ 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
|
||||
where injection is supported.
|
||||
|
||||
|
||||
# Where can I use DI?
|
||||
|
||||
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
|
||||
|
||||
## 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:
|
||||
|
||||
<pre>
|
||||
var MyController = function(dep1, dep2) {
|
||||
...
|
||||
}
|
||||
MyController.$inject = ['dep1', 'dep2'];
|
||||
|
||||
MyController.prototype.aMethod = function() {
|
||||
var MyController = function($scope, dep1, dep2) {
|
||||
...
|
||||
$scope.aMethod = function() {
|
||||
...
|
||||
}
|
||||
}
|
||||
MyController.$inject = ['$scope', 'dep1', 'dep2'];
|
||||
</pre>
|
||||
|
||||
|
||||
## Factory methods
|
||||
|
||||
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
||||
services, and filters. The factory methods are register with the module, and the recommended way
|
||||
services, and filters. The factory methods are registered with the module, and the recommended way
|
||||
of declaring factories is:
|
||||
|
||||
<pre>
|
||||
@@ -231,4 +229,4 @@ of declaring factories is:
|
||||
run(['depService', function(depService) {
|
||||
...
|
||||
}]);
|
||||
</pre>
|
||||
</pre>
|
||||
|
||||
@@ -63,7 +63,7 @@ api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is sh
|
||||
here:
|
||||
|
||||
<pre>
|
||||
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
|
||||
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
|
||||
</pre>
|
||||
|
||||
# Compilation process, and directive matching
|
||||
@@ -110,7 +110,7 @@ Compilation of HTML happens in three phases:
|
||||
## Reasons behind the compile/link separation
|
||||
|
||||
At this point you may wonder why the compile process is broken down to a compile and link phase.
|
||||
To understand this, let's look at a real world example with repeater:
|
||||
To understand this, let's look at a real world example with a repeater:
|
||||
|
||||
<pre>
|
||||
Hello {{user}}, you have these actions:
|
||||
@@ -144,9 +144,9 @@ links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the s
|
||||
instance of an `li` is performed.
|
||||
|
||||
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
||||
compilation process form descending into the `li` element. Instead the {@link
|
||||
compilation process from descending into the `li` element. Instead the {@link
|
||||
api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
|
||||
separately. The result of of the `li` element compilation is a linking function which contains all
|
||||
separately. The result of the `li` element compilation is a linking function which contains all
|
||||
of the directives contained in the `li` element, ready to be attached to a specific clone of the `li`
|
||||
element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat}
|
||||
watches the expression and as items are added to the array it clones the `li` element, creates a
|
||||
@@ -253,7 +253,7 @@ 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
|
||||
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 default values. Therefore the above can be
|
||||
simplified as:
|
||||
@@ -296,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
|
||||
compiler}. The attributes are:
|
||||
|
||||
* `name` - Name of the current scope. Optional defaults to the name at registration.
|
||||
* `name` - Name of the current scope. Optional and defaults to the name at registration.
|
||||
|
||||
* `priority` - When there are multiple directives defined on a single DOM element, sometimes it
|
||||
is necessary to specify the order in which the directives are applied. The `priority` is used
|
||||
@@ -310,7 +310,7 @@ compiler}. The attributes are:
|
||||
* `scope` - If set to:
|
||||
|
||||
* `true` - then a new scope will be created for this directive. If multiple directives on the
|
||||
same element request new scope, only one new scope is created. The new scope rule does not
|
||||
same element request a new scope, only one new scope is created. The new scope rule does not
|
||||
apply for the root of the template since the root of the template always gets a new scope.
|
||||
|
||||
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
|
||||
@@ -321,35 +321,37 @@ compiler}. The attributes are:
|
||||
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:
|
||||
|
||||
* `@` or `@attr` - bind a local scope property to the DOM attribute. The result is always a
|
||||
string since DOM attributes are strings. If no `attr` name is specified then the local name
|
||||
and attribute name are same. Given `<widget my-attr="hello {{name}}">` and widget definition
|
||||
* `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
|
||||
always a string since DOM attributes are strings. If no `attr` name is specified then the
|
||||
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
|
||||
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
|
||||
component scope).
|
||||
|
||||
* `=` or `=expression` - 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
|
||||
name are same. Given `<widget my-attr="parentModel">` and widget definition of
|
||||
`scope: { localModel:'=myAttr' }`, then widget scope property `localName` will reflect the
|
||||
* `=` or `=attr` - set up bi-directional binding between a local scope property and the
|
||||
parent scope property of name defined via the value of the `attr` attribute. If no `attr`
|
||||
name is specified then the attribute name is assumed to be the same as the local name.
|
||||
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
|
||||
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.
|
||||
If no `attr` name is specified then the local name and attribute name are same.
|
||||
Given `<widget my-attr="count = count + value">` and widget definition of
|
||||
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
|
||||
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
|
||||
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
||||
map of local variable names and values into the expression wrapper fn. For example, if the
|
||||
expression is `increment(amount)` then we can specify the amount value by calling the
|
||||
`localFn` as `localFn({amount: 22})`.
|
||||
If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||
local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
||||
`scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
|
||||
a function wrapper for the `count = count + value` expression. Often it's desirable to
|
||||
pass data from the isolated scope via an expression and to the parent scope, this can be
|
||||
done by passing a map of local variable names and values into the expression wrapper fn.
|
||||
For example, if the expression is `increment(amount)` then we can specify the amount value
|
||||
by calling the `localFn` as `localFn({amount: 22})`.
|
||||
|
||||
* `controller` - Controller constructor function. The controller is instantiated before the
|
||||
pre-linking phase and it is shared with other directives if they request it by name (see
|
||||
`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
|
||||
* `$element` - Current element
|
||||
@@ -472,7 +474,7 @@ compiler linking function will fail to locate the correct elements for linking.
|
||||
|
||||
### Post-linking function
|
||||
|
||||
Executed after the child elements are linked. Safe to do DOM transformation in here.
|
||||
Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
|
||||
|
||||
<a name="Attributes"></a>
|
||||
## Attributes
|
||||
@@ -526,6 +528,7 @@ dialog component may work.
|
||||
on-ok="show = false; doSomething()">
|
||||
Body goes here: {{username}} is {{title}}.
|
||||
</dialog>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
|
||||
@@ -535,7 +538,7 @@ into the dialog.
|
||||
Here is an example of what the template definition for the `dialog` widget may look like.
|
||||
|
||||
<pre>
|
||||
<div ng-show="show()">
|
||||
<div ng-show="visible">
|
||||
<h3>{{title}}</h3>
|
||||
<div class="body" ng-transclude></div>
|
||||
<div class="footer">
|
||||
@@ -547,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.
|
||||
|
||||
The first issue we have to solve is that the dialog box template expect `title` to be defined, but
|
||||
the place of instantiation would like to bind to `username`. Furthermore the buttons expect `onOk`
|
||||
as well as `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
The first issue we have to solve is that the dialog box template expects `title` to be defined, but
|
||||
the place of instantiation would like to bind to `username`. Furthermore the buttons expect the
|
||||
`onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||
expects as follows:
|
||||
|
||||
<pre>
|
||||
scope: {
|
||||
title: 'bind', // set up title to accept data-binding
|
||||
onOk: 'expression', // create a delegate onOk function
|
||||
onCancel: 'expression', // create a delegate onCancel function
|
||||
show: 'accessor' // create a getter/setter function for visibility.
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -581,7 +584,7 @@ isolated scope then it will not be able to bind to anything. For this reason the
|
||||
is a child of the original scope, before the widget created an isolated scope for its local
|
||||
variables. This makes the transcluded and widget isolated scope siblings.
|
||||
|
||||
This may seem as unexpected complexity, but it gives the widget user and developer the least
|
||||
This may seem to be unexpected complexity, but it gives the widget user and developer the least
|
||||
surprise.
|
||||
|
||||
Therefore the final directive definition looks something like this:
|
||||
@@ -589,11 +592,13 @@ Therefore the final directive definition looks something like this:
|
||||
<pre>
|
||||
transclude: true,
|
||||
scope: {
|
||||
title: 'bind', // set up title to accept data-binding
|
||||
onOk: 'expression', // create a delegate onOk function
|
||||
onCancel: 'expression', // create a delegate onCancel function
|
||||
show: 'accessor' // create a getter/setter function for visibility.
|
||||
}
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
},
|
||||
restrict: 'E',
|
||||
replace: true
|
||||
</pre>
|
||||
|
||||
# Creating Components
|
||||
@@ -604,7 +609,6 @@ can be built.
|
||||
|
||||
Following is an example of building a reusable widget.
|
||||
|
||||
|
||||
<doc:example module="zippyModule">
|
||||
<doc:source>
|
||||
<script>
|
||||
|
||||
@@ -15,10 +15,9 @@ For example, these are all valid expressions in angular:
|
||||
|
||||
## Angular Expressions vs. JS Expressions
|
||||
|
||||
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct, since angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of angular expressions as JavaScript expressions with following differences
|
||||
differences:
|
||||
It might be tempting to think of Angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct, since Angular does not use a JavaScript `eval()` to evaluate expressions.
|
||||
You can think of Angular expressions as JavaScript expressions with following differences:
|
||||
|
||||
* **Attribute Evaluation:** evaluation of all properties are against the scope, doing the
|
||||
evaluation, unlike in JavaScript where the expressions are evaluated against the global
|
||||
@@ -92,9 +91,9 @@ You can try evaluating different expressions here:
|
||||
# Property Evaluation
|
||||
|
||||
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
|
||||
to global window properties, angular expressions have to use {@link api/ng.$window
|
||||
to global window properties, Angular expressions have to use {@link api/ng.$window
|
||||
`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is
|
||||
defined on `window`, in an expression must use `$window.alert()`. This is done intentionally to
|
||||
defined on `window`, in an expression you must use `$window.alert()`. This is done intentionally to
|
||||
prevent accidental access to the global state (a common source of subtle bugs).
|
||||
|
||||
<doc:example>
|
||||
@@ -148,7 +147,7 @@ Similarly, invoking a function `a.b.c()` on undefined or null simply returns und
|
||||
## No Control Flow Statements
|
||||
|
||||
You cannot write a control flow statement in an expression. The reason behind this is core to the
|
||||
angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||
Angular philosophy that application logic should be in controllers, not in the view. If you need a
|
||||
conditional, loop, or to throw from a view expression, delegate to a JavaScript method instead.
|
||||
|
||||
|
||||
@@ -179,9 +178,9 @@ You might be wondering, what is the significance of the $ prefix? It is simply a
|
||||
angular uses, to differentiate its API names from others. If angular didn't use $, then evaluating
|
||||
`a.length()` would return undefined because neither a nor angular define such a property.
|
||||
|
||||
Consider that in a future version of angular we might choose to add a length method, in which case
|
||||
Consider that in a future version of Angular we might choose to add a length method, in which case
|
||||
the behavior of the expression would change. Worse yet, you the developer could create a length
|
||||
property and then we would have a collision. This problem exists because angular augments existing
|
||||
property and then we would have a collision. This problem exists because Angular augments existing
|
||||
objects with additional behavior. By prefixing its additions with $ we are reserving our namespace
|
||||
so that angular developers and developers who use angular can develop in harmony without collisions.
|
||||
so that angular developers and developers who use Angular can develop in harmony without collisions.
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ Server-side validation is still necessary for a secure application.
|
||||
|
||||
|
||||
# Simple form
|
||||
The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
|
||||
The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
|
||||
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
|
||||
In addition it provides {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
In addition it provides an {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
@@ -63,7 +63,7 @@ To allow styling of form as well as controls, `ngModel` add these CSS classes:
|
||||
- `ng-pristine`
|
||||
- `ng-dirty`
|
||||
|
||||
Following example uses the CSS to display validity of each form control.
|
||||
The following example uses the CSS to display validity of each form control.
|
||||
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
|
||||
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
|
||||
|
||||
@@ -190,18 +190,18 @@ The validation can occur in two places:
|
||||
|
||||
* **View to Model update** -
|
||||
In a similar way, whenever a user interacts with a control it calls {@link api/ng.directive:ngModel.NgModelController#$setViewValue NgModelController#$setViewValue}.
|
||||
This in turn pipelines all functions in {@link api/ng.directive:ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
This in turn pipelines all functions in the {@link api/ng.directive:ngModel.NgModelController#$parsers NgModelController#$parsers} array, so that each of these functions has an opportunity to convert the value and change validity state of the form control through {@link api/ng.directive:ngModel.NgModelController#$setValidity NgModelController#$setValidity}.
|
||||
|
||||
In the following example we create two directives.
|
||||
|
||||
* The first one is `integer` and it validates whether the input is a valid integer.
|
||||
For example `1.23` is an invalid value, since it contains a fraction.
|
||||
Note, that we unshift the array instead of pushing.
|
||||
Note that we unshift the array instead of pushing.
|
||||
This is because we want to be first parser and consume the control string value, as we need to execute the validation function before a conversion to number occurs.
|
||||
|
||||
* The second directive is a `smart-float`.
|
||||
It parses both `1.2` and `1,2` into a valid float number `1.2`.
|
||||
Note that, we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
Note that we can't use input type `number` here as HTML5 browsers would not allow the user to type what it would consider an invalid number such as `1,2`.
|
||||
|
||||
|
||||
<doc:example module="form-example1">
|
||||
@@ -272,7 +272,7 @@ In the following example we create two directives.
|
||||
</doc:example>
|
||||
|
||||
|
||||
# Implementing custom form control (using `ngModel`)
|
||||
# Implementing custom form controls (using `ngModel`)
|
||||
Angular implements all of the basic HTML form controls ({@link api/ng.directive:input input}, {@link api/ng.directive:select select}, {@link api/ng.directive:textarea textarea}), which should be sufficient for most cases.
|
||||
However, if you need more flexibility, you can write your own form control as a directive.
|
||||
|
||||
@@ -300,8 +300,8 @@ The following example shows how to add two-way data-binding to contentEditable e
|
||||
});
|
||||
|
||||
// model -> view
|
||||
ctrl.$render = function(value) {
|
||||
elm.html(value);
|
||||
ctrl.$render = function() {
|
||||
elm.html(ctrl.$viewValue);
|
||||
};
|
||||
|
||||
// load init value from DOM
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
# Overview
|
||||
|
||||
This document describes the Internet Explorer (IE) idiosyncrasies when dealing with custom HTML
|
||||
attributes and tags. Read this document if you are planning on deploying your angular application
|
||||
attributes and tags. Read this document if you are planning on deploying your Angular application
|
||||
on IE v8.0 or earlier.
|
||||
|
||||
# Short Version
|
||||
|
||||
To make your angular application work on IE please make sure that:
|
||||
To make your Angular application work on IE please make sure that:
|
||||
|
||||
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
|
||||
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||
|
||||
@@ -6,7 +6,7 @@ Angular is pure client-side technology, written entirely in JavaScript. It works
|
||||
long-established technologies of the web (HTML, CSS, and JavaScript) to make the development of
|
||||
web apps easier and faster than ever before.
|
||||
|
||||
One important way that angular simplifies web development is by increasing the level of abstraction
|
||||
One important way that Angular simplifies web development is by increasing the level of abstraction
|
||||
between the developer and most low-level web app development tasks. Angular automatically takes
|
||||
care of many of these tasks, including:
|
||||
|
||||
@@ -14,10 +14,10 @@ care of many of these tasks, including:
|
||||
* Setting Up Listeners and Notifiers
|
||||
* Input Validation
|
||||
|
||||
Because angular handles much of the work involved in these tasks, developers can concentrate more
|
||||
Because Angular handles much of the work involved in these tasks, developers can concentrate more
|
||||
on application logic and less on repetitive, error-prone, lower-level coding.
|
||||
|
||||
At the same time that angular simplifies the development of web apps, it brings relatively
|
||||
At the same time that Angular simplifies the development of web apps, it brings relatively
|
||||
sophisticated techniques to the client-side, including:
|
||||
|
||||
* Separation of data, application logic, and presentation components
|
||||
@@ -31,12 +31,12 @@ These techniques have been for the most part absent from the client-side for far
|
||||
|
||||
## Single-page / Round-trip Applications
|
||||
|
||||
You can use angular to develop both single-page and round-trip apps, but angular is designed
|
||||
You can use Angular to develop both single-page and round-trip apps, but Angular is designed
|
||||
primarily for developing single-page apps. Angular supports browser history, forward and back
|
||||
buttons, and bookmarking in single-page apps.
|
||||
|
||||
You normally wouldn't want to load angular with every page change, as would be the case with using
|
||||
angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
||||
angular's features (for example, templates to leverage angular's data-binding feature) to an
|
||||
You normally wouldn't want to load Angular with every page change, as would be the case with using
|
||||
Angular in a round-trip app. However, it would make sense to do so if you were adding a subset of
|
||||
Angular's features (for example, templates to leverage angular's data-binding feature) to an
|
||||
existing round-trip app. You might follow this course of action if you were migrating an older app
|
||||
to a single-page angular app.
|
||||
to a single-page Angular app.
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
# What is a Module?
|
||||
|
||||
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
|
||||
specifying how an application should be bootstrapped. There are several advantages to this
|
||||
approach:
|
||||
Angular apps don't have a main method. Instead modules declaratively specify how an application
|
||||
should be bootstrapped. There are several advantages to this approach:
|
||||
|
||||
* 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.
|
||||
@@ -31,7 +30,7 @@ Important things to notice:
|
||||
<doc:source>
|
||||
<script>
|
||||
// declare a module
|
||||
var simpleAppModule = angular.module('myApp', []);
|
||||
var myAppModule = angular.module('myApp', []);
|
||||
|
||||
// configure the module.
|
||||
// in this example we will create a greeting filter
|
||||
@@ -195,7 +194,7 @@ and thus script loaders can take advantage of this property and parallelize the
|
||||
|
||||
# Unit Testing
|
||||
|
||||
In its simplest form a unit-test is a way of instantiating a subset of the application in test and
|
||||
In its simplest form a unit test is a way of instantiating a subset of the application in test and
|
||||
then applying a stimulus to it. It is important to realize that each module can only be loaded
|
||||
once per injector. Typically an app has only one injector. But in tests, each test has its own
|
||||
injector, which means that the modules are loaded multiple times per VM. Properly structured
|
||||
@@ -223,8 +222,8 @@ In all of these examples we are going to assume this module definition:
|
||||
Let's write some tests:
|
||||
<pre>
|
||||
describe('myApp', function() {
|
||||
// load the application relevant modules then load a special
|
||||
// test module which overrides the $window with mock version,
|
||||
// load the relevant application modules then load a special
|
||||
// test module which overrides the $window with a mock version,
|
||||
// so that calling window.alert() will not block the test
|
||||
// runner with a real alert box. This is an example of overriding
|
||||
// configuration information in tests.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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
|
||||
on.
|
||||
|
||||
In the `<html>` tag, we specify that it is an angular
|
||||
In the `<html>` tag, we specify that it is an Angular
|
||||
application with the `ng-app` directive. The `ng-app` will cause Angular to {@link
|
||||
bootstrap auto initialize} your application.
|
||||
|
||||
@@ -121,7 +121,7 @@ We load Angular using the `<script>` tag:
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
|
||||
|
||||
From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data
|
||||
From the `ng-model` attribute of the `<input>` tags, Angular automatically sets up two-way data
|
||||
binding, and we also demonstrate some easy input validation:
|
||||
|
||||
Quantity: <input type="integer" min="0" ng-model="qty" required >
|
||||
@@ -129,7 +129,7 @@ binding, and we also demonstrate some easy input validation:
|
||||
|
||||
These input widgets look normal enough, but consider these points:
|
||||
|
||||
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
|
||||
* When this page loaded, Angular bound the names of the input widgets (`qty` and `cost`) to
|
||||
variables of the same name. Think of those variables as the "Model" component of the
|
||||
Model-View-Controller design pattern.
|
||||
* Note that the HTML widget {@link api/ng.directive:input input}
|
||||
@@ -193,7 +193,7 @@ Angular frees you from the following pain:
|
||||
code. Angular eliminates almost all of this boilerplate, leaving code that describes the
|
||||
overall flow of the application rather than all of the implementation details.
|
||||
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
|
||||
of plumbing just to get a basic "Hello World" AJAX app working. With angular you can bootstrap
|
||||
of plumbing just to get a basic "Hello World" AJAX app working. With Angular you can bootstrap
|
||||
your app easily using services, which are auto-injected into your application in a {@link
|
||||
http://code.google.com/p/google-guice/ Guice}-like dependency-injection style. This allows you
|
||||
to get started developing features quickly. As a bonus, you get full control over the
|
||||
|
||||
@@ -81,7 +81,7 @@ Logically the rendering of `{{greeting}}` involves:
|
||||
You can think of the scope and its properties as the data which is used to render the view. The
|
||||
scope is the single source-of-truth for all things view related.
|
||||
|
||||
From testability, the separation of the controller and the view is desirable, because it allows us
|
||||
From a testability point of view, the separation of the controller and the view is desirable, because it allows us
|
||||
to test the behavior without being distracted by the rendering details.
|
||||
|
||||
<pre>
|
||||
@@ -151,7 +151,7 @@ This example illustrates scopes in application, and prototypical inheritance of
|
||||
</file>
|
||||
</example>
|
||||
|
||||
Notice that the Angular automatically places `ng-scope` class on elements where scopes are
|
||||
Notice that Angular automatically places `ng-scope` class on elements where scopes are
|
||||
attached. The `<style>` definition in this example highlights in red the new scope locations. The
|
||||
child scopes are necessary because the repeater evaluates `{{employee.name}}` expression, but
|
||||
depending on which scope the expression is evaluated it produces different result. Similarly the
|
||||
@@ -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
|
||||
of {@link api/ng.directive:ngApp `ng-app`} directive. Typically
|
||||
`ng-app` is placed an the `<html>` element, but it can be placed on other elements as well, if,
|
||||
for example, only a portion of the view needs to be controlled by angular.
|
||||
for example, only a portion of the view needs to be controlled by Angular.
|
||||
|
||||
To examine the scope in the debugger:
|
||||
|
||||
@@ -218,7 +218,7 @@ api/ng.$rootScope.Scope#$emit emitted} to scope parents.
|
||||
|
||||
## Scope Life Cycle
|
||||
|
||||
The normal flow of browser receiving an event is that it executes a corresponding JavaScript
|
||||
The normal flow of a browser receiving an event is that it executes a corresponding JavaScript
|
||||
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
|
||||
more events.
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
<a name="H1_1"></a>
|
||||
# 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
|
||||
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.
|
||||
|
||||
|
||||
<a name="H1_2"></a>
|
||||
# Contributing to Source Code
|
||||
|
||||
We'd love for you to contribute to our source code and to make `angular` even better than it is
|
||||
today! Here are the guidelines we'd like you to use:
|
||||
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 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
|
||||
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
|
||||
is successfully accepted upstream.
|
||||
@@ -64,45 +64,39 @@ inheritance only when absolutely necessary.
|
||||
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
|
||||
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>
|
||||
# Checking Out and Building Angular
|
||||
|
||||
The `angular` 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`:
|
||||
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
|
||||
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
|
||||
Rake website.
|
||||
|
||||
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
|
||||
quite a good source for information on Git.
|
||||
|
||||
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
|
||||
development web server. Depending on your system, you can install Node either from source or as a
|
||||
pre-packaged bundle.
|
||||
|
||||
You'll also need npm and the following npm modules:
|
||||
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:
|
||||
|
||||
* 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
|
||||
quite a good source for information on Git.
|
||||
* `cd angular.js`
|
||||
* `npm install`
|
||||
|
||||
|
||||
## Creating a Github Account and Forking Angular
|
||||
@@ -112,31 +106,35 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
|
||||
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
|
||||
minified `angular` files:
|
||||
To build AngularJS, you check out the source code and use Rake to generate the non-minified and
|
||||
minified AngularJS files:
|
||||
|
||||
1. To clone your Github repository, run:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
4. To build `angular`, run:
|
||||
4. To add node.js dependencies
|
||||
|
||||
npm install
|
||||
|
||||
5. To build AngularJS, run:
|
||||
|
||||
rake package
|
||||
|
||||
The build output can be located under the `build` directory. It consists of the following files and
|
||||
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.
|
||||
|
||||
* `angular.js` — The non-minified `angular` script.
|
||||
@@ -145,8 +143,6 @@ artifacts.
|
||||
|
||||
* `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/index.html` — The main page for the documentation.
|
||||
@@ -154,60 +150,70 @@ artifacts.
|
||||
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
|
||||
|
||||
|
||||
<a name="webserver"></a>
|
||||
## 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.
|
||||
|
||||
1. To start the web server, run:
|
||||
|
||||
./nodeserver.sh
|
||||
rake webserver
|
||||
|
||||
2. To access the local server, go to this website:
|
||||
|
||||
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>
|
||||
## Running the Unit Test Suite
|
||||
|
||||
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
|
||||
tests:
|
||||
Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
|
||||
tests once on Chrome run:
|
||||
|
||||
1. To start the JSTD server, run:
|
||||
rake 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:
|
||||
rake test:unit[Opera+Firefox]
|
||||
|
||||
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:
|
||||
|
||||
rake 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/
|
||||
|
||||
3. To trigger a test execution, run:
|
||||
|
||||
./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
|
||||
3. To re-run tests just change any source or test file.
|
||||
|
||||
|
||||
## Running the End2End Test Suite
|
||||
To learn more about all of the preconfigured Rake tasks run:
|
||||
|
||||
To run the End2End test suite:
|
||||
rake -T
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
rake webserver
|
||||
|
||||
1. Start the local web server.
|
||||
2. In a browser, go to:
|
||||
|
||||
http://localhost:8000/build/docs/docs-scenario.html
|
||||
|
||||
The tests are executed automatically.
|
||||
or in terminal run:
|
||||
|
||||
rake test:e2e
|
||||
|
||||
|
||||
|
||||
@@ -216,30 +222,38 @@ To run the End2End test suite:
|
||||
|
||||
To create and submit a change:
|
||||
|
||||
1. Create a new branch off the master for your changes:
|
||||
1. 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
|
||||
|
||||
2. Check out the branch:
|
||||
3. Check out the 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
|
||||
|
||||
5. Run JavaScript Lint and be sure to address all new warnings and errors:
|
||||
|
||||
rake lint
|
||||
|
||||
6. Push your branch to Github:
|
||||
|
||||
git push origin my-fix-branch
|
||||
|
||||
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
|
||||
from the main (upstream) repository:
|
||||
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
@name Downloading
|
||||
@description
|
||||
|
||||
# Including angular scripts from the angular server
|
||||
The quickest way to get started is to point your html `<script>` tag to a
|
||||
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
||||
local copy.
|
||||
# Including angular scripts from the Google CDN
|
||||
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
|
||||
This way, you don't have to download anything or maintain a local copy.
|
||||
|
||||
There are two types of angular script URLs you can point to, one for development and one for
|
||||
production:
|
||||
@@ -15,21 +14,25 @@ development.
|
||||
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
||||
production.
|
||||
|
||||
To point your code to an angular script on the angular server, use the following template. This
|
||||
example points to (non-minified) version 0.10.6:
|
||||
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||
example points to the minified version 1.0.2:
|
||||
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<head>
|
||||
<title>My Angular App</title>
|
||||
<script src="http://code.angularjs.org/angular-0.10.6.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
Note that only versions 1.0.1 and above are available on the CDN, if you need an earlier version
|
||||
you can use the <http://code.angularjs.org/> URL which was the previous recommended location for
|
||||
hosted code source. If you're still using the angular server you should switch to the CDN version
|
||||
for even faster loading times.
|
||||
|
||||
# Downloading and hosting angular files locally
|
||||
This option is for those who want to work with angular offline, or those who want to host the
|
||||
@@ -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:
|
||||
|
||||
* __`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
|
||||
should always use this non-minified angular script.
|
||||
|
||||
* __`angular-<version>.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.min.js`__ — This is a minified and obfuscated version of
|
||||
`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.
|
||||
|
||||
* __`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.
|
||||
|
||||
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
|
||||
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
|
||||
* __`angular-mocks.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
|
||||
`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.
|
||||
|
||||
* __`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
|
||||
our docs, or even more importantly, view the docs offline.
|
||||
|
||||
+135
-13
@@ -4,6 +4,8 @@
|
||||
|
||||
#FAQ
|
||||
|
||||
## Questions
|
||||
|
||||
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
|
||||
|
||||
Because HTML has Angular brackets and "ng" sounds like "Angular".
|
||||
@@ -21,7 +23,7 @@ So it's definitely not a plugin or some other native browser extension.
|
||||
### Is AngularJS a templating system?
|
||||
|
||||
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
|
||||
important reason why the Angular templating system is different, that makes it very good fit for
|
||||
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
|
||||
code to constantly sync the view with the model and the model with the view as in other
|
||||
@@ -30,7 +32,7 @@ templating systems.
|
||||
|
||||
### Do I need to worry about security holes in AngularJS?
|
||||
|
||||
Like with any technology, AngularJS is not impervious to attack. angular does, however, provide
|
||||
Like any other technology, AngularJS is not impervious to attack. Angular does, however, provide
|
||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
||||
attacks. AngularJS does round-trip escaping on all strings for you and even offers XSRF protection
|
||||
for server-side communication.
|
||||
@@ -46,9 +48,9 @@ Yes. See instructions in {@link downloading}.
|
||||
|
||||
|
||||
|
||||
### What browsers does angular work with?
|
||||
### What browsers does Angular work with?
|
||||
|
||||
Our we run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
|
||||
|
||||
|
||||
@@ -67,32 +69,152 @@ illustration we typically build snappy apps with hundreds or thousands of active
|
||||
The size of the file is < 29KB compressed and minified.
|
||||
|
||||
|
||||
### Can I use the open-source Closure Library with angular?
|
||||
### 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}
|
||||
in angular.
|
||||
in Angular.
|
||||
|
||||
### Does angular use the jQuery library?
|
||||
### Does Angular use the jQuery library?
|
||||
|
||||
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
|
||||
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
|
||||
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
|
||||
|
||||
|
||||
### What is testability like in angular?
|
||||
### 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.
|
||||
|
||||
|
||||
### How can I learn more about angular?
|
||||
### How can I learn more about Angular?
|
||||
|
||||
Watch the July 28, 2010 talk
|
||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
||||
AJAX Apps}".
|
||||
Watch the July 17, 2012 talk
|
||||
"{@link http://www.youtube.com/watch?v=1CpiB3Wk25U AngularJS Intro + Dependency Injection}".
|
||||
|
||||
|
||||
### How is angular licensed?
|
||||
### How is Angular licensed?
|
||||
|
||||
The MIT License.
|
||||
|
||||
### Can I download and use the Angular logo artwork?
|
||||
|
||||
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
|
||||
angular.js/images/logo}"
|
||||
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
|
||||
Creative Commons Attribution-ShareAlike 3.0 Unported License}". If you have some other use in mind, contact us.
|
||||
|
||||
### How can I get some AngularJS schwag?
|
||||
|
||||
We often bring a few t-shirts and stickers to events where we're presenting. If you want to order your own, the folks who
|
||||
make our schwag will be happy to do a custom run for you, based on our existing template. By using the design they have on file,
|
||||
they'll waive the setup costs, and you can order any quantity you need.
|
||||
|
||||
**Stickers**
|
||||
Contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
|
||||
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
|
||||
|
||||
As long as the design stays exactly the same, {@link http://www.stickergiant.com StickerGiant} will give you a reorder discount.
|
||||
|
||||
**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.
|
||||
|
||||
@@ -47,20 +47,23 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
|
||||
# Working with the code
|
||||
|
||||
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
|
||||
code management or to use scripts that copy snapshots of project files into your workspace
|
||||
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your
|
||||
computer for your preferred option.
|
||||
environment. The tutorial relies on the use of Git versioning system for source code management.
|
||||
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
|
||||
and follow the instructions for setting up your computer.
|
||||
|
||||
<div class="tabbable" show="true">
|
||||
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
|
||||
<ol>
|
||||
<li><p>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>
|
||||
<p>You will need Java to run unit tests.</p></li>
|
||||
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p>
|
||||
<p>You can build Git from source or use the pre-compiled package.</p></li>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
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
|
||||
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>
|
||||
@@ -71,77 +74,41 @@ directory.</p></li>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
directory.</p></li>
|
||||
<li><p>You will need an http server running on your system. Mac and Linux machines typically
|
||||
have Apache pre-installed, but If you don't already have one installed, you can <a
|
||||
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run
|
||||
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
||||
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
|
||||
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane well" id="git-win" title="Git on Windows">
|
||||
<ol>
|
||||
<li><p>You will need Java to run unit tests, so run the following command to 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>.</p>
|
||||
<pre>java -version</pre>
|
||||
<p></p></li>
|
||||
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li>
|
||||
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a
|
||||
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
|
||||
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
|
||||
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
|
||||
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
|
||||
command in a terminal window:</p>
|
||||
<pre>node --version</pre>
|
||||
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
|
||||
don't have it already:</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>
|
||||
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
|
||||
<li><p>Change your current directory to angular-phonecat.</p>
|
||||
<pre>cd angular-phonecat</pre>
|
||||
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
|
||||
directory.</p>
|
||||
<p>You should run all <code>git</code> commands from msysGit bash.</p>
|
||||
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be
|
||||
<p>You should run all <code>git</code> commands from Git bash.</p>
|
||||
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
|
||||
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
|
||||
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>
|
||||
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
|
||||
bundled http server.</p></li>
|
||||
</ol>
|
||||
</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
|
||||
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">
|
||||
<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>
|
||||
<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
|
||||
@@ -74,70 +74,6 @@ directory.</li>
|
||||
</li>
|
||||
</ol>
|
||||
</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>
|
||||
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<ul doc-tutorial-nav="1"></ul>
|
||||
|
||||
|
||||
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that angular will use to
|
||||
In order to illustrate how Angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that Angular will use to
|
||||
dynamically display the same result with any set of data.
|
||||
|
||||
In this step you will add some basic information about two cell phones to an HTML page.
|
||||
|
||||
@@ -61,7 +61,7 @@ repeater tells Angular to create a `<li>` element for each phone in the list usi
|
||||
tag as the template.
|
||||
|
||||
* 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.
|
||||
|
||||
<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}.
|
||||
|
||||
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
|
||||
`./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
|
||||
execute the tests and report the results in the terminal.
|
||||
|
||||
4. Execute the test by running `./scripts/test.sh`
|
||||
|
||||
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)
|
||||
info: Testacular server started at http://localhost:9876/
|
||||
info (launcher): Starting browser "Chrome"
|
||||
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
|
||||
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
|
||||
|
||||
Yay! The test passed! Or not...
|
||||
|
||||
Note: If you see errors after you run the test, close the browser window and go back to the
|
||||
terminal and kill the script, then repeat the procedure above.
|
||||
4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
|
||||
and will rerun the tests for you. Now isn't that sweet?
|
||||
|
||||
# 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>
|
||||
</table>
|
||||
|
||||
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
|
||||
`./scripts/test.sh` script.
|
||||
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
@@ -54,7 +54,7 @@ __`app/index.html`:__
|
||||
</div>
|
||||
</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.directive:ngRepeat ngRepeat} directive.
|
||||
|
||||
@@ -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`
|
||||
* 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
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
following output.
|
||||
You should now see the following output in the Testacular tab:
|
||||
|
||||
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)
|
||||
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
|
||||
|
||||
|
||||
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.
|
||||
|
||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||
can see them running on {@link
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
`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
|
||||
Angular's server}.
|
||||
|
||||
|
||||
@@ -208,13 +208,10 @@ Finally, we verify that the default value of `orderProp` is set correctly:
|
||||
});
|
||||
</pre>
|
||||
|
||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||
output.
|
||||
You should now see the following output in the Testacular tab:
|
||||
|
||||
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
|
||||
|
||||
@@ -84,8 +84,8 @@ __`test/e2e/scenarios.js`__:
|
||||
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.
|
||||
|
||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||
can see them running on {@link
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
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
|
||||
Angular's server}.
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ history (back and forward navigation) and bookmarks.
|
||||
|
||||
### A Note About DI, Injector and Providers
|
||||
|
||||
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} is the core feature of
|
||||
As you {@link tutorial/step_05 noticed}, {@link guide/di dependency injection} (DI) is the core feature of
|
||||
AngularJS, so it's important for you to understand a thing or two about how it works.
|
||||
|
||||
When the application bootstraps, Angular creates an injector that will be used for all DI stuff in
|
||||
@@ -79,7 +79,7 @@ angular.module('phonecat', []).
|
||||
</pre>
|
||||
|
||||
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.
|
||||
|
||||
Note that during the injector configuration phase, the providers can be injected as well, but they
|
||||
@@ -232,8 +232,8 @@ to various URLs and verify that the correct view was rendered.
|
||||
</pre>
|
||||
|
||||
|
||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||
can see them running on {@link
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
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
|
||||
Angular's server}.
|
||||
|
||||
|
||||
@@ -147,13 +147,9 @@ __`test/unit/controllersSpec.js`:__
|
||||
...
|
||||
</pre>
|
||||
|
||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||
output.
|
||||
You should now see the following output in the Testacular tab:
|
||||
|
||||
Chrome: Runner reset.
|
||||
...
|
||||
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)
|
||||
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
|
||||
|
||||
|
||||
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
|
||||
@@ -177,11 +173,12 @@ __`test/e2e/scenarios.js`:__
|
||||
</pre>
|
||||
|
||||
|
||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||
can see them running on {@link
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
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
|
||||
Angular's server}.
|
||||
|
||||
|
||||
# Experiments
|
||||
|
||||
* Using the {@link guide/dev_guide.e2e-testing Angular's end-to-end test runner API}, write a test
|
||||
|
||||
@@ -110,13 +110,9 @@ describe('filter', function() {
|
||||
Note that you need to configure our test injector with the `phonecatFilters` module before any of
|
||||
our filter tests execute.
|
||||
|
||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||
output.
|
||||
You should now see the following output in the Testacular tab:
|
||||
|
||||
Chrome: Runner reset.
|
||||
....
|
||||
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)
|
||||
Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
|
||||
|
||||
|
||||
# Experiments
|
||||
|
||||
@@ -102,8 +102,8 @@ __`test/e2e/scenarios.js`:__
|
||||
});
|
||||
</pre>
|
||||
|
||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||
can see them running on {@link
|
||||
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
|
||||
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
|
||||
Angular's server}.
|
||||
|
||||
|
||||
@@ -214,13 +214,9 @@ describe('PhoneCat controllers', function() {
|
||||
});
|
||||
</pre>
|
||||
|
||||
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
|
||||
output.
|
||||
You should now see the following output in the Testacular tab:
|
||||
|
||||
Chrome: Runner reset.
|
||||
....
|
||||
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)
|
||||
Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||
previous steps using the `git checkout` 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
|
||||
{@link guide/ Developer Guide}.
|
||||
|
||||
@@ -36,7 +36,7 @@ writer.makeDir('build/docs/', true).then(function() {
|
||||
});
|
||||
}).then(function printStats() {
|
||||
console.log('DONE. Generated ' + docs.length + ' pages in ' + (now()-start) + 'ms.' );
|
||||
}).end();
|
||||
}).done();
|
||||
|
||||
|
||||
function writeTheRest(writesFuture) {
|
||||
@@ -82,10 +82,7 @@ function writeTheRest(writesFuture) {
|
||||
writesFuture.push(writer.output('appcache.manifest',appCache()));
|
||||
writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
|
||||
|
||||
writesFuture.push(writer.symlinkTemplate('app.yaml'));
|
||||
writesFuture.push(writer.symlinkTemplate('index.yaml'));
|
||||
writesFuture.push(writer.symlinkTemplate('favicon.ico'));
|
||||
writesFuture.push(writer.symlinkTemplate('main.py'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#
|
||||
# This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version.
|
||||
|
||||
Options -Indexes
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
|
||||
RewriteRule appcache.manifest appcache-offline.manifest
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
application: docs-angularjs-org
|
||||
version: 1
|
||||
runtime: python27
|
||||
api_version: 1
|
||||
threadsafe: yes
|
||||
default_expiration: "2h"
|
||||
|
||||
handlers:
|
||||
- url: /
|
||||
script: main.app
|
||||
|
||||
- url: /appcache.manifest
|
||||
static_files: appcache.manifest
|
||||
upload: appcache\.manifest
|
||||
|
||||
- url: /docs-scenario.html
|
||||
static_files: docs-scenario.html
|
||||
upload: docs-scenario\.html
|
||||
|
||||
- url: /docs-scenario.js
|
||||
static_files: docs-scenario.js
|
||||
upload: docs-scenario\.js
|
||||
|
||||
- url: /favicon\.ico
|
||||
static_files: favicon.ico
|
||||
upload: favicon\.ico
|
||||
|
||||
- url: /docs-keywords.js
|
||||
static_files: docs-keywords.js
|
||||
upload: docs-keywords\.js
|
||||
|
||||
- url: /robots.txt
|
||||
static_files: robots.txt
|
||||
upload: robots\.txt
|
||||
|
||||
- url: /sitemap.xml
|
||||
static_files: sitemap.xml
|
||||
upload: sitemap\.xml
|
||||
|
||||
- url: /css
|
||||
static_dir: css
|
||||
|
||||
- url: /font
|
||||
static_dir: font
|
||||
|
||||
- url: /img
|
||||
static_dir: img
|
||||
|
||||
- url: /js
|
||||
static_dir: js
|
||||
|
||||
- url: /partials/(.+):(.+)
|
||||
static_files: partials/\1_\2
|
||||
upload: partials/.*
|
||||
|
||||
- url: /partials
|
||||
static_dir: partials
|
||||
|
||||
- url: /syntaxhighlighter
|
||||
static_dir: syntaxhighlighter
|
||||
|
||||
- url: /.*
|
||||
static_files: index.html
|
||||
upload: index.html
|
||||
|
||||
|
||||
libraries:
|
||||
- name: webapp2
|
||||
version: "2.5.1"
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<title>AngularJS Docs E2E Test Runner</title>
|
||||
<script>
|
||||
var gae = (location.pathname.split('/').length == 2),
|
||||
var production = location.hostname === 'docs.angularjs.org',
|
||||
headEl = document.head,
|
||||
angularVersion = {
|
||||
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||
@@ -33,9 +33,8 @@
|
||||
|
||||
|
||||
function path(name) {
|
||||
return gae
|
||||
? 'http://code.angularjs.org/' + angularVersion.stable + '/' +
|
||||
name.replace(/\.js$/, '-' + angularVersion.stable + '.js')
|
||||
return production
|
||||
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
|
||||
: '../' + name;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
baseUrl = location.href.replace(rUrl, indexFile),
|
||||
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
|
||||
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
|
||||
gae = (baseUrl.split('/').length == 4),
|
||||
production = location.hostname === 'docs.angularjs.org',
|
||||
headEl = document.getElementsByTagName('head')[0],
|
||||
sync = true,
|
||||
angularVersion = {
|
||||
@@ -45,7 +45,7 @@
|
||||
addTag('script', {src: 'docs-keywords.js'}, sync);
|
||||
|
||||
function path(name) {
|
||||
if (gae) {
|
||||
if (production) {
|
||||
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
|
||||
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
|
||||
angularVersion.stable +
|
||||
@@ -55,7 +55,7 @@
|
||||
name = 'http://code.angularjs.org/' +
|
||||
angularVersion.stable +
|
||||
'/' +
|
||||
name.replace(/\.js$/, '-' + angularVersion.stable +'.min.js');
|
||||
name.replace(/\.js$/, '.min.js');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -122,14 +122,14 @@
|
||||
<li><a href="http://angularjs.org"><i class="icon-home icon-white"></i> Home</a></li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<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="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>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -139,16 +139,16 @@
|
||||
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="tutorial">Tutorial</a></li>
|
||||
<li><a href="guide/">Developer Guide</a></li>
|
||||
<li><a href="api/">API Reference</a></li>
|
||||
<li><a href="misc/contribute">Contribute</a></li>
|
||||
<li><a href="http://docs.angularjs.org/tutorial">Tutorial</a></li>
|
||||
<li><a href="http://docs.angularjs.org/guide/">Developer Guide</a></li>
|
||||
<li><a href="http://docs.angularjs.org/api/">API Reference</a></li>
|
||||
<li><a href="http://docs.angularjs.org/misc/contribute">Contribute</a></li>
|
||||
<li><a href="http://code.angularjs.org/">Download</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="icon-comment icon-white"></i> Discuss <b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
indexes:
|
||||
|
||||
# AUTOGENERATED
|
||||
|
||||
# This index.yaml is automatically updated whenever the dev_appserver
|
||||
# detects that a new type of query is run. If you want to manage the
|
||||
# index.yaml file manually, remove the above marker line (the line
|
||||
# saying "# AUTOGENERATED"). If you want to manage some indexes
|
||||
# manually, move them above the marker line. The index.yaml file is
|
||||
# automatically uploaded to the admin console when you next deploy
|
||||
# your application using appcfg.py.
|
||||
|
||||
@@ -30,9 +30,17 @@ docsApp.directive.code = function() {
|
||||
|
||||
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||
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,
|
||||
controller: function($scope, $attrs, openJsFiddle) {
|
||||
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
|
||||
var sources = {
|
||||
module: $attrs.sourceEdit,
|
||||
deps: read($attrs.sourceEditDeps),
|
||||
@@ -45,14 +53,19 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||
$scope.fiddle = function(e) {
|
||||
e.stopPropagation();
|
||||
openJsFiddle(sources);
|
||||
}
|
||||
};
|
||||
$scope.plunkr = function(e) {
|
||||
e.stopPropagation();
|
||||
openPlunkr(sources);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function read(text) {
|
||||
var files = [];
|
||||
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;
|
||||
}
|
||||
@@ -111,8 +124,6 @@ docsApp.directive.docTutorialReset = function() {
|
||||
'<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 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');
|
||||
}
|
||||
};
|
||||
@@ -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>',
|
||||
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}}',
|
||||
@@ -297,7 +349,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
|
||||
tutorial: 'Tutorial',
|
||||
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
|
||||
if (DOCS_PATH.test(path)) {
|
||||
var parts = path.split('/'),
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import webapp2
|
||||
from google.appengine.ext.webapp import template
|
||||
|
||||
|
||||
class IndexHandler(webapp2.RequestHandler):
|
||||
def get(self):
|
||||
fragment = self.request.get('_escaped_fragment_')
|
||||
|
||||
if fragment:
|
||||
fragment = '/partials' + fragment + '.html'
|
||||
self.redirect(fragment, permanent=True)
|
||||
else:
|
||||
self.response.headers['Content-Type'] = 'text/html'
|
||||
self.response.out.write(template.render('index-nocache.html', None))
|
||||
|
||||
|
||||
app = webapp2.WSGIApplication([('/', IndexHandler)])
|
||||
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
JASMINE_NODE='jasmine-node'
|
||||
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
|
||||
# Locally (npm)-installed jasmine-node
|
||||
local_jasmine='./node_modules/.bin/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
|
||||
|
||||
@@ -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- ');
|
||||
});
|
||||
}
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Script to initialize angular repo
|
||||
# - install required node packages
|
||||
# - install Testacular
|
||||
# - install git hooks
|
||||
|
||||
|
||||
node=`which node 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Please install NodeJS."
|
||||
echo "http://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm=`which npm 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Please install NPM."
|
||||
fi
|
||||
|
||||
|
||||
echo "Installing required npm packages..."
|
||||
npm install
|
||||
|
||||
testacular=`which testacular 2>&1`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Installing Testacular..."
|
||||
npm install -g testacular
|
||||
fi
|
||||
|
||||
echo "Installing git hooks..."
|
||||
ln -sf ../../validate-commit-msg.js .git/hooks/commit-msg
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/sh
|
||||
/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java $@
|
||||
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* @fileoverview Jasmine JsTestDriver Adapter.
|
||||
* @author misko@hevery.com (Misko Hevery)
|
||||
*/
|
||||
(function(window) {
|
||||
var rootDescribes = new Describes(window);
|
||||
var describePath = [];
|
||||
rootDescribes.collectMode();
|
||||
|
||||
var JASMINE_TYPE = 'jasmine test case';
|
||||
TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE);
|
||||
|
||||
var jasminePlugin = {
|
||||
name:'jasmine',
|
||||
|
||||
getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) {
|
||||
for (var i = 0; i < testCaseInfos.length; i++) {
|
||||
if (testCaseInfos[i].getType() == JASMINE_TYPE) {
|
||||
testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
runTestConfiguration: function(testRunConfiguration, onTestDone, onTestRunConfigurationComplete){
|
||||
if (testRunConfiguration.getTestCaseInfo().getType() != JASMINE_TYPE) return false;
|
||||
|
||||
var jasmineEnv = jasmine.currentEnv_ = new jasmine.Env();
|
||||
rootDescribes.playback();
|
||||
var specLog = jstestdriver.console.log_ = [];
|
||||
var start;
|
||||
jasmineEnv.specFilter = function(spec) {
|
||||
return rootDescribes.isExclusive(spec);
|
||||
};
|
||||
jasmineEnv.reporter = {
|
||||
log: function(str){
|
||||
specLog.push(str);
|
||||
},
|
||||
|
||||
reportRunnerStarting: function(runner) { },
|
||||
|
||||
reportSpecStarting: function(spec) {
|
||||
specLog = jstestdriver.console.log_ = [];
|
||||
start = new Date().getTime();
|
||||
},
|
||||
|
||||
reportSpecResults: function(spec) {
|
||||
var suite = spec.suite;
|
||||
var results = spec.results();
|
||||
if (results.skipped) return;
|
||||
var end = new Date().getTime();
|
||||
var messages = [];
|
||||
var resultItems = results.getItems();
|
||||
var state = 'passed';
|
||||
for ( var i = 0; i < resultItems.length; i++) {
|
||||
if (!resultItems[i].passed()) {
|
||||
state = resultItems[i].message.match(/AssertionError:/) ? 'error' : 'failed';
|
||||
messages.push({
|
||||
message: resultItems[i].toString(),
|
||||
name: resultItems[i].trace.name,
|
||||
stack: formatStack(resultItems[i].trace.stack)
|
||||
});
|
||||
}
|
||||
}
|
||||
onTestDone(
|
||||
new jstestdriver.TestResult(
|
||||
suite.getFullName(),
|
||||
spec.description,
|
||||
state,
|
||||
jstestdriver.angular.toJson(messages),
|
||||
specLog.join('\n'),
|
||||
end - start));
|
||||
},
|
||||
|
||||
reportSuiteResults: function(suite) {},
|
||||
|
||||
reportRunnerResults: function(runner) {
|
||||
onTestRunConfigurationComplete();
|
||||
}
|
||||
};
|
||||
jasmineEnv.execute();
|
||||
return true;
|
||||
},
|
||||
|
||||
onTestsFinish: function(){
|
||||
jasmine.currentEnv_ = null;
|
||||
rootDescribes.collectMode();
|
||||
}
|
||||
};
|
||||
jstestdriver.pluginRegistrar.register(jasminePlugin);
|
||||
|
||||
function formatStack(stack) {
|
||||
var lines = (stack||'').split(/\r?\n/);
|
||||
var frames = [];
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
if (!lines[i].match(/\/jasmine[\.-]/)) {
|
||||
frames.push(lines[i].replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, ' '));
|
||||
}
|
||||
}
|
||||
return frames.join('\n');
|
||||
}
|
||||
|
||||
function noop(){}
|
||||
function Describes(window){
|
||||
var describes = {};
|
||||
var beforeEachs = {};
|
||||
var afterEachs = {};
|
||||
// Here we store:
|
||||
// 0: everyone runs
|
||||
// 1: run everything under ddescribe
|
||||
// 2: run only iits (ignore ddescribe)
|
||||
var exclusive = 0;
|
||||
var collectMode = true;
|
||||
intercept('describe', describes);
|
||||
intercept('xdescribe', describes);
|
||||
intercept('beforeEach', beforeEachs);
|
||||
intercept('afterEach', afterEachs);
|
||||
|
||||
function intercept(functionName, collection){
|
||||
window[functionName] = function(desc, fn){
|
||||
if (collectMode) {
|
||||
collection[desc] = function(){
|
||||
jasmine.getEnv()[functionName](desc, fn);
|
||||
};
|
||||
} else {
|
||||
jasmine.getEnv()[functionName](desc, fn);
|
||||
}
|
||||
};
|
||||
}
|
||||
window.ddescribe = function(name, fn){
|
||||
if (exclusive < 1) {
|
||||
exclusive = 1; // run ddescribe only
|
||||
}
|
||||
window.describe(name, function(){
|
||||
var oldIt = window.it;
|
||||
window.it = function(name, fn){
|
||||
if (fn) fn.exclusive = 1; // run anything under ddescribe
|
||||
oldIt(name, fn);
|
||||
};
|
||||
try {
|
||||
fn.call(this);
|
||||
} finally {
|
||||
window.it = oldIt;
|
||||
};
|
||||
});
|
||||
};
|
||||
window.iit = function(name, fn){
|
||||
exclusive = fn.exclusive = 2; // run only iits
|
||||
jasmine.getEnv().it(name, fn);
|
||||
};
|
||||
|
||||
|
||||
this.collectMode = function() {
|
||||
collectMode = true;
|
||||
exclusive = 0; // run everything
|
||||
};
|
||||
this.playback = function(){
|
||||
collectMode = false;
|
||||
playback(beforeEachs);
|
||||
playback(afterEachs);
|
||||
playback(describes);
|
||||
|
||||
function playback(set) {
|
||||
for ( var name in set) {
|
||||
set[name]();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.isExclusive = function(spec) {
|
||||
if (exclusive) {
|
||||
var blocks = spec.queue.blocks;
|
||||
for ( var i = 0; i < blocks.length; i++) {
|
||||
if (blocks[i].func.exclusive >= exclusive) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
})(window);
|
||||
|
||||
// Patch Jasmine for proper stack traces
|
||||
jasmine.Spec.prototype.fail = function (e) {
|
||||
var expectationResult = new jasmine.ExpectationResult({
|
||||
passed: false,
|
||||
message: e ? jasmine.util.formatException(e) : 'Exception'
|
||||
});
|
||||
// PATCH
|
||||
if (e) {
|
||||
expectationResult.trace = e;
|
||||
}
|
||||
this.results_.addResult(expectationResult);
|
||||
};
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
da92db714142b49f9cf61db664e782bb0ccad80b
|
||||
@@ -1,20 +0,0 @@
|
||||
Copyright (c) 2008-2011 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,190 +0,0 @@
|
||||
jasmine.TrivialReporter = function(doc) {
|
||||
this.document = doc || document;
|
||||
this.suiteDivs = {};
|
||||
this.logRunningSpecs = false;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
|
||||
var el = document.createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(document.createTextNode(child));
|
||||
} else {
|
||||
if (child) { el.appendChild(child); }
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == "className") {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
|
||||
var showPassed, showSkipped;
|
||||
|
||||
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
|
||||
this.createDom('div', { className: 'banner' },
|
||||
this.createDom('div', { className: 'logo' },
|
||||
this.createDom('span', { className: 'title' }, "Jasmine"),
|
||||
this.createDom('span', { className: 'version' }, runner.env.versionString())),
|
||||
this.createDom('div', { className: 'options' },
|
||||
"Show ",
|
||||
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
|
||||
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
|
||||
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
|
||||
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
|
||||
)
|
||||
),
|
||||
|
||||
this.runnerDiv = this.createDom('div', { className: 'runner running' },
|
||||
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
|
||||
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
|
||||
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
|
||||
);
|
||||
|
||||
this.document.body.appendChild(this.outerDiv);
|
||||
|
||||
var suites = runner.suites();
|
||||
for (var i = 0; i < suites.length; i++) {
|
||||
var suite = suites[i];
|
||||
var suiteDiv = this.createDom('div', { className: 'suite' },
|
||||
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
|
||||
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
|
||||
this.suiteDivs[suite.id] = suiteDiv;
|
||||
var parentDiv = this.outerDiv;
|
||||
if (suite.parentSuite) {
|
||||
parentDiv = this.suiteDivs[suite.parentSuite.id];
|
||||
}
|
||||
parentDiv.appendChild(suiteDiv);
|
||||
}
|
||||
|
||||
this.startedAt = new Date();
|
||||
|
||||
var self = this;
|
||||
showPassed.onclick = function(evt) {
|
||||
if (showPassed.checked) {
|
||||
self.outerDiv.className += ' show-passed';
|
||||
} else {
|
||||
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
|
||||
}
|
||||
};
|
||||
|
||||
showSkipped.onclick = function(evt) {
|
||||
if (showSkipped.checked) {
|
||||
self.outerDiv.className += ' show-skipped';
|
||||
} else {
|
||||
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
|
||||
var results = runner.results();
|
||||
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
|
||||
this.runnerDiv.setAttribute("class", className);
|
||||
//do it twice for IE
|
||||
this.runnerDiv.setAttribute("className", className);
|
||||
var specs = runner.specs();
|
||||
var specCount = 0;
|
||||
for (var i = 0; i < specs.length; i++) {
|
||||
if (this.specFilter(specs[i])) {
|
||||
specCount++;
|
||||
}
|
||||
}
|
||||
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
|
||||
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
|
||||
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
|
||||
|
||||
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
|
||||
var results = suite.results();
|
||||
var status = results.passed() ? 'passed' : 'failed';
|
||||
if (results.totalCount === 0) { // todo: change this to check results.skipped
|
||||
status = 'skipped';
|
||||
}
|
||||
this.suiteDivs[suite.id].className += " " + status;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
|
||||
if (this.logRunningSpecs) {
|
||||
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
|
||||
var results = spec.results();
|
||||
var status = results.passed() ? 'passed' : 'failed';
|
||||
if (results.skipped) {
|
||||
status = 'skipped';
|
||||
}
|
||||
var specDiv = this.createDom('div', { className: 'spec ' + status },
|
||||
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
|
||||
this.createDom('a', {
|
||||
className: 'description',
|
||||
href: '?spec=' + encodeURIComponent(spec.getFullName()),
|
||||
title: spec.getFullName()
|
||||
}, spec.description));
|
||||
|
||||
|
||||
var resultItems = results.getItems();
|
||||
var messagesDiv = this.createDom('div', { className: 'messages' });
|
||||
for (var i = 0; i < resultItems.length; i++) {
|
||||
var result = resultItems[i];
|
||||
|
||||
if (result.type == 'log') {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
|
||||
} else if (result.type == 'expect' && result.passed && !result.passed()) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
|
||||
|
||||
if (result.trace.stack) {
|
||||
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (messagesDiv.childNodes.length > 0) {
|
||||
specDiv.appendChild(messagesDiv);
|
||||
}
|
||||
|
||||
this.suiteDivs[spec.suite.id].appendChild(specDiv);
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.log = function() {
|
||||
var console = jasmine.getGlobal().console;
|
||||
if (console && console.log) {
|
||||
if (console.log.apply) {
|
||||
console.log.apply(console, arguments);
|
||||
} else {
|
||||
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.getLocation = function() {
|
||||
return this.document.location;
|
||||
};
|
||||
|
||||
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
|
||||
var paramMap = {};
|
||||
var params = this.getLocation().search.substring(1).split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
|
||||
}
|
||||
|
||||
if (!paramMap.spec) {
|
||||
return true;
|
||||
}
|
||||
return spec.getFullName().indexOf(paramMap.spec) === 0;
|
||||
};
|
||||
@@ -1,166 +0,0 @@
|
||||
body {
|
||||
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.jasmine_reporter a:visited, .jasmine_reporter a {
|
||||
color: #303;
|
||||
}
|
||||
|
||||
.jasmine_reporter a:hover, .jasmine_reporter a:active {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.run_spec {
|
||||
float:right;
|
||||
padding-right: 5px;
|
||||
font-size: .8em;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.jasmine_reporter {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
color: #303;
|
||||
background-color: #fef;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 1.1em;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.logo .version {
|
||||
font-size: .6em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.runner.running {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
|
||||
.options {
|
||||
text-align: right;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.suite {
|
||||
border: 1px outset gray;
|
||||
margin: 5px 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.suite .suite {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.suite.passed {
|
||||
background-color: #dfd;
|
||||
}
|
||||
|
||||
.suite.failed {
|
||||
background-color: #fdd;
|
||||
}
|
||||
|
||||
.spec {
|
||||
margin: 5px;
|
||||
padding-left: 1em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.spec.failed, .spec.passed, .spec.skipped {
|
||||
padding-bottom: 5px;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
.spec.failed {
|
||||
background-color: #fbb;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.spec.passed {
|
||||
background-color: #bfb;
|
||||
border-color: green;
|
||||
}
|
||||
|
||||
.spec.skipped {
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
.messages {
|
||||
border-left: 1px dashed gray;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.passed {
|
||||
background-color: #cfc;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.failed {
|
||||
background-color: #fbb;
|
||||
}
|
||||
|
||||
.skipped {
|
||||
color: #777;
|
||||
background-color: #eee;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/*.resultMessage {*/
|
||||
/*white-space: pre;*/
|
||||
/*}*/
|
||||
|
||||
.resultMessage span.result {
|
||||
display: block;
|
||||
line-height: 2em;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.resultMessage .mismatch {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.stackTrace {
|
||||
white-space: pre;
|
||||
font-size: .8em;
|
||||
margin-left: 10px;
|
||||
max-height: 5em;
|
||||
overflow: auto;
|
||||
border: 1px inset red;
|
||||
padding: 1em;
|
||||
background: #eef;
|
||||
}
|
||||
|
||||
.finished-at {
|
||||
padding-left: 1em;
|
||||
font-size: .6em;
|
||||
}
|
||||
|
||||
.show-passed .passed,
|
||||
.show-skipped .skipped {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
#jasmine_content {
|
||||
position:fixed;
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.runner {
|
||||
border: 1px solid gray;
|
||||
display: block;
|
||||
margin: 5px 0;
|
||||
padding: 2px 0 2px 10px;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 905 B |
@@ -1 +0,0 @@
|
||||
1.1.0
|
||||
BIN
Binary file not shown.
@@ -1,130 +0,0 @@
|
||||
#
|
||||
# Configuration File for JavaScript Lint 0.3.0
|
||||
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
|
||||
#
|
||||
# This configuration file can be used to lint a collection of scripts, or to enable
|
||||
# or disable warnings for scripts that are linted via the command line.
|
||||
#
|
||||
|
||||
### Warnings
|
||||
# Enable or disable warnings based on requirements.
|
||||
# Use "+WarningName" to display or "-WarningName" to suppress.
|
||||
#
|
||||
-no_return_value # function {0} does not always return a value
|
||||
+duplicate_formal # duplicate formal argument {0}
|
||||
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
|
||||
+var_hides_arg # variable {0} hides argument
|
||||
+redeclared_var # redeclaration of {0} {1}
|
||||
-anon_no_return_value # anonymous function does not always return a value
|
||||
+missing_semicolon # missing semicolon
|
||||
+meaningless_block # meaningless block; curly braces have no impact
|
||||
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
|
||||
-unreachable_code # unreachable code
|
||||
-missing_break # missing break statement
|
||||
+missing_break_for_last_case # missing break statement for last case in switch
|
||||
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
|
||||
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
|
||||
+useless_void # use of the void type may be unnecessary (void is always undefined)
|
||||
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
|
||||
+use_of_label # use of label
|
||||
-block_without_braces # block statement without curly braces
|
||||
+leading_decimal_point # leading decimal point may indicate a number or an object member
|
||||
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
|
||||
+octal_number # leading zeros make an octal number
|
||||
+nested_comment # nested comment
|
||||
-misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
|
||||
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
|
||||
+empty_statement # empty statement or extra semicolon
|
||||
-missing_option_explicit # the "option explicit" control comment is missing
|
||||
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
|
||||
+dup_option_explicit # duplicate "option explicit" control comment
|
||||
+useless_assign # useless assignment
|
||||
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
|
||||
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
|
||||
-missing_default_case # missing default case in switch statement
|
||||
+duplicate_case_in_switch # duplicate case in switch statements
|
||||
+default_not_at_end # the default case is not at the end of the switch statement
|
||||
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
|
||||
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
|
||||
+useless_comparison # useless comparison; comparing identical expressions
|
||||
+with_statement # with statement hides undeclared variables; use temporary variable instead
|
||||
+trailing_comma_in_array # extra comma is not recommended in array initializers
|
||||
+assign_to_function_call # assignment to a function call
|
||||
+parseint_missing_radix # parseInt missing radix parameter
|
||||
|
||||
|
||||
### Output format
|
||||
# Customize the format of the error message.
|
||||
# __FILE__ indicates current file path
|
||||
# __FILENAME__ indicates current file name
|
||||
# __LINE__ indicates current line
|
||||
# __ERROR__ indicates error message
|
||||
#
|
||||
# Visual Studio syntax (default):
|
||||
+output-format __FILE__(__LINE__): __ERROR__
|
||||
# Alternative syntax:
|
||||
#+output-format __FILE__:__LINE__: __ERROR__
|
||||
|
||||
|
||||
### Context
|
||||
# Show the in-line position of the error.
|
||||
# Use "+context" to display or "-context" to suppress.
|
||||
#
|
||||
+context
|
||||
|
||||
|
||||
### Semicolons
|
||||
# By default, assignments of an anonymous function to a variable or
|
||||
# property (such as a function prototype) must be followed by a semicolon.
|
||||
#
|
||||
+lambda_assign_requires_semicolon
|
||||
|
||||
|
||||
### Control Comments
|
||||
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
|
||||
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
|
||||
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
|
||||
# although legacy control comments are enabled by default for backward compatibility.
|
||||
#
|
||||
+legacy_control_comments
|
||||
|
||||
|
||||
### JScript Function Extensions
|
||||
# JScript allows member functions to be defined like this:
|
||||
# function MyObj() { /*constructor*/ }
|
||||
# function MyObj.prototype.go() { /*member function*/ }
|
||||
#
|
||||
# It also allows events to be attached like this:
|
||||
# function window::onload() { /*init page*/ }
|
||||
#
|
||||
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
|
||||
#
|
||||
-jscript_function_extensions
|
||||
|
||||
|
||||
### Defining identifiers
|
||||
# By default, "option explicit" is enabled on a per-file basis.
|
||||
# To enable this for all files, use "+always_use_option_explicit"
|
||||
-always_use_option_explicit
|
||||
|
||||
# Define certain identifiers of which the lint is not aware.
|
||||
# (Use this in conjunction with the "undeclared identifier" warning.)
|
||||
#
|
||||
# Common uses for webpages might be:
|
||||
#+define window
|
||||
#+define document
|
||||
|
||||
|
||||
### Files
|
||||
# Specify which files to lint
|
||||
# Use "+recurse" to enable recursion (disabled by default).
|
||||
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
|
||||
# or "+process Folder\Path\*.htm".
|
||||
#
|
||||
+process src/*.js
|
||||
+process src/service/*.js
|
||||
+process src/scenario/*.js
|
||||
+process test/*.js
|
||||
+process test/service/*.js
|
||||
+process test/scenario/*.js
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
1.3.3d
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
./gen_docs.sh
|
||||
|
||||
rm build/docs/index.html
|
||||
rm -rf build/docs/css
|
||||
rm -rf build/docs/js
|
||||
rm -rf build/docs/img
|
||||
rm -rf build/docs/examples
|
||||
|
||||
cd build/docs
|
||||
|
||||
ln -s ../../docs/src/templates/index.html
|
||||
ln -s ../../docs/src/templates/css
|
||||
ln -s ../../docs/src/templates/js
|
||||
ln -s ../../docs/img
|
||||
ln -s ../../docs/examples
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "AngularJS",
|
||||
"version": "0.0.0",
|
||||
"dependencies" : {
|
||||
"testacular" : "canary",
|
||||
"jasmine-node" : "*",
|
||||
"q-fs" : "*",
|
||||
"qq" : "*"
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
|
||||
This test demonstrates the time difference between document's DOMContentLoaded and window's load events.
|
||||
|
||||
-->
|
||||
<html>
|
||||
<head ng:app>
|
||||
<script>
|
||||
startTS = new Date().getTime();
|
||||
onDOMContentLoadedTS = 0; // default for browsers where DOMCL is not supported
|
||||
</script>
|
||||
<title>DOMContentLoaded test</title>
|
||||
<script src="../build/angular.min.js"></script>
|
||||
<script>
|
||||
angular.element(document).bind('DOMContentLoaded', function(e) {onDOMContentLoadedTS = new Date().getTime()});
|
||||
angular.element(window).bind('load', function(e) {
|
||||
onloadTS = new Date().getTime();
|
||||
log.innerHTML = 'start: ' + new Date(startTS) + '<br/>DOMContentLoaded: +' + (onDOMContentLoadedTS - startTS) + 'ms<br/> load: +' + (onloadTS - startTS) + 'ms';
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DOMContentLoaded test</h1>
|
||||
<p>{{ 'yay!' || 'angular starting...' }}</p>
|
||||
|
||||
<img width="100px" src="http://lh5.ggpht.com/_BLyMhylclm0/TST_bbGH0zI/AAAAAAAAATY/oNUn9kivKN8/s912/1020047.jpg" />
|
||||
<img width="100px" src="http://lh5.ggpht.com/_MqEybfAuUFk/TSOOiegUlPI/AAAAAAAADHY/AEwEWc64_-M/s800/IMG_7294.JPG" />
|
||||
<img width="100px" src="http://lh3.ggpht.com/_LdjD3ua8rpE/TSOW99rwjZI/AAAAAAAAFC0/0qJRhhN45RM/s912/Saison%2010%20%2834%29.JPG" />
|
||||
<img width="100px" src="http://lh6.ggpht.com/_oy_-am3CVUw/TSOQBddZpwI/AAAAAAAACaw/ogFgoD79bVE/s912/P1100886.JPG" />
|
||||
<img width="100px" src="http://lh4.ggpht.com/_srSaA7ZN7oc/TDdxXbA_i1I/AAAAAAAAQ2w/ii3vgrnfCrM/s800/Urlaub10%20157.jpg" />
|
||||
<img width="100px" src="http://lh5.ggpht.com/_y6vXu6iRrfM/SIaYhRQBYNI/AAAAAAAAAmE/lV2NYwxtsQM/s912/North%20Dakota%20Trip%20014.JPG" />
|
||||
<img width="100px" src="http://lh5.ggpht.com/_Jjv9cIn9cS8/RuwZCgfOl6I/AAAAAAAAAOc/QrrMe8vpawg/s800/Shark%20Trip%20-%20day%202%20513.JPG" />
|
||||
|
||||
<p id="log"></p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,21 +0,0 @@
|
||||
describe('perf misc', function() {
|
||||
it('operation speeds', function() {
|
||||
perf(
|
||||
function typeByTypeof() { return typeof noop == 'function'; }, // WINNER
|
||||
function typeByProperty() { return noop.apply && noop.call; },
|
||||
function typeByConstructor() { return noop.constructor == Function; }
|
||||
);
|
||||
});
|
||||
|
||||
it('property access', function() {
|
||||
var name = 'value';
|
||||
var none = 'x';
|
||||
var scope = {};
|
||||
perf(
|
||||
function direct() { return scope.value; }, // WINNER
|
||||
function byName() { return scope[name]; },
|
||||
function undefinedDirect() { return scope.x; },
|
||||
function undefiendByName() { return scope[none]; }
|
||||
);
|
||||
});
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user