Compare commits

..

212 Commits

Author SHA1 Message Date
Igor Minar 2ee0f56c54 chore(release): cutting the 1.1.1 pathological-kerning release 2012-11-27 01:45:35 +01:00
Igor Minar 9b18644f30 docs(CHANGELOG): release notes for 1.0.3 and 1.1.1 releases 2012-11-27 01:43:05 +01:00
Rado Kirov fce100a46c fix($http): only set X-XSFR-TOKEN header for same-domain request
This is needed to prevent CORS preflight checks. The XSFR token
is quite useless for CORS requests anyway.

BREAKING CHANGE: X-XSFR-TOKEN is no longer send for cross domain
requests. This shouldn't affect any known production service.

Closes #1096
2012-11-26 23:58:59 +01:00
Rado Kirov 3a75b1124d fix($http): remove 'X-Requested-With' from header defaults
X-Requested-With header is rarely used in practice and by using
it all the time we are triggering preflight checks for crossdomain
requests.

We could try detecting if we are doing CORS requests or not, but
it doesn't look like it's worth the trouble.

BREAKING CHANGE: 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';
}]);
```

Closes #1004
2012-11-26 23:36:40 +01:00
Rado Kirov a32bc40fd7 fix($location): reset $location.$$replace with every watch call
Closes #1111
2012-11-26 23:21:02 +01:00
Igor Minar cfe13b5dac chore(validate-commit-msg): recognize 'revert' as valid commit type 2012-11-26 21:05:38 +01:00
Igor Minar d859dcecea 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 20:36:53 +01:00
Igor Minar d3b32a7c94 style(jqLite): better variable names
selector => cssClasses
2012-11-26 20:36:53 +01:00
Igor Minar 1b17dfa693 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 20:36:53 +01:00
Igor Minar e6d9bea4f3 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 20:36:53 +01:00
Igor Minar c8e9105fe6 test(ngRepeat): clean up and improve tests 2012-11-26 20:36:52 +01:00
Igor Minar d644dcfa52 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:31:54 +01:00
Igor Minar e7d37ee45a test(ngRepeat): add test for issue #1076 2012-11-26 20:17:11 +01:00
Pawel Kozlowski 733a97adf8 feat(form): add ability to reset a form to pristine state
Retting a form to pristine state will cause all of the nested
form and form controls to be recursively reset as well.

Closes #856
2012-11-26 16:44:34 +01:00
Igor Minar 96ed9ff59a fix(jqLite): support append on document fragment
previously jquery didn't support append on this node type, now it does
(since 1.8.x) so I'm adding this to jqlite as well.
2012-11-26 15:45:04 +01:00
Igor Minar b9a9f91fbf 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 15:45:04 +01:00
Igor Minar 650fd933df 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 15:45:04 +01:00
Igor Minar e249502880 chore(jquery): upgrade to jquery 1.8.2 2012-11-26 15:45:04 +01:00
Iristyle ca3e0e7374 docs(CONTRIBUTING.md): add contrib info file for GitHub 2012-11-25 21:00:14 +01:00
Vojta Jina e6966e05f5 fix(Scope): allow removing a listener during event 2012-11-25 11:39:54 +01:00
Kevin Western 682418f029 docs(README.md): fix "API Docs" link
use direct link to api docs
2012-11-25 01:21:52 +01:00
Dean Sofer c8fd7fd0e2 docs(api): add ngRequired to input/select/textarea directives
Closes #1202
2012-11-25 01:18:10 +01:00
JP Sugarbroad 168db33985 feat($cacheFactory): cache.put now returns the added value
This allows common programming patterns to be expressed with more
concise code.

See #1583 for code examples.
2012-11-25 00:01:34 +01:00
Tom Davis 79af2badcb fix($http): config.param should expand array values properly
Today, calling e.g. $http(url, { params: { a: [1,2,3] } }) results in a query
string like "?a=%5B1%2C2%2C3%5D" which is undesirable. This commit enhances
buildURL to createa query string like "?a=1&a=2&a=3".

BREAKING CHANGE: 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.

Closes #1363
2012-11-24 22:26:23 +01:00
Zach Dexter 610927d77b feat(linky): allow optional 'target' argument
Closes #1443
2012-11-24 22:21:50 +01:00
Jeremy Tymes 55d15806fb 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:56:28 +01:00
Adrian Gheorghe 94e1c0391c 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:27:24 +01:00
Kris Jenkins b21f4a376d docs(): Fix a couple of typos in the documentation 2012-11-21 23:06:59 +01:00
Dave Clayton f28f283fcf docs(guide/concepts): some typo/grammar fixes 2012-11-17 23:55:32 +01:00
John Hume e362a510e3 docs(guide/directive): fix typo 2012-11-17 23:49:19 +01:00
Uri Goldshtein 8a7f752a80 docs($q): fix missing bracket in the example 2012-11-17 23:45:08 +01:00
Igor Minar af7e0bd0a7 fix(CSP): update to the latest CSP api
window.SecurityPolicy.isActive() is now window.securityPolicy.isActive

since this is available only in Chrome Canary which has already been
updated, we can safely make this change without worrying about
backwards compatilibty.

Closes #1577
2012-11-15 01:46:58 +01:00
Igor Minar bd524fc4e5 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:56:28 +01:00
Haralan Dobrev 19a324ce11 docs(angular.module): improve angular.Module#run docs 2012-11-11 11:40:18 +01:00
Jamison Dance cd8b78ebfd docs(guide): fix run-on sentence in modules guide 2012-11-11 11:34:06 +01:00
Jamison Dance 8891757891 docs(tutorial): change module name in step-7 2012-11-11 11:34:06 +01:00
Wes Alvaro 5c5193946d 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:31:51 +01:00
Josh Adams ffa6c5195f docs(ngList): fix typo 2012-11-11 11:24:59 +01:00
Josh Adams a758799c7f docs(encodeUriSegment): fix typo 2012-11-11 11:22:43 +01:00
Tim Macfarlane e9253a88b9 docs(guide/directive): fix names in scope '='; easier to grok 2012-11-11 11:20:24 +01:00
Christian Vuerings f3e053cb6f docs(ngHide): Fix typo and make it more in line with ngShow 2012-11-11 10:36:28 +01:00
Anna Vester 04450c48df feat($sanitize): support telephone links
Per http://www.ietf.org/rfc/rfc3966.txt support tel: links
2012-11-11 10:31:27 +01:00
Igor Minar 8650843603 chore(docs): fix docs-scenario.html 2012-11-11 10:31:27 +01:00
Igor Minar e034fa08a8 chore(docs): remove obsolete gae files 2012-11-11 10:31:27 +01:00
Miško Hevery c6b4ab3548 Update docs/content/guide/directive.ngdoc
docs(directive): fix typo
2012-11-05 19:34:20 -08:00
Sudhir Jonathan b429f538a3 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 16:47:28 -07:00
Sudhir Jonathan b3cae4f457 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:13 -07:00
Igor Minar 7b52a976e1 chore(validate-commit-msg): allow '/' in scope 2012-10-31 14:47:59 -07:00
Fred Sauer 3a624a7ff5 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:47:53 -07:00
Tim Macfarlane b32adb7dea docs(module): fix typo in example
fixed example app, `simpleAppModule` should have been `myAppModule`.
2012-10-31 14:21:28 -07:00
sqwishy trick 271d2bed3a chore(injector): fix typo in injector documentation 2012-10-31 14:19:05 -07:00
Adam Macejak 249a1d84e7 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 13:58:13 -07:00
Daniel Luz fdf85bfd86 docs(contribute): fix task name for continuous testing 2012-10-31 13:12:49 -07:00
Igor Minar 090e5426ac 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:03:50 -07:00
Shyam Seshadri 7c67b2fb6a feat(docs): add plunkr support
Add option to edit source in Angular Docs in Plunkr in addition to JsFiddle
2012-10-31 12:54:52 -07:00
Daniel Luz 3c9b39ff52 fix(doc): typo on FAQ
Closes #1493
2012-10-31 10:24:12 -07:00
Igor Minar 54b3875ba5 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 17:49:56 -07:00
Igor Minar 008a782bc8 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 17:49:36 -07:00
Igor Minar 524c5c8b5d style($compile): better fn names for debugging 2012-10-29 17:46:44 -07:00
Igor Minar b936236fbc refactor(): simplify nodeLinkFn 2012-10-29 17:46:44 -07:00
Igor Minar fc115bfd0d 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 17:46:44 -07:00
Braden Shepherdson bca1604c12 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-26 08:51:28 -07:00
Braden Shepherdson f4517b500c doc(faq): Add Common Pitfalls section
Describes several common pitfalls new users of Angular fall into that
I've observed in #angularjs.
2012-10-26 08:49:44 -07:00
Braden Shepherdson f54edbbdd4 doc(faq): Fix minor spelling and wording errors 2012-10-26 08:49:44 -07:00
Igor Minar be50e0769a chore(check-size.sh): fix rake target 2012-10-22 12:39:37 -07:00
Igor Minar cf78fb5661 docs(contribute): add CLA note to code submission section 2012-10-19 09:14:05 -07:00
Igor Minar 5c9eb75867 docs(contribute): add visible link to github project 2012-10-19 09:02:06 -07:00
Igor Minar f43cf3b816 chore(jstd-scenario-adapter): remove from our repo
since we don't need the adapter for JsTD (testacular contains its own),
I'm removing this dead code.
2012-10-18 03:26:51 -07:00
Igor Minar 175e727f05 chore(validate-commit-msg): allow * and - in scope string 2012-10-18 03:26:08 -07:00
Igor Minar d938983c06 chore(jasmine): remove Jasmine from our repo
it's bundled with Testacular, so we don't need it here
2012-10-18 03:14:27 -07:00
Igor Minar 8d69f4b93a chore(jstd): remove JsTestDriver from our repo
Testacular FTW!
2012-10-18 03:13:04 -07:00
Igor Minar ca96ec32f9 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:33:45 -07:00
Igor Minar 4f59022582 chore(Rakefile): remove test_out dir when cleaning 2012-10-17 15:44:18 -07:00
Igor Minar 3bd95dbb1a 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 15:36:51 -07:00
Igor Minar c959fa4fe8 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 14:38:15 -07:00
Vojta Jina a5d434d857 chore(test): add junit config for testacular 2012-10-17 13:17:16 -07:00
Igor Minar 0ae0591f42 chore(Rakefile): misc_options should support + -> , conversion 2012-10-17 12:48:08 -07:00
Igor Minar 43ac783d35 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:45:10 -07:00
Misko Hevery c96dc60594 fix(doc): disable directory listing in docs.angularjs.org 2012-10-05 16:43:01 -07:00
Igor Minar b440ad36f3 docs(downloading): update the downloading docs 2012-10-05 03:13:51 -07:00
Vojta Jina 8b2532cec7 chore: add travis config 2012-09-24 23:39:33 -07:00
Vojta Jina 8db47ca7d4 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-20 18:32:01 -07:00
Vojta Jina bcaa3bb373 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-09-17 18:08:16 -07:00
Igor Minar 6fc4fdb438 docs(README): update README.md with new rake tasks 2012-09-17 14:51:21 -07:00
Igor Minar 6a5f8c0483 chore(Rakefile): fix test:jquery task 2012-09-17 14:50:51 -07:00
Igor Minar 20c116d9d5 docs(contribute): update contribute docs 2012-09-16 10:40:44 -07:00
Igor Minar 4a04c2ec0c chore(): remove unused files 2012-09-16 10:39:43 -07:00
Igor Minar 89dd566277 docs(contribute): update misc/contribute docs with Testacular info 2012-09-15 08:11:53 -07:00
Igor Minar 9d168f058f 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-13 16:23:18 -07:00
Miško Hevery 5418564f04 docs(directive): remove reference to old isolation syntax 2012-09-13 11:31:06 -07:00
Misko Hevery b0a05a7531 fix($route): support inline annotation on .resolve 2012-09-11 22:10:26 -07:00
Tom Hughes 209b67df6a feat($http): Allow setting withCredentials on defaults
Closes #1095.
2012-09-11 21:59:31 -07:00
Vojta Jina 2e1539356a chore(scripts): add init-repo script 2012-09-11 17:27:57 -07:00
Misko Hevery 331cd5a8cb fix($evalAsync): have only one global async queue
Having one async queue per scope complicates the matters when users wish to do
partial scope updates, since many services put events on the rootScope. By
having single queue the programing model is simplified.
2012-09-11 16:12:41 -07:00
Brian Ford f2ebfa16b0 docs(guide): fix directive interpolation example code
Closes #1339
2012-09-11 16:12:41 -07:00
Shyam Seshadri 95276a7e10 fix(scenario): emit RunnerBegin event 2012-09-11 16:12:41 -07:00
Vojta Jina 5dbd942bac chore(scripts): add commit-msg hook (validation) 2012-09-11 16:12:40 -07:00
Jimmy Zhuo 84c13d96ff fix(scenario): NPE when no angular loaded in test page 2012-09-11 16:12:40 -07:00
Daniel Luz 79941d2527 docs($rootScope): fix iteration limit described by $watch, it's actually 10 as of now 2012-09-11 15:11:02 -07:00
Daniel Luz 03ebecd5eb docs($rootScope): fix typos and minor wording tweaks on $watch 2012-09-11 15:11:02 -07:00
Daniel Luz 62bb728d07 docs($rootScope): fix quoting on expression 2012-09-11 15:11:02 -07:00
Daniel Luz b8eb843b25 docs($rootScope): standardize on present, third-person actions for descriptions 2012-09-11 15:11:02 -07:00
Daniel Luz 053247e412 docs($rootScope): backquote attribute types too on $on 2012-09-11 15:11:02 -07:00
Daniel Luz 7fa391c979 docs($cacheFactory): fix backquotes on method descriptions 2012-09-11 15:11:01 -07:00
Daniel Luz b01c28c900 docs($rootScope): fix typos on $new 2012-09-11 15:11:01 -07:00
Daniel Luz c0b9e94dec docs($rootScope): fix typo on $eval 2012-09-11 15:11:01 -07:00
Daniel Luz 83fbdd1097 docs($rootScope): fix typos on $watch 2012-09-11 15:11:01 -07:00
Jay Zeng 03042c52b9 docs(ngResource): Spelling typo (agressive => aggressive) 2012-09-11 15:08:55 -07:00
Igor Minar 2a4a8226d1 fix($resource): fix isDefined -> angular.isDefined 2012-09-10 14:49:22 -07:00
sgtpep c81d8176cc 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 16:06:27 -07:00
Kai Groner 04329151d2 fix(FormController): propagate dirty state to parent forms 2012-09-06 16:06:26 -07:00
Jonathan Zacsh a9be003fce chore(docs): get correct location for jasmine-node 2012-09-06 16:06:25 -07:00
Shyam Seshadri ca30fce28c fix(*): name all anonymous watch functions in Angular
This will allow us to see function names in Batarang and debugger.

Closes #1119
2012-09-06 16:06:25 -07:00
Xiangru Chen b6e4a71166 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 16:06:24 -07:00
Misko Hevery d9eff86ef7 fix($injector): more conservative annotation parsing 2012-09-06 16:06:24 -07:00
Pedro Del Gallego 8cb9c99ec0 feat(scenario): add dblclick method to the ngScenario dsl 2012-09-06 16:06:24 -07:00
Iwein Fuld 9473780e77 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 16:06:23 -07:00
Misko Hevery eb5fd400d3 docs(concept): correct example for creating injector 2012-09-06 16:06:23 -07:00
Godmar Back 0472c5f07e docs(module): fixed module example and corrected typos 2012-09-06 16:06:23 -07:00
Cameron Westland 92558fe411 feat(mocha): support mocha in angular mocks 2012-09-06 16:06:23 -07:00
Gregory Pike d519953a4b feat(ngModel): support ngTrim attribute on input 2012-09-06 16:06:23 -07:00
Benjamín Eidelman 4909d1d39d 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 16:06:22 -07:00
Jay Zeng 7079ff5eb6 docs(module): myAppModule -> simpleAppModule 2012-09-06 16:06:22 -07:00
petrovalex 10e1c759f4 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 16:06:22 -07:00
petrovalex 6c67719dfa fix(ngClassEven/Odd): filtering/ordering and repeater
Closes #1076
2012-09-06 16:06:22 -07:00
Max Martinsson cebd015f78 fix(ngClass): works with class interpolation
Closes #1016
2012-09-06 16:06:21 -07:00
Max Martinsson fbdab513dd feat($resource): support custom headers per action
Closes #736
2012-09-06 16:06:21 -07:00
Zhenbo Zhang f2b7fffdc0 fix(ngRepeat): now works with primitive types
closes #933
2012-09-06 16:06:21 -07:00
petrovalex 42c38b29f7 fix($parser): string concatination with undefined model
Closes #988
2012-09-06 16:06:21 -07:00
Stein Jakob Nordbø f299fd5122 fix(dateFilter): support sub-second precision on dateFilter 2012-09-06 16:06:19 -07:00
Igor Minar 05c88b866b docs($route): rename leftover $afterRouteChange to $routeChangeSuccess 2012-09-06 15:03:35 -07:00
Igor Minar 9b08bfa251 chore(release): prepare 1.1.1 pathological-kerning iteration 2012-09-06 10:41:23 -07:00
Misko Hevery 99a000bac2 fix(docs): broken url to angular-bootstrap 2012-09-04 18:15:00 -07:00
Igor Minar f353fea042 chore(Rakefile): add 'version' rake task to generate version.txt 2012-09-04 16:38:01 -07:00
Igor Minar b1f50307b3 chore(docs): bump up the stable version 2012-09-04 16:31:57 -07:00
Igor Minar d0c0eadedd chore(release): cut the 1.1.0 increase-gravatar release 2012-09-04 11:11:09 -07:00
Igor Minar b8fac353f0 chore(docs): don't rewrite colons in doc filenames 2012-09-04 11:11:09 -07:00
Igor Minar b22308152f chore(Rakefile): zip only the build dir 2012-08-31 13:59:03 -07:00
Igor Minar 5e9041818b revert: fix(ng-repeat) to work with primitive types
this was accidentaly merged in. the commit is not ready yet
and we don't have CLA signature.

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

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

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

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

- use symlinks when creating final zip file

- switch from btar to zip

- get rid of version numbers from filenames

- rewrite version numbers in all index files

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

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

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

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

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

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

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

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

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

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

if the default was not prevented, the test will fail and the page will
be reloaded causing the test runner to panic.
2012-08-07 22:07:49 -07:00
Igor Minar c25cb7d488 refactor(formSpec): group preventDefault specs into a describe 2012-08-07 17:23:16 -07:00
Igor Minar 54e4a6ffbf docs(faq): update faq docs 2012-08-07 10:15:54 -07:00
Igor Minar eee9a51fad docs(styles): fix the cog icon alignment 2012-08-06 16:54:18 -07:00
Vojta Jina 77e6d833f6 chore(nodeserver): add font mime type 2012-08-04 12:09:28 -07:00
Vojta Jina 33ad2b4126 docs(guide): hide scenario for directive example
scenario test for this example would be tricky, we need to teach
the runner how to inject mocks first.
2012-07-30 21:21:34 -07:00
Vojta Jina b84eaffd39 docs: fix icons
Copy fontawesome during build
2012-07-30 21:20:28 -07:00
brettcannon a1107e81eb fix(docs): "in depth" -> "in-depth" 2012-07-20 20:54:42 -07:00
JP Sugarbroad e3e8813e3c refactor($injector): move $injector into the providerCache
Better than special-casing '$injector' in createInjector.
2012-07-19 21:56:22 -07:00
Igor Minar 6e2d9711e8 chore(release): start 1.1.0 increase-gravatas iteration 2012-07-19 21:48:58 -07:00
153 changed files with 6424 additions and 8204 deletions
-1
View File
@@ -10,6 +10,5 @@ performance/temp*.html
*~
angular.js.tmproj
node_modules
jsTestDriver*.conf
angular.xcodeproj
.idea
+13
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"]
+198 -2
View File
@@ -1,9 +1,207 @@
<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
@@ -17,8 +215,6 @@ _Note: 1.1.x releases unlike 1.0.x are considered unstable.
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
This release also contains all bug fixes available in [1.0.2](#1.0.2).
<a name="1.0.2"></a>
+32
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
+22 -6
View File
@@ -13,17 +13,33 @@ it makes development fun!
* Web site: http://angularjs.org
* Tutorial: http://docs.angularjs.org/tutorial
* API Docs: http://docs.angularjs.org
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
Compiling
Building AngularJS
---------
rake compile
[Once you have your environment setup](http://docs.angularjs.org/misc/contribute) just run:
rake package
Running Tests
-------------
./server.sh # start the server
open http://localhost:9876/capture # capture browser
./test.sh # run all unit tests
Running tests requires installation of [Testacular](http://vojtajina.github.com/testacular):
sudo npm install -g testacular
To execute all unit tests, use:
rake test:unit
To execute end-to-end (e2e) tests, use:
rake package
rake webserver &
rake test:e2e
To learn more about the rake tasks, run `rake -T` and also read our
[contribution guidelines](http://docs.angularjs.org/misc/contribute) and instructions in this
[commit message](https://github.com/angular/angular.js/commit/9d168f058f9c6d7eeae0daa7cb72ea4e02a0003a).
+83 -44
View File
@@ -40,6 +40,7 @@ desc 'Clean Generated Files'
task :clean do
FileUtils.rm_r(BUILD_DIR, :force => true)
FileUtils.mkdir(BUILD_DIR)
FileUtils.rm_r('test_out', :force => true)
end
@@ -56,25 +57,6 @@ task :concat_scenario => :init do
end
desc 'Concat JSTD Scenario Adapter'
task :concat_jstd_scenario_adapter => :init do
concat_file('jstd-scenario-adapter.js', [
'src/ngScenario/jstd-scenario-adapter/angular.prefix',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'src/ngScenario/jstd-scenario-adapter/angular.suffix',
])
# TODO(vojta) use jstd configuration when implemented
# (instead of including jstd-adapter-config.js)
File.open(path_to('jstd-scenario-adapter-config.js'), 'w') do |f|
f.write("/**\r\n" +
" * Configuration for jstd scenario adapter \n */\n" +
"var jstdScenarioAdapter = {\n relativeUrlPrefix: '/build/docs/'\n};\n")
end
end
desc 'Concat AngularJS files'
task :concat => :init do
@@ -114,7 +96,7 @@ end
desc 'Minify JavaScript'
task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter] do
task :minify => [:init, :concat, :concat_scenario] do
[ 'angular.js',
'angular-cookies.js',
'angular-loader.js',
@@ -123,8 +105,16 @@ task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter
'angular-bootstrap.js',
'angular-bootstrap-prettify.js'
].each do |file|
closure_compile(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
@@ -150,7 +140,7 @@ end
desc 'Create angular distribution'
task :package => [:clean, :minify, :docs] do
task :package => [:clean, :minify, :version, :docs] do
zip_dir = "angular-#{NG_VERSION.full}"
zip_file = "#{zip_dir}.zip"
@@ -164,37 +154,74 @@ task :package => [:clean, :minify, :docs] do
end
namespace :server do
desc 'Start development webserver'
task :webserver, :port do |t, args|
exec "node lib/nodeserver/server.js #{args[:port]}"
end
desc 'Run JsTestDriver Server'
task :start do
sh %x(java -jar lib/jstestdriver/JsTestDriver.jar --browser open --port 9876)
desc 'Run all AngularJS tests'
task :test, :browsers, :misc_options do |t, args|
[ 'test:jqlite',
'test:jquery',
'test:modules',
'test:e2e'
].each do |task|
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
end
end
namespace :test do
desc 'Run all unit tests (single run)'
task :unit, :browsers, :misc_options do |t, args|
[ 'test:jqlite',
'test:jquery',
'test:modules'
].each do |task|
Rake::Task[task].invoke(args[:browsers], args[:misc_options])
end
end
desc 'Run JavaScript tests against the server'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all)
desc 'Run jqLite-based unit test suite (single run)'
task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run jQuery-based unit test suite (single run)'
task :jquery, :browsers, :misc_options do |t, args|
start_testacular('testacular-jquery.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run bundled modules unit test suite (single run)'
task :modules, :browsers, :misc_options do |t, args|
start_testacular('testacular-modules.conf.js', true, args[:browsers], args[:misc_options])
end
desc 'Run e2e test suite (single run)'
task :e2e, :browsers, :misc_options do |t, args|
start_testacular('testacular-e2e.conf.js', true, args[:browsers], args[:misc_options])
end
end
desc 'Run JavaScript tests'
task :test do
sh %(java -jar lib/jstestdriver/JsTestDriver.jar --tests all --browser open --port 9876)
end
namespace :autotest do
desc 'Run jqLite-based unit test suite (autowatch)'
task :jqlite, :browsers, :misc_options do |t, args|
start_testacular('testacular-jqlite.conf.js', false, args[:browsers], args[:misc_options])
end
desc 'Lint'
task :lint do
out = %x(lib/jsl/jsl -conf lib/jsl/jsl.default.conf)
print out
end
desc 'push_angularjs'
task :push_angularjs => :compile do
sh %(cat angularjs.ftp | ftp -N angularjs.netrc angularjs.org)
desc 'Run jQuery-based unit test suite (autowatch)'
task :jquery, :browsers, :misc_options do |t, args|
start_testacular('testacular-jquery.conf.js', false, args[:browsers], args[:misc_options])
end
end
@@ -245,7 +272,10 @@ def closure_compile(filename)
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 \
--language_in ECMASCRIPT5_STRICT \
--js #{path_to(filename)} \
@@ -296,3 +326,12 @@ def rewrite_file(filename)
f.write content
end
end
def start_testacular(config, singleRun, browsers, misc_options)
sh "./node_modules/testacular/bin/testacular start " +
"#{config} " +
"#{'--single-run=true' if singleRun} " +
"#{'--browsers=' + browsers.gsub('+', ',') if browsers} " +
"#{(misc_options || '').gsub('+', ',')}"
end
+24 -30
View File
@@ -196,36 +196,30 @@ angularFiles = {
]
};
// Execute only in slim-jim
if (typeof JASMINE_ADAPTER !== 'undefined') {
// Testacular config
var mergedFiles = [];
angularFiles.jstd.forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
if (!deps) {
console.log('No dependency:' + file)
if (exports) {
exports.files = angularFiles
exports.mergeFiles = function mergeFiles() {
var files = [];
[].splice.call(arguments, 0).forEach(function(file) {
if (file.match(/testacular/)) {
files.push(file);
} else {
angularFiles[file].forEach(function(f) {
// replace @ref
var match = f.match(/^\@(.*)/);
if (match) {
var deps = angularFiles[match[1]];
files = files.concat(deps);
} else {
if (!/jstd|jasmine/.test(f)) { //TODO(i): remove once we don't have jstd/jasmine in repo
files.push(f);
}
}
});
}
mergedFiles = mergedFiles.concat(deps);
} else {
mergedFiles.push(file);
}
});
});
files = [JASMINE, JASMINE_ADAPTER];
mergedFiles.forEach(function(file){
if (/jstd|jasmine/.test(file)) return;
files.push(file);
});
exclude = angularFiles.jstdExclude;
autoWatch = true;
autoWatchInterval = 1;
logLevel = LOG_INFO;
logColors = true;
return files;
}
}
-5
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
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
rake compile
rake minify
gzip -c < build/angular.min.js > build/angular.min.js.gzip
ls -l build/angular.min.*
+1 -1
View File
@@ -3,5 +3,5 @@
@description
Use the API Reference documentation when you need more information about a specific feature. Check out
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recommend the
{@link tutorial/ Tutorial}.
+29 -29
View File
@@ -32,14 +32,14 @@ This is how we get the ball rolling (refer to the diagram and example below):
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
{@link guide/directive directive}, which designates application boundary
5. {@link guide/module Module} specified in {@link
api/ng.directive:ngApp ng-app} (if any) is used to configure
api/ng.directive:ngApp ng-app} (if any) is used to configure
the {@link api/AUTO.$injector $injector}
6. {@link api/AUTO.$injector $injector} is used to create the {@link
api/ng.$compile $compile} service as well as {@link
api/ng.$rootScope $rootScope}
7. {@link api/ng.$compile $compile} service is used to compile the DOM and link
7. {@link api/ng.$compile $compile} service is used to compile the DOM and link
it with {@link api/ng.$rootScope $rootScope}
8. {@link api/ng.directive:ngInit ng-init} {@link
8. {@link api/ng.directive:ngInit ng-init} {@link
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
scope}
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
@@ -80,8 +80,8 @@ implementing custom event callbacks, or when working with a third-party library
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
the work you wish to do in Angular execution context.
2. Angular executes the `stimulusFn()`, which typically modifies application state.
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
loop is made up of two smaller loops which process {@link
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
@@ -96,7 +96,7 @@ implementing custom event callbacks, or when working with a third-party library
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
which may have changed since last iteration. If a change is detected then the `$watch`
function is called which typically updates the DOM with the new value.
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
the execution leaves the Angular and JavaScript context. This is followed by the browser
re-rendering the DOM to reflect any changes.
@@ -122,7 +122,7 @@ user enters text into the text field.
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
on the `name` property and notifies the {@link api/ng.$interpolate
&#123;&#123;name&#125;&#125; } interpolation, which in turn updates the DOM.
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
the JavaScript execution context.
7. The browser re-renders the view with update text.
@@ -165,7 +165,7 @@ a diagram depicting the scope boundaries.
function GreetCtrl($scope) {
$scope.name = 'World';
}
function ListCtrl($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
@@ -196,7 +196,7 @@ controller.
The separation of the controller and the view is important because:
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
for specifying application behavior. The controller should not contain any rendering
for specifying application behavior. The controller should not contain any rendering
information (DOM references or HTML fragments).
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
specifying UI. The View should not contain any behavior.
@@ -220,7 +220,7 @@ The separation of the controller and the view is important because:
$scope.action = function() {
$scope.name = 'OK';
}
$scope.name = 'World';
}
</file>
@@ -249,8 +249,8 @@ primitive, object hash, or a full object Type. In short the model is a plain Jav
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
The view is what the users sees. The view begins its life as a template, it is merged with the
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view, to most other templating systems.
model and finally rendered into the browser DOM. Angular takes a very different approach to
rendering the view, to most other templating systems.
* **Others** - Most templating systems begin as an HTML string with special templating markup.
Often the template markup breaks the HTML syntax which means that the template can not be
@@ -260,13 +260,13 @@ rendering the view, to most other templating systems.
When the model changes the whole process needs to be repeated. The granularity of the template
is the granularity of the DOM updates. The key here is that the templating system manipulates
strings.
* **Angular** - Angular is different, since its templating system works on DOM objects not on
* **Angular** - Angular is different, since its templating system works on DOM objects not on
strings. The template is still written in HTML string, but it is HTML (not HTML with
template sprinkled in.) The browser parses the HTML into DOM, and the DOM becomes the input to
the template engine know as the {@link api/ng.$compile compiler}. The compiler
looks for {@link guide/directive directives} which in turn set up {@link
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
continuously updating view which does not need template model re-merging. Your model becomes
continuously updating view which does not need template model re-merging. Your model becomes
the single source-of-truth for your view.
<div class="clear">
@@ -339,13 +339,13 @@ in HTML.
{@link api/ng.$filter Filters} perform data transformation roles. Typically
they are used in conjunction with the locale to format the data in locale specific output.
They are follow the spirit of UNIX filters and follow similar syntax `|` (pipe).
They follow the spirit of UNIX filters and use similar syntax `|` (pipe).
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
Number formatting: {{ 1234567890 | number }} <br>
array filtering <input ng-model="predicate">
array filtering <input ng-model="predicate">
{{ list | filter:predicate | json }}
</div>
</file>
@@ -362,7 +362,7 @@ An {@link api/AUTO.$injector injector} is a service locator. There is a single
{@link api/AUTO.$injector injector} per Angular {@link
api/ng.directive:ngApp application}. The {@link
api/AUTO.$injector injector} provides a way to look up an object instance by its
name. The injector keeps on internal cache of all objects so that repeated calls to get the same
name. The injector keeps an internal cache of all objects so that repeated calls to get the same
object name result in the same instance. If the object does not exist, then the {@link
api/AUTO.$injector injector} asks the instance factory to create a new instance.
@@ -373,20 +373,20 @@ as a {@link api/AUTO.$provide provider}.
<pre>
// Create a module
var myModule = angular.module('myModule', [])
// Configure the injector
myModule.factory('serviceA', function() {
return {
// instead of {}, put your object creation here
};
});
// create an injector and configure it from 'myModule'
var $injector = angular.injector('myModule');
var $injector = angular.injector(['myModule']);
// retrieve an object from the injector by name
var serviceA = $injector.get('serviceA');
// always true because of instance cache
$injector.get('serviceA') === $injector.get('serviceA');
</pre>
@@ -395,7 +395,7 @@ as a {@link api/AUTO.$provide provider}.
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
used to {@link api/AUTO.$injector#invoke call} methods and {@link
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
allows the methods and types to ask for their dependencies rather then to look for them.
allows the methods and types to ask for their dependencies instead of having to look for them.
<pre>
// You write functions such as this one.
@@ -405,12 +405,12 @@ allows the methods and types to ask for their dependencies rather then to look f
// Angular provides the injector for your application
var $injector = ...;
///////////////////////////////////////////////
// the old-school way of getting dependencies.
var serviceA = $injector.get('serviceA');
var serviceB = $injector.get('serviceB');
// now call the function
doSomething(serviceA, serviceB);
@@ -425,7 +425,7 @@ function arguments. When angular calls the function, it will use the {@link
api/AUTO.$injector#invoke call} which will automatically fill the function
arguments.
Examine the `ClockCtrl` bellow, and notice how it list the dependencies in constructor. When the
Examine the `ClockCtrl` bellow, and notice how it lists the dependencies in the constructor. When the
{@link api/ng.directive:ngController ng-controller} instantiates
the controller it automatically provides the dependencies. There is no need to create
dependencies, look for dependencies, or even get a reference to the injector.
@@ -442,15 +442,15 @@ dependencies, look for dependencies, or even get a reference to the injector.
// which will be available for injection
factory('time', function($timeout) {
var time = {};
(function tick() {
time.now = new Date().toString();
$timeout(tick, 1000);
})();
return time;
});
// Notice that you can simply ask for time
// Notice that you can simply ask for time
// and it will be provided. No need to look for it.
function ClockCtrl($scope, time) {
$scope.time = time;
@@ -122,7 +122,7 @@ Returns the current value of an input field with the given `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
used for test ouput.
used for test output.
## repeater(selector, label).row(index)
Returns an array with the bindings in the row at the given `index` in the repeater matching the
@@ -23,13 +23,13 @@ changes to $location are reflected into the browser address bar.
## Comparing $location to window.location
<table>
<table class="table">
<thead>
<tr>
<td class="empty-corner-lt"></td>
<td>window.location</td>
<td>$location service</td>
<th class="empty-corner-lt"></th>
<th>window.location</th>
<th>$location service</th>
</tr>
</thead>
@@ -165,13 +165,13 @@ facilitate the browser URL change and history management.
<img src="img/guide/hashbang_vs_regular_url.jpg">
<table>
<table class="table">
<thead>
<tr>
<td class="empty-corner-lt"></td>
<td>Hashbang mode</td>
<td>HTML5 mode</td>
<th class="empty-corner-lt"></th>
<th>Hashbang mode</th>
<th>HTML5 mode</th>
</tr>
</thead>
@@ -543,69 +543,73 @@ then uses the information it obtains to compose hashbang URLs (such as
## Changes to your code
<table>
<tr class="head">
<td>Navigation inside the app</td>
<td>Change to</td>
</tr>
<table class="table">
<thead>
<tr class="head">
<th>Navigation inside the app</th>
<th>Change to</th>
</tr>
</thead>
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
<tbody>
<tr>
<td>$location.href = value<br />$location.hash = value<br />$location.update(value)<br
/>$location.updateHash(value)</td>
<td>$location.path(path).search(search)</td>
</tr>
<td>$location.path(path).search(search)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</td>
</tr>
<tr>
<td>$location.hashPath = path</td>
<td>$location.path(path)</td>
</tr>
<tr>
<td>$location.hashSearch = search</td>
<td>$location.search(search)</td>
</tr>
<tr>
<td>$location.hashSearch = search</td>
<td>$location.search(search)</td>
</tr>
<tr class="head">
<td>Navigation outside the app</td>
<td>Use lower level API</td>
</tr>
<tr class="head">
<td>Navigation outside the app</td>
<td>Use lower level API</td>
</tr>
<tr>
<td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td>
</tr>
<tr>
<td>$location.href = value<br />$location.update(value)</td>
<td>$window.location.href = value</td>
</tr>
<tr>
<td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td>
</tr>
<tr>
<td>$location[protocol | host | port | path | search]</td>
<td>$window.location[protocol | host | port | path | search]</td>
</tr>
<tr class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr class="head">
<td>Read access</td>
<td>Change to</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</td>
</tr>
<tr>
<td>$location.hashPath</td>
<td>$location.path()</td>
</tr>
<tr>
<td>$location.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.hashSearch</td>
<td>$location.search()</td>
</tr>
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
<tr>
<td>$location.href<br />$location.protocol<br />$location.host<br />$location.port<br
/>$location.hash</td>
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
<td>$location.absUrl()<br />$location.protocol()<br />$location.host()<br />$location.port()<br
/>$location.path() + $location.search()</td>
</tr>
</tr>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td>
</tr>
<tr>
<td>$location.path<br />$location.search</td>
<td>$window.location.path<br />$window.location.search</td>
</tr>
</tbody>
</table>
## Two-way binding to $location
+20 -18
View File
@@ -63,7 +63,7 @@ api/ng.$rootScope.Scope#$digest digest} cycle. An example of interpolation is sh
here:
<pre>
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
<a href="img/{{username}}.jpg">Hello {{username}}!</a>
</pre>
# Compilation process, and directive matching
@@ -253,7 +253,7 @@ An example skeleton of the directive is shown here, for the complete list see be
In most cases you will not need such fine control and so the above can be simplified. All of the
different parts of this skeleton are explained in following sections. In this section we are
interested only isomers of this skeleton.
interested only in some of this skeleton.
The first step in simplyfing the code is to rely on the default values. Therefore the above can be
simplified as:
@@ -321,25 +321,27 @@ compiler}. The attributes are:
derived from the parent scope. These local properties are useful for aliasing values for
templates. Locals definition is a hash of local scope property to its source:
* `@` or `@attr` - bind a local scope property to the DOM attribute. The result is always a
string since DOM attributes are strings. If no `attr` name is specified then the local name
and attribute name are same. Given `<widget my-attr="hello {{name}}">` and widget definition
* `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
always a string since DOM attributes are strings. If no `attr` name is specified then the
attribute name is assumed to be the same as the local name.
Given `<widget my-attr="hello {{name}}">` and widget definition
of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
`localName` property on the widget scope. The `name` is read from the parent scope (not
component scope).
* `=` or `=expression` - set up bi-directional binding between a local scope property and the
parent scope property. If no `attr` name is specified then the local name and attribute
name are same. Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localName` will reflect the
* `=` or `=attr` - set up bi-directional binding between a local scope property and the
parent scope property of name defined via the value of the `attr` attribute. If no `attr`
name is specified then the attribute name is assumed to be the same as the local name.
Given `<widget my-attr="parentModel">` and widget definition of
`scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
in `localModel` and any changes in `localModel` will reflect in `parentModel`.
* `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
If no `attr` name is specified then the local name and attribute name are same.
Given `<widget my-attr="count = count + value">` and widget definition of
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
If no `attr` name is specified then the attribute name is assumed to be the same as the
local name. Given `<widget my-attr="count = count + value">` and widget definition of
`scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
the isolate scope via an expression and to the parent scope, this can be done by passing a
map of local variable names and values into the expression wrapper fn. For example, if the
@@ -349,7 +351,7 @@ compiler}. The attributes are:
* `controller` - Controller constructor function. The controller is instantiated before the
pre-linking phase and it is shared with other directives if they request it by name (see
`require` attribute). This allows the directives to communicate with each other and augment
each other behavior. The controller is injectable with the following locals:
each other's behavior. The controller is injectable with the following locals:
* `$scope` - Current scope associated with the element
* `$element` - Current element
@@ -535,7 +537,7 @@ into the dialog.
Here is an example of what the template definition for the `dialog` widget may look like.
<pre>
<div ng-show="show()">
<div ng-show="show">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
@@ -555,10 +557,10 @@ expects as follows:
<pre>
scope: {
title: 'bind', // set up title to accept data-binding
onOk: 'expression', // create a delegate onOk function
onCancel: 'expression', // create a delegate onCancel function
show: 'accessor' // create a getter/setter function for visibility.
title: '=', // set up title to accept data-binding
onOk: '&', // create a delegate onOk function
onCancel: '&', // create a delegate onCancel function
show: '='
}
</pre>
+3 -4
View File
@@ -5,9 +5,8 @@
# What is a Module?
Most applications have a main method which instantiates, wires, and bootstraps the application.
Angular apps don't have a main method, instead modules serve the purpose of declaratively
specifying how an application should be bootstrapped. There are several advantages to this
approach:
Angular apps don't have a main method. Instead modules declaratively specify how an application
should be bootstrapped. There are several advantages to this approach:
* The process is more declarative which is easier to understand
* In unit-testing there is no need to load all modules, which may aid in writing unit-tests.
@@ -31,7 +30,7 @@ Important things to notice:
<doc:source>
<script>
// declare a module
var simpleAppModule = angular.module('myApp', []);
var myAppModule = angular.module('myApp', []);
// configure the module.
// in this example we will create a greeting filter
+75 -65
View File
@@ -13,19 +13,19 @@
<a name="H1_1"></a>
# License
`Angular` is an open source project licensed under the {@link
AngularJS is an open source project licensed under the {@link
http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. Your contributions are
always welcome. When working with `angular` source base, please follow the guidelines provided on
always welcome. When working with AngularJS code base, please follow the guidelines provided on
this page.
<a name="H1_2"></a>
# Contributing to Source Code
We'd love for you to contribute to our source code and to make `angular` even better than it is
today! Here are the guidelines we'd like you to use:
We'd love for you to contribute to our source code and to make AngularJS even better than it is
today! Here are the guidelines we'd like you to follow:
* Major changes that you intend to contribute to the project must be discussed first on our {@link
* Major changes that you intend to contribute to the project should be discussed first on our {@link
https://groups.google.com/forum/?hl=en#!forum/angular mailing list} so that we can better
coordinate our efforts, prevent duplication of work, and help you to craft the change so that it
is successfully accepted upstream.
@@ -64,45 +64,39 @@ inheritance only when absolutely necessary.
external API. See our existing code to see what we mean.
* We don't go crazy with type annotations for private internal APIs unless it's an internal API
that is used throughout `angular`. The best guidance is to do what makes the most sense.
that is used throughout AngularJS. The best guidance is to do what makes the most sense.
<a name="H1_4"></a>
# Checking Out and Building Angular
The `angular` source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. Several steps are needed to check out and build `angular`:
The AngularJS source code is hosted at {@link http://github.com Github}, which we also use to
accept code contributions. The AngularJS repository can be found at **<https://github.com/angular/angular.js>**.
Several steps are needed to check out and build AngularJS:
## Installation Dependencies
Before you can build `angular`, you must install or configure the following dependencies on your
Before you can build AngularJS, you must install or configure the following dependencies on your
machine:
* {@link http://rake.rubyforge.org Rake}: We use Rake as our build system, which is pre-installed
on most Macintosh and Linux machines. If that is not true in your case, you can grab it from the
Rake website.
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
* {@link http://nodejs.org Node.js}: We use Node to generate the documentation and to run a
development web server. Depending on your system, you can install Node either from source or as a
pre-packaged bundle.
You'll also need npm and the following npm modules:
Once installed, you'll also need several npms (node packages), which you can install once you checked out a local copy
of the Angular repository (see below) with:
* install npm: `curl http://npmjs.org/install.sh | sh`
* install q: `npm install q`
* install qq: `npm install qq`
* install q-fs: `npm install q-fs`
* install jasmine-node: `npm install jasmine`
* Java: The Java runtime is used to run {@link http://code.google.com/p/js-test-driver
JsTestDriver} (JSTD), which we use to run our unit test suite. JSTD binaries are part of the
`angular` source base, which means there is no need to install or configure it separately.
* Git: The {@link http://help.github.com/mac-git-installation Github Guide to Installing Git} is
quite a good source for information on Git.
* `cd angular.js`
* `npm install`
## Creating a Github Account and Forking Angular
@@ -112,31 +106,31 @@ Afterwards, go ahead and {@link http://help.github.com/forking fork} the {@link
https://github.com/angular/angular.js main angular repository}.
## Building `Angular`
## Building AngularJS
To build `angular`, you check out the source code and use Rake to generate the non-minified and
minified `angular` files:
To build AngularJS, you check out the source code and use Rake to generate the non-minified and
minified AngularJS files:
1. To clone your Github repository, run:
git clone git@github.com:<github username>/angular.js.git
2. To go to the `angular` directory, run:
2. To go to the AngularJS directory, run:
cd angular.js
3. To add the main `angular` repository as an upstream remote to your repository, run:
3. To add the main AngularJS repository as an upstream remote to your repository, run:
git remote add upstream https://github.com/angular/angular.js.git
4. To build `angular`, run:
4. To build AngularJS, run:
rake package
The build output can be located under the `build` directory. It consists of the following files and
directories:
* `angular-<version>.tgz` — This is the complete tarball, which contains all of the release build
* `angular-<version>.zip` — This is the complete zip file, which contains all of the release build
artifacts.
* `angular.js` — The non-minified `angular` script.
@@ -145,8 +139,6 @@ artifacts.
* `angular-scenario.js` — The `angular` End2End test runner.
* `angular-ie-compat.js` — The Internet Explorer compatibility patch file.
* `docs/` — A directory that contains all of the files needed to run `docs.angularjs.org`.
* `docs/index.html` — The main page for the documentation.
@@ -154,60 +146,70 @@ artifacts.
* `docs/docs-scenario.html` — The End2End test runner for the documentation application.
<a name="webserver"></a>
## Running a Local Development Web Server
To debug or test code, it is often useful to have a local HTTP server. For this purpose, we have
To debug code and run end-to-end tests, it is often useful to have a local HTTP server. For this purpose, we have
made available a local web server based on Node.js.
1. To start the web server, run:
./nodeserver.sh
rake webserver
2. To access the local server, go to this website:
http://localhost:8000/
By default, it serves the contents of the `angular` project directory.
By default, it serves the contents of the AngularJS project directory.
<a name="unit-tests"></a>
## Running the Unit Test Suite
Our unit and integration tests are written with Jasmine and executed with JsTestDriver. To run the
tests:
Our unit and integration tests are written with Jasmine and executed with Testacular. To run all of the
tests once on Chrome run:
1. To start the JSTD server, run:
rake test:unit
./server.sh
To run the tests on other browsers (Chrome, ChromeCanary, Firefox, Opera and Safari are pre-configured) use:
2. To capture one or more browsers, go to this website:
rake test:unit[Opera+Firefox]
During development it's however more productive to continuously run unit tests every time the source or test files
change. To execute tests in this mode run:
1. To start the Testacular server, capture Chrome browser and run unit tests, run:
rake autotest:jqlite
2. To capture more browsers, open this url in the desired browser (url might be different if you have multiple instance
of Testacular running, read Testacular's console output for the correct url):
http://localhost:9876/
3. To trigger a test execution, run:
./test.sh
4. To automatically run the test suite each time one or more of the files in the project directory
is changed, you can install `watchr` and then run:
watchr watchr.rb
5. To view the output of each test run, you can tail this log file:
./logs/jstd.log
3. To re-run tests just change any source or test file.
## Running the End2End Test Suite
To learn more about all of the preconfigured Rake tasks run:
To run the End2End test suite:
rake -T
## Running the end-to-end Test Suite
To run the E2E test suite:
1. Start the local web server if it's not running already.
rake webserver
1. Start the local web server.
2. In a browser, go to:
http://localhost:8000/build/docs/docs-scenario.html
The tests are executed automatically.
or in terminal run:
rake test:e2e
@@ -216,30 +218,38 @@ To run the End2End test suite:
To create and submit a change:
1. Create a new branch off the master for your changes:
1. Please sign our Contributor License Agreement (CLA) before sending pull requests. For any code changes to be
accepted, the CLA must be signed. It's a quick process, we promise!
For individuals we have a [simple click-through form](http://code.google.com/legal/individual-cla-v1.0.html). For
corporations we'll need you to
[print, sign and one of scan+email, fax or mail the form](http://code.google.com/legal/corporate-cla-v1.0.html).
2. Create a new branch off the master for your changes:
git branch my-fix-branch
2. Check out the branch:
3. Check out the branch:
git checkout my-fix-branch
3. Create your patch, make sure to have plenty of tests (that pass).
4. Create your patch, make sure to have plenty of tests (that pass).
4. Commit your changes:
5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
please check out our
[commit message conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#)
and our commit message presubmit hook `validate-commit-msg.js`):
git commit -a
5. Run JavaScript Lint and be sure to address all new warnings and errors:
rake lint
6. Push your branch to Github:
git push origin my-fix-branch
7. In Github, send a pull request to `angular:master`.
8. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository:
+16 -14
View File
@@ -16,14 +16,14 @@ development.
production.
To point your code to an angular script on the angular server, use the following template. This
example points to (non-minified) version 0.10.6:
example points to (non-minified) version 1.0.2:
<pre>
<!doctype html>
<html ng-app>
<head>
<title>My Angular App</title>
<script src="http://code.angularjs.org/angular-0.10.6.js"></script>
<script src="http://code.angularjs.org/1.0.2/angular.js"></script>
</head>
<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:
* __`angular-<version>.js`__ — This file is non-obfuscated, non-minified, and human-readable by
* __`angular.js`__ — This file is non-obfuscated, non-minified, and human-readable by
opening it it any editor or browser. In order to get better error messages during development, you
should always use this non-minified angular script.
* __`angular-<version>.min.js`__ — This is a minified and obfuscated version of
`angular-<version>.js` created with the Closure compiler. Use this version for production in order
* __`angular.min.js`__ — This is a minified and obfuscated version of
`angular.js` created with the Closure compiler. Use this version for production in order
to minimize the size of the application that is downloaded by your user's browser.
* __`angular-<version>.tgz`__ — This is a tarball archive that contains all of the files released
* __`angular.zip`__ — This is a zip archive that contains all of the files released
for this angular version. Use this file to get everything in a single download.
* __`angular-ie-compat-<version>.js`__ — This is a special file that contains code and data
specifically tailored for getting Internet Explorer to work with angular. If you host your own copy
of angular files, make sure that this file is available for download, and that it resides under the
same parent path as `angular-<version>.js` or `angular-<version>.min.js`.
* __`angular-mocks-<version>.js`__ — This file contains an implementation of mocks that makes
* __`angular-mocks.js`__ — This file contains an implementation of mocks that makes
testing angular apps even easier. Your unit/integration test harness should load this file after
`angular-<version>.js` is loaded.
* __`angular-scenario-<version>.js`__ — This file is a very nifty JavaScript file that allows you
* __`angular-scenario.js`__ — This file is a very nifty JavaScript file that allows you
to write and execute end-to-end tests for angular applications.
* __`docs-<version>`__ — this directory contains all the files that compose the
* __`angular-loader.min.js`__ — Module loader for Angular modules. If you are loading multiple script files containing
Angular modules, you can load them asynchronosuly and in any order as long as you load this file first. Often the
contents of this file are copy&pasted into the `index.html` to avoid even the inial request to `angular-loader.min.js`.
See [angular-seed](https://github.com/angular/angular-seed/blob/master/app/index-async.html) for an example of usage.
* __`angular-resource.js`__, __`angular-cookies.js`__, etc - extra Angular modules with additional functionality.
* __`docs`__ — this directory contains all the files that compose the
<http://docs.angularjs.org/> documentation app. These files are handy to see the older version of
our docs, or even more importantly, view the docs offline.
+109 -10
View File
@@ -4,6 +4,8 @@
#FAQ
## Questions
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
Because HTML has Angular brackets and "ng" sounds like "Angular".
@@ -21,7 +23,7 @@ So it's definitely not a plugin or some other native browser extension.
### Is AngularJS a templating system?
At the highest level, Angular does look like a just another templating system. But there is one
important reason why Angular templating system is different and makes it very good fit for
important reason why the Angular templating system is different, that makes it very good fit for
application development: bidirectional data binding. The template is compiled in the browser and
the compilation step produces a live view. This means you, the developers, don't need to write
code to constantly sync the view with the model and the model with the view as in other
@@ -30,7 +32,7 @@ templating systems.
### Do I need to worry about security holes in AngularJS?
Like with any technology, AngularJS is not impervious to attack. angular does, however, provide
Like 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.
@@ -46,9 +48,9 @@ Yes. See instructions in {@link downloading}.
### What browsers does angular work with?
### What browsers does Angular work with?
Our we run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
@@ -67,32 +69,129 @@ illustration we typically build snappy apps with hundreds or thousands of active
The size of the file is < 29KB compressed and minified.
### Can I use the open-source Closure Library with angular?
### Can I use the open-source Closure Library with Angular?
Yes, you can use widgets from the {@link http://code.google.com/closure/library Closure Library}
in angular.
in Angular.
### Does angular use the jQuery library?
### Does Angular use the jQuery library?
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
### What is testability like in angular?
### What is testability like in Angular?
Very testable and designed this way from ground up. It has an integrated dependency injection
framework, provides mocks for many heavy dependencies (server-side communication). See
{@link api/ng service} for details.
### How can I learn more about angular?
### How can I learn more about Angular?
Watch the July 28, 2010 talk
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
AJAX Apps}".
### How is angular licensed?
### How is Angular licensed?
The MIT License.
## Common Pitfalls
The Angular support channel (#angularjs on Freenode) sees a number of recurring pitfalls that new users of Angular fall into.
This document aims to point them out before you discover them the hard way.
### DOM Manipulation
Stop trying to use jQuery to modify the DOM in controllers. Really.
That includes adding elements, removing elements, retrieving their contents, showing and hiding them.
Use built-in directives, or write your own where necessary, to do your DOM manipulation.
See below about duplicating functionality.
If you're struggling to break the habit, consider removing jQuery from your app.
Really. Angular has the $http service and powerful directives that make it almost always unnecessary.
Angular's bundled jQLite has a handful of the features most commonly used in writing Angular directives, especially binding to events.
### Trying to duplicate functionality that already exists
There's a good chance that your app isn't the first to require certain functionality.
There are a few pieces of Angular that are particularly likely to be reimplemented out of old habits.
**ng-repeat**
`ng-repeat` gets this a lot.
People try to use jQuery (see above) to add more elements to some container as they're fetched from the server.
No, bad dog.
This is what `ng-repeat` is for, and it does its job very well.
Store the data from the server in an array on your `$scope`, and bind it to the DOM with `ng-repeat`.
**ng-show**
`ng-show` gets this frequently too.
Conditionally showing and hiding things using jQuery is a common pattern in other apps, but Angular has a better way.
`ng-show` (and `ng-hide`) conditionally show and hide elements based on boolean expressions.
Describe the conditions for showing and hiding an element in terms of `$scope` variables:
<div ng-show="!loggedIn">Click <a href="#/login">here</a> to log in</div>
Note also the counterpart `ng-hide` and similar `ng-disabled`.
Note especially the powerful `ng-switch` that should be used instead of several mutually exclusive `ng-show`s.
**ng-class**
`ng-class` is the last of the big three.
Conditionally applying classes to elements is another thing commonly done manually using jQuery.
Angular, of course, has a better way.
You can give `ng-class` a whitespace-separated set of class names, and then it's identical to ordinary `class`.
That's not very exciting, so there's a second syntax:
<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>
Where you give `ng-class` an object, whose keys are CSS class names and whose values are conditional expressions using `$scope` variables.
The element will then have all the classes whose conditions are truthy, and none of those whose conditions are falsy.
Note also the handy `ng-class-even` and `ng-class-odd`, and the related though somewhat different `ng-style`.
### `$watch` and `$apply`
Angular's two-way data binding is the root of all awesome in Angular.
However, it's not magic, and there are some situations where you need to give it a nudge in the right direction.
When you bind a value to an element in Angular using `ng-model`, `ng-repeat`, etc., Angular creates a `$watch` on that value.
Then whenever a value on a scope changes, all `$watch`es observing that element are executed, and everything updates.
Sometimes, usually when you're writing a custom directive, you will have to define your own `$watch` on a scope value to make the directive react to changes.
On the flip side, sometimes you change a scope value in some code but the app doesn't react to it.
Angular checks for scope variable changes after pieces of your code have finished running; for example, when `ng-click` calls a function on your scope, Angular will check for changes and react.
However, some code is outside of Angular and you'll have to call `scope.$apply()` yourself to trigger the update.
This is most commonly seen in event handlers in custom directives.
### Combining `ng-repeat` with other directives
`ng-repeat` is extremely useful, one of the most powerful directives in Angular.
However the transformation it applies to the DOM is substantial.
Therefore applying other directives (such as `ng-show`, `ng-controller` and others) to the same element as `ng-repeat` generally leads to problems.
If you want to apply a directive to the whole repeat, wrap the repeat in a parent element and put it there.
If you want to apply a directive to each inner piece of the repeat, put it on a child of the element with `ng-repeat`.
### `$rootScope` exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypically inheriting from a root scope at the top of the tree.
Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app.
For these, you can inject `$rootScope` and set values on it like any other scope.
Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like `ng-show` just like values on your local `$scope`.
Of course, global state sucks and you should use `$rootScope` sparingly, like you would (hopefully) use with global variables in any language.
In particular, don't use it for code, only data.
If you're tempted to put a function on `$rootScope`, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
+32 -65
View File
@@ -47,20 +47,23 @@ really digging into it. If you're looking for a shorter introduction to AngularJ
# Working with the code
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. Options for working with the tutorial are to use the Git versioning system for source
code management or to use scripts that copy snapshots of project files into your workspace
(`sandbox`) directory. Select one of the tabs below and follow the instructions for setting up your
computer for your preferred option.
environment. The tutorial relies on the use of Git versioning system for source code management.
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
and follow the instructions for setting up your computer.
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed by running the
following command in a terminal window:</p>
<pre>java -version</pre>
<p>You will need Java to run unit tests.</p></li>
<li><p>Download Git from the <a href="http://git-scm.com/download">Git</a> site.</p>
<p>You can build Git from source or use the pre-compiled package.</p></li>
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
don't have it already:</p>
<pre>npm install -g testacular</pre>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
@@ -71,77 +74,41 @@ directory.</p></li>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can <a
href="http://nodejs.org/#download">install node.js</a>. Use <code>node</code> to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Java to run unit tests, so run the following command to verify that you
have <a href="http://java.com/">Java</a> installed and that the <code>java</code> executable is on
your <code>PATH</code>.</p>
<pre>java -version</pre>
<p></p></li>
<li><p>Install msysGit from <a href="http://git-scm.com/download">the Git</a> site.</p></li>
<li><p>Open msysGit bash and clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<li><p>You will need Node.js and Testacular to run unit tests, so please verify that you have
<a href="http://nodejs.org/">Node.js</a> v0.8 or better installed
and that the <code>node</code> executable is on your <code>PATH</code> by running the following
command in a terminal window:</p>
<pre>node --version</pre>
<p>Additionally install <a href="http://vojtajina.github.com/testacular">Testacular</a> if you
don't have it already:</p>
<pre>npm install -g testacular</pre>
</li>
<li><p>You'll also need Git, which you can get from
<a href="http://git-scm.com/download">the Git site</a>.</p></li>
<li><p>Clone the angular-phonecat repository located at <a
href="https://github.com/angular/angular-phonecat">Github</a> by running the following command:</p>
<pre>git clone git://github.com/angular/angular-phonecat.git</pre>
<p>This command creates the angular-phonecat directory in your current directory.</p></li>
<li><p>Change your current directory to angular-phonecat.</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p>
<p>You should run all <code>git</code> commands from msysGit bash.</p>
<p>Other commands like <code>test-server.bat</code> or <code>test.bat</code> should be
<p>You should run all <code>git</code> commands from Git bash.</p>
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux">
<ol>
<li><p>You need Java to run unit tests, so verify that you have <a
href="http://java.com/">Java</a> installed by running the following command in a terminal
window:</p>
<pre>java -version</pre>
<li><p>Download the <a href="http://code.angularjs.org/angular-phonecat/">zip archive</a>
containing all of the files and unzip them into the [tutorial-dir] directory</p>.</li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from your
<code>sandbox</code> directory.</p></li>
<li><p>You need an http server running on your system and Mac and Linux machines typically
have Apache pre-installed. If you don't have an http server installed, you can <a
href="http://nodejs.org/#download">install node.js</a> and use it to run
<code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows">
<ol>
<li><p>Verify that you have <a href="http://java.com/">Java</a> installed and that the
<code>java</code> executable is on your <code>PATH</code> by running the following command in the
Windows command line:</p>
<pre>java -version</pre>
<p>You need Java to run unit tests, so download the <a
href="http://code.angularjs.org/angular-phonecat/">zip archive</a> that contains all of the files
and unzip the files into the [tutorial-dir] directory</p></li>
<li><p>Change your current directory to [tutorial-dir]/sandbox, as follows:</p>
<pre>cd [tutorial-dir]/sandbox</pre>
<p>The tutorial instructions assume you are running all commands from this directory.</p></li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can install <a href="http://nodejs.org/#download">node.js</a>. Make sure that
<code>nodejs\bin</code> was added into your <code>PATH</code>. Use <code>node</code> to run
<code>scripts\web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
</divs>
The last thing to do is to make sure your computer has a web browser and a good text editor
installed. Now, let's get some cool stuff done!
+1 -65
View File
@@ -46,7 +46,7 @@ directory.</li>
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
<ol>
<li><p>Open msysGit bash and run this command (in angular-phonecat directory):</p>
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
<pre>git checkout -f step-0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
@@ -74,70 +74,6 @@ directory.</li>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-mac" title="Snapshots on Mac/Linux" value="snapshotUnix">
<ol>
<li><p>In the angular-phonecat directory, run this command:</p>
<pre>./goto_step.sh 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run
<code>./scripts/web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
<div class="tab-pane well" id="ss-win" title="Snapshots on Windows" value="snapshotWin">
<ol>
<li><p>Open windows command line and run this command (in the angular-phonecat directory):</p>
<pre>goto_step.bat 0</pre>
<p>This resets your workspace to step 0 of the tutorial app.</p>
<p>You must repeat this for every future step in the tutorial and change the number to
the number of the step you are on. This will cause any changes you made within
your working directory to be lost.</p></li>
<li>To see the app running in a browser, do one of the following:
<ul>
<li><b>For node.js users:</b>
<ol>
<li>In a <i>separate</i> terminal tab or window, run <code>node
scripts\web-server.js</code> to start the web server.</li>
<li>Open a browser window for the app and navigate to <a
href="http://localhost:8000/app/index.html">http://localhost:8000/app/index.html</a></li>
</ol>
</li>
<li><b>For other http servers:</b>
<ol>
<li>Configure the server to serve the files in the angular-phonecat
<code>sandbox</code> directory.</li>
<li>Navigate in your browser to
<code>http://localhost:[port-number]/[context-path]/app/index.html</code>.</li>
</ol>
</li>
</ul>
</li>
</ol>
</div>
</div>
+13 -20
View File
@@ -61,7 +61,7 @@ repeater tells Angular to create a `<li>` element for each phone in the list usi
tag as the template.
* As we've learned in step 0, the curly braces around `phone.name` and `phone.snippet` denote
bindings. As opposed to evaluating constants, these expression are refering to our application
bindings. As opposed to evaluating constants, these expressions are referring to our application
model, which was set up in our `PhoneListCtrl` controller.
<img class="diagram" src="img/tutorial/tutorial_02.png">
@@ -146,31 +146,25 @@ http://pivotal.github.com/jasmine/ Jasmine home page} and on the {@link
https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
The angular-seed project is pre-configured to run all unit tests using {@link
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
http://vojtajina.github.com/testacular/ Testacular}. To run the test, do the following:
1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
`./scripts/test-server.sh` to start the test web server.
`./scripts/test.sh` to start the Testacular server.
2. Open a new browser window and navigate to {@link http://localhost:9876}.
2. Testacular will start a new instance of Chrome browser automatically. Just ignore it and let it run in
the background. Testacular will use this browser for test execution.
3. Choose "Capture this browser in strict mode".
3. You should see the following or similar output in the terminal:
At this point, you can leave this window open and forget about it. JsTestDriver will use it to
execute the tests and report the results in the terminal.
4. Execute the test by running `./scripts/test.sh`
You should see the following or similar output:
Chrome: Runner reset.
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
info: Testacular server started at http://localhost:9876/
info (launcher): Starting browser "Chrome"
info (Chrome 22.0): Connected on socket id tPUm9DXcLHtZTKbAEO-n
Chrome 22.0: Executed 1 of 1 SUCCESS (0.093 secs / 0.004 secs)
Yay! The test passed! Or not...
Note: If you see errors after you run the test, close the browser window and go back to the
terminal and kill the script, then repeat the procedure above.
4. To rerun the tests, just change any of the source or test files. Testacular will notice the change
and will rerun the tests for you. Now isn't that sweet?
# Experiments
@@ -198,8 +192,7 @@ execute the tests and report the results in the terminal.
<tr ng-repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
</table>
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
`./scripts/test.sh` script.
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`.
# Summary
+6 -1
View File
@@ -54,7 +54,7 @@ __`app/index.html`:__
</div>
</pre>
We added a standard HTML `<input>` tag and used angular's
We added a standard HTML `<input>` tag and used Angular's
{@link api/ng.filter:filter $filter} function to process the input for the
{@link api/ng.directive:ngRepeat ngRepeat} directive.
@@ -122,6 +122,11 @@ To run the end-to-end test, open one of the following in a new browser tab:
`http://localhost:[port-number]/[context-path]/test/e2e/runner.html`
* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
Previously we've seen how Testacular can be used to execute unit tests. Well, it can also run the
end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests are slow, so unlike
with unit tests, Testacular will exit after the test run and will not automatically rerun the test
suite on every file change. To rerun the test suite, execute the `e2e-test.sh` script again.
This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in Angular. Although this example is for a simple test, it
really is that easy to set up any functional, readable, end-to-end test.
+4 -8
View File
@@ -134,13 +134,9 @@ The unit test now verifies that the default ordering property is set.
We used Jasmine's API to extract the controller construction into a `beforeEach` block, which is
shared by all tests in the parent `describe` block.
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
following output.
You should now see the following output in the Testacular tab:
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
Let's turn our attention to the end-to-end test.
@@ -168,8 +164,8 @@ __`test/e2e/scenarios.js`:__
The end-to-end test verifies that the ordering mechanism of the select box is working correctly.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
`runner.html` to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
Angular's server}.
+3 -6
View File
@@ -208,13 +208,10 @@ Finally, we verify that the default value of `orderProp` is set correctly:
});
</pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
You should now see the following output in the Testacular tab:
Chrome 22.0: Executed 2 of 2 SUCCESS (0.028 secs / 0.007 secs)
Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
# Experiments
+2 -2
View File
@@ -84,8 +84,8 @@ __`test/e2e/scenarios.js`__:
We added a new end-to-end test to verify that the app is generating correct links to the phone
views that we will implement in the upcoming steps.
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
Angular's server}.
+3 -3
View File
@@ -79,7 +79,7 @@ angular.module('phonecat', []).
</pre>
In order to configure our application with routes, we need to create a module for our application.
We call this module `phonecatApp` and using the `config` API we request the `$routeProvider` to be
We call this module `phonecat` and using the `config` API we request the `$routeProvider` to be
injected into our config function and use `$routeProvider.when` API to define our routes.
Note that during the injector configuration phase, the providers can be injected as well, but they
@@ -232,8 +232,8 @@ to various URLs and verify that the correct view was rendered.
</pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
Angular's server}.
+5 -8
View File
@@ -147,13 +147,9 @@ __`test/unit/controllersSpec.js`:__
...
</pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
You should now see the following output in the Testacular tab:
Chrome: Runner reset.
...
Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
Chrome 22.0: Executed 3 of 3 SUCCESS (0.039 secs / 0.012 secs)
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that the
@@ -177,11 +173,12 @@ __`test/e2e/scenarios.js`:__
</pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
Angular's server}.
# Experiments
* Using the {@link guide/dev_guide.e2e-testing Angular's end-to-end test runner API}, write a test
+2 -6
View File
@@ -110,13 +110,9 @@ describe('filter', function() {
Note that you need to configure our test injector with the `phonecatFilters` module before any of
our filter tests execute.
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
You should now see the following output in the Testacular tab:
Chrome: Runner reset.
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
Chrome 22.0: Executed 4 of 4 SUCCESS (0.034 secs / 0.012 secs)
# Experiments
+2 -2
View File
@@ -102,8 +102,8 @@ __`test/e2e/scenarios.js`:__
});
</pre>
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
can see them running on {@link
You can now rerun `./scripts/e2e-test.sh` or refresh the browser tab with the end-to-end test
runner to see the tests run, or you can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
Angular's server}.
+2 -6
View File
@@ -214,13 +214,9 @@ describe('PhoneCat controllers', function() {
});
</pre>
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
You should now see the following output in the Testacular tab:
Chrome: Runner reset.
....
Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
Chrome 22.0: Executed 4 of 4 SUCCESS (0.038 secs / 0.01 secs)
# Summary
+1 -1
View File
@@ -3,7 +3,7 @@
@description
Our application is now complete. Feel free to experiment with the code further, and jump back to
previous steps using the `git checkout` 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
{@link guide/ Developer Guide}.
-3
View File
@@ -82,10 +82,7 @@ function writeTheRest(writesFuture) {
writesFuture.push(writer.output('appcache.manifest',appCache()));
writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
writesFuture.push(writer.symlinkTemplate('app.yaml'));
writesFuture.push(writer.symlinkTemplate('index.yaml'));
writesFuture.push(writer.symlinkTemplate('favicon.ico'));
writesFuture.push(writer.symlinkTemplate('main.py'));
}
+1
View File
@@ -6,6 +6,7 @@
#
# This file must be processed by Rake in order to replace %ANGULAR_VERSION% with the actual version.
Options -Indexes
RewriteEngine on
RewriteCond %{HTTP_COOKIE} ng-offline="NG_VERSION_FULL"
RewriteRule appcache.manifest appcache-offline.manifest
-69
View File
@@ -1,69 +0,0 @@
application: docs-angularjs-org
version: 1
runtime: python27
api_version: 1
threadsafe: yes
default_expiration: "2h"
handlers:
- url: /
script: main.app
- url: /appcache.manifest
static_files: appcache.manifest
upload: appcache\.manifest
- url: /docs-scenario.html
static_files: docs-scenario.html
upload: docs-scenario\.html
- url: /docs-scenario.js
static_files: docs-scenario.js
upload: docs-scenario\.js
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /docs-keywords.js
static_files: docs-keywords.js
upload: docs-keywords\.js
- url: /robots.txt
static_files: robots.txt
upload: robots\.txt
- url: /sitemap.xml
static_files: sitemap.xml
upload: sitemap\.xml
- url: /css
static_dir: css
- url: /font
static_dir: font
- url: /img
static_dir: img
- url: /js
static_dir: js
- url: /partials/(.+):(.+)
static_files: partials/\1_\2
upload: partials/.*
- url: /partials
static_dir: partials
- url: /syntaxhighlighter
static_dir: syntaxhighlighter
- url: /.*
static_files: index.html
upload: index.html
libraries:
- name: webapp2
version: "2.5.1"
+3 -4
View File
@@ -3,7 +3,7 @@
<head>
<title>AngularJS Docs E2E Test Runner</title>
<script>
var gae = (location.pathname.split('/').length == 2),
var production = location.hostname === 'docs.angularjs.org',
headEl = document.head,
angularVersion = {
current: '"NG_VERSION_FULL"', // rewrite during build
@@ -33,9 +33,8 @@
function path(name) {
return gae
? 'http://code.angularjs.org/' + angularVersion.stable + '/' +
name.replace(/\.js$/, '-' + angularVersion.stable + '.js')
return production
? 'http://code.angularjs.org/' + angularVersion.stable + '/' + name
: '../' + name;
}
</script>
+9 -9
View File
@@ -22,7 +22,7 @@
baseUrl = location.href.replace(rUrl, indexFile),
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
gae = (baseUrl.split('/').length == 4),
production = location.hostname === 'docs.angularjs.org',
headEl = document.getElementsByTagName('head')[0],
sync = true,
angularVersion = {
@@ -45,7 +45,7 @@
addTag('script', {src: 'docs-keywords.js'}, sync);
function path(name) {
if (gae) {
if (production) {
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
angularVersion.stable +
@@ -55,7 +55,7 @@
name = 'http://code.angularjs.org/' +
angularVersion.stable +
'/' +
name.replace(/\.js$/, '-' + angularVersion.stable +'.min.js');
name.replace(/\.js$/, '.min.js');
}
return name;
}
@@ -126,10 +126,10 @@
<i class="icon-eye-open icon-white"></i> Learn <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li class="disabled"><a href="">Why AngularJS?</a></li>
<li class="disabled"><a href="http://angularjs.org/">Why AngularJS?</a></li>
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
<li><a href="tutorial">Tutorial</a></li>
<li><a href="https://github.com/angular/angular.js/wiki/Projects-using-AngularJS">Case Studies</a></li>
<li><a href="http://builtwith.angularjs.org/">Case Studies</a></li>
<li><a href="misc/faq">FAQ</a></li>
</ul>
</li>
@@ -139,10 +139,10 @@
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="tutorial">Tutorial</a></li>
<li><a href="guide/">Developer Guide</a></li>
<li><a href="api/">API Reference</a></li>
<li><a href="misc/contribute">Contribute</a></li>
<li><a href="http://docs.angularjs.org/tutorial">Tutorial</a></li>
<li><a href="http://docs.angularjs.org/guide/">Developer Guide</a></li>
<li><a href="http://docs.angularjs.org/api/">API Reference</a></li>
<li><a href="http://docs.angularjs.org/misc/contribute">Contribute</a></li>
<li><a href="http://code.angularjs.org/">Download</a></li>
</ul>
</li>
-12
View File
@@ -1,12 +0,0 @@
indexes:
# AUTOGENERATED
# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run. If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED"). If you want to manage some indexes
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.
+57 -8
View File
@@ -30,9 +30,16 @@ docsApp.directive.code = function() {
docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
return {
template: '<button ng-click="fiddle($event)" class="btn btn-primary pull-right"><i class="icon-pencil icon-white"></i> Edit</button>\n',
template: '<div class="btn-group pull-right">' +
'<a class="btn dropdown-toggle btn-primary" data-toggle="dropdown" href>' +
' <i class="icon-pencil icon-white"></i> Edit<span class="caret"></span>' +
'</a>' +
'<ul class="dropdown-menu">' +
' <li><a ng-click="plunkr($event)" href="">In Plunkr</a></li>' +
' <li><a ng-click="fiddle($event)" href="">In JsFiddle</a></li>' +
'</ul>',
scope: true,
controller: function($scope, $attrs, openJsFiddle) {
controller: function($scope, $attrs, openJsFiddle, openPlunkr) {
var sources = {
module: $attrs.sourceEdit,
deps: read($attrs.sourceEditDeps),
@@ -45,14 +52,19 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
$scope.fiddle = function(e) {
e.stopPropagation();
openJsFiddle(sources);
}
};
$scope.plunkr = function(e) {
e.stopPropagation();
openPlunkr(sources);
};
}
}
function read(text) {
var files = [];
angular.forEach(text ? text.split(' ') : [], function(refId) {
files.push({name: refId.split('-')[0], content: getEmbeddedTemplate(refId)});
// refId is index.html-343, so we need to strip the unique ID when exporting the name
files.push({name: refId.replace(/-\d+$/, ''), content: getEmbeddedTemplate(refId)});
});
return files;
}
@@ -111,8 +123,6 @@ docsApp.directive.docTutorialReset = function() {
'<div class="tabbable" ng-show="show" ng-model="$cookies.platformPreference">\n' +
tab('Git on Mac/Linux', 'git checkout -f step-' + step, 'gitUnix', step) +
tab('Git on Windows', 'git checkout -f step-' + step, 'gitWin', step) +
tab('Snapshots on Mac/Linux', './goto_step.sh ' + step, 'snapshotUnix', step) +
tab('Snapshots on on Windows', './goto_step.bat ' + step, 'snapshotWin', step) +
'</div>\n');
}
};
@@ -147,8 +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>',
CSS = '</style> <!-- Ugly Hack due to jsFiddle issue: http://goo.gl/BUfGZ --> \n' +
'{{head:0}}<style>\n.ng-invalid { border: 1px solid red; }\n{{css}}',
@@ -297,7 +346,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
tutorial: 'Tutorial',
cookbook: 'Examples'
};
$scope.$watch(function() {return $location.path(); }, function(path) {
$scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) {
// ignore non-doc links which are used in examples
if (DOCS_PATH.test(path)) {
var parts = path.split('/'),
-18
View File
@@ -1,18 +0,0 @@
import webapp2
from google.appengine.ext.webapp import template
class IndexHandler(webapp2.RequestHandler):
def get(self):
fragment = self.request.get('_escaped_fragment_')
if fragment:
fragment = '/partials' + fragment + '.html'
self.redirect(fragment, permanent=True)
else:
self.response.headers['Content-Type'] = 'text/html'
self.response.out.write(template.render('index-nocache.html', None))
app = webapp2.WSGIApplication([('/', IndexHandler)])
+2 -3
View File
@@ -1,10 +1,9 @@
#!/usr/bin/env bash
JASMINE_NODE='jasmine-node'
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
# Locally (npm)-installed jasmine-node
local_jasmine='./node_modules/.bin/jasmine-node'
local_jasmine='./node_modules/.bin/jasmine-node'
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
if [[ -x "$local_jasmine" ]];then
JASMINE_NODE="$local_jasmine"
else
-47
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- ');
});
}
Executable
+32
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
View File
@@ -1,2 +0,0 @@
#!/bin/sh
/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java $@
-198
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);
};
-1
View File
@@ -1 +0,0 @@
da92db714142b49f9cf61db664e782bb0ccad80b
-20
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.
-190
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;
};
-166
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

-1
View File
@@ -1 +0,0 @@
1.1.0
+3704 -3668
View File
File diff suppressed because it is too large Load Diff
+2 -4
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
1.7.2
1.8.2
BIN
View File
Binary file not shown.
-130
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.
-1
View File
@@ -1 +0,0 @@
1.3.3d
-17
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
+1
View File
@@ -2,6 +2,7 @@
"name": "AngularJS",
"version": "0.0.0",
"dependencies" : {
"testacular" : "canary",
"jasmine-node" : "*",
"q-fs" : "*",
"qq" : "*"
-18
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>
-1
View File
@@ -1 +0,0 @@
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 20000 --config jsTestDriver-coverage.conf
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
java -jar lib/jstestdriver/JsTestDriver.jar --port 9877 --browserTimeout 90000 --config jsTestDriver-scenario.conf
-4
View File
@@ -1,4 +0,0 @@
#!/bin/bash
node gen_jstd_configs.js
java -jar lib/jstestdriver/JsTestDriver.jar --port 9876 --browserTimeout 90000
+2 -2
View File
@@ -788,7 +788,7 @@ function toKeyValue(obj) {
/**
* We need our custom 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
* segments:
* segment = *pchar
@@ -832,7 +832,7 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @name ng.directive:ngApp
*
* @element ANY
* @param {angular.Module} ngApp on optional application
* @param {angular.Module} ngApp an optional application
* {@link angular.module module} name to load.
*
* @description
+10
View File
@@ -97,5 +97,15 @@ HashQueueMap.prototype = {
return array.shift();
}
}
},
/**
* return the first item without deleting it
*/
peek: function(key) {
var array = this[hashKey(key)];
if (array) {
return array[0];
}
}
};
+7 -8
View File
@@ -20,7 +20,7 @@
* // create an injector
* var $injector = angular.injector(['ng']);
*
* // use the injector to kick of your application
* // use the injector to kick off your application
* // use the type inference to auto inject arguments, or use implicit injection
* $injector.invoke(function($rootScope, $compile, $document){
* $compile($document)($rootScope);
@@ -40,7 +40,7 @@
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function annotate(fn) {
var $inject,
@@ -410,9 +410,10 @@ function createInjector(modulesToLoad) {
decorator: decorator
}
},
providerInjector = createInternalInjector(providerCache, function() {
throw Error("Unknown provider: " + path.join(' <- '));
}),
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() {
throw Error("Unknown provider: " + path.join(' <- '));
})),
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) {
@@ -489,9 +490,7 @@ function createInjector(modulesToLoad) {
try {
for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i],
provider = invokeArgs[0] == '$injector'
? providerInjector
: providerInjector.get(invokeArgs[0]);
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
+1 -1
View File
@@ -210,7 +210,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
}, $delegate);
}]);
$provide.decorator('$rootScope', ['$delegate', function(embedRootScope) {
docsRootScope.$watch(function() {
docsRootScope.$watch(function embedRootScopeDigestWatch() {
embedRootScope.$digest();
});
return embedRootScope;
+1 -1
View File
@@ -9,7 +9,7 @@ directive.dropdownToggle =
return {
restrict: 'C',
link: function(scope, element, attrs) {
scope.$watch(function(){return $location.path();}, function() {
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
close && close();
});
+19 -14
View File
@@ -54,6 +54,7 @@
* - [replaceWith()](http://api.jquery.com/replaceWith/)
* - [text()](http://api.jquery.com/text/)
* - [toggleClass()](http://api.jquery.com/toggleClass/)
* - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers.
* - [unbind()](http://api.jquery.com/unbind/)
* - [val()](http://api.jquery.com/val/)
* - [wrap()](http://api.jquery.com/wrap/)
@@ -129,12 +130,7 @@ function JQLitePatchJQueryRemove(name, dispatchThis) {
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
element = jqLite(set[setIndex]);
if (fireEvent) {
events = element.data('events');
if ( (fns = events && events.$destroy) ) {
forEach(fns, function(fn){
fn.handler();
});
}
element.triggerHandler('$destroy');
} else {
fireEvent = !fireEvent;
}
@@ -266,9 +262,9 @@ function JQLiteHasClass(element, selector) {
indexOf( " " + selector + " " ) > -1);
}
function JQLiteRemoveClass(element, selector) {
if (selector) {
forEach(selector.split(' '), function(cssClass) {
function JQLiteRemoveClass(element, cssClasses) {
if (cssClasses) {
forEach(cssClasses.split(' '), function(cssClass) {
element.className = trim(
(" " + element.className + " ")
.replace(/[\n\t]/g, " ")
@@ -278,9 +274,9 @@ function JQLiteRemoveClass(element, selector) {
}
}
function JQLiteAddClass(element, selector) {
if (selector) {
forEach(selector.split(' '), function(cssClass) {
function JQLiteAddClass(element, cssClasses) {
if (cssClasses) {
forEach(cssClasses.split(' '), function(cssClass) {
if (!JQLiteHasClass(element, cssClass)) {
element.className = trim(element.className + ' ' + trim(cssClass));
}
@@ -663,8 +659,9 @@ forEach({
append: function(element, node) {
forEach(new JQLite(node), function(child){
if (element.nodeType === 1)
if (element.nodeType === 1 || element.nodeType === 11) {
element.appendChild(child);
}
});
},
@@ -728,7 +725,15 @@ forEach({
return element.getElementsByTagName(selector);
},
clone: JQLiteClone
clone: JQLiteClone,
triggerHandler: function(element, eventName) {
var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
forEach(eventFns, function(fn) {
fn.call(element, null);
});
}
}, function(fn, name){
/**
* chaining functions
+4 -4
View File
@@ -30,7 +30,7 @@ function setupModuleLoader(window) {
*
* # Module
*
* A module is a collocation of services, directives, filters, and configure information. Module
* A module is a collocation of services, directives, filters, and configuration information. Module
* is used to configure the {@link AUTO.$injector $injector}.
*
* <pre>
@@ -60,7 +60,7 @@ function setupModuleLoader(window) {
* @param {!string} name The name of the module to create or retrieve.
* @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
* the module is being retrieved for further configuration.
* @param {Function} configFn Option configuration function for the module. Same as
* @param {Function} configFn Optional configuration function for the module. Same as
* {@link angular.Module#config Module#config()}.
* @returns {module} new module with the {@link angular.Module} api.
*/
@@ -215,8 +215,8 @@ function setupModuleLoader(window) {
* @param {Function} initializationFn Execute this function after injector creation.
* Useful for application initialization.
* @description
* Use this method to register work which needs to be performed when the injector with
* with the current module is finished loading.
* Use this method to register work which should be performed when the injector is done
* loading all modules.
*/
run: function(block) {
runBlocks.push(block);
+4 -3
View File
@@ -55,9 +55,10 @@ function $AnchorScrollProvider() {
// does not scroll when user clicks on anchor link that is currently on
// (no url change, no $locaiton.hash() change), browser native does scroll
if (autoScrollingEnabled) {
$rootScope.$watch(function() {return $location.hash();}, function() {
$rootScope.$evalAsync(scroll);
});
$rootScope.$watch(function autoScrollWatch() {return $location.hash();},
function autoScrollWatchAction() {
$rootScope.$evalAsync(scroll);
});
}
return scroll;
+9 -5
View File
@@ -14,11 +14,11 @@
* @returns {object} Newly created cache object with the following set of methods:
*
* - `{object}` `info()` — Returns id, size, and options of cache.
* - `{void}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache.
* - `{{*}} `get({string} key) — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key) — Removes a key-value pair from the cache.
* - `{void}` `removeAll() — Removes all cached values.
* - `{void}` `destroy() — Removes references to this cache from $cacheFactory.
* - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns it.
* - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
* - `{void}` `removeAll()` — Removes all cached values.
* - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
*
*/
function $CacheFactoryProvider() {
@@ -53,6 +53,8 @@ function $CacheFactoryProvider() {
if (size > capacity) {
this.remove(staleEnd.key);
}
return value;
},
@@ -70,6 +72,8 @@ function $CacheFactoryProvider() {
remove: function(key) {
var lruEntry = lruHash[key];
if (!lruEntry) return;
if (lruEntry == freshEnd) freshEnd = lruEntry.p;
if (lruEntry == staleEnd) staleEnd = lruEntry.n;
link(lruEntry.n,lruEntry.p);
+31 -30
View File
@@ -310,26 +310,26 @@ function $CompileProvider($provide) {
//================================
function compile($compileNode, transcludeFn, maxPriority) {
if (!($compileNode instanceof jqLite)) {
function compile($compileNodes, transcludeFn, maxPriority) {
if (!($compileNodes instanceof jqLite)) {
// jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
$compileNode = jqLite($compileNode);
$compileNodes = jqLite($compileNodes);
}
// We can not compile top level text elements since text nodes can be merged and we will
// not be able to attach scope data to them, so we will wrap them in <span>
forEach($compileNode, function(node, index){
forEach($compileNodes, function(node, index){
if (node.nodeType == 3 /* text node */) {
$compileNode[index] = jqLite(node).wrap('<span></span>').parent()[0];
$compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
}
});
var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
return function(scope, cloneConnectFn){
var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
return function publicLinkFn(scope, cloneConnectFn){
assertArg(scope, 'scope');
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
var $linkNode = cloneConnectFn
? JQLitePrototype.clone.call($compileNode) // IMPORTANT!!!
: $compileNode;
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
: $compileNodes;
$linkNode.data('$scope', scope);
safeAddClass($linkNode, 'ng-scope');
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
@@ -380,7 +380,7 @@ function $CompileProvider($provide) {
? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
: null;
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal)
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length)
? null
: compileNodes(nodeList[i].childNodes,
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
@@ -432,13 +432,14 @@ function $CompileProvider($provide) {
/**
* Looks for directives on the given node ands them to the directive collection which is sorted.
* Looks for directives on the given node and adds them to the directive collection which is
* sorted.
*
* @param node node to search
* @param directives an array to which the directives are added to. This array is sorted before
* @param node Node to search.
* @param directives An array to which the directives are added to. This array is sorted before
* the function returns.
* @param attrs the shared attrs object which is used to populate the normalized attributes.
* @param {number=} max directive priority
* @param attrs The shared attrs object which is used to populate the normalized attributes.
* @param {number=} maxPriority Max directive priority.
*/
function collectDirectives(node, directives, attrs, maxPriority) {
var nodeType = node.nodeType,
@@ -473,7 +474,7 @@ function $CompileProvider($provide) {
// use class as directive
className = node.className;
if (isString(className)) {
if (isString(className) && className !== '') {
while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
nName = directiveNormalize(match[2]);
if (addDirective(directives, nName, 'C', maxPriority)) {
@@ -527,7 +528,7 @@ function $CompileProvider($provide) {
preLinkFns = [],
postLinkFns = [],
newScopeDirective = null,
newIsolatedScopeDirective = null,
newIsolateScopeDirective = null,
templateDirective = null,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
@@ -549,10 +550,10 @@ function $CompileProvider($provide) {
}
if (directiveValue = directive.scope) {
assertNoDuplicate('isolated scope', newIsolatedScopeDirective, directive, $compileNode);
assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
if (isObject(directiveValue)) {
safeAddClass($compileNode, 'ng-isolate-scope');
newIsolatedScopeDirective = directive;
newIsolateScopeDirective = directive;
}
safeAddClass($compileNode, 'ng-scope');
newScopeDirective = newScopeDirective || directive;
@@ -706,12 +707,12 @@ function $CompileProvider($provide) {
}
$element = attrs.$$element;
if (newScopeDirective && isObject(newScopeDirective.scope)) {
if (newIsolateScopeDirective) {
var LOCAL_REGEXP = /^\s*([@=&])\s*(\w*)\s*$/;
var parentScope = scope.$parent || scope;
forEach(newScopeDirective.scope, function(definiton, scopeName) {
forEach(newIsolateScopeDirective.scope, function(definiton, scopeName) {
var match = definiton.match(LOCAL_REGEXP) || [],
attrName = match[2]|| scopeName,
mode = match[1], // @, =, or &
@@ -734,10 +735,10 @@ function $CompileProvider($provide) {
// reset the change, or we will throw this exception on every $digest
lastValue = scope[scopeName] = parentGet(parentScope);
throw Error(NON_ASSIGNABLE_MODEL_EXPRESSION + attrs[attrName] +
' (directive: ' + newScopeDirective.name + ')');
' (directive: ' + newIsolateScopeDirective.name + ')');
};
lastValue = scope[scopeName] = parentGet(parentScope);
scope.$watch(function() {
scope.$watch(function parentValueWatch() {
var parentValue = parentGet(parentScope);
if (parentValue !== scope[scopeName]) {
@@ -747,7 +748,7 @@ function $CompileProvider($provide) {
lastValue = scope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
parentSet(parentScope, lastValue = scope[scopeName]);
parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
}
}
return parentValue;
@@ -765,7 +766,7 @@ function $CompileProvider($provide) {
default: {
throw Error('Invalid isolate scope definition for directive ' +
newScopeDirective.name + ': ' + definiton);
newIsolateScopeDirective.name + ': ' + definiton);
}
}
});
@@ -899,7 +900,7 @@ function $CompileProvider($provide) {
origAsyncDirective = directives.shift(),
// The fact that we have to copy and patch the directive seems wrong!
derivedSyncDirective = extend({}, origAsyncDirective, {
controller: null, templateUrl: null, transclude: null
controller: null, templateUrl: null, transclude: null, scope: null
});
$compileNode.html('');
@@ -991,12 +992,12 @@ function $CompileProvider($provide) {
if (interpolateFn) {
directives.push({
priority: 0,
compile: valueFn(function(scope, node) {
compile: valueFn(function textInterpolateLinkFn(scope, node) {
var parent = node.parent(),
bindings = parent.data('$binding') || [];
bindings.push(interpolateFn);
safeAddClass(parent.data('$binding', bindings), 'ng-binding');
scope.$watch(interpolateFn, function(value) {
scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
node[0].nodeValue = value;
});
})
@@ -1014,7 +1015,7 @@ function $CompileProvider($provide) {
directives.push({
priority: 100,
compile: valueFn(function(scope, element, attr) {
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
var $$observers = (attr.$$observers || (attr.$$observers = {}));
if (name === 'class') {
@@ -1026,7 +1027,7 @@ function $CompileProvider($provide) {
attr[name] = undefined;
($$observers[name] || ($$observers[name] = [])).$$inter = true;
(attr.$$observers && attr.$$observers[name].$$scope || scope).
$watch(interpolateFn, function(value) {
$watch(interpolateFn, function interpolateFnWatchAction(value) {
attr.$set(name, value);
});
})
+1
View File
@@ -27,6 +27,7 @@ var htmlAnchorDirective = valueFn({
// if we have no href url, then don't navigate anywhere.
if (!element.attr('href')) {
event.preventDefault();
return false; // Needed for opera
}
});
}
+4 -1
View File
@@ -284,7 +284,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
priority: 100,
compile: function() {
return function(scope, element, attr) {
scope.$watch(attr[normalized], function(value) {
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
attr.$set(attrName, !!value);
});
};
@@ -302,6 +302,9 @@ forEach(['src', 'href'], function(attrName) {
priority: 99, // it needs to run after the attributes are interpolated
link: function(scope, element, attr) {
attr.$observe(normalized, function(value) {
if (!value)
return;
attr.$set(attrName, value);
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
+32 -2
View File
@@ -5,7 +5,8 @@ var nullFormCtrl = {
$addControl: noop,
$removeControl: noop,
$setValidity: noop,
$setDirty: noop
$setDirty: noop,
$setPristine: noop
};
/**
@@ -37,7 +38,8 @@ function FormController(element, attrs) {
var form = this,
parentForm = element.parent().controller('form') || nullFormCtrl,
invalidCount = 0, // used to easily determine if we are valid
errors = form.$error = {};
errors = form.$error = {},
controls = [];
// init state
form.$name = attrs.name;
@@ -61,6 +63,8 @@ function FormController(element, attrs) {
}
form.$addControl = function(control) {
controls.push(control);
if (control.$name && !form.hasOwnProperty(control.$name)) {
form[control.$name] = control;
}
@@ -73,6 +77,8 @@ function FormController(element, attrs) {
forEach(errors, function(queue, validationToken) {
form.$setValidity(validationToken, true, control);
});
arrayRemove(controls, control);
};
form.$setValidity = function(validationToken, isValid, control) {
@@ -117,8 +123,32 @@ function FormController(element, attrs) {
element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
form.$dirty = true;
form.$pristine = false;
parentForm.$setDirty();
};
/**
* @ngdoc function
* @name ng.directive:form.FormController#$setPristine
* @methodOf ng.directive:form.FormController
*
* @description
* Sets the form to its pristine state.
*
* This method can be called to remove the 'ng-dirty' class and set the form to its pristine
* state (ng-pristine class). This method will also propagate to all the controls contained
* in this form.
*
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
* saving or resetting it.
*/
form.$setPristine = function () {
element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
form.$dirty = false;
form.$pristine = true;
forEach(controls, function(control) {
control.$setPristine();
});
};
}
+68 -18
View File
@@ -15,7 +15,10 @@ var inputType = {
*
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} required Adds `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -25,6 +28,8 @@ var inputType = {
* patterns defined as scope expressions.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trimming the
* input.
*
* @example
<doc:example>
@@ -32,12 +37,12 @@ var inputType = {
<script>
function Ctrl($scope) {
$scope.text = 'guest';
$scope.word = /^\w*$/;
$scope.word = /^\s*\w*\s*$/;
}
</script>
<form name="myForm" ng-controller="Ctrl">
Single word: <input type="text" name="input" ng-model="text"
ng-pattern="word" required>
ng-pattern="word" required ng-trim="false">
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.input.$error.pattern">
@@ -66,6 +71,12 @@ var inputType = {
input('text').enter('hello world');
expect(binding('myForm.input.$valid')).toEqual('false');
});
it('should not be trimmed', function() {
input('text').enter('untrimmed ');
expect(binding('text')).toEqual('untrimmed ');
expect(binding('myForm.input.$valid')).toEqual('true');
});
</doc:scenario>
</doc:example>
*/
@@ -85,6 +96,9 @@ var inputType = {
* @param {string=} min Sets the `min` validation error key if the value entered is less then `min`.
* @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -151,6 +165,9 @@ var inputType = {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -216,6 +233,9 @@ var inputType = {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -370,7 +390,14 @@ function isEmpty(value) {
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var listener = function() {
var value = trim(element.val());
var value = element.val();
// By default we will trim the value
// If the attribute ng-trim exists we will avoid trimming
// e.g. <input ng-model="foo" ng-trim="false">
if (toBoolean(attr.ngTrim || 'T')) {
value = trim(value);
}
if (ctrl.$viewValue !== value) {
scope.$apply(function() {
@@ -638,6 +665,9 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -662,6 +692,7 @@ function checkboxInputType(scope, element, attr, ctrl) {
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {boolean=} ngRequired Sets `required` attribute if set to true
* @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
* minlength.
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
@@ -947,6 +978,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
parentForm.$setValidity(validationErrorKey, isValid, this);
};
/**
* @ngdoc function
* @name ng.directive:ngModel.NgModelController#$setPristine
* @methodOf ng.directive:ngModel.NgModelController
*
* @description
* Sets the control to its pristine state.
*
* This method can be called to remove the 'ng-dirty' class and set the control to its pristine
* state (ng-pristine class).
*/
this.$setPristine = function () {
this.$dirty = false;
this.$pristine = true;
$element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
};
/**
* @ngdoc function
@@ -995,22 +1042,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// model -> value
var ctrl = this;
$scope.$watch(ngModelGet, function(value) {
// ignore change from view
if (ctrl.$modelValue === value) return;
$scope.$watch(function ngModelWatch() {
var value = ngModelGet($scope);
var formatters = ctrl.$formatters,
idx = formatters.length;
// if scope model value and ngModel value are out of sync
if (ctrl.$modelValue !== value) {
ctrl.$modelValue = value;
while(idx--) {
value = formatters[idx](value);
}
var formatters = ctrl.$formatters,
idx = formatters.length;
if (ctrl.$viewValue !== value) {
ctrl.$viewValue = value;
ctrl.$render();
ctrl.$modelValue = value;
while(idx--) {
value = formatters[idx](value);
}
if (ctrl.$viewValue !== value) {
ctrl.$viewValue = value;
ctrl.$render();
}
}
});
}];
@@ -1159,7 +1209,7 @@ var requiredDirective = function() {
* @name ng.directive:ngList
*
* @description
* Text input that converts between comma-seperated string into an array of strings.
* Text input that converts between comma-separated string into an array of strings.
*
* @element input
* @param {string=} ngList optional delimiter that should be used to split the value. If
@@ -1242,7 +1292,7 @@ var ngValueDirective = function() {
};
} else {
return function(scope, elm, attr) {
scope.$watch(attr.ngValue, function(value) {
scope.$watch(attr.ngValue, function valueWatchAction(value) {
attr.$set('value', value, false);
});
};
+2 -2
View File
@@ -49,7 +49,7 @@
*/
var ngBindDirective = ngDirective(function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBind);
scope.$watch(attr.ngBind, function(value) {
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
element.text(value == undefined ? '' : value);
});
});
@@ -132,7 +132,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
var ngBindHtmlUnsafeDirective = [function() {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
scope.$watch(attr.ngBindHtmlUnsafe, function ngBindHtmlUnsafeWatchAction(value) {
element.html(value || '');
});
};
+47 -9
View File
@@ -3,17 +3,55 @@
function classDirective(name, selector) {
name = 'ngClass' + name;
return ngDirective(function(scope, element, attr) {
scope.$watch(attr[name], function(newVal, oldVal) {
scope.$watch(attr[name], ngClassWatchAction, true);
attr.$observe('class', function(value) {
var ngClass = scope.$eval(attr[name]);
ngClassWatchAction(ngClass, ngClass);
});
if (name !== 'ngClass') {
scope.$watch('$index', function($index, old$index) {
var mod = $index % 2;
if (mod !== old$index % 2) {
if (mod == selector) {
addClass(scope.$eval(attr[name]));
} else {
removeClass(scope.$eval(attr[name]));
}
}
});
}
function ngClassWatchAction(newVal, oldVal) {
if (selector === true || scope.$index % 2 === selector) {
if (oldVal && (newVal !== oldVal)) {
if (isObject(oldVal) && !isArray(oldVal))
oldVal = map(oldVal, function(v, k) { if (v) return k });
element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
}
if (isObject(newVal) && !isArray(newVal))
newVal = map(newVal, function(v, k) { if (v) return k });
if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
}, true);
removeClass(oldVal);
}
addClass(newVal);
}
}
function removeClass(classVal) {
if (isObject(classVal) && !isArray(classVal)) {
classVal = map(classVal, function(v, k) { if (v) return k });
}
element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
}
function addClass(classVal) {
if (isObject(classVal) && !isArray(classVal)) {
classVal = map(classVal, function(v, k) { if (v) return k });
}
if (classVal) {
element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
}
}
});
}
+1 -1
View File
@@ -101,7 +101,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
element.html('');
};
scope.$watch(srcExp, function(src) {
scope.$watch(srcExp, function ngIncludeWatchAction(src) {
var thisChangeId = ++changeCounter;
if (src) {
+2 -2
View File
@@ -188,7 +188,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
offset + endSymbol));
});
scope.$watch(function() {
scope.$watch(function ngPluralizeWatch() {
var value = parseFloat(scope.$eval(numberExp));
if (!isNaN(value)) {
@@ -199,7 +199,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
} else {
return '';
}
}, function(newVal) {
}, function ngPluralizeWatchAction(newVal) {
element.text(newVal);
});
}
+4 -1
View File
@@ -88,7 +88,8 @@ var ngRepeatDirective = ngDirective({
// We need an array of these objects since the same object can be returned from the iterator.
// We expect this to be a rare case.
var lastOrder = new HashQueueMap();
scope.$watch(function(scope){
scope.$watch(function ngRepeatWatch(scope){
var index, length,
collection = scope.$eval(rhs),
collectionLength = size(collection, true),
@@ -117,7 +118,9 @@ var ngRepeatDirective = ngDirective({
for (index = 0, length = array.length; index < length; index++) {
key = (collection === array) ? index : array[index];
value = collection[key];
last = lastOrder.shift(value);
if (last) {
// if we have already seen this object, then we need to reuse the
// associated scope/element
+5 -5
View File
@@ -34,7 +34,7 @@
*/
//TODO(misko): refactor to remove element from the DOM
var ngShowDirective = ngDirective(function(scope, element, attr){
scope.$watch(attr.ngShow, function(value){
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
element.css('display', toBoolean(value) ? '' : 'none');
});
});
@@ -45,11 +45,11 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
* @name ng.directive:ngHide
*
* @description
* The `ngHide` and `ngShow` directives hide or show a portion
* of the HTML conditionally.
* The `ngHide` and `ngShow` directives hide or show a portion of the DOM tree (HTML)
* conditionally.
*
* @element ANY
* @param {expression} ngHide If the {@link guide/expression expression} truthy then
* @param {expression} ngHide If the {@link guide/expression expression} is truthy then
* the element is shown or hidden respectively.
*
* @example
@@ -74,7 +74,7 @@ var ngShowDirective = ngDirective(function(scope, element, attr){
*/
//TODO(misko): refactor to remove element from the DOM
var ngHideDirective = ngDirective(function(scope, element, attr){
scope.$watch(attr.ngHide, function(value){
scope.$watch(attr.ngHide, function ngHideWatchAction(value){
element.css('display', toBoolean(value) ? 'none' : '');
});
});
+1 -1
View File
@@ -38,7 +38,7 @@
</example>
*/
var ngStyleDirective = ngDirective(function(scope, element, attr) {
scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
if (oldStyles && (newStyles !== oldStyles)) {
forEach(oldStyles, function(val, style) { element.css(style, '');});
}
+1 -1
View File
@@ -72,7 +72,7 @@ var ngSwitchDirective = valueFn({
selectedElement,
selectedScope;
scope.$watch(watchExpr, function(value) {
scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
if (selectedElement) {
selectedScope.$destroy();
selectedElement.remove();
+10 -4
View File
@@ -29,6 +29,9 @@
*
* @param {string} name assignable expression to data-bind to.
* @param {string=} required The control is considered valid only if value is entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
* `required` when you want to data-bind to the `required` attribute.
* @param {comprehension_expression=} ngOptions in one of the following forms:
*
* * for array data sources:
@@ -269,7 +272,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// we have to do it on each watch since ngModel watches reference, but
// we need to work of an array, so we need to see if anything was inserted/removed
scope.$watch(function() {
scope.$watch(function selectMultipleWatch() {
if (!equals(lastView, ctrl.$viewValue)) {
lastView = copy(ctrl.$viewValue);
ctrl.$render();
@@ -386,7 +389,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
selected,
selectedSet = false, // nothing is selected yet
lastElement,
element;
element,
label;
if (multiple) {
selectedSet = new HashMap(modelValue);
@@ -410,9 +414,11 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
selected = modelValue === valueFn(scope, locals);
selectedSet = selectedSet || selected; // see if at least one item is selected
}
label = displayFn(scope, locals); // what will be seen by the user
label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
optionGroup.push({
id: keyName ? keys[index] : index, // either the index into array or key from object
label: displayFn(scope, locals) || '', // what will be seen by the user
label: label,
selected: selected // determine if we should be selected
});
}
@@ -544,7 +550,7 @@ var optionDirective = ['$interpolate', function($interpolate) {
}
if (interpolateFn) {
scope.$watch(interpolateFn, function(newVal, oldVal) {
scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
attr.$set('value', newVal);
if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
selectCtrl.addOption(newVal);
+12 -3
View File
@@ -117,9 +117,18 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
formatedText = '',
parts = [];
var hasExponent = false;
if (numStr.indexOf('e') !== -1) {
formatedText = numStr;
} else {
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
if (match && match[2] == '-' && match[3] > fractionSize + 1) {
numStr = '0';
} else {
formatedText = numStr;
hasExponent = true;
}
}
if (!hasExponent) {
var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
// determine fractionSize if it is not specified
@@ -320,7 +329,7 @@ dateFilter.$inject = ['$locale'];
function dateFilter($locale) {
var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
function jsonStringToDate(string){
var match;
if (match = string.match(R_ISO8601_STR)) {
+65 -17
View File
@@ -29,6 +29,43 @@ function parseHeaders(headers) {
}
var IS_SAME_DOMAIN_URL_MATCH = /^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/;
/**
* Parse a request and location URL and determine whether this is a same-domain request.
*
* @param {string} requestUrl The url of the request.
* @param {string} locationUrl The current browser location url.
* @returns {boolean} Whether the request is for the same domain.
*/
function isSameDomain(requestUrl, locationUrl) {
var match = IS_SAME_DOMAIN_URL_MATCH.exec(requestUrl);
// if requestUrl is relative, the regex does not match.
if (match == null) return true;
var domain1 = {
protocol: match[2],
host: match[4],
port: int(match[6]) || DEFAULT_PORTS[match[2]] || null,
// IE8 sets unmatched groups to '' instead of undefined.
relativeProtocol: match[2] === undefined || match[2] === ''
};
match = URL_MATCH.exec(locationUrl);
var domain2 = {
protocol: match[1],
host: match[3],
port: int(match[5]) || DEFAULT_PORTS[match[1]] || null
};
return (domain1.protocol == domain2.protocol || domain1.relativeProtocol) &&
domain1.host == domain2.host &&
(domain1.port == domain2.port || (domain1.relativeProtocol &&
domain2.port == DEFAULT_PORTS[domain2.protocol]));
}
/**
* Returns a function that provides access to parsed headers.
*
@@ -88,7 +125,7 @@ function $HttpProvider() {
JSON_END = /[\}\]]\s*$/,
PROTECTION_PREFIX = /^\)\]\}',?\n/;
var $config = this.defaults = {
var defaults = this.defaults = {
// transform incoming response data
transformResponse: [function(data) {
if (isString(data)) {
@@ -108,8 +145,7 @@ function $HttpProvider() {
// default headers
headers: {
common: {
'Accept': 'application/json, text/plain, */*',
'X-Requested-With': 'XMLHttpRequest'
'Accept': 'application/json, text/plain, */*'
},
post: {'Content-Type': 'application/json;charset=utf-8'},
put: {'Content-Type': 'application/json;charset=utf-8'}
@@ -212,7 +248,6 @@ function $HttpProvider() {
*
* - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
* - `Accept: application/json, text/plain, * / *`
* - `X-Requested-With: XMLHttpRequest`
* - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
* - `Content-Type: application/json`
* - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
@@ -347,7 +382,7 @@ function $HttpProvider() {
* to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
* called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
* runs on your domain could read the cookie, your server can be assured that the XHR came from
* JavaScript running on your domain.
* JavaScript running on your domain. The header will not be set for cross-domain requests.
*
* To take advantage of this, your server needs to set a token in a JavaScript readable session
* cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
@@ -381,6 +416,8 @@ function $HttpProvider() {
* - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
* XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
* requests with credentials} for more information.
* - **responseType** - `{string}` - see {@link
* https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
*
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
* standard `then` method and two http specific methods: `success` and `error`. The `then`
@@ -473,10 +510,12 @@ function $HttpProvider() {
function $http(config) {
config.method = uppercase(config.method);
var reqTransformFn = config.transformRequest || $config.transformRequest,
respTransformFn = config.transformResponse || $config.transformResponse,
defHeaders = $config.headers,
reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
var reqTransformFn = config.transformRequest || defaults.transformRequest,
respTransformFn = config.transformResponse || defaults.transformResponse,
defHeaders = defaults.headers,
xsrfToken = isSameDomain(config.url, $browser.url()) ?
$browser.cookies()['XSRF-TOKEN'] : undefined,
reqHeaders = extend({'X-XSRF-TOKEN': xsrfToken},
defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
promise;
@@ -486,6 +525,10 @@ function $HttpProvider() {
delete reqHeaders['Content-Type'];
}
if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
config.withCredentials = defaults.withCredentials;
}
// send request
promise = sendReq(config, reqData, reqHeaders);
@@ -617,11 +660,11 @@ function $HttpProvider() {
*
* @description
* Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
* default headers as well as request and response transformations.
* default headers, withCredentials as well as request and response transformations.
*
* See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
*/
$http.defaults = $config;
$http.defaults = defaults;
return $http;
@@ -656,7 +699,7 @@ function $HttpProvider() {
* Makes the request
*
* !!! ACCESSES CLOSURE VARS:
* $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
* $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
*/
function sendReq(config, reqData, reqHeaders) {
var deferred = $q.defer(),
@@ -697,7 +740,7 @@ function $HttpProvider() {
// if we won't have the response in cache, send the request to the backend
if (!cachedResp) {
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
config.withCredentials);
config.withCredentials, config.responseType);
}
return promise;
@@ -752,10 +795,15 @@ function $HttpProvider() {
var parts = [];
forEachSorted(params, function(value, key) {
if (value == null || value == undefined) return;
if (isObject(value)) {
value = toJson(value);
}
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
if (!isArray(value)) value = [value];
forEach(value, function(v) {
if (isObject(v)) {
v = toJson(v);
}
parts.push(encodeURIComponent(key) + '=' +
encodeURIComponent(v));
});
});
return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
}
+7 -3
View File
@@ -32,7 +32,7 @@ function $HttpBackendProvider() {
function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
// TODO(vojta): fix the signature
return function(method, url, post, callback, headers, timeout, withCredentials) {
return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
@@ -65,8 +65,8 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
// always async
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
completeRequest(
callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
completeRequest(callback, status || xhr.status, xhr.response || xhr.responseText,
xhr.getAllResponseHeaders());
}
};
@@ -74,6 +74,10 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument,
xhr.withCredentials = true;
}
if (responseType) {
xhr.responseType = responseType;
}
xhr.send(post || '');
if (timeout > 0) {
+16 -10
View File
@@ -52,7 +52,7 @@ function $InterpolateProvider() {
};
this.$get = ['$parse', function($parse) {
this.$get = ['$parse', '$exceptionHandler', function($parse, $exceptionHandler) {
var startSymbolLength = startSymbol.length,
endSymbolLength = endSymbol.length;
@@ -124,18 +124,24 @@ function $InterpolateProvider() {
if (!mustHaveExpression || hasInterpolation) {
concat.length = length;
fn = function(context) {
for(var i = 0, ii = length, part; i<ii; i++) {
if (typeof (part = parts[i]) == 'function') {
part = part(context);
if (part == null || part == undefined) {
part = '';
} else if (typeof part != 'string') {
part = toJson(part);
try {
for(var i = 0, ii = length, part; i<ii; i++) {
if (typeof (part = parts[i]) == 'function') {
part = part(context);
if (part == null || part == undefined) {
part = '';
} else if (typeof part != 'string') {
part = toJson(part);
}
}
concat[i] = part;
}
concat[i] = part;
return concat.join('');
}
catch(err) {
var newErr = new Error('Error while interpolating: ' + text + '\n' + err.toString());
$exceptionHandler(newErr);
}
return concat.join('');
};
fn.exp = text;
fn.parts = parts;
+3 -2
View File
@@ -590,6 +590,7 @@ function $LocationProvider(){
var changeCounter = 0;
$rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url();
var currentReplace = $location.$$replace;
if (!changeCounter || oldUrl != $location.absUrl()) {
changeCounter++;
@@ -598,12 +599,12 @@ function $LocationProvider(){
defaultPrevented) {
$location.$$parse(oldUrl);
} else {
$browser.url($location.absUrl(), $location.$$replace);
$location.$$replace = false;
$browser.url($location.absUrl(), currentReplace);
afterLocationChange(oldUrl);
}
});
}
$location.$$replace = false;
return changeCounter;
});
+9 -1
View File
@@ -5,7 +5,15 @@ var OPERATORS = {
'true':function(){return true;},
'false':function(){return false;},
undefined:noop,
'+':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)+(isDefined(b)?b:0);},
'+':function(self, locals, a,b){
a=a(self, locals); b=b(self, locals);
if (isDefined(a)) {
if (isDefined(b)) {
return a + b;
}
return a;
}
return isDefined(b)?b:undefined;},
'-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
'*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
'/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
+1 -1
View File
@@ -42,7 +42,7 @@
* alert('Success: ' + greeting);
* }, function(reason) {
* alert('Failed: ' + reason);
* );
* });
* </pre>
*
* At first it might not be obvious why this extra complexity is worth the trouble. The payoff
+57 -34
View File
@@ -165,9 +165,9 @@ function $RootScopeProvider(){
* the scope and its child scopes to be permanently detached from the parent and thus stop
* participating in model change detection and listener notification by invoking.
*
* @param {boolean} isolate if true then the scoped does not prototypically inherit from the
* parent scope. The scope is isolated, as it can not se parent scope properties.
* When creating widgets it is useful for the widget to not accidently read parent
* @param {boolean} isolate if true then the scope does not prototypically inherit from the
* parent scope. The scope is isolated, as it can not see parent scope properties.
* When creating widgets it is useful for the widget to not accidentally read parent
* state.
*
* @returns {Object} The newly created child scope.
@@ -195,7 +195,6 @@ function $RootScopeProvider(){
child['this'] = child;
child.$$listeners = {};
child.$parent = this;
child.$$asyncQueue = [];
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
child.$$prevSibling = this.$$childTail;
if (this.$$childHead) {
@@ -221,18 +220,18 @@ function $RootScopeProvider(){
* reruns when it detects changes the `watchExpression` can execute multiple times per
* {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
* - The `listener` is called only when the value from the current `watchExpression` and the
* previous call to `watchExpression' are not equal (with the exception of the initial run
* previous call to `watchExpression` are not equal (with the exception of the initial run,
* see below). The inequality is determined according to
* {@link angular.equals} function. To save the value of the object for later comparison
* {@link angular.equals} function. To save the value of the object for later comparison, the
* {@link angular.copy} function is used. It also means that watching complex options will
* have adverse memory and performance implications.
* - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
* is achieved by rerunning the watchers until no changes are detected. The rerun iteration
* limit is 100 to prevent infinity loop deadlock.
* limit is 10 to prevent an infinite loop deadlock.
*
*
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
* you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
* can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
* detected, be prepared for multiple calls to your listener.)
*
@@ -278,7 +277,7 @@ function $RootScopeProvider(){
* - `string`: Evaluated as {@link guide/expression expression}
* - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
*
* @param {boolean=} objectEquality Compare object for equality rather then for refference.
* @param {boolean=} objectEquality Compare object for equality rather than for reference.
* @returns {function()} Returns a deregistration function for this listener.
*/
$watch: function(watchExp, listener, objectEquality) {
@@ -362,7 +361,7 @@ function $RootScopeProvider(){
$digest: function() {
var watch, value, last,
watchers,
asyncQueue,
asyncQueue = this.$$asyncQueue,
length,
dirty, ttl = TTL,
next, current, target = this,
@@ -371,18 +370,19 @@ function $RootScopeProvider(){
beginPhase('$digest');
do {
do { // "while dirty" loop
dirty = false;
current = target;
do {
asyncQueue = current.$$asyncQueue;
while(asyncQueue.length) {
try {
current.$eval(asyncQueue.shift());
} catch (e) {
$exceptionHandler(e);
}
while(asyncQueue.length) {
try {
current.$eval(asyncQueue.shift());
} catch (e) {
$exceptionHandler(e);
}
}
do { // "traverse the scopes" loop
if ((watchers = current.$$watchers)) {
// process our watches
length = watchers.length;
@@ -453,7 +453,7 @@ function $RootScopeProvider(){
* @function
*
* @description
* Remove the current scope (and all of its children) from the parent scope. Removal implies
* Removes the current scope (and all of its children) from the parent scope. Removal implies
* that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
* propagate to the current scope and its children. Removal also implies that the current
* scope is eligible for garbage collection.
@@ -476,6 +476,11 @@ function $RootScopeProvider(){
if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
// This is bogus code that works around Chrome's GC leak
// see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
this.$$childTail = null;
},
/**
@@ -486,7 +491,7 @@ function $RootScopeProvider(){
*
* @description
* Executes the `expression` on the current scope returning the result. Any exceptions in the
* expression are propagated (uncaught). This is useful when evaluating engular expressions.
* expression are propagated (uncaught). This is useful when evaluating Angular expressions.
*
* # Example
* <pre>
@@ -607,7 +612,7 @@ function $RootScopeProvider(){
* @function
*
* @description
* Listen on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
* Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
* event life cycle.
*
* @param {string} name Event name to listen on.
@@ -617,13 +622,13 @@ function $RootScopeProvider(){
* The event listener function format is: `function(event, args...)`. The `event` object
* passed into the listener has the following attributes:
*
* - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
* - `currentScope` - {Scope}: the current scope which is handling the event.
* - `name` - {string}: Name of the event.
* - `stopPropagation` - {function=}: calling `stopPropagation` function will cancel further event propagation
* (available only for events that were `$emit`-ed).
* - `preventDefault` - {function}: calling `preventDefault` sets `defaultPrevented` flag to true.
* - `defaultPrevented` - {boolean}: true if `preventDefault` was called.
* - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
* - `currentScope` - `{Scope}`: the current scope which is handling the event.
* - `name` - `{string}`: Name of the event.
* - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
* propagation (available only for events that were `$emit`-ed).
* - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
*/
$on: function(name, listener) {
var namedListeners = this.$$listeners[name];
@@ -633,7 +638,7 @@ function $RootScopeProvider(){
namedListeners.push(listener);
return function() {
arrayRemove(namedListeners, listener);
namedListeners[indexOf(namedListeners, listener)] = null;
};
},
@@ -681,6 +686,14 @@ function $RootScopeProvider(){
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
for (i=0, length=namedListeners.length; i<length; i++) {
// if listeners were deregistered, defragment the array
if (!namedListeners[i]) {
namedListeners.splice(i, 1);
i--;
length--;
continue;
}
try {
namedListeners[i].apply(null, listenerArgs);
if (stopPropagation) return event;
@@ -730,19 +743,29 @@ function $RootScopeProvider(){
},
defaultPrevented: false
},
listenerArgs = concat([event], arguments, 1);
listenerArgs = concat([event], arguments, 1),
listeners, i, length;
//down while you can, then up and next sibling or up and next sibling until back at root
do {
current = next;
event.currentScope = current;
forEach(current.$$listeners[name], function(listener) {
listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) {
// if listeners were deregistered, defragment the array
if (!listeners[i]) {
listeners.splice(i, 1);
i--;
length--;
continue;
}
try {
listener.apply(null, listenerArgs);
listeners[i].apply(null, listenerArgs);
} catch(e) {
$exceptionHandler(e);
}
});
}
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
+3 -3
View File
@@ -28,7 +28,7 @@ function $RouteProvider(){
* Object properties:
*
* - `controller` `{(string|function()=}` Controller fn that should be associated with newly
* created scope or the name of a {@link angular.Module#controller registered controller}
* created scope or the name of a {@link angular.Module#controller registered controller}
* if passed as a string.
* - `template` `{string=}` html template as a string that should be used by
* {@link ng.directive:ngView ngView} or
@@ -39,7 +39,7 @@ function $RouteProvider(){
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
* be injected into the controller. If any of these dependencies are promises, they will be
* resolved and converted to a value before the controller is instantiated and the
* `$afterRouteChange` event is fired. The map object is:
* `$routeChangeSuccess` event is fired. The map object is:
*
* - `key` `{string}`: a name of a dependency to be injected into the controller.
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
@@ -373,7 +373,7 @@ function $RouteProvider(){
forEach(next.resolve || {}, function(value, key) {
keys.push(key);
values.push(isFunction(value) ? $injector.invoke(value) : $injector.get(value));
values.push(isString(value) ? $injector.get(value) : $injector.invoke(value));
});
if (isDefined(template = next.template)) {
} else if (isDefined(template = next.templateUrl)) {
+7 -6
View File
@@ -5,6 +5,7 @@
*
* @name ng.$sniffer
* @requires $window
* @requires $document
*
* @property {boolean} history Does the browser support html5 history api ?
* @property {boolean} hashchange Does the browser support hashchange event ?
@@ -13,9 +14,10 @@
* This is very simple implementation of testing browser's features.
*/
function $SnifferProvider() {
this.$get = ['$window', function($window) {
this.$get = ['$window', '$document', function($window, $document) {
var eventSupport = {},
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]);
android = int((/android (\d+)/.exec(lowercase($window.navigator.userAgent)) || [])[1]),
document = $document[0];
return {
// Android has history.pushState, but it does not update location correctly
@@ -25,7 +27,7 @@ function $SnifferProvider() {
history: !!($window.history && $window.history.pushState && !(android < 4)),
hashchange: 'onhashchange' in $window &&
// IE8 compatible mode lies
(!$window.document.documentMode || $window.document.documentMode > 7),
(!document.documentMode || document.documentMode > 7),
hasEvent: function(event) {
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
// it. In particular the event is not fired when backspace or delete key are pressed or
@@ -33,14 +35,13 @@ function $SnifferProvider() {
if (event == 'input' && msie == 9) return false;
if (isUndefined(eventSupport[event])) {
var divElm = $window.document.createElement('div');
var divElm = document.createElement('div');
eventSupport[event] = 'on' + event in divElm;
}
return eventSupport[event];
},
// TODO(i): currently there is no way to feature detect CSP without triggering alerts
csp: false
csp: document.securityPolicy ? document.securityPolicy.isActive : false
};
}];
}
+1 -1
View File
@@ -29,7 +29,7 @@ function $TimeoutProvider() {
* @param {number=} [delay=0] Delay in milliseconds.
* @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
* @returns {*} Promise that will be resolved when the timeout is reached. The value this
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
* promise will be resolved with is the return value of the `fn` function.
*/
function timeout(fn, delay, invokeApply) {
+18 -18
View File
@@ -1587,14 +1587,20 @@ window.jstestdriver && (function(window) {
})(window);
window.jasmine && (function(window) {
(window.jasmine || window.mocha) && (function(window) {
var currentSpec = null;
beforeEach(function() {
currentSpec = this;
});
afterEach(function() {
var spec = getCurrentSpec();
var injector = spec.$injector;
var injector = currentSpec.$injector;
spec.$injector = null;
spec.$modules = null;
currentSpec.$injector = null;
currentSpec.$modules = null;
currentSpec = null;
if (injector) {
injector.get('$rootElement').unbind();
@@ -1616,13 +1622,8 @@ window.jasmine && (function(window) {
angular.callbacks.counter = 0;
});
function getCurrentSpec() {
return jasmine.getEnv().currentSpec;
}
function isSpecRunning() {
var spec = getCurrentSpec();
return spec && spec.queue.running;
return currentSpec && currentSpec.queue.running;
}
/**
@@ -1647,11 +1648,10 @@ window.jasmine && (function(window) {
return isSpecRunning() ? workFn() : workFn;
/////////////////////
function workFn() {
var spec = getCurrentSpec();
if (spec.$injector) {
if (currentSpec.$injector) {
throw Error('Injector already created, can not register a module!');
} else {
var modules = spec.$modules || (spec.$modules = []);
var modules = currentSpec.$modules || (currentSpec.$modules = []);
angular.forEach(moduleFns, function(module) {
modules.push(module);
});
@@ -1718,13 +1718,13 @@ window.jasmine && (function(window) {
return isSpecRunning() ? workFn() : workFn;
/////////////////////
function workFn() {
var spec = getCurrentSpec();
var modules = spec.$modules || [];
var modules = currentSpec.$modules || [];
modules.unshift('ngMock');
modules.unshift('ng');
var injector = spec.$injector;
var injector = currentSpec.$injector;
if (!injector) {
injector = spec.$injector = angular.injector(modules);
injector = currentSpec.$injector = angular.injector(modules);
}
for(var i = 0, ii = blockFns.length; i < ii; i++) {
try {

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