Compare commits

..

77 Commits

Author SHA1 Message Date
Igor Minar d0c0eadedd chore(release): cut the 1.1.0 increase-gravatar release 2012-09-04 11:11:09 -07:00
Igor Minar b8fac353f0 chore(docs): don't rewrite colons in doc filenames 2012-09-04 11:11:09 -07:00
Igor Minar b22308152f chore(Rakefile): zip only the build dir 2012-08-31 13:59:03 -07:00
Igor Minar 5e9041818b revert: fix(ng-repeat) to work with primitive types
this was accidentaly merged in. the commit is not ready yet
and we don't have CLA signature.

This reverts commit 98d489712e.
2012-08-31 13:59:03 -07:00
Igor Minar db861db1f2 docs(changelog): release notes for 1.0.2 and 1.1.0 releases 2012-08-31 13:59:03 -07:00
Jonathan Zacsh b12d1b6813 fix(docs): Making sure gen_docs.sh looks for a globally installed copy of jasmine-node as well as local. 2012-08-30 22:33:30 -07:00
Fernando Correia acb499f820 docs(tutorial): correct typos and clarify a few sections 2012-08-30 22:19:34 -07:00
Brice Burgess 9a710c788d fix(docs): indicate support for passing a string as the controller property on $routeProvider's route object 2012-08-30 22:13:20 -07:00
brettcannon 1b34c6d558 doc(misc) Mention how attribute names map to directive names. 2012-08-30 22:09:16 -07:00
Igor Minar a62c7b8b4e test(locationSpec): fix broken tests after vojta's commit 2012-08-30 16:25:23 -07:00
Sahat Yalkabov 62cfedbe0c doc(module) changed simpleApp to myApp in the Module page guide for consistency 2012-08-30 16:10:39 -07:00
Steve Nicolai 5cb7297a08 doc(devguide) - Fix typos and small grammatical errors in the developer guide. 2012-08-30 16:02:24 -07:00
Igor Minar 0f05516d14 chore(docs): ask GAE to serve docs-keywords.js 2012-08-30 15:58:55 -07:00
Uri Goldshtein f5f1200f25 Loading from Google CDN
As you guys had mansion, we can and need to do it through Google CDN for better performance,
so i've updated it accordingly
2012-08-30 15:49:11 -07:00
Tyson Benson c023c850c3 docs(typos): fix typos in dev guide 2012-08-30 15:43:58 -07:00
German Galvis 5318588d6e fix(scenario): Adding meta tag to avoid cache issues 2012-08-30 15:36:42 -07:00
phil 14c8f6a7ca docs(api): fix typo on home page
Refference -> Reference
2012-08-30 15:31:29 -07:00
csugden 351deb555f Update docs/content/guide/overview.ngdoc
Corrects video information
2012-08-30 15:28:15 -07:00
Jamie Krug 847d2da0f8 fix(docs): Fix typos and improve grammar. 2012-08-30 15:25:21 -07:00
Jamie Krug dbefd671e4 fix(docs): Fix bad links. 2012-08-30 15:25:20 -07:00
Colin Frei aff68a9ddf docs(module) fix typo 2012-08-30 15:22:08 -07:00
Zhenbo Zhang 0a71753ce3 fix(ng-repeat) to work with primitive types 2012-08-30 15:20:40 -07:00
Vojta Jina 1a8642aac2 fix(mocks): free up memory after every spec 2012-08-30 15:18:09 -07:00
Igor Minar 8114d55a15 test(bootstrap): test exception siling during bootstrap
Closes #1018
2012-08-30 15:15:11 -07:00
Igor Minar 9398040a41 test(ngApp): add missing test for [ng-app] bootstrap 2012-08-30 15:15:11 -07:00
Brian Ford d804bbcd51 feat($interpolate): provide contextual error messages
if an exception occurs during interpolation of a string
(e.g. name() in "Hello, {{name()}}!" throws an exception) we now print
an error message with the expression that was being evaluated when the
exception was thrown.
2012-08-30 14:50:22 -07:00
Igor Minar d3fa7a2e9e fix(jqLite): better support for xhtml
it turns out that some stuff doesn't work in xhtml as it does in html.

for example   can't be innerHTML-ed and auto-closing of elements
doesn't work.

the reporter of the referenced issue claimed that innerHTML vs text on
script made a difference but that doesn't appear to be true in my testing.

I'm not including test for this because testacular doesn't currently
run tests in xhtml yet.

Closes #1301
2012-08-30 10:53:23 -07:00
Igor Minar 8693eac417 chore(docs): correctly link docs images 2012-08-30 02:26:35 -07:00
Igor Minar e0184d4aef chore(Rakefile): fix the default task 2012-08-29 16:56:48 -07:00
Igor Minar 1702e49548 chore(Rakefile): remove bogus symlink from build 2012-08-29 14:58:10 -07:00
Igor Minar d6706efe7f chore(docs): use symlinks to build docs
so that we can just edit source files without rebuilding docs.

this works for all docs files, except for those that are generated
or rewritten during build.
2012-08-28 16:06:50 -07:00
Igor Minar b08d4b22d2 chore(Rakefile): various build script changes
- restructure rake tasks

  this splits up the concatination and minification into two
  tasks so that we can just build angular.js quickly without wasting
  time with minification which is often not needed when just debugging
  some issue on 3rd party site.

- use symlinks when creating final zip file

- switch from btar to zip

- get rid of version numbers from filenames

- rewrite version numbers in all index files

Closes #1226
2012-08-28 12:38:34 -07:00
Misko Hevery e8ded01cf5 doc($log): correct non-working example 2012-08-27 15:44:38 -07:00
Misko Hevery 7a5f25f667 doc(guide): add concepts 2012-08-27 15:44:38 -07:00
Misko Hevery 96697f464f fix(ngdoc): failing test 2012-08-27 15:44:38 -07:00
Colin Frei 7e18724dfa doc(directive) correct typos 2012-08-27 15:01:50 -07:00
Misko Hevery c269eb3d26 fix(docs) typo 2012-08-27 14:59:19 -07:00
Misko Hevery fa62ea810f fix(ng-list): remove data bound flicker 2012-08-27 14:59:18 -07:00
Misko Hevery bf8ed8a532 doc(misc) updated getting started to reflect the new homepage 2012-08-27 14:59:18 -07:00
Misko Hevery d05a2809a1 doc(guide) simplify the guide home page 2012-08-27 14:59:17 -07:00
Igor Minar fa6c8c3131 chore(Rakefile): rewrite version numbers in all index files 2012-08-27 12:26:04 -07:00
Igor Minar f7ac8ef97a chore(docs): support _escaped_fragment_ hack for crawler 2012-08-25 02:30:55 -07:00
Igor Minar 4a4b28dbf3 chore(docs): use GAE and Google CDN for docs
Short summary: if you use local node server everything should work as before,
if you use GAE, everything should work now as well, but we pull assets from CDN.

- GAE doesn't support ':' in filenames, so I had to replace it with '_'
  but only in the filename, all servers were reconfigured to rewrite the
  urls from : to _ when doing file lookup
- We now pull angular assets from google CDN when deployed on GAE (locally
  or in production). When running on a non GAE server we pull assets from
  ../ directory as before
- Since only certain versions of Angular are available on CDN and we want
  to be able to autodeploy docs, I had to pin down the Angular files
  to a "stable" version when running on GAE
2012-08-24 14:54:35 -07:00
Igor Minar 3e12bc481d docs(a): expose hidden docs
It seems that docs for these directive were previously hidden by accident
2012-08-24 14:54:34 -07:00
johnlindquist 32137cab82 docs(ngRoute): fix typo
aftre -> after
2012-08-23 15:11:07 -04:00
phil f7b4296c38 docs(tutorial): fix typo in step_00
Just removed an extra comma. No big deal.
2012-08-23 01:02:28 -07:00
Igor Minar cab5e1d9b3 fix(docs): update docs top menu links 2012-08-16 11:26:36 -07:00
Igor Minar dfe99836cd fix($compile): denormalize directive templates
Since developers are allowed to customize start/end interpolation
strings, but third-party directive creators don't know about these
customizations, we should standardize on {{ }} in templates of
reusable (third-party) directives. During the compilation, these
templates are then denormalized to use whatever the custom
start/end symbol is, effectively translating the template into the
syntax of the runtime environment.

This addresses an issue raised at http://goo.gl/e8VPV

Existing code should not be affected by this change since project
that do use custom interpolation markers are not expected to use
{{ }} in existing directive templates.
2012-08-13 14:33:56 -07:00
Igor Minar 0f37194fb7 refactor($compile): code cleanup 2012-08-13 09:48:23 -07:00
Brian Ford e85774f709 fix(ngPluralize): fixes ng-pluralize when using non-standard start/end symbols
Closes #1134
2012-08-13 09:48:23 -07:00
Igor Minar 44345c74de style(ngPluralizeSpec): fix indentation 2012-08-13 09:48:22 -07:00
Igor Minar 58f121a5c2 feat($interpolate): expose start/end symbols in run phase
previously the startSymbol() and endSymbol() getters were exposed only via provider
in the config phase
2012-08-13 09:48:22 -07:00
Igor Minar cf6023ef22 docs($interpolateProvider): fixing docs 2012-08-13 09:48:22 -07:00
Igor Minar 2034871764 fix($interpolate): $interpolateProvider.endSymbol() returns startSymbol
I also added missing tests.
2012-08-13 09:48:21 -07:00
Igor Minar 15d283b114 docs($interpolate): fix typo in description 2012-08-13 09:48:21 -07:00
Vojta Jina 9be169365c docs($compileProvider): remove duplicate of .directive() 2012-08-12 10:45:14 -07:00
Vojta Jina 00683a8bbb docs: fix broken links to $compileProvider.directive() 2012-08-12 10:44:29 -07:00
Brian Ford f00b6cca02 fix(docs): fixed documentation for using linky 2012-08-10 16:33:25 -07:00
Brian Ford e05a97c6f5 chore(ngDoc): add support for custom @usage metadata 2012-08-10 16:33:13 -07:00
Brian Ford 2e3651686c fix(docs): added note about using JSON3 as a polyfill for IE7 2012-08-10 16:27:44 -07:00
Brian Ford 536de14821 fix(docs): added note about needing JSON shim for IE7 and earlier 2012-08-10 16:27:44 -07:00
Vojta Jina e0a54f6b20 feat($http): support reponseType
Closes #1013
2012-08-10 16:17:59 -07:00
Igor Minar 9767f7bdd3 fix(option): support option elements in datalist
previously we expected to find option elements only within select element and if
that was not the case we throw an error. This made it impossible to include datalist
element with nested option elements in the template.

Closes #1165
2012-08-10 16:14:30 -07:00
Vojta Jina 167aa0c29c feat($sniffer): auto detect CSP mode
Chrome Canary now has CSP with apis that allow auto-detection. This change
will turn on CSP mode automatically when we detect its presence.

https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html#script-interfaces--experimental
2012-08-10 14:53:53 -07:00
unirgy 4ccd9eb883 docs($rootScope): fix $on listener signature doc
Added args in $on() listener syntax declaration
2012-08-10 14:50:22 -07:00
Igor Minar c0d638a94b test(jqLite): add missing test for $destroy event 2012-08-10 13:04:39 -07:00
Igor Minar 054d40f338 fix(form): prevent page reload when form destroyed
this fix ensures that we prevent the default action on form submission
(full page reload) even in cases when the form is being destroyed as
a result of the submit event handler (e.g. when route change is
triggered).

The fix is more complicated than I'd like it to be mainly because
we need to ensure that we don't create circular references between
js closures and dom elements via DOM event handlers that would then
result in a memory leak.

Also the differences between IE8, IE9 and normal browsers make testing
this ugly.

Closes #1238
2012-08-10 13:03:55 -07:00
Igor Minar 5cec32492c test(form): fix broken preventDefault test
the original test relied on incorrect assumptions about how jasmine async
tests work (when setTimeout is triggered) and how browser reloads a page
(the sequence of events) and thus the test passes even when the default
is not prevented.

this change fixes the test by registering an extra submit event handler
that checks if the default was prevented.

