Compare commits

...

192 commits

Author SHA1 Message Date
Igor Minar
a03e370a09 chore(release): cut the 1.0.3 bouncy-thunder release 2012-11-27 01:44:46 +01:00
Igor Minar
23677d3ddb docs(CHANGELOG): release notes for 1.0.3 and 1.1.1 releases 2012-11-27 01:44:46 +01:00
Rado Kirov
fc781560a3 fix($location): reset $location.$$replace with every watch call
Closes #1111
2012-11-26 23:24:39 +01:00
Vojta Jina
c9199ee663 docs: load angular from CDN only on production
So that when running the docs locally, eg. during e2e testing, we use the latest build version of angular, rather than the stable one from CDN.

This fixes e2e tests running with Testacular.
2012-11-26 21:33:45 +01:00
Igor Minar
6f18adedef fix(ngClassOdd/ngClassEven): support shrinking/reordering in repeaters
We need to watch $index in addition to cssClasses because only then
we can correctly respond to shrinking or reordered repeaters.

Closes #1076
2012-11-26 21:33:45 +01:00
Igor Minar
6ad894cd58 style(jqLite): better variable names
selector => cssClasses
2012-11-26 21:33:45 +01:00
Igor Minar
cde2f1a868 fix(ngRepeat): support mostly-stable repeating for primitives
I'm reverting changes that were originally done to ngRepeat to fix #933,
because these are now not necessary after the previous changes to keep
ngModel always synced with the DOM.
2012-11-26 21:33:45 +01:00
Igor Minar
6a831495de fix(ngModel): sync ngModel state with scope state
In cases when we reuse elements in a repeater but associate
them with a new scope (see #933 - repeating over array of
primitives) it's possible for the internal ngModel state and
the scope state to get out of sync. This change ensure that
the two are always sync-ed up even in cases where we
reassociate an element with a different (but similar) scope.

In the case of repeating over array of primitives it's still
possible to run into issue if we iterate over primitives and
use form controls or similar widgets without ngModel - oh well,
we'd likely need a special repeater for primitives to deal
with this properly, even then there might be cornercases.

Closes #933
2012-11-26 21:33:45 +01:00
Igor Minar
6e2c38f54d test(ngRepeat): clean up and improve tests 2012-11-26 20:39:10 +01:00
Igor Minar
00e7e31418 fix(ngRepeat): attempt to simplify and improve existing fix for #933
I'm keeping this in for future reference. The issue with this solution
is that if we shift() the first item in the array, the whole repeater
DOM will be rebuilt from scratch, we need to do better than that.
2012-11-26 20:39:00 +01:00
Igor Minar
ff4b3e20c1 test(ngRepeat): add test for issue #1076 2012-11-26 20:38:51 +01:00
Igor Minar
269fb43b36 fix(jqLite): fire $destroy event via triggerHandler
in jQuery 1.8.x the data() data structure is changed and events are
not accessible via data().events. Since all we need is to trigger
all event handlers, we can do so via triggerHandler() api instead of
mocking with the internal jQuery data structures.

This fix was originally proposed by PeteAppleton via PR #1512.

Closes #1512
2012-11-26 16:03:43 +01:00
Igor Minar
7530654328 feat(jqLite): add triggerHandler()
we need triggerHandler() to become jQuery 1.8.x compatible.

this is not fully featured triggerHandler() implementation - it doesn't
bother creating new DOM events and passing them into the event handlers.

this is intentional, we don't need access to the native DOM event for our
own purposes and creating these event objects is really tricky.
2012-11-26 16:03:39 +01:00
Iristyle
c7bd464384 docs(CONTRIBUTING.md): add contrib info file for GitHub 2012-11-25 21:00:56 +01:00
Vojta Jina
ef1874d1f3 fix(Scope): allow removing a listener during event 2012-11-25 11:41:32 +01:00
Kevin Western
c6d8205fdd docs(README.md): fix "API Docs" link
use direct link to api docs
2012-11-25 01:24:03 +01:00
Dean Sofer
55150a669a docs(api): add ngRequired to input/select/textarea directives
Closes #1202
2012-11-25 01:19:47 +01:00
Jeremy Tymes
1eb9e22d45 fix($cacheFactory): return undefined when removing non-existent entry
Instead of throwning an exception, remove should return undefined when
cache entry to be removed doesn't exist.

Closes #1497
2012-11-24 21:58:17 +01:00
Adrian Gheorghe
c0de8fb737 fix($resource): prevent default params to be shared between actions
Having a $resource defined as:

var R = $resource('/Path', {}, {
  get: {method: 'GET', params: {objId: '1'}},
  perform: {method: 'GET'}
});

was causing both actions to call the same URI (if called in this order):

R.get({}); // => /Path?objId=1
R.perform({}); // => /Path?objId=1
2012-11-24 21:29:16 +01:00
Kris Jenkins
557e3894d7 docs(): Fix a couple of typos in the documentation 2012-11-22 08:28:49 +01:00
Dave Clayton
38a9695413 docs(guide/concepts): some typo/grammar fixes 2012-11-22 08:28:49 +01:00
John Hume
293e0336b0 docs(guide/directive): fix typo 2012-11-22 08:28:49 +01:00
Uri Goldshtein
1f5bc0a1cd docs($q): fix missing bracket in the example 2012-11-22 08:28:49 +01:00
Igor Minar
1fe666192b fix($rootScope): workaround for Chrome's memleak
Under certain circumstances chrome fails to GC scopes
because of buggy optimizations and caching. Nulling out
references to (not from!) other scopes helps Chrome to
realize that this object should be GC-ed.

This is really just a workaround as the real problem needs
to be fixed in Chrome.

See discusstion at:
https://github.com/angular/angular.js/issues/1313#issuecomment-10378451

And chrome bug at:
https://code.google.com/p/v8/issues/detail?id=2073

Closes #1313
2012-11-14 19:53:29 +01:00
Igor Minar
29541e735d revert($resource): support custom headers per action
This reverts commit b936e52874.

This commit introduces a feature and should haven't been merged
into the stable branch.
2012-11-11 12:07:26 +01:00
Igor Minar
f5b567d44b chore(validate-commit-msg): recognize 'revert' as valid commit type 2012-11-11 12:06:05 +01:00
Haralan Dobrev
5ee3bbee90 docs(angular.module): improve angular.Module#run docs 2012-11-11 11:40:52 +01:00
Jamison Dance
80927c5811 docs(guide): fix run-on sentence in modules guide 2012-11-11 11:35:20 +01:00
Jamison Dance
ca8b344e20 docs(tutorial): change module name in step-7 2012-11-11 11:35:15 +01:00
Wes Alvaro
3dab93874d docs($timeout): set return type to Promise instead of *.
The cancel function accepts a Promise, but the timeout function
fails to specify returning a Promise.
2012-11-11 11:32:00 +01:00
Josh Adams
7550f90a57 docs(ngList): fix typo 2012-11-11 11:25:40 +01:00
Josh Adams
d78fea87d1 docs(encodeUriSegment): fix typo 2012-11-11 11:23:46 +01:00
Tim Macfarlane
27cee7db0a docs(guide/directive): fix names in scope '='; easier to grok 2012-11-11 11:20:57 +01:00
Christian Vuerings
60acba3840 docs(ngHide): Fix typo and make it more in line with ngShow 2012-11-11 10:37:59 +01:00
Igor Minar
51bed36370 chore(docs): fix docs-scenario.html 2012-11-08 22:18:34 +01:00
Igor Minar
6d940213ac chore(docs): remove obsolete gae files 2012-11-08 22:18:34 +01:00
Miško Hevery
494b527fa7 docs(directive): fix typo 2012-11-05 19:35:31 -08:00
Sudhir Jonathan
8ce84cb2ea chore(testacular): use local testacular version
Making testacular a dependency to avoid having to install it globally.
(Causes npm issues on some machines)
2012-10-31 17:00:00 -07:00
Sudhir Jonathan
d981c2a3ec fix(select): select option with a label of 0 is not shown
Bug caused by the use of the `||` operator to replace all non-truthy
values with an empty string. Changed to replace only `undefined` values.

Closes #1401
2012-10-31 15:03:48 -07:00
Igor Minar
537e20065a chore(validate-commit-msg): allow '/' in scope 2012-10-31 14:48:24 -07:00
Fred Sauer
97578b4dae docs(guide/location): fix table formatting
Fix table formatting so headings are bold, rows are separated by lines, and rows have :hover style
2012-10-31 14:48:18 -07:00
Tim Macfarlane
fa12564607 docs(module): fix typo in example
fixed example app, `simpleAppModule` should have been `myAppModule`.
2012-10-31 14:22:12 -07:00
sqwishy trick
54bcb9ae25 chore(injector): fix typo in injector documentation 2012-10-31 14:19:52 -07:00
Adam Macejak
ad7ce0d402 fix(scenario-runner): support data-ng and x-ng based attributes
Prefixed attributes like data-ng-model and x-ng-model were not being
found by the Selector. It was only looking at ng: and ng- prefixed
attributes.
Added a few tests as well to ensure the aforementioned prefixed
attributes are being matched properly.

Closes #1020
2012-10-31 14:10:26 -07:00
Daniel Luz
085e0ea8ef docs(contribute): fix task name for continuous testing 2012-10-31 13:13:33 -07:00
Igor Minar
bb52c4e8d3 fix(docs): correctly generate filenames for plunkr/fiddle
previously examples like $http where broken because we would strip part of the
filename (http-hello.html -> http)

we really want to strip only the id suffix that we append to disambiguate
common filenames (like index.html) which appear in many examples.
2012-10-31 13:06:22 -07:00
Shyam Seshadri
295af335c1 feat(docs): add plunkr support
Add option to edit source in Angular Docs in Plunkr in addition to JsFiddle
2012-10-31 13:06:16 -07:00
Daniel Luz
2c2e18c37a fix(doc): typo on FAQ
Closes #1493
2012-10-31 10:26:00 -07:00
Igor Minar
adfb75e3c6 fix($compile): don't look for class directives in empty string
if className is undefined or empty string, don't bother looking for directives in there
2012-10-29 19:39:34 -07:00
Igor Minar
9bff5c60df fix($compile): compilation should not recurse into empty nodes
if a node doesn't have children then don't try to compile these non-existent children
2012-10-29 19:39:21 -07:00
Igor Minar
3ba008d4b2 style($compile): better fn names for debugging 2012-10-29 19:38:57 -07:00
Igor Minar
4e45a2f8e2 refactor($compile): simplify nodeLinkFn 2012-10-29 19:38:29 -07:00
Igor Minar
4dbd8452eb fix($compile): prevent double attr interpolation w/ templateUrl
This fixes the issue that caused two attr interpolation observers
to be registered for the same attribute as a result of isolate
scope definition with attr (@) property for this attribute.

Duplicate observers would then fight with each other updating the
model.

The issue occured only when this directive was used in a repeater
because that's when we clone the template node which caused the
two observers to point to two different sets of $attr instances.

Closes #1166, #836
2012-10-29 19:38:03 -07:00
Braden Shepherdson
45a8db9c08 fix(currency): Handle not-quite-zero values
IEEE 754 floating point sometimes results in values that are very small,
rather than zero. One example is 1.0 + 1.07 - 2.07, which returns
4.440892098500626e-16 instead of 0.

This change tweaks the number formatting logic so that an exponential
value with a negative exponent that is larger than the precision+1
returns 0 instead. For example: with precision 2, anything with an
exponent of -4, -5 or more would become 0. 9e-3 = 0.009 = 0.01, but 9e-4
= 0.0009 = 0.001 = 0.00. This detail is unlikely to matter since this
quirk is usually only triggered with values very close to zero.

Closes #1469
2012-10-29 19:37:52 -07:00
Braden Shepherdson
d930a410fb doc(faq): Add Common Pitfalls section
Describes several common pitfalls new users of Angular fall into that
I've observed in #angularjs.
2012-10-29 19:37:38 -07:00
Braden Shepherdson
66505ffc40 doc(faq): Fix minor spelling and wording errors 2012-10-29 19:37:29 -07:00
Igor Minar
045de959b9 chore(check-size.sh): fix rake target 2012-10-29 19:37:21 -07:00
Igor Minar
3ca11d5235 docs(contribute): add CLA note to code submission section 2012-10-19 09:15:34 -07:00
Igor Minar
d5d8ac01e3 docs(contribute): add visible link to github project 2012-10-19 09:15:34 -07:00
Igor Minar
ace81c053c chore(validate-commit-msg): allow * and - in scope string 2012-10-18 03:29:12 -07:00
Igor Minar
1e95c419b8 chore(jasmine): remove Jasmine from our repo
it's bundled with Testacular, so we don't need it here
2012-10-18 03:29:12 -07:00
Igor Minar
49ed63d26a chore(jstd): remove JsTestDriver from our repo
Testacular FTW!
2012-10-18 03:29:12 -07:00
Igor Minar
6ff2685668 docs(tutorial): replace JsTD with Testacular + drop snapshots
JsTD references have been replaced with Testacular stuff.

snapshots are PITA to maintain so I'm dropping them, everyone loves the Git
version anyway.
2012-10-18 02:34:27 -07:00
Igor Minar
c4573c04aa chore(Rakefile): remove test_out dir when cleaning 2012-10-17 20:20:54 -07:00
Igor Minar
d57abdb3f7 chore(Rakefile): tune JVM for closure compiler
Using the client VM and forcing 32bit mode gives us huge perf boost.

before:

reali   0m8.173s
user    0m39.984s
sys     0m1.408s

after:

real    0m3.000s
user    0m12.687s
sys     0m0.852s
2012-10-17 20:20:53 -07:00
Igor Minar
4050e89446 chore(Rakefile): paralelize closure compilation
this speeds up the build by paralelizing closure compilation (the slowest
piece of the build process)

before:

real  0m14.372s
user  0m31.649s
sys   0m1.006s

after:

real  0m8.191s
user  0m40.473s
sys   0m1.378s
2012-10-17 20:16:36 -07:00
Vojta Jina
b6620c737f chore(test): add junit config for testacular 2012-10-17 20:16:36 -07:00
Igor Minar
0c8e908841 chore(Rakefile): misc_options should support + -> , conversion 2012-10-17 20:16:35 -07:00
Igor Minar
5595e196a8 chore(Rakefile): use exec for webserver
exec unlike system replaces the current process. this way when we kill
the webserver process we don't get scary looking 'rake aborted' error
2012-10-17 12:44:38 -07:00
Misko Hevery
f92e4146d1 fix(doc): disable directory listing in docs.angularjs.org 2012-10-08 15:09:06 -07:00
Vojta Jina
8b7108e3c9 chore: add travis config 2012-10-05 10:20:02 -07:00
Igor Minar
caf702cc88 docs(downloading): update the downloading docs 2012-10-05 03:15:11 -07:00
Vojta Jina
cf2c49ed7f fix($compile): reference local in isolate scope
This was really corner case:
Watcher needs to return changed value, to notify that model might have changed and one more $digest cycle needs to be performed.

The watcher, that takes care of reference binding into an isolate scope ("="), did not return changed value, if the change was from the isolate scope to the parent.

If any other watcher returned change, it worked fine, as this change caused re-digest.

Closes #1272
2012-09-22 12:00:16 -07:00
Igor Minar
ccd52abf5d docs(README): update README.md with new rake tasks 2012-09-17 14:52:06 -07:00
Igor Minar
74c574015d chore(Rakefile): fix test:jquery task 2012-09-17 14:52:06 -07:00
Igor Minar
1f1a6fb6d2 docs(contribute): update contribute docs 2012-09-17 09:46:34 -07:00
Igor Minar
8632e893b0 chore(): remove unused files 2012-09-17 09:46:34 -07:00
Igor Minar
c2b6e127fa docs(contribute): update misc/contribute docs with Testacular info 2012-09-17 09:46:34 -07:00
Igor Minar
06eceeb09f chore(testing): Testacular config files + rake tasks
- adds testacular config files for jqlite, jquery, modules and e2e tests
- replaces obsolete JsTD Rake tasks with Testacular onces
- rake tasks are parameterazied so that they can be used locally as well as on CI server

usage:

rake test  # run all tests on Chrome
rake test[Safari+Chrome+Opera]  # run all tests on Safari, Chrome and Opera
rake test[Safari]  # run all tests on Safari
rake test:jqlite # run unit tests using jqlite on Chrome
rake test:jqlite[Safari,"--reporter=dots"]  # run jqlite-based unit tests on Safari with dots reporter
rake autotest:jquery  # start testacular with jquery-based config and watch fs for changes
rake test:e2e # run end to end tests
2012-09-17 09:46:13 -07:00
Miško Hevery
8133d468b9 docs(directive): remove reference to old isolation syntax 2012-09-13 11:32:13 -07:00
Misko Hevery
074a354fa9 fix($route): support inline annotation on .resolve 2012-09-11 23:16:41 -07:00
Vojta Jina
e191582a02 chore(scripts): add init-repo script 2012-09-11 23:16:38 -07:00
Jay Zeng
6fbe926cda docs(ngResource): Spelling typo (agressive => aggressive) 2012-09-11 16:39:46 -07:00
Igor Minar
ebbc224e09 fix($resource): fix isDefined -> angular.isDefined 2012-09-11 16:39:46 -07:00
Shyam Seshadri
2c6aa4c300 fix(*): name all anonymous watch functions in Angular
This will allow us to see function names in Batarang and debugger.

Closes #1119
2012-09-11 16:39:46 -07:00
Zhenbo Zhang
f7a8f17fc7 fix(ng-repeat) to work with primitive types 2012-09-11 16:38:42 -07:00
Brian Ford
191efbb558 docs(guide): fix directive interpolation example code
Closes #1339
2012-09-11 16:19:45 -07:00
Shyam Seshadri
bf873d6f02 fix(scenario): emit RunnerBegin event 2012-09-11 16:19:44 -07:00
Vojta Jina
e741107c55 chore(scripts): add commit-msg hook (validation) 2012-09-11 16:19:44 -07:00
Jimmy Zhuo
82f4b99d99 fix(scenario): NPE when no angular loaded in test page 2012-09-11 16:19:44 -07:00
Daniel Luz
7210b7ae1d docs($rootScope): fix iteration limit described by $watch, it's actually 10 as of now 2012-09-11 16:19:44 -07:00
Daniel Luz
afed23c001 docs($rootScope): fix typos and minor wording tweaks on $watch 2012-09-11 16:19:44 -07:00
Daniel Luz
1f69cc2989 docs($rootScope): fix quoting on expression 2012-09-11 16:19:43 -07:00
Daniel Luz
3401833c83 docs($rootScope): standardize on present, third-person actions for descriptions 2012-09-11 16:19:43 -07:00
Daniel Luz
06606e2816 docs($rootScope): backquote attribute types too on $on 2012-09-11 16:19:43 -07:00
Daniel Luz
eba64e1f31 docs($cacheFactory): fix backquotes on method descriptions 2012-09-11 16:19:43 -07:00
Daniel Luz
81dd1df1b1 docs($rootScope): fix typos on $new 2012-09-11 16:19:43 -07:00
Daniel Luz
dbafbb0de5 docs($rootScope): fix typo on $eval 2012-09-11 16:19:42 -07:00
Daniel Luz
1d0aa7b7c6 docs($rootScope): fix typos on $watch 2012-09-11 16:19:42 -07:00
Igor Minar
afd02ca48c fix(docs): update docs top menu links 2012-09-06 15:56:11 -07:00
sgtpep
67db7616ad fix(a): prevent Opera from incorrectly navigating on link click
we handle the navigation by ourselves, so we need to prevent the default action.

Opera ignores event.preventDefault() call so we must return false.
2012-09-06 15:54:20 -07:00
Kai Groner
3d7c752e27 fix(FormController): propagate dirty state to parent forms 2012-09-06 15:54:19 -07:00
Jonathan Zacsh
f02833d634 chore(docs): get correct location for jasmine-node 2012-09-06 15:54:19 -07:00
Misko Hevery
0eb373e0e6 fix($injector): more conservative annotation parsing 2012-09-06 15:49:50 -07:00
Xiangru Chen
fd3071843c fix(ngSrc): don't set src if value is empty string
Current implementation of ngSrc may lead to empty src attribute when page is loading.

For example:

<img ng-src="{{image.url}}">
can be temporarily rendered as

<img src="">
before the image resource is loaded.

