Compare commits
125 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2a769e196 | |||
| 68a8c8907d | |||
| 701d61080a | |||
| a8cc449706 | |||
| 2aa212b19c | |||
| 1f23cfe9c7 | |||
| 0fa8e47fb5 | |||
| 8043784fd7 | |||
| 526a6b31e5 | |||
| 14fd064a62 | |||
| 3178afbf0c | |||
| ce3b616432 | |||
| 54a761905d | |||
| aa531d7bd1 | |||
| d7e9ae1215 | |||
| 6cf9ede88e | |||
| 6092291bd7 | |||
| 3d0f11212f | |||
| 6194e002e2 | |||
| 75545d4d1c | |||
| d67eb2f2db | |||
| 6b8153ff0f | |||
| fb132732f1 | |||
| 336b157497 | |||
| d16975a9de | |||
| 87f6b36bab | |||
| 43fccf5617 | |||
| a5b3bcf41c | |||
| 8801d9c286 | |||
| a8e114f351 | |||
| 9a3a9b46e5 | |||
| 934204ec18 | |||
| 7cb8f8fb44 | |||
| 8d34bf2fea | |||
| 8801e69dba | |||
| f4afa398a1 | |||
| 32063278bd | |||
| 92208d2f85 | |||
| ab7c74b4b9 | |||
| e283abe171 | |||
| d7620f68bb | |||
| 971d97e2ec | |||
| 559d5efc04 | |||
| 85042820fb | |||
| 24a2eec815 | |||
| d987a79ab1 | |||
| eba09353e6 | |||
| 297660c9a3 | |||
| 8343c05fd8 | |||
| 7c3d064786 | |||
| c2ccc1cbdf | |||
| 04e080660a | |||
| f3cca88384 | |||
| 978bbd2d49 | |||
| 652feebd86 | |||
| 16ccbc4f61 | |||
| 072d45fd01 | |||
| 4439e39319 | |||
| b49c3a1a1e | |||
| c7addd4886 | |||
| 6df60aff52 | |||
| e7a080d6e6 | |||
| 661a728764 | |||
| 89303fd2dc | |||
| 1f8be1ca66 | |||
| cbc2024092 | |||
| f0ff7023c3 | |||
| 6e8728a364 | |||
| f179a63dd4 | |||
| 3a71c1e595 | |||
| ef7a61a67e | |||
| a6b2ee785b | |||
| d5a1336e6b | |||
| d4312b731a | |||
| 66f051386e | |||
| 8b3f9684e0 | |||
| 331f32deac | |||
| bb80c96754 | |||
| 0d8e19c26f | |||
| ed2fd2d0ca | |||
| 7c60151cb8 | |||
| 965308a32c | |||
| 92c612a9de | |||
| a7b53abcad | |||
| d575e1f613 | |||
| 2ba458387d | |||
| 98489a1d0c | |||
| 51d501aab2 | |||
| 841bdf1c07 | |||
| 86cac55c7c | |||
| c0995399d4 | |||
| de6cc287e5 | |||
| afd6771163 | |||
| 4cda028609 | |||
| 8ecce7642b | |||
| d1d5761232 | |||
| 759cba1a8d | |||
| 23cd40a8ec | |||
| f3188c1d09 | |||
| 2f4967f100 | |||
| 4fe4e7457c | |||
| d4e7274d4b | |||
| cffa015554 | |||
| 1104c7d75b | |||
| 4c6b4447db | |||
| 741a37b338 | |||
| 1157c5d341 | |||
| e48adebfb7 | |||
| 0a61dcb486 | |||
| 4b51eaadf8 | |||
| e2457ca16d | |||
| bd62790080 | |||
| 53fdcafa44 | |||
| af6f2483be | |||
| d8522aa349 | |||
| bae3121683 | |||
| 54c0d464b0 | |||
| cf89e8653c | |||
| 0c3500f532 | |||
| c12f525df4 | |||
| e7ba830691 | |||
| 4eb0716711 | |||
| ed90f3b7ea | |||
| 14b19ecf5e | |||
| 644432a14c |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <launchConfigurationWorkingSet editPageId="org.eclipse.ui.resourceWorkingSetPage" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1262905463390_2" label="workingSet" name="workingSet"> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/test" type="2"/> <item factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/angular.js/src" type="2"/> </launchConfigurationWorkingSet>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js}/test.sh"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/perf" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/perf.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/build" type="2"/> </resources>}"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> <item path="/angular.js/src" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/angular.js/docs" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/gen_docs.sh}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/angular.js/lib/jsl/jsl}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-conf lib/jsl/jsl.default.conf"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/angular.js}"/>
|
||||
</launchConfiguration>
|
||||
@@ -1,14 +0,0 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
@@ -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
|
||||
+240
-1
@@ -1,8 +1,247 @@
|
||||
<a name="1.1.3"></a>
|
||||
# 1.1.3 radioactive-gargle (2013-02-20)
|
||||
|
||||
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||
They pass all tests but we reserve the right to change new features/apis in between minor releases. Check them
|
||||
out and please give us feedback._
|
||||
|
||||
_Note: This release also contains all bug fixes available in [1.0.5](#1.0.5)._
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- initialize interpolated attributes before directive linking
|
||||
([bb8448c0](https://github.com/angular/angular.js/commit/bb8448c011127306df08c7479b66e5afe7a0fa94))
|
||||
- interpolate @ locals before the link function runs
|
||||
([2ed53087](https://github.com/angular/angular.js/commit/2ed53087d7dd06d728e333a449265f7685275548))
|
||||
- **$http:**
|
||||
- do not encode special characters `@$:,` in params
|
||||
([288b69a3](https://github.com/angular/angular.js/commit/288b69a314e9bd14458b6647532eb62aad5c5cdf))
|
||||
- **$resource:**
|
||||
- params should expand array values properly
|
||||
([2a212344](https://github.com/angular/angular.js/commit/2a2123441c2b749b8f316a24c3ca3f77a9132a01))
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$http:** allow overriding the XSRF header and cookie name
|
||||
([8155c3a2](https://github.com/angular/angular.js/commit/8155c3a29ea0eb14806913b8ac08ba7727e1969c))
|
||||
- **$parse:** added `constant` and `literal` properties
|
||||
([1ed63858](https://github.com/angular/angular.js/commit/1ed638582d2f2c7f89384d9712f4cfac52cc5b70))
|
||||
- **$resource:** expose promise based api via $then and $resolved
|
||||
([dba6bc73](https://github.com/angular/angular.js/commit/dba6bc73e802fdae685a9f351d3e23c7efa8568a))
|
||||
- **$routeProvider:** add support to catch-all parameters in routes
|
||||
([7eafbb98](https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5))
|
||||
- **Scope:**
|
||||
- expose transcluded and isolate scope info for batarang
|
||||
([649b8922](https://github.com/angular/angular.js/commit/649b892205615a144dafff9984c0e6ab10ed341d))
|
||||
- only evaluate constant $watch expressions once
|
||||
([1d7a95df](https://github.com/angular/angular.js/commit/1d7a95df565192fc02a18b0b297b39dd615eaeb5))
|
||||
- **angular.noConflict:** added api to restore previous angular namespace reference
|
||||
([12ba6cec](https://github.com/angular/angular.js/commit/12ba6cec4fb79521101744e02a7e09f9fbb591c4))
|
||||
- **Directives:**
|
||||
- **ngSwitch:** support multiple matches on ngSwitchWhen and ngSwitchDefault
|
||||
([0af17204](https://github.com/angular/angular.js/commit/0af172040e03811c59d01682968241e3df226774),
|
||||
[#1074](https://github.com/angular/angular.js/issues/1074))
|
||||
- **Filters:**
|
||||
- **date:** add `[.,]sss` formatter for milliseconds
|
||||
([df744f3a](https://github.com/angular/angular.js/commit/df744f3af46fc227a934f16cb63c7a6038e7133b))
|
||||
- **filter:** add comparison function to filter
|
||||
([ace54ff0](https://github.com/angular/angular.js/commit/ace54ff08c4593195b49eadb04d258e6409d969e))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **$http:** due to [288b69a3](https://github.com/angular/angular.js/commit/288b69a314e9bd14458b6647532eb62aad5c5cdf),
|
||||
$http now follows RFC3986 and does not encode special characters like `$@,:` in params.
|
||||
If your application needs to encode these characters, encode them manually, before sending the request.
|
||||
- **$resource:** due to [2a212344](https://github.com/angular/angular.js/commit/2a2123441c2b749b8f316a24c3ca3f77a9132a01),
|
||||
if the server relied on the buggy behavior of serializing arrays as http query arguments then
|
||||
either the backend should be fixed or a simple serialization of the array should be done
|
||||
on the client before calling the resource service.
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="1.0.5"></a>
|
||||
# 1.0.5 flatulent-propulsion (2013-02-20)
|
||||
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- sanitize values bound to a[href]
|
||||
([9532234b](https://github.com/angular/angular.js/commit/9532234bf1c408af9a6fd2c4743fdb585b920531))
|
||||
- rename $compileNote to compileNode
|
||||
([92ca7efa](https://github.com/angular/angular.js/commit/92ca7efaa4bc4f37da3008b234e19343a1fa4207),
|
||||
[#1941](https://github.com/angular/angular.js/issues/1941))
|
||||
- should not leak memory when there are top level empty text nodes
|
||||
([791804bd](https://github.com/angular/angular.js/commit/791804bdbfa6da7a39283623bd05628a01cd8720))
|
||||
- allow startingTag method to handle text / comment nodes
|
||||
([755beb2b](https://github.com/angular/angular.js/commit/755beb2b66ce9f9f9a218f2355bbaf96d94fbc15))
|
||||
- **$cookies:** set cookies on Safari&IE when base[href] is undefined
|
||||
([70909245](https://github.com/angular/angular.js/commit/7090924515214752b919b0c5630b3ea5e7c77223),
|
||||
[#1190](https://github.com/angular/angular.js/issues/1190))
|
||||
- **$http:**
|
||||
- patch for Firefox bug w/ CORS and response headers
|
||||
([e19b04c9](https://github.com/angular/angular.js/commit/e19b04c9ec985821edf1269c628cfa261f81d631),
|
||||
[#1468](https://github.com/angular/angular.js/issues/1468))
|
||||
- **$resource:**
|
||||
- update RegExp to allow urlParams with out leading slash
|
||||
([b7e1fb05](https://github.com/angular/angular.js/commit/b7e1fb0515798e1b4f3f2426f6b050951bee2617))
|
||||
- **Directives:**
|
||||
- **a:** workaround IE bug affecting mailto urls
|
||||
([37e8b122](https://github.com/angular/angular.js/commit/37e8b12265291918396bfee65d444a8f63697b73),
|
||||
[#1949](https://github.com/angular/angular.js/issues/1949))
|
||||
- **ngClass:** keep track of old ngClass value manually
|
||||
([5f5d4fea](https://github.com/angular/angular.js/commit/5f5d4feadbfa9d8ecc8150041dfd2bca2b2e9fea),
|
||||
[#1637](https://github.com/angular/angular.js/issues/1637))
|
||||
- **ngSwitch:** make ngSwitch compatible with controller backwards-compatiblity module
|
||||
([9b7c1d0f](https://github.com/angular/angular.js/commit/9b7c1d0f7ce442d4ad2ec587e66d2d335e64fa4e))
|
||||
- **Filters:**
|
||||
- **date:** invert timezone sign and always display sign
|
||||
([b001c8ec](https://github.com/angular/angular.js/commit/b001c8ece5472626bf49cf82753e8ac1aafd2513),
|
||||
[#1261](https://github.com/angular/angular.js/issues/1261))
|
||||
- **number:** fix formatting when "0" passed as fractionSize
|
||||
([f5835963](https://github.com/angular/angular.js/commit/f5835963d5982003a713dd354eefd376ed39ac02))
|
||||
- **scenario runner:** include error messages in XML output
|
||||
([d46fe3c2](https://github.com/angular/angular.js/commit/d46fe3c23fa269dcc10249148f2af14f3db6b066))
|
||||
- **Misc:**
|
||||
- don't use instanceof to detect arrays
|
||||
([3c2aee01](https://github.com/angular/angular.js/commit/3c2aee01b0b299995eb92f4255159585b0f53c10),
|
||||
[#1966](https://github.com/angular/angular.js/issues/1966))
|
||||
- angular.forEach should correctly iterate over objects with length prop
|
||||
([ec54712f](https://github.com/angular/angular.js/commit/ec54712ff3dab1ade44f94fa82d67edeffa79a1d),
|
||||
[#1840](https://github.com/angular/angular.js/issues/1840))
|
||||
|
||||
|
||||
|
||||
<a name="1.1.2"></a>
|
||||
# 1.1.2 tofu-animation (2013-01-22)
|
||||
|
||||
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||
They pass all tests but we reserve the right to change new features/apis in between minor releases. Check them
|
||||
out and please give us feedback._
|
||||
|
||||
_Note: This release also contains all bug fixes available in [1.0.4](#1.0.4)._
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** support modifying the DOM structure in postlink fn
|
||||
([cdf6fb19](https://github.com/angular/angular.js/commit/cdf6fb19c85560b30607e71dc2b19fde54760faa))
|
||||
- **$log:** add $log.debug()
|
||||
([9e991ddb](https://github.com/angular/angular.js/commit/9e991ddb1de13adf520eda459950be5b90b5b6d9),
|
||||
[#1592](https://github.com/angular/angular.js/issues/1592))
|
||||
- **$parse:** allow strict equality in angular expressions
|
||||
([a179a9a9](https://github.com/angular/angular.js/commit/a179a9a96eda5c566bda8a70ac8a75822c936a68),
|
||||
[#908](https://github.com/angular/angular.js/issues/908))
|
||||
- **$resource:**
|
||||
- allow dynamic default parameters
|
||||
([cc42c99b](https://github.com/angular/angular.js/commit/cc42c99bec6a03d6c41b8e1d29ba2b1f5c16b87d))
|
||||
- support all $http.config actions
|
||||
([af89daf4](https://github.com/angular/angular.js/commit/af89daf4641f57b92be6c1f3635f5a3237f20c71))
|
||||
- **$route:** allow using functions as template params in 'when'
|
||||
([faf02f0c](https://github.com/angular/angular.js/commit/faf02f0c4db7962f863b0da2a82c8cafab2c706f))
|
||||
- **$timeout-mock:** add verifyNoPendingTasks method
|
||||
([f0c6ebc0](https://github.com/angular/angular.js/commit/f0c6ebc07653f6267acec898ccef5677884e3081),
|
||||
[#1245](https://github.com/angular/angular.js/issues/1245))
|
||||
- **directive:**
|
||||
- added ngOpen boolean directive
|
||||
([b8bd4d54](https://github.com/angular/angular.js/commit/b8bd4d5460d9952e9a3bb14992636b17859bd457))
|
||||
- ngKeydown, ngKeyup
|
||||
([e03182f0](https://github.com/angular/angular.js/commit/e03182f018f5069acd5e883ce2e9349b83f2d03f),
|
||||
[#1035](https://github.com/angular/angular.js/issues/1035))
|
||||
- **limitTo filter:** limitTo filter accepts strings
|
||||
([9e96d983](https://github.com/angular/angular.js/commit/9e96d983451899ef0cef3e68395c8f6c1ef83bbe),
|
||||
[#653](https://github.com/angular/angular.js/issues/653))
|
||||
- **scenario:**
|
||||
- add mouseover method to the ngScenario dsl
|
||||
([2f437e89](https://github.com/angular/angular.js/commit/2f437e89781cb2b449abb685e36b26ca1cf0fff5))
|
||||
- fail when an option to select does not exist
|
||||
([15183f3e](https://github.com/angular/angular.js/commit/15183f3e1fbee031c9595206163962788f98b298))
|
||||
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- **date:** due to [cc821502](https://github.com/angular/angular.js/commit/cc821502bca64d15e1c576bf20a62b28b3d9a88a),
|
||||
string input without timezone info is now parsed as local time/date
|
||||
|
||||
|
||||
|
||||
<a name="1.0.4"></a>
|
||||
# 1.0.4 bewildering-hair (2013-01-22)
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **$compile:**
|
||||
- do not wrap empty root text nodes in spans
|
||||
([49f9e4ce](https://github.com/angular/angular.js/commit/49f9e4cef13e68ff85b3c160cf8fac6e7cd042a3),
|
||||
[#1059](https://github.com/angular/angular.js/issues/1059))
|
||||
- safely create transclude comment nodes
|
||||
([74dd2f79](https://github.com/angular/angular.js/commit/74dd2f7980ea8ec434a6e0565d857c910653ed9b),
|
||||
[#1740](https://github.com/angular/angular.js/issues/1740))
|
||||
- **$injector:**
|
||||
- remove bogus fn arg
|
||||
([b6b7c5a1](https://github.com/angular/angular.js/commit/b6b7c5a1d66073937709158da8c2d688cb45c9f6),
|
||||
[#1711](https://github.com/angular/angular.js/issues/1711))
|
||||
- provider can now be defined in the array format
|
||||
([2c405f41](https://github.com/angular/angular.js/commit/2c405f417125c80c387a51baece8bf6e1e0c0a81),
|
||||
[#1452](https://github.com/angular/angular.js/issues/1452))
|
||||
- **$resource:**
|
||||
- HTTP method should be case-insensitive
|
||||
([8991680d](https://github.com/angular/angular.js/commit/8991680d8ab632dda60cd70c780868c803c74509),
|
||||
[#1403](https://github.com/angular/angular.js/issues/1403))
|
||||
- correct leading slash removal in resource URLs
|
||||
([b2f46251](https://github.com/angular/angular.js/commit/b2f46251aca76c8568ee7d4bab54edbc9d7a186a))
|
||||
- **$route:**
|
||||
- support route params not separated with slashes.
|
||||
([c6392616](https://github.com/angular/angular.js/commit/c6392616ea5245bd0d2f77dded0b948d9e2637c8))
|
||||
- correctly extract $routeParams from urls
|
||||
([30a9da5d](https://github.com/angular/angular.js/commit/30a9da5dc159dd1e19b677914356925c7ebdf632))
|
||||
- **Scope:** ensure that a scope is destroyed only once
|
||||
([d6da505f](https://github.com/angular/angular.js/commit/d6da505f4e044f8a487ac27a3ec707c11853ee0a),
|
||||
[#1627](https://github.com/angular/angular.js/issues/1627))
|
||||
- **angular.equals:**
|
||||
- consistently compare undefined object props
|
||||
([5ae63fd3](https://github.com/angular/angular.js/commit/5ae63fd385295d5a7bbdc79466f59727dcab1c85),
|
||||
[3c2e1c5e](https://github.com/angular/angular.js/commit/3c2e1c5e4d12529b1d69a6173c38097527dccc4f),
|
||||
[#1648](https://github.com/angular/angular.js/issues/1648))
|
||||
- **date filter:** parse string input as local time unless TZ is specified
|
||||
([cc821502](https://github.com/angular/angular.js/commit/cc821502bca64d15e1c576bf20a62b28b3d9a88a),
|
||||
[#847](https://github.com/angular/angular.js/issues/847))
|
||||
- **jqLite:**
|
||||
- children() should only return elements
|
||||
([febb4c1c](https://github.com/angular/angular.js/commit/febb4c1c35cf767ae31fc9fef1f4b4f026ac9de0))
|
||||
- make next() ignore non-element nodes
|
||||
([76a6047a](https://github.com/angular/angular.js/commit/76a6047af690781b8238ba7924279470ba76d081))
|
||||
- **scenario:** don't trigger input events on IE9
|
||||
([8b9e6c35](https://github.com/angular/angular.js/commit/8b9e6c3501746edb2c9e2d585e8e0eaeb8ba8327))
|
||||
- **Directives:**
|
||||
- **ngRepeat:** correctly apply $last if repeating over object
|
||||
([7e746015](https://github.com/angular/angular.js/commit/7e746015ea7dec3e9eb81bc4678fa9b6a83bc47c),
|
||||
[#1789](https://github.com/angular/angular.js/issues/1789))
|
||||
- **ngSwitch:** don't leak when destroyed while not attached
|
||||
([a26234f7](https://github.com/angular/angular.js/commit/a26234f7183013e2fcc9b35377e181ad96dc9917),
|
||||
[#1621](https://github.com/angular/angular.js/issues/1621))
|
||||
- **select:** support optgroup + select[multiple] combo
|
||||
([26adeb11](https://github.com/angular/angular.js/commit/26adeb119bc4fafa6286de484626b8de4170abc9),
|
||||
[#1553](https://github.com/angular/angular.js/issues/1553))
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **$compile:** support modifying the DOM structure in postlink fn
|
||||
([cdf6fb19](https://github.com/angular/angular.js/commit/cdf6fb19c85560b30607e71dc2b19fde54760faa))
|
||||
|
||||
|
||||
|
||||
<a name="1.1.1"></a>
|
||||
# 1.1.1 pathological-kerning (2012-11-26)
|
||||
|
||||
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html).
|
||||
They pass all tests but we reseve the right to change new features/apis in between minor releases. Check them
|
||||
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)._
|
||||
|
||||
@@ -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:
|
||||
@@ -26,10 +26,6 @@ Building AngularJS
|
||||
|
||||
Running Tests
|
||||
-------------
|
||||
Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
|
||||
|
||||
sudo npm install -g testacular
|
||||
|
||||
To execute all unit tests, use:
|
||||
|
||||
rake test:unit
|
||||
|
||||
@@ -21,6 +21,8 @@ task :default => [:package]
|
||||
|
||||
desc 'Init the build workspace'
|
||||
task :init do
|
||||
%x(npm install)
|
||||
|
||||
FileUtils.mkdir(BUILD_DIR) unless File.directory?(BUILD_DIR)
|
||||
|
||||
v = YAML::load( File.open( 'version.yaml' ) )
|
||||
@@ -131,9 +133,15 @@ task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter
|
||||
end
|
||||
|
||||
|
||||
desc 'Generate version.txt file'
|
||||
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
|
||||
|
||||
|
||||
@@ -286,14 +294,22 @@ 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 \
|
||||
-client \
|
||||
-d32 \
|
||||
#{java32flags()} \
|
||||
-jar lib/closure-compiler/compiler.jar \
|
||||
--compilation_level SIMPLE_OPTIMIZATIONS \
|
||||
--language_in ECMASCRIPT5_STRICT \
|
||||
@@ -348,6 +364,8 @@ end
|
||||
|
||||
|
||||
def start_testacular(config, singleRun, browsers, misc_options)
|
||||
Rake::Task[:init].invoke
|
||||
|
||||
sh "./node_modules/testacular/bin/testacular start " +
|
||||
"#{config} " +
|
||||
"#{'--single-run=true' if singleRun} " +
|
||||
|
||||
Vendored
-1
@@ -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',
|
||||
|
||||
+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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
{@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,21 +59,21 @@ 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -233,8 +233,8 @@ The separation of the controller and the view is important because:
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
|
||||
|
||||
The model is the data which is used merged with the template to produce the view. To be able to
|
||||
render the model into the view, the model has to be referenceable from the scope. Unlike many
|
||||
other frameworks Angular makes no restrictions or requirements an the model. There are no classes
|
||||
render the model into the view, the model has to be able to be referenced from the scope. Unlike many
|
||||
other frameworks Angular makes no restrictions or requirements on the model. There are no classes
|
||||
to inherit from or special accessor methods for accessing or changing the model. The model can be
|
||||
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
|
||||
|
||||
@@ -248,9 +248,9 @@ primitive, object hash, or a full object Type. In short the model is a plain Jav
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
||||
|
||||
The view is what the users sees. The view begins its life as a template, it is merged with the
|
||||
The view is what the user sees. The view begins its life as a template, is merged with the
|
||||
model and finally rendered into the browser DOM. Angular takes a very different approach to
|
||||
rendering the view, to most other templating systems.
|
||||
rendering the view compared to most other templating systems.
|
||||
|
||||
* **Others** - Most templating systems begin as an HTML string with special templating markup.
|
||||
Often the template markup breaks the HTML syntax which means that the template can not be
|
||||
@@ -261,9 +261,9 @@ rendering the view, to most other templating systems.
|
||||
is the granularity of the DOM updates. The key here is that the templating system manipulates
|
||||
strings.
|
||||
* **Angular** - Angular is different, since its templating system works on DOM objects not on
|
||||
strings. The template is still written in HTML string, but it is HTML (not HTML with
|
||||
template sprinkled in.) The browser parses the HTML into DOM, and the DOM becomes the input to
|
||||
the template engine know as the {@link api/ng.$compile compiler}. The compiler
|
||||
strings. The template is still written in an HTML string, but it is HTML (not HTML with
|
||||
template sprinkled in.) The browser parses the HTML into the DOM, and the DOM becomes the input to
|
||||
the template engine known as the {@link api/ng.$compile compiler}. The compiler
|
||||
looks for {@link guide/directive directives} which in turn set up {@link
|
||||
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
|
||||
continuously updating view which does not need template model re-merging. Your model becomes
|
||||
@@ -291,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,7 +337,7 @@ in HTML.
|
||||
<a name="filters"></a>
|
||||
# Filters
|
||||
|
||||
{@link api/ng.$filter Filters} perform data transformation roles. Typically
|
||||
{@link api/ng.$filter Filters} perform data transformation. Typically
|
||||
they are used in conjunction with the locale to format the data in locale specific output.
|
||||
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
|
||||
|
||||
@@ -358,7 +358,7 @@ They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
|
||||
|
||||
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||
|
||||
An {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
The {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||
{@link api/AUTO.$injector injector} per Angular {@link
|
||||
api/ng.directive:ngApp application}. The {@link
|
||||
api/AUTO.$injector injector} provides a way to look up an object instance by its
|
||||
@@ -438,7 +438,7 @@ dependencies, look for dependencies, or even get a reference to the injector.
|
||||
</file>
|
||||
<file name="script.js">
|
||||
angular.module('timeExampleModule', []).
|
||||
// Declare new object call time,
|
||||
// Declare new object called time,
|
||||
// which will be available for injection
|
||||
factory('time', function($timeout) {
|
||||
var time = {};
|
||||
|
||||
@@ -11,7 +11,7 @@ that will help you verify the health of your Angular application.
|
||||
|
||||
# Overview
|
||||
You will write scenario tests in JavaScript, which describe how your application should behave,
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more it blocks
|
||||
given a certain interaction in a specific state. A scenario is comprised of one or more `it` blocks
|
||||
(you can think of these as the requirements of your application), which in turn are made of
|
||||
**commands** and **expectations**. Commands tell the Runner to do something with the application
|
||||
(such as navigate to a page or click on a button), and expectations tell the Runner to assert
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,9 +2,7 @@
|
||||
@name Developer Guide: Templates: Understanding Angular Filters
|
||||
@description
|
||||
|
||||
Angular filters format data for display to the user. In addition to formatting data, filters can
|
||||
also modify the DOM. This allows filters to handle tasks such as conditionally applying CSS styles
|
||||
to filtered output.
|
||||
Angular filters format data for display to the user.
|
||||
|
||||
For example, you might have a data object that needs to be formatted according to the locale before
|
||||
displaying it to the user. You can pass expressions through a chain of filters like this:
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -95,7 +95,7 @@ Compilation of HTML happens in three phases:
|
||||
var $compile = ...; // injected into your code
|
||||
var scope = ...;
|
||||
|
||||
var html = '<div ng-bind='exp'></div>';
|
||||
var html = '<div ng-bind="exp"></div>';
|
||||
|
||||
// Step 1: parse HTML into DOM element
|
||||
var template = angular.element(html);
|
||||
@@ -110,7 +110,7 @@ Compilation of HTML happens in three phases:
|
||||
## Reasons behind the compile/link separation
|
||||
|
||||
At this point you may wonder why the compile process is broken down to a compile and link phase.
|
||||
To understand this, let's look at a real world example with repeater:
|
||||
To understand this, let's look at a real world example with a repeater:
|
||||
|
||||
<pre>
|
||||
Hello {{user}}, you have these actions:
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -342,11 +342,11 @@ compiler}. The attributes are:
|
||||
If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||
local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
||||
`scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
|
||||
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
|
||||
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
||||
map of local variable names and values into the expression wrapper fn. For example, if the
|
||||
expression is `increment(amount)` then we can specify the amount value by calling the
|
||||
`localFn` as `localFn({amount: 22})`.
|
||||
a function wrapper for the `count = count + value` expression. Often it's desirable to
|
||||
pass data from the isolated scope via an expression and to the parent scope, this can be
|
||||
done by passing a map of local variable names and values into the expression wrapper fn.
|
||||
For example, if the expression is `increment(amount)` then we can specify the amount value
|
||||
by calling the `localFn` as `localFn({amount: 22})`.
|
||||
|
||||
* `controller` - Controller constructor function. The controller is instantiated before the
|
||||
pre-linking phase and it is shared with other directives if they request it by name (see
|
||||
@@ -474,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
|
||||
@@ -528,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
|
||||
@@ -537,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">
|
||||
@@ -549,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: '=', // set up title to accept data-binding
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
show: '='
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
}
|
||||
</pre>
|
||||
|
||||
@@ -583,7 +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:
|
||||
@@ -591,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
|
||||
@@ -606,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.
|
||||
|
||||
@@ -158,9 +158,9 @@ angular.module('myModule', []).
|
||||
|
||||
angular.module('myModule', []).
|
||||
config(function($provide, $compileProvider, $filterProvider) {
|
||||
$provide.value('a', 123)
|
||||
$provide.factory('a', function() { return 123; })
|
||||
$compileProvider.directive('directiveName', ...).
|
||||
$provide.value('a', 123);
|
||||
$provide.factory('a', function() { return 123; });
|
||||
$compileProvider.directive('directiveName', ...);
|
||||
$filterProvider.register('filterName', ...);
|
||||
});
|
||||
</pre>
|
||||
@@ -194,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
|
||||
@@ -222,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.
|
||||
|
||||
|
||||
@@ -123,7 +123,11 @@ minified AngularJS files:
|
||||
|
||||
git remote add upstream https://github.com/angular/angular.js.git
|
||||
|
||||
4. To build AngularJS, run:
|
||||
4. To add node.js dependencies
|
||||
|
||||
npm install
|
||||
|
||||
5. To build AngularJS, run:
|
||||
|
||||
rake package
|
||||
|
||||
@@ -218,7 +222,8 @@ To run the E2E test suite:
|
||||
|
||||
To create and submit a change:
|
||||
|
||||
1. Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
|
||||
1. <a name="CLA"></a>
|
||||
Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
|
||||
accepted, the CLA must be signed. It's a quick process, we promise!
|
||||
|
||||
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
@name Downloading
|
||||
@description
|
||||
|
||||
# Including angular scripts from the angular server
|
||||
The quickest way to get started is to point your html `<script>` tag to a
|
||||
<http://code.angularjs.org/> URL. This way, you don't have to download anything or maintain a
|
||||
local copy.
|
||||
# Including angular scripts from the Google CDN
|
||||
The quickest way to get started is to point your html `<script>` tag to a Google CDN URL.
|
||||
This way, you don't have to download anything or maintain a local copy.
|
||||
|
||||
There are two types of angular script URLs you can point to, one for development and one for
|
||||
production:
|
||||
@@ -15,21 +14,25 @@ development.
|
||||
* __angular-<version>.min.js__ — This is the minified version, which we strongly suggest you use in
|
||||
production.
|
||||
|
||||
To point your code to an angular script on the angular server, use the following template. This
|
||||
example points to (non-minified) version 1.0.2:
|
||||
To point your code to an angular script on the Google CDN server, use the following template. This
|
||||
example points to the minified version 1.0.2:
|
||||
|
||||
<pre>
|
||||
<!doctype html>
|
||||
<html ng-app>
|
||||
<head>
|
||||
<title>My Angular App</title>
|
||||
<script src="http://code.angularjs.org/1.0.2/angular.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
Note that only versions 1.0.1 and above are available on the CDN, if you need an earlier version
|
||||
you can use the <http://code.angularjs.org/> URL which was the previous recommended location for
|
||||
hosted code source. If you're still using the angular server you should switch to the CDN version
|
||||
for even faster loading times.
|
||||
|
||||
# Downloading and hosting angular files locally
|
||||
This option is for those who want to work with angular offline, or those who want to host the
|
||||
|
||||
@@ -32,7 +32,7 @@ templating systems.
|
||||
|
||||
### Do I need to worry about security holes in AngularJS?
|
||||
|
||||
Like with any technology, AngularJS is not impervious to attack. Angular does, however, provide
|
||||
Like any other technology, AngularJS is not impervious to attack. Angular does, however, provide
|
||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
||||
attacks. AngularJS does round-trip escaping on all strings for you and even offers XSRF protection
|
||||
for server-side communication.
|
||||
@@ -90,15 +90,38 @@ framework, provides mocks for many heavy dependencies (server-side communication
|
||||
|
||||
### How can I learn more about Angular?
|
||||
|
||||
Watch the July 28, 2010 talk
|
||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
||||
AJAX Apps}".
|
||||
Watch the July 17, 2012 talk
|
||||
"{@link http://www.youtube.com/watch?v=1CpiB3Wk25U AngularJS Intro + Dependency Injection}".
|
||||
|
||||
|
||||
### How is Angular licensed?
|
||||
|
||||
The MIT License.
|
||||
|
||||
### Can I download and use the Angular logo artwork?
|
||||
|
||||
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
|
||||
angular.js/images/logo}"
|
||||
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
|
||||
Creative Commons Attribution-ShareAlike 3.0 Unported License}". If you have some other use in mind, contact us.
|
||||
|
||||
### How can I get some AngularJS schwag?
|
||||
|
||||
We often bring a few t-shirts and stickers to events where we're presenting. If you want to order your own, the folks who
|
||||
make our schwag will be happy to do a custom run for you, based on our existing template. By using the design they have on file,
|
||||
they'll waive the setup costs, and you can order any quantity you need.
|
||||
|
||||
**Stickers**
|
||||
Contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
|
||||
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
|
||||
|
||||
As long as the design stays exactly the same, {@link http://www.stickergiant.com StickerGiant} will give you a reorder discount.
|
||||
|
||||
**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
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ __`app/index.html`:__
|
||||
|
||||
<html ng-app>
|
||||
|
||||
The `ng-app` attribute is represents an Angular directive (named `ngApp`; Angular uses
|
||||
The `ng-app` attribute represents an Angular directive (named `ngApp`; Angular uses
|
||||
`name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
|
||||
used to flag an element which Angular should consider to be the root element of our application.
|
||||
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||
@@ -127,7 +127,7 @@ being the element on which the `ngApp` directive was defined.
|
||||
|
||||
* Double-curly binding with an expression:
|
||||
|
||||
Nothing here {{'yet' + '!'}}`
|
||||
Nothing here {{'yet' + '!'}}
|
||||
|
||||
This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<ul doc-tutorial-nav="1"></ul>
|
||||
|
||||
|
||||
In order to illustrate how angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that angular will use to
|
||||
In order to illustrate how Angular enhances standard HTML, you will create a purely *static* HTML
|
||||
page and then examine how we can turn this HTML code into a template that Angular will use to
|
||||
dynamically display the same result with any set of data.
|
||||
|
||||
In this step you will add some basic information about two cell phones to an HTML page.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@description
|
||||
|
||||
Our application is now complete. Feel free to experiment with the code further, and jump back to
|
||||
previous steps using the `git checkout` commandx.
|
||||
previous steps using the `git checkout` command.
|
||||
|
||||
For more details and examples of the Angular concepts we touched on in this tutorial, see the
|
||||
{@link guide/ Developer Guide}.
|
||||
|
||||
+23
-5
@@ -55,12 +55,15 @@ describe('ngdoc', function() {
|
||||
'@name a\n' +
|
||||
'@param {*} a short\n' +
|
||||
'@param {Type} b med\n' +
|
||||
'@param {Class=} [c=2] long\nline');
|
||||
'@param {Class=} [c=2] long\nline\n' +
|
||||
'@param {function(number, string=)} d fn with optional arguments');
|
||||
doc.parse();
|
||||
expect(doc.param).toEqual([
|
||||
{name:'a', description:'<p>short</p>', type:'*', optional:false, 'default':undefined},
|
||||
{name:'b', description:'<p>med</p>', type:'Type', optional:false, 'default':undefined},
|
||||
{name:'c', description:'<p>long\nline</p>', type:'Class', optional:true, 'default':'2'}
|
||||
{name:'c', description:'<p>long\nline</p>', type:'Class', optional:true, 'default':'2'},
|
||||
{name:'d', description:'<p>fn with optional arguments</p>',
|
||||
type: 'function(number, string=)', optional: false, 'default':undefined}
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -318,9 +321,9 @@ describe('ngdoc', function() {
|
||||
});
|
||||
|
||||
it('should not parse @property without a type', function() {
|
||||
var doc = new Doc("@property fake");
|
||||
var doc = new Doc("@property fake", 'test.js', '44');
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow(new Error("Not a valid 'property' format: fake"));
|
||||
toThrow(new Error("Not a valid 'property' format: fake (found in: test.js:44)"));
|
||||
});
|
||||
|
||||
it('should parse @property with type', function() {
|
||||
@@ -350,15 +353,30 @@ describe('ngdoc', function() {
|
||||
describe('@returns', function() {
|
||||
it('should not parse @returns without type', function() {
|
||||
var doc = new Doc("@returns lala");
|
||||
expect(doc.parse).toThrow();
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow();
|
||||
});
|
||||
|
||||
|
||||
it('should not parse @returns with invalid type', function() {
|
||||
var doc = new Doc("@returns {xx}x} lala", 'test.js', 34);
|
||||
expect(function() { doc.parse(); }).
|
||||
toThrow(new Error("Not a valid 'returns' format: {xx}x} lala (found in: test.js:34)"));
|
||||
});
|
||||
|
||||
|
||||
it('should parse @returns with type and description', function() {
|
||||
var doc = new Doc("@name a\n@returns {string} descrip tion");
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip tion</p>'});
|
||||
});
|
||||
|
||||
it('should parse @returns with complex type and description', function() {
|
||||
var doc = new Doc("@name a\n@returns {function(string, number=)} description");
|
||||
doc.parse();
|
||||
expect(doc.returns).toEqual({type: 'function(string, number=)', description: '<p>description</p>'});
|
||||
});
|
||||
|
||||
it('should transform description of @returns with markdown', function() {
|
||||
var doc = new Doc("@name a\n@returns {string} descrip *tion*");
|
||||
doc.parse();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+56
-41
@@ -214,23 +214,25 @@ Doc.prototype = {
|
||||
if (atName) {
|
||||
var text = trim(atText.join('\n')), match;
|
||||
if (atName == 'param') {
|
||||
match = text.match(/^\{([^}=]+)(=)?\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||
// 1 12 2 34 4 5 5 6 6 3 7 7
|
||||
match = text.match(/^\{([^}]+)\}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||
// 1 1 23 3 4 4 5 5 2 6 6
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'param' format: " + text);
|
||||
throw new Error("Not a valid 'param' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
|
||||
var optional = (match[1].slice(-1) === '=');
|
||||
var param = {
|
||||
name: match[5] || match[4],
|
||||
description:self.markdown(text.replace(match[0], match[7])),
|
||||
type: match[1],
|
||||
optional: !!match[2],
|
||||
'default':match[6]
|
||||
name: match[4] || match[3],
|
||||
description:self.markdown(text.replace(match[0], match[6])),
|
||||
type: optional ? match[1].substring(0, match[1].length-1) : match[1],
|
||||
optional: optional,
|
||||
'default':match[5]
|
||||
};
|
||||
self.param.push(param);
|
||||
} else if (atName == 'returns' || atName == 'return') {
|
||||
match = text.match(/^\{([^}=]+)\}\s+(.*)/);
|
||||
match = text.match(/^\{([^}]+)\}\s+(.*)/);
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'returns' format: " + text + ' in ' + self.file + ':' + self.line);
|
||||
throw new Error("Not a valid 'returns' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
self.returns = {
|
||||
type: match[1],
|
||||
@@ -245,7 +247,7 @@ Doc.prototype = {
|
||||
} else if(atName == 'property') {
|
||||
match = text.match(/^\{(\S+)\}\s+(\S+)(\s+(.*))?/);
|
||||
if (!match) {
|
||||
throw new Error("Not a valid 'property' format: " + text);
|
||||
throw new Error("Not a valid 'property' format: " + text + ' (found in: ' + self.file + ':' + self.line + ')');
|
||||
}
|
||||
var property = new Doc({
|
||||
type: match[1],
|
||||
@@ -383,40 +385,53 @@ Doc.prototype = {
|
||||
var self = this;
|
||||
dom.h('Usage', function() {
|
||||
var restrict = self.restrict || 'AC';
|
||||
|
||||
if (restrict.match(/E/)) {
|
||||
dom.text('as element (see ');
|
||||
dom.text('This directive can be used as custom element, but we aware of ');
|
||||
dom.tag('a', {href:'guide/ie'}, 'IE restrictions');
|
||||
dom.text(')');
|
||||
dom.code(function() {
|
||||
dom.text('<');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"');
|
||||
dom.text('>\n</');
|
||||
dom.text(dashCase(self.shortName));
|
||||
dom.text('>');
|
||||
});
|
||||
dom.text('.');
|
||||
}
|
||||
if (restrict.match(/A/)) {
|
||||
var element = self.element || 'ANY';
|
||||
dom.text('as attribute');
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' ');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"', true);
|
||||
dom.text('>\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/C/)) {
|
||||
dom.text('as class');
|
||||
var element = self.element || 'ANY';
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' class="');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams(' ', ': ', ';', true);
|
||||
dom.text('">\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
|
||||
if (self.usage) {
|
||||
dom.tag('pre', function() {
|
||||
dom.tag('code', function() {
|
||||
dom.text(self.usage);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (restrict.match(/E/)) {
|
||||
dom.text('as element:');
|
||||
dom.code(function() {
|
||||
dom.text('<');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"');
|
||||
dom.text('>\n</');
|
||||
dom.text(dashCase(self.shortName));
|
||||
dom.text('>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/A/)) {
|
||||
var element = self.element || 'ANY';
|
||||
dom.text('as attribute');
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' ');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams('\n ', '="', '"', true);
|
||||
dom.text('>\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
if (restrict.match(/C/)) {
|
||||
dom.text('as class');
|
||||
var element = self.element || 'ANY';
|
||||
dom.code(function() {
|
||||
dom.text('<' + element + ' class="');
|
||||
dom.text(dashCase(self.shortName));
|
||||
renderParams(' ', ': ', ';', true);
|
||||
dom.text('">\n ...\n');
|
||||
dom.text('</' + element + '>');
|
||||
});
|
||||
}
|
||||
}
|
||||
self.html_usage_directiveInfo(dom);
|
||||
self.html_usage_parameters(dom);
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<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">
|
||||
@@ -148,7 +148,7 @@
|
||||
</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">
|
||||
|
||||
@@ -37,7 +37,8 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
|
||||
'<ul class="dropdown-menu">' +
|
||||
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
|
||||
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
|
||||
'</ul>',
|
||||
'</ul>' +
|
||||
'</div>',
|
||||
scope: true,
|
||||
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
|
||||
var sources = {
|
||||
@@ -189,7 +190,9 @@ docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angula
|
||||
});
|
||||
|
||||
postData['files[index.html]'] = templateMerge(indexHtmlContent, indexProp);
|
||||
|
||||
postData['tags[]'] = "angularjs";
|
||||
|
||||
postData.private = true;
|
||||
postData.description = 'AngularJS Example Plunkr';
|
||||
|
||||
formPostData('http://plnkr.co/edit/?p=preview', postData);
|
||||
|
||||
+4
-4
@@ -2,9 +2,9 @@
|
||||
"name": "AngularJS",
|
||||
"version": "0.0.0",
|
||||
"dependencies" : {
|
||||
"testacular" : "canary",
|
||||
"jasmine-node" : "*",
|
||||
"q-fs" : "*",
|
||||
"qq" : "*"
|
||||
"testacular" : "0.5.9",
|
||||
"jasmine-node" : "1.2.3",
|
||||
"q-fs" : "0.1.36",
|
||||
"qq" : "0.3.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -1,49 +0,0 @@
|
||||
def generate_object(f, objName, iterations)
|
||||
f.write("var #{objName}='[");
|
||||
|
||||
iterations.times do |i|
|
||||
f.write('{')
|
||||
|
||||
f.write('"simpleStringProperty":') #23
|
||||
f.write('"some string value ' + ('%07d' % i) + '"') #27
|
||||
f.write(',')
|
||||
|
||||
f.write('"stringWithQuotes":') #19
|
||||
f.write('"some string with \\\\"quotes\\\\" ' + ('%07d' % i) + '"') #36
|
||||
f.write(',')
|
||||
|
||||
f.write('"stringWithUnicode":')
|
||||
f.write('"short string with \\u1234 unicode \\u2345 chars ' + ('%07d' % i) + '"')
|
||||
f.write(',')
|
||||
|
||||
f.write('"aNumber":') #10
|
||||
f.write(i) #?
|
||||
f.write(',')
|
||||
|
||||
f.write('"smallArray":')
|
||||
f.write('["a",23,"b",42,' + i.to_s + ']')
|
||||
f.write(',')
|
||||
|
||||
f.write('"smallObj":')
|
||||
f.write('{"foo":"bar","baz":543,"num":' + i.to_s + ',"fuz":"fuz buz huz duz ' + i.to_s + '"}')
|
||||
f.write(',')
|
||||
|
||||
f.write('"timeStamp":')
|
||||
f.write('"2010-12-22T04:58:01.' + ("%03d" % (i%1000)) + '"')
|
||||
|
||||
f.write('},')
|
||||
end
|
||||
|
||||
f.write('"just a padding string"]\';' + "\n\n");
|
||||
end
|
||||
|
||||
file_path = File.join(File.dirname(__FILE__), 'jsonParserPayload.js')
|
||||
|
||||
File.open(file_path, 'w') do |f|
|
||||
generate_object(f, 'superTinyJsonString', 1) #~300b
|
||||
generate_object(f, 'tinyJsonString', 3) #~1kb
|
||||
generate_object(f, 'smallJsonString', 30) #~10kb
|
||||
generate_object(f, 'mediumJsonString', 600) #~200kb
|
||||
generate_object(f, 'largeJsonString', 2000) #~650kb
|
||||
end
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
describe('json', function() {
|
||||
|
||||
it('angular parser', function() {
|
||||
perf(
|
||||
function angular() {
|
||||
fromJson(largeJsonString);
|
||||
},
|
||||
function nativeDelegate() {
|
||||
fromJson(largeJsonString, true);
|
||||
},
|
||||
function nativeJSON() {
|
||||
JSON.parse(largeJsonString);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<script>
|
||||
function el(id) {
|
||||
return document.getElementById(id);
|
||||
}
|
||||
function update() {
|
||||
el("output").innerHTML = el("input").value;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
Your name: <input id="input" type="text" value="World"
|
||||
onkeydown="setTimeout(update,0)"/>
|
||||
<hr/>
|
||||
Hello <span id="output">{{yourname}}</span>!
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,67 +0,0 @@
|
||||
if (window.jstestdriver) {
|
||||
jstd = jstestdriver;
|
||||
dump = bind(jstd.console, jstd.console.log);
|
||||
}
|
||||
|
||||
function time(fn) {
|
||||
var count = 1,
|
||||
targetTime = 500,
|
||||
start = new Date().getTime(),
|
||||
stop = start + targetTime,
|
||||
elapsed,
|
||||
end,
|
||||
iterations,
|
||||
pad = angularFilter.number;
|
||||
|
||||
// do one iteration to guess how long it will take
|
||||
fn();
|
||||
while((end=new Date().getTime()) < stop ){
|
||||
// how much time has elapsed since we started the test
|
||||
elapsed = (end-start) || 1;
|
||||
// guess how many more iterations we need before we reach
|
||||
// the time limit. We do this so that we spend most of our
|
||||
// time in tight loop
|
||||
iterations = Math.ceil(
|
||||
// how much more time we need
|
||||
(targetTime - elapsed)
|
||||
/
|
||||
2 // to prevent overrun guess low
|
||||
/
|
||||
// this is how much the cost is so far per iteration
|
||||
(elapsed / count)
|
||||
);
|
||||
count += iterations;
|
||||
while(iterations--) {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
elapsed = end - start;
|
||||
return {
|
||||
count: count,
|
||||
total: elapsed,
|
||||
time: elapsed / count,
|
||||
name: fn.name,
|
||||
msg: '' + pad(elapsed / count, 3)
|
||||
+ ' ms [ ' + pad(1 / elapsed * count * 1000, 0) + ' ops/sec ] '
|
||||
+ '(' + elapsed + ' ms/' + count + ')'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function perf() {
|
||||
var log = [],
|
||||
summary = [],
|
||||
i,
|
||||
baseline,
|
||||
pad = angularFilter.number;
|
||||
|
||||
for (i = 0; i < arguments.length; i++) {
|
||||
var fn = arguments[i];
|
||||
var info = time(fn);
|
||||
if (baseline === undefined) baseline = info.time;
|
||||
summary.push(info.name + ': ' + pad(baseline / info.time, 2) + ' X');
|
||||
log.push('\n ' + info.name + ': ' + info.msg);
|
||||
}
|
||||
log.unshift(summary.join(' - '));
|
||||
dump(log.join(' '));
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script>
|
||||
</head>
|
||||
<body ng:init="$window.$root = this; data = [{foo: 'foo'},{bar: 'bar'}]">
|
||||
<p>This is a demo of a potential bug in angular.</p>
|
||||
<p>Try the following:</p>
|
||||
<ol>
|
||||
<li> Type "foo" on the filter box.
|
||||
<li> Clear the contents of the filter box.
|
||||
<li> Type "bar" on the filter box.
|
||||
<li> Clear the contents of the filter box.
|
||||
</ol>
|
||||
<p>Why doesn't the data goes back to the original?</p>
|
||||
<hr>
|
||||
Input: <input type="text" ng:model="filterName" id="filterInputField"/>
|
||||
<br/>
|
||||
<table ng:eval="filtered_data = data.$filter(filterName)" style="border: 1px solid black">
|
||||
<tr>
|
||||
<th>Foo</th>
|
||||
<th>Bar</th>
|
||||
</tr>
|
||||
<tr ng:repeat="record in filtered_data">
|
||||
<td>{{record.foo}}</td>
|
||||
<td>{{record.bar}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,10 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script>
|
||||
<body>
|
||||
<span ng:init='x = {d:3}; x1 = {bar:[x,5]}; x1.bar[0].d = 4'>
|
||||
<input ng:model="x1.bar[0].d" type="text"></input>
|
||||
<input ng:model="x.d" type="text"></input>
|
||||
<span> {{x1}} -- {{x1.bar[0].d}}</span>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<script type="text/javascript" src="../build/angular.js" ng:autobind></script>
|
||||
<body ng:init="scope = { itemId: 12345 }">
|
||||
<input ng:model="value" /><br />
|
||||
<a id="link-1" href ng:click="value = 1">link 1</a> (link, don't reload)<br />
|
||||
<a id="link-2" href="" ng:click="value = 2">link 2</a> (link, don't reload)<br />
|
||||
<a id="link-3" ng:href="#{{'123'}}" ng:click="value = 3">link 3</a> (link, reload!)<br />
|
||||
<a id="link-4" href="" ng:model="xx" ng:click="value = 4">anchor</a> (link, don't reload)<br />
|
||||
<a id="link-5" ng:model="xxx" ng:click="value = 5">anchor</a> (no link)<br />
|
||||
<a id="link-6" ng:href="#/{{value}}">link</a> (link, change hash)
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,18 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<script type="text/javascript" src="../build/angular.js" ng:autobind></script>
|
||||
<script type="text/javascript">
|
||||
function Cntl($route) {
|
||||
$route.when('/item1', {});
|
||||
$route.when('/item2', {});
|
||||
$route.onChange(function() {
|
||||
alert('change');
|
||||
});
|
||||
}
|
||||
Cntl.$inject = ['$route'];
|
||||
</script>
|
||||
<body ng:controller="Ctrl">
|
||||
<a href="#/item1">test</a>
|
||||
<a href="#/item2">test</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:ng="http://angularjs.org" xmlns:my="http://mynamespace.org">
|
||||
<head>
|
||||
<style>
|
||||
my\:time {color:#00f;display:block;border:1px solid #ccc;background-color:#ddd;}
|
||||
</style>
|
||||
<script src="../build/angular.js" ng:autobind></script>
|
||||
<script>
|
||||
angular.widget('my:time', function(compileElement){
|
||||
compileElement.css('display', 'block');
|
||||
return function(linkElement) {
|
||||
function update() {
|
||||
linkElement.text('Current time is: ' + new Date());
|
||||
setTimeout(update, 1000);
|
||||
}
|
||||
update();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<my:time></my:time>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script>
|
||||
</head>
|
||||
<body ng:init="$window.$root = this; data = [{foo: 'foo'},{bar: 'bar'}]">
|
||||
<ng:include src="'ng_include_this.partial'" scope="this"/>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
included HTML. eval count: {{c=c+1}}
|
||||
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
angular.module.ng('myService', function($resource){
|
||||
this.myData = $resource('resource_json_date.json');
|
||||
}, {$inject:['$resource'], $creation:'eager'});
|
||||
|
||||
/* The Controller object */
|
||||
MyController = function() {
|
||||
this.inlineData = angular.fromJson('{reportDate:"2010-10-13T17:37:00Z"}');
|
||||
this.jsonData = this.myData.get();
|
||||
};
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body ng:controller="MyController" ng:init="$window.$root = this">
|
||||
<h3>This data is loaded with angular.fromJson:</h3>
|
||||
{{ inlineData.reportDate | date }}
|
||||
<hr/>
|
||||
<h3>This data is loaded from a resource using a service:</h3>
|
||||
<p>Name: {{ jsonData.name }}</p>
|
||||
<p>Parsed date: {{ jsonData.reportDate }} (A date should be displayed here)</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
{reportDate:"2010-10-13T17:37:00Z", name:"camilo"}
|
||||
@@ -1,8 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<script type="text/javascript" src="../src/angular-bootstrap.js" ng:autobind></script>
|
||||
<body>
|
||||
<textarea ng:model="html" rows="10" cols="100"></textarea>
|
||||
<div>{{html|html}}</div>
|
||||
</body>
|
||||
</html>
|
||||
+47
-15
@@ -49,8 +49,7 @@ if ('i' !== 'I'.toLowerCase()) {
|
||||
function fromCharCode(code) {return String.fromCharCode(code);}
|
||||
|
||||
|
||||
var Error = window.Error,
|
||||
/** holds major version number for IE or NaN for real browsers */
|
||||
var /** holds major version number for IE or NaN for real browsers */
|
||||
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
|
||||
jqLite, // delay binding since jQuery could be loaded after us.
|
||||
jQuery, // delay binding
|
||||
@@ -91,6 +90,30 @@ var Error = window.Error,
|
||||
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
||||
* @returns {Object|Array} Reference to `obj`.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {*} obj
|
||||
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
|
||||
*/
|
||||
function isArrayLike(obj) {
|
||||
if (!obj || (typeof obj.length !== 'number')) return false;
|
||||
|
||||
// We have on object which has length property. Should we treat it as array?
|
||||
if (typeof obj.hasOwnProperty != 'function' &&
|
||||
typeof obj.constructor != 'function') {
|
||||
// This is here for IE8: it is a bogus object treat it as array;
|
||||
return true;
|
||||
} else {
|
||||
return obj instanceof JQLite || // JQLite
|
||||
(jQuery && obj instanceof jQuery) || // jQuery
|
||||
toString.call(obj) !== '[object Object]' || // some browser native object
|
||||
typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function forEach(obj, iterator, context) {
|
||||
var key;
|
||||
if (obj) {
|
||||
@@ -102,7 +125,7 @@ function forEach(obj, iterator, context) {
|
||||
}
|
||||
} else if (obj.forEach && obj.forEach !== forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (isObject(obj) && isNumber(obj.length)) {
|
||||
} else if (isArrayLike(obj)) {
|
||||
for (key = 0; key < obj.length; key++)
|
||||
iterator.call(context, obj[key], key);
|
||||
} else {
|
||||
@@ -147,7 +170,7 @@ function reverseParams(iteratorFn) {
|
||||
/**
|
||||
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
||||
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
||||
* the number string gets longer over time, and it can also overflow, where as the the nextId
|
||||
* the number string gets longer over time, and it can also overflow, where as the nextId
|
||||
* will grow much slower, it is a string, and it will never overflow.
|
||||
*
|
||||
* @returns an unique alpha-numeric string
|
||||
@@ -543,9 +566,7 @@ function copy(source, destination){
|
||||
} else {
|
||||
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
|
||||
if (isArray(source)) {
|
||||
while(destination.length) {
|
||||
destination.pop();
|
||||
}
|
||||
destination.length = 0;
|
||||
for ( var i = 0; i < source.length; i++) {
|
||||
destination.push(copy(source[i]));
|
||||
}
|
||||
@@ -621,13 +642,15 @@ function equals(o1, o2) {
|
||||
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
|
||||
keySet = {};
|
||||
for(key in o1) {
|
||||
if (key.charAt(0) !== '$' && !isFunction(o1[key]) && !equals(o1[key], o2[key])) {
|
||||
return false;
|
||||
}
|
||||
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
||||
if (!equals(o1[key], o2[key])) return false;
|
||||
keySet[key] = true;
|
||||
}
|
||||
for(key in o2) {
|
||||
if (!keySet[key] && key.charAt(0) !== '$' && !isFunction(o2[key])) return false;
|
||||
if (!keySet[key] &&
|
||||
key.charAt(0) !== '$' &&
|
||||
o2[key] !== undefined &&
|
||||
!isFunction(o2[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -754,9 +777,18 @@ function startingTag(element) {
|
||||
// are not allowed to have children. So we just ignore it.
|
||||
element.html('');
|
||||
} catch(e) {}
|
||||
return jqLite('<div>').append(element).html().
|
||||
match(/^(<[^>]+>)/)[1].
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
||||
// As Per DOM Standards
|
||||
var TEXT_NODE = 3;
|
||||
var elemHtml = jqLite('<div>').append(element).html();
|
||||
try {
|
||||
return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
|
||||
elemHtml.
|
||||
match(/^(<[^>]+>)/)[1].
|
||||
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
||||
} catch(e) {
|
||||
return lowercase(elemHtml);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -840,7 +872,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
* Use this directive to auto-bootstrap on application. Only
|
||||
* one directive can be used per HTML document. The directive
|
||||
* designates the root of the application and is typically placed
|
||||
* ot the root of the page.
|
||||
* at the root of the page.
|
||||
*
|
||||
* In the example below if the `ngApp` directive would not be placed
|
||||
* on the `html` element then the document would not be compiled
|
||||
|
||||
@@ -192,7 +192,7 @@ function annotate(fn) {
|
||||
* This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
|
||||
* are supported.
|
||||
*
|
||||
* # The `$injector` property
|
||||
* # The `$inject` property
|
||||
*
|
||||
* If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
|
||||
* services to be injected into the function.
|
||||
@@ -440,7 +440,7 @@ function createInjector(modulesToLoad) {
|
||||
}
|
||||
|
||||
function provider(name, provider_) {
|
||||
if (isFunction(provider_)) {
|
||||
if (isFunction(provider_) || isArray(provider_)) {
|
||||
provider_ = providerInjector.instantiate(provider_);
|
||||
}
|
||||
if (!provider_.$get) {
|
||||
@@ -557,7 +557,7 @@ function createInjector(modulesToLoad) {
|
||||
args.push(
|
||||
locals && locals.hasOwnProperty(key)
|
||||
? locals[key]
|
||||
: getService(key, path)
|
||||
: getService(key)
|
||||
);
|
||||
}
|
||||
if (!fn.$inject) {
|
||||
|
||||
Vendored
+4
-4
@@ -4,10 +4,10 @@ var directive = {};
|
||||
var service = { value: {} };
|
||||
|
||||
var DEPENDENCIES = {
|
||||
'angular.js': 'http://code.angularjs.org/angular-' + angular.version.full + '.min.js',
|
||||
'angular-resource.js': 'http://code.angularjs.org/angular-resource-' + angular.version.full + '.min.js',
|
||||
'angular-sanitize.js': 'http://code.angularjs.org/angular-sanitize-' + angular.version.full + '.min.js',
|
||||
'angular-cookies.js': 'http://code.angularjs.org/angular-cookies-' + angular.version.full + '.min.js'
|
||||
'angular.js': 'http://code.angularjs.org/' + angular.version.full + '/angular.min.js',
|
||||
'angular-resource.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-resource.min.js',
|
||||
'angular-sanitize.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-sanitize.min.js',
|
||||
'angular-cookies.js': 'http://code.angularjs.org/' + angular.version.full + '/angular-cookies.min.js'
|
||||
};
|
||||
|
||||
|
||||
|
||||
+13
-4
@@ -59,7 +59,7 @@
|
||||
* - [val()](http://api.jquery.com/val/)
|
||||
* - [wrap()](http://api.jquery.com/wrap/)
|
||||
*
|
||||
* ## In addtion to the above, Angular privides an additional method to both jQuery and jQuery lite:
|
||||
* ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite:
|
||||
*
|
||||
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
|
||||
* retrieves controller associated with the `ngController` directive. If `name` is provided as
|
||||
@@ -647,14 +647,14 @@ forEach({
|
||||
children: function(element) {
|
||||
var children = [];
|
||||
forEach(element.childNodes, function(element){
|
||||
if (element.nodeName != '#text')
|
||||
if (element.nodeType === 1)
|
||||
children.push(element);
|
||||
});
|
||||
return children;
|
||||
},
|
||||
|
||||
contents: function(element) {
|
||||
return element.childNodes;
|
||||
return element.childNodes || [];
|
||||
},
|
||||
|
||||
append: function(element, node) {
|
||||
@@ -717,7 +717,16 @@ forEach({
|
||||
},
|
||||
|
||||
next: function(element) {
|
||||
return element.nextSibling;
|
||||
if (element.nextElementSibling) {
|
||||
return element.nextElementSibling;
|
||||
}
|
||||
|
||||
// IE8 doesn't have nextElementSibling
|
||||
var elm = element.nextSibling;
|
||||
while (elm != null && elm.nodeType !== 1) {
|
||||
elm = elm.nextSibling;
|
||||
}
|
||||
return elm;
|
||||
},
|
||||
|
||||
find: function(element, selector) {
|
||||
|
||||
@@ -53,7 +53,7 @@ function $AnchorScrollProvider() {
|
||||
}
|
||||
|
||||
// does not scroll when user clicks on anchor link that is currently on
|
||||
// (no url change, no $locaiton.hash() change), browser native does scroll
|
||||
// (no url change, no $location.hash() change), browser native does scroll
|
||||
if (autoScrollingEnabled) {
|
||||
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
|
||||
function autoScrollWatchAction() {
|
||||
|
||||
+6
-5
@@ -237,7 +237,7 @@ function Browser(window, document, $log, $sniffer) {
|
||||
*/
|
||||
self.baseHref = function() {
|
||||
var href = baseElement.attr('href');
|
||||
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
|
||||
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
@@ -276,14 +276,15 @@ function Browser(window, document, $log, $sniffer) {
|
||||
} else {
|
||||
if (isString(value)) {
|
||||
cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
|
||||
|
||||
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
|
||||
// - 300 cookies
|
||||
// - 20 cookies per unique domain
|
||||
// - 4096 bytes per cookie
|
||||
if (cookieLength > 4096) {
|
||||
$log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
|
||||
cookieLength + " > 4096 bytes)!");
|
||||
}
|
||||
if (lastCookies.length > 20) {
|
||||
$log.warn("Cookie '"+ name +"' possibly not set or overflowed because too many cookies " +
|
||||
"were already set (" + lastCookies.length + " > 20 )");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+122
-60
@@ -155,7 +155,8 @@ function $CompileProvider($provide) {
|
||||
Suffix = 'Directive',
|
||||
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
|
||||
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
|
||||
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ';
|
||||
MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
|
||||
urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
|
||||
|
||||
|
||||
/**
|
||||
@@ -209,11 +210,41 @@ function $CompileProvider($provide) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$compileProvider#urlSanitizationWhitelist
|
||||
* @methodOf ng.$compileProvider
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
|
||||
* urls during a[href] sanitization.
|
||||
*
|
||||
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
|
||||
*
|
||||
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
|
||||
* absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
|
||||
* expression. If a match is found the original url is written into the dom. Otherwise the
|
||||
* absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
|
||||
*
|
||||
* @param {RegExp=} regexp New regexp to whitelist urls with.
|
||||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
|
||||
* chaining otherwise.
|
||||
*/
|
||||
this.urlSanitizationWhitelist = function(regexp) {
|
||||
if (isDefined(regexp)) {
|
||||
urlSanitizationWhitelist = regexp;
|
||||
return this;
|
||||
}
|
||||
return urlSanitizationWhitelist;
|
||||
};
|
||||
|
||||
|
||||
this.$get = [
|
||||
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
|
||||
'$controller', '$rootScope',
|
||||
'$controller', '$rootScope', '$document',
|
||||
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
|
||||
$controller, $rootScope) {
|
||||
$controller, $rootScope, $document) {
|
||||
|
||||
var Attributes = function(element, attr) {
|
||||
this.$$element = element;
|
||||
@@ -235,7 +266,8 @@ function $CompileProvider($provide) {
|
||||
*/
|
||||
$set: function(key, value, writeAttr, attrName) {
|
||||
var booleanKey = getBooleanAttrName(this.$$element[0], key),
|
||||
$$observers = this.$$observers;
|
||||
$$observers = this.$$observers,
|
||||
normalizedVal;
|
||||
|
||||
if (booleanKey) {
|
||||
this.$$element.prop(key, value);
|
||||
@@ -254,6 +286,19 @@ function $CompileProvider($provide) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sanitize a[href] values
|
||||
if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
|
||||
urlSanitizationNode.setAttribute('href', value);
|
||||
|
||||
// href property always returns normalized absolute url, so we can match against that
|
||||
normalizedVal = urlSanitizationNode.href;
|
||||
if (!normalizedVal.match(urlSanitizationWhitelist)) {
|
||||
this[key] = value = 'unsafe:' + normalizedVal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (writeAttr !== false) {
|
||||
if (value === null || value === undefined) {
|
||||
this.$$element.removeAttr(attrName);
|
||||
@@ -297,7 +342,8 @@ function $CompileProvider($provide) {
|
||||
}
|
||||
};
|
||||
|
||||
var startSymbol = $interpolate.startSymbol(),
|
||||
var urlSanitizationNode = $document[0].createElement('a'),
|
||||
startSymbol = $interpolate.startSymbol(),
|
||||
endSymbol = $interpolate.endSymbol(),
|
||||
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
|
||||
? identity
|
||||
@@ -318,7 +364,7 @@ function $CompileProvider($provide) {
|
||||
// We can not compile top level text elements since text nodes can be merged and we will
|
||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||
forEach($compileNodes, function(node, index){
|
||||
if (node.nodeType == 3 /* text node */) {
|
||||
if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
|
||||
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
||||
}
|
||||
});
|
||||
@@ -330,7 +376,14 @@ function $CompileProvider($provide) {
|
||||
var $linkNode = cloneConnectFn
|
||||
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
|
||||
: $compileNodes;
|
||||
$linkNode.data('$scope', scope);
|
||||
|
||||
// Attach scope only to non-text nodes.
|
||||
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
|
||||
var node = $linkNode[i];
|
||||
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
|
||||
$linkNode.eq(i).data('$scope', scope);
|
||||
}
|
||||
}
|
||||
safeAddClass($linkNode, 'ng-scope');
|
||||
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
|
||||
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
|
||||
@@ -367,68 +420,75 @@ function $CompileProvider($provide) {
|
||||
* @returns {?function} A composite linking function of all of the matched directives or null.
|
||||
*/
|
||||
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
var linkFns = [],
|
||||
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
|
||||
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
for(var i = 0; i < nodeList.length; i++) {
|
||||
attrs = new Attributes();
|
||||
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
|
||||
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
|
||||
directives = collectDirectives(nodeList[i], [], attrs, maxPriority);
|
||||
|
||||
nodeLinkFn = (directives.length)
|
||||
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
||||
: null;
|
||||
nodeLinkFn = (directives.length)
|
||||
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
|
||||
: null;
|
||||
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
|
||||
? null
|
||||
: compileNodes(nodeList[i].childNodes,
|
||||
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
|
||||
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
}
|
||||
linkFns.push(nodeLinkFn);
|
||||
linkFns.push(childLinkFn);
|
||||
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
|
||||
}
|
||||
|
||||
// return a linking function if we have found anything, null otherwise
|
||||
return linkFnFound ? compositeLinkFn : null;
|
||||
// return a linking function if we have found anything, null otherwise
|
||||
return linkFnFound ? compositeLinkFn : null;
|
||||
|
||||
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
|
||||
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn;
|
||||
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
|
||||
var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
|
||||
|
||||
for(var i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
node = nodeList[n];
|
||||
nodeLinkFn = linkFns[i++];
|
||||
childLinkFn = linkFns[i++];
|
||||
// copy nodeList so that linking doesn't break due to live list updates.
|
||||
var stableNodeList = [];
|
||||
for (i = 0, ii = nodeList.length; i < ii; i++) {
|
||||
stableNodeList.push(nodeList[i]);
|
||||
}
|
||||
|
||||
if (nodeLinkFn) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new(isObject(nodeLinkFn.scope));
|
||||
jqLite(node).data('$scope', childScope);
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
childTranscludeFn = nodeLinkFn.transclude;
|
||||
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
|
||||
(function(transcludeFn) {
|
||||
return function(cloneFn) {
|
||||
var transcludeScope = scope.$new();
|
||||
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
|
||||
node = stableNodeList[n];
|
||||
nodeLinkFn = linkFns[i++];
|
||||
childLinkFn = linkFns[i++];
|
||||
|
||||
return transcludeFn(transcludeScope, cloneFn).
|
||||
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
|
||||
if (nodeLinkFn) {
|
||||
if (nodeLinkFn.scope) {
|
||||
childScope = scope.$new(isObject(nodeLinkFn.scope));
|
||||
jqLite(node).data('$scope', childScope);
|
||||
} else {
|
||||
childScope = scope;
|
||||
}
|
||||
childTranscludeFn = nodeLinkFn.transclude;
|
||||
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
|
||||
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
|
||||
(function(transcludeFn) {
|
||||
return function(cloneFn) {
|
||||
var transcludeScope = scope.$new();
|
||||
transcludeScope.$$transcluded = true;
|
||||
|
||||
return transcludeFn(transcludeScope, cloneFn).
|
||||
bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
|
||||
};
|
||||
})(childTranscludeFn || transcludeFn)
|
||||
);
|
||||
} else {
|
||||
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
|
||||
}
|
||||
} else if (childLinkFn) {
|
||||
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
|
||||
}
|
||||
} else if (childLinkFn) {
|
||||
childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -575,7 +635,7 @@ function $CompileProvider($provide) {
|
||||
if (directiveValue == 'element') {
|
||||
$template = jqLite(compileNode);
|
||||
$compileNode = templateAttrs.$$element =
|
||||
jqLite('<!-- ' + directiveName + ': ' + templateAttrs[directiveName] + ' -->');
|
||||
jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
|
||||
compileNode = $compileNode[0];
|
||||
replaceWith($rootElement, jqLite($template[0]), compileNode);
|
||||
childTranscludeFn = compile($template, transcludeFn, terminalPriority);
|
||||
@@ -719,6 +779,8 @@ function $CompileProvider($provide) {
|
||||
lastValue,
|
||||
parentGet, parentSet;
|
||||
|
||||
scope.$$isolateBindings[scopeName] = mode + attrName;
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case '@': {
|
||||
@@ -929,7 +991,7 @@ function $CompileProvider($provide) {
|
||||
}
|
||||
|
||||
directives.unshift(derivedSyncDirective);
|
||||
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, $compileNode, tAttrs, childTranscludeFn);
|
||||
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
|
||||
afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn);
|
||||
|
||||
|
||||
@@ -1009,10 +1071,10 @@ function $CompileProvider($provide) {
|
||||
function addAttrInterpolateDirective(node, directives, value, name) {
|
||||
var interpolateFn = $interpolate(value, true);
|
||||
|
||||
|
||||
// no interpolation found -> ignore
|
||||
if (!interpolateFn) return;
|
||||
|
||||
|
||||
directives.push({
|
||||
priority: 100,
|
||||
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
|
||||
|
||||
+15
-6
@@ -11,15 +11,25 @@
|
||||
*
|
||||
* The reasoning for this change is to allow easy creation of action links with `ngClick` directive
|
||||
* without changing the location or causing page reloads, e.g.:
|
||||
* <a href="" ng-click="model.$save()">Save</a>
|
||||
* `<a href="" ng-click="model.$save()">Save</a>`
|
||||
*/
|
||||
var htmlAnchorDirective = valueFn({
|
||||
restrict: 'E',
|
||||
compile: function(element, attr) {
|
||||
// turn <a href ng-click="..">link</a> into a link in IE
|
||||
// but only if it doesn't have name attribute, in which case it's an anchor
|
||||
if (!attr.href) {
|
||||
attr.$set('href', '');
|
||||
|
||||
if (msie <= 8) {
|
||||
|
||||
// turn <a href ng-click="..">link</a> into a stylable link in IE
|
||||
// but only if it doesn't have name attribute, in which case it's an anchor
|
||||
if (!attr.href && !attr.name) {
|
||||
attr.$set('href', '');
|
||||
}
|
||||
|
||||
// add a comment node to anchors to workaround IE bug that causes element content to be reset
|
||||
// to new attribute content if attribute is updated with value containing @ and element also
|
||||
// contains value with @
|
||||
// see issue #1949
|
||||
element.append(document.createComment('IE fix'));
|
||||
}
|
||||
|
||||
return function(scope, element) {
|
||||
@@ -27,7 +37,6 @@ var htmlAnchorDirective = valueFn({
|
||||
// if we have no href url, then don't navigate anywhere.
|
||||
if (!element.attr('href')) {
|
||||
event.preventDefault();
|
||||
return false; // Needed for opera
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
it('should execute ng-click but not reload when no href but name specified', function() {
|
||||
element('#link-5').click();
|
||||
expect(input('value').val()).toEqual('5');
|
||||
expect(element('#link-5').attr('href')).toBe('');
|
||||
expect(element('#link-5').attr('href')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should only change url when only ng-href', function() {
|
||||
@@ -309,8 +309,9 @@ forEach(['src', 'href'], function(attrName) {
|
||||
|
||||
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
|
||||
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
|
||||
// to set the property as well to achieve the desired effect
|
||||
if (msie) element.prop(attrName, value);
|
||||
// to set the property as well to achieve the desired effect.
|
||||
// we use attr[attrName] value since $set can sanitize the url.
|
||||
if (msie) element.prop(attrName, attr[attrName]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,13 +14,13 @@ var nullFormCtrl = {
|
||||
*
|
||||
* @property {boolean} $pristine True if user has not interacted with the form yet.
|
||||
* @property {boolean} $dirty True if user has already interacted with the form.
|
||||
* @property {boolean} $valid True if all of the containg forms and controls are valid.
|
||||
* @property {boolean} $valid True if all of the containing forms and controls are valid.
|
||||
* @property {boolean} $invalid True if at least one containing control or form is invalid.
|
||||
*
|
||||
* @property {Object} $error Is an object hash, containing references to all invalid controls or
|
||||
* forms, where:
|
||||
*
|
||||
* - keys are validation tokens (error names) — such as `REQUIRED`, `URL` or `EMAIL`),
|
||||
* - keys are validation tokens (error names) — such as `required`, `url` or `email`),
|
||||
* - values are arrays of controls or forms that are invalid with given error.
|
||||
*
|
||||
* @description
|
||||
@@ -133,7 +133,7 @@ function FormController(element, attrs) {
|
||||
* does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
|
||||
* sub-group of controls needs to be determined.
|
||||
*
|
||||
* @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
|
||||
* @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
|
||||
* related scope, under this name.
|
||||
*
|
||||
*/
|
||||
@@ -206,12 +206,12 @@ function FormController(element, attrs) {
|
||||
</script>
|
||||
<form name="myForm" ng-controller="Ctrl">
|
||||
userType: <input name="input" ng-model="userType" required>
|
||||
<span class="error" ng-show="myForm.input.$error.REQUIRED">Required!</span><br>
|
||||
<span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
|
||||
<tt>userType = {{userType}}</tt><br>
|
||||
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
|
||||
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
|
||||
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
|
||||
<tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
|
||||
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
|
||||
</form>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
function classDirective(name, selector) {
|
||||
name = 'ngClass' + name;
|
||||
return ngDirective(function(scope, element, attr) {
|
||||
var oldVal = undefined;
|
||||
|
||||
scope.$watch(attr[name], ngClassWatchAction, true);
|
||||
|
||||
@@ -26,13 +27,14 @@ function classDirective(name, selector) {
|
||||
}
|
||||
|
||||
|
||||
function ngClassWatchAction(newVal, oldVal) {
|
||||
function ngClassWatchAction(newVal) {
|
||||
if (selector === true || scope.$index % 2 === selector) {
|
||||
if (oldVal && (newVal !== oldVal)) {
|
||||
removeClass(oldVal);
|
||||
}
|
||||
addClass(newVal);
|
||||
}
|
||||
oldVal = newVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +67,7 @@ function classDirective(name, selector) {
|
||||
*
|
||||
* The directive won't add duplicate classes if a particular class was already set.
|
||||
*
|
||||
* When the expression changes, the previously added classes are removed and only then the classes
|
||||
* When the expression changes, the previously added classes are removed and only then the
|
||||
* new classes are added.
|
||||
*
|
||||
* @element ANY
|
||||
|
||||
@@ -92,14 +92,17 @@ var ngRepeatDirective = ngDirective({
|
||||
scope.$watch(function ngRepeatWatch(scope){
|
||||
var index, length,
|
||||
collection = scope.$eval(rhs),
|
||||
collectionLength = size(collection, true),
|
||||
childScope,
|
||||
cursor = iterStartElement, // current position of the node
|
||||
// Same as lastOrder but it has the current state. It will become the
|
||||
// lastOrder on the next iteration.
|
||||
nextOrder = new HashQueueMap(),
|
||||
arrayLength,
|
||||
childScope,
|
||||
key, value, // key/value of iteration
|
||||
array, last, // last object information {scope, element, index}
|
||||
cursor = iterStartElement; // current position of the node
|
||||
array,
|
||||
last; // last object information {scope, element, index}
|
||||
|
||||
|
||||
|
||||
if (!isArray(collection)) {
|
||||
// if object, extract keys, sort them and use to determine order of iteration over obj props
|
||||
@@ -114,6 +117,8 @@ var ngRepeatDirective = ngDirective({
|
||||
array = collection || [];
|
||||
}
|
||||
|
||||
arrayLength = array.length;
|
||||
|
||||
// we are not using forEach for perf reasons (trying to avoid #call)
|
||||
for (index = 0, length = array.length; index < length; index++) {
|
||||
key = (collection === array) ? index : array[index];
|
||||
@@ -149,7 +154,7 @@ var ngRepeatDirective = ngDirective({
|
||||
childScope.$index = index;
|
||||
|
||||
childScope.$first = (index === 0);
|
||||
childScope.$last = (index === (collectionLength - 1));
|
||||
childScope.$last = (index === (arrayLength - 1));
|
||||
childScope.$middle = !(childScope.$first || childScope.$last);
|
||||
|
||||
if (!last) {
|
||||
|
||||
@@ -62,51 +62,53 @@
|
||||
var NG_SWITCH = 'ng-switch';
|
||||
var ngSwitchDirective = valueFn({
|
||||
restrict: 'EA',
|
||||
compile: function(element, attr) {
|
||||
require: 'ngSwitch',
|
||||
// asks for $scope to fool the BC controller module
|
||||
controller: ['$scope', function ngSwitchController() {
|
||||
this.cases = {};
|
||||
}],
|
||||
link: function(scope, element, attr, ctrl) {
|
||||
var watchExpr = attr.ngSwitch || attr.on,
|
||||
cases = {};
|
||||
selectedTransclude,
|
||||
selectedElement,
|
||||
selectedScope;
|
||||
|
||||
element.data(NG_SWITCH, cases);
|
||||
return function(scope, element){
|
||||
var selectedTransclude,
|
||||
selectedElement,
|
||||
selectedScope;
|
||||
|
||||
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
|
||||
if (selectedElement) {
|
||||
selectedScope.$destroy();
|
||||
selectedElement.remove();
|
||||
selectedElement = selectedScope = null;
|
||||
}
|
||||
if ((selectedTransclude = cases['!' + value] || cases['?'])) {
|
||||
scope.$eval(attr.change);
|
||||
selectedScope = scope.$new();
|
||||
selectedTransclude(selectedScope, function(caseElement) {
|
||||
selectedElement = caseElement;
|
||||
element.append(caseElement);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
|
||||
if (selectedElement) {
|
||||
selectedScope.$destroy();
|
||||
selectedElement.remove();
|
||||
selectedElement = selectedScope = null;
|
||||
}
|
||||
if ((selectedTransclude = ctrl.cases['!' + value] || ctrl.cases['?'])) {
|
||||
scope.$eval(attr.change);
|
||||
selectedScope = scope.$new();
|
||||
selectedTransclude(selectedScope, function(caseElement) {
|
||||
selectedElement = caseElement;
|
||||
element.append(caseElement);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var ngSwitchWhenDirective = ngDirective({
|
||||
transclude: 'element',
|
||||
priority: 500,
|
||||
require: '^ngSwitch',
|
||||
compile: function(element, attrs, transclude) {
|
||||
var cases = element.inheritedData(NG_SWITCH);
|
||||
assertArg(cases);
|
||||
cases['!' + attrs.ngSwitchWhen] = transclude;
|
||||
return function(scope, element, attr, ctrl) {
|
||||
ctrl.cases['!' + attrs.ngSwitchWhen] = transclude;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
var ngSwitchDefaultDirective = ngDirective({
|
||||
transclude: 'element',
|
||||
priority: 500,
|
||||
require: '^ngSwitch',
|
||||
compile: function(element, attrs, transclude) {
|
||||
var cases = element.inheritedData(NG_SWITCH);
|
||||
assertArg(cases);
|
||||
cases['?'] = transclude;
|
||||
return function(scope, element, attr, ctrl) {
|
||||
ctrl.cases['?'] = transclude;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<hr />
|
||||
|
||||
<pre>$location.path() = {{$location.path()}}</pre>
|
||||
<pre>$route.current.template = {{$route.current.template}}</pre>
|
||||
<pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
|
||||
<pre>$route.current.params = {{$route.current.params}}</pre>
|
||||
<pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
|
||||
<pre>$routeParams = {{$routeParams}}</pre>
|
||||
@@ -147,7 +147,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
||||
if (current.controller) {
|
||||
locals.$scope = lastScope;
|
||||
controller = $controller(current.controller, locals);
|
||||
element.contents().data('$ngControllerController', controller);
|
||||
element.children().data('$ngControllerController', controller);
|
||||
}
|
||||
|
||||
link(lastScope);
|
||||
|
||||
@@ -265,7 +265,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
var lastView;
|
||||
ctrl.$render = function() {
|
||||
var items = new HashMap(ctrl.$viewValue);
|
||||
forEach(selectElement.children(), function(option) {
|
||||
forEach(selectElement.find('option'), function(option) {
|
||||
option.selected = isDefined(items.get(option.value));
|
||||
});
|
||||
};
|
||||
@@ -282,7 +282,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
|
||||
selectElement.bind('change', function() {
|
||||
scope.$apply(function() {
|
||||
var array = [];
|
||||
forEach(selectElement.children(), function(option) {
|
||||
forEach(selectElement.find('option'), function(option) {
|
||||
if (option.selected) {
|
||||
array.push(option.value);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@
|
||||
* the browser console.
|
||||
*
|
||||
* In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
|
||||
* {@link ngMock.$exceptionHandler mock $exceptionHandler}
|
||||
* {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
|
||||
*
|
||||
* @param {Error} exception Exception associated with the error.
|
||||
* @param {string=} cause optional information about the context in which
|
||||
* the error was thrown.
|
||||
*
|
||||
*/
|
||||
function $ExceptionHandlerProvider() {
|
||||
this.$get = ['$log', function($log){
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
*/
|
||||
function filterFilter() {
|
||||
return function(array, expression) {
|
||||
if (!(array instanceof Array)) return array;
|
||||
if (!isArray(array)) return array;
|
||||
var predicates = [];
|
||||
predicates.check = function(value) {
|
||||
for (var j = 0; j < predicates.length; j++) {
|
||||
|
||||
@@ -168,7 +168,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
|
||||
fraction += '0';
|
||||
}
|
||||
|
||||
if (fractionSize) formatedText += decimalSep + fraction.substr(0, fractionSize);
|
||||
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
|
||||
}
|
||||
|
||||
parts.push(isNegative ? pattern.negPre : pattern.posPre);
|
||||
@@ -211,8 +211,12 @@ function dateStrGetter(name, shortForm) {
|
||||
}
|
||||
|
||||
function timeZoneGetter(date) {
|
||||
var offset = date.getTimezoneOffset();
|
||||
return padNumber(offset / 60, 2) + padNumber(Math.abs(offset % 60), 2);
|
||||
var zone = -1 * date.getTimezoneOffset();
|
||||
var paddedZone = (zone >= 0) ? "+" : "";
|
||||
|
||||
paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2);
|
||||
|
||||
return paddedZone;
|
||||
}
|
||||
|
||||
function ampmGetter(date, formats) {
|
||||
@@ -298,7 +302,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
||||
*
|
||||
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
|
||||
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's
|
||||
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ).
|
||||
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
|
||||
* specified in the string input, the time is considered to be in the local timezone.
|
||||
* @param {string=} format Formatting rules (see Description). If not specified,
|
||||
* `mediumDate` is used.
|
||||
* @returns {string} Formatted string or the input if input is not recognized as date/millis.
|
||||
@@ -318,7 +323,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
|
||||
expect(binding("1288323623006 | date:'medium'")).
|
||||
toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
|
||||
expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
|
||||
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} \-?\d{4}/);
|
||||
toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
|
||||
expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
|
||||
toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
|
||||
});
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
orderByFilter.$inject = ['$parse'];
|
||||
function orderByFilter($parse){
|
||||
return function(array, sortPredicate, reverseOrder) {
|
||||
if (!(array instanceof Array)) return array;
|
||||
if (!isArray(array)) return array;
|
||||
if (!sortPredicate) return array;
|
||||
sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
|
||||
sortPredicate = map(sortPredicate, function(predicate){
|
||||
|
||||
+6
-3
@@ -136,7 +136,7 @@ function $HttpProvider() {
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name ng.$http
|
||||
* @requires $httpBacked
|
||||
* @requires $httpBackend
|
||||
* @requires $browser
|
||||
* @requires $cacheFactory
|
||||
* @requires $rootScope
|
||||
@@ -172,8 +172,7 @@ function $HttpProvider() {
|
||||
* }).
|
||||
* error(function(data, status, headers, config) {
|
||||
* // called asynchronously if an error occurs
|
||||
* // or server returns response with status
|
||||
* // code outside of the <200, 400) range
|
||||
* // or server returns response with an error status.
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
@@ -182,6 +181,10 @@ function $HttpProvider() {
|
||||
* an object representing the response. See the api signature and type info below for more
|
||||
* details.
|
||||
*
|
||||
* A response status code that falls in the [200, 300) range is considered a success status and
|
||||
* will result in the success callback being called. Note that if the response is a redirect,
|
||||
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
|
||||
* called for such responses.
|
||||
*
|
||||
* # Shortcut methods
|
||||
*
|
||||
|
||||
+24
-2
@@ -65,8 +65,30 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
|
||||
// always async
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
completeRequest(
|
||||
callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
|
||||
var responseHeaders = xhr.getAllResponseHeaders();
|
||||
|
||||
// TODO(vojta): remove once Firefox 21 gets released.
|
||||
// begin: workaround to overcome Firefox CORS http response headers bug
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=608735
|
||||
// Firefox already patched in nightly. Should land in Firefox 21.
|
||||
|
||||
// CORS "simple response headers" http://www.w3.org/TR/cors/
|
||||
var value,
|
||||
simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
|
||||
"Expires", "Last-Modified", "Pragma"];
|
||||
if (!responseHeaders) {
|
||||
responseHeaders = "";
|
||||
forEach(simpleHeaders, function (header) {
|
||||
var value = xhr.getResponseHeader(header);
|
||||
if (value) {
|
||||
responseHeaders += header + ": " + value + "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
// end of the workaround.
|
||||
|
||||
completeRequest(callback, status || xhr.status, xhr.responseText,
|
||||
responseHeaders);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+4
-3
@@ -840,9 +840,10 @@ function getterFn(path, csp) {
|
||||
* @param {string} expression String expression to compile.
|
||||
* @returns {function(context, locals)} a function which represents the compiled expression:
|
||||
*
|
||||
* * `context`: an object against which any expressions embedded in the strings are evaluated
|
||||
* against (Topically a scope object).
|
||||
* * `locals`: local variables context object, useful for overriding values in `context`.
|
||||
* * `context` – `{object}` – an object against which any expressions embedded in the strings
|
||||
* are evaluated against (tipically a scope object).
|
||||
* * `locals` – `{object=}` – local variables context object, useful for overriding values in
|
||||
* `context`.
|
||||
*
|
||||
* The return function also has an `assign` property, if the expression is assignable, which
|
||||
* allows one to set values to expressions.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user