if the default was not prevented, the test will fail and the page will
be reloaded causing the test runner to panic.
2012-08-07 22:07:49 -07:00
Igor Minar c25cb7d488 refactor(formSpec): group preventDefault specs into a describe 2012-08-07 17:23:16 -07:00
Igor Minar 54e4a6ffbf docs(faq): update faq docs 2012-08-07 10:15:54 -07:00
Igor Minar eee9a51fad docs(styles): fix the cog icon alignment 2012-08-06 16:54:18 -07:00
Vojta Jina 77e6d833f6 chore(nodeserver): add font mime type 2012-08-04 12:09:28 -07:00
Vojta Jina 33ad2b4126 docs(guide): hide scenario for directive example
scenario test for this example would be tricky, we need to teach
the runner how to inject mocks first.
2012-07-30 21:21:34 -07:00
Vojta Jina b84eaffd39 docs: fix icons
Copy fontawesome during build
2012-07-30 21:20:28 -07:00
brettcannon a1107e81eb fix(docs): "in depth" -> "in-depth" 2012-07-20 20:54:42 -07:00
JP Sugarbroad e3e8813e3c refactor($injector): move $injector into the providerCache
Better than special-casing '$injector' in createInjector.
2012-07-19 21:56:22 -07:00
Igor Minar 6e2d9711e8 chore(release): start 1.1.0 increase-gravatas iteration 2012-07-19 21:48:58 -07:00
140 changed files with 4333 additions and 2165 deletions
+1
View File
@@ -10,5 +10,6 @@ performance/temp*.html
*~
angular.js.tmproj
node_modules
jsTestDriver*.conf
angular.xcodeproj
.idea
-13
View File
@@ -1,13 +0,0 @@
language: node_js
node_js:
- 0.8
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm install -g testacular@canary
- rake package
- ./nodeserver.sh > /dev/null &
script:
- rake test[Firefox,"--reporters=dots"]
+3 -200
View File
@@ -1,206 +1,7 @@
<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
out and please give us feedback._
_Note: This release also contains all bug fixes available in [1.0.3](#1.0.3)._
## Features
- **$cacheFactory:** cache.put now returns the added value
([168db339](https://github.com/angular/angular.js/commit/168db33985aa025eb48bc21087717ab70da0bd72))
- **$http:** Allow setting withCredentials on defaults
([209b67df](https://github.com/angular/angular.js/commit/209b67df6a49fe1646ce63c5e7d11ed26e8abbc1),
[#1095](https://github.com/angular/angular.js/issues/1095))
- **$resource:** support custom headers per action
([fbdab513](https://github.com/angular/angular.js/commit/fbdab513dd48f667ad857030cf4b3481ecdd9097),
[#736](https://github.com/angular/angular.js/issues/736))
- **$sanitize:** support telephone links
([04450c48](https://github.com/angular/angular.js/commit/04450c48dfea065e1c9e4ab8adad94993ed1b037))
- **FormController:** add ability to reset a form to pristine state
([733a97ad](https://github.com/angular/angular.js/commit/733a97adf87bf8f7ec6be22b37c4676cf7b5fc2b),
[#856](https://github.com/angular/angular.js/issues/856))
- **jqLite:** add triggerHandler()
([650fd933](https://github.com/angular/angular.js/commit/650fd933df614ac733cd43fe31d81d622a2ce2bc))
- **linky filter:** allow optional 'target' argument
([610927d7](https://github.com/angular/angular.js/commit/610927d77b77700c5c61accd503a2af0fa51cfe6),
[#1443](https://github.com/angular/angular.js/issues/1443))
- **angular-mocks:** support mocha in angular mocks
([92558fe4](https://github.com/angular/angular.js/commit/92558fe4119fb1ee793d781de1888abef181c7f6))
- **ngModel:** support ngTrim attribute on input
([d519953a](https://github.com/angular/angular.js/commit/d519953a4b219035587e3fcb2e9cc52e02b408ca))
- **scenario:** add dblclick method to the ngScenario dsl
([8cb9c99e](https://github.com/angular/angular.js/commit/8cb9c99ec064fd95567118d29bfa4a19b8613ab3))
- **CSP:** update to the latest CSP api
([af7e0bd0](https://github.com/angular/angular.js/commit/af7e0bd0a7c286667c526cb7e0c733d3ee5f17fd),
[#1577](https://github.com/angular/angular.js/issues/1577))
## Bug Fixes
- **$http:**
- config.param should expand array values properly (see breaking change notes below)
([79af2bad](https://github.com/angular/angular.js/commit/79af2badcb087881e3fd600f6ae5bf3f86a2daf8),
[#1363](https://github.com/angular/angular.js/issues/1363))
- prevent CORS preflight checks by removing `X-Requested-With` from header defaults (see breaking
change notes below)
([3a75b112](https://github.com/angular/angular.js/commit/3a75b1124d062f64093a90b26630938558909e8d),
[#1004](https://github.com/angular/angular.js/issues/1004))
- prevent CORS preflight checks by not setting `X-XSFR-TOKEN` header for cross domain requests (see
breaking change notes below)
([fce100a4](https://github.com/angular/angular.js/commit/fce100a46c5681562253c3a856d67bbd35fbc2f2),
[#1096](https://github.com/angular/angular.js/issues/1096))
## Refactorings
- **$evalAsync:** have only one global async queue
([331cd5a8](https://github.com/angular/angular.js/commit/331cd5a8cb5efdafe8ad7eb386aed4033cfc1bb3))
## Breaking Changes
- Due to fix for [#1363](https://github.com/angular/angular.js/issues/1363) it's possible but unlikely
that $http will start generating different URLs for requests. This affects only cases when a request
is made with a parameter, value of which is an array. If the server relied on the buggy behavior then
either the backend should be fixed or a simple serialization of the array should be done on the client
before calling the $http service.
- Due to fix for [#1004](https://github.com/angular/angular.js/issues/1004) the `X-Requested-With` header
is not set by $http service any more. If anyone actually uses this header it's quite easy to add
it back via:
```
myAppModule.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
```
- Due to fix for [#1096](https://github.com/angular/angular.js/issues/1096) `X-XSFR-TOKEN` header is
no longer send for cross domain requests. This shouldn't affect any known production service. If we are
wrong, please let us know ;-)
<a name="1.0.3"></a>
# 1.0.3 bouncy-thunder (2012-11-26)
## Bug Fixes
- **$cacheFactory:** return undefined when removing non-existent entry
([55d15806](https://github.com/angular/angular.js/commit/55d15806fb14b1d98b5ca2770bbbb59e11548c62),
[#1497](https://github.com/angular/angular.js/issues/1497))
- **$compile:**
- prevent double attr interpolation w/ templateUrl
([fc115bfd](https://github.com/angular/angular.js/commit/fc115bfd0d18017f4bcef1e39fb22d97a98f8ab1),
[#1166](https://github.com/angular/angular.js/issues/1166))
- reference local in isolate scope
([8db47ca7](https://github.com/angular/angular.js/commit/8db47ca7d4303e3e45a838219a1f6e9be8770ed4),
[#1272](https://github.com/angular/angular.js/issues/1272))
- don't look for class directives in empty string
([54b3875b](https://github.com/angular/angular.js/commit/54b3875ba5cb6ce8ddac61ace33c1b2f600875ff))
- compilation should not recurse into empty nodes
([008a782b](https://github.com/angular/angular.js/commit/008a782bc8ed8a7ebcb63d563d1420fd1b312452))
- **$injector:** more conservative annotation parsing
- **$location:** reset $location.$$replace with every watch call
([a32bc40f](https://github.com/angular/angular.js/commit/a32bc40fd75ca46e3581ad7a6e3a24a31df6e266),
[#1111](https://github.com/angular/angular.js/issues/1111))
([d9eff86e](https://github.com/angular/angular.js/commit/d9eff86ef77dd76208cef21e882239d4db0eac1e))
- **$parser:** string concatination with undefined model
([42c38b29](https://github.com/angular/angular.js/commit/42c38b29f7dcb3327fe58e630b8e2973676989e0),
[#988](https://github.com/angular/angular.js/issues/988))
- **$resource:**
- prevent default params to be shared between actions
([94e1c039](https://github.com/angular/angular.js/commit/94e1c0391c351b6f691fad8abed2828fa20548b2))
- allow falsy values in URL parameters
([4909d1d3](https://github.com/angular/angular.js/commit/4909d1d39d61d6945a0820a5a7276c1e657ba262))
- ignore undefined parameters
([10e1c759](https://github.com/angular/angular.js/commit/10e1c759f4602d993a76b0eacf6a2d04c8880017),
[#875](https://github.com/angular/angular.js/issues/875),
[#782](https://github.com/angular/angular.js/issues/782))
- **Scope:**
- workaround for Chrome's memleak
([bd524fc4](https://github.com/angular/angular.js/commit/bd524fc4e5fc0feffe85632a7a6560da6bd9b762),
[#1313](https://github.com/angular/angular.js/issues/1313))
- allow removing a listener during event
([e6966e05](https://github.com/angular/angular.js/commit/e6966e05f508d1d2633b9ff327fea912b12555ac))
- **$route:** support inline annotation on .resolve
([b0a05a75](https://github.com/angular/angular.js/commit/b0a05a7531ed7235aa6d2c4e3ea11373e1fc73f1))
- **FormController:** propagate dirty state to parent forms
([04329151](https://github.com/angular/angular.js/commit/04329151d2df833f803629cefa781aa6409fe6a5))
- **a:** prevent Opera from incorrectly navigating on link click
([c81d8176](https://github.com/angular/angular.js/commit/c81d8176cc55cd15acae05259ead73f90a01f0b7))
- **jqLite:**
- support append on document fragment
([96ed9ff5](https://github.com/angular/angular.js/commit/96ed9ff59a454486c88bdf92ad9d28ab8864b85e))
- fire $destroy event via triggerHandler (this makes AngularJS compatible with **jQuery 1.8.x**)
([b9a9f91f](https://github.com/angular/angular.js/commit/b9a9f91fbf99b71cfde434b6277f4c7d2533556f),
[#1512](https://github.com/angular/angular.js/issues/1512))
- **Filters**
- **currency:** Handle not-quite-zero values
([bca1604c](https://github.com/angular/angular.js/commit/bca1604c12262b66ce3b8004994fb4841fb8b87d),
[#1469](https://github.com/angular/angular.js/issues/1469))
- **date:**
- make timezone optional
([9473780e](https://github.com/angular/angular.js/commit/9473780e77a960ba27644ca76c2413924cc8972e))
- support sub-second precision on dateFilter
([f299fd51](https://github.com/angular/angular.js/commit/f299fd512248321b426a5ab924a329aa1b691280))
- **Directives**
- **ngClass:** works with class interpolation
([cebd015f](https://github.com/angular/angular.js/commit/cebd015f78c5e21bd37d4bc055dbcdc21dac2ef2),
[#1016](https://github.com/angular/angular.js/issues/1016))
- **ngClassOdd/ngClassEven:** support shrinking/reordering in repeaters
([d859dcec](https://github.com/angular/angular.js/commit/d859dcecea654d1d858cd756c6efb8435a453197),
[6c67719d](https://github.com/angular/angular.js/commit/6c67719dfa6ff3f2a15a8e1e7660cf2e6e9155b0),
[#1076](https://github.com/angular/angular.js/issues/1076))
- **ngModel:** sync ngModel state with scope state
([e6d9bea4](https://github.com/angular/angular.js/commit/e6d9bea4f3b2eb28851298d3dc3a30d46062d58a),
[#933](https://github.com/angular/angular.js/issues/933))
- **ngRepeat:** now works better with primitive types
([e6d9bea4](https://github.com/angular/angular.js/commit/e6d9bea4f3b2eb28851298d3dc3a30d46062d58a),
[#933](https://github.com/angular/angular.js/issues/933))
- **ngSrc:** don't set src if value is empty string
([b6e4a711](https://github.com/angular/angular.js/commit/b6e4a71166c7f00f4140fd7ea8f0cd81b4487a3f))
- **select:** select option with a label of 0 is not shown
([b3cae4f4](https://github.com/angular/angular.js/commit/b3cae4f457f1688346bbd0b08cccc9c504f83406),
[#1401](https://github.com/angular/angular.js/issues/1401))
- **scenario:**
- emit RunnerBegin event
([95276a7e](https://github.com/angular/angular.js/commit/95276a7e1047c7a3ac6613d8612c62f544388fc9))
- NPE when no angular loaded in test page
([84c13d96](https://github.com/angular/angular.js/commit/84c13d96ff6e993b2ee9ff6bf49614fc1d514b04))
- support data-ng and x-ng based attributes
([249a1d84](https://github.com/angular/angular.js/commit/249a1d84e7ac3b8528d317b8b0a80acb5dd9a271),
[#1020](https://github.com/angular/angular.js/issues/1020))
## Docs
- add plunkr support
([7c67b2fb](https://github.com/angular/angular.js/commit/7c67b2fb6afbc18f3593c64a5f339f04f9003f3c))
- various small documentation fixes and improvements
## Refactorings
- name all anonymous watch functions in Angular
([ca30fce2](https://github.com/angular/angular.js/commit/ca30fce28ca13284bfa1c926e810ed75cdcde499),
[#1119](https://github.com/angular/angular.js/issues/1119))
<a name="1.1.0"></a>
# 1.1.0 increase-gravatas (2012-08-31)
_Note: 1.1.x releases unlike 1.0.x are considered unstable.
[More info](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html)_
This release also contains all bug fixes available in [1.0.2](#1.0.2).
_Note: 1.1.x releases are [considered unstable](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html)._
## Features
@@ -215,6 +16,8 @@ This release also contains all bug fixes available in [1.0.2](#1.0.2).
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
This release also contains all bug fixes available in [1.0.2](#1.0.2).
<a name="1.0.2"></a>
-32
View File
@@ -1,32 +0,0 @@
## Submitting issues
If you have questions about how to use AngularJS, please direct these to the
[Google Group][groups] discussion list or [StackOverflow][stackoverflow]. We are
also available on [IRC][irc].
### Guidelines
* Search the archive first, it's likely that your question was already answered.
* A live example demonstrating your problem or question, will get an answer faster.
* Create one using this [template][template]
* If you get help, help others. Good karma rulez!
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues.
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[template]: http://plnkr.co/edit/gist:3510140
## Contributing to Source Code
We'd love for you to contribute to our source code and to make AngularJS even
better than it is today!
Please read the [contribution guidelines][contribute] to learn about how to submit code as well as
other useful info like how to build and test AngularJS code.
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute
+6 -22
View File
@@ -13,33 +13,17 @@ it makes development fun!
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org/api
* API Docs: http://docs.angularjs.org
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
Building AngularJS
Compiling
---------
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
rake package
rake compile
Running Tests
-------------
Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
./server.sh # start the server
open http://localhost:9876/capture # capture browser
./test.sh # run all unit tests
sudo npm install -g testacular
To execute all unit tests, use:
rake test:unit
To execute end-to-end (e2e) tests, use:
rake package
rake webserver &
rake test:e2e
To learn more about the rake tasks, run `rake -T` and also read our
[contribution guidelines](http://docs.angularjs.org/misc/contribute) and instructions in this
[commit message](https://github.com/angular/angular.js/commit/9d168f058f9c6d7eeae0daa7cb72ea4e02a0003a).
+25 -83
View File
@@ -40,7 +40,6 @@ desc 'Clean Generated Files'
task :clean do
FileUtils.rm_r(BUILD_DIR, :force => true)
FileUtils.mkdir(BUILD_DIR)
FileUtils.rm_r('test_out', :force => true)
end
@@ -124,16 +123,8 @@ task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter
'angular-bootstrap.js',
'angular-bootstrap-prettify.js'
].each do |file|
fork { closure_compile(file) }
closure_compile(file)
end
Process.waitall
end
desc 'Generate version.txt file'
task :version => [:init] do
`echo #{NG_VERSION.full} > #{path_to('version.txt')}`
end
@@ -159,7 +150,7 @@ end
desc 'Create angular distribution'
task :package => [:clean, :minify, :version, :docs] do
task :package => [:clean, :minify, :docs] do
zip_dir = "angular-#{NG_VERSION.full}"
zip_file = "#{zip_dir}.zip"
@@ -173,74 +164,37 @@ task :package => [:clean, :minify, :version, :docs] do
end
desc 'Start development webserver'
task :webserver, :port do |t, args|
exec "node lib/nodeserver/server.js #{args[:port]}"
namespace :server do
desc 'Run JsTestDriver Server'
task :start do
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
end
desc 'Run JavaScript tests against the server'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
end
end
desc 'Run all AngularJS tests'
task :test, :browsers, :misc_options do |t, args|
[ 'test:jqlite',
'test:jquery',
'test:modules',
'test:e2e'
].each do |task|
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
end
desc 'Run JavaScript tests'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
end
namespace :test do
desc 'Run all unit tests (single run)'
task :unit, :browsers, :misc_options do |t, args|
[ 'test:jqlite',
'test:jquery',
'test:modules'
].each do |task|
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
end
end
desc 'Run jqLite-based unit test suite (single run)'
task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run jQuery-based unit test suite (single run)'
task :jquery, :browsers, :misc_options do |t, args|
start_testacular('testacular-jquery.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run bundled modules unit test suite (single run)'
task :modules, :browsers, :misc_options do |t, args|
start_testacular('testacular-modules.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run e2e test suite (single run)'
task :e2e, :browsers, :misc_options do |t, args|
start_testacular('testacular-e2e.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Lint'
task :lint do
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
print out
end
namespace :autotest do
desc 'Run jqLite-based unit test suite (autowatch)'
task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', false, args[:browsers], args[:misc_options])
end
desc 'Run jQuery-based unit test suite (autowatch)'
task :jquery, :browsers, :misc_options do |t, args|
start_testacular('testacular-jquery.conf.js', false, args[:browsers], args[:misc_options])
end
desc 'push_angularjs'
task :push_angularjs => :compile do
sh %(cat angularjs.ftp | ftp -N angularjs.netrc angularjs.org)
end
@@ -291,10 +245,7 @@ def closure_compile(filename)
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
%x(java \
-client \
-d32 \
-jar lib/closure-compiler/compiler.jar \
%x(java -jar lib/closure-compiler/compiler.jar \
--compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5_STRICT \
--js #{path_to(filename)} \
@@ -345,12 +296,3 @@ def rewrite_file(filename)
f.write content
end
end
def start_testacular(config, singleRun, browsers, misc_options)
sh "./node_modules/testacular/bin/testacular start " +
"#{config} " +
"#{'--single-run=true' if singleRun} " +
"#{'--browsers=' + browsers.gsub('+', ',') if browsers} " +
"#{(misc_options || '').gsub('+', ',')}"
end
+30 -24
View File
@@ -196,30 +196,36 @@ angularFiles = {
]
};
if (exports) {
exports.files = angularFiles
exports.mergeFiles = function mergeFiles() {
var files = [];
[].splice.call(arguments, 0).forEach(function(file) {
if (file.match(/testacular/)) {
files.push(file);
} else {
angularFiles[file].forEach(function(f) {
// replace @ref
var match = f.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
files = files.concat(deps);
} else {
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
files.push(f);
}
}
});
// Execute only in slim-jim
if (typeof JASMINE_ADAPTER !== 'undefined') {
// Testacular config
var mergedFiles = [];
angularFiles.jstd.forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
if (!deps) {
console.log('No dependency:' + file)
}
});
mergedFiles = mergedFiles.concat(deps);
} else {
mergedFiles.push(file);
}
});
return files;
}
files = [JASMINE, JASMINE_ADAPTER];
mergedFiles.forEach(function(file){
if (/jstd|jasmine/.test(file)) return;
files.push(file);
});
exclude = angularFiles.jstdExclude;
autoWatch = true;
autoWatchInterval = 1;
logLevel = LOG_INFO;
logColors = true;
}
+5
View File
@@ -0,0 +1,5 @@
bin
cd angularjs.org/ng
put angular-debug.js js/angular-debug.js
put angular-minified.js js/angular-minified.js
put angular-scenario.js js/angular-scenario.js
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
rake minify
rake compile
gzip -c < build/angular.min.js > build/angular.min.js.gzip
ls -l build/angular.min.*
+1 -1
View File
@@ -3,5 +3,5 @@
@description
Use the API Reference documentation when you need more information about a specific feature. Check out
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the
{@link tutorial/ Tutorial}.
+29 -29
View File
@@ -32,14 +32,14 @@ This is how we get the ball rolling (refer to the diagram and example below):
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
{@link guide/directive directive}, which designates application boundary
5. {@link guide/module Module} specified in {@link
api/ng.directive:ngApp ng-app} (if any) is used to configure
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
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. {@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. {@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
@@ -80,8 +80,8 @@ implementing custom event callbacks, or when working with a third-party library
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
@@ -96,7 +96,7 @@ implementing custom event callbacks, or when working with a third-party library
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 Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
@@ -122,7 +122,7 @@ user enters text into the text field.
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#123;&#123;name&#125;&#125; } interpolation, which in turn updates the DOM.
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
the JavaScript execution context.
7. The browser re-renders the view with update text.
@@ -165,7 +165,7 @@ a diagram depicting the scope boundaries.
function GreetCtrl($scope) {
$scope.name = 'World';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
@@ -196,7 +196,7 @@ controller.
The separation of the controller and the view is important because:
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
for specifying application behavior. The controller should not contain any rendering
for specifying application behavior. The controller should not contain any rendering
information (DOM references or HTML fragments).
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
specifying UI. The View should not contain any behavior.
@@ -220,7 +220,7 @@ The separation of the controller and the view is important because:
$scope.action = function() {
$scope.name = 'OK';
}
$scope.name = 'World';
}
</file>
@@ -249,8 +249,8 @@ primitive, object hash, or a full object Type. In short the model is a plain Jav
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
The view is what the users sees. The view begins its life as a template, it is merged with the
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view, to most other templating systems.
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view, to most other templating systems.
* **Others** - Most templating systems begin as an HTML string with special templating markup.
Often the template markup breaks the HTML syntax which means that the template can not be
@@ -260,13 +260,13 @@ rendering the view, to most other templating systems.
When the model changes the whole process needs to be repeated. The granularity of the template
is the granularity of the DOM updates. The key here is that the templating system manipulates
strings.
* **Angular** - Angular is different, since its templating system works on DOM objects not on
* **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
looks for {@link guide/directive directives} which in turn set up {@link
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
continuously updating view which does not need template model re-merging. Your model becomes
continuously updating view which does not need template model re-merging. Your model becomes
the single source-of-truth for your view.
<div class="clear">
@@ -339,13 +339,13 @@ in HTML.
{@link api/ng.$filter Filters} perform data transformation roles. 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).
They are follow the spirit of UNIX filters and follow similar syntax `|` (pipe).
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
Number formatting: {{ 1234567890 | number }} <br>
array filtering <input ng-model="predicate">
array filtering <input ng-model="predicate">
{{ list | filter:predicate | json }}
</div>
</file>
@@ -362,7 +362,7 @@ An {@link api/AUTO.$injector injector} is a service locator. There is a single
{@link api/AUTO.$injector injector} per Angular {@link
api/ng.directive:ngApp application}. The {@link
api/AUTO.$injector injector} provides a way to look up an object instance by its
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
name. The injector keeps on internal cache of all objects so that repeated calls to get the same
object name result in the same instance. If the object does not exist, then the {@link
api/AUTO.$injector injector} asks the instance factory to create a new instance.
@@ -373,20 +373,20 @@ as a {@link api/AUTO.$provide provider}.
<pre>
// Create a module
var myModule = angular.module('myModule', [])
// Configure the injector
myModule.factory('serviceA', function() {
return {
// instead of {}, put your object creation here
};
});
// create an injector and configure it from 'myModule'
var $injector = angular.injector(['myModule']);
var $injector = angular.injector('myModule');
// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');
// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');
</pre>
@@ -395,7 +395,7 @@ as a {@link api/AUTO.$provide provider}.
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
used to {@link api/AUTO.$injector#invoke call} methods and {@link
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
allows the methods and types to ask for their dependencies instead of having to look for them.
allows the methods and types to ask for their dependencies rather then to look for them.
<pre>
// You write functions such as this one.
@@ -405,12 +405,12 @@ allows the methods and types to ask for their dependencies instead of having to
// Angular provides the injector for your application
var $injector = ...;
///////////////////////////////////////////////
// the old-school way of getting dependencies.
var serviceA = $injector.get('serviceA');
var serviceB = $injector.get('serviceB');
// now call the function
doSomething(serviceA, serviceB);
@@ -425,7 +425,7 @@ function arguments. When angular calls the function, it will use the {@link
api/AUTO.$injector#invoke call} which will automatically fill the function
arguments.
Examine the `ClockCtrl` bellow, and notice how it lists the dependencies in the constructor. When the
Examine the `ClockCtrl` bellow, and notice how it list the dependencies in constructor. When the
{@link api/ng.directive:ngController ng-controller} instantiates
the controller it automatically provides the dependencies. There is no need to create
dependencies, look for dependencies, or even get a reference to the injector.
@@ -442,15 +442,15 @@ dependencies, look for dependencies, or even get a reference to the injector.
// which will be available for injection
factory('time', function($timeout) {
var time = {};
(function tick() {
time.now = new Date().toString();
$timeout(tick, 1000);
})();
return time;
});
// Notice that you can simply ask for time
// Notice that you can simply ask for time
// and it will be provided. No need to look for it.
function ClockCtrl($scope, time) {
$scope.time = time;
@@ -122,7 +122,7 @@ Returns the current value of an input field with the given `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
used for test output.
used for test ouput.
## repeater(selector, label).row(index)
Returns an array with the bindings in the row at the given `index` in the repeater matching the
@@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
## Comparing $location to window.location
<table class="table">
<table>
<thead>
<tr>
<th class="empty-corner-lt"></th>
<th>window.location</th>
<th>$location service</th>
<td class="empty-corner-lt"></td>
<td>window.location</td>
<td>$location service</td>
</tr>
</thead>
@@ -165,13 +165,13 @@ facilitate the browser URL change and history management.
<img src="img/guide/hashbang_vs_regular_url.jpg">
<table class="table">
<table>
<thead>
<tr>
<th class="empty-corner-lt"></th>
<th>Hashbang mode</th>
<th>HTML5 mode</th>
<td class="empty-corner-lt"></td>
<td>Hashbang mode</td>
<td>HTML5 mode</td>
</tr>
</thead>
@@ -543,73 +543,69 @@ then uses the information it obtains to compose hashbang URLs (such as
## Changes to your code
<table class="table">
<thead>
<tr class="head">
<th>Navigation inside the app</th>
<th>Change to</th>
</tr>
</thead>
<table>
<tr class="head">
<td>Navigation inside the app</td>
<td>Change to</td>
</tr>
<tbody>
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
/>$location.updateHash(value)</td>
<td>$location.path(path).search(search)</td>
</tr>
<td>$location.path(path).search(search)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</td>
</tr>
<tr>
<td>$location.hashSearch = search</td>
<td>$location.search(search)</td>
</tr>
<tr>
<td>$location.hashSearch = search</td>
<td>$location.search(search)</td>
</tr>
<tr class="head">
<td>Navigation outside the app</td>
<td>Use lower level API</td>
</tr>
<tr class="head">
<td>Navigation outside the app</td>
<td>Use lower level API</td>
</tr>
<tr>
<td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td>
</tr>
<tr>
<td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td>
</tr>
<tr>
<td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td>
</tr>
<tr>
<td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td>
</tr>
<tr class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</td>
</tr>
<tr>
<td>$location.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
/>$location.hash</td>
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
/>$location.path() + $location.search()</td>
</tr>
</tr>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td>
</tr>
</tbody>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td>
</tr>
</table>
## Two-way binding to $location
+18 -20
View File
@@ -63,7 +63,7 @@ api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is sh
here:
<pre>
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
</pre>
# Compilation process, and directive matching
@@ -253,7 +253,7 @@ An example skeleton of the directive is shown here, for the complete list see be
In most cases you will not need such fine control and so the above can be simplified. All of the
different parts of this skeleton are explained in following sections. In this section we are
interested only in some of this skeleton.
interested only isomers of this skeleton.
The first step in simplyfing the code is to rely on the default values. Therefore the above can be
simplified as:
@@ -321,27 +321,25 @@ compiler}. The attributes are:
derived from the parent scope. These local properties are useful for aliasing values for
templates. Locals definition is a hash of local scope property to its source:
* `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
always a string since DOM attributes are strings. If no `attr` name is specified then the
attribute name is assumed to be the same as the local name.
Given `<widget my-attr="hello {{name}}">` and widget definition
* `@` or `@attr` - bind a local scope property to the DOM attribute. The result is always a
string since DOM attributes are strings. If no `attr` name is specified then the local name
and attribute name are same. Given `<widget my-attr="hello {{name}}">` and widget definition
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
`localName` property on the widget scope. The `name` is read from the parent scope (not
component scope).
* `=` or `=attr` - set up bi-directional binding between a local scope property and the
parent scope property of name defined via the value of the `attr` attribute. If no `attr`
name is specified then the attribute name is assumed to be the same as the local name.
Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
* `=` or `=expression` - set up bi-directional binding between a local scope property and the
parent scope property. If no `attr` name is specified then the local name and attribute
name are same. Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localName` will reflect the
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
in `localModel` and any changes in `localModel` will reflect in `parentModel`.
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
If no `attr` name is specified then the 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
If no `attr` name is specified then the local name and attribute name are same.
Given `<widget my-attr="count = count + value">` and widget definition of
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
the isolate scope via an expression and to the parent scope, this can be done by passing a
map of local variable names and values into the expression wrapper fn. For example, if the
@@ -351,7 +349,7 @@ compiler}. The attributes are:
* `controller` - Controller constructor function. The controller is instantiated before the
pre-linking phase and it is shared with other directives if they request it by name (see
`require` attribute). This allows the directives to communicate with each other and augment
each other's behavior. The controller is injectable with the following locals:
each other behavior. The controller is injectable with the following locals:
* `$scope` - Current scope associated with the element
* `$element` - Current element
@@ -537,7 +535,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="show()">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
@@ -557,10 +555,10 @@ expects as follows:
<pre>
scope: {
title: '=', // set up title to accept data-binding
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
show: '='
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.
}
</pre>
+4 -3
View File
@@ -5,8 +5,9 @@
# What is a Module?
Most applications have a main method which instantiates, wires, and bootstraps the application.
Angular apps don't have a main method. Instead modules declaratively specify how an application
should be bootstrapped. There are several advantages to this approach:
Angular apps don't have a main method, instead modules serve the purpose of declaratively
specifying how an application should be bootstrapped. There are several advantages to this
approach:
* The process is more declarative which is easier to understand
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
@@ -30,7 +31,7 @@ Important things to notice:
<doc:source>
<script>
// declare a module
var myAppModule = angular.module('myApp', []);
var simpleAppModule = angular.module('myApp', []);
// configure the module.
// in this example we will create a greeting filter
+65 -75
View File
@@ -13,19 +13,19 @@
<a name="H1_1"></a>
# License
AngularJS is an open source project licensed under the {@link
`Angular` is an open source project licensed under the {@link
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
always welcome. When working with AngularJS code base, please follow the guidelines provided on
always welcome. When working with `angular` source base, please follow the guidelines provided on
this page.
<a name="H1_2"></a>
# Contributing to Source Code
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
We'd love for you to contribute to our source code and to make `angular` even better than it is
today! Here are the guidelines we'd like you to use:
* Major changes that you intend to contribute to the project should be discussed first on our {@link
* Major changes that you intend to contribute to the project must be discussed first on our {@link
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
is successfully accepted upstream.
@@ -64,39 +64,45 @@ inheritance only when absolutely necessary.
external API. See our existing code to see what we mean.
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
that is used throughout `angular`. The best guidance is to do what makes the most sense.
<a name="H1_4"></a>
# Checking Out and Building Angular
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
Several steps are needed to check out and build AngularJS:
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. Several steps are needed to check out and build `angular`:
## Installation Dependencies
Before you can build AngularJS, you must install or configure the following dependencies on your
Before you can build `angular`, you must install or configure the following dependencies on your
machine:
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
Rake website.
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
development web server. Depending on your system, you can install Node either from source or as a
pre-packaged bundle.
Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
of the Angular repository (see below) with:
You'll also need npm and the following npm modules:
* `cd angular.js`
* `npm install`
* install npm: `curl http://npmjs.org/install.sh | sh`
* install q: `npm install q`
* install qq: `npm install qq`
* install q-fs: `npm install q-fs`
* install jasmine-node: `npm install jasmine`
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
`angular` source base, which means there is no need to install or configure it separately.
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
## Creating a Github Account and Forking Angular
@@ -106,31 +112,31 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
https://github.com/angular/angular.js main angular repository}.
## Building AngularJS
## Building `Angular`
To build AngularJS, you check out the source code and use Rake to generate the non-minified and
minified AngularJS files:
To build `angular`, you check out the source code and use Rake to generate the non-minified and
minified `angular` files:
1. To clone your Github repository, run:
git clone git@github.com:<github username>/angular.js.git
2. To go to the AngularJS directory, run:
2. To go to the `angular` directory, run:
cd angular.js
3. To add the main AngularJS repository as an upstream remote to your repository, run:
3. To add the main `angular` repository as an upstream remote to your repository, run:
git remote add upstream https://github.com/angular/angular.js.git
4. To build AngularJS, run:
4. To build `angular`, run:
rake package
The build output can be located under the `build` directory. It consists of the following files and
directories:
* `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
artifacts.
* `angular.js` — The non-minified `angular` script.
@@ -139,6 +145,8 @@ artifacts.
* `angular-scenario.js` — The `angular` End2End test runner.
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
* `docs/index.html` — The main page for the documentation.
@@ -146,70 +154,60 @@ artifacts.
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
<a name="webserver"></a>
## Running a Local Development Web Server
To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
made available a local web server based on Node.js.
1. To start the web server, run:
rake webserver
./nodeserver.sh
2. To access the local server, go to this website:
http://localhost:8000/
By default, it serves the contents of the AngularJS project directory.
By default, it serves the contents of the `angular` project directory.
<a name="unit-tests"></a>
## Running the Unit Test Suite
Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
tests once on Chrome run:
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
tests:
rake test:unit
1. To start the JSTD server, run:
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
./server.sh
rake test:unit[Opera+Firefox]
During development it's however more productive to continuously run unit tests every time the source or test files
change. To execute tests in this mode run:
1. To start the Testacular server, capture Chrome browser and run unit tests, run:
rake autotest:jqlite
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
of Testacular running, read Testacular's console output for the correct url):
2. To capture one or more browsers, go to this website:
http://localhost:9876/
3. To re-run tests just change any source or test file.
3. To trigger a test execution, run:
./test.sh
4. To automatically run the test suite each time one or more of the files in the project directory
is changed, you can install `watchr` and then run:
watchr watchr.rb
5. To view the output of each test run, you can tail this log file:
./logs/jstd.log
To learn more about all of the preconfigured Rake tasks run:
## Running the End2End Test Suite
rake -T
## Running the end-to-end Test Suite
To run the E2E test suite:
1. Start the local web server if it's not running already.
rake webserver
To run the End2End test suite:
1. Start the local web server.
2. In a browser, go to:
http://localhost:8000/build/docs/docs-scenario.html
or in terminal run:
rake test:e2e
The tests are executed automatically.
@@ -218,38 +216,30 @@ 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
accepted, the CLA must be signed. It's a quick process, we promise!
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
2. Create a new branch off the master for your changes:
1. Create a new branch off the master for your changes:
git branch my-fix-branch
3. Check out the branch:
2. Check out the branch:
git checkout my-fix-branch
4. Create your patch, make sure to have plenty of tests (that pass).
3. Create your patch, make sure to have plenty of tests (that pass).
5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
please check out our
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
and our commit message presubmit hook `validate-commit-msg.js`):
4. Commit your changes:
git commit -a
5. Run JavaScript Lint and be sure to address all new warnings and errors:
rake lint
6. Push your branch to Github:
git push origin my-fix-branch
7. In Github, send a pull request to `angular:master`.
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository:
+14 -16
View File
@@ -16,14 +16,14 @@ development.
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:
example points to (non-minified) version 0.10.6:
<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="http://code.angularjs.org/angular-0.10.6.js"></script>
</head>
<body>
</body>
@@ -42,31 +42,29 @@ Download the version you want and have fun.
Each directory under <http://code.angularjs.org/> includes the following set of files:
* __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
opening it it any editor or browser. In order to get better error messages during development, you
should always use this non-minified angular script.
* __`angular.min.js`__ — This is a minified and obfuscated version of
`angular.js` created with the Closure compiler. Use this version for production in order
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
to minimize the size of the application that is downloaded by your user's browser.
* __`angular.zip`__ — This is a zip archive that contains all of the files released
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
for this angular version. Use this file to get everything in a single download.
* __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
of angular files, make sure that this file is available for download, and that it resides under the
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
testing angular apps even easier. Your unit/integration test harness should load this file after
`angular-<version>.js` is loaded.
* __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
to write and execute end-to-end tests for angular applications.
* __`angular-loader.min.js`__ — Module loader for Angular modules. If you are loading multiple script files containing
Angular modules, you can load them asynchronosuly and in any order as long as you load this file first. Often the
contents of this file are copy&pasted into the `index.html` to avoid even the inial request to `angular-loader.min.js`.
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
* __`docs`__ — this directory contains all the files that compose the
* __`docs-<version>`__ — this directory contains all the files that compose the
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
our docs, or even more importantly, view the docs offline.
+10 -109
View File
@@ -4,8 +4,6 @@
#FAQ
## Questions
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
Because HTML has Angular brackets and "ng" sounds like "Angular".
@@ -23,7 +21,7 @@ So it's definitely not a plugin or some other native browser extension.
### Is AngularJS a templating system?
At the highest level, Angular does look like a just another templating system. But there is one
important reason why the Angular templating system is different, that makes it very good fit for
important reason why Angular templating system is different and makes it very good fit for
application development: bidirectional data binding. The template is compiled in the browser and
the compilation step produces a live view. This means you, the developers, don't need to write
code to constantly sync the view with the model and the model with the view as in other
@@ -32,7 +30,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 with any 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.
@@ -48,9 +46,9 @@ Yes. See instructions in {@link downloading}.
### What browsers does Angular work with?
### What browsers does angular work with?
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
Our we run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
@@ -69,129 +67,32 @@ illustration we typically build snappy apps with hundreds or thousands of active
The size of the file is < 29KB compressed and minified.
### Can I use the open-source Closure Library with Angular?
### Can I use the open-source Closure Library with angular?
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
in Angular.
in angular.
### Does Angular use the jQuery library?
### Does angular use the jQuery library?
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
### What is testability like in Angular?
### What is testability like in angular?
Very testable and designed this way from ground up. It has an integrated dependency injection
framework, provides mocks for many heavy dependencies (server-side communication). See
{@link api/ng service} for details.
### How can I learn more about Angular?
### How can I learn more about angular?
Watch the July 28, 2010 talk
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
AJAX Apps}".
### How is Angular licensed?
### How is angular licensed?
The MIT License.
## Common Pitfalls
The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into.
This document aims to point them out before you discover them the hard way.
### DOM Manipulation
Stop trying to use jQuery to modify the DOM in controllers. Really.
That includes adding elements, removing elements, retrieving their contents, showing and hiding them.
Use built-in directives, or write your own where necessary, to do your DOM manipulation.
See below about duplicating functionality.
If you're struggling to break the habit, consider removing jQuery from your app.
Really. Angular has the $http service and powerful directives that make it almost always unnecessary.
Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events.
### Trying to duplicate functionality that already exists
There's a good chance that your app isn't the first to require certain functionality.
There are a few pieces of Angular that are particularly likely to be reimplemented out of old habits.
**ng-repeat**
`ng-repeat` gets this a lot.
People try to use jQuery (see above) to add more elements to some container as they're fetched from the server.
No, bad dog.
This is what `ng-repeat` is for, and it does its job very well.
Store the data from the server in an array on your `$scope`, and bind it to the DOM with `ng-repeat`.
**ng-show**
`ng-show` gets this frequently too.
Conditionally showing and hiding things using jQuery is a common pattern in other apps, but Angular has a better way.
`ng-show` (and `ng-hide`) conditionally show and hide elements based on boolean expressions.
Describe the conditions for showing and hiding an element in terms of `$scope` variables:
<div ng-show="!loggedIn">Click <a href="#/login">here</a> to log in</div>
Note also the counterpart `ng-hide` and similar `ng-disabled`.
Note especially the powerful `ng-switch` that should be used instead of several mutually exclusive `ng-show`s.
**ng-class**
`ng-class` is the last of the big three.
Conditionally applying classes to elements is another thing commonly done manually using jQuery.
Angular, of course, has a better way.
You can give `ng-class` a whitespace-separated set of class names, and then it's identical to ordinary `class`.
That's not very exciting, so there's a second syntax:
<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>
Where you give `ng-class` an object, whose keys are CSS class names and whose values are conditional expressions using `$scope` variables.
The element will then have all the classes whose conditions are truthy, and none of those whose conditions are falsy.
Note also the handy `ng-class-even` and `ng-class-odd`, and the related though somewhat different `ng-style`.
### `$watch` and `$apply`
Angular's two-way data binding is the root of all awesome in Angular.
However, it's not magic, and there are some situations where you need to give it a nudge in the right direction.
When you bind a value to an element in Angular using `ng-model`, `ng-repeat`, etc., Angular creates a `$watch` on that value.
Then whenever a value on a scope changes, all `$watch`es observing that element are executed, and everything updates.
Sometimes, usually when you're writing a custom directive, you will have to define your own `$watch` on a scope value to make the directive react to changes.
On the flip side, sometimes you change a scope value in some code but the app doesn't react to it.
Angular checks for scope variable changes after pieces of your code have finished running; for example, when `ng-click` calls a function on your scope, Angular will check for changes and react.
However, some code is outside of Angular and you'll have to call `scope.$apply()` yourself to trigger the update.
This is most commonly seen in event handlers in custom directives.
### Combining `ng-repeat` with other directives
`ng-repeat` is extremely useful, one of the most powerful directives in Angular.
However the transformation it applies to the DOM is substantial.
Therefore applying other directives (such as `ng-show`, `ng-controller` and others) to the same element as `ng-repeat` generally leads to problems.
If you want to apply a directive to the whole repeat, wrap the repeat in a parent element and put it there.
If you want to apply a directive to each inner piece of the repeat, put it on a child of the element with `ng-repeat`.
### `$rootScope` exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app.
For these, you can inject `$rootScope` and set values on it like any other scope.
Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like `ng-show` just like values on your local `$scope`.
Of course, global state sucks and you should use `$rootScope` sparingly, like you would (hopefully) use with global variables in any language.
In particular, don't use it for code, only data.
If you're tempted to put a function on `$rootScope`, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
+65 -32
View File
@@ -47,23 +47,20 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
# Working with the code
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. The tutorial relies on the use of Git versioning system for source code management.
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
and follow the instructions for setting up your computer.
environment. Options for working with the tutorial are to use the Git versioning system for source
code management or to use scripts that copy snapshots of project files into your workspace
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your
computer for your preferred option.
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
don't have it already:</p>
<pre>npm install -g testacular</pre>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
following command in a terminal window:</p>
<pre>java -version</pre>
<p>You will need Java to run unit tests.</p></li>
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p>
<p>You can build Git from source or use the pre-compiled package.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
@@ -74,41 +71,77 @@ directory.</p></li>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
have Apache pre-installed, but If you don't already have one installed, you can <a
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
don't have it already:</p>
<pre>npm install -g testacular</pre>
</li>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<li><p>You will need Java to run unit tests, so run the following command to verify that you
have <a href="http://java.com/">Java</a> installed and that the <code>java</code> executable is on
your <code>PATH</code>.</p>
<pre>java -version</pre>
<p></p></li>
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li>
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
<li><p>Change your current directory to angular-phonecat.</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p>
<p>You should run all <code>git</code> commands from Git bash.</p>
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
<p>You should run all <code>git</code> commands from msysGit bash.</p>
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be
executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
bundled http server.</p></li>
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux">
<ol>
<li><p>You need Java to run unit tests, so verify that you have <a
href="http://java.com/">Java</a> installed by running the following command in a terminal
window:</p>
<pre>java -version</pre>
<li><p>Download the <a href="http://code.angularjs.org/angular-phonecat/">zip archive</a>
containing all of the files and unzip them into the [tutorial-dir] directory</p>.</li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from your
<code>sandbox</code> directory.</p></li>
<li><p>You need an http server running on your system and Mac and Linux machines typically
have Apache pre-installed. If you don't have an http server installed, you can <a
href="http://nodejs.org/#download">install node.js</a> and use it to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
<code>java</code> executable is on your <code>PATH</code> by running the following command in the
Windows command line:</p>
<pre>java -version</pre>
<p>You need Java to run unit tests, so download the <a
href="http://code.angularjs.org/angular-phonecat/">zip archive</a> that contains all of the files
and unzip the files into the [tutorial-dir] directory</p></li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from this directory.</p></li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
</divs>
The last thing to do is to make sure your computer has a web browser and a good text editor
installed. Now, let's get some cool stuff done!
+65 -1
View File
@@ -46,7 +46,7 @@ directory.</li>
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
<ol>
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
<pre>git checkout -f step-0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
@@ -74,6 +74,70 @@ directory.</li>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux" value="snapshotUnix">
<ol>
<li><p>In the angular-phonecat directory, run this command:</p>
<pre>./goto_step.sh 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run
<code>./scripts/web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows" value="snapshotWin">
<ol>
<li><p>Open windows command line and run this command (in the angular-phonecat directory):</p>
<pre>goto_step.bat 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node
scripts\web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
</div>
+20 -13
View File
@@ -61,7 +61,7 @@ repeater tells Angular to create a `<li>` element for each phone in the list usi
tag as the template.
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
bindings. As opposed to evaluating constants, these expressions are referring to our application
bindings. As opposed to evaluating constants, these expression are refering to our application
model, which was set up in our `PhoneListCtrl` controller.
<img class="diagram" src="img/tutorial/tutorial_02.png">
@@ -146,25 +146,31 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
The angular-seed project is pre-configured to run all unit tests using {@link
http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the following:
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test.sh` to start the Testacular server.
`./scripts/test-server.sh` to start the test web server.
2. Testacular will start a new instance of Chrome browser automatically. Just ignore it and let it run in
the background. Testacular will use this browser for test execution.
2. Open a new browser window and navigate to {@link http://localhost:9876}.
3. You should see the following or similar output in the terminal:
3. Choose "Capture this browser in strict mode".
info: Testacular server started at http://localhost:9876/
info (launcher): Starting browser "Chrome"
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
At this point, you can leave this window open and forget about it. JsTestDriver will use it to
execute the tests and report the results in the terminal.
4. Execute the test by running `./scripts/test.sh`
You should see the following or similar output:
Chrome: Runner reset.
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
Yay! The test passed! Or not...
4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
and will rerun the tests for you. Now isn't that sweet?
Note: If you see errors after you run the test, close the browser window and go back to the
terminal and kill the script, then repeat the procedure above.
# Experiments
@@ -192,7 +198,8 @@ http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the fol
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
</table>
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
`./scripts/test.sh` script.
# Summary
+1 -6
View File
@@ -54,7 +54,7 @@ __`app/index.html`:__
</div>
</pre>
We added a standard HTML `<input>` tag and used Angular's
We added a standard HTML `<input>` tag and used angular's
{@link api/ng.filter:filter $filter} function to process the input for the
{@link api/ng.directive:ngRepeat ngRepeat} directive.
@@ -122,11 +122,6 @@ To run the end-to-end test, open one of the following in a new browser tab:
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
Previously we've seen how Testacular can be used to execute unit tests. Well, it can also run the
end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests are slow, so unlike
with unit tests, Testacular will exit after the test run and will not automatically rerun the test
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
really is that easy to set up any functional, readable, end-to-end test.
+8 -4
View File
@@ -134,9 +134,13 @@ The unit test now verifies that the default ordering property is set.
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
shared by all tests in the parent `describe` block.
You should now see the following output in the Testacular tab:
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
following output.
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
Let's turn our attention to the end-to-end test.
@@ -164,8 +168,8 @@ __`test/e2e/scenarios.js`:__
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
`runner.html` to see the tests run, or you can see them running on {@link
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
Angular's server}.
+6 -3
View File
@@ -208,10 +208,13 @@ Finally, we verify that the default value of `orderProp` is set correctly:
});
</pre>
You should now see the following output in the Testacular tab:
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
# Experiments
+2 -2
View File
@@ -84,8 +84,8 @@ __`test/e2e/scenarios.js`__:
We added a new end-to-end test to verify that the app is generating correct links to the phone
views that we will implement in the upcoming steps.
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
Angular's server}.
+3 -3
View File
@@ -79,7 +79,7 @@ angular.module('phonecat', []).
</pre>
In order to configure our application with routes, we need to create a module for our application.
We call this module `phonecat` and using the `config` API we request the `$routeProvider` to be
We call this module `phonecatApp` and using the `config` API we request the `$routeProvider` to be
injected into our config function and use `$routeProvider.when` API to define our routes.
Note that during the injector configuration phase, the providers can be injected as well, but they
@@ -232,8 +232,8 @@ to various URLs and verify that the correct view was rendered.
</pre>
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
Angular's server}.
+8 -5
View File
@@ -147,9 +147,13 @@ __`test/unit/controllersSpec.js`:__
...
</pre>
You should now see the following output in the Testacular tab:
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
Chrome: Runner reset.
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
@@ -173,12 +177,11 @@ __`test/e2e/scenarios.js`:__
</pre>
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
Angular's server}.
# Experiments
* Using the {@link guide/dev_guide.e2e-testing Angular's end-to-end test runner API}, write a test
+6 -2
View File
@@ -110,9 +110,13 @@ describe('filter', function() {
Note that you need to configure our test injector with the `phonecatFilters` module before any of
our filter tests execute.
You should now see the following output in the Testacular tab:
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
Chrome: Runner reset.
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
# Experiments
+2 -2
View File
@@ -102,8 +102,8 @@ __`test/e2e/scenarios.js`:__
});
</pre>
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
Angular's server}.
+6 -2
View File
@@ -214,9 +214,13 @@ describe('PhoneCat controllers', function() {
});
</pre>
You should now see the following output in the Testacular tab:
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
Chrome: Runner reset.
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
# Summary
+1 -1
View File
@@ -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` or `goto_step.sh` commands.
For more details and examples of the Angular concepts we touched on in this tutorial, see the
{@link guide/ Developer Guide}.
+3
View File
@@ -82,7 +82,10 @@ function writeTheRest(writesFuture) {
writesFuture.push(writer.output('appcache.manifest',appCache()));
writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
writesFuture.push(writer.symlinkTemplate('app.yaml'));
writesFuture.push(writer.symlinkTemplate('index.yaml'));
writesFuture.push(writer.symlinkTemplate('favicon.ico'));
writesFuture.push(writer.symlinkTemplate('main.py'));
}
-1
View File
@@ -6,7 +6,6 @@
#
# This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version.
Options -Indexes
RewriteEngine on
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
RewriteRule appcache.manifest appcache-offline.manifest
+69
View File
@@ -0,0 +1,69 @@
application: docs-angularjs-org
version: 1
runtime: python27
api_version: 1
threadsafe: yes
default_expiration: "2h"
handlers:
- url: /
script: main.app
- url: /appcache.manifest
static_files: appcache.manifest
upload: appcache\.manifest
- url: /docs-scenario.html
static_files: docs-scenario.html
upload: docs-scenario\.html
- url: /docs-scenario.js
static_files: docs-scenario.js
upload: docs-scenario\.js
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /docs-keywords.js
static_files: docs-keywords.js
upload: docs-keywords\.js
- url: /robots.txt
static_files: robots.txt
upload: robots\.txt
- url: /sitemap.xml
static_files: sitemap.xml
upload: sitemap\.xml
- url: /css
static_dir: css
- url: /font
static_dir: font
- url: /img
static_dir: img
- url: /js
static_dir: js
- url: /partials/(.+):(.+)
static_files: partials/\1_\2
upload: partials/.*
- url: /partials
static_dir: partials
- url: /syntaxhighlighter
static_dir: syntaxhighlighter
- url: /.*
static_files: index.html
upload: index.html
libraries:
- name: webapp2
version: "2.5.1"
+4 -3
View File
@@ -3,7 +3,7 @@
<head>
<title>AngularJS Docs E2E Test Runner</title>
<script>
var production = location.hostname === 'docs.angularjs.org',
var gae = (location.pathname.split('/').length == 2),
headEl = document.head,
angularVersion = {
current: '"NG_VERSION_FULL"', // rewrite during build
@@ -33,8 +33,9 @@
function path(name) {
return production
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
return gae
? 'http://code.angularjs.org/' + angularVersion.stable + '/' +
name.replace(/\.js$/, '-' + angularVersion.stable + '.js')
: '../' + name;
}
</script>
+3 -3
View File
@@ -22,7 +22,7 @@
baseUrl = location.href.replace(rUrl, indexFile),
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
production = location.hostname === 'docs.angularjs.org',
gae = (baseUrl.split('/').length == 4),
headEl = document.getElementsByTagName('head')[0],
sync = true,
angularVersion = {
@@ -45,7 +45,7 @@
addTag('script', {src: 'docs-keywords.js'}, sync);
function path(name) {
if (production) {
if (gae) {
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
angularVersion.stable +
@@ -55,7 +55,7 @@
name = 'http://code.angularjs.org/' +
angularVersion.stable +
'/' +
name.replace(/\.js$/, '.min.js');
name.replace(/\.js$/, '-' + angularVersion.stable +'.min.js');
}
return name;
}
+12
View File
@@ -0,0 +1,12 @@
indexes:
# AUTOGENERATED
# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run. If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED"). If you want to manage some indexes
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.
+8 -57
View File
@@ -30,16 +30,9 @@ docsApp.directive.code = function() {
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
return {
template: '<div class="btn-group pull-right">' +
'<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
' <i class="icon-pencil icon-white"></i> Edit<span class="caret"></span>' +
'</a>' +
'<ul class="dropdown-menu">' +
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
'</ul>',
template: '<button ng-click="fiddle($event)" class="btn btn-primary pull-right"><i class="icon-pencil icon-white"></i> Edit</button>\n',
scope: true,
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
controller: function($scope, $attrs, openJsFiddle) {
var sources = {
module: $attrs.sourceEdit,
deps: read($attrs.sourceEditDeps),
@@ -52,19 +45,14 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
$scope.fiddle = function(e) {
e.stopPropagation();
openJsFiddle(sources);
};
$scope.plunkr = function(e) {
e.stopPropagation();
openPlunkr(sources);
};
}
}
}
function read(text) {
var files = [];
angular.forEach(text ? text.split(' ') : [], function(refId) {
// refId is index.html-343, so we need to strip the unique ID when exporting the name
files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
files.push({name: refId.split('-')[0], content: getEmbeddedTemplate(refId)});
});
return files;
}
@@ -123,6 +111,8 @@ docsApp.directive.docTutorialReset = function() {
'<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' +
tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) +
tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) +
tab('Snapshots on Mac/Linux', './goto_step.sh ' + step, 'snapshotUnix', step) +
tab('Snapshots on on Windows', './goto_step.bat ' + step, 'snapshotWin', step) +
'</div>\n');
}
};
@@ -157,47 +147,8 @@ docsApp.serviceFactory.formPostData = function($document) {
};
};
docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angularUrls) {
return function(content) {
var allFiles = [].concat(content.js, content.css, content.html);
var indexHtmlContent = '<!doctype html>\n' +
'<html ng-app>\n' +
' <head>\n' +
' <script src="{{angularJSUrl}}"></script>\n' +
'{{scriptDeps}}\n' +
' </head>\n' +
' <body>\n\n' +
'{{indexContents}}' +
'\n\n </body>\n' +
'</html>\n';
var scriptDeps = '';
angular.forEach(content.deps, function(file) {
if (file.name !== 'angular.js') {
scriptDeps += ' <script src="' + file.name + '"></script>\n'
}
});
indexProp = {
angularJSUrl: angularUrls['angular.js'],
scriptDeps: scriptDeps,
indexContents: content.html[0].content
};
var postData = {};
angular.forEach(allFiles, function(file, index) {
if (file.content && file.name != 'index.html') {
postData['files[' + file.name + ']'] = file.content;
}
});
postData['files[index.html]'] = templateMerge(indexHtmlContent, indexProp);
postData.description = 'AngularJS Example Plunkr';
formPostData('http://plnkr.co/edit/?p=preview', postData);
};
};
docsApp.serviceFactory.openJsFiddle = function(templateMerge, formPostData, angularUrls) {
docsApp.serviceFactory.openJsFiddle = function(templateMerge, getEmbeddedTemplate, formPostData, angularUrls) {
var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
'{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}',
@@ -346,7 +297,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
tutorial: 'Tutorial',
cookbook: 'Examples'
};
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
$scope.$watch(function() {return $location.path(); }, function(path) {
// ignore non-doc links which are used in examples
if (DOCS_PATH.test(path)) {
var parts = path.split('/'),
+18
View File
@@ -0,0 +1,18 @@
import webapp2
from google.appengine.ext.webapp import template
class IndexHandler(webapp2.RequestHandler):
def get(self):
fragment = self.request.get('_escaped_fragment_')
if fragment:
fragment = '/partials' + fragment + '.html'
self.redirect(fragment, permanent=True)
else:
self.response.headers['Content-Type'] = 'text/html'
self.response.out.write(template.render('index-nocache.html', None))
app = webapp2.WSGIApplication([('/', IndexHandler)])
+3 -2
View File
@@ -1,9 +1,10 @@
#!/usr/bin/env bash
JASMINE_NODE='jasmine-node'
local_jasmine='./node_modules/.bin/jasmine-node'
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
# Locally (npm)-installed jasmine-node
local_jasmine='./node_modules/.bin/jasmine-node'
if [[ -x "$local_jasmine" ]];then
JASMINE_NODE="$local_jasmine"
else
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env node
/* This file reads in list of files from angularFiles.js and generate various jstd config files */
var fs = require('fs'),
angularSrc,
angularScenario;
fs.readFile('angularFiles.js', function(err, data) {
eval(data.toString());
var prefix = 'server: http://localhost:9876\n\n',
prefixScenario = 'server: http://localhost:9877\n\n';
angularSrc = angularFiles.angularSrc.join('\n- ');
angularScenario = angularFiles.angularScenario.join('\n- ');
fs.writeFile('./jsTestDriver.conf', prefix + combine(angularFiles.jstd,
angularFiles.jstdExclude));
fs.writeFile('./jsTestDriver-modules.conf', prefix + combine(angularFiles.jstdModules));
fs.writeFile('./jsTestDriver-scenario.conf', prefixScenario +
combine(angularFiles.jstdScenario) +
'\n\nproxy:\n- {matcher: "*", server: "http://localhost:8000"}');
fs.writeFile('./jsTestDriver-perf.conf', prefix + combine(angularFiles.jstdPerf,
angularFiles.jstdPerfExclude));
fs.writeFile('./jsTestDriver-jquery.conf', prefix + combine(angularFiles.jstdJquery,
angularFiles.jstdJqueryExclude));
fs.writeFile('./jsTestDriver-coverage.conf', prefix +
combine(angularFiles.jstd, angularFiles.jstdExclude) +
'\n\nplugin:\n- name: "coverage"\n' +
'jar: "lib/jstestdriver/coverage.jar"\n' +
'module: "com.google.jstestdriver.coverage.CoverageModule"');
});
function combine(load, exclude) {
var fileList = 'load:\n- ' + load.join('\n- ');
if (exclude) fileList += ('\n\nexclude:\n- ' + exclude.join('\n- '));
//Replace placeholders for src list before returning
return fileList.replace(/@(.*)/g, function(all, alias) {
return angularFiles[alias].join('\n- ');
});
}
-32
View File
@@ -1,32 +0,0 @@
#!/usr/bin/env bash
#
# Script to initialize angular repo
# - install required node packages
# - install Testacular
# - install git hooks
node=`which node 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NodeJS."
echo "http://nodejs.org/"
exit 1
fi
npm=`which npm 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NPM."
fi
echo "Installing required npm packages..."
npm install
testacular=`which testacular 2>&1`
if [ $? -ne 0 ]; then
echo "Installing Testacular..."
npm install -g testacular
fi
echo "Installing git hooks..."
ln -sf ../../validate-commit-msg.js .git/hooks/commit-msg
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java $@
+198
View File
@@ -0,0 +1,198 @@
/**
* @fileoverview Jasmine JsTestDriver Adapter.
* @author misko@hevery.com (Misko Hevery)
*/
(function(window) {
var rootDescribes = new Describes(window);
var describePath = [];
rootDescribes.collectMode();
var JASMINE_TYPE = 'jasmine test case';
TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE);
var jasminePlugin = {
name:'jasmine',
getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) {
for (var i = 0; i < testCaseInfos.length; i++) {
if (testCaseInfos[i].getType() == JASMINE_TYPE) {
testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
}
}
return false;
},
runTestConfiguration: function(testRunConfiguration, onTestDone, onTestRunConfigurationComplete){
if (testRunConfiguration.getTestCaseInfo().getType() != JASMINE_TYPE) return false;
var jasmineEnv = jasmine.currentEnv_ = new jasmine.Env();
rootDescribes.playback();
var specLog = jstestdriver.console.log_ = [];
var start;
jasmineEnv.specFilter = function(spec) {
return rootDescribes.isExclusive(spec);
};
jasmineEnv.reporter = {
log: function(str){
specLog.push(str);
},
reportRunnerStarting: function(runner) { },
reportSpecStarting: function(spec) {
specLog = jstestdriver.console.log_ = [];
start = new Date().getTime();
},
reportSpecResults: function(spec) {
var suite = spec.suite;
var results = spec.results();
if (results.skipped) return;
var end = new Date().getTime();
var messages = [];
var resultItems = results.getItems();
var state = 'passed';
for ( var i = 0; i < resultItems.length; i++) {
if (!resultItems[i].passed()) {
state = resultItems[i].message.match(/AssertionError:/) ? 'error' : 'failed';
messages.push({
message: resultItems[i].toString(),
name: resultItems[i].trace.name,
stack: formatStack(resultItems[i].trace.stack)
});
}
}
onTestDone(
new jstestdriver.TestResult(
suite.getFullName(),
spec.description,
state,
jstestdriver.angular.toJson(messages),
specLog.join('\n'),
end - start));
},
reportSuiteResults: function(suite) {},
reportRunnerResults: function(runner) {
onTestRunConfigurationComplete();
}
};
jasmineEnv.execute();
return true;
},
onTestsFinish: function(){
jasmine.currentEnv_ = null;
rootDescribes.collectMode();
}
};
jstestdriver.pluginRegistrar.register(jasminePlugin);
function formatStack(stack) {
var lines = (stack||'').split(/\r?\n/);
var frames = [];
for (i = 0; i < lines.length; i++) {
if (!lines[i].match(/\/jasmine[\.-]/)) {
frames.push(lines[i].replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, ' '));
}
}
return frames.join('\n');
}
function noop(){}
function Describes(window){
var describes = {};
var beforeEachs = {};
var afterEachs = {};
// Here we store:
// 0: everyone runs
// 1: run everything under ddescribe
// 2: run only iits (ignore ddescribe)
var exclusive = 0;
var collectMode = true;
intercept('describe', describes);
intercept('xdescribe', describes);
intercept('beforeEach', beforeEachs);
intercept('afterEach', afterEachs);
function intercept(functionName, collection){
window[functionName] = function(desc, fn){
if (collectMode) {
collection[desc] = function(){
jasmine.getEnv()[functionName](desc, fn);
};
} else {
jasmine.getEnv()[functionName](desc, fn);
}
};
}
window.ddescribe = function(name, fn){
if (exclusive < 1) {
exclusive = 1; // run ddescribe only
}
window.describe(name, function(){
var oldIt = window.it;
window.it = function(name, fn){
if (fn) fn.exclusive = 1; // run anything under ddescribe
oldIt(name, fn);
};
try {
fn.call(this);
} finally {
window.it = oldIt;
};
});
};
window.iit = function(name, fn){
exclusive = fn.exclusive = 2; // run only iits
jasmine.getEnv().it(name, fn);
};
this.collectMode = function() {
collectMode = true;
exclusive = 0; // run everything
};
this.playback = function(){
collectMode = false;
playback(beforeEachs);
playback(afterEachs);
playback(describes);
function playback(set) {
for ( var name in set) {
set[name]();
}
}
};
this.isExclusive = function(spec) {
if (exclusive) {
var blocks = spec.queue.blocks;
for ( var i = 0; i < blocks.length; i++) {
if (blocks[i].func.exclusive >= exclusive) {
return true;
}
}
return false;
}
return true;
};
}
})(window);
// Patch Jasmine for proper stack traces
jasmine.Spec.prototype.fail = function (e) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception'
});
// PATCH
if (e) {
expectationResult.trace = e;
}
this.results_.addResult(expectationResult);
};
+1
View File
@@ -0,0 +1 @@
da92db714142b49f9cf61db664e782bb0ccad80b
+20
View File
@@ -0,0 +1,20 @@
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+190
View File
@@ -0,0 +1,190 @@
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};
+166
View File
@@ -0,0 +1,166 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

+1
View File
@@ -0,0 +1 @@
1.1.0
Executable
BIN
View File
Binary file not shown.
+130
View File
@@ -0,0 +1,130 @@
#
# Configuration File for JavaScript Lint 0.3.0
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
#
# This configuration file can be used to lint a collection of scripts, or to enable
# or disable warnings for scripts that are linted via the command line.
#
### Warnings
# Enable or disable warnings based on requirements.
# Use "+WarningName" to display or "-WarningName" to suppress.
#
-no_return_value # function {0} does not always return a value
+duplicate_formal # duplicate formal argument {0}
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
+var_hides_arg # variable {0} hides argument
+redeclared_var # redeclaration of {0} {1}
-anon_no_return_value # anonymous function does not always return a value
+missing_semicolon # missing semicolon
+meaningless_block # meaningless block; curly braces have no impact
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
-unreachable_code # unreachable code
-missing_break # missing break statement
+missing_break_for_last_case # missing break statement for last case in switch
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
+useless_void # use of the void type may be unnecessary (void is always undefined)
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
+use_of_label # use of label
-block_without_braces # block statement without curly braces
+leading_decimal_point # leading decimal point may indicate a number or an object member
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
+octal_number # leading zeros make an octal number
+nested_comment # nested comment
-misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
+empty_statement # empty statement or extra semicolon
-missing_option_explicit # the "option explicit" control comment is missing
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
+dup_option_explicit # duplicate "option explicit" control comment
+useless_assign # useless assignment
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
-missing_default_case # missing default case in switch statement
+duplicate_case_in_switch # duplicate case in switch statements
+default_not_at_end # the default case is not at the end of the switch statement
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
+useless_comparison # useless comparison; comparing identical expressions
+with_statement # with statement hides undeclared variables; use temporary variable instead
+trailing_comma_in_array # extra comma is not recommended in array initializers
+assign_to_function_call # assignment to a function call
+parseint_missing_radix # parseInt missing radix parameter
### Output format
# Customize the format of the error message.
# __FILE__ indicates current file path
# __FILENAME__ indicates current file name
# __LINE__ indicates current line
# __ERROR__ indicates error message
#
# Visual Studio syntax (default):
+output-format __FILE__(__LINE__): __ERROR__
# Alternative syntax:
#+output-format __FILE__:__LINE__: __ERROR__
### Context
# Show the in-line position of the error.
# Use "+context" to display or "-context" to suppress.
#
+context
### Semicolons
# By default, assignments of an anonymous function to a variable or
# property (such as a function prototype) must be followed by a semicolon.
#
+lambda_assign_requires_semicolon
### Control Comments
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
# although legacy control comments are enabled by default for backward compatibility.
#
+legacy_control_comments
### JScript Function Extensions
# JScript allows member functions to be defined like this:
# function MyObj() { /*constructor*/ }
# function MyObj.prototype.go() { /*member function*/ }
#
# It also allows events to be attached like this:
# function window::onload() { /*init page*/ }
#
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
#
-jscript_function_extensions
### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
-always_use_option_explicit
# Define certain identifiers of which the lint is not aware.
# (Use this in conjunction with the "undeclared identifier" warning.)
#
# Common uses for webpages might be:
#+define window
#+define document
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
+process src/*.js
+process src/service/*.js
+process src/scenario/*.js
+process test/*.js
+process test/service/*.js
+process test/scenario/*.js
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
1.3.3d
Executable
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
./gen_docs.sh
rm build/docs/index.html
rm -rf build/docs/css
rm -rf build/docs/js
rm -rf build/docs/img
rm -rf build/docs/examples
cd build/docs
ln -s ../../docs/src/templates/index.html
ln -s ../../docs/src/templates/css
ln -s ../../docs/src/templates/js
ln -s ../../docs/img
ln -s ../../docs/examples
-1
View File
@@ -2,7 +2,6 @@
"name": "AngularJS",
"version": "0.0.0",
"dependencies" : {
"testacular" : "canary",
"jasmine-node" : "*",
"q-fs" : "*",
"qq" : "*"
+18
View File
@@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.angularjs</groupId>
<artifactId>AngularJS</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>AngularJS</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
</build>
</project>
+1
View File
@@ -0,0 +1 @@
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 20000 --config jsTestDriver-coverage.conf
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
java -jar lib/jstestdriver/JsTestDriver.jar --port 9877 --browserTimeout 90000 --config jsTestDriver-scenario.conf
Executable
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
node gen_jstd_configs.js
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 90000
+2 -2
View File
@@ -788,7 +788,7 @@ function toKeyValue(obj) {
/**
* We need our custom method because encodeURIComponent is too agressive and doesn't follow
* We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
* segments:
* segment = *pchar
@@ -832,7 +832,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @name ng.directive:ngApp
*
* @element ANY
* @param {angular.Module} ngApp an optional application
* @param {angular.Module} ngApp on optional application
* {@link angular.module module} name to load.
*
* @description
-10
View File
@@ -97,15 +97,5 @@ HashQueueMap.prototype = {
return array.shift();
}
}
},
/**
* return the first item without deleting it
*/
peek: function(key) {
var array = this[hashKey(key)];
if (array) {
return array[0];
}
}
};
+7 -8
View File
@@ -20,7 +20,7 @@
* // create an injector
* var $injector = angular.injector(['ng']);
*
* // use the injector to kick off your application
* // use the injector to kick of your application
* // use the type inference to auto inject arguments, or use implicit injection
* $injector.invoke(function($rootScope, $compile, $document){
* $compile($document)($rootScope);
@@ -40,7 +40,7 @@
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function annotate(fn) {
var $inject,
@@ -410,9 +410,10 @@ function createInjector(modulesToLoad) {
decorator: decorator
}
},
providerInjector = createInternalInjector(providerCache, function() {
throw Error("Unknown provider: " + path.join(' <- '));
}),
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() {
throw Error("Unknown provider: " + path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) {
@@ -489,9 +490,7 @@ function createInjector(modulesToLoad) {
try {
for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i],
provider = invokeArgs[0] == '$injector'
? providerInjector
: providerInjector.get(invokeArgs[0]);
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
+1 -1
View File
@@ -210,7 +210,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
}, $delegate);
}]);
$provide.decorator('$rootScope', ['$delegate', function(embedRootScope) {
docsRootScope.$watch(function embedRootScopeDigestWatch() {
docsRootScope.$watch(function() {
embedRootScope.$digest();
});
return embedRootScope;
+1 -1
View File
@@ -9,7 +9,7 @@ directive.dropdownToggle =
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
scope.$watch(function(){return $location.path();}, function() {
close && close();
});
+13 -17
View File
@@ -54,7 +54,6 @@
* - [replaceWith()](http://api.jquery.com/replaceWith/)
* - [text()](http://api.jquery.com/text/)
* - [toggleClass()](http://api.jquery.com/toggleClass/)
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
* - [unbind()](http://api.jquery.com/unbind/)
* - [val()](http://api.jquery.com/val/)
* - [wrap()](http://api.jquery.com/wrap/)
@@ -130,7 +129,12 @@ function JQLitePatchJQueryRemove(name, dispatchThis) {
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
element = jqLite(set[setIndex]);
if (fireEvent) {
element.triggerHandler('$destroy');
events = element.data('events');
if ( (fns = events && events.$destroy) ) {
forEach(fns, function(fn){
fn.handler();
});
}
} else {
fireEvent = !fireEvent;
}
@@ -262,9 +266,9 @@ function JQLiteHasClass(element, selector) {
indexOf( " " + selector + " " ) > -1);
}
function JQLiteRemoveClass(element, cssClasses) {
if (cssClasses) {
forEach(cssClasses.split(' '), function(cssClass) {
function JQLiteRemoveClass(element, selector) {
if (selector) {
forEach(selector.split(' '), function(cssClass) {
element.className = trim(
(" " + element.className + " ")
.replace(/[\n\t]/g, " ")
@@ -274,9 +278,9 @@ function JQLiteRemoveClass(element, cssClasses) {
}
}
function JQLiteAddClass(element, cssClasses) {
if (cssClasses) {
forEach(cssClasses.split(' '), function(cssClass) {
function JQLiteAddClass(element, selector) {
if (selector) {
forEach(selector.split(' '), function(cssClass) {
if (!JQLiteHasClass(element, cssClass)) {
element.className = trim(element.className + ' ' + trim(cssClass));
}
@@ -724,15 +728,7 @@ forEach({
return element.getElementsByTagName(selector);
},
clone: JQLiteClone,
triggerHandler: function(element, eventName) {
var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
forEach(eventFns, function(fn) {
fn.call(element, null);
});
}
clone: JQLiteClone
}, function(fn, name){
/**
* chaining functions
+4 -4
View File
@@ -30,7 +30,7 @@ function setupModuleLoader(window) {
*
* # Module
*
* A module is a collocation of services, directives, filters, and configuration information. Module
* A module is a collocation of services, directives, filters, and configure information. Module
* is used to configure the {@link AUTO.$injector $injector}.
*
* <pre>
@@ -60,7 +60,7 @@ function setupModuleLoader(window) {
* @param {!string} name The name of the module to create or retrieve.
* @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
* the module is being retrieved for further configuration.
* @param {Function} configFn Optional configuration function for the module. Same as
* @param {Function} configFn Option configuration function for the module. Same as
* {@link angular.Module#config Module#config()}.
* @returns {module} new module with the {@link angular.Module} api.
*/
@@ -215,8 +215,8 @@ function setupModuleLoader(window) {
* @param {Function} initializationFn Execute this function after injector creation.
* Useful for application initialization.
* @description
* Use this method to register work which should be performed when the injector is done
* loading all modules.
* Use this method to register work which needs to be performed when the injector with
* with the current module is finished loading.
*/
run: function(block) {
runBlocks.push(block);
+3 -4
View File
@@ -55,10 +55,9 @@ 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
if (autoScrollingEnabled) {
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
function autoScrollWatchAction() {
$rootScope.$evalAsync(scroll);
});
$rootScope.$watch(function() {return $location.hash();}, function() {
$rootScope.$evalAsync(scroll);
});
}
return scroll;
+4 -6
View File
@@ -15,10 +15,10 @@
*
* - `{object}` `info()` — Returns id, size, and options of cache.
* - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
* - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
* - `{void}` `removeAll()` — Removes all cached values.
* - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
* - `{{*}} `get({string} key) — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key) — Removes a key-value pair from the cache.
* - `{void}` `removeAll() — Removes all cached values.
* - `{void}` `destroy() — Removes references to this cache from $cacheFactory.
*
*/
function $CacheFactoryProvider() {
@@ -70,8 +70,6 @@ function $CacheFactoryProvider() {
remove: function(key) {
var lruEntry = lruHash[key];
if (!lruEntry) return;
if (lruEntry == freshEnd) freshEnd = lruEntry.p;
if (lruEntry == staleEnd) staleEnd = lruEntry.n;
link(lruEntry.n,lruEntry.p);
+30 -31
View File
@@ -310,26 +310,26 @@ function $CompileProvider($provide) {
//================================
function compile($compileNodes, transcludeFn, maxPriority) {
if (!($compileNodes instanceof jqLite)) {
function compile($compileNode, transcludeFn, maxPriority) {
if (!($compileNode instanceof jqLite)) {
// jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
$compileNodes = jqLite($compileNodes);
$compileNode = jqLite($compileNode);
}
// 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){
forEach($compileNode, function(node, index){
if (node.nodeType == 3 /* text node */) {
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
$compileNode[index] = jqLite(node).wrap('<span></span>').parent()[0];
}
});
var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
return function publicLinkFn(scope, cloneConnectFn){
var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
return function(scope, cloneConnectFn){
assertArg(scope, 'scope');
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
var $linkNode = cloneConnectFn
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
: $compileNodes;
? JQLitePrototype.clone.call($compileNode) // IMPORTANT!!!
: $compileNode;
$linkNode.data('$scope', scope);
safeAddClass($linkNode, 'ng-scope');
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
@@ -380,7 +380,7 @@ function $CompileProvider($provide) {
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
: null;
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal)
? null
: compileNodes(nodeList[i].childNodes,
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
@@ -432,14 +432,13 @@ function $CompileProvider($provide) {
/**
* Looks for directives on the given node and adds them to the directive collection which is
* sorted.
* Looks for directives on the given node ands them to the directive collection which is sorted.
*
* @param node Node to search.
* @param directives An array to which the directives are added to. This array is sorted before
* @param node node to search
* @param directives an array to which the directives are added to. This array is sorted before
* the function returns.
* @param attrs The shared attrs object which is used to populate the normalized attributes.
* @param {number=} maxPriority Max directive priority.
* @param attrs the shared attrs object which is used to populate the normalized attributes.
* @param {number=} max directive priority
*/
function collectDirectives(node, directives, attrs, maxPriority) {
var nodeType = node.nodeType,
@@ -474,7 +473,7 @@ function $CompileProvider($provide) {
// use class as directive
className = node.className;
if (isString(className) && className !== '') {
if (isString(className)) {
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
nName = directiveNormalize(match[2]);
if (addDirective(directives, nName, 'C', maxPriority)) {
@@ -528,7 +527,7 @@ function $CompileProvider($provide) {
preLinkFns = [],
postLinkFns = [],
newScopeDirective = null,
newIsolateScopeDirective = null,
newIsolatedScopeDirective = null,
templateDirective = null,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
@@ -550,10 +549,10 @@ function $CompileProvider($provide) {
}
if (directiveValue = directive.scope) {
assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, $compileNode);
if (isObject(directiveValue)) {
safeAddClass($compileNode, 'ng-isolate-scope');
newIsolateScopeDirective = directive;
newIsolatedScopeDirective = directive;
}
safeAddClass($compileNode, 'ng-scope');
newScopeDirective = newScopeDirective || directive;
@@ -707,12 +706,12 @@ function $CompileProvider($provide) {
}
$element = attrs.$$element;
if (newIsolateScopeDirective) {
if (newScopeDirective && isObject(newScopeDirective.scope)) {
var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
var parentScope = scope.$parent || scope;
forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
forEach(newScopeDirective.scope, function(definiton, scopeName) {
var match = definiton.match(LOCAL_REGEXP) || [],
attrName = match[2]|| scopeName,
mode = match[1], // @, =, or &
@@ -735,10 +734,10 @@ function $CompileProvider($provide) {
// reset the change, or we will throw this exception on every $digest
lastValue = scope[scopeName] = parentGet(parentScope);
throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
' (directive: ' + newIsolateScopeDirective.name + ')');
' (directive: ' + newScopeDirective.name + ')');
};
lastValue = scope[scopeName] = parentGet(parentScope);
scope.$watch(function parentValueWatch() {
scope.$watch(function() {
var parentValue = parentGet(parentScope);
if (parentValue !== scope[scopeName]) {
@@ -748,7 +747,7 @@ function $CompileProvider($provide) {
lastValue = scope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
parentSet(parentScope, lastValue = scope[scopeName]);
}
}
return parentValue;
@@ -766,7 +765,7 @@ function $CompileProvider($provide) {
default: {
throw Error('Invalid isolate scope definition for directive ' +
newIsolateScopeDirective.name + ': ' + definiton);
newScopeDirective.name + ': ' + definiton);
}
}
});
@@ -900,7 +899,7 @@ function $CompileProvider($provide) {
origAsyncDirective = directives.shift(),
// The fact that we have to copy and patch the directive seems wrong!
derivedSyncDirective = extend({}, origAsyncDirective, {
controller: null, templateUrl: null, transclude: null, scope: null
controller: null, templateUrl: null, transclude: null
});
$compileNode.html('');
@@ -992,12 +991,12 @@ function $CompileProvider($provide) {
if (interpolateFn) {
directives.push({
priority: 0,
compile: valueFn(function textInterpolateLinkFn(scope, node) {
compile: valueFn(function(scope, node) {
var parent = node.parent(),
bindings = parent.data('$binding') || [];
bindings.push(interpolateFn);
safeAddClass(parent.data('$binding', bindings), 'ng-binding');
scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
scope.$watch(interpolateFn, function(value) {
node[0].nodeValue = value;
});
})
@@ -1015,7 +1014,7 @@ function $CompileProvider($provide) {
directives.push({
priority: 100,
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
compile: valueFn(function(scope, element, attr) {
var $$observers = (attr.$$observers || (attr.$$observers = {}));
if (name === 'class') {
@@ -1027,7 +1026,7 @@ function $CompileProvider($provide) {
attr[name] = undefined;
($$observers[name] || ($$observers[name] = [])).$$inter = true;
(attr.$$observers && attr.$$observers[name].$$scope || scope).
$watch(interpolateFn, function interpolateFnWatchAction(value) {
$watch(interpolateFn, function(value) {
attr.$set(name, value);
});
})
-1
View File
@@ -27,7 +27,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
}
});
}
+1 -4
View File
@@ -284,7 +284,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
priority: 100,
compile: function() {
return function(scope, element, attr) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
scope.$watch(attr[normalized], function(value) {
attr.$set(attrName, !!value);
});
};
@@ -302,9 +302,6 @@ forEach(['src', 'href'], function(attrName) {
priority: 99, // it needs to run after the attributes are interpolated
link: function(scope, element, attr) {
attr.$observe(normalized, function(value) {
if (!value)
return;
attr.$set(attrName, value);
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
-1
View File
@@ -117,7 +117,6 @@ function FormController(element, attrs) {
element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
form.$dirty = true;
form.$pristine = false;
parentForm.$setDirty();
};
}
+15 -34
View File
@@ -15,10 +15,7 @@ var inputType = {
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Adds `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -88,9 +85,6 @@ var inputType = {
* @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
* @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -157,9 +151,6 @@ var inputType = {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -225,9 +216,6 @@ var inputType = {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -650,9 +638,6 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -677,7 +662,6 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {boolean=} ngRequired Sets `required` attribute if set to true
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -1011,25 +995,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// model -> value
var ctrl = this;
$scope.$watch(ngModelGet, function(value) {
$scope.$watch(function ngModelWatch() {
var value = ngModelGet($scope);
// ignore change from view
if (ctrl.$modelValue === value) return;
// if scope model value and ngModel value are out of sync
if (ctrl.$modelValue !== value) {
var formatters = ctrl.$formatters,
idx = formatters.length;
var formatters = ctrl.$formatters,
idx = formatters.length;
ctrl.$modelValue = value;
while(idx--) {
value = formatters[idx](value);
}
ctrl.$modelValue = value;
while(idx--) {
value = formatters[idx](value);
}
if (ctrl.$viewValue !== value) {
ctrl.$viewValue = value;
ctrl.$render();
}
if (ctrl.$viewValue !== value) {
ctrl.$viewValue = value;
ctrl.$render();
}
});
}];
@@ -1178,7 +1159,7 @@ var requiredDirective = function() {
* @name ng.directive:ngList
*
* @description
* Text input that converts between comma-separated string into an array of strings.
* Text input that converts between comma-seperated string into an array of strings.
*
* @element input
* @param {string=} ngList optional delimiter that should be used to split the value. If
@@ -1261,7 +1242,7 @@ var ngValueDirective = function() {
};
} else {
return function(scope, elm, attr) {
scope.$watch(attr.ngValue, function valueWatchAction(value) {
scope.$watch(attr.ngValue, function(value) {
attr.$set('value', value, false);
});
};
+2 -2
View File
@@ -49,7 +49,7 @@
*/
var ngBindDirective = ngDirective(function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBind);
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
scope.$watch(attr.ngBind, function(value) {
element.text(value == undefined ? '' : value);
});
});
@@ -132,7 +132,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
var ngBindHtmlUnsafeDirective = [function() {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
element.html(value || '');
});
};
+9 -47
View File
@@ -3,55 +3,17 @@
function classDirective(name, selector) {
name = 'ngClass' + name;
return ngDirective(function(scope, element, attr) {
scope.$watch(attr[name], ngClassWatchAction, true);
attr.$observe('class', function(value) {
var ngClass = scope.$eval(attr[name]);
ngClassWatchAction(ngClass, ngClass);
});
if (name !== 'ngClass') {
scope.$watch('$index', function($index, old$index) {
var mod = $index % 2;
if (mod !== old$index % 2) {
if (mod == selector) {
addClass(scope.$eval(attr[name]));
} else {
removeClass(scope.$eval(attr[name]));
}
}
});
}
function ngClassWatchAction(newVal, oldVal) {
scope.$watch(attr[name], function(newVal, oldVal) {
if (selector === true || scope.$index % 2 === selector) {
if (oldVal && (newVal !== oldVal)) {
removeClass(oldVal);
}
addClass(newVal);
}
}
function removeClass(classVal) {
if (isObject(classVal) && !isArray(classVal)) {
classVal = map(classVal, function(v, k) { if (v) return k });
}
element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
}
function addClass(classVal) {
if (isObject(classVal) && !isArray(classVal)) {
classVal = map(classVal, function(v, k) { if (v) return k });
}
if (classVal) {
element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
}
}
if (isObject(oldVal) && !isArray(oldVal))
oldVal = map(oldVal, function(v, k) { if (v) return k });
element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
}
if (isObject(newVal) && !isArray(newVal))
newVal = map(newVal, function(v, k) { if (v) return k });
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
}, true);
});
}
+1 -1
View File
@@ -101,7 +101,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
element.html('');
};
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
scope.$watch(srcExp, function(src) {
var thisChangeId = ++changeCounter;
if (src) {
+2 -2
View File
@@ -188,7 +188,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
offset + endSymbol));
});
scope.$watch(function ngPluralizeWatch() {
scope.$watch(function() {
var value = parseFloat(scope.$eval(numberExp));
if (!isNaN(value)) {
@@ -199,7 +199,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
} else {
return '';
}
}, function ngPluralizeWatchAction(newVal) {
}, function(newVal) {
element.text(newVal);
});
}
+1 -4
View File
@@ -88,8 +88,7 @@ var ngRepeatDirective = ngDirective({
// We need an array of these objects since the same object can be returned from the iterator.
// We expect this to be a rare case.
var lastOrder = new HashQueueMap();
scope.$watch(function ngRepeatWatch(scope){
scope.$watch(function(scope){
var index, length,
collection = scope.$eval(rhs),
collectionLength = size(collection, true),
@@ -118,9 +117,7 @@ var ngRepeatDirective = ngDirective({
for (index = 0, length = array.length; index < length; index++) {
key = (collection === array) ? index : array[index];
value = collection[key];
last = lastOrder.shift(value);
if (last) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
+5 -5
View File
@@ -34,7 +34,7 @@
*/
//TODO(misko): refactor to remove element from the DOM
var ngShowDirective = ngDirective(function(scope, element, attr){
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
scope.$watch(attr.ngShow, function(value){
element.css('display', toBoolean(value) ? '' : 'none');
});
});
@@ -45,11 +45,11 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
* @name ng.directive:ngHide
*
* @description
* The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML)
* conditionally.
* The `ngHide` and `ngShow` directives hide or show a portion
* of the HTML conditionally.
*
* @element ANY
* @param {expression} ngHide If the {@link guide/expression expression} is truthy then
* @param {expression} ngHide If the {@link guide/expression expression} truthy then
* the element is shown or hidden respectively.
*
* @example
@@ -74,7 +74,7 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
*/
//TODO(misko): refactor to remove element from the DOM
var ngHideDirective = ngDirective(function(scope, element, attr){
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
scope.$watch(attr.ngHide, function(value){
element.css('display', toBoolean(value) ? 'none' : '');
});
});
+1 -1
View File
@@ -38,7 +38,7 @@
</example>
*/
var ngStyleDirective = ngDirective(function(scope, element, attr) {
scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
if (oldStyles && (newStyles !== oldStyles)) {
forEach(oldStyles, function(val, style) { element.css(style, '');});
}
+1 -1
View File
@@ -72,7 +72,7 @@ var ngSwitchDirective = valueFn({
selectedElement,
selectedScope;
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
scope.$watch(watchExpr, function(value) {
if (selectedElement) {
selectedScope.$destroy();
selectedElement.remove();
+4 -10
View File
@@ -29,9 +29,6 @@
*
* @param {string} name assignable expression to data-bind to.
* @param {string=} required The control is considered valid only if value is entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {comprehension_expression=} ngOptions in one of the following forms:
*
* * for array data sources:
@@ -272,7 +269,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// we have to do it on each watch since ngModel watches reference, but
// we need to work of an array, so we need to see if anything was inserted/removed
scope.$watch(function selectMultipleWatch() {
scope.$watch(function() {
if (!equals(lastView, ctrl.$viewValue)) {
lastView = copy(ctrl.$viewValue);
ctrl.$render();
@@ -389,8 +386,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
selected,
selectedSet = false, // nothing is selected yet
lastElement,
element,
label;
element;
if (multiple) {
selectedSet = new HashMap(modelValue);
@@ -414,11 +410,9 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
selected = modelValue === valueFn(scope, locals);
selectedSet = selectedSet || selected; // see if at least one item is selected
}
label = displayFn(scope, locals); // what will be seen by the user
label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
optionGroup.push({
id: keyName ? keys[index] : index, // either the index into array or key from object
label: label,
label: displayFn(scope, locals) || '', // what will be seen by the user
selected: selected // determine if we should be selected
});
}
@@ -550,7 +544,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
}
if (interpolateFn) {
scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
scope.$watch(interpolateFn, function(newVal, oldVal) {
attr.$set('value', newVal);
if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
selectCtrl.addOption(newVal);
+3 -12
View File
@@ -117,18 +117,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
formatedText = '',
parts = [];
var hasExponent = false;
if (numStr.indexOf('e') !== -1) {
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
if (match && match[2] == '-' && match[3] > fractionSize + 1) {
numStr = '0';
} else {
formatedText = numStr;
hasExponent = true;
}
}
if (!hasExponent) {
formatedText = numStr;
} else {
var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
// determine fractionSize if it is not specified
@@ -329,7 +320,7 @@ dateFilter.$inject = ['$locale'];
function dateFilter($locale) {
var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
function jsonStringToDate(string){
var match;
if (match = string.match(R_ISO8601_STR)) {
+3 -1
View File
@@ -381,6 +381,8 @@ function $HttpProvider() {
* - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
* XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
* requests with credentials} for more information.
* - **responseType** - `{string}` - see {@link
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
*
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
* standard `then` method and two http specific methods: `success` and `error`. The `then`
@@ -697,7 +699,7 @@ function $HttpProvider() {
// if we won't have the response in cache, send the request to the backend
if (!cachedResp) {
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
config.withCredentials);
config.withCredentials, config.responseType);
}
return promise;
+7 -3
View File
@@ -32,7 +32,7 @@ function $HttpBackendProvider() {
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
// TODO(vojta): fix the signature
return function(method, url, post, callback, headers, timeout, withCredentials) {
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
@@ -65,8 +65,8 @@ 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());
completeRequest(callback, status || xhr.status, xhr.response || xhr.responseText,
xhr.getAllResponseHeaders());
}
};
@@ -74,6 +74,10 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
xhr.withCredentials = true;
}
if (responseType) {
xhr.responseType = responseType;
}
xhr.send(post || '');
if (timeout > 0) {
+16 -10
View File
@@ -52,7 +52,7 @@ function $InterpolateProvider() {
};
this.$get = ['$parse', function($parse) {
this.$get = ['$parse', '$exceptionHandler', function($parse, $exceptionHandler) {
var startSymbolLength = startSymbol.length,
endSymbolLength = endSymbol.length;
@@ -124,18 +124,24 @@ function $InterpolateProvider() {
if (!mustHaveExpression || hasInterpolation) {
concat.length = length;
fn = function(context) {
for(var i = 0, ii = length, part; i<ii; i++) {
if (typeof (part = parts[i]) == 'function') {
part = part(context);
if (part == null || part == undefined) {
part = '';
} else if (typeof part != 'string') {
part = toJson(part);
try {
for(var i = 0, ii = length, part; i<ii; i++) {
if (typeof (part = parts[i]) == 'function') {
part = part(context);
if (part == null || part == undefined) {
part = '';
} else if (typeof part != 'string') {
part = toJson(part);
}
}
concat[i] = part;
}
concat[i] = part;
return concat.join('');
}
catch(err) {
var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString());
$exceptionHandler(newErr);
}
return concat.join('');
};
fn.exp = text;
fn.parts = parts;
+2 -3
View File
@@ -590,7 +590,6 @@ function $LocationProvider(){
var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var currentReplace = $location.$$replace;
if (!changeCounter || oldUrl != $location.absUrl()) {
changeCounter++;
@@ -599,12 +598,12 @@ function $LocationProvider(){
defaultPrevented) {
$location.$$parse(oldUrl);
} else {
$browser.url($location.absUrl(), currentReplace);
$browser.url($location.absUrl(), $location.$$replace);
$location.$$replace = false;
afterLocationChange(oldUrl);
}
});
}
$location.$$replace = false;
return changeCounter;
});
+1 -9
View File
@@ -5,15 +5,7 @@ var OPERATORS = {
'true':function(){return true;},
'false':function(){return false;},
undefined:noop,
'+':function(self, locals, a,b){
a=a(self, locals); b=b(self, locals);
if (isDefined(a)) {
if (isDefined(b)) {
return a + b;
}
return a;
}
return isDefined(b)?b:undefined;},
'+':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
'-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
'*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
'/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
+1 -1
View File
@@ -42,7 +42,7 @@
* alert('Success: ' + greeting);
* }, function(reason) {
* alert('Failed: ' + reason);
* });
* );
* </pre>
*
* At first it might not be obvious why this extra complexity is worth the trouble. The payoff
+23 -46
View File
@@ -165,9 +165,9 @@ function $RootScopeProvider(){
* the scope and its child scopes to be permanently detached from the parent and thus stop
* participating in model change detection and listener notification by invoking.
*
* @param {boolean} isolate if true then the scope does not prototypically inherit from the
* parent scope. The scope is isolated, as it can not see parent scope properties.
* When creating widgets it is useful for the widget to not accidentally read parent
* @param {boolean} isolate if true then the scoped does not prototypically inherit from the
* parent scope. The scope is isolated, as it can not se parent scope properties.
* When creating widgets it is useful for the widget to not accidently read parent
* state.
*
* @returns {Object} The newly created child scope.
@@ -221,18 +221,18 @@ function $RootScopeProvider(){
* reruns when it detects changes the `watchExpression` can execute multiple times per
* {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
* - The `listener` is called only when the value from the current `watchExpression` and the
* previous call to `watchExpression` are not equal (with the exception of the initial run,
* previous call to `watchExpression' are not equal (with the exception of the initial run
* see below). The inequality is determined according to
* {@link angular.equals} function. To save the value of the object for later comparison, the
* {@link angular.equals} function. To save the value of the object for later comparison
* {@link angular.copy} function is used. It also means that watching complex options will
* have adverse memory and performance implications.
* - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
* is achieved by rerunning the watchers until no changes are detected. The rerun iteration
* limit is 10 to prevent an infinite loop deadlock.
* limit is 100 to prevent infinity loop deadlock.
*
*
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
* you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
* can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
* detected, be prepared for multiple calls to your listener.)
*
@@ -278,7 +278,7 @@ function $RootScopeProvider(){
* - `string`: Evaluated as {@link guide/expression expression}
* - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
*
* @param {boolean=} objectEquality Compare object for equality rather than for reference.
* @param {boolean=} objectEquality Compare object for equality rather then for refference.
* @returns {function()} Returns a deregistration function for this listener.
*/
$watch: function(watchExp, listener, objectEquality) {
@@ -453,7 +453,7 @@ function $RootScopeProvider(){
* @function
*
* @description
* Removes the current scope (and all of its children) from the parent scope. Removal implies
* Remove the current scope (and all of its children) from the parent scope. Removal implies
* that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
* propagate to the current scope and its children. Removal also implies that the current
* scope is eligible for garbage collection.
@@ -476,11 +476,6 @@ function $RootScopeProvider(){
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
// This is bogus code that works around Chrome's GC leak
// see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
this.$$childTail = null;
},
/**
@@ -491,7 +486,7 @@ function $RootScopeProvider(){
*
* @description
* Executes the `expression` on the current scope returning the result. Any exceptions in the
* expression are propagated (uncaught). This is useful when evaluating Angular expressions.
* expression are propagated (uncaught). This is useful when evaluating engular expressions.
*
* # Example
* <pre>
@@ -612,7 +607,7 @@ function $RootScopeProvider(){
* @function
*
* @description
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
* Listen on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
* event life cycle.
*
* @param {string} name Event name to listen on.
@@ -622,13 +617,13 @@ function $RootScopeProvider(){
* The event listener function format is: `function(event, args...)`. The `event` object
* passed into the listener has the following attributes:
*
* - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
* - `currentScope` - `{Scope}`: the current scope which is handling the event.
* - `name` - `{string}`: Name of the event.
* - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
* propagation (available only for events that were `$emit`-ed).
* - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
* - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
* - `currentScope` - {Scope}: the current scope which is handling the event.
* - `name` - {string}: Name of the event.
* - `stopPropagation` - {function=}: calling `stopPropagation` function will cancel further event propagation
* (available only for events that were `$emit`-ed).
* - `preventDefault` - {function}: calling `preventDefault` sets `defaultPrevented` flag to true.
* - `defaultPrevented` - {boolean}: true if `preventDefault` was called.
*/
$on: function(name, listener) {
var namedListeners = this.$$listeners[name];
@@ -638,7 +633,7 @@ function $RootScopeProvider(){
namedListeners.push(listener);
return function() {
namedListeners[indexOf(namedListeners, listener)] = null;
arrayRemove(namedListeners, listener);
};
},
@@ -686,14 +681,6 @@ function $RootScopeProvider(){
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
for (i=0, length=namedListeners.length; i<length; i++) {
// if listeners were deregistered, defragment the array
if (!namedListeners[i]) {
namedListeners.splice(i, 1);
i--;
length--;
continue;
}
try {
namedListeners[i].apply(null, listenerArgs);
if (stopPropagation) return event;
@@ -743,29 +730,19 @@ function $RootScopeProvider(){
},
defaultPrevented: false
},
listenerArgs = concat([event], arguments, 1),
listeners, i, length;
listenerArgs = concat([event], arguments, 1);
//down while you can, then up and next sibling or up and next sibling until back at root
do {
current = next;
event.currentScope = current;
listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) {
// if listeners were deregistered, defragment the array
if (!listeners[i]) {
listeners.splice(i, 1);
i--;
length--;
continue;
}
forEach(current.$$listeners[name], function(listener) {
try {
listeners[i].apply(null, listenerArgs);
listener.apply(null, listenerArgs);
} catch(e) {
$exceptionHandler(e);
}
}
});
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
+3 -3
View File
@@ -28,7 +28,7 @@ function $RouteProvider(){
* Object properties:
*
* - `controller` `{(string|function()=}` Controller fn that should be associated with newly
* created scope or the name of a {@link angular.Module#controller registered controller}
* created scope or the name of a {@link angular.Module#controller registered controller}
* if passed as a string.
* - `template` `{string=}` html template as a string that should be used by
* {@link ng.directive:ngView ngView} or
@@ -39,7 +39,7 @@ function $RouteProvider(){
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
* be injected into the controller. If any of these dependencies are promises, they will be
* resolved and converted to a value before the controller is instantiated and the
* `$routeChangeSuccess` event is fired. The map object is:
* `$afterRouteChange` event is fired. The map object is:
*
* - `key` `{string}`: a name of a dependency to be injected into the controller.
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
@@ -373,7 +373,7 @@ function $RouteProvider(){
forEach(next.resolve || {}, function(value, key) {
keys.push(key);
values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
values.push(isFunction(value) ? $injector.invoke(value) : $injector.get(value));
});
if (isDefined(template = next.template)) {
} else if (isDefined(template = next.templateUrl)) {
+7 -6
View File
@@ -5,6 +5,7 @@
*
* @name ng.$sniffer
* @requires $window
* @requires $document
*
* @property {boolean} history Does the browser support html5 history api ?
* @property {boolean} hashchange Does the browser support hashchange event ?
@@ -13,9 +14,10 @@
* This is very simple implementation of testing browser's features.
*/
function $SnifferProvider() {
this.$get = ['$window', function($window) {
this.$get = ['$window', '$document', function($window, $document) {
var eventSupport = {},
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]),
document = $document[0];
return {
// Android has history.pushState, but it does not update location correctly
@@ -25,7 +27,7 @@ function $SnifferProvider() {
history: !!($window.history && $window.history.pushState && !(android < 4)),
hashchange: 'onhashchange' in $window &&
// IE8 compatible mode lies
(!$window.document.documentMode || $window.document.documentMode > 7),
(!document.documentMode || document.documentMode > 7),
hasEvent: function(event) {
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
// it. In particular the event is not fired when backspace or delete key are pressed or
@@ -33,14 +35,13 @@ function $SnifferProvider() {
if (event == 'input' && msie == 9) return false;
if (isUndefined(eventSupport[event])) {
var divElm = $window.document.createElement('div');
var divElm = document.createElement('div');
eventSupport[event] = 'on' + event in divElm;
}
return eventSupport[event];
},
// TODO(i): currently there is no way to feature detect CSP without triggering alerts
csp: false
csp: document.SecurityPolicy ? document.SecurityPolicy.isActive() : false
};
}];
}
+1 -1
View File
@@ -29,7 +29,7 @@ function $TimeoutProvider() {
* @param {number=} [delay=0] Delay in milliseconds.
* @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
* @returns {*} Promise that will be resolved when the timeout is reached. The value this
* promise will be resolved with is the return value of the `fn` function.
*/
function timeout(fn, delay, invokeApply) {
+6 -13
View File
@@ -225,7 +225,7 @@ angular.module('ngResource', ['ng']).
};
/**
* We need our custom mehtod because encodeURIComponent is too aggressive and doesn't follow
* We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
* segments:
* segment = *pchar
@@ -279,18 +279,12 @@ angular.module('ngResource', ['ng']).
url: function(params) {
var self = this,
url = this.template,
val,
encodedVal;
params = params || {};
forEach(this.urlParams, function(_, urlParam){
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
if (angular.isDefined(val) && val !== null) {
encodedVal = encodeUriSegment(val);
url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
} else {
url = url.replace(new RegExp("/?:" + urlParam + "(\\W)", "g"), '$1');
}
encodedVal = encodeUriSegment(params[urlParam] || self.defaults[urlParam] || "");
url = url.replace(new RegExp(":" + urlParam + "(\\W)"), encodedVal + "$1");
});
url = url.replace(/\/?#$/, '');
var query = [];
@@ -311,10 +305,9 @@ angular.module('ngResource', ['ng']).
actions = extend({}, DEFAULT_ACTIONS, actions);
function extractParams(data, actionParams){
function extractParams(data){
var ids = {};
actionParams = extend({}, paramDefaults, actionParams);
forEach(actionParams, function(value, key){
forEach(paramDefaults || {}, function(value, key){
ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
});
return ids;
@@ -368,7 +361,7 @@ angular.module('ngResource', ['ng']).
var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
$http({
method: action.method,
url: route.url(extend({}, extractParams(data, action.params || {}), params)),
url: route.url(extend({}, extractParams(data), action.params || {}, params)),
data: data
}).then(function(response) {
var data = response.data;
+1 -1
View File
@@ -17,7 +17,7 @@
angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) {
scope.$watch(attr.ngBindHtml, function(value) {
value = $sanitize(value);
element.html(value || '');
});
-3
View File
@@ -106,9 +106,6 @@ angular.scenario.ObjectModel = function(runner) {
self.emit('StepError', it, modelStep, error);
});
runner.on('RunnerBegin', function() {
self.emit('RunnerBegin');
});
runner.on('RunnerEnd', function() {
self.emit('RunnerEnd');
});
+4 -5
View File
@@ -294,11 +294,10 @@ function browserTrigger(element, type, keys) {
iframe = _jQuery('#application iframe')[0],
appWindow = iframe ? iframe.contentWindow : window,
fakeProcessDefault = true,
finalProcessDefault,
angular = appWindow.angular || {};
finalProcessDefault;
// igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
angular['ff-684208-preventDefault'] = false;
appWindow.angular['ff-684208-preventDefault'] = false;
evnt.preventDefault = function() {
fakeProcessDefault = false;
return originalPreventDefault.apply(evnt, arguments);
@@ -308,9 +307,9 @@ function browserTrigger(element, type, keys) {
pressed('shift'), pressed('meta'), 0, element);
element.dispatchEvent(evnt);
finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
finalProcessDefault = !(appWindow.angular['ff-684208-preventDefault'] || !fakeProcessDefault);
delete angular['ff-684208-preventDefault'];
delete appWindow.angular['ff-684208-preventDefault'];
return finalProcessDefault;
}

Some files were not shown because too many files have changed in this diff Show More