Some browser emits a request to the current page when seeing <img src=""> (Firefox13 and IE8 will, Chromium20 won't), which leads to performance problems.
2012-09-06 15:49:49 -07:00
Iwein Fuld
a631ceb223 fix(dateFilter): make timezone optional
Makes the time zone optional in the date filter

Problem with the current R_ISO8601_STR regex was that the time was optional, but the zone was not.
This results in the filter not formatting local date times, which it could easily do.

For example:
2012-08-30 -> formatted
2012-08-30T06:06:06.123Z -> formatted
2012-08-30T06:06:06.123 -> NOT formatted

A simple change in the regex fixes this. Arguably this is closer to the ISO8601 spec which specifies
local dates being in the "current time zone" and not requiring a Z. In any case it behaves more like
a user would expect.
2012-09-06 15:49:49 -07:00
Misko Hevery
a713928210 docs(concept): correct example for creating injector 2012-09-06 15:49:49 -07:00
Godmar Back
05fa20df81 docs(module): fixed module example and corrected typos 2012-09-06 15:49:49 -07:00
Benjamín Eidelman
125573602f fix($resource): allow falsy values in URL parameters
Close #1212

when a param value was 0 (or false) it was ignored and removed from url.
after this fix that only happens if the value is undefined or null.
2012-09-06 15:49:49 -07:00
Jay Zeng
ed5dfbcd66 docs(module): myAppModule -> simpleAppModule 2012-09-06 15:49:49 -07:00
petrovalex
d2e52b2376 fix($resource): ignore undefined parameters
- $resource should handle multiple params with same name
- ignore slashes of undefined parameters
- fix default parameters issue, mentioned in #875

Closes #875
Closes #782
2012-09-06 15:49:49 -07:00
petrovalex
a56aaa9877 fix(ngClassEven/Odd): filtering/ordering and repeater
Closes #1076
2012-09-06 15:49:48 -07:00
Max Martinsson
79bb7b1f0b fix(ngClass): works with class interpolation
Closes #1016
2012-09-06 15:49:48 -07:00
Max Martinsson
b936e52874 feat($resource): support custom headers per action
Closes #736
2012-09-06 15:49:48 -07:00
petrovalex
0d52ff0f10 fix($parser): string concatination with undefined model
Closes #988
2012-09-06 15:49:48 -07:00
Stein Jakob Nordbø
baf52e902d fix(dateFilter): support sub-second precision on dateFilter 2012-09-06 15:49:48 -07:00
Igor Minar
dffea9e2b7 docs($route): rename leftover $afterRouteChange to $routeChangeSuccess 2012-09-06 15:03:58 -07:00
Igor Minar
4a411b8f82 chore(release): prepare 1.0.3 bouncy-thunder iteration 2012-09-06 08:42:51 -07:00
Misko Hevery
278bfc4bb2 fix(docs): broken url to angular-bootstrap 2012-09-04 18:16:52 -07:00
Igor Minar
18731173f9 chore(Rakefile): add 'version' rake task to generate version.txt 2012-09-04 16:38:29 -07:00
Igor Minar
d43fb404d7 chore(docs): bump up the stable version 2012-09-04 16:30:33 -07:00
Igor Minar
da984ad187 chore(release): cut the 1.0.2 debilitating-awesomeness release 2012-09-04 11:08:40 -07:00
Igor Minar
4015357ce5 chore(docs): don't rewrite colons in doc filenames 2012-09-04 11:08:40 -07:00
Igor Minar
dc3d11ad19 chore(Rakefile): zip only the build dir 2012-09-04 11:08:40 -07:00
Igor Minar
0e1545eb04 revert: fix(ng-repeat) to work with primitive types
this commit was accidentaly merged. it needs more work and we don't
have CLA signature

This reverts commit 98d489712e.
2012-08-31 13:44:36 -07:00
Igor Minar
ec7cabf5c9 docs(changelog): release notes for 1.0.2 and 1.1.0 releases 2012-08-31 13:23:23 -07:00
Jonathan Zacsh
3051beba2f fix(docs): Making sure gen_docs.sh looks for a globally installed copy of jasmine-node as well as local. 2012-08-30 22:38:54 -07:00
Fernando Correia
92304323b1 docs(tutorial): correct typos and clarify a few sections 2012-08-30 22:38:54 -07:00
Brice Burgess
c28123a872 fix(docs): indicate support for passing a string as the controller property on $routeProvider's route object 2012-08-30 22:38:53 -07:00
brettcannon
d798423813 doc(misc) Mention how attribute names map to directive names. 2012-08-30 22:38:52 -07:00
Sahat Yalkabov
2583e77cc7 doc(module) changed simpleApp to myApp in the Module page guide for consistency 2012-08-30 21:34:43 -07:00
Steve Nicolai
f66836fee4 doc(devguide) - Fix typos and small grammatical errors in the developer guide. 2012-08-30 21:34:42 -07:00
Uri Goldshtein
0ccc445d53 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 21:34:42 -07:00
Tyson Benson
b7d5fa1cbe docs(typos): fix typos in dev guide 2012-08-30 21:34:42 -07:00
German Galvis
8bb3942453 fix(scenario): Adding meta tag to avoid cache issues 2012-08-30 21:34:42 -07:00
phil
51a79cebcb docs(api): fix typo on home page
Refference -> Reference
2012-08-30 21:34:41 -07:00
csugden
36bcf64008 Update docs/content/guide/overview.ngdoc
Corrects video information
2012-08-30 21:34:41 -07:00
Jamie Krug
5c6630605b fix(docs): Fix typos and improve grammar. 2012-08-30 21:34:41 -07:00
Jamie Krug
125827406c fix(docs): Fix bad links. 2012-08-30 21:34:41 -07:00
Colin Frei
62c21422a6 docs(module) fix typo 2012-08-30 21:34:41 -07:00
Zhenbo Zhang
98d489712e fix(ng-repeat) to work with primitive types 2012-08-30 21:34:41 -07:00
Igor Minar
2cab2d8ef1 test(locationSpec): fix broken tests after vojta's commit 2012-08-30 16:54:07 -07:00
Vojta Jina
8fa2bb72bc fix(mocks): free up memory after every spec 2012-08-30 16:53:52 -07:00
Igor Minar
d151f94937 chore(docs): ask GAE to serve docs-keywords.js 2012-08-30 15:59:29 -07:00
Igor Minar
5b74b7185b test(bootstrap): test exception siling during bootstrap
Closes #1018
2012-08-30 15:18:11 -07:00
Igor Minar
4f0be2ae4e test(ngApp): add missing test for [ng-app] bootstrap 2012-08-30 15:18:02 -07:00
Igor Minar
bb9badeb2a fix(jqLite): better support for xhtml
it turns out that some stuff doesn't work in xhtml as it does in html.

for example &nbsp; 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:52:36 -07:00
Igor Minar
c287c8361d chore(docs): correctly link docs images 2012-08-30 08:59:17 -07:00
Igor Minar
ade7127c79 chore(Rakefile): fix the default task 2012-08-30 08:58:51 -07:00
Igor Minar
d341483f1f chore(Rakefile): remove bogus symlink from build 2012-08-30 08:58:39 -07:00
Igor Minar
b36acbc857 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:08:03 -07:00
Igor Minar
a4fea38b94 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 16:07:47 -07:00
Misko Hevery
300c5c0c99 doc($log): correct non-working example 2012-08-27 21:20:51 -07:00
Misko Hevery
152537c4e9 doc(guide): add concepts 2012-08-27 21:20:51 -07:00
Misko Hevery
8b46bf6bc9 fix(ngdoc): failing test 2012-08-27 21:20:50 -07:00
Colin Frei
aef861eb41 doc(directive) correct typos 2012-08-27 21:20:50 -07:00
Misko Hevery
f61d36861d fix(docs) typo 2012-08-27 21:20:50 -07:00
Misko Hevery
2af0348cea fix(ng-list): remove data bound flicker 2012-08-27 21:20:50 -07:00
Misko Hevery
78c5743494 doc(misc) updated getting started to reflect the new homepage 2012-08-27 21:20:49 -07:00
Misko Hevery
2cb9fbd043 doc(guide) simplify the guide home page 2012-08-27 21:20:49 -07:00
Igor Minar
e9dad5dbf4 chore(Rakefile): rewrite version numbers in all index files 2012-08-27 12:25:40 -07:00
Igor Minar
54895fc2a1 chore(docs): support _escaped_fragment_ hack for crawler 2012-08-25 02:31:20 -07:00
Igor Minar
60a12b4161 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 15:00:36 -07:00
Igor Minar
cd7e58ba41 docs(a): expose hidden docs
It seems that docs for these directive were previously hidden by accident
2012-08-24 14:59:52 -07:00
johnlindquist
9391475dc3 docs(ngRoute): fix typo
aftre -> after
2012-08-24 14:59:43 -07:00
phil
7840803add docs(tutorial): fix typo in step_00
Just removed an extra comma. No big deal.
2012-08-24 14:59:21 -07:00
Igor Minar
7d77de2834 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:35:32 -07:00
Igor Minar
ab044cada6 refactor($compile): code cleanup 2012-08-13 12:36:42 -07:00
Brian Ford
d010e0cc7d fix(ngPluralize): fixes ng-pluralize when using non-standard start/end symbols
Closes #1134
2012-08-13 12:36:33 -07:00
Igor Minar
40f728b1aa style(ngPluralizeSpec): fix indentation 2012-08-13 12:36:22 -07:00
Igor Minar
23abb26405 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 12:36:14 -07:00
Igor Minar
fd55bc8e1d docs($interpolateProvider): fixing docs 2012-08-13 09:51:57 -07:00
Igor Minar
541aaa4e08 fix($interpolate): $interpolateProvider.endSymbol() returns startSymbol
I also added missing tests.
2012-08-13 09:51:45 -07:00
Igor Minar
f22c422547 docs($interpolate): fix typo in description 2012-08-13 09:51:35 -07:00
Vojta Jina
0e461f0c07 docs($compileProvider): remove duplicate of .directive() 2012-08-12 11:04:32 -07:00
Vojta Jina
5074448443 docs: fix broken links to $compileProvider.directive() 2012-08-12 11:04:20 -07:00
Brian Ford
8d66af11e6 fix(docs): fixed documentation for using linky 2012-08-10 16:38:01 -07:00
Brian Ford
169948bb47 chore(ngDoc): add support for custom @usage metadata 2012-08-10 16:37:54 -07:00
Brian Ford
58d9469574 fix(docs): added note about using JSON3 as a polyfill for IE7 2012-08-10 16:37:42 -07:00
Brian Ford
8d858a2360 fix(docs): added note about needing JSON shim for IE7 and earlier 2012-08-10 16:36:56 -07:00
Igor Minar
5540748890 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:49 -07:00
unirgy
f8a52be817 docs($rootScope): fix $on listener signature doc
Added args in $on() listener syntax declaration
2012-08-10 14:52:57 -07:00
Igor Minar
3b5f1105f6 test(jqLite): add missing test for $destroy event 2012-08-10 14:21:11 -07:00
Igor Minar
663ccc5449 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 14:21:02 -07:00
Igor Minar
263f47819f 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-10 14:20:52 -07:00
Igor Minar
6b75475ce3 refactor(formSpec): group preventDefault specs into a describe 2012-08-10 14:20:28 -07:00
Igor Minar
07c354a8c0 docs(faq): update faq docs 2012-08-10 14:20:13 -07:00
Igor Minar
1391579599 docs(styles): fix the cog icon alignment 2012-08-10 14:19:57 -07:00
Vojta Jina
5d2bd1d84c chore(nodeserver): add font mime type 2012-08-10 14:19:47 -07:00
Vojta Jina
bf77e212af 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-08-10 14:19:37 -07:00
Vojta Jina
eef2f9c31e docs(design): fix icons
Copy fontawesome during build
2012-08-10 14:18:45 -07:00
brettcannon
438627c2c3 fix(docs): "in depth" -> "in-depth" 2012-08-10 14:18:06 -07:00
173 changed files with 11176 additions and 4738 deletions

14
.gitattributes vendored Normal file
View file

@ -0,0 +1,14 @@
# Auto detect text files and perform LF normalization
* text=auto
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

1
.gitignore vendored
View file

@ -10,6 +10,5 @@ performance/temp*.html
*~ *~
angular.js.tmproj angular.js.tmproj
node_modules node_modules
jsTestDriver*.conf
angular.xcodeproj angular.xcodeproj
.idea .idea

13
.travis.yml Normal file
View file

@ -0,0 +1,13 @@
language: node_js
node_js:
- 0.8
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- npm install -g testacular@canary
- rake package
- ./nodeserver.sh > /dev/null &
script:
- rake test[Firefox,"--reporters=dots"]

View file

@ -1,3 +1,296 @@
<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).
## Features
- **$http:** support custom reponseType
([e0a54f6b](https://github.com/angular/angular.js/commit/e0a54f6b206dc2b6595f2bc3a17c5932e7477545),
[#1013](https://github.com/angular/angular.js/issues/1013))
- **$interpolate:**
- provide contextual error messages
([d804bbcd](https://github.com/angular/angular.js/commit/d804bbcd51ec83bee1f4a3ccd42c3bd7eb38a988))
- expose start/end symbols in run phase
([58f121a5](https://github.com/angular/angular.js/commit/58f121a5c293ed57043e22ed526fdf99642fca81))
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
<a name="1.0.2"></a>
# 1.0.2 debilitating-awesomeness (2012-08-31)
## Bug Fixes
- **$compile:** denormalize directive templates
([dfe99836](https://github.com/angular/angular.js/commit/dfe99836cd98c2a1b0f9bde6216bd44088de275a))
- **$interpolate:** $interpolateProvider.endSymbol() returns startSymbol
([20348717](https://github.com/angular/angular.js/commit/20348717640c0ef405c9fdcc8fec5b566efc48b3))
- **jqLite:** better support for xhtml
([d3fa7a2e](https://github.com/angular/angular.js/commit/d3fa7a2e9e93c9dae13d852b28c878f7d6b7c420),
[#1301](https://github.com/angular/angular.js/issues/1301))
- **mocks:** free up memory after every spec
([1a8642aa](https://github.com/angular/angular.js/commit/1a8642aac2de40dccdab464e58dc164006c300bb))
- **e2e test runner:** Adding meta tag to avoid cache issues
([5318588d](https://github.com/angular/angular.js/commit/5318588d6e8ee9a31f4002affd6858d25305aabf))
- Directives:
- **form:** prevent page reload when form destroyed
([054d40f3](https://github.com/angular/angular.js/commit/054d40f338f9000cddcf7f0513af37328b88ef41),
[#1238](https://github.com/angular/angular.js/issues/1238))
- **ngList:** remove data bound flicker
([fa62ea81](https://github.com/angular/angular.js/commit/fa62ea810f6c701e898dd07c6c9228f13d5b5e02))
- **ngPluralize:** fixes ng-pluralize when using non-standard start/end symbols
([e85774f7](https://github.com/angular/angular.js/commit/e85774f709b9f681b0ff8d829b07568b0f844a62),
[#1134](https://github.com/angular/angular.js/issues/1134))
- **option:** support option elements in datalist
([9767f7bd](https://github.com/angular/angular.js/commit/9767f7bdd3e1ce6f65bdea992d67369ead13d813),
[#1165](https://github.com/angular/angular.js/issues/1165))
## Docs
- Conceptual Overview of AngularJS (high level overview of how things work):
<http://docs.angularjs.org/guide/concepts>
([7a5f25f6](https://github.com/angular/angular.js/commit/7a5f25f6671eb5f51b06615d74a05855ab79f31e))
- Lots of spelling, grammar and other fixes:
[9a710c78](https://github.com/angular/angular.js/commit/9a710c788d880785d2b02a9c5411eb15e9c278bf),
[847d2da0](https://github.com/angular/angular.js/commit/847d2da0f8d1e265eda7b4dd3e7eb52ac86d784e),
[dbefd671](https://github.com/angular/angular.js/commit/dbefd671e41c3bda481850bb7e566349e275d759),
[cab5e1d9](https://github.com/angular/angular.js/commit/cab5e1d9b363eac6fd31b15c5b86f30993e2f147),
[f00b6cca](https://github.com/angular/angular.js/commit/f00b6cca024a9418f353651f29c984f934575bd9),
[2e365168](https://github.com/angular/angular.js/commit/2e3651686c2bd84cf464ecc236c8ad77e61179df),
[536de148](https://github.com/angular/angular.js/commit/536de148214290f0b4a0595fa16c00da5e527e79),
[a1107e81](https://github.com/angular/angular.js/commit/a1107e81ebf2254caf75718de2e3ec773cce0c56),
[5ef9ed87](https://github.com/angular/angular.js/commit/5ef9ed87d82b109715a87e9aa1b1d5b63f515d3a),
[8c81a0f3](https://github.com/angular/angular.js/commit/8c81a0f3728b9308854ceb9bf392ec467b95d8eb),
[bde931af](https://github.com/angular/angular.js/commit/bde931afd5cf2483df236e06992666a0a4182794),
[6553fe68](https://github.com/angular/angular.js/commit/6553fe68d17d42ec25e0c592ceaa1077cc0ec4f6),
[13b5fd1b](https://github.com/angular/angular.js/commit/13b5fd1b9d60f1a9187da8a89db9272284ccdac4),
[17209d5b](https://github.com/angular/angular.js/commit/17209d5b4a579edf8425715b5cdf25bc5cd96711),
[31c82560](https://github.com/angular/angular.js/commit/31c825607dd524241c811ca3e401b119c810e977),
[ab6937e2](https://github.com/angular/angular.js/commit/ab6937e2518bfd77d9fe42e3d2e11fe4a7a16814),
[fbfda241](https://github.com/angular/angular.js/commit/fbfda241f616bcfe8273f501dd49120a3cb35fab),
[206371b7](https://github.com/angular/angular.js/commit/206371b7372c242db234ca8da12d1c7a8a322d54),
[b6b92bd8](https://github.com/angular/angular.js/commit/b6b92bd866e1d6d066f1c9bf1937496cd3e28664),
[79f2d843](https://github.com/angular/angular.js/commit/79f2d843a8458bfdc23fe9f179a1416fe21f7533),
[64a9cd8f](https://github.com/angular/angular.js/commit/64a9cd8f4fac1c518869a1c955fe60bd6ef76439),
[7f6e1326](https://github.com/angular/angular.js/commit/7f6e1326f3a7a6a2ba2dbd48dd6571ebe929a7c1),
[1fd2b3d4](https://github.com/angular/angular.js/commit/1fd2b3d402f36e395a1fe9ea7e3f91a1b2833426),
[d56d69cc](https://github.com/angular/angular.js/commit/d56d69cc8319f69135a17a9bb5ae394123b33c51),
[01e726b2](https://github.com/angular/angular.js/commit/01e726b2fa3fb0d2584c9bb8df116ff3a9f05879),
[16136216](https://github.com/angular/angular.js/commit/161362164532af3578c9e3e8b52cd80b15345add),
[92a3d282](https://github.com/angular/angular.js/commit/92a3d2821856c75eb95f8ec6ccf26d6a9b37fdd9),
[4c585019](https://github.com/angular/angular.js/commit/4c5850195699b1d982963f25399d24bf8b815f81),
[c076fe08](https://github.com/angular/angular.js/commit/c076fe08cf47e8af4b5e8845aed917ebb7dbd593),
[2473412b](https://github.com/angular/angular.js/commit/2473412ba55f7c47f2ca24311312ce95ee11949e),
[1f2d5000](https://github.com/angular/angular.js/commit/1f2d50000e82630bfce6eb9cf0a8da752fd1e826),
[5026315d](https://github.com/angular/angular.js/commit/5026315d6f4495d636d86ae2a022fb55cc0ca211),
[f0a090dd](https://github.com/angular/angular.js/commit/f0a090ddf256d0c144e705c0cdf4216d824140f9),
[6d9313a6](https://github.com/angular/angular.js/commit/6d9313a68d82654d389c0b2c3e4af148382f14be)) and more!
<a name="1.0.1"></a> <a name="1.0.1"></a>
# 1.0.1 thorium-shielding (2012-06-25) # 1.0.1 thorium-shielding (2012-06-25)

32
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,32 @@
## Submitting issues
If you have questions about how to use AngularJS, please direct these to the
[Google Group][groups] discussion list or [StackOverflow][stackoverflow]. We are
also available on [IRC][irc].
### Guidelines
* Search the archive first, it's likely that your question was already answered.
* A live example demonstrating your problem or question, will get an answer faster.
* Create one using this [template][template]
* If you get help, help others. Good karma rulez!
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new
features, by not reporting duplicate issues.
[stackoverflow]: http://stackoverflow.com/questions/tagged/angularjs
[groups]: https://groups.google.com/forum/?fromgroups#!forum/angular
[irc]: http://webchat.freenode.net/?channels=angularjs&uio=d4
[template]: http://plnkr.co/edit/gist:3510140
## Contributing to Source Code
We'd love for you to contribute to our source code and to make AngularJS even
better than it is today!
Please read the [contribution guidelines][contribute] to learn about how to submit code as well as
other useful info like how to build and test AngularJS code.
[list]: https://groups.google.com/forum/?fromgroups#!forum/angular
[contribute]: http://docs.angularjs.org/misc/contribute

View file

@ -13,17 +13,33 @@ it makes development fun!
* Web site: http://angularjs.org * Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial * Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org * API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide * Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
Compiling Building AngularJS
--------- ---------
rake compile [Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
rake package
Running Tests Running Tests
------------- -------------
./server.sh # start the server Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
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).

242
Rakefile
View file

@ -1,6 +1,13 @@
require 'yaml' require 'yaml'
include FileUtils include FileUtils
## High level flow of the build:
##
## clean -> init -> concat -> minify -> package
##
content = File.open('angularFiles.js', 'r') {|f| f.read } content = File.open('angularFiles.js', 'r') {|f| f.read }
files = eval(content.gsub(/\};(\s|\S)*/, '}'). files = eval(content.gsub(/\};(\s|\S)*/, '}').
gsub(/angularFiles = /, ''). gsub(/angularFiles = /, '').
@ -9,7 +16,7 @@ files = eval(content.gsub(/\};(\s|\S)*/, '}').
BUILD_DIR = 'build' BUILD_DIR = 'build'
task :default => [:compile, :test] task :default => [:package]
desc 'Init the build workspace' desc 'Init the build workspace'
@ -19,12 +26,13 @@ task :init do
v = YAML::load( File.open( 'version.yaml' ) ) v = YAML::load( File.open( 'version.yaml' ) )
match = v['version'].match(/^([^-]*)(-snapshot)?$/) match = v['version'].match(/^([^-]*)(-snapshot)?$/)
NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename). NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename, :stable).
new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''), new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''),
match[1].split('.')[0], match[1].split('.')[0],
match[1].split('.')[1], match[1].split('.')[1],
match[1].split('.')[2].sub(/\D+.*$/, ''), match[1].split('.')[2].sub(/\D+.*$/, ''),
v['codename']) v['codename'],
v['stable'])
end end
@ -32,11 +40,12 @@ desc 'Clean Generated Files'
task :clean do task :clean do
FileUtils.rm_r(BUILD_DIR, :force => true) FileUtils.rm_r(BUILD_DIR, :force => true)
FileUtils.mkdir(BUILD_DIR) FileUtils.mkdir(BUILD_DIR)
FileUtils.rm_r('test_out', :force => true)
end end
desc 'Compile Scenario' desc 'Concat Scenario'
task :compile_scenario => :init do task :concat_scenario => :init do
concat_file('angular-scenario.js', [ concat_file('angular-scenario.js', [
'lib/jquery/jquery.js', 'lib/jquery/jquery.js',
@ -47,8 +56,9 @@ task :compile_scenario => :init do
], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css')) ], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css'))
end end
desc 'Compile JSTD Scenario Adapter'
task :compile_jstd_scenario_adapter => :init do desc 'Concat JSTD Scenario Adapter'
task :concat_jstd_scenario_adapter => :init do
concat_file('jstd-scenario-adapter.js', [ concat_file('jstd-scenario-adapter.js', [
'src/ngScenario/jstd-scenario-adapter/angular.prefix', 'src/ngScenario/jstd-scenario-adapter/angular.prefix',
@ -66,9 +76,9 @@ task :compile_jstd_scenario_adapter => :init do
end end
desc 'Compile JavaScript'
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
desc 'Concat AngularJS files'
task :concat => :init do
concat_file('angular.js', [ concat_file('angular.js', [
'src/angular.prefix', 'src/angular.prefix',
files['angularSrc'], files['angularSrc'],
@ -98,133 +108,139 @@ task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js') FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
closure_compile('angular.js') rewrite_file(path_to('angular-mocks.js')) do |content|
closure_compile('angular-cookies.js') content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
closure_compile('angular-loader.js') end
closure_compile('angular-resource.js') end
closure_compile('angular-sanitize.js')
closure_compile('angular-bootstrap.js')
closure_compile('angular-bootstrap-prettify.js')
desc 'Minify JavaScript'
task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter] do
[ 'angular.js',
'angular-cookies.js',
'angular-loader.js',
'angular-resource.js',
'angular-sanitize.js',
'angular-bootstrap.js',
'angular-bootstrap-prettify.js'
].each do |file|
fork { closure_compile(file) }
end
Process.waitall
end
desc 'Generate version.txt file'
task :version => [:init] do
`echo #{NG_VERSION.full} > #{path_to('version.txt')}`
end end
desc 'Generate docs' desc 'Generate docs'
task :docs => [:init] do task :docs => [:init] do
`node docs/src/gen-docs.js` `node docs/src/gen-docs.js`
rewrite_file(path_to('docs/.htaccess')) do |content|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full) [ path_to('docs/.htaccess'),
path_to('docs/index.html'),
path_to('docs/index-debug.html'),
path_to('docs/index-nocache.html'),
path_to('docs/index-jq.html'),
path_to('docs/index-jq-debug.html'),
path_to('docs/index-jq-nocache.html'),
path_to('docs/docs-scenario.html')
].each do |src|
rewrite_file(src) do |content|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full).
sub('"NG_VERSION_STABLE"', NG_VERSION.stable)
end
end end
end end
desc 'Create angular distribution' desc 'Create angular distribution'
task :package => [:clean, :compile, :docs] do task :package => [:clean, :minify, :version, :docs] do
tarball = "angular-#{NG_VERSION.full}.tgz" zip_dir = "angular-#{NG_VERSION.full}"
zip_file = "#{zip_dir}.zip"
pkg_dir = path_to("pkg/angular-#{NG_VERSION.full}") FileUtils.ln_s BUILD_DIR, zip_dir
FileUtils.rm_r(path_to('pkg'), :force => true) %x(zip -r #{zip_file} #{zip_dir})
FileUtils.mkdir_p(pkg_dir) FileUtils.rm zip_dir
[ path_to('angular.js'), FileUtils.mv zip_file, path_to(zip_file)
path_to('angular.min.js'),
path_to('angular-loader.js'), puts "Package created: #{path_to(zip_file)}"
path_to('angular-loader.min.js'), end
path_to('angular-bootstrap.js'),
path_to('angular-bootstrap.min.js'),
path_to('angular-bootstrap-prettify.js'), desc 'Start development webserver'
path_to('angular-bootstrap-prettify.min.js'), task :webserver, :port do |t, args|
path_to('angular-mocks.js'), exec "node lib/nodeserver/server.js #{args[:port]}"
path_to('angular-cookies.js'), end
path_to('angular-cookies.min.js'),
path_to('angular-resource.js'),
path_to('angular-resource.min.js'), desc 'Run all AngularJS tests'
path_to('angular-sanitize.js'), task :test, :browsers, :misc_options do |t, args|
path_to('angular-sanitize.min.js'), [ 'test:jqlite',
path_to('angular-scenario.js'), 'test:jquery',
path_to('jstd-scenario-adapter.js'), 'test:modules',
path_to('jstd-scenario-adapter-config.js'), 'test:e2e'
].each do |src| ].each do |task|
dest = src.gsub(/^.*\//, '').gsub(/((\.min)?\.js)$/, "-#{NG_VERSION.full}\\1") Rake::Task[task].invoke(args[:browsers], args[:misc_options])
FileUtils.cp(src, pkg_dir + '/' + dest)
end
FileUtils.cp_r path_to('i18n'), "#{pkg_dir}/i18n-#{NG_VERSION.full}"
FileUtils.cp_r path_to('docs'), "#{pkg_dir}/docs-#{NG_VERSION.full}"
rewrite_file("#{pkg_dir}/angular-mocks-#{NG_VERSION.full}.js") do |content|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
end end
end
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/index.html", namespace :test do
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq.html",
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-nocache.html", desc 'Run all unit tests (single run)'
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-nocache.html", task :unit, :browsers, :misc_options do |t, args|
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-debug.html", [ 'test:jqlite',
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-debug.html" 'test:jquery',
].each do |src| 'test:modules'
rewrite_file(src) do |content| ].each do |task|
content.gsub!(/'angular(.*)\.js/, '\'angular\1-' + NG_VERSION.full + '.js') Rake::Task[task].invoke(args[:browsers], args[:misc_options])
end end
end end
rewrite_file("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html") do |content| desc 'Run jqLite-based unit test suite (single run)'
content.sub!('angular-scenario.js', "angular-scenario-#{NG_VERSION.full}.js") task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', true, args[:browsers], args[:misc_options])
end end
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/appcache.manifest", desc 'Run jQuery-based unit test suite (single run)'
"#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest" task :jquery, :browsers, :misc_options do |t, args|
].each do |src| start_testacular('testacular-jquery.conf.js', true, args[:browsers], args[:misc_options])
rewrite_file(src) do |content|
content.sub!('../angular.min.js', "angular-#{NG_VERSION.full}.min.js").
sub!('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/")
end
end end
%x(tar -czf #{path_to(tarball)} -C #{path_to('pkg')} .) desc 'Run bundled modules unit test suite (single run)'
task :modules, :browsers, :misc_options do |t, args|
FileUtils.cp path_to(tarball), pkg_dir start_testacular('testacular-modules.conf.js', true, args[:browsers], args[:misc_options])
FileUtils.mv pkg_dir, path_to(['pkg', NG_VERSION.full])
puts "Package created: #{path_to(tarball)}"
end
namespace :server do
desc 'Run JsTestDriver Server'
task :start do
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
end end
desc 'Run JavaScript tests against the server'
task :test do desc 'Run e2e test suite (single run)'
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all) task :e2e, :browsers, :misc_options do |t, args|
start_testacular('testacular-e2e.conf.js', true, args[:browsers], args[:misc_options])
end
end
namespace :autotest do
desc 'Run jqLite-based unit test suite (autowatch)'
task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', false, args[:browsers], args[:misc_options])
end end
end
desc 'Run jQuery-based unit test suite (autowatch)'
desc 'Run JavaScript tests' task :jquery, :browsers, :misc_options do |t, args|
task :test do start_testacular('testacular-jquery.conf.js', false, args[:browsers], args[:misc_options])
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876) end
end
desc 'Lint'
task :lint do
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
print out
end
desc 'push_angularjs'
task :push_angularjs => :compile do
sh %(cat angularjs.ftp | ftp -N angularjs.netrc angularjs.org)
end end
@ -271,11 +287,14 @@ end
def closure_compile(filename) def closure_compile(filename)
puts "Compiling #{filename} ..." puts "Minifying #{filename} ..."
min_path = path_to(filename.gsub(/\.js$/, '.min.js')) min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
%x(java -jar lib/closure-compiler/compiler.jar \ %x(java \
-client \
-d32 \
-jar lib/closure-compiler/compiler.jar \
--compilation_level SIMPLE_OPTIMIZATIONS \ --compilation_level SIMPLE_OPTIMIZATIONS \
--language_in ECMASCRIPT5_STRICT \ --language_in ECMASCRIPT5_STRICT \
--js #{path_to(filename)} \ --js #{path_to(filename)} \
@ -289,7 +308,7 @@ end
def concat_file(filename, deps, footer='') def concat_file(filename, deps, footer='')
puts "Building #{filename} ..." puts "Creating #{filename} ..."
File.open(path_to(filename), 'w') do |f| File.open(path_to(filename), 'w') do |f|
concat = 'cat ' + deps.flatten.join(' ') concat = 'cat ' + deps.flatten.join(' ')
@ -326,3 +345,12 @@ def rewrite_file(filename)
f.write content f.write content
end end
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

54
angularFiles.js vendored
View file

@ -196,36 +196,30 @@ angularFiles = {
] ]
}; };
// Execute only in slim-jim if (exports) {
if (typeof JASMINE_ADAPTER !== 'undefined') { exports.files = angularFiles
// Testacular config exports.mergeFiles = function mergeFiles() {
var mergedFiles = []; var files = [];
angularFiles.jstd.forEach(function(file) {
// replace @ref [].splice.call(arguments, 0).forEach(function(file) {
var match = file.match(/^\@(.*)/); if (file.match(/testacular/)) {
if (match) { files.push(file);
var deps = angularFiles[match[1]]; } else {
if (!deps) { angularFiles[file].forEach(function(f) {
console.log('No dependency:' + file) // replace @ref
var match = f.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
files = files.concat(deps);
} else {
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
files.push(f);
}
}
});
} }
mergedFiles = mergedFiles.concat(deps); });
} else {
mergedFiles.push(file);
}
});
files = [JASMINE, JASMINE_ADAPTER]; return files;
}
mergedFiles.forEach(function(file){
if (/jstd|jasmine/.test(file)) return;
files.push(file);
});
exclude = angularFiles.jstdExclude;
autoWatch = true;
autoWatchInterval = 1;
logLevel = LOG_INFO;
logColors = true;
} }

View file

@ -1,5 +0,0 @@
bin
cd angularjs.org/ng
put angular-debug.js js/angular-debug.js
put angular-minified.js js/angular-minified.js
put angular-scenario.js js/angular-scenario.js

View file

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
rake compile rake minify
gzip -c < build/angular.min.js > build/angular.min.js.gzip gzip -c < build/angular.min.js > build/angular.min.js.gzip
ls -l build/angular.min.* ls -l build/angular.min.*

View file

@ -2,6 +2,6 @@
@name API Reference @name API Reference
@description @description
Use the API Refference documentation when you need more information about a specific feature. Check out Use the API Reference documentation when you need more information about a specific feature. Check out
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the {@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
{@link tutorial/ Tutorial}. {@link tutorial/ Tutorial}.

View file

@ -24,8 +24,8 @@ initialization.
</html> </html>
</pre> </pre>
* Place the `script` tag at the buttom of the page. Placing script tags at the end of the page * Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
improves app load time becouse the HTML loading is not blocked by loading of the `angular.js` improves app load time because the HTML loading is not blocked by loading of the `angular.js`
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
your production code to this URL, as it will expose a security hole on your site. For your production code to this URL, as it will expose a security hole on your site. For
experimental development linking to our site is fine. experimental development linking to our site is fine.
@ -34,12 +34,12 @@ initialization.
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in * Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
production. production.
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want * Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
anugular to auto-bootstrap your application. angular to auto-bootstrap your application.
<html ng-app> <html ng-app>
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html` * If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
to make IE happy. (This is here for historical resons, and we no longer recomend use of to make IE happy. (This is here for historical reasons, and we no longer recommend use of
`ng:`.) `ng:`.)
<html xmlns:ng="http://angularjs.org"> <html xmlns:ng="http://angularjs.org">

View file

@ -7,7 +7,7 @@
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
and even create new HTML element or attributes with custom behavior. Angular calls these behavior and even create new HTML element or attributes with custom behavior. Angular calls these behavior
extensions {@link api/ng.$compileProvider.directive directives}. extensions {@link api/ng.$compileProvider#directive directives}.
HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion. HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion.
For example if something needs to be centered, there is no need to provide instructions to the For example if something needs to be centered, there is no need to provide instructions to the
@ -60,7 +60,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
</pre> </pre>
Directive is just a function which executes when the compiler encounters it in the DOM. See {@link Directive is just a function which executes when the compiler encounters it in the DOM. See {@link
api/ng.$compileProvider.directive directive API} for in depth documentation on how api/ng.$compileProvider#directive directive API} for in-depth documentation on how
to write directives. to write directives.
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the Here is a directive which makes any element draggable. Notice the `draggable` attribute on the

View file

@ -0,0 +1,467 @@
@ngdoc overview
@name Conceptual Overview
@description
# Overview
This document gives a quick overview of the main angular components and how they work together.
These are:
* {@link concepts#startup startup} - bring up hello world
* {@link concepts#runtime runtime} - overview of angular runtime
* {@link concepts#scope scope} - the glue between the view and the controller
* {@link concepts#controller controller} - application behavior
* {@link concepts#model model} - your application data
* {@link concepts#view view} - what the user sees
* {@link concepts#directives directives} - extend HTML vocabulary
* {@link concepts#filters filters} - format the data in user locale
* {@link concepts#injector injector} - assembles your application
* {@link concepts#module module} - configures the injector
* {@link concepts#angular_namespace `$`} - angular namespace
<a name="startup"></a>
# Startup
This is how we get the ball rolling (refer to the diagram and example below):
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
1. Browser loads the HTML and parses it into a DOM
2. Browser loads `angular.js` script
3. Angular waits for `DOMContentLoaded` event
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
{@link guide/directive directive}, which designates application boundary
5. {@link guide/module Module} specified in {@link
api/ng.directive:ngApp ng-app} (if any) is used to configure
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
it with {@link api/ng.$rootScope $rootScope}
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
`Hello World!`
<div class="clear">
</div>
<example>
<file name="index.html">
<p ng-init=" name='World' ">Hello {{name}}!</p>
</file>
</example>
<a name="runtime"></a>
# Runtime
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
The diagram and the example below describe how Angular interacts with browser's event loop.
1. Browsers event-loop waits for an event to arrive. Event is a user interactions, timer event,
or network event (response from a server).
2. The events callback gets executed. This enters the JavaScript context. The callback can
modify the DOM structure.
3. Once the callback finishes execution, the browser leaves the JavaScript context and
re-renders the view based on DOM changes.
Angular modifies the normal JavaScript flow by providing it's own event processing loop. This
splits the JavaScript into classical and Angular execution context. Only operations which are
applied in Angular execution context will benefit from angular data-binding, exception handling,
property watching, etc... Use $apply() to enter Angular execution context from JavaScript. Keep in
mind that in most places (controllers, services) the $apply has already been called for you by the
directive which is handling the event. The need to call $apply is reserved only when
implementing custom event callbacks, or when working with a third-party library callbacks.
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
stabilizes, which means that the {@link api/ng.$rootScope.Scope#$evalAsync
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
$watch} list does not detect any changes.
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
schedule work which needs to occur outside of current stack frame, but before the browser
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
suffers from slowness and may cause view flickering since the browser renders the view after
each event.
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
which may have changed since last iteration. If a change is detected then the `$watch`
function is called which typically updates the DOM with the new value.
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
Here is the explanation of how the `Hello wold` example achieves the data-binding effect when the
user enters text into the text field.
1. During the compilation phase:
1. the {@link api/ng.directive:ngModel ng-model} and {@link
api/ng.directive:input input} {@link guide/directive
directive} set up a `keydown` listener on the `<input>` control.
2. the {@link api/ng.$interpolate &#123;&#123;name&#125;&#125; } interpolation
sets up a {@link api/ng.$rootScope.Scope#$watch $watch} to be notified of
`name` changes.
2. During the runtime phase:
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
2. The {@link api/ng.directive:input input} directive
captures the change to the input's value and calls {@link
api/ng.$rootScope.Scope#$apply $apply}`("name = 'X';")` to update the
application model inside the Angular execution context.
3. Angular applies the `name = 'X';` to the model.
4. The {@link api/ng.$rootScope.Scope#$digest $digest} loop begins
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#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
the JavaScript execution context.
7. The browser re-renders the view with update text.
<div class="clear">
</div>
<example>
<file name="index.html">
<input ng-model="name">
<p>Hello {{name}}!</p>
</file>
</example>
<a name="scope"></a>
#Scope
The {@link guide/scope scope} is responsible for detecting changes to the model section and
provides the execution context for expressions. The scopes are nested in a hierarchical structure
which closely follow the DOM structure. (See individual directive documentation to see which
directives cause a creation of new scopes.)
The following example demonstrates how `name` {@link guide/expression expression} will evaluate
into different value depending on which scope it is evaluated in. The example is followed by
a diagram depicting the scope boundaries.
<div class="clear">
</div>
<div class="show-scope">
<example>
<file name="index.html">
<div ng-controller="GreetCtrl">
Hello {{name}}!
</div>
<div ng-controller="ListCtrl">
<ol>
<li ng-repeat="name in names">{{name}}</li>
</ol>
</div>
</file>
<file name="script.js">
function GreetCtrl($scope) {
$scope.name = 'World';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
</file>
<file name="style.css">
.show-scope .doc-example-live.ng-scope,
.show-scope .doc-example-live .ng-scope {
border: 1px solid red;
margin: 3px;
}
</file>
</example>
</div>
<img class="center" src="img/guide/concepts-scope.png">
<a name="controller"></a>
# Controller
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
Controller is the code behind the view. Its job is to construct the model and publish it to the
view along with callback methods. The view is a projection of the scope onto the template (the
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
controller.
The separation of the controller and the view is important because:
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
for specifying application behavior. The controller should not contain any rendering
information (DOM references or HTML fragments).
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
specifying UI. The View should not contain any behavior.
* Since the controller is unaware of the view, there could be many views for the same
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
and testability.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-controller="MyCtrl">
Hello {{name}}!
<button ng-click="action()">
OK
</button>
</div>
</file>
<file name="script.js">
function MyCtrl($scope) {
$scope.action = function() {
$scope.name = 'OK';
}
$scope.name = 'World';
}
</file>
</example>
<a name="model"></a>
# Model
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
The model is the data which is used merged with the template to produce the view. To be able to
render the model into the view, the model has to be referenceable from the scope. Unlike many
other frameworks Angular makes no restrictions or requirements an the model. There are no classes
to inherit from or special accessor methods for accessing or changing the model. The model can be
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
<div class="clear">
</div>
<a name="view"></a>
# View
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
The view is what the 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.
* **Others** - Most templating systems begin as an HTML string with special templating markup.
Often the template markup breaks the HTML syntax which means that the template can not be
edited by an HTML editor. The template string is then parsed by the template engine, and
merged with the data. The result of the merge is an HTML string. The HTML string is then
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
When the model changes the whole process needs to be repeated. The granularity of the template
is the granularity of the DOM updates. The key here is that the templating system manipulates
strings.
* **Angular** - Angular is different, since its templating system works on DOM objects not on
strings. The template is still written in 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
the single source-of-truth for your view.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
<input ng-model="list" ng-list> <br>
<input ng-model="list" ng-list> <br>
<pre>list={{list}}</pre> <br>
<ol>
<li ng-repeat="item in list">
{{item}}
</li>
</ol>
</div>
</file>
</example>
<a name="directives"></a>
# Directives
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute,
element name, or a class name. A directive allows you to extend the HTML vocabulary in a
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
in HTML.
<example module="directive">
<file name="script.js">
angular.module('directive', []).directive('contenteditable', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
// view -> model
elm.bind('blur', function() {
scope.$apply(function() {
ctrl.$setViewValue(elm.html());
});
});
// model -> view
ctrl.render = function(value) {
elm.html(value);
};
// load init value from DOM
ctrl.$setViewValue(elm.html());
}
};
});
</file>
<file name="index.html">
<div contentEditable="true" ng-model="content">Edit Me</div>
<pre>model = {{content}}</pre>
</file>
<file name="style.css">
div[contentEditable] {
cursor: pointer;
background-color: #D0D0D0;
margin-bottom: 1em;
padding: 1em;
}
</file>
</example>
<a name="filters"></a>
# Filters
{@link api/ng.$filter Filters} perform data transformation 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).
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
Number formatting: {{ 1234567890 | number }} <br>
array filtering <input ng-model="predicate">
{{ list | filter:predicate | json }}
</div>
</file>
</example>
<a name="module"></a>
<a name="injector"></a>
# Modules and the Injector
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
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
object name result in the same instance. If the object does not exist, then the {@link
api/AUTO.$injector injector} asks the instance factory to create a new instance.
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
as a {@link api/AUTO.$provide provider}.
<div class='clear'></div>
<pre>
// Create a module
var myModule = angular.module('myModule', [])
// Configure the injector
myModule.factory('serviceA', function() {
return {
// instead of {}, put your object creation here
};
});
// create an injector and configure it from 'myModule'
var $injector = angular.injector(['myModule']);
// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');
// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');
</pre>
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
used to {@link api/AUTO.$injector#invoke call} methods and {@link
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
allows the methods and types to ask for their dependencies instead of having to look for them.
<pre>
// You write functions such as this one.
function doSomething(serviceA, serviceB) {
// do something here.
}
// Angular provides the injector for your application
var $injector = ...;
///////////////////////////////////////////////
// the old-school way of getting dependencies.
var serviceA = $injector.get('serviceA');
var serviceB = $injector.get('serviceB');
// now call the function
doSomething(serviceA, serviceB);
///////////////////////////////////////////////
// the cool way of getting dependencies.
// the $injector will supply the arguments to the function automatically
$injector.invoke(doSomething); // This is how the framework calls your functions
</pre>
Notice that the only thing you needed to write was the function, and list the dependencies in the
function arguments. When angular calls the function, it will use the {@link
api/AUTO.$injector#invoke call} which will automatically fill the function
arguments.
Examine the `ClockCtrl` bellow, and notice how it lists the dependencies in the constructor. When the
{@link api/ng.directive:ngController ng-controller} instantiates
the controller it automatically provides the dependencies. There is no need to create
dependencies, look for dependencies, or even get a reference to the injector.
<example module="timeExampleModule">
<file name="index.html">
<div ng-controller="ClockCtrl">
Current time is: {{ time.now }}
</div>
</file>
<file name="script.js">
angular.module('timeExampleModule', []).
// Declare new object call time,
// which will be available for injection
factory('time', function($timeout) {
var time = {};
(function tick() {
time.now = new Date().toString();
$timeout(tick, 1000);
})();
return time;
});
// Notice that you can simply ask for time
// and it will be provided. No need to look for it.
function ClockCtrl($scope, time) {
$scope.time = time;
}
</file>
</example>
<a name="angular_namespace"></a>
# Angular Namespace
To prevent accidental name collision, Angular prefixes names of objects which could potentially
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
with Angular code.

View file

@ -122,7 +122,7 @@ Returns the current value of an input field with the given `name`.
## repeater(selector, label).count() ## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
used for test ouput. used for test output.
## repeater(selector, label).row(index) ## repeater(selector, label).row(index)
Returns an array with the bindings in the row at the given `index` in the repeater matching the Returns an array with the bindings in the row at the given `index` in the repeater matching the

View file

@ -253,7 +253,7 @@ describe('state', function() {
var mainCtrl = $controller(MainCtrl, {$scope: mainScope}); var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
childScope = mainScope.$new(); childScope = mainScope.$new();
var childCtrl = $controller(ChildCtrl, {$scope: childScope}); var childCtrl = $controller(ChildCtrl, {$scope: childScope});
babyScope = $rootScope.$new(); babyScope = childCtrl.$new();
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope}); var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
})); }));

View file

@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
## Comparing $location to window.location ## Comparing $location to window.location
<table> <table class="table">
<thead> <thead>
<tr> <tr>
<td class="empty-corner-lt"></td> <th class="empty-corner-lt"></th>
<td>window.location</td> <th>window.location</th>
<td>$location service</td> <th>$location service</th>
</tr> </tr>
</thead> </thead>
@ -165,13 +165,13 @@ facilitate the browser URL change and history management.
<img src="img/guide/hashbang_vs_regular_url.jpg"> <img src="img/guide/hashbang_vs_regular_url.jpg">
<table> <table class="table">
<thead> <thead>
<tr> <tr>
<td class="empty-corner-lt"></td> <th class="empty-corner-lt"></th>
<td>Hashbang mode</td> <th>Hashbang mode</th>
<td>HTML5 mode</td> <th>HTML5 mode</th>
</tr> </tr>
</thead> </thead>
@ -331,11 +331,11 @@ to entry point of your application (e.g. index.html)
### Crawling your app ### Crawling your app
If you want your AJAX application to be indexed by web crawlers, you rill need to add the following If you want your AJAX application to be indexed by web crawlers, you will need to add the following
meta tag to the HEAD section of your document: meta tag to the HEAD section of your document:
<pre><meta name="fragment" content="!" /></pre> <pre><meta name="fragment" content="!" /></pre>
This statement causes a crawler to request links with empty `_escaped_fragment_` parameter so that This statement causes a crawler to request links with an empty `_escaped_fragment_` parameter so that
your server can recognize the crawler and serve it HTML snapshots. For more information about this your server can recognize the crawler and serve it HTML snapshots. For more information about this
technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX
Applications Crawlable}. Applications Crawlable}.
@ -543,69 +543,73 @@ then uses the information it obtains to compose hashbang URLs (such as
## Changes to your code ## Changes to your code
<table> <table class="table">
<tr class="head"> <thead>
<td>Navigation inside the app</td> <tr class="head">
<td>Change to</td> <th>Navigation inside the app</th>
</tr> <th>Change to</th>
</tr>
</thead>
<tr> <tbody>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br <tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
/>$location.updateHash(value)</td> />$location.updateHash(value)</td>
<td>$location.path(path).search(search)</td> <td>$location.path(path).search(search)</td>
</tr> </tr>
<tr> <tr>
<td>$location.hashPath = path</td> <td>$location.hashPath = path</td>
<td>$location.path(path)</td> <td>$location.path(path)</td>
</tr> </tr>
<tr> <tr>
<td>$location.hashSearch = search</td> <td>$location.hashSearch = search</td>
<td>$location.search(search)</td> <td>$location.search(search)</td>
</tr> </tr>
<tr class="head"> <tr class="head">
<td>Navigation outside the app</td> <td>Navigation outside the app</td>
<td>Use lower level API</td> <td>Use lower level API</td>
</tr> </tr>
<tr> <tr>
<td>$location.href = value<br />$location.update(value)</td> <td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td> <td>$window.location.href = value</td>
</tr> </tr>
<tr> <tr>
<td>$location[protocol | host | port | path | search]</td> <td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td> <td>$window.location[protocol | host | port | path | search]</td>
</tr> </tr>
<tr class="head"> <tr class="head">
<td>Read access</td> <td>Read access</td>
<td>Change to</td> <td>Change to</td>
</tr> </tr>
<tr> <tr>
<td>$location.hashPath</td> <td>$location.hashPath</td>
<td>$location.path()</td> <td>$location.path()</td>
</tr> </tr>
<tr> <tr>
<td>$location.hashSearch</td> <td>$location.hashSearch</td>
<td>$location.search()</td> <td>$location.search()</td>
</tr> </tr>
<tr> <tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br <td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
/>$location.hash</td> />$location.hash</td>
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br <td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
/>$location.path() + $location.search()</td> />$location.path() + $location.search()</td>
</tr> </tr>
<tr> <tr>
<td>$location.path<br />$location.search</td> <td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td> <td>$window.location.path<br />$window.location.search</td>
</tr> </tr>
</tbody>
</table> </table>
## Two-way binding to $location ## Two-way binding to $location

View file

@ -2,12 +2,12 @@
@name Developer Guide: Angular Services: Creating Services @name Developer Guide: Angular Services: Creating Services
@description @description
While angular offers several useful services, for any nontrivial application you'll find it useful While Angular offers several useful services, for any nontrivial application you'll find it useful
to write your own custom services. To do this you begin by registering a service factory function to write your own custom services. To do this you begin by registering a service factory function
with a module either via the {@link api/angular.module Module#factory api} or directly with a module either via the {@link api/angular.module Module#factory api} or directly
via the {@link api/AUTO.$provide $provide} api inside of module config function. via the {@link api/AUTO.$provide $provide} api inside of module config function.
All angular services participate in {@link di dependency injection (DI)} by registering All Angular services participate in {@link di dependency injection (DI)} by registering
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
dependencies which need to be provided for the factory function of the registered service. The dependencies which need to be provided for the factory function of the registered service. The
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
@ -76,17 +76,17 @@ angular.module('myModule', [], function($provide) {
# Instantiating Angular Services # Instantiating Angular Services
All services in Angular are instantiates services lazily, this means that a service will be created All services in Angular are instantiated lazily. This means that a service will be created
only when it is needed for instantiation of a service or an application component that depends on it. only when it is needed for instantiation of a service or an application component that depends on it.
In other words, angular won't instantiate lazy services unless they are requested directly or In other words, Angular won't instantiate lazy services unless they are requested directly or
indirectly by the application. indirectly by the application.
# Services as singletons # Services as singletons
Lastly, it is important to realize that all angular services are application singletons. This means Lastly, it is important to realize that all Angular services are application singletons. This means
that there is only one instance of a given service per injector. Since angular is lethally allergic that there is only one instance of a given service per injector. Since Angular is lethally allergic
to the global state, it is possible to create multiple injectors, each with its own instance of a to global state, it is possible to create multiple injectors, each with its own instance of a
given service, but that is rarely needed, except in tests where this property is crucially given service, but that is rarely needed, except in tests where this property is crucially
important. important.

View file

@ -2,7 +2,7 @@
@name Developer Guide: Angular Services: Testing Angular Services @name Developer Guide: Angular Services: Testing Angular Services
@description @description
Following is a unit test for the service in the example in {@link The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
spy (mock) instead of a real browser alert. spy (mock) instead of a real browser alert.
@ -55,7 +55,7 @@ it('should clear messages after alert', function() {
* {@link dev_guide.services.understanding_services Understanding Angular Services} * {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services} * {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} * {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers} * {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
## Related API ## Related API

View file

@ -9,7 +9,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
* `ng-invalid`, `ng-valid` * `ng-invalid`, `ng-valid`
- **Usage:** angular applies this class to an input widget element if that element's input does - **Usage:** angular applies this class to an input widget element if that element's input does
notpass validation. (see {@link api/ng.directive:input input} directive). not pass validation. (see {@link api/ng.directive:input input} directive).
* `ng-pristine`, `ng-dirty` * `ng-pristine`, `ng-dirty`
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class - **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class

View file

@ -24,7 +24,7 @@ because first the template (which is the uncompiled HTML along with any addition
directives) is compiled on the browser, and second, the compilation step produces a live view. We directives) is compiled on the browser, and second, the compilation step produces a live view. We
say live because any changes to the view are immediately reflected in the model, and any changes in say live because any changes to the view are immediately reflected in the model, and any changes in
the model are propagated to the view. This makes the model always the single-source-of-truth for the model are propagated to the view. This makes the model always the single-source-of-truth for
the application state, greatly simplifying the programing model for the developer. You can think of the application state, greatly simplifying the programming model for the developer. You can think of
the view as simply an instant projection of your model. the view as simply an instant projection of your model.
Because the view is just a projection of the model, the controller is completely separated from the Because the view is just a projection of the model, the controller is completely separated from the

View file

@ -14,9 +14,6 @@ displaying it to the user. You can pass expressions through a chain of filters l
The expression evaluator simply passes the value of name to The expression evaluator simply passes the value of name to
{@link api/ng.filter:uppercase uppercase filter}. {@link api/ng.filter:uppercase uppercase filter}.
In addition to formatting data, filters can also modify the DOM. This allows filters to handle
tasks such as conditionally applying CSS styles to filtered output.
## Related Topics ## Related Topics

View file

@ -16,7 +16,7 @@ this may seem obvious it usually is very difficult to be able to call an individ
typical project. The reason is that the developers often time mix concerns, and they end up with a typical project. The reason is that the developers often time mix concerns, and they end up with a
piece of code which does everything. It reads the data from XHR, it sorts it and then it piece of code which does everything. It reads the data from XHR, it sorts it and then it
manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we
provide dependency injection for your XHR (which you can mock out) and we crated abstraction which provide dependency injection for your XHR (which you can mock out) and we created abstraction which
allow you to sort your model without having to resort to manipulating the DOM. So that in the end, allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
it is easy to write a sort function which sorts some data, so that your test can create a data set, it is easy to write a sort function which sorts some data, so that your test can create a data set,
apply the function, and assert that the resulting model is in the correct order. The test does not apply the function, and assert that the resulting model is in the correct order. The test does not

View file

@ -165,7 +165,7 @@ For example:
}); });
</pre> </pre>
Results in code bloat do to the need of temporary variable: Results in code bloat due to the need of temporary variable:
<pre> <pre>
var greeterFactory = function(renamed$window) { var greeterFactory = function(renamed$window) {
...; ...;

View file

@ -10,7 +10,7 @@ can be extended such that HTML can be turned into a declarative domain specific
# Invoking directives from HTML # Invoking directives from HTML
Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating Directives have camel cased names such as `ngBind`. The directive can be invoked by translating
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
@ -63,7 +63,7 @@ api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is sh
here: here:
<pre> <pre>
<img src="img/{{username}}.jpg">Hello {{username}}!</img> <a href="img/{{username}}.jpg">Hello {{username}}!</a>
</pre> </pre>
# Compilation process, and directive matching # Compilation process, and directive matching
@ -74,7 +74,7 @@ Compilation of HTML happens in three phases:
realize because the templates must be parsable HTML. This is in contrast to most templating realize because the templates must be parsable HTML. This is in contrast to most templating
systems that operate on strings, rather than on DOM elements. systems that operate on strings, rather than on DOM elements.
2. The compilation of the DOM is performed by the call to {@link api/ng.$compile 2. The compilation of the DOM is performed by the call to the {@link api/ng.$compile
$compile()} method. The method traverses the DOM and matches the directives. If a match is found $compile()} method. The method traverses the DOM and matches the directives. If a match is found
it is added to the list of directives associated with the given DOM element. Once all directives it is added to the list of directives associated with the given DOM element. Once all directives
for a given DOM element have been identified they are sorted by priority and their `compile()` for a given DOM element have been identified they are sorted by priority and their `compile()`
@ -109,8 +109,8 @@ Compilation of HTML happens in three phases:
## Reasons behind the compile/link separation ## Reasons behind the compile/link separation
At this point you may wonder why is the compile process broken down to a compile and link phase. At this point you may wonder why the compile process is broken down to a compile and link phase.
To understand this, lets look at a real world example with repeater: To understand this, let's look at a real world example with repeater:
<pre> <pre>
Hello {{user}}, you have these actions: Hello {{user}}, you have these actions:
@ -125,7 +125,7 @@ The short answer is that compile and link separation is needed any time a change
a change in DOM structure such as in repeaters. a change in DOM structure such as in repeaters.
When the above example is compiled, the compiler visits every node and looks for directives. The When the above example is compiled, the compiler visits every node and looks for directives. The
`{{user}}` is an example of {@link api/ng.$interpolate interpolation} directive. {@link `{{user}}` is an example of an {@link api/ng.$interpolate interpolation} directive. {@link
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
@ -138,16 +138,16 @@ But compiling on every `li` element clone would be slow, since the compilation r
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
repeater which needs to unroll 100 items we would quickly run into performance problems. repeater which needs to unroll 100 items we would quickly run into performance problems.
The solution is to break the compilation process into two phases the compile phase where all of The solution is to break the compilation process into two phases; the compile phase where all of
the directives are identified and sorted by priority, and a linking phase where any work which the directives are identified and sorted by priority, and a linking phase where any work which
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
instance of an `li` is performed. instance of an `li` is performed.
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the {@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
compilation process form descending into `li` element. Instead the {@link compilation process form descending into the `li` element. Instead the {@link
api/ng.directive:ngRepeat ngRepeat} directive compiles `li` api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
separately. The result of of the `li` element compilation is a linking function which contains all separately. The result of of the `li` element compilation is a linking function which contains all
of the directives contained in the `li` element ready to be attached to a specific clone of `li` of the directives contained in the `li` element, ready to be attached to a specific clone of the `li`
element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat} element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat}
watches the expression and as items are added to the array it clones the `li` element, creates a watches the expression and as items are added to the array it clones the `li` element, creates a
new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the
@ -156,18 +156,18 @@ link function on the cloned `li`.
Summary: Summary:
* *compile function* - The compile function is relatively rare in directives, since most * *compile function* - The compile function is relatively rare in directives, since most
directives are concerned with working with a specific DOM element instance rather then directives are concerned with working with a specific DOM element instance rather than
transforming the template DOM element. Any operation which can be shared among the instance of transforming the template DOM element. Any operation which can be shared among the instance of
directives should be moved to the compile function for performance reasons. directives should be moved to the compile function for performance reasons.
* *link function* - It is rare for the directive not to have a link function. Link function * *link function* - It is rare for the directive not to have a link function. A link function
allows the directive to register listeners to the specific cloned DOM element instance as well allows the directive to register listeners to the specific cloned DOM element instance as well
as to copy content into the DOM from the scope. as to copy content into the DOM from the scope.
# Writing directives (short version) # Writing directives (short version)
In this example we will build a directive which displays the current time. In this example we will build a directive that displays the current time.
<doc:example module="time"> <doc:example module="time">
<doc:source> <doc:source>
@ -211,17 +211,15 @@ In this example we will build a directive which displays the current time.
$timeout.cancel(timeoutId); $timeout.cancel(timeoutId);
}); });
updateLater(); // kick of the UI update process. updateLater(); // kick off the UI update process.
} }
}); });
</script> </script>
<div ng-controller="Ctrl2"> <div ng-controller="Ctrl2">
Date format: <input ng-model='format'> <hr/> Date format: <input ng-model="format"> <hr/>
Current time is: <span my-current-time="format"></span> Current time is: <span my-current-time="format"></span>
</div> </div>
</doc:source> </doc:source>
<doc:scenario>
</doc:scenario>
</doc:example> </doc:example>
@ -255,9 +253,9 @@ An example skeleton of the directive is shown here, for the complete list see be
In most cases you will not need such fine control and so the above can be simplified. All of the In most cases you will not need such fine control and so the above can be simplified. All of the
different parts of this skeleton are explained in following sections. In this section we are different parts of this skeleton are explained in following sections. In this section we are
interested only isomers of this skeleton. interested only in some of this skeleton.
The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be The first step in simplyfing the code is to rely on the default values. Therefore the above can be
simplified as: simplified as:
<pre> <pre>
@ -273,7 +271,7 @@ simplified as:
}); });
</pre> </pre>
Most directives concern themselves only with instances not with template transformations allowing Most directives concern themselves only with instances, not with template transformations, allowing
further simplification: further simplification:
<pre> <pre>
@ -290,7 +288,7 @@ further simplification:
The factory method is responsible for creating the directive. It is invoked only once, when the The factory method is responsible for creating the directive. It is invoked only once, when the
{@link api/ng.$compile compiler} matches the directive for the first time. You can {@link api/ng.$compile compiler} matches the directive for the first time. You can
perform any initialization work here. The method is invoked using the {@link perform any initialization work here. The method is invoked using the {@link
http://localhost:8000/build/docs/api/AUTO.$injector#invoke $injector.invoke} which api/AUTO.$injector#invoke $injector.invoke} which
makes it injectable following all of the rules of injection annotation. makes it injectable following all of the rules of injection annotation.
## Directive Definition Object ## Directive Definition Object
@ -316,42 +314,44 @@ compiler}. The attributes are:
apply for the root of the template since the root of the template always gets a new scope. apply for the root of the template since the root of the template always gets a new scope.
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from * `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
normal scope that it does not prototypically inherit from the parent scope. This is useful normal scope in that it does not prototypically inherit from the parent scope. This is useful
when creating reusable components, which should not accidentally read or modify data in when creating reusable components, which should not accidentally read or modify data in the
parent scope. <br/> parent scope. <br/>
The 'isolate' scope takes an object hash which defines a set of local scope properties The 'isolate' scope takes an object hash which defines a set of local scope properties
derived from the parent scope. These local properties are useful for aliasing values for derived from the parent scope. These local properties are useful for aliasing values for
templates. Locals definition is a hash of local scope property to its source: templates. Locals definition is a hash of local scope property to its source:
* `@` or `@attr` - bind a local scope property to the DOM attribute. The result is always a * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
string since DOM attributes are strings. If no `attr` name is specified then the local name always a string since DOM attributes are strings. If no `attr` name is specified then the
and attribute name are same. Given `<widget my-attr="hello {{name}}">` and widget definition attribute name is assumed to be the same as the local name.
Given `<widget my-attr="hello {{name}}">` and widget definition
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
`localName` property on the widget scope. The `name` is read from the parent scope (not `localName` property on the widget scope. The `name` is read from the parent scope (not
component scope). component scope).
* `=` or `=expression` - set up bi-directional binding between a local scope property and the * `=` or `=attr` - set up bi-directional binding between a local scope property and the
parent scope property. If no `attr` name is specified then the local name and attribute parent scope property of name defined via the value of the `attr` attribute. If no `attr`
name are same. Given `<widget my-attr="parentModel">` and widget definition of name is specified then the attribute name is assumed to be the same as the local name.
`scope: { localModel:'=myAttr' }`, then widget scope property `localName` will reflect the Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
in `localModel` and any changes in `localModel` will reflect in `parentModel`. in `localModel` and any changes in `localModel` will reflect in `parentModel`.
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
If no `attr` name is specified then the local name and attribute name are same. If no `attr` name is specified then the attribute name is assumed to be the same as the
Given `<widget my-attr="count = count + value">` and widget definition of local name. Given `<widget my-attr="count = count + value">` and widget definition of
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
a function wrapper for the `increment()` expression. Often it's desirable to pass data from a function wrapper for the `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 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 map of local variable names and values into the expression wrapper fn. For example, if the
expression is `increment(amount)` then we can specify the amount value by calling the expression is `increment(amount)` then we can specify the amount value by calling the
`localFn` as `localFn({amount: 22})`. `localFn` as `localFn({amount: 22})`.
* `controller` - Controller constructor function. The controller is instantiated before the * `controller` - Controller constructor function. The controller is instantiated before the
pre-linking phase and it is shared with other directives if they request it by name (see pre-linking phase and it is shared with other directives if they request it by name (see
`require` attribute). This allows the directives to communicate with each other and augment `require` attribute). This allows the directives to communicate with each other and augment
each other behavior. The controller is injectable with the following locals: each other's behavior. The controller is injectable with the following locals:
* `$scope` - Current scope associated with the element * `$scope` - Current scope associated with the element
* `$element` - Current element * `$element` - Current element
@ -383,7 +383,7 @@ compiler}. The attributes are:
the template loading is asynchronous the compilation/linking is suspended until the template the template loading is asynchronous the compilation/linking is suspended until the template
is loaded. is loaded.
* `replace` - if set to `true` then the template will replace the current element, rather then * `replace` - if set to `true` then the template will replace the current element, rather than
append the template to the element. append the template to the element.
* `transclude` - compile the content of the element and make it available to the directive. * `transclude` - compile the content of the element and make it available to the directive.
@ -409,24 +409,24 @@ compiler}. The attributes are:
function compile(tElement, tAttrs, transclude) { ... } function compile(tElement, tAttrs, transclude) { ... }
</pre> </pre>
Compile function deals with transforming the template DOM. Since most directives do not do The compile function deals with transforming the template DOM. Since most directives do not do
template transformation, it is not used often. Examples which require compile functions are template transformation, it is not used often. Examples that require compile functions are
directives which transform template DOM such as {@link directives that transform template DOM, such as {@link
api/ng.directive:ngRepeat ngRepeat} or load the contents api/ng.directive:ngRepeat ngRepeat}, or load the contents
asynchronously such as {@link api/ng.directive:ngView ngView}. The asynchronously, such as {@link api/ng.directive:ngView ngView}. The
compile functions takes the following arguments. compile function takes the following arguments.
* `tElement` - template element - The element where the directive has been declared. It is * `tElement` - template element - The element where the directive has been declared. It is
safe to do template transformation on the element and child elements only. safe to do template transformation on the element and child elements only.
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
between all directive compile functions. See {@link between all directive compile functions. See {@link
#Attributes Attributes} guide/directive#Attributes Attributes}.
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`. * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
NOTE: The template instance and the link instance may not be the same objects if the template has NOTE: The template instance and the link instance may not be the same objects if the template has
been cloned. For this reason it is not safe in the compile function to do anything other the DOM been cloned. For this reason it is not safe in the compile function to do anything other than DOM
transformation that applies to all DOM clones. Specifically, DOM listener registration should be transformation that applies to all DOM clones. Specifically, DOM listener registration should be
done in a linking function rather than in a compile function. done in a linking function rather than in a compile function.
@ -446,7 +446,7 @@ A compile function can have a return value which can be either a function or an
function link(scope, iElement, iAttrs, controller) { ... } function link(scope, iElement, iAttrs, controller) { ... }
</pre> </pre>
Link function is responsible for registering DOM listeners as well as updating the DOM. It is The link function is responsible for registering DOM listeners as well as updating the DOM. It is
executed after the template has been cloned. This is where most of the directive logic will be executed after the template has been cloned. This is where most of the directive logic will be
put. put.
@ -458,7 +458,8 @@ put.
already been linked. already been linked.
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
between all directive linking functions. See {@link #Attributes Attributes} between all directive linking functions. See {@link
guide/directive#Attributes Attributes}.
* `controller` - a controller instance - A controller instance if at least one directive on the * `controller` - a controller instance - A controller instance if at least one directive on the
element defines a controller. The controller is shared among all the directives, which allows element defines a controller. The controller is shared among all the directives, which allows
@ -478,11 +479,11 @@ Executed after the child elements are linked. Safe to do DOM transformation in h
<a name="Attributes"></a> <a name="Attributes"></a>
## Attributes ## Attributes
The attributes object - passed as a parameter in the link() or compile() functions - is a way of The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
accessing: link() or compile() functions - is a way of accessing:
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways * *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
the attributes. the attributes.
* *directive inter-communication:* All directives share the same instance of the attributes * *directive inter-communication:* All directives share the same instance of the attributes
@ -536,7 +537,7 @@ into the dialog.
Here is an example of what the template definition for the `dialog` widget may look like. Here is an example of what the template definition for the `dialog` widget may look like.
<pre> <pre>
<div ng-show="show()"> <div ng-show="show">
<h3>{{title}}</h3> <h3>{{title}}</h3>
<div class="body" ng-transclude></div> <div class="body" ng-transclude></div>
<div class="footer"> <div class="footer">
@ -556,10 +557,10 @@ expects as follows:
<pre> <pre>
scope: { scope: {
title: 'bind', // set up title to accept data-binding title: '=', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function onOk: '&', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function onCancel: '&', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility. show: '='
} }
</pre> </pre>
@ -577,7 +578,7 @@ To solve the issue of lack of isolation, the directive declares a new `isolated`
isolated scope does not prototypically inherit from the child scope, and therefore we don't have isolated scope does not prototypically inherit from the child scope, and therefore we don't have
to worry about accidentally clobbering any properties. to worry about accidentally clobbering any properties.
However 'isolated' scope creates a new problem: if a transcluded DOM is a child of the widget However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
is a child of the original scope, before the widget created an isolated scope for its local is a child of the original scope, before the widget created an isolated scope for its local
variables. This makes the transcluded and widget isolated scope siblings. variables. This makes the transcluded and widget isolated scope siblings.

View file

@ -3,7 +3,7 @@
@description @description
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{ Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
expression }}`. Expressions are process by the {@link api/ng.$parse $parse} expression }}`. Expressions are processed by {@link api/ng.$parse $parse}
service. service.
For example, these are all valid expressions in angular: For example, these are all valid expressions in angular:

View file

@ -300,7 +300,7 @@ The following example shows how to add two-way data-binding to contentEditable e
}); });
// model -> view // model -> view
ctrl.render = function(value) { ctrl.$render = function(value) {
elm.html(value); elm.html(value);
}; };

View file

@ -12,10 +12,14 @@ on IE v8.0 or earlier.
To make your angular application work on IE please make sure that: To make your angular application work on IE please make sure that:
1. you **do not** use custom element tags such as `<ng:view>` (use the attribute version `<div 1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
ng-view>` instead), or [JSON2](https://github.com/douglascrockford/JSON-js) or
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
2. if you **do use** custom element tags, then you must take these steps to make IE happy: 2. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
`<div ng-view>` instead), or
3. if you **do use** custom element tags, then you must take these steps to make IE happy:
<pre> <pre>
<html xmlns:ng="http://angularjs.org"> <html xmlns:ng="http://angularjs.org">
@ -25,7 +29,7 @@ To make your angular application work on IE please make sure that:
document.createElement('ng-include'); document.createElement('ng-include');
document.createElement('ng-pluralize'); document.createElement('ng-pluralize');
document.createElement('ng-view'); document.createElement('ng-view');
// Optionally these for CSS // Optionally these for CSS
document.createElement('ng:include'); document.createElement('ng:include');
document.createElement('ng:pluralize'); document.createElement('ng:pluralize');
@ -52,7 +56,7 @@ The **important** parts are:
# Long Version # Long Version
IE has an issues with element tag names which are not standard HTML tag names. These fall into two IE has issues with element tag names which are not standard HTML tag names. These fall into two
categories, and each category has its own fix. categories, and each category has its own fix.
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must * If the tag name starts with `my:` prefix than it is considered an XML namespace and must
@ -61,13 +65,13 @@ categories, and each category has its own fix.
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using * If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
`document.createElement('my-tag')` `document.createElement('my-tag')`
* If you have are planning on styling the custom tag with CSS selectors, then it must be * If you are planning on styling the custom tag with CSS selectors, then it must be
pre-created using `document.createElement('my-tag')` regardless of XML namespace. pre-created using `document.createElement('my-tag')` regardless of XML namespace.
## The Good News ## The Good News
The good news is that these restrictions only apply to element tag names, and not to element The good news is that these restrictions only apply to element tag names, and not to element
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`. attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
@ -84,7 +88,7 @@ result):
</html> </html>
</pre> </pre>
It should pares into the following DOM: It should parse into the following DOM:
<pre> <pre>
#document #document
@ -118,12 +122,12 @@ In IE, the behavior is that the `BODY` element has three children:
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have 3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
the `/` character. Furthermore this closing element should not be part of the DOM since it is the `/` character. Furthermore this closing element should not be part of the DOM since it is
only used to delimitate the structure of the DOM. only used to delineate the structure of the DOM.
## CSS Styling of Custom Tag Names ## CSS Styling of Custom Tag Names
The to make CSS selector work with custom elements the custom element name must be shived with the To make CSS selectors work with custom elements, the custom element name must be pre-created with
`document.createElement('my-tag')` regardless of XML namespace. `document.createElement('my-tag')` regardless of XML namespace.
<pre> <pre>
@ -133,7 +137,7 @@ The to make CSS selector work with custom elements the custom element name must
<script> <script>
// needed to make ng-include parse properly // needed to make ng-include parse properly
document.createElement('ng-include'); document.createElement('ng-include');
// needed to enable CSS reference // needed to enable CSS reference
document.createElement('ng:view'); document.createElement('ng:view');
</script> </script>

View file

@ -10,33 +10,3 @@ of the following documents before returning here to the Developer Guide:
* {@link misc/started Getting Started} * {@link misc/started Getting Started}
* {@link tutorial/index Angular Tutorial} * {@link tutorial/index Angular Tutorial}
<hr>
## {@link overview Overview of Angular}
## {@link bootstrap Initializing Angular}
## {@link dev_guide.mvc About MVC in Angular}
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
## {@link scope Angular Scope Objects}
## {@link compiler Angular HTML Compiler}
## {@link dev_guide.templates Angular Templates}
* {@link dev_guide.templates.filters Understanding Angular Filters}
* {@link forms Understanding Angular Forms}
## {@link dev_guide.services Angular Services}
* {@link dev_guide.services.understanding_services Understanding Angular Services}
* {@link dev_guide.services.creating_services Creating Angular Services}
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
* {@link dev_guide.services.testing_services Testing Angular Services}
## {@link di About Dependency Injection}

View file

@ -5,9 +5,8 @@
# What is a Module? # What is a Module?
Most applications have a main method which instantiates, wires, and bootstraps the application. Most applications have a main method which instantiates, wires, and bootstraps the application.
Angular apps don't have a main method, instead modules serve the purpose of declaratively Angular apps don't have a main method. Instead modules declaratively specify how an application
specifying how an application should be bootstrapped. There are several advantages to this should be bootstrapped. There are several advantages to this approach:
approach:
* The process is more declarative which is easier to understand * The process is more declarative which is easier to understand
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests. * In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
@ -27,15 +26,15 @@ Important things to notice:
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what * Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
bootstraps the app using your module. bootstraps the app using your module.
<doc:example module='simpleApp'> <doc:example module='myApp'>
<doc:source> <doc:source>
<script> <script>
// declare a module // declare a module
var simpleAppModule = angular.module('simpleApp', []); var myAppModule = angular.module('myApp', []);
// configure the module. // configure the module.
// in this example we will create a greeting filter // in this example we will create a greeting filter
simpleAppModule.filter('greet', function() { myAppModule.filter('greet', function() {
return function(name) { return function(name) {
return 'Hello, ' + name + '!'; return 'Hello, ' + name + '!';
}; };
@ -139,7 +138,7 @@ angular.module('myModule', []).
// This is an example of a run block. // This is an example of a run block.
// You can have as many of these as you want. // You can have as many of these as you want.
// You can only inject instances (not Providers) // You can only inject instances (not Providers)
// int the run blocks // into the run blocks
}); });
</pre> </pre>

View file

@ -119,7 +119,7 @@ bootstrap auto initialize} your application.
We load Angular using the `<script>` tag: We load Angular using the `<script>` tag:
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data
binding, and we also demonstrate some easy input validation: binding, and we also demonstrate some easy input validation:
@ -202,7 +202,6 @@ Angular frees you from the following pain:
# Watch a Presentation About Angular # Watch a Presentation About Angular
Here is an early presentation on angular, but note that substantial development has occurred since Here is a presentation on Angular from May 2012.
the talk was given in July of 2010.
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe> <iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>

View file

@ -28,7 +28,7 @@ watch {@link guide/expression expressions} and propagate events.
## Scope as Data-Model ## Scope as Data-Model
Scope is the glue between application controller and the view. During the template {@link compiler Scope is the glue between application controller and the view. During the template {@link compiler
linking} phase the {@link api/ng.$compileProvider.directive directives} set up linking} phase the {@link api/ng.$compileProvider#directive directives} set up
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The {@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
`$watch` allows the directives to be notified of property changes, which allows the directive to `$watch` allows the directives to be notified of property changes, which allows the directive to
render the updated value to the DOM. render the updated value to the DOM.
@ -222,7 +222,7 @@ The normal flow of browser receiving an event is that it executes a correspondin
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
more events. more events.
When the browser calls into JavaScript the code executes outside they Angular execution context, When the browser calls into JavaScript the code executes outside the Angular execution context,
which means that Angular is unaware of model modifications. To properly process model which means that Angular is unaware of model modifications. To properly process model
modifications the execution has to enter the Angular execution context using the {@link modifications the execution has to enter the Angular execution context using the {@link
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
@ -231,9 +231,9 @@ directive listens on DOM events, such as {@link
api/ng.directive:ngClick `ng-click`} it must evaluate the api/ng.directive:ngClick `ng-click`} it must evaluate the
expression inside the `$apply` method. expression inside the `$apply` method.
After evaluating the expression `$apply` method performs a {@link After evaluating the expression, the `$apply` method performs a {@link
api/ng.$rootScope.Scope#$digest `$digest`}. In $digest phase the scope examines all api/ng.$rootScope.Scope#$digest `$digest`}. In the $digest phase the scope examines all
of the `$watch` expressions and compares them with previous value. This dirty checking, is done of the `$watch` expressions and compares them with the previous value. This dirty checking is done
asynchronously. This means that assignment such as `$scope.username="angular"` will not asynchronously. This means that assignment such as `$scope.username="angular"` will not
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
@ -250,13 +250,13 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
2. **Watcher registration** 2. **Watcher registration**
During template linking directives register {@link During template linking directives register {@link
api/ng.$rootScope.Scope#$watch watches} on the scope. This watches will be api/ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
used to propagate model values to the DOM. used to propagate model values to the DOM.
3. **Model mutation** 3. **Model mutation**
For mutations to be properly observed, you should make them only within the {@link For mutations to be properly observed, you should make them only within the {@link
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular apis do this api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers, implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
or asynchronous work with {@link api/ng.$http $http} or {@link or asynchronous work with {@link api/ng.$http $http} or {@link
api/ng.$timeout $timeout} services. api/ng.$timeout $timeout} services.
@ -279,10 +279,10 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
### Scopes and Directives ### Scopes and Directives
During the compilation phase, the {@link compiler compiler} matches {@link During the compilation phase, the {@link compiler compiler} matches {@link
api/ng.$compileProvider.directive directives} against the DOM template. The directives api/ng.$compileProvider#directive directives} against the DOM template. The directives
usually fall into one of two categories: usually fall into one of two categories:
- Observing {@link api/ng.$compileProvider.directive directives}, such as - Observing {@link api/ng.$compileProvider#directive directives}, such as
double-curly expressions `{{expression}}`, register listeners using the {@link double-curly expressions `{{expression}}`, register listeners using the {@link
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
to be notified whenever the expression changes so that it can update the view. to be notified whenever the expression changes so that it can update the view.
@ -299,7 +299,7 @@ correctly.
### Directives that Create Scopes ### Directives that Create Scopes
In most cases, {@link api/ng.$compileProvider.directive directives} and scopes interact In most cases, {@link api/ng.$compileProvider#directive directives} and scopes interact
but do not create new instances of scope. However, some directives, such as {@link but do not create new instances of scope. However, some directives, such as {@link
api/ng.directive:ngController ng-controller} and {@link api/ng.directive:ngController ng-controller} and {@link
api/ng.directive:ngRepeat ng-repeat}, create new child scopes api/ng.directive:ngRepeat ng-repeat}, create new child scopes

View file

@ -13,19 +13,19 @@
<a name="H1_1"></a> <a name="H1_1"></a>
# License # License
`Angular` is an open source project licensed under the {@link AngularJS is an open source project licensed under the {@link
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
always welcome. When working with `angular` source base, please follow the guidelines provided on always welcome. When working with AngularJS code base, please follow the guidelines provided on
this page. this page.
<a name="H1_2"></a> <a name="H1_2"></a>
# Contributing to Source Code # Contributing to Source Code
We'd love for you to contribute to our source code and to make `angular` even better than it is We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to use: today! Here are the guidelines we'd like you to follow:
* Major changes that you intend to contribute to the project must be discussed first on our {@link * Major changes that you intend to contribute to the project should be discussed first on our {@link
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
is successfully accepted upstream. is successfully accepted upstream.
@ -64,45 +64,39 @@ inheritance only when absolutely necessary.
external API. See our existing code to see what we mean. external API. See our existing code to see what we mean.
* We don't go crazy with type annotations for private internal APIs unless it's an internal API * We don't go crazy with type annotations for private internal APIs unless it's an internal API
that is used throughout `angular`. The best guidance is to do what makes the most sense. that is used throughout AngularJS. The best guidance is to do what makes the most sense.
<a name="H1_4"></a> <a name="H1_4"></a>
# Checking Out and Building Angular # Checking Out and Building Angular
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. Several steps are needed to check out and build `angular`: accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
Several steps are needed to check out and build AngularJS:
## Installation Dependencies ## Installation Dependencies
Before you can build `angular`, you must install or configure the following dependencies on your Before you can build AngularJS, you must install or configure the following dependencies on your
machine: machine:
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed * {@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 on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
Rake website. 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 * {@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 development web server. Depending on your system, you can install Node either from source or as a
pre-packaged bundle. pre-packaged bundle.
You'll also need npm and the following npm modules: Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
of the Angular repository (see below) with:
* install npm: `curl http://npmjs.org/install.sh | sh` * `cd angular.js`
* install q: `npm install q` * `npm install`
* 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 ## Creating a Github Account and Forking Angular
@ -112,31 +106,31 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
https://github.com/angular/angular.js main angular repository}. https://github.com/angular/angular.js main angular repository}.
## Building `Angular` ## Building AngularJS
To build `angular`, you check out the source code and use Rake to generate the non-minified and To build AngularJS, you check out the source code and use Rake to generate the non-minified and
minified `angular` files: minified AngularJS files:
1. To clone your Github repository, run: 1. To clone your Github repository, run:
git clone git@github.com:<github username>/angular.js.git git clone git@github.com:<github username>/angular.js.git
2. To go to the `angular` directory, run: 2. To go to the AngularJS directory, run:
cd angular.js cd angular.js
3. To add the main `angular` repository as an upstream remote to your repository, run: 3. To add the main AngularJS repository as an upstream remote to your repository, run:
git remote add upstream https://github.com/angular/angular.js.git git remote add upstream https://github.com/angular/angular.js.git
4. To build `angular`, run: 4. To build AngularJS, run:
rake package rake package
The build output can be located under the `build` directory. It consists of the following files and The build output can be located under the `build` directory. It consists of the following files and
directories: directories:
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build * `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
artifacts. artifacts.
* `angular.js` — The non-minified `angular` script. * `angular.js` — The non-minified `angular` script.
@ -145,8 +139,6 @@ artifacts.
* `angular-scenario.js` — The `angular` End2End test runner. * `angular-scenario.js` — The `angular` End2End test runner.
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`. * `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
* `docs/index.html` — The main page for the documentation. * `docs/index.html` — The main page for the documentation.
@ -154,60 +146,70 @@ artifacts.
* `docs/docs-scenario.html` — The End2End test runner for the documentation application. * `docs/docs-scenario.html` — The End2End test runner for the documentation application.
<a name="webserver"></a>
## Running a Local Development Web Server ## Running a Local Development Web Server
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
made available a local web server based on Node.js. made available a local web server based on Node.js.
1. To start the web server, run: 1. To start the web server, run:
./nodeserver.sh rake webserver
2. To access the local server, go to this website: 2. To access the local server, go to this website:
http://localhost:8000/ http://localhost:8000/
By default, it serves the contents of the `angular` project directory. By default, it serves the contents of the AngularJS project directory.
<a name="unit-tests"></a> <a name="unit-tests"></a>
## Running the Unit Test Suite ## Running the Unit Test Suite
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
tests: tests once on Chrome run:
1. To start the JSTD server, run: rake test:unit
./server.sh To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
2. To capture one or more browsers, go to this website: rake test:unit[Opera+Firefox]
During development it's however more productive to continuously run unit tests every time the source or test files
change. To execute tests in this mode run:
1. To start the Testacular server, capture Chrome browser and run unit tests, run:
rake autotest:jqlite
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
of Testacular running, read Testacular's console output for the correct url):
http://localhost:9876/ http://localhost:9876/
3. To trigger a test execution, run: 3. To re-run tests just change any source or test file.
./test.sh
4. To automatically run the test suite each time one or more of the files in the project directory
is changed, you can install `watchr` and then run:
watchr watchr.rb
5. To view the output of each test run, you can tail this log file:
./logs/jstd.log
## Running the End2End Test Suite To learn more about all of the preconfigured Rake tasks run:
To run the End2End test suite: rake -T
## Running the end-to-end Test Suite
To run the E2E test suite:
1. Start the local web server if it's not running already.
rake webserver
1. Start the local web server.
2. In a browser, go to: 2. In a browser, go to:
http://localhost:8000/build/docs/docs-scenario.html http://localhost:8000/build/docs/docs-scenario.html
The tests are executed automatically. or in terminal run:
rake test:e2e
@ -216,30 +218,38 @@ To run the End2End test suite:
To create and submit a change: To create and submit a change:
1. Create a new branch off the master for your changes: 1. Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
accepted, the CLA must be signed. It's a quick process, we promise!
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
2. Create a new branch off the master for your changes:
git branch my-fix-branch git branch my-fix-branch
2. Check out the branch: 3. Check out the branch:
git checkout my-fix-branch git checkout my-fix-branch
3. Create your patch, make sure to have plenty of tests (that pass). 4. Create your patch, make sure to have plenty of tests (that pass).
4. Commit your changes: 5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
please check out our
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
and our commit message presubmit hook `validate-commit-msg.js`):
git commit -a git commit -a
5. Run JavaScript Lint and be sure to address all new warnings and errors:
rake lint
6. Push your branch to Github: 6. Push your branch to Github:
git push origin my-fix-branch git push origin my-fix-branch
7. In Github, send a pull request to `angular:master`. 7. In Github, send a pull request to `angular:master`.
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes 8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository: from the main (upstream) repository:

View file

@ -16,14 +16,14 @@ development.
production. production.
To point your code to an angular script on the angular server, use the following template. This To point your code to an angular script on the angular server, use the following template. This
example points to (non-minified) version 0.10.6: example points to (non-minified) version 1.0.2:
<pre> <pre>
<!doctype html> <!doctype html>
<html ng-app> <html ng-app>
<head> <head>
<title>My Angular App</title> <title>My Angular App</title>
<script src="http://code.angularjs.org/angular-0.10.6.js"></script> <script src="http://code.angularjs.org/1.0.2/angular.js"></script>
</head> </head>
<body> <body>
</body> </body>
@ -42,29 +42,31 @@ Download the version you want and have fun.
Each directory under <http://code.angularjs.org/> includes the following set of files: Each directory under <http://code.angularjs.org/> includes the following set of files:
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by * __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
opening it it any editor or browser. In order to get better error messages during development, you opening it it any editor or browser. In order to get better error messages during development, you
should always use this non-minified angular script. should always use this non-minified angular script.
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of * __`angular.min.js`__ — This is a minified and obfuscated version of
`angular-<version>.js` created with the Closure compiler. Use this version for production in order `angular.js` created with the Closure compiler. Use this version for production in order
to minimize the size of the application that is downloaded by your user's browser. to minimize the size of the application that is downloaded by your user's browser.
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released * __`angular.zip`__ — This is a zip archive that contains all of the files released
for this angular version. Use this file to get everything in a single download. for this angular version. Use this file to get everything in a single download.
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data * __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
of angular files, make sure that this file is available for download, and that it resides under the
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
testing angular apps even easier. Your unit/integration test harness should load this file after testing angular apps even easier. Your unit/integration test harness should load this file after
`angular-<version>.js` is loaded. `angular-<version>.js` is loaded.
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you * __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
to write and execute end-to-end tests for angular applications. to write and execute end-to-end tests for angular applications.
* __`docs-<version>`__ — this directory contains all the files that compose the * __`angular-loader.min.js`__ — Module loader for Angular modules. If you are loading multiple script files containing
Angular modules, you can load them asynchronosuly and in any order as long as you load this file first. Often the
contents of this file are copy&pasted into the `index.html` to avoid even the inial request to `angular-loader.min.js`.
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
* __`docs`__ — this directory contains all the files that compose the
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of <http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
our docs, or even more importantly, view the docs offline. our docs, or even more importantly, view the docs offline.

View file

@ -4,78 +4,194 @@
#FAQ #FAQ
### Why is this project called "angular"? Why is the namespace called "ng"? ## Questions
Because HTML has angular brackets and "ng" sounds like "angular". ### Why is this project called "AngularJS"? Why is the namespace called "ng"?
### Is <angular/> an HTML5 tag? Because HTML has Angular brackets and "ng" sounds like "Angular".
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
together.
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}? ### Is AngularJS a library, framework, plugin or a browser extension?
No, angular is none of these. You don't call its functions, it does not call your functions, AngularJS fits the definition of a framework the best, even though it's much more lightweight than
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections a typical framework and that's why many confuse it with a library.
of your data. There are lots of existing widget libraries which you can integrate with angular.
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
### Do I need to worry about security holes in angular? AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
So it's definitely not a plugin or some other native browser extension.
Like with any technology, angular is not impervious to attack. angular does, however, provide
built-in protection from basic security holes including cross-site scripting and HTML injection
attacks. angular does round-trip escaping on all strings for you.
### Can I download the source, build, and host the angular environment locally? ### Is AngularJS a templating system?
Yes. See instructions in {@link downloading}. At the highest level, Angular does look like a just another templating system. But there is one
important reason why the Angular templating system is different, that makes it very good fit for
### Is angular a templating system? application development: bidirectional data binding. The template is compiled in the browser and
the compilation step produces a live view. This means you, the developers, don't need to write
At the highest level, angular does look like a just another templating system. But there is one
important reason why angular templating system is different and makes it very good fit for
application development: bidirectional data binding. The template is compiled on the browser and
the compilation step produces a live view. This means you, the developer, don't need to write
code to constantly sync the view with the model and the model with the view as in other code to constantly sync the view with the model and the model with the view as in other
templating systems. templating systems.
### What browsers does angular work with?
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and ### Do I need to worry about security holes in AngularJS?
above. Note that CSS only works on IE7 and above.
### What's angular's performance like? Like 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.
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your AngularJS was designed to be compatible with other security measures like Content Security Policy
app's performance will vary depending on how many bindings you use. (CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
possible attack vectors and we highly recommended their use.
### How big is the angular bootstrap JS file that I need to include?
The size of the library itself is < 50KB compressed and obfuscated. ### Can I download the source, build, and host the AngularJS environment locally?
### Can I use the open-source Closure Library with angular? Yes. See instructions in {@link downloading}.
### What browsers does Angular work with?
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
### What's Angular's performance like?
The startup time heavily depends on your network connection, state of the cache, browser used and
available hardware, but typically we measure bootstrap time in tens or hundreds of milliseconds.
The runtime performance will vary depending on the number and complexity of bindings on the page
as well as the speed of your backend (for apps that fetch data from the backend). Just for an
illustration we typically build snappy apps with hundreds or thousands of active bindings.
### How big is the angular.js file that I need to include?
The size of the file is < 29KB compressed and minified.
### Can I use the open-source Closure Library with Angular?
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library} Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
in angular. in Angular.
### Does angular use the jQuery library? ### Does Angular use the jQuery library?
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library. Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
If jQuery is not present in your script path, angular falls back on its own implementation of application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
manipulate the DOM.
### What is testability like in angular?
Very testable. It has an integrated dependency injection framework. See ### What is testability like in Angular?
Very testable and designed this way from ground up. It has an integrated dependency injection
framework, provides mocks for many heavy dependencies (server-side communication). See
{@link api/ng service} for details. {@link api/ng service} for details.
### How can I learn more about angular?
### How can I learn more about Angular?
Watch the July 28, 2010 talk Watch the July 28, 2010 talk
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building "{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
AJAX Apps}". AJAX Apps}".
### How is angular licensed?
### How is Angular licensed?
The MIT License. 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.

View file

@ -2,142 +2,37 @@
@name Getting Started @name Getting Started
@description @description
# Hello World! We want you to have an easy time while starting to use Angular. We've put together the following steps on your path to
becoming an Angular expert.
A great way for you to get started with AngularJS is to create the tradtional 1. Read the {@link guide/concepts conceptual overview}.<br/>Understand Angular's vocabulary and how all the Angular
"Hello World!" app: components work together.
1. Do the {@link tutorial/ AngularJS Tutorial}.<br/>Walk end-to-end through building and application complete with tests
1. In your favorite text editor, create an HTML file on top of a node.js web server. Covers every major AngularJS feature and show you how to set up your development
(for example, `helloworld.html`). environment.
2. From the __Source__ box below, copy and paste the code into your HTML file. 1. Download or clone the {@link https://github.com/angular/angular-seed Seed App project template}.<br/>Gives you a
(Double-click on the source to easily select all.) starter app with a directory layout, test harness, and scripts to begin building your application.
3. Open the file in your web browser.
<doc:example>
<doc:source>
Hello {{'World'}}!
</doc:source>
</doc:example>
The resulting web page should look something like the following:
<img class="center" src="img/helloworld.png" border="1">
Now let's take a closer look at that code, and see what is going on behind
the scenes.
The `ng-app` tags tells angular to process the entire HTML page and bootstrap the app when the page
is loaded:
<pre>
<html ng-app>
</pre>
The next line downloads the angular script:
<pre>
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
</pre>
(For details on what happens when angular processes an HTML page,
see {@link guide/bootstrap Bootstrap}.)
Finally, this line in the `<body>` of the page is the template that describes
how to display our greeting in the UI:
<pre>
Hello {{'World'}}!
</pre>
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
the greeting text. Here the expression is the string literal 'World'.
Next let's look at a more interesting example, that uses AngularJS to
bind a dynamic expression to our greeting text.
# Hello AngularJS World!
This example demonstrates angular's two-way data binding:
1. Edit the HTML file you created in the "Hello World!" example above.
2. Replace the contents of `<body>` with the code from the __Source__ box below.
3. Refresh your browser window.
<doc:example>
<doc:source>
Your name: <input type="text" ng-model="yourname" placeholder="World">
<hr>
Hello {{yourname || 'World'}}!
</doc:source>
</doc:example>
After the refresh, the page should look something like this:
<img class="left" src="img/helloworld_2way.png" border="1" >
These are some of the important points to note from this example:
* The text input {@link guide/directive directive}
is bound to a model variable called `yourname`.
* The double curly braces notation binds the `yourname` model to the greeting text.
* You did not need to explicitly register an event listener or define an event handler for events!
Now try typing your name into the input box, and notice the immediate change to
the displayed greeting. This demonstrates the concept of angular's
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
field are immediately
reflected in the model (one direction), and any changes to the model are
reflected in the greeting text (the other direction).
# Anatomy Of An Angular App #Further Steps
This section describes the 3 parts of an angular app, and explains how they map to the ##Watch Videos
Model-View-Controller design pattern:
## Templates If you havent had a chance to watch the videos from the homepage, please check out:
* {@link http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Introduction to AngularJS}
* {@link http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Creating Directives}
* {@link http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Communicating with Servers}
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and And visit our {@link http://www.youtube.com/user/angularjs YouTube channel} for more AngularJS video presentations and
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully tutorials.
extensible, meaning that with angular you can build your own declarative language on top of HTML!
##Subscribe
## Application Logic and Behavior * Subscribe to the {@link http://groups.google.com/forum/?fromgroups#!forum/angular mailing list}. Ask questions here!
* Follow us on {@link https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F&region=follow_link&screen_name=angularjs&source=followbutton&variant=2.0 Twitter}
* Add us to your circles on {@link https://plus.google.com/110323587230527980117/posts Google+}
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With ##Read more
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
write, test, maintain, and understand.
The AngularJS documentation includes the {@link guide/index Developer Guide} covering concepts and the
## Data {@link api/ API Reference} for syntax and usage.
The Model is referenced from properties on {@link guide/scope angular scope objects}.
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
matters is that these are all referenced by the scope object.
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
The following illustration shows the parts of an angular application and how they work together:
<img class="left" src="img/angular_parts.png" border="0" />
In addition, angular comes with a set of Services, which have the following properties:
* The services provided are very useful for building web applications.
* You can extend and add application-specific behavior to services.
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
# Where To Go Next
* If you like what you've learned so far, you should definitely check out our awesome {@link
tutorial/ Tutorial}, which walks you through the process of building real apps with AngularJS.
* For further explanations and examples of the AngularJS concepts presented on this page, see the
{@link guide/index Developer Guide}.
* For additional hands-on examples of using AngularJS, including more source code that you can
copy and paste into your own pages, take a look through the {@link cookbook/ Cookbook}.

View file

@ -47,20 +47,23 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
# Working with the code # Working with the code
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. Options for working with the tutorial are to use the Git versioning system for source environment. The tutorial relies on the use of Git versioning system for source code management.
code management or to use scripts that copy snapshots of project files into your workspace You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your and follow the instructions for setting up your computer.
computer for your preferred option.
<div class="tabbable" show="true"> <div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux"> <div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol> <ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the <li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
following command in a terminal window:</p> <a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
<pre>java -version</pre> and that the <code>node</code> executable is on your <code>PATH</code> by running the following
<p>You will need Java to run unit tests.</p></li> command in a terminal window:</p>
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p> <pre>node --version</pre>
<p>You can build Git from source or use the pre-compiled package.</p></li> <p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
don't have it already:</p>
<pre>npm install -g testacular</pre>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a <li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p> href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre> <pre>git clone git://github.com/angular/angular-phonecat.git</pre>
@ -71,77 +74,41 @@ directory.</p></li>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat <p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li> directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically <li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can <a have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol> </ol>
</div> </div>
<div class="tab-pane well" id="git-win" title="Git on Windows"> <div class="tab-pane well" id="git-win" title="Git on Windows">
<ol> <ol>
<li><p>You will need Java to run unit tests, so run the following command to verify that you <li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
have <a href="http://java.com/">Java</a> installed and that the <code>java</code> executable is on <a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
your <code>PATH</code>.</p> and that the <code>node</code> executable is on your <code>PATH</code> by running the following
<pre>java -version</pre> command in a terminal window:</p>
<p></p></li> <pre>node --version</pre>
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li> <p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a don't have it already:</p>
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p> <pre>npm install -g testacular</pre>
</li>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre> <pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the angular-phonecat directory in your current directory.</p></li> <p>This command creates the angular-phonecat directory in your current directory.</p></li>
<li><p>Change your current directory to angular-phonecat.</p> <li><p>Change your current directory to angular-phonecat.</p>
<pre>cd angular-phonecat</pre> <pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat <p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p> directory.</p>
<p>You should run all <code>git</code> commands from msysGit bash.</p> <p>You should run all <code>git</code> commands from Git bash.</p>
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be <p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
executed from the Windows command line.</li> executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one <li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run bundled http server.</p></li>
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol> </ol>
</div> </div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux">
<ol>
<li><p>You need Java to run unit tests, so verify that you have <a
href="http://java.com/">Java</a> installed by running the following command in a terminal
window:</p>
<pre>java -version</pre>
<li><p>Download the <a href="http://code.angularjs.org/angular-phonecat/">zip archive</a>
containing all of the files and unzip them into the [tutorial-dir] directory</p>.</li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from your
<code>sandbox</code> directory.</p></li>
<li><p>You need an http server running on your system and Mac and Linux machines typically
have Apache pre-installed. If you don't have an http server installed, you can <a
href="http://nodejs.org/#download">install node.js</a> and use it to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
<code>java</code> executable is on your <code>PATH</code> by running the following command in the
Windows command line:</p>
<pre>java -version</pre>
<p>You need Java to run unit tests, so download the <a
href="http://code.angularjs.org/angular-phonecat/">zip archive</a> that contains all of the files
and unzip the files into the [tutorial-dir] directory</p></li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from this directory.</p></li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
</divs>
The last thing to do is to make sure your computer has a web browser and a good text editor The last thing to do is to make sure your computer has a web browser and a good text editor
installed. Now, let's get some cool stuff done! installed. Now, let's get some cool stuff done!

View file

@ -46,7 +46,7 @@ directory.</li>
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin"> <div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
<ol> <ol>
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p> <li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
<pre>git checkout -f step-0</pre> <pre>git checkout -f step-0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p> <p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to <p>You must repeat this for every future step in the tutorial and change the number to
@ -74,70 +74,6 @@ directory.</li>
</li> </li>
</ol> </ol>
</div> </div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux" value="snapshotUnix">
<ol>
<li><p>In the angular-phonecat directory, run this command:</p>
<pre>./goto_step.sh 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run
<code>./scripts/web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows" value="snapshotWin">
<ol>
<li><p>Open windows command line and run this command (in the angular-phonecat directory):</p>
<pre>goto_step.bat 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node
scripts\web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
</div> </div>
@ -173,10 +109,11 @@ __`app/index.html`:__
<html ng-app> <html ng-app>
The `ng-app` attribute is represents an Angular directive used to flag an element which Angular The `ng-app` attribute is represents an Angular directive (named `ngApp`; Angular uses
should consider to be the root element of our application. This gives application developers the `name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
freedom to tell Angular if the entire html page or only a portion of it should be treated as the used to flag an element which Angular should consider to be the root element of our application.
Angular application. This gives application developers the freedom to tell Angular if the entire html page or only a
portion of it should be treated as the Angular application.
* AngularJS script tag: * AngularJS script tag:
@ -195,7 +132,7 @@ being the element on which the `ngApp` directive was defined.
This line demonstrates the core feature of Angular's templating capabilities a binding, denoted This line demonstrates the core feature of Angular's templating capabilities a binding, denoted
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding. by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
The binding tells Angular, that it should evaluate an expression and insert the result into the The binding tells Angular that it should evaluate an expression and insert the result into the
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
binding will result in efficient continuous updates whenever the result of the expression binding will result in efficient continuous updates whenever the result of the expression
evaluation changes. evaluation changes.

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. tag as the template.
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote * As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
bindings. As opposed to evaluating constants, these expression are refering to our application bindings. As opposed to evaluating constants, these expressions are referring to our application
model, which was set up in our `PhoneListCtrl` controller. model, which was set up in our `PhoneListCtrl` controller.
<img class="diagram" src="img/tutorial/tutorial_02.png"> <img class="diagram" src="img/tutorial/tutorial_02.png">
@ -146,31 +146,25 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
https://github.com/pivotal/jasmine/wiki Jasmine wiki}. https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
The angular-seed project is pre-configured to run all unit tests using {@link The angular-seed project is pre-configured to run all unit tests using {@link
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following: http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run 1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test-server.sh` to start the test web server. `./scripts/test.sh` to start the Testacular server.
2. Open a new browser window and navigate to {@link http://localhost:9876}. 2. Testacular will start a new instance of Chrome browser automatically. Just ignore it and let it run in
the background. Testacular will use this browser for test execution.
3. Choose "Capture this browser in strict mode". 3. You should see the following or similar output in the terminal:
At this point, you can leave this window open and forget about it. JsTestDriver will use it to info: Testacular server started at http://localhost:9876/
execute the tests and report the results in the terminal. info (launcher): Starting browser "Chrome"
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
4. Execute the test by running `./scripts/test.sh` Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
You should see the following or similar output:
Chrome: Runner reset.
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
Yay! The test passed! Or not... Yay! The test passed! Or not...
Note: If you see errors after you run the test, close the browser window and go back to the 4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
terminal and kill the script, then repeat the procedure above. and will rerun the tests for you. Now isn't that sweet?
# Experiments # Experiments
@ -198,8 +192,7 @@ execute the tests and report the results in the terminal.
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr> <tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
</table> </table>
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the * Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
`./scripts/test.sh` script.
# Summary # Summary

View file

@ -54,9 +54,9 @@ __`app/index.html`:__
</div> </div>
</pre> </pre>
We added a standard HTML `<input>` tag and used angular's We added a standard HTML `<input>` tag and used Angular's
{@link api/ng.filter:filter $filter} function to process the input for the {@link api/ng.filter:filter $filter} function to process the input for the
`ngRepeat` directive. {@link api/ng.directive:ngRepeat ngRepeat} directive.
This lets a user enter search criteria and immediately see the effects of their search on the phone This lets a user enter search criteria and immediately see the effects of their search on the phone
list. This new code demonstrates the following: list. This new code demonstrates the following:
@ -122,6 +122,11 @@ To run the end-to-end test, open one of the following in a new browser tab:
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html` `http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html} * casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
Previously we've seen how Testacular can be used to execute unit tests. Well, it can also run the
end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests are slow, so unlike
with unit tests, Testacular will exit after the test run and will not automatically rerun the test
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
This test verifies that the search box and the repeater are correctly wired together. Notice how This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
really is that easy to set up any functional, readable, end-to-end test. really is that easy to set up any functional, readable, end-to-end test.
@ -176,12 +181,14 @@ ngBindTemplate} directives, which are invisible to the user while the page is lo
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
with the `query` binding. with the `query` binding, prefixed by "Current filter:". For instance:
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pause; this <div id="status">Current filter: {{query}}</div>
gives you the opportunity to explore the state of your application while it is displayed in the
browser. The app is live! You can change the search query to prove it. Notice how useful this is * Add a `pause()` statement inside of an end-to-end test and rerun it. You'll see the runner pause;
for troubleshooting end-to-end tests. this gives you the opportunity to explore the state of your application while it is displayed in
the browser. The app is live! You can change the search query to prove it. Notice how useful this
is for troubleshooting end-to-end tests.
# Summary # Summary

View file

@ -63,7 +63,7 @@ necessary!
## Controller ## Controller
__`app/js/controller.js`:__ __`app/js/controllers.js`:__
<pre> <pre>
function PhoneListCtrl($scope) { function PhoneListCtrl($scope) {
$scope.phones = [ $scope.phones = [
@ -103,7 +103,7 @@ to the model.
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
the unit test first. the unit test first.
__`test/unit/controllerSpec.js`:__ __`test/unit/controllersSpec.js`:__
<pre> <pre>
describe('PhoneCat controllers', function() { describe('PhoneCat controllers', function() {
@ -134,13 +134,9 @@ The unit test now verifies that the default ordering property is set.
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
shared by all tests in the parent `describe` block. shared by all tests in the parent `describe` block.
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the You should now see the following output in the Testacular tab:
following output.
Chrome: Runner reset. Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
Let's turn our attention to the end-to-end test. Let's turn our attention to the end-to-end test.
@ -168,8 +164,8 @@ __`test/e2e/scenarios.js`:__
The end-to-end test verifies that the ordering mechanism of the select box is working correctly. The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
can see them running on {@link `runner.html` to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
Angular's server}. Angular's server}.

View file

@ -22,7 +22,7 @@ GitHub}:
## Data ## Data
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
stored in the JSON format. stored in the JSON format.
Following is a sample of the file: Following is a sample of the file:
@ -104,7 +104,7 @@ to avoid any possible naming collisions.
Since angular infers the controller's dependencies from the names of arguments to the controller's Since angular infers the controller's dependencies from the names of arguments to the controller's
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming) constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
minified as well, and the dependency injector would be able to identify services correctly. minified as well, and the dependency injector would not be able to identify services correctly.
To overcome issues caused by minification, just assign an array with service identifier strings To overcome issues caused by minification, just assign an array with service identifier strings
into the `$inject` property of the controller function, just like the last line in the snippet into the `$inject` property of the controller function, just like the last line in the snippet
@ -164,8 +164,8 @@ isolated from the work done in other tests.
* We created a new scope for our controller by calling `$rootScope.$new()` * We created a new scope for our controller by calling `$rootScope.$new()`
* We called `scope.$new(PhoneListCtrl)` to get Angular to create the child scope associated with * We called the injected `$controller` function passing the `PhoneListCtrl` function and the created
the `PhoneListCtrl` controller. scope as parameters.
Because our code now uses the `$http` service to fetch the phone list data in our controller, before Because our code now uses the `$http` service to fetch the phone list data in our controller, before
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
@ -208,13 +208,10 @@ Finally, we verify that the default value of `orderProp` is set correctly:
}); });
</pre> </pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following You should now see the following output in the Testacular tab:
output.
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
# Experiments # Experiments

View file

@ -65,7 +65,7 @@ api/ng.directive:ngSrc ngSrc} directive. That directive prevents the
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`). specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
Using `ngSrc` (`ng-src`) prevents the browser from making an http request to an invalid location. Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
## Test ## Test
@ -84,10 +84,11 @@ __`test/e2e/scenarios.js`__:
We added a new end-to-end test to verify that the app is generating correct links to the phone We added a new end-to-end test to verify that the app is generating correct links to the phone
views that we will implement in the upcoming steps. views that we will implement in the upcoming steps.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
can see them running on {@link runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
angular's server}. Angular's server}.
# Experiments # Experiments
@ -96,11 +97,15 @@ or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
`/app/{{phone.imageUrl}}`). `/app/{{phone.imageUrl}}`).
The issue here is that the browser will fire a request for that invalid image address as soon as
it hits the `img` tag, which is before Angular has a chance to evaluate the expression and inject
the valid address.
# Summary # Summary
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about angular Now that you have added phone images and links, go to {@link step_07 step 7} to learn about Angular
layout templates and how angular makes it easy to create applications that have multiple views. layout templates and how Angular makes it easy to create applications that have multiple views.
<ul doc-tutorial-nav="6"></ul> <ul doc-tutorial-nav="6"></ul>

View file

@ -19,7 +19,7 @@ detail page is displayed.
The most important changes are listed below. You can see the full diff on {@link The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-6...step-7 https://github.com/angular/angular-phonecat/compare/step-6...step-7
GitHub}: GitHub}.
## Multiple Views, Routing and Layout Template ## Multiple Views, Routing and Layout Template
@ -79,7 +79,7 @@ angular.module('phonecat', []).
</pre> </pre>
In order to configure our application with routes, we need to create a module for our application. In order to configure our application with routes, we need to create a module for our application.
We call this module `phonecatApp` and using the `config` API we request the `$routeProvider` to be We call this module `phonecat` and using the `config` API we request the `$routeProvider` to be
injected into our config function and use `$routeProvider.when` API to define our routes. injected into our config function and use `$routeProvider.when` API to define our routes.
Note that during the injector configuration phase, the providers can be injected as well, but they Note that during the injector configuration phase, the providers can be injected as well, but they
@ -114,14 +114,14 @@ directive:
__`app/index.html`:__ __`app/index.html`:__
<pre> <pre>
<!doctype html> <!doctype html>
<html ng-app="phonecat"> <html lang="en" ng-app="phonecat">
... ...
</pre> </pre>
## Controllers ## Controllers
__`app/js/controller.js`:__ __`app/js/controllers.js`:__
<pre> <pre>
... ...
function PhoneDetailCtrl($scope, $routeParams) { function PhoneDetailCtrl($scope, $routeParams) {
@ -140,11 +140,12 @@ route into the layout template, which makes it a perfect fit for our `index.html
__`app/index.html`:__ __`app/index.html`:__
<pre> <pre>
<html ng-app="phonecat"> <html lang="en" ng-app="phonecat">
<head> <head>
... ...
<script src="lib/angular/angular.js"></script> <script src="lib/angular/angular.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head> </head>
<body> <body>
@ -231,10 +232,10 @@ to various URLs and verify that the correct view was rendered.
</pre> </pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
can see them running on {@link runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
angular's server}. Angular's server}.
# Experiments # Experiments

View file

@ -16,7 +16,7 @@ Now when you click on a phone on the list, the phone details page with phone-spe
is displayed. is displayed.
To implement the phone details view we will use {@link api/ng.$http $http} to fetch To implement the phone details view we will use {@link api/ng.$http $http} to fetch
our data, and we'll flesh out the `phone-details.html` view template. our data, and we'll flesh out the `phone-detail.html` view template.
The most important changes are listed below. You can see the full diff on {@link The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-7...step-8 https://github.com/angular/angular-phonecat/compare/step-7...step-8
@ -59,7 +59,7 @@ show this data in the phone detail view.
We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works
the same way as the phone list controller. the same way as the phone list controller.
__`app/js/controller.js`:__ __`app/js/controllers.js`:__
<pre> <pre>
function PhoneDetailCtrl($scope, $routeParams, $http) { function PhoneDetailCtrl($scope, $routeParams, $http) {
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) { $http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
@ -81,7 +81,7 @@ Note where we use the angular `{{expression}}` markup and `ngRepeat` to project
our model into the view. our model into the view.
__`app/partials/phone-details.html`:__ __`app/partials/phone-detail.html`:__
<pre> <pre>
<img ng-src="{{phone.images[0]}}" class="phone"> <img ng-src="{{phone.images[0]}}" class="phone">
@ -121,7 +121,7 @@ TODO!
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
step 5. step 5.
__`test/unit/controllerSpec.js`:__ __`test/unit/controllersSpec.js`:__
<pre> <pre>
... ...
describe('PhoneDetailCtrl', function(){ describe('PhoneDetailCtrl', function(){
@ -147,13 +147,9 @@ __`test/unit/controllerSpec.js`:__
... ...
</pre> </pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following You should now see the following output in the Testacular tab:
output.
Chrome: Runner reset. Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
@ -177,10 +173,11 @@ __`test/e2e/scenarios.js`:__
</pre> </pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
can see them running on {@link runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
angular's server}. Angular's server}.
# Experiments # Experiments

View file

@ -15,7 +15,7 @@ Navigate to one of the detail pages.
In the previous step, the details page displayed either "true" or "false" to indicate whether In the previous step, the details page displayed either "true" or "false" to indicate whether
certain phone features were present or not. We have used a custom filter to convert those text certain phone features were present or not. We have used a custom filter to convert those text
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see, what the filter code looks like. strings into glyphs: ✓ for "true", and ✘ for "false". Let's see what the filter code looks like.
The most important changes are listed below. You can see the full diff on {@link The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-8...step-9 https://github.com/angular/angular-phonecat/compare/step-8...step-9
@ -110,13 +110,9 @@ describe('filter', function() {
Note that you need to configure our test injector with the `phonecatFilters` module before any of Note that you need to configure our test injector with the `phonecatFilters` module before any of
our filter tests execute. our filter tests execute.
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following You should now see the following output in the Testacular tab:
output.
Chrome: Runner reset. Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
# Experiments # Experiments

View file

@ -13,7 +13,7 @@ In this step, you will add a clickable phone image swapper to the phone details
The phone details view displays one large image of the current phone and several smaller thumbnail The phone details view displays one large image of the current phone and several smaller thumbnail
images. It would be great if we could replace the large image with any of the thumbnails just by images. It would be great if we could replace the large image with any of the thumbnails just by
clicking on the desired thumbnail image. Let's have a look at how we can do this with angular. clicking on the desired thumbnail image. Let's have a look at how we can do this with Angular.
The most important changes are listed below. You can see the full diff on {@link The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-9...step-10 https://github.com/angular/angular-phonecat/compare/step-9...step-10
@ -102,10 +102,10 @@ __`test/e2e/scenarios.js`:__
}); });
</pre> </pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
can see them running on {@link runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
angular's server}. Angular's server}.
# Experiments # Experiments

View file

@ -13,7 +13,7 @@ In this step, you will improve the way our app fetches data.
The last improvement we will make to our app is to define a custom service that represents a {@link The last improvement we will make to our app is to define a custom service that represents a {@link
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
can make xhr requests for data in an easier way, without having to deal with the lower-level {@link can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
api/ng.$http $http} API, HTTP methods and URLs. api/ng.$http $http} API, HTTP methods and URLs.
The most important changes are listed below. You can see the full diff on {@link The most important changes are listed below. You can see the full diff on {@link
@ -57,13 +57,22 @@ The {@link api/ngResource.$resource `$resource`} service makes it easy to create
lines of code. This client can then be used in our application, instead of the lower-level {@link lines of code. This client can then be used in our application, instead of the lower-level {@link
api/ng.$http $http} service. api/ng.$http $http} service.
__`app/js/app.js`.__
<pre>
...
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
...
</pre>
We need to add 'phonecatServices' to 'phonecat' application's requires array.
## Controller ## Controller
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
lower-level {@link api/ng.$http $http} service, replacing it with a new service called lower-level {@link api/ng.$http $http} service, replacing it with a new service called
`Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to `Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to
use than `$http for interacting with data sources exposed as RESTful resources. It is also easier use than `$http` for interacting with data sources exposed as RESTful resources. It is also easier
now to understand what the code in our controllers is doing. now to understand what the code in our controllers is doing.
__`app/js/controllers.js`.__ __`app/js/controllers.js`.__
@ -107,8 +116,8 @@ This is a simple statement that we want to query for all phones.
An important thing to notice in the code above is that we don't pass any callback functions when An important thing to notice in the code above is that we don't pass any callback functions when
invoking methods of our Phone service. Although it looks as if the result were returned invoking methods of our Phone service. Although it looks as if the result were returned
synchronously, that is not the case at all. What is returned synchronously is a "future" — an synchronously, that is not the case at all. What is returned synchronously is a "future" — an
object, which will be filled with data when the xhr response returns. Because of the data-binding object, which will be filled with data when the XHR response returns. Because of the data-binding
in angular, we can use this future and bind it to our template. Then, when the data arrives, the in Angular, we can use this future and bind it to our template. Then, when the data arrives, the
view will automatically update. view will automatically update.
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
@ -205,13 +214,9 @@ describe('PhoneCat controllers', function() {
}); });
</pre> </pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following You should now see the following output in the Testacular tab:
output.
Chrome: Runner reset. Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
# Summary # Summary

View file

@ -3,7 +3,7 @@
@description @description
Our application is now complete. Feel free to experiment with the code further, and jump back to Our application is now complete. Feel free to experiment with the code further, and jump back to
previous steps using the `git checkout` or `goto_step.sh` commands. previous steps using the `git checkout` commandx.
For more details and examples of the Angular concepts we touched on in this tutorial, see the For more details and examples of the Angular concepts we touched on in this tutorial, see the
{@link guide/ Developer Guide}. {@link guide/ Developer Guide}.
@ -11,7 +11,7 @@ For more details and examples of the Angular concepts we touched on in this tuto
For several more examples of code, see the {@link cookbook/ Cookbook}. For several more examples of code, see the {@link cookbook/ Cookbook}.
When you are ready to start developing a project using Angular, we recommend that you bootstrap When you are ready to start developing a project using Angular, we recommend that you bootstrap
your development with the {@link https://github.com/angular/angular-seed angular seed} project. your development with the {@link https://github.com/angular/angular-seed angular-seed} project.
We hope this tutorial was useful to you and that you learned enough about Angular to make you want We hope this tutorial was useful to you and that you learned enough about Angular to make you want
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your to learn more. We especially hope you are inspired to go out and develop Angular web apps of your

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -58,10 +58,10 @@ exports.Example.prototype.addSource = function(name, content) {
}; };
exports.Example.prototype.toHtml = function() { exports.Example.prototype.toHtml = function() {
return '<h1>Source</h1>\n' + return '<h2>Source</h2>\n' +
this.toHtmlEdit() + this.toHtmlEdit() +
this.toHtmlTabs() + this.toHtmlTabs() +
'<h1>Demo</h1>\n' + '<h2>Demo</h2>\n' +
this.toHtmlEmbed(); this.toHtmlEmbed();
}; };

View file

@ -12,8 +12,10 @@ process.on('uncaughtException', function(err) {
var start = now(); var start = now();
var docs; var docs;
writer.makeDir('build/docs/syntaxhighlighter').then(function() { writer.makeDir('build/docs/', true).then(function() {
console.log('Generating Angular Reference Documentation...'); return writer.makeDir('build/docs/partials/');
}).then(function() {
console.log('Generating AngularJS Reference Documentation...');
return reader.collect(); return reader.collect();
}).then(function generateHtmlDocPartials(docs_) { }).then(function generateHtmlDocPartials(docs_) {
docs = docs_; docs = docs_;
@ -40,8 +42,10 @@ writer.makeDir('build/docs/syntaxhighlighter').then(function() {
function writeTheRest(writesFuture) { function writeTheRest(writesFuture) {
var metadata = ngdoc.metadata(docs); var metadata = ngdoc.metadata(docs);
writesFuture.push(writer.copyDir('img')); writesFuture.push(writer.symlinkTemplate('css'));
writesFuture.push(writer.copyDir('font')); writesFuture.push(writer.symlinkTemplate('font'));
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img'));
writesFuture.push(writer.symlinkTemplate('js'));
var manifest = 'manifest="/build/docs/appcache.manifest"'; var manifest = 'manifest="/build/docs/appcache.manifest"';
@ -53,7 +57,7 @@ function writeTheRest(writesFuture) {
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html', writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html',
writer.replace, {'doc:manifest': manifest})); writer.replace, {'doc:manifest': ''}));
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html', writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html',
writer.replace, {'doc:manifest': ''})); writer.replace, {'doc:manifest': ''}));
@ -65,27 +69,24 @@ function writeTheRest(writesFuture) {
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html', writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html',
writer.replace, {'doc:manifest': ''})); writer.replace, {'doc:manifest': ''}));
writesFuture.push(writer.copyTpl('offline.html')); writesFuture.push(writer.symlinkTemplate('offline.html'));
writesFuture.push(writer.copyTpl('docs-scenario.html'));
writesFuture.push(writer.copyTpl('js/jquery.min.js'));
writesFuture.push(writer.copyTpl('js/jquery.js'));
writesFuture.push(writer.output('js/docs-keywords.js', writesFuture.push(writer.copyTemplate('docs-scenario.html')); // will be rewritten, don't symlink
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
writesFuture.push(writer.output('docs-keywords.js',
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'])); ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render())); writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n')); writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
writesFuture.push(writer.output('appcache.manifest',appCache())); writesFuture.push(writer.output('appcache.manifest',appCache()));
writesFuture.push(writer.copyTpl('.htaccess')); writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
writesFuture.push(writer.copy('docs/src/templates/js/docs.js', 'js/docs.js')); writesFuture.push(writer.symlinkTemplate('favicon.ico'));
writesFuture.push(writer.copy('docs/src/templates/css/bootstrap.min.css', 'css/bootstrap.min.css'));
writesFuture.push(writer.copy('docs/src/templates/css/docs.css', 'css/docs.css'));
writesFuture.push(writer.copy('docs/src/templates/css/font-awesome.css', 'css/font-awesome.css'));
} }
function now() { return new Date().getTime(); } function now() { return new Date().getTime(); }
function noop() {}; function noop() {};

View file

@ -201,7 +201,7 @@ Doc.prototype = {
} }
}); });
flush(); flush();
this.shortName = this.name.split(/[\.:#]/).pop(); this.shortName = this.name.split(/[\.:#]/).pop().trim();
this.id = this.id || // if we have an id just use it this.id = this.id || // if we have an id just use it
(((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) || // try to extract it from file name (((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) || // try to extract it from file name
this.name; // default to name this.name; // default to name
@ -451,12 +451,16 @@ Doc.prototype = {
dom.h('Usage', function() { dom.h('Usage', function() {
dom.h('In HTML Template Binding', function() { dom.h('In HTML Template Binding', function() {
dom.tag('code', function() { dom.tag('code', function() {
dom.text('{{ '); if (self.usage) {
dom.text(self.shortName); dom.text(self.usage);
dom.text('_expression | '); } else {
dom.text(self.shortName); dom.text('{{ ');
self.parameters(dom, ':', true); dom.text(self.shortName);
dom.text(' }}'); dom.text('_expression | ');
dom.text(self.shortName);
self.parameters(dom, ':', true);
dom.text(' }}');
}
}); });
}); });
@ -733,7 +737,7 @@ function metadata(docs){
for ( var i = 1; i < path.length; i++) { for ( var i = 1; i < path.length; i++) {
path.splice(i, 1); path.splice(i, 1);
} }
var shortName = path.pop(); var shortName = path.pop().trim();
if (path.pop() == 'input') { if (path.pop() == 'input') {
shortName = 'input [' + shortName + ']'; shortName = 'input [' + shortName + ']';

View file

@ -6,6 +6,7 @@
# #
# This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version. # This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version.
Options -Indexes
RewriteEngine on RewriteEngine on
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL" RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
RewriteRule appcache.manifest appcache-offline.manifest RewriteRule appcache.manifest appcache-offline.manifest

View file

@ -19,6 +19,11 @@ img.AngularJS-small {
height: 1em; height: 1em;
} }
.icon-cog {
line-height: 13px;
}
/* =============================== */ /* =============================== */
.form-search .dropdown-menu { .form-search .dropdown-menu {
@ -140,6 +145,11 @@ ul.events > li > h3 {
font-family: monospace; font-family: monospace;
} }
.center {
display: block;
margin: 2em auto;
}
.diagram { .diagram {
display: block; display: block;
margin: 2em auto; margin: 2em auto;
@ -170,3 +180,7 @@ ul.events > li > h3 {
color: white; color: white;
text-decoration: none; text-decoration: none;
} }
.clear {
clear: both;
}

View file

@ -2,8 +2,42 @@
<html xmlns:ng="http://angularjs.org"> <html xmlns:ng="http://angularjs.org">
<head> <head>
<title>AngularJS Docs E2E Test Runner</title> <title>AngularJS Docs E2E Test Runner</title>
<script type="text/javascript" src="../angular-scenario.js" ng:autotest></script> <script>
<script type="text/javascript" src="docs-scenario.js"></script> var production = location.hostname === 'docs.angularjs.org',
headEl = document.head,
angularVersion = {
current: '"NG_VERSION_FULL"', // rewrite during build
stable: '"NG_VERSION_STABLE"'
};
addTag('script', {src: path('angular-scenario.js')}, function() {
addTag('script', {src: 'docs-scenario.js'}, function() {
angular.scenario.setUpAndRun();
});
});
function addTag(name, attributes, callback) {
var el = document.createElement(name),
attrName;
for (attrName in attributes) {
el.setAttribute(attrName, attributes[attrName]);
}
if (callback) {
el.onload = callback;
}
headEl.appendChild(el);
}
function path(name) {
return production
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
: '../' + name;
}
</script>
</head> </head>
<body> <body>
</body> </body>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -22,8 +22,13 @@
baseUrl = location.href.replace(rUrl, indexFile), baseUrl = location.href.replace(rUrl, indexFile),
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl), jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
debug = /index[^\.]*-debug\.html$/.test(baseUrl), debug = /index[^\.]*-debug\.html$/.test(baseUrl),
production = location.hostname === 'docs.angularjs.org',
headEl = document.getElementsByTagName('head')[0], headEl = document.getElementsByTagName('head')[0],
sync = true; sync = true,
angularVersion = {
current: '"NG_VERSION_FULL"', // rewrite during build
stable: '"NG_VERSION_STABLE"'
};
addTag('base', {href: baseUrl}); addTag('base', {href: baseUrl});
addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'}); addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'});
@ -37,9 +42,23 @@
addTag('script', {src: path('angular-bootstrap.js') }, sync); addTag('script', {src: path('angular-bootstrap.js') }, sync);
addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync); addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync);
addTag('script', {src: 'js/docs.js'}, sync); addTag('script', {src: 'js/docs.js'}, sync);
addTag('script', {src: 'js/docs-keywords.js'}, sync); addTag('script', {src: 'docs-keywords.js'}, sync);
function path(name) { function path(name) {
if (production) {
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
angularVersion.stable +
'/' +
name.replace(/\.js$/, '.min.js');
} else {
name = 'http://code.angularjs.org/' +
angularVersion.stable +
'/' +
name.replace(/\.js$/, '.min.js');
}
return name;
}
return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js'); return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js');
} }
@ -107,10 +126,10 @@
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b> <i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li class="disabled"><a href="">Why AngularJS?</a></li> <li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li> <li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
<li><a href="tutorial">Tutorial</a></li> <li><a href="tutorial">Tutorial</a></li>
<li><a href="https://github.com/angular/angular.js/wiki/Projects-using-AngularJS">Case Studies</a></li> <li><a href="http://builtwith.angularjs.org/">Case Studies</a></li>
<li><a href="misc/faq">FAQ</a></li> <li><a href="misc/faq">FAQ</a></li>
</ul> </ul>
</li> </li>
@ -120,10 +139,10 @@
<i class="icon-book icon-white"></i> Develop <b class="caret"></b> <i class="icon-book icon-white"></i> Develop <b class="caret"></b>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="tutorial">Tutorial</a></li> <li><a href="http://docs.angularjs.org/tutorial">Tutorial</a></li>
<li><a href="guide/">Developer Guide</a></li> <li><a href="http://docs.angularjs.org/guide/">Developer Guide</a></li>
<li><a href="api/">API Reference</a></li> <li><a href="http://docs.angularjs.org/api/">API Reference</a></li>
<li><a href="misc/contribute">Contribute</a></li> <li><a href="http://docs.angularjs.org/misc/contribute">Contribute</a></li>
<li><a href="http://code.angularjs.org/">Download</a></li> <li><a href="http://code.angularjs.org/">Download</a></li>
</ul> </ul>
</li> </li>

View file

@ -30,9 +30,16 @@ docsApp.directive.code = function() {
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) { docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
return { return {
template: '<button ng-click="fiddle($event)" class="btn btn-primary pull-right"><i class="icon-pencil icon-white"></i> Edit</button>\n', template: '<div class="btn-group pull-right">' +
'<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
' <i class="icon-pencil icon-white"></i> Edit<span class="caret"></span>' +
'</a>' +
'<ul class="dropdown-menu">' +
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
'</ul>',
scope: true, scope: true,
controller: function($scope, $attrs, openJsFiddle) { controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
var sources = { var sources = {
module: $attrs.sourceEdit, module: $attrs.sourceEdit,
deps: read($attrs.sourceEditDeps), deps: read($attrs.sourceEditDeps),
@ -45,14 +52,19 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
$scope.fiddle = function(e) { $scope.fiddle = function(e) {
e.stopPropagation(); e.stopPropagation();
openJsFiddle(sources); openJsFiddle(sources);
} };
$scope.plunkr = function(e) {
e.stopPropagation();
openPlunkr(sources);
};
} }
} }
function read(text) { function read(text) {
var files = []; var files = [];
angular.forEach(text ? text.split(' ') : [], function(refId) { angular.forEach(text ? text.split(' ') : [], function(refId) {
files.push({name: refId.split('-')[0], content: getEmbeddedTemplate(refId)}); // refId is index.html-343, so we need to strip the unique ID when exporting the name
files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
}); });
return files; return files;
} }
@ -96,7 +108,7 @@ docsApp.directive.docTutorialReset = function() {
' <ol>\n' + ' <ol>\n' +
' <li><p>Reset the workspace to step ' + step + '.</p>' + ' <li><p>Reset the workspace to step ' + step + '.</p>' +
' <pre>' + command + '</pre></li>\n' + ' <pre>' + command + '</pre></li>\n' +
' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{{docTutorialReset}}/app">angular\'s server</a>.</p></li>\n' + ' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-' + step + '/app">Angular\'s server</a>.</p></li>\n' +
' </ol>\n' + ' </ol>\n' +
' </div>\n'; ' </div>\n';
} }
@ -111,8 +123,6 @@ docsApp.directive.docTutorialReset = function() {
'<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' + '<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' +
tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) + tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) +
tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) + tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) +
tab('Snapshots on Mac/Linux', './goto_step.sh ' + step, 'snapshotUnix', step) +
tab('Snapshots on on Windows', './goto_step.bat ' + step, 'snapshotWin', step) +
'</div>\n'); '</div>\n');
} }
}; };
@ -147,8 +157,47 @@ 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>', var HTML = '<div ng-app=\"{{module}}\">\n{{html:2}}</div>',
CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' + CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
'{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}', '{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}',
@ -297,7 +346,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
tutorial: 'Tutorial', tutorial: 'Tutorial',
cookbook: 'Examples' cookbook: 'Examples'
}; };
$scope.$watch(function() {return $location.path(); }, function(path) { $scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
// ignore non-doc links which are used in examples // ignore non-doc links which are used in examples
if (DOCS_PATH.test(path)) { if (DOCS_PATH.test(path)) {
var parts = path.split('/'), var parts = path.split('/'),

View file

@ -4,7 +4,7 @@
*/ */
var qfs = require('q-fs'); var qfs = require('q-fs');
var Q = require('qq'); var Q = require('qq');
var OUTPUT_DIR = "build/docs/"; var OUTPUT_DIR = 'build/docs/';
var fs = require('fs'); var fs = require('fs');
exports.output = output; exports.output = output;
@ -17,29 +17,27 @@ function output(file, content) {
}; };
//recursively create directory //recursively create directory
exports.makeDir = function(path) { exports.makeDir = function(p) {
var parts = path.split(/\//); var parts = p.split(/\//);
var path = "."; var path = ".";
//Sequentially create directories
var done = Q.defer();
(function createPart() {
if(!parts.length) { // Recursively rebuild directory structure
done.resolve(); return qfs.exists(p).
} else { then(function createPart(exists) {
path += "/" + parts.shift(); if(!exists && parts.length) {
qfs.isDirectory(path).then(function(isDir) { path += "/" + parts.shift();
if(!isDir) { return qfs.exists(path).then(function(exists) {
qfs.makeDirectory(path); if (!exists) {
return qfs.makeDirectory(path).then(createPart, createPart);
} else {
return createPart();
}
});
} }
createPart();
}); });
}
})();
return done.promise;
}; };
exports.copyTpl = function(filename) { exports.copyTemplate = function(filename) {
return exports.copy('docs/src/templates/' + filename, filename); return exports.copy('docs/src/templates/' + filename, filename);
}; };
@ -59,8 +57,29 @@ exports.copy = function(from, to, transform) {
} }
return output(to, content); return output(to, content);
}); });
};
exports.symlink = symlink;
function symlink(from, to) {
return qfs.exists(to).then(function(exists) {
if (!exists) {
return qfs.symbolicLink(to, from);
}
});
} }
exports.symlinkTemplate = symlinkTemplate;
function symlinkTemplate(filename) {
var dest = OUTPUT_DIR + filename,
dirDepth = dest.split('/').length,
src = Array(dirDepth).join('../') + 'docs/src/templates/' + filename;
return symlink(src, dest);
}
/* Replace placeholders in content accordingly /* Replace placeholders in content accordingly
* @param content{string} content to be modified * @param content{string} content to be modified
* @param replacements{obj} key and value pairs in which key will be replaced with value in content * @param replacements{obj} key and value pairs in which key will be replaced with value in content
@ -132,3 +151,4 @@ exports.toString = function toString(obj) {
function noop() {}; function noop() {};

View file

@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<title>Personal Log Scenario Runner</title> <title>Personal Log Scenario Runner</title>
<meta http-equiv="expires" content="0">
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script> <script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
<script type="text/javascript" src="personalLogScenario.js"></script> <script type="text/javascript" src="personalLogScenario.js"></script>
</head> </head>

View file

@ -1,4 +1,19 @@
#!/bin/bash #!/usr/bin/env bash
if [ ! -e gen_docs.disable ]; then
./node_modules/.bin/jasmine-node docs/spec --noColor && node docs/src/gen-docs.js JASMINE_NODE='jasmine-node'
local_jasmine='./node_modules/.bin/jasmine-node'
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
if [[ -x "$local_jasmine" ]];then
JASMINE_NODE="$local_jasmine"
else
echo 'Could not find a locally or globally installed executable of' \
'jasmine-node. Try: `npm install jasmine-node`.' >&2
exit 1
fi
fi
if [[ ! -e gen_docs.disable ]]; then
echo 'Testing, then building documentation...'
"$JASMINE_NODE" docs/spec --noColor && node docs/src/gen-docs.js
fi fi

View file

@ -1,47 +0,0 @@
#!/usr/bin/env node
/* This file reads in list of files from angularFiles.js and generate various jstd config files */
var fs = require('fs'),
angularSrc,
angularScenario;
fs.readFile('angularFiles.js', function(err, data) {
eval(data.toString());
var prefix = 'server: http://localhost:9876\n\n',
prefixScenario = 'server: http://localhost:9877\n\n';
angularSrc = angularFiles.angularSrc.join('\n- ');
angularScenario = angularFiles.angularScenario.join('\n- ');
fs.writeFile('./jsTestDriver.conf', prefix + combine(angularFiles.jstd,
angularFiles.jstdExclude));
fs.writeFile('./jsTestDriver-modules.conf', prefix + combine(angularFiles.jstdModules));
fs.writeFile('./jsTestDriver-scenario.conf', prefixScenario +
combine(angularFiles.jstdScenario) +
'\n\nproxy:\n- {matcher: "*", server: "http://localhost:8000"}');
fs.writeFile('./jsTestDriver-perf.conf', prefix + combine(angularFiles.jstdPerf,
angularFiles.jstdPerfExclude));
fs.writeFile('./jsTestDriver-jquery.conf', prefix + combine(angularFiles.jstdJquery,
angularFiles.jstdJqueryExclude));
fs.writeFile('./jsTestDriver-coverage.conf', prefix +
combine(angularFiles.jstd, angularFiles.jstdExclude) +
'\n\nplugin:\n- name: "coverage"\n' +
'jar: "lib/jstestdriver/coverage.jar"\n' +
'module: "com.google.jstestdriver.coverage.CoverageModule"');
});
function combine(load, exclude) {
var fileList = 'load:\n- ' + load.join('\n- ');
if (exclude) fileList += ('\n\nexclude:\n- ' + exclude.join('\n- '));
//Replace placeholders for src list before returning
return fileList.replace(/@(.*)/g, function(all, alias) {
return angularFiles[alias].join('\n- ');
});
}

View file

@ -2,6 +2,7 @@
<html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org"> <html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="expires" content="0">
<title>&lt;angular/&gt; Docs Scenario Runner</title> <title>&lt;angular/&gt; Docs Scenario Runner</title>
<script type="text/javascript" src="../../build/angular-scenario.js" ng:autotest></script> <script type="text/javascript" src="../../build/angular-scenario.js" ng:autotest></script>
<script type="text/javascript" src="i18n-e2e.js"></script> <script type="text/javascript" src="i18n-e2e.js"></script>

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

32
init-repo.sh Executable file
View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
#
# Script to initialize angular repo
# - install required node packages
# - install Testacular
# - install git hooks
node=`which node 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NodeJS."
echo "http://nodejs.org/"
exit 1
fi
npm=`which npm 2>&1`
if [ $? -ne 0 ]; then
echo "Please install NPM."
fi
echo "Installing required npm packages..."
npm install
testacular=`which testacular 2>&1`
if [ $? -ne 0 ]; then
echo "Installing Testacular..."
npm install -g testacular
fi
echo "Installing git hooks..."
ln -sf ../../validate-commit-msg.js .git/hooks/commit-msg

2
java
View file

@ -1,2 +0,0 @@
#!/bin/sh
/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java $@

View file

@ -1,198 +0,0 @@
/**
* @fileoverview Jasmine JsTestDriver Adapter.
* @author misko@hevery.com (Misko Hevery)
*/
(function(window) {
var rootDescribes = new Describes(window);
var describePath = [];
rootDescribes.collectMode();
var JASMINE_TYPE = 'jasmine test case';
TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE);
var jasminePlugin = {
name:'jasmine',
getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) {
for (var i = 0; i < testCaseInfos.length; i++) {
if (testCaseInfos[i].getType() == JASMINE_TYPE) {
testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
}
}
return false;
},
runTestConfiguration: function(testRunConfiguration, onTestDone, onTestRunConfigurationComplete){
if (testRunConfiguration.getTestCaseInfo().getType() != JASMINE_TYPE) return false;
var jasmineEnv = jasmine.currentEnv_ = new jasmine.Env();
rootDescribes.playback();
var specLog = jstestdriver.console.log_ = [];
var start;
jasmineEnv.specFilter = function(spec) {
return rootDescribes.isExclusive(spec);
};
jasmineEnv.reporter = {
log: function(str){
specLog.push(str);
},
reportRunnerStarting: function(runner) { },
reportSpecStarting: function(spec) {
specLog = jstestdriver.console.log_ = [];
start = new Date().getTime();
},
reportSpecResults: function(spec) {
var suite = spec.suite;
var results = spec.results();
if (results.skipped) return;
var end = new Date().getTime();
var messages = [];
var resultItems = results.getItems();
var state = 'passed';
for ( var i = 0; i < resultItems.length; i++) {
if (!resultItems[i].passed()) {
state = resultItems[i].message.match(/AssertionError:/) ? 'error' : 'failed';
messages.push({
message: resultItems[i].toString(),
name: resultItems[i].trace.name,
stack: formatStack(resultItems[i].trace.stack)
});
}
}
onTestDone(
new jstestdriver.TestResult(
suite.getFullName(),
spec.description,
state,
jstestdriver.angular.toJson(messages),
specLog.join('\n'),
end - start));
},
reportSuiteResults: function(suite) {},
reportRunnerResults: function(runner) {
onTestRunConfigurationComplete();
}
};
jasmineEnv.execute();
return true;
},
onTestsFinish: function(){
jasmine.currentEnv_ = null;
rootDescribes.collectMode();
}
};
jstestdriver.pluginRegistrar.register(jasminePlugin);
function formatStack(stack) {
var lines = (stack||'').split(/\r?\n/);
var frames = [];
for (i = 0; i < lines.length; i++) {
if (!lines[i].match(/\/jasmine[\.-]/)) {
frames.push(lines[i].replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, ' '));
}
}
return frames.join('\n');
}
function noop(){}
function Describes(window){
var describes = {};
var beforeEachs = {};
var afterEachs = {};
// Here we store:
// 0: everyone runs
// 1: run everything under ddescribe
// 2: run only iits (ignore ddescribe)
var exclusive = 0;
var collectMode = true;
intercept('describe', describes);
intercept('xdescribe', describes);
intercept('beforeEach', beforeEachs);
intercept('afterEach', afterEachs);
function intercept(functionName, collection){
window[functionName] = function(desc, fn){
if (collectMode) {
collection[desc] = function(){
jasmine.getEnv()[functionName](desc, fn);
};
} else {
jasmine.getEnv()[functionName](desc, fn);
}
};
}
window.ddescribe = function(name, fn){
if (exclusive < 1) {
exclusive = 1; // run ddescribe only
}
window.describe(name, function(){
var oldIt = window.it;
window.it = function(name, fn){
if (fn) fn.exclusive = 1; // run anything under ddescribe
oldIt(name, fn);
};
try {
fn.call(this);
} finally {
window.it = oldIt;
};
});
};
window.iit = function(name, fn){
exclusive = fn.exclusive = 2; // run only iits
jasmine.getEnv().it(name, fn);
};
this.collectMode = function() {
collectMode = true;
exclusive = 0; // run everything
};
this.playback = function(){
collectMode = false;
playback(beforeEachs);
playback(afterEachs);
playback(describes);
function playback(set) {
for ( var name in set) {
set[name]();
}
}
};
this.isExclusive = function(spec) {
if (exclusive) {
var blocks = spec.queue.blocks;
for ( var i = 0; i < blocks.length; i++) {
if (blocks[i].func.exclusive >= exclusive) {
return true;
}
}
return false;
}
return true;
};
}
})(window);
// Patch Jasmine for proper stack traces
jasmine.Spec.prototype.fail = function (e) {
var expectationResult = new jasmine.ExpectationResult({
passed: false,
message: e ? jasmine.util.formatException(e) : 'Exception'
});
// PATCH
if (e) {
expectationResult.trace = e;
}
this.results_.addResult(expectationResult);
};

View file

@ -1 +0,0 @@
da92db714142b49f9cf61db664e782bb0ccad80b

View file

@ -1,20 +0,0 @@
Copyright (c) 2008-2011 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,190 +0,0 @@
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

View file

@ -1,166 +0,0 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

View file

@ -1 +0,0 @@
1.1.0

Binary file not shown.

View file

@ -1,130 +0,0 @@
#
# Configuration File for JavaScript Lint 0.3.0
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
#
# This configuration file can be used to lint a collection of scripts, or to enable
# or disable warnings for scripts that are linted via the command line.
#
### Warnings
# Enable or disable warnings based on requirements.
# Use "+WarningName" to display or "-WarningName" to suppress.
#
-no_return_value # function {0} does not always return a value
+duplicate_formal # duplicate formal argument {0}
-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
+var_hides_arg # variable {0} hides argument
+redeclared_var # redeclaration of {0} {1}
-anon_no_return_value # anonymous function does not always return a value
+missing_semicolon # missing semicolon
+meaningless_block # meaningless block; curly braces have no impact
+comma_separated_stmts # multiple statements separated by commas (use semicolons?)
-unreachable_code # unreachable code
-missing_break # missing break statement
+missing_break_for_last_case # missing break statement for last case in switch
+comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
+useless_void # use of the void type may be unnecessary (void is always undefined)
+multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
+use_of_label # use of label
-block_without_braces # block statement without curly braces
+leading_decimal_point # leading decimal point may indicate a number or an object member
+trailing_decimal_point # trailing decimal point may indicate a number or an object member
+octal_number # leading zeros make an octal number
+nested_comment # nested comment
-misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
+empty_statement # empty statement or extra semicolon
-missing_option_explicit # the "option explicit" control comment is missing
+partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
+dup_option_explicit # duplicate "option explicit" control comment
+useless_assign # useless assignment
+ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
+ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
-missing_default_case # missing default case in switch statement
+duplicate_case_in_switch # duplicate case in switch statements
+default_not_at_end # the default case is not at the end of the switch statement
+legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
+jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
+useless_comparison # useless comparison; comparing identical expressions
+with_statement # with statement hides undeclared variables; use temporary variable instead
+trailing_comma_in_array # extra comma is not recommended in array initializers
+assign_to_function_call # assignment to a function call
+parseint_missing_radix # parseInt missing radix parameter
### Output format
# Customize the format of the error message.
# __FILE__ indicates current file path
# __FILENAME__ indicates current file name
# __LINE__ indicates current line
# __ERROR__ indicates error message
#
# Visual Studio syntax (default):
+output-format __FILE__(__LINE__): __ERROR__
# Alternative syntax:
#+output-format __FILE__:__LINE__: __ERROR__
### Context
# Show the in-line position of the error.
# Use "+context" to display or "-context" to suppress.
#
+context
### Semicolons
# By default, assignments of an anonymous function to a variable or
# property (such as a function prototype) must be followed by a semicolon.
#
+lambda_assign_requires_semicolon
### Control Comments
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
# although legacy control comments are enabled by default for backward compatibility.
#
+legacy_control_comments
### JScript Function Extensions
# JScript allows member functions to be defined like this:
# function MyObj() { /*constructor*/ }
# function MyObj.prototype.go() { /*member function*/ }
#
# It also allows events to be attached like this:
# function window::onload() { /*init page*/ }
#
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
#
-jscript_function_extensions
### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
-always_use_option_explicit
# Define certain identifiers of which the lint is not aware.
# (Use this in conjunction with the "undeclared identifier" warning.)
#
# Common uses for webpages might be:
#+define window
#+define document
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
+process src/*.js
+process src/service/*.js
+process src/scenario/*.js
+process test/*.js
+process test/service/*.js
+process test/scenario/*.js

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
1.3.3d

View file

@ -80,7 +80,10 @@ StaticServlet.MimeMap = {
'jpeg': 'image/jpeg', 'jpeg': 'image/jpeg',
'gif': 'image/gif', 'gif': 'image/gif',
'png': 'image/png', 'png': 'image/png',
'manifest': 'text/cache-manifest' 'manifest': 'text/cache-manifest',
// it should be application/font-woff
// but only this silences chrome warnings
'woff': 'font/opentype'
}; };
StaticServlet.prototype.handleRequest = function(req, res) { StaticServlet.prototype.handleRequest = function(req, res) {
@ -105,6 +108,7 @@ StaticServlet.prototype.handleRequest = function(req, res) {
path = path.replace(match[0], '/index.html'); path = path.replace(match[0], '/index.html');
sys.puts('Rewrite to ' + path); sys.puts('Rewrite to ' + path);
} }
// end of docs rewriting // end of docs rewriting
fs.stat(path, function(err, stat) { fs.stat(path, function(err, stat) {

View file

@ -1,17 +0,0 @@
#!/bin/sh
./gen_docs.sh
rm build/docs/index.html
rm -rf build/docs/css
rm -rf build/docs/js
rm -rf build/docs/img
rm -rf build/docs/examples
cd build/docs
ln -s ../../docs/src/templates/index.html
ln -s ../../docs/src/templates/css
ln -s ../../docs/src/templates/js
ln -s ../../docs/img
ln -s ../../docs/examples

View file

@ -2,6 +2,7 @@
"name": "AngularJS", "name": "AngularJS",
"version": "0.0.0", "version": "0.0.0",
"dependencies" : { "dependencies" : {
"testacular" : "canary",
"jasmine-node" : "*", "jasmine-node" : "*",
"q-fs" : "*", "q-fs" : "*",
"qq" : "*" "qq" : "*"

18
pom.xml
View file

@ -1,18 +0,0 @@
<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>

View file

@ -1 +0,0 @@
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 20000 --config jsTestDriver-coverage.conf

View file

@ -1,3 +0,0 @@
#!/bin/bash
java -jar lib/jstestdriver/JsTestDriver.jar --port 9877 --browserTimeout 90000 --config jsTestDriver-scenario.conf

View file

@ -1,4 +0,0 @@
#!/bin/bash
node gen_jstd_configs.js
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 90000

View file

@ -788,7 +788,7 @@ function toKeyValue(obj) {
/** /**
* We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow * We need our custom method 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 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
* segments: * segments:
* segment = *pchar * segment = *pchar
@ -832,7 +832,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @name ng.directive:ngApp * @name ng.directive:ngApp
* *
* @element ANY * @element ANY
* @param {angular.Module} ngApp on optional application * @param {angular.Module} ngApp an optional application
* {@link angular.module module} name to load. * {@link angular.module module} name to load.
* *
* @description * @description

View file

@ -97,5 +97,15 @@ HashQueueMap.prototype = {
return array.shift(); return array.shift();
} }
} }
},
/**
* return the first item without deleting it
*/
peek: function(key) {
var array = this[hashKey(key)];
if (array) {
return array[0];
}
} }
}; };

View file

@ -20,7 +20,7 @@
* // create an injector * // create an injector
* var $injector = angular.injector(['ng']); * var $injector = angular.injector(['ng']);
* *
* // use the injector to kick of your application * // use the injector to kick off your application
* // use the type inference to auto inject arguments, or use implicit injection * // use the type inference to auto inject arguments, or use implicit injection
* $injector.invoke(function($rootScope, $compile, $document){ * $injector.invoke(function($rootScope, $compile, $document){
* $compile($document)($rootScope); * $compile($document)($rootScope);
@ -40,7 +40,7 @@
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/; var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function annotate(fn) { function annotate(fn) {
var $inject, var $inject,

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