Compare commits

...

254 Commits

Author SHA1 Message Date
Chirayu Krishnappa f031127160 fix(i18n): update obsolete/404 code.google.com links 2015-04-28 00:49:37 -07:00
Martin Probst 00b44d8e12 refactor(externs): move Closure Externs back to Closure code repository
While Closure Compiler generally recommends to maintain the externs for
projects together with their source, this has not worked well for
AngularJS:
- Changes to externs must be tested; they can break clients. AngularJS
  has no testing infrastructure for this.
- Changes mostly come from users inside of Google and are much more
  easily submitted together with the code using them within Google's
  repository.

This change deletes the externs here and adds a README.closure.md to
document the change. They will be added back to Closure Compiler in a
separate submit.

Closes #5907
2014-01-22 11:39:09 -08:00
Igor Minar ca865d29a3 test(compileSpec): fix broken build on FF
FF 26.0 now throws:

"TypeError: NodeList doesn't have an indexed property setter."

when we try to assign to `childNodes[1]`, since this test still works properly
on Chrome and the issue being tested is not a cross-browser issues, I'm
just making the patchability check more robust instead of trying to figure
out how to make this test fully pass on FF.
2014-01-22 11:19:31 -08:00
Martin Probst 3ccec13aa7 feat(Angular.js): add externs file for Closure Compiler
This adds an (incomplete) externs file for use with the Closure Compiler. Users
can pass this as -extern to the compiler pass to get type checking and protect
their AngularJS use against property renaming in advanced compilation mode.
2013-10-30 14:59:33 -07:00
Daniel Lamb 43d49013d1 revert(validate-commit-msg): fix incorrect comment
Revert d5b62465f0 since it was not valid.

Closes #3952
2013-10-21 16:27:04 +01:00
Pete Bacon Darwin 116fac0562 docs(guide/controller): improve guidance and examples
Remove mention of global controller functions
Convert larger examples to runnable demos
Remove mention of pre-1.0 controllers, in particular discussion of
controller inheritance.

TODO: Probably could do with updating to explain the "controller as" syntax
at some point.

Closes: #4373
2013-10-11 12:59:39 +01:00
Felix c3024254b6 docs(guide/controller): use .controller syntax
Use the recommended `module.controller` syntax rather than global
functions to define controllers in the examples.
2013-10-11 12:58:22 +01:00
Pete Bacon Darwin 770353df19 docs($provide): improve docs and examples further
Improve the "tracking" service example by adding a configuration option.
Get better formatting of the generated code samples using <pre> tags.
Move the detailed explanations into each function's documentation block.
Improve the overview and list the constituent functions by significance.

Closes #4302
2013-10-10 18:22:52 +01:00
Tim Ruffles 85b7d24357 docs($provide): improve examples and explanations
$provide's example seems awkward. Replace with more real-world example,
using an injected service, where the service defined has a good reason to
be a singleton.

There's quite a lot of confusion around $provide:
http://stackoverflow.com/search?q=angularjs+service+vs+factory
Tests for example at: http://jsbin.com/EMabAv/1/edit?js,output
2013-10-10 18:22:51 +01:00
Marko Bonaci 8469779a8e docs(tutorial/step11): correct Jasmine Matcher link
Link http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html
is no longer valid.

Closes #4329
2013-10-09 11:30:47 +01:00
Brian Ford 3374e35953 docs(ngValue): add docs for ngValue directive
Closes #4267
2013-10-07 14:42:54 +01:00
Dave Peticolas 90ff8a98d8 docs(ngModel): fix grammar and improve clarity
Closes #4291

Conflicts:
	src/ng/directive/input.js
2013-10-07 14:41:08 +01:00
Joe Hanink a4dc21ebf5 docs(angular.bind): clarify that bind is partial application
The `angular.bind` function reflects the definition of "partial application", which
reduces a function's arity rather than transforming a function with n args into a
chain of n functions, each having a single arg.

curry : f(x,y,z) -> f(x)(y)(z)
partial application : f(x,y,z) -> f(x)(y,z)

Closes #4239
2013-10-03 23:46:24 +01:00
mtaran-google ec93f94cc9 docs(guide/directive): fix indentation in example code
Closes #4241
2013-10-03 23:45:36 +01:00
gdennie 7665497a53 docs(guide/directive): clarify use of binding to scopes
The use of 'angular' as sample text is confusing to the newbie in that they are forced
to confirm that the text 'angular' is not a keyword or otherwise referring to a system
component. This is changed to a more obvious sample text.

The most common form of `ngBind` is moved to the top of the list.

Closes #4237
2013-10-03 23:44:54 +01:00
Pete Bacon Darwin 2acadc4216 docs(rootScope): improve grammar and clarity 2013-10-03 23:18:45 +01:00
paolo-delmundo c7658d9457 fix($sanitize): sanitize DOCTYPE declarations correctly
HTML to be sanitized that contains a DOCTYPE declaration were causing
the HTML parser to throw an error.  Now the parser correctly removes
the declarations when sanitizing HTML.

Closes #3931
2013-10-03 08:43:06 +01:00
Uri Goldshtein b92c650e05 docs(angular.copy): add an example with the two possible arguments
Closes #4179
2013-09-30 22:16:30 +01:00
Richard Sentino f7a0f9d841 docs(tutorial/step0): fix minor typo
Closes #4154
2013-09-30 21:42:37 +01:00
Uri Goldshtein b17d40b4a5 docs($timeout): add a $timeout example
The original example is by gxlcl.

Closes #4180
2013-09-28 15:26:36 +01:00
Thomas Tuts d745df7e5f docs(guide/overview): fix typo
Closes #4188
2013-09-28 15:05:43 +01:00
joscarsson 53b444419c docs(guide/e2e-testing): select also uses ng-model (like input)
This is specified for input fields, but not for selects. This change specifies it also for select().
2013-09-27 16:24:17 -07:00
David Bennett 9a21050b43 docs(angular.Module): fix controller and directive method parameters 2013-09-27 16:11:42 -07:00
Dave Peticolas 8473b9d558 docs(ngCsp): fix grammar 2013-09-27 13:14:23 -07:00
Dave Peticolas 679d418a50 docs(dblClick): fix grammar 2013-09-27 13:07:01 -07:00
Dave Peticolas 16d247b386 docs(ngDisabled): clarify 2013-09-27 13:06:13 -07:00
Misha Moroshko 4767d34ae8 docs(docs.css): prevent <code> elements from wrapping
Closes #4114
2013-09-25 22:39:37 +01:00
Dave Peticolas 5efc2ed5ac docs(ngHref): fix formatting and clarify
Closes #4106
2013-09-25 22:33:13 +01:00
lorint f9bf194439 docs(jqLite): fix typo
Closes #4105
2013-09-25 22:31:19 +01:00
gdennie 3c4460b513 docs(guide/$location): provide a title for section about replace()
Closes #4104
2013-09-25 22:30:10 +01:00
gdennie a98931de0e docs(guide/$location): clarify $location service role
Clean up confusing use of the term URL to refer to $location as well as 'URL in the browser'.

Closes #4103
2013-09-25 22:27:43 +01:00
Mr.Raindrop 7e5154e755 docs($http): fix adding default header to get request example
Initially, `$httpProvider.defaults.headers.get` is `undefined`, so
`$httpProvider.defaults.headers.get['My-Header']='value'` will throw an
error.

Closes #4101
2013-09-25 22:27:33 +01:00
janhartigan ec6b1cfaba docs(guide/e2e-testing): Fix typo
Closes #4100
2013-09-25 22:27:06 +01:00
Pete Bacon Darwin 8d8801f1ae fix(ngScenario): fix error message description 2013-09-25 12:43:03 +01:00
Boris Serdyuk 301647bf1b refactor(angular.toJson): use charAt instead of regexp
Provides a performance improvement when serializing to JSON strings.

Closes #4093
2013-09-23 11:16:33 +01:00
Pete Bacon Darwin 1c03a1b9c0 docs(ngModelController): clarify issue with isolated scope directive
See #4043
2013-09-19 21:09:20 +01:00
ts-web fd797cdb7e docs(input): fix spelling error and reword for clarity 2013-09-19 21:09:20 +01:00
Dave Peticolas ed1dbf2554 doc(ngApp): fix grammar 2013-09-19 20:17:49 +01:00
Jared Forsyth 022cb3dc4e docs($exceptionHandler): add an example of overriding the handler
Closes #3816
2013-09-19 14:51:50 +01:00
Maarten Stolte 4f107acfcf docs(guide/i18n): change non-existent de-ge to de-de
The de-ge locale does not exist

Closes #4053
2013-09-19 11:27:20 +01:00
Dave Peticolas f363bcb437 docs(ngForm): fix grammar and improve explanation
Closes #4050
2013-09-19 10:41:30 +01:00
Ash 7b2259f32c docs(guide/$location): describe workaround for collocated apps
When using Angular in the root of a domain with HTML5 URLs
where there are links to external paths within the same directory,
the `otherwise` route handler will catch these external files.
This can be fixed by prefixing '.' onto the links to URLs that should
be handled by angular routing.

Original Issue: #3520
Example of Fix: http://fiddle.jshell.net/fgHf6/3/

Closes #3555
2013-09-18 14:34:39 +01:00
Zachary Friedman 9e88fa18b9 docs(tutorial/step_03): add info about karma-ng-scenario plug-in
The existing documentation for this step could have people find themselves
unable to run the `e2e-test.sh` script. This note added regarding
`karma-ng-scenario` will minimize their confusion and allow people to run
the script.

Closes #4033
2013-09-18 12:45:05 +01:00
Hubert SABLONNIÈRE 094580c3da fix(scenario): include "not " in error messages if test is inverted
Closes #3840
2013-09-18 12:34:25 +01:00
James cc4d08c5f0 docs(input): clarify that contenteditable is an HTML5 attribute
Closes #3841
2013-09-17 11:44:04 +01:00
Jesse Palmer d0ae241afd docs(orderBy): fix typo in orderBy.js documentation
Closes #3838
2013-09-16 22:29:25 +01:00
Dave Peticolas e1f103a8e4 doc(api): fix grammar in a directive description
- Add missing words.
- Simplify text.
2013-09-16 16:36:19 +01:00
Dave Peticolas d17aa84be1 docs(api): fix grammar in ngClick description
- Add missing word 'directive'.
- Add missing word 'an'.
2013-09-16 16:33:51 +01:00
Ben Tesser e87c88914f docs($browser): add jsdoc tags and fix typo 2013-09-13 21:37:51 +01:00
Dean Sofer b5d48ee1f0 docs(ngController): rephrased the description for clarity 2013-09-13 14:27:26 +01:00
Pete Bacon Darwin 1c010b33aa docs($http): add examples when calling $http outside $apply
Closes #3996
2013-09-13 14:20:14 +01:00
Dang Nguyen Anh Khoa 16c7ab1ba0 docs($http): explain why $http may not make the request immediately
I came across this issue today and after researching has found out this thread on so:
http://stackoverflow.com/questions/17039998/angular-not-making-http-requests-immediately.

It took me quite sometimes to figure out this so I hope the addition in documentation could save somebody else some times and frustration.
2013-09-13 14:20:14 +01:00
Gowtam Lal 9ef5d8f318 fix(ngOptions): ignore object properties which start with $ 2013-09-13 13:22:36 +01:00
brakon 6a634e309b docs(guide/e2e_testing): clarify that .enter searches by ng-model 2013-09-13 12:34:40 +01:00
Woody Peterson 13f58447e2 test($browser): correct false positive in ApplicationSpec.js
Previously, the check that Application should return a new $window and
$document had the arguments reversed in the first call to navigateTo;
thus, the subsequent check of inequality of $window and $document in the
next navigateTo call would always pass.

This corrects the argument order, which makes this test not succeptible
to false positives.
2013-09-11 22:21:12 +01:00
cjmling bc72211e7b docs(tutorial/step-10): fix incorrect link to step-8 tests
Closes #3972
2013-09-11 20:50:26 +01:00
Paxton Hare 230e124ddb docs(ngModel): provide link for best practices.
Closes #3973
2013-09-11 20:42:15 +01:00
Randi Hillerøe 10016ab3fd docs(guide/concepts): remove div-clear-tags that break the formatting
Closes #3974
2013-09-11 20:37:44 +01:00
Butch Peters 69dc003a0b docs(Attributes): add missing documentation for $observe method
- Add proper ngdoc annotations to existing $observe documentation
- Add link to directive guide for usage example of $observe
- Add note about $observe function parameter signature

Closes #3957
2013-09-11 12:11:57 +01:00
naorye ae2fd55575 docs($q): clarify what happens when rejected
Closes #3943
2013-09-10 22:09:01 +01:00
jakub-bochenski f102fb75b6 docs(angular.copy): clarify corner cases
The behaviour when null or undefined was passed was not clear.
The exception thrown when source == destination was not documented.

Closes #3946
2013-09-10 22:07:22 +01:00
Anthony Tran 8a7240ddfd docs(forms.ngdoc): fix spacing in example
Closes #3930
2013-09-09 17:31:45 +01:00
Richard ac70ec0340 docs(README): add dashboard link
Closes #3934
2013-09-09 12:26:41 +01:00
Pete Bacon Darwin dbd90a4d78 docs(mock.inject): fix typo 2013-09-09 08:44:25 +01:00
JasonM23 5b1f9b3c2b docs(mock.inject): document underscore wrapping syntax
Add a summary describing the ignored underscore syntax sugar helper,
with a simple use case example.

Closes #3621
2013-09-05 14:35:25 +01:00
Alexander Kaidalov 08a07f2d30 docs(tutorial): fix markup for tutorial_03.png diagram
Closes #3707
2013-09-05 14:11:52 +01:00
Alexander Kaidalov b1143c9481 docs(tutorial): fix markup for tutorial_04.png diagram 2013-09-05 14:08:58 +01:00
Pete Bacon Darwin 73e1d0054c docs(tutorial): clarify use of inject() in step 9
Closes #3718
2013-09-05 13:58:34 +01:00
Pete Bacon Darwin 33ab261817 docs(booleanAttrs): improve parameter docs for boolean attributes 2013-09-05 13:29:21 +01:00
Nick Donohue 230ff0576a docs(css_styling_guide): add ng-scope and ng-binding classes
I noticed angular was adding these css classes to elements and believe they
should be listed in the documentation at this page. The ng-scope class is
mentioned in the developer guide, hence the link there, and the ng-binding
class is not mentioned anywhere else in the documentation or the guide that
I found.

Closes #3728
2013-09-05 13:07:10 +01:00
Pete Bacon Darwin e3371d7c53 docs(angular.bootstrap): clarify modules parameter
It was not clear what you could pass to specify modules to load in the
`module` parameter of this function. The `modules` parameter takes an
array.

The main case is to provide a String, which is the name of a "predefined"
angular module.
The side cases are to provide a Function (or an annotated function in the
form of an Array), which will be invoked by the injector as a run block.

It is not possible to "define" new modules via this parameter.

Closes #3692
2013-09-05 12:19:18 +01:00
Calvin Fernandez 9b2b93d9bd docs(bootstrap.ngdoc): clarify bootstrap example
Clear up confusion about module declaration when using manual bootstrap.
2013-09-05 10:24:22 +01:00
Pete Bacon Darwin d7fb721b4d docs(): parameter for html5Mode is boolean 2013-09-05 10:02:07 +01:00
Ben Lesh e7cfa5c2bf docs($anchorScroll): provide an example of basic usage.
Per a request made by Peter Bacon Darwin here:  http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html?showComment=1370941217879#c8718313084813008967
2013-09-05 08:34:35 +01:00
jankuca 2a3212a0a3 fix($http): allow empty responses to be cached
Closes #3809
2013-09-02 11:48:14 +02:00
Igor Minar 7a08a76875 chore(build): add jenkins_build.sh file
cherry-pick from the master branch with the promises-aplus tests
removed.
2013-08-30 23:36:17 +02:00
Brian Ford 22a09dddc6 chore: upgrade grunt packages to match master 2013-08-28 14:59:26 -07:00
phanboy4 8c72549cc2 docs(guide): update description of $inject mechanism to be a little clearer 2013-08-28 13:43:28 -07:00
Brian Ford bba5214930 docs(overview): improve grammar 2013-08-22 17:40:50 -07:00
Igor Minar fb194b9488 chore(release): start new 1.0.9 iteration
Marc is working on the code name :-)
2013-08-22 11:23:17 -07:00
Igor Minar 56817e9faa chore(release): cut the 1.0.8 bubble-burst release 2013-08-22 11:20:23 -07:00
Igor Minar e87fb8a8e1 chore(grunt): ensure that grunt uses zip for compression 2013-08-22 11:19:53 -07:00
Igor Minar 5be0fc40ed docs(changelog): release notes for 1.0.8 bubble-burst 2013-08-22 11:07:45 -07:00
Igor Minar a98337b359 docs(CHANGELOG): update changelog 2013-08-22 11:07:41 -07:00
Igor Minar 143d016899 docs(CHANGELOG): release notes for 1.2.0-rc1 spooky-giraffe 2013-08-22 11:07:36 -07:00
ghodss 3d70e55d72 docs(guide): warn about module creation versus retrieval
Updated Module documentation to include the suggestion of the top-rated comment: "This documentation should warn that "angular.module('myModule', [])" always creates a new module, but "angular.module('myModule')" always retrieves an existing reference."
2013-08-22 10:59:29 -07:00
Igor Minar dbcc44dc80 revert: feat(ngForm): Supports expression in form names
This reverts commit 4407e81c61.

No features or breaking changes in the stable branch please.
2013-08-22 10:22:17 -07:00
Igor Minar db87fd52ca chore(changelog.js): pickup breaking changes f/ chore/refactor commits 2013-08-22 10:07:41 -07:00
Marcel Morgan 792509e987 docs(guide): grammatical corrections to Form and Control definitions 2013-08-22 09:15:50 -07:00
Igor Minar 166e0d63d0 revert: fix($compile): correct controller instantiation...
fix($compile): correct controller for async directives

This reverts commit 51d32243fe
as well as commit   9c51d50318

Changing ordering of events in stable branch is not a good idea.
2013-08-21 01:27:58 -07:00
Igor Minar 0d7f19bb62 revert: fix($compile): always instantiate controllers...
fix($compile): always instantiate controllers in parent->child order

This reverts commit 683fd713c4.

It turns out that there is some existing code that relies on the
incorrect timing. Rather than breaking these apps that depend on
stable releases, we are going to keep this changeo only in master
and the apps will need to migrate to the correc timing during the
1.2 upgrade.
2013-08-21 01:21:02 -07:00
Michał Gołębiowski 607045d592 fix(package.json): add a repository field
The `npm install` command complains about the missing repository field.

Closes #3674
2013-08-20 23:56:38 -07:00
Chirayu Krishnappa 51d32243fe fix($compile): correct controller instantiation for async directives
This fixes regression introduced by #3514 (9c51d503) - this commit is being
reverted here and a better fix is included.

The regression caused the controller to be instantiated before the isolate scope
was initialized.

Closes #3493
Closes #3482
Closes #3537
Closes #3540
2013-08-20 18:51:07 -07:00
Reto Aebersold 1c1a1bc9ed style(docs): replace CRLF by LF in svg header logo 2013-08-16 20:06:35 -07:00
Brian Ford 553fdb318f fix(grunt): fix regex in grunt util to handle pre-release versions
NOTE: this also includes a temporary work-around for Bower
2013-08-15 12:43:05 -07:00
Rob Dodson 607ed4ee46 docs($cookies): add info about angular-cookies.js
per the [top comment here](http://docs.angularjs.org/api/ngCookies.$cookies#comment-912064775)

updating documentation so it matches [$resource](http://docs.angularjs.org/api/ngResource.$resource)
and instructs the user to include the `angular-cookies.js` and load `ngCookies`.

Closes #3607
2013-08-15 10:25:00 -07:00
ItsLeeOwen ec1cece270 fix(orderBy): remove redundant if statement
Removed unnecessary additional conditional statement.
2013-08-14 17:01:58 -07:00
Vojta Jina 4656e386fb chore: fix Travis build
Specify hostname/port for connect server to avoid
https://github.com/joyent/libuv/issues/826

Conflicts:
	Gruntfile.js
2013-08-14 16:12:37 -07:00
Vojta Jina f29f2f99b1 chore: disable npm install on Travis
Grunt is configured to run `npm install` before every task. That is convenient when switching a branch for example.

On Travis, this makes no sense and is causing tons of NPM warnings (eg. packages not defining repository field etc).
2013-08-14 16:12:37 -07:00
Vojta Jina cc27f08588 chore: update Node.js on Travis 2013-08-14 16:12:37 -07:00
Vojta Jina 99fe398b59 chore: update Karma to v0.10 2013-08-14 16:12:36 -07:00
Vojta Jina cb89e02432 chore(sauce): use tunnel-identifier and ready-file only on Travis
When running locally, there's not TRAVIS_JOB_NUMBER env variable defined and it screws
the Sauce Connect (it uses a tunnel with empty name), this makes it work locally without defining
TRAVIS_JOB_NUMBER env variable.

Also, if you run the sauce_connect_setup.sh locally, without having SAUCE_CONNECT_READY_FILE, it
does not pass the `--ready-file` argument to avoid Sauce Connect blowing up.
2013-08-14 16:12:36 -07:00
Andy Gurden ac69392cd7 fix($timeout): clean deferreds immediately after callback exec/cancel
Make sure $timeout callbacks are forgotten about immediately after
execution or cancellation.

Previously when passing invokeApply=false, the cleanup used $q and so
would be pending until the next $digest was triggered. This does not
make a large functional difference, but can be very visible when
looking at memory consumption of an app or debugging around the
$$asyncQueue - these callbacks can have a big retaining tree.
2013-08-14 16:04:48 -07:00
Vojta Jina a5fb372e1e fix(mocks.$timeout): forward delay argument
The $timeout decorator was not forwarding the delay argument to `browser.defer.flush(delay)`.
2013-08-14 16:04:48 -07:00
ebeal da720712f3 fix(tutorial): fix broken link caused by bad line break 2013-08-14 15:46:48 -07:00
Mikk Kirstein 0cb3dc8782 docs($http): added return to interceptors success callback 2013-08-14 14:19:10 -07:00
Igor Minar dfd95f0115 revert: docs($interpolate): add example for the provider
This reverts commit 1a01e80b9c.

This example is bogus, breaks docs.angularjs.org and karma e2e tests
2013-08-14 14:08:18 -07:00
David Bennett 7636670a77 docs(input): add missing ngChange directive for email type
All other input types already have it.
2013-08-13 10:17:44 -07:00
Siddique Hameed fe6247a7f8 docs(guide/unit-testing): add expression example
* Improved developer guide, directive unit testing documentation code with scope expression
* Removed documentation block with nothing on it
2013-08-12 16:23:39 -07:00
Vojta Jina 2b90ef1694 test(matchers): update toThrow matcher 2013-08-12 16:23:39 -07:00
Chirayu Krishnappa 099138fb9a fix($parse): move global getter out of parse.js 2013-08-12 16:23:39 -07:00
Igor Minar cbe31d8dfd fix($location): default to / for the url base if no base[href]
With the recent refactoring of $location service we changed this behavior
resulting in a regression.

Previously we thought that html5 mode always required base[href]
to be set in order for urls to resolve properly. It turns out that
base[href] is problematic because it makes anchor urls (#foo) to
always resolve to the base url, which is almost always incorrect
and results in all anchors links and other anchor urls (e.g. svg
references) to be broken.

For this reason, we should now start recommending that people just
deploy to root context (/) and not set the base[href] when using
the html5 mode (push/pop history state).

If it's impossible to deploy to the root context then either all
urls in the app must be absolute or base[href] must be set with the
caveat that anchor urls in such app won't work.

Closes #2762
2013-08-12 16:23:38 -07:00
Vineet Kumar 06b0930b6a fix(ngCloak): hide element even when CSS 'display' is set
Previously an element like
<div class="foo ng-cloak">...</div>
would still be annoyingly visible if it matched a CSS rule like
.foo { display: inline-block; }, overriding ng-cloak's display: none.
2013-08-12 16:23:38 -07:00
Sebastian Müller 7b7be341b6 refactor(core): use native String.prototype.trim if available 2013-08-12 16:23:38 -07:00
Lucas Galfasó 751c77f87b fix(i18n): Do not transform arrays into objects
Do not trasnform arrays into objects when generating the locale objects
Add unit test for this check
2013-08-12 16:23:38 -07:00
Ben Holley 634ac03c5e style(sanitize): fix typo in variable names 2013-08-12 16:23:38 -07:00
Vojta Jina 8cab53c64d chore(package.json): fix name to work with latest NPM 2013-08-12 16:23:38 -07:00
Igor Minar edef295b11 fix(grunt): cache version number
caching the version number speeds up the build and preserves resources.

this also fixed EMFILE error that now occurs on some macs.
2013-08-12 16:23:38 -07:00
Jeff Cross 64e447354e fix(dump): Prevented window.dump from being overridden by karma-jasmine.
In commit 6820322db562382fac903be35831275948825317 of Karma-Jasmine, the
dependency on angular.dump was removed. This caused two undesirable side
effects in the angular.js project. 1) Tests for presence of mock dump were failing,
and 2) the default window.dump was not outputting valuable angular-aware info. This
simple fix adds window.dump in testabilityPatch, to preprocess dumped input prior
to passing it to the global dump method.
2013-08-12 16:23:38 -07:00
Brenton da1f7c762d fix(equals): {} and [] should not be considered equivalent
angular.equals was returning inconsistent values for the comparison between
{} and []:

    angular.equals({}, []) // true
    angular.equals([], {}]) // false

Since these object are not of the same type, they should not be considered
equivalent.
2013-08-12 16:23:38 -07:00
Roland 89366bdbf9 docs(guide): remove superfluous }); 2013-08-12 16:23:37 -07:00
Igor Minar 78efa0e36c fix($compile): don't check attr.specified on non-ie7
the specified attribute is depricated and creates warnings in Firefox

Closes #3231
Closes #2160
2013-08-12 16:23:37 -07:00
Matias Niemelä 3a8b3db174 chore(.gitignore): ignore npm-debug.log file 2013-08-12 16:23:37 -07:00
Emmanuel 1a01e80b9c docs($interpolate): add example for the provider 2013-08-12 16:23:37 -07:00
Pete Bacon Darwin d59027c40e fix($q): call reject() even if $exceptionHandler rethrows
Normally $exceptionHandler doesn't throw an exception.  It is normally
used just for logging and so on.  But if an application developer
implemented a version that did throw an exception then $q would never
have called reject() when converting an exception thrown inside a `then`
handler into a rejected promise.
2013-08-12 16:23:37 -07:00
jankuca c197c2aa27 chore(bower): add a .bowerrc file 2013-08-12 16:23:37 -07:00
Eric Hagman 01cd34957e fix(jqLite): return array from multi select in val() 2013-08-12 12:00:47 -07:00
OpherV 864517e5a2 docs($compile): update directive type signature
To avoid "Argument type Array is not assignable to parameter type function" validation error  When using the minifcation-safe array style

(eg .directive('myDirective', ['$http','$timeout','$compile', function($http,$timeout $compile).... )

Closes #3392
2013-08-09 10:34:26 -07:00
Niall Smart 1dd5d2ec1f docs(ngModel): validators should return undefined for invalid values.
Closes #3525
2013-08-09 10:24:48 -07:00
Santi Albo 6da835f4bc docs(httpBackend): update documentation for expect methods
`expect` methods can receive an Object as the data parameter, which was
undocumented.
2013-08-09 10:10:45 -07:00
Andy Hitchman 5cca077e4a fix(angular.copy): change angular.copy to correcly clone RegExp
angular.copy previously copied RegExp as an empty object. Change detects
RegExp instance and clones into new RegExp. This change is based on a previous
fix to allow Date to be copied.

Closes #3473
Closes #3474
2013-08-09 00:17:34 -07:00
Igor Minar e290aa8c13 docs(ngModel): clarify docs for NgModelController#
Closes #3498
2013-08-08 23:08:08 -07:00
jankuca 9c51d50318 fix($compile): always instantiate controllers before pre-link fns run
Controllers should be always instantiated after compile fn runs, but before
pre-link fn runs. This way, controllers are available to pre-link fns that
request them.

Previously this was broken for async directives (directives with templateUrl).

Closes #3493
Closes #3482
Closes #3514
2013-08-08 22:58:51 -07:00
Matias Niemelä 1c3a46adda chore(ngdoc): wrap all pages inside of a container tag for easy styling 2013-08-07 22:11:45 +01:00
Matthew Windwer 4407e81c61 feat(ngForm): Supports expression in form names
<form name="ctrl.form"> form controller will accessible
as $scope.ctrl.form instead of $scope['ctrl.form']

BREAKING CHANGE:
If you have form names that will evaluate as an expression:

<form name="ctrl.form">

And if you are accessing the form from your controller:

  Before:

  function($scope) {
    $scope['ctrl.form'] // form controller instance
  }

  After:

  function($scope) {
    $scope.ctrl.form // form controller instance
  }

This makes it possible to access a form from a controller
using the new "controller as" syntax. Supporting the previous
behavior offers no benefit.
2013-08-07 13:59:41 -07:00
neilmcgibbon ad76e77fce fix(input): fix the email regex to accept TLDs up to 6 characters long
The input field email regex does't not match long domain extensions. This commit extends the email regexp to take a 6 character TLD.

Example 6-character TLDs include .museum and .travel - (e.g. allabout.travel).
2013-08-07 14:18:22 -04:00
Pawel Kozlowski ac5b9055f6 fix(jqLite): forgive unregistration of a non-registered handler 2013-08-07 19:09:04 +02:00
Michael Stewart c18074a310 docs(compile): fix minor spelling mistake
Closes: #3468
2013-08-06 16:31:11 +01:00
Mark Campbell ed703d8e2c docs(guide/controller): fix wording in list of 'Do not use'
Wording has been changed in two of the examples to read naturally.
For example:

From: 'Do not use controllers for to run stateless or stateful code
shared across controllers'

To: 'Do not use controllers for sharing stateless or stateful code
across controllers'

Closes #3454
2013-08-03 22:06:03 +01:00
Igor Minar 9c53d0769e revert: fix(location): fix parameter handling on search()
This reverts commit 90532f5e3c.

The commit contains references to minErr that are not available
in the stable branch.
2013-08-01 09:34:56 -07:00
Misko Hevery 90532f5e3c fix(location): fix parameter handling on search() 2013-07-31 17:10:10 -07:00
Brenton 2bc04d23fb docs(header): replace logo.png with logo.svg
The current logo looks awful on high-density displays.  SVG is a
better choice because it can scale to any resolution without
increasing file size.

Amending #2775 to add support for IE 8 by falling back to existing PNG
with img.onerror

Using relative URLs as directed by @btford and @petebacondarwin.

(commit by Brenton Simpson - @appsforartists)

Closes #2874

Conflicts:

	docs/src/templates/css/docs.css
	docs/src/templates/index.html
2013-07-31 12:06:04 -07:00
Roland 7f6da764e1 docs(tutorial): mention the controller along the scope 2013-07-27 17:14:30 +01:00
Roland 6926ef8f67 docs(tutorial): add formatting
the string literal {{query}} was missing as it was not enclosed into ``
2013-07-27 16:07:51 +01:00
Roland bba2b7cfce docs(tutorial): add that the test also creates a controller 2013-07-27 15:53:35 +01:00
Pawel Kozlowski dc1e55ce1a fix(form): pick the right attribute name for ngForm
Closes #2997
2013-07-24 14:41:54 -07:00
Paul Meskers 408e868237 fix(numberFilter): always convert scientific notation to decimal
Previously, the number filter would format small and large numbers
as scientific notation. It now uses toFixed() to ensure that all
requested digits are shown.
2013-07-24 12:06:19 -07:00
Pavel Vasek 97abb12473 fix($location): prevent infinite digest error due to IE bug
If an app uses HTML5 mode and we open an html5 url on IE8 or 9 which
don't support location href, we use location.replace to reload the page
with the hashbang equivalent of the url but this fails with infinite
digest. This is because location.replace doesn't update location.href
synchronously on IE8 and 9.

Closes #2802, #3305, #1417
2013-07-24 10:38:29 -07:00
Braden Shepherdson d26bffbc3f docs(bootstrap): Note that ngScenario requires ngApp
ngScenario expects an ngApp directive to be used, and doesn't work for
manually bootstrapped apps. The failure mode is to hang on navigation.

Trying to make this wont-fix bug less obscure by documenting it.
Eventually Protractor will replace ngScenario and fix this.
2013-07-23 20:35:03 +01:00
Spencer 2f3bd9dae7 docs(cacheFactory): correct typos 2013-07-23 20:16:58 +01:00
Richard John 256e5dff55 docs(index): add seed app link to menu item 2013-07-23 20:11:03 +01:00
Igor Minar acb6b75fe9 chore(dump): remove dead code
This code is not being used any more and the test is now failing
due to Karma changes. Karma used to expose window.dump but that
changed recently and that's why our build is now failing.

I'm removing the code and test, but we still need to figure out
how to route window.dump through angular.mock.dump, but that will
have to be a separate commit.
2013-07-22 14:01:38 -07:00
Igor Minar 683fd713c4 fix($compile): always instantiate controllers in parent->child order
Previously it was possible to get into a situation where child controller
was being instantiated before parent which resulted in an error.

Closes #2738
2013-07-22 11:32:50 -07:00
Jérémy 3591ae0103 docs(input): fix example
The input [number] error spans did not show on the example, as they were
relying on an non-existing property (myForm.list.$error) vs the working
property (myForm.input.$error)
2013-07-21 21:24:53 +02:00
Vineet Kumar 5fedfd79a5 docs(ngController): remove obsolete mention of scope as this in controller
Controllers are now (since angular 1.0) instantiated as regular constructorsand the scope
is injectable as $scope rather than being referenced as `this` in controller methods.
2013-07-21 20:30:40 +02:00
David Sanders bdde40e755 docs($window): improve style and clarify wording 2013-07-21 20:24:49 +02:00
Pete Bacon Darwin 88c4963328 docs(jqLite): document "$destroy" event 2013-07-18 19:53:13 +01:00
Matias Niemelä 67a81eff42 chore(ngdocs): fix improve button overlap 2013-07-18 18:56:08 +01:00
Spencer add43e91dc docs($templateCache): add examples of usage 2013-07-17 16:41:09 +01:00
Bruno Coelho b3c7a6d566 docs(dateFilter): fix typos
Fix closing parenthesis, quotes around string literal and remove
trailing whitespace.

Closes #3250
2013-07-17 11:28:01 +01:00
James deBoer 424bd49ede test(utils): Adds a missing test for snake_case 2013-07-16 11:18:11 -07:00
Matias Niemelä 6a58404507 chore(gitignore): add libpeerconnection.log
Google chrome (when tested using karma) spits out a log file called libpeerconnection.log
2013-07-15 09:28:54 -07:00
Matias Niemelä d4ce8362b1 chore(ngdocs): remove autofocus for the filtering search 2013-07-15 14:57:47 +01:00
sdesmond caa12dbc57 docs(di): promote registering controllers on modules 2013-07-14 16:23:04 +02:00
David 1122b3c14d style(ngMock): add missing whitespace 2013-07-14 16:06:38 +02:00
Ben Ripkens a357649da5 fix(angular.equals): add support for regular expressions
Regular expression objects didn't used to be considered to be equal when using
'angular.equals'. Dirty checking therefore failed to recognize a
property modification.

Closes #2685

Conflicts:

	test/AngularSpec.js
2013-07-13 22:35:17 -07:00
Greg Thornton 332a3c7984 feat(Angular.js): skip JSON.stringify for undefined
Return early in `angular.toJson` if the object to be stringified is `undefined`.
IE8 stringifies `undefined` to `'undefined'` whereas other browsers return
`undefined`. This normalizes behavior and passes currently broken unit tests
in IE8.
2013-07-12 20:49:50 +02:00
Pete Bacon Darwin fcd761b9d7 fix(sanitize): match URI schemes case-insensitively
According to RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
schemes such as http or mailto are case-insensitive. So links such as
http://server/ and HTTP://server/ are valid and equivalent.

Closes #3210
2013-07-12 09:32:23 +01:00
Wesley Cho b0d5f062e3 fix(ngSubmit): expose $event to ngSubmit callback 2013-07-11 17:27:36 -07:00
Brian Ford 2c0753225a revert: feat(ngDocs): add links to source for API
This reverts commit 61fb5863df.
2013-07-11 15:32:33 -07:00
Mikk Kirstein 3b898664ee fix(ngValue): made ngValue to write value attribute to element 2013-07-11 14:59:38 -07:00
Julien Bouquillon 61fb5863df feat(ngDocs): add links to source for API
- add tests
 - the link points to the gruntUtil.getVersion().number tree on github
2013-07-11 14:40:06 -07:00
Paulo Scardine a4ec297925 fix(scope): watches can be safely unregistered inside watch handlers
Closes #2915
2013-07-11 22:07:15 +01:00
Brian Ford 93d7e60d43 chore(build): add check for merge conflicts, ddescribe, and iit 2013-07-11 11:59:38 -07:00
Igor Minar 338264b5f6 test(ngPattern): fix disabled test 2013-07-11 11:58:47 -07:00
Igor Minar 19b51caa2c test(ngList): remove disabled test
this test fails and we don't have intentions on making it pass since
we never made a commitment to implement this feature.
2013-07-11 11:12:17 -07:00
Igor Minar 8c08b4373c docs(ngList): fix example and add e2e test 2013-07-11 09:23:18 -07:00
Igor Minar 0b38882a91 style(input): remove ws 2013-07-11 09:23:18 -07:00
sdesmond 3364d69a3b docs(guide): clarify example 2013-07-10 22:58:43 +02:00
sdesmond e6c9bfa4a9 docs(guide): example filter does not conditionally assign a color 2013-07-10 22:55:03 +02:00
Robert Fauver 7a3e182e9c docs(guide/di): fix typo 2013-07-10 22:30:53 +02:00
Tay Ray Chuan 2471f6b01c docs(contribute): improve git instructions 2013-07-10 22:23:12 +02:00
Lefteris Paraskevas 1fefafd09f docs(overview): fix typo
Removed repeated "the" in the sentence: The input invalidates itself by turning red when you enter invalid data or leave "the" the input fields blank (Line 137).
2013-07-10 22:12:27 +02:00
Mark Striemer 8a63dc3151 docs(ngMock): correct verifyNoOutstandingExpectation example 2013-07-10 20:32:53 +02:00
Marco Vito Moscaritolo 403008816c docs(angular.identity): fix missing 'angular' in identity function 2013-07-09 14:32:59 +01:00
Pete Bacon Darwin 62d552ffe2 docs(ngModelController): provide a more intuitive example
The example directive, using contenteditable was not showing required
even if you cleared the content from it.

Closes #3156
2013-07-08 14:53:15 +01:00
Pete Bacon Darwin bcaa4217bc docs(numberFilter): fix explanation of default fraction size
The default fraction size for the number filter is actually computed
from the `NUMBER_FORMATS.PATTERNS.maxFrac` value in the current locale.

Closes #3157
2013-07-08 11:23:37 +01:00
tgkokk 0823f6dfab docs(guide/e2e-testing): fix typos 2013-07-07 20:32:06 +01:00
basarat 87bb554aec docs(input): ng-model doesn't work well with isolated scope directive
Closes #3123
2013-07-04 00:35:52 +01:00
Andrew O'Brien 36447cb2b5 docs(guide/directive): make directive controller minification-safe
It is best to emphasize that the "controller" property needs to be min safe

Closes #3125
2013-07-04 00:29:10 +01:00
Anders Hessellund Jensen 3b2c6f09cb fix($compile): empty normalized href should pass sanitation check
Sometimes IE returns an empty string for its normalized href on a tags.
This should pass the sanitation check in $compile.

Closes #2219, #2593
2013-07-04 00:13:04 +01:00
Joao Sa 63414b9653 fix(jqLite): prepend array in correct order
Match jQuery behavior when prepending array into empty element
2013-07-03 20:25:28 +01:00
exex zian 5f24bb0267 docs(tutorial/step9): formatted Unicode character line
Add tick and cross mark corresponding to their respective unicodes.
2013-07-02 22:50:52 -07:00
Vojta Jina 52519d45b9 chore(travis): speed up the build
- parallelize the tasks
- cache requests (e2e tests)

This reduces the time from ~18min to ~12min.

It makes the output little messy. We could buffer output of each task and display it once it's fully finished, nicely. I think giving instant feedback is better.
2013-07-02 15:12:03 -07:00
Niall Smart 78728df099 docs(guide/location): fix example code - hashPrefix is a method 2013-07-02 10:01:51 +01:00
Vojta Jina 732db27cd6 chore: add karma-script-launcher plugin
This plugin is shipped as a default one with Karma. It's specified as a peer dependency.

I assume, there's an old version of NPM on the CI server, which does not support peerDependencies and therefore it didn't get installed.

This will make the dependency explicit.
2013-07-01 10:15:56 -07:00
Itamar Rogel 3cad63fbd8 docs($cacheFactory): show that you can access existing caches 2013-07-01 12:03:10 +01:00
Spencer Applegate d2be5939dc docs(Angular.js): explain that toJson strips $... properties
In Angular.toJson, any properties with a leading '$' character will be
stripped from the resulting string since angular uses this notation
internally for services.  There have been complaints of not knowing
about this functionality until it breaks within their code.
2013-07-01 11:36:17 +01:00
Vojta Jina 9a77d03047 chore: set up Sauce Labs with Travis
This should not affect the Jenkins build at all.

Now, the Travis build uses Chrome on Sauce Labs, which in theory gives us opportunity to use any
browser/platform that Sauce Labs offers.
2013-06-28 16:36:30 -07:00
Vojta Jina 8efcec67cc chore: clean up angularFiles.js 2013-06-28 16:35:05 -07:00
Vojta Jina 4fbd4bbd8d chore: update karma to 0.9.4
And also add shared config to make karma configs a bit simpler.
2013-06-28 16:30:48 -07:00
Vojta Jina 2fae296cbc chore: remove jstd leftovers 2013-06-28 16:29:09 -07:00
Igor Minar cef8466419 docs(misc/faq): remove obsolte t-shirt instructions 2013-06-28 11:27:55 -07:00
Andrew Peterson 083159ebbe docs(ngBind): clarify some of the writing 2013-06-27 21:20:56 +01:00
Andrew Peterson 32e440cffc docs(ngPluralize): improve wording 2013-06-27 21:15:33 +01:00
Adam 89c8c93b9a docs(guide/e2e-testing): clarify description of input(name) selector
The description of the input selector made it seem that you were selecting
an input element based upon it's name attribute. In reality, you are
selecting an element by the string in the ng-model attribute.
2013-06-27 20:46:09 +01:00
Pete Bacon Darwin 296074f548 docs(ngMock/$httpBackend): fix testing example
Closes #3075
2013-06-27 20:38:15 +01:00
Nelson Blaha 2ccfaffa74 docs(tutorial): add experiment showing reverse sort 2013-06-27 19:36:46 +01:00
Jeffrey Palmer 192672a162 docs(guide/controller): fix an error in the scope inheritance example
The chained scope creation example at the bottom of this document was using the childCtrl to create the babyScope, instead of the childScope.
2013-06-25 23:54:33 +01:00
Domenic Denicola 7f4e658d3d docs(guide/expression): remove reference to NullPointerException 2013-06-25 21:13:56 +01:00
Pete Bacon Darwin ff57695855 refactor(angular.bootstrap): rename internal function 2013-06-20 15:23:04 +01:00
NimaVaziri ae8deb1246 docs(cookbook/helloworld): display "World" if no name is entered 2013-06-20 14:40:07 +01:00
Pete Bacon Darwin b9dcb35e9b fix(Angular.js): don't crash on invalid query parameters 2013-06-20 14:32:05 +01:00
Caio Cunha 25d9f5a804 fix($http): ensure case-insens. header overriding
If user send content-type header, both content-type and default
Content-Type headers were sent. Now default header overriding is
case-insensitive.
2013-06-19 22:43:19 +01:00
sarkasm 1b234cb7af docs(directive): fix typo 2013-06-19 11:51:18 +01:00
gdi2290 d219442945 docs(tutorial): add missing 'node' command and <code> tags 2013-06-18 22:05:43 +01:00
John Bohn 2b33be47cb docs(tutorial/step_07): add commas make tutorial read more clearly 2013-06-18 21:57:21 +01:00
Ore Landau 499baced12 docs(loader): fix typo and minor semantic error 2013-06-18 21:23:00 +01:00
Ore Landau 7aa9fecab8 docs(guide/di): fix headings hierarchy 2013-06-13 22:51:11 +01:00
Misha Moroshko 9b6c82d804 docs(select): fix typos in ngOptions 2013-06-13 22:48:03 +01:00
Ore Landau c3117b7544 docs($q): fix a few issues 2013-06-13 22:42:26 +01:00
Jad Naous 67744384e8 docs(guide/e2e-testing): fix verb tense 2013-06-13 22:37:33 +01:00
Ore Landau 17c401d09a docs(tutorial/step_05): apply more useful link to services 2013-06-13 21:15:32 +01:00
Dean Sofer 488aea15f4 docs(FormController): add methods for FormController 2013-06-12 21:49:52 +01:00
Dean Peterson 43df853ee3 docs(ngModelController): improve $parsers/$formatters with example 2013-06-12 21:23:16 +01:00
Ore Landau 28d5dcb578 docs(ngClass): fix minor typo. 2013-06-12 20:47:59 +01:00
Pete Bacon Darwin 7eb15c46a2 docs(guide/bootstrap): clarify manual bootstrapping 2013-06-12 20:42:12 +01:00
Pete Bacon Darwin 1fac36e2cb docs(ngRoute): clarify when gets updated 2013-06-11 22:35:47 +01:00
Pete Bacon Darwin 4b6c87b6e7 docs(ngSubmit): clarify that there must be no action attribute 2013-06-11 21:30:10 +01:00
Igor Minar ce6c2b2072 chore(docs): fix memory leak in example embed code
we need to sever the link between the main root scope and the example
root scope - this is only needed because we are embedding one app
in the other.
2013-06-10 13:10:38 -07:00
Igor Minar 3e94a2c54d docs(faq): update customink order info 2013-06-10 11:39:26 -07:00
Jared Forsyth b1e488f5d7 docs(guide/unit-testing): fix typo 2013-06-04 22:28:58 +01:00
Jared Forsyth 03d867160f docs(guide/injecting_controllers): add a hint in example
Add a hint to tell the user that they need to click 3 times before an alert is shown.
2013-06-04 22:25:38 +01:00
Marcin Wosinek 9870e65c5f docs(ngTransclude): fix outdated scope definition in example 2013-06-04 22:14:15 +01:00
Pete Bacon Darwin aa839b9ff0 docs(guide/unit-testing): fix controller test example 2013-06-04 22:10:27 +01:00
Robbie Ferrero fdb66aa237 docs(Angular.js): clarify ngApp usage 2013-06-04 22:01:26 +01:00
Robb Shecter e0ca5fdd51 docs(angular-mocks): fix typo in example
fromJSON() should be fromJson()
2013-06-04 21:54:05 +01:00
Alan Klement 681c1c53e4 docs(sanitize): add @description section 2013-06-04 21:50:38 +01:00
Siddique Hameed 631c4863d8 docs(index): make menu links relative
Before the Develop drop down menu items were hard coded with an absolute url,
which meant that they did not work correctly on local or ci server builds.
2013-06-04 21:08:56 +01:00
Luc Morin 944bda12c7 docs(ngClass): clarify the use of object map 2013-06-04 21:01:43 +01:00
Ehsan Ghandhari bc36c4dea4 docs(guide/concepts): add comment as a type of directive 2013-06-04 20:54:03 +01:00
Robb Shecter 722766958b docs(guide/understanding_model): improve example consistency 2013-06-04 20:50:35 +01:00
Manuel Kiessling 73fd3ca2eb docs(guide/compiler): fix some minor language errors 2013-06-04 20:38:27 +01:00
Alex Young efe8ad51ed docs(guide/di): fix some small grammatical issues 2013-06-04 20:31:06 +01:00
Jens Rantil d5b62465f0 docs(validate-commit-msg): fix incorrect comment
If you `cd` into the repo, `validate-commit-msg.js` will be in the root
of it.
2013-06-04 20:24:27 +01:00
Luc Morin bc76e7255b docs(input): provide explanation of how ngModel will affect the local scope 2013-06-04 20:16:37 +01:00
Eduardo Garcia 8dd23ad2f2 docs(guide): format snippets of code in plain text 2013-06-04 20:07:09 +01:00
adamshaylor bce75d7c68 docs(overview.ngdoc): clarify wording 2013-06-04 20:02:18 +01:00
Michał Gołębiowski 815053e403 fix(jqLite): correctly monkey-patch core jQuery methods
When real jQuery is present, Angular monkey patch it to fire `$destroy` event.

This commit fixes two issues in the jQuery patch:
- passing a selector to the $.fn.remove method (only fire `$destroy` on the matched elements)
- using `$.fn.html` without parameters as a getter (do not fire `$destroy`)
2013-05-23 11:45:57 -07:00
Igor Minar 6173abe20b docs(changelog): fix changelog formatting 2013-05-22 21:48:37 -07:00
Igor Minar 6fcf0afa35 docs(changelog): add note about animation breaking change 2013-05-22 21:48:37 -07:00
Eddie Monge 05521e276f style(docs/template): add in missing semicolons 2013-05-22 22:56:51 +01:00
Jens Rantil 38ffbbd7dd docs(guide/directive): clarify directive priority
Fixes #2644.
2013-05-22 21:10:03 +01:00
Igor Minar 47e1878e4c chore(release): start 1.1.8 bubble-burst iteration 2013-05-22 01:14:09 -07:00
367 changed files with 16703 additions and 14636 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"directory": "bower_components",
"json": "bower.json"
}
+2
View File
@@ -12,3 +12,5 @@ angular.js.tmproj
node_modules
angular.xcodeproj
.idea
libpeerconnection.log
npm-debug.log
+12 -6
View File
@@ -1,13 +1,19 @@
language: node_js
node_js:
- 0.8
- 0.10
env:
global:
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- SAUCE_CONNECT_READY_FILE=/tmp/sauce-connect-ready
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- export SAUCE_ACCESS_KEY=`echo $SAUCE_ACCESS_KEY | rev`
- ./lib/sauce/sauce_connect_setup.sh
- npm install -g grunt-cli
- grunt package
- grunt webserver > /dev/null &
- grunt ci-checks package
- ./lib/sauce/sauce_connect_block.sh
script:
- grunt test --browsers Firefox --reporters=dots
- grunt parallel:travis --reporters dots --browsers SL_Chrome
+702 -39
View File
@@ -1,3 +1,658 @@
<a name="1.0.8"></a>
# 1.0.8 bubble-burst (2013-08-22)
Contains only these fixes cherry-picked from [v1.2.0rc1](#1.2.0rc1).
## Bug Fixes
- **$compile:**
- don't check attr.specified on non-ie7
([78efa0e3](https://github.com/angular/angular.js/commit/78efa0e36c1cb9fe293190381baa5a3fe5b3d1cb),
[#3231](https://github.com/angular/angular.js/issues/3231), [#2160](https://github.com/angular/angular.js/issues/2160))
- empty normalized href should pass sanitation check
([3b2c6f09](https://github.com/angular/angular.js/commit/3b2c6f09cb857b86641cefde5b92d84d58c1118d),
[#2219](https://github.com/angular/angular.js/issues/2219))
- **$http:** ensure case-insensitive header overriding
([25d9f5a8](https://github.com/angular/angular.js/commit/25d9f5a804b7a6a61db6e84e594b1b5fe7ea14bf))
- **$location:**
- default to / for the url base if no base[href]
([cbe31d8d](https://github.com/angular/angular.js/commit/cbe31d8dfd12ce973c574bfc825ffc0ffb8eb7c4),
[#2762](https://github.com/angular/angular.js/issues/2762))
- prevent infinite digest error due to IE bug
([97abb124](https://github.com/angular/angular.js/commit/97abb124738e0ca5d00d807d65c482f7890feadd),
[#2802](https://github.com/angular/angular.js/issues/2802))
- don't crash on invalid query parameters
([b9dcb35e](https://github.com/angular/angular.js/commit/b9dcb35e9bc64cb2f48f3a349ead66c501cbdc48))
- **$parse:** move global getter out of parse.js
([099138fb](https://github.com/angular/angular.js/commit/099138fb9a94178d3d82568fbda28d0c87443de9))
- **$q:** call `reject()` even if `$exceptionHandler` rethrows
([d59027c4](https://github.com/angular/angular.js/commit/d59027c40ed73fa9e114706d0c5a885785311dec))
- **$timeout:** clean deferreds immediately after callback exec/cancel
([ac69392c](https://github.com/angular/angular.js/commit/ac69392cd7f939ebbd37765e377051d4c05df4a5))
- **$sanitize:** match URI schemes case-insensitively
([fcd761b9](https://github.com/angular/angular.js/commit/fcd761b9d7c3c91673efce9b980ac5e7973adf3d),
[#3210](https://github.com/angular/angular.js/issues/3210))
- **Scope:** watches can be safely unregistered inside watch handlers
([a4ec2979](https://github.com/angular/angular.js/commit/a4ec297925f052bf9ea1aba9f584eaaf7472fb93),
[#2915](https://github.com/angular/angular.js/issues/2915))
- **ngMock**
- $timeout should forward delay argument
([a5fb372e](https://github.com/angular/angular.js/commit/a5fb372e1e6aed8cdb1f572f1df3d6fe89388f3e))
- **jqLite:**
- return array from multi select in val()
([01cd3495](https://github.com/angular/angular.js/commit/01cd34957e778a2fa8d26e2805c2dd5a7f986465))
- forgive unregistration of a non-registered handler
([ac5b9055](https://github.com/angular/angular.js/commit/ac5b9055f6d7224e5e8e49941c0fc9cb16c64a7e))
- prepend array in correct order
([63414b96](https://github.com/angular/angular.js/commit/63414b965397a9fd7d2f49e8dea4b848e0d6707e))
- correctly monkey-patch core jQuery methods
([815053e4](https://github.com/angular/angular.js/commit/815053e403ace666b2383643227ecde5f36742c5))
- **Directives:**
- **form:** pick the right attribute name for ngForm
([dc1e55ce](https://github.com/angular/angular.js/commit/dc1e55ce1a314b6c1ad4b9d5b4a31226e1fa1e18),
[#2997](https://github.com/angular/angular.js/issues/2997))
- **input:** fix the email regex to accept TLDs up to 6 characters long
([ad76e77f](https://github.com/angular/angular.js/commit/ad76e77fce09d0aee28b5ca1a328d5df8596b935))
- **ngCloak:** hide element even when CSS 'display' is set
([06b0930b](https://github.com/angular/angular.js/commit/06b0930b6a821bdfed78875f821baf1b8ede2442))
- **ngSubmit:** expose $event to ngSubmit callback
([b0d5f062](https://github.com/angular/angular.js/commit/b0d5f062e316370c7ac57cfd628d085015a8187d))
- **ngValue:** made ngValue to write value attribute to element
([3b898664](https://github.com/angular/angular.js/commit/3b898664eea9913b6b25261d7310a61de476d173))
- **Filters:**
- **number:** always convert scientific notation to decimal
([408e8682](https://github.com/angular/angular.js/commit/408e868237d80f9332f2c540f91b2809d9938fbc))
- **orderBy:** remove redundant if statement
([ec1cece2](https://github.com/angular/angular.js/commit/ec1cece270e293e7c55556fc68afee9a2ad40641))
- **i18n:** Do not transform arrays into objects
([751c77f8](https://github.com/angular/angular.js/commit/751c77f87b34389c5b85a23c71080d367c42d31b))
- **jqLite:**
- return array from multi select in val()
([01cd3495](https://github.com/angular/angular.js/commit/01cd34957e778a2fa8d26e2805c2dd5a7f986465))
- forgive unregistration of a non-registered handler
([ac5b9055](https://github.com/angular/angular.js/commit/ac5b9055f6d7224e5e8e49941c0fc9cb16c64a7e))
- prepend array in correct order
([63414b96](https://github.com/angular/angular.js/commit/63414b965397a9fd7d2f49e8dea4b848e0d6707e))
- correctly monkey-patch core jQuery methods
([815053e4](https://github.com/angular/angular.js/commit/815053e403ace666b2383643227ecde5f36742c5))
- **Misc:**
- **angular.copy:** change angular.copy to correctly clone RegExp
([5cca077e](https://github.com/angular/angular.js/commit/5cca077e4a40a26cc2deee2a86a215f575f25b22),
[#3473](https://github.com/angular/angular.js/issues/3473), [#3474](https://github.com/angular/angular.js/issues/3474))
- **angular.equals:**
- add support for regular expressions
([a357649d](https://github.com/angular/angular.js/commit/a357649da5d9f0633fa8e8a249f58dfc1105698e),
[#2685](https://github.com/angular/angular.js/issues/2685))
- {} and [] should not be considered equivalent
([da1f7c76](https://github.com/angular/angular.js/commit/da1f7c762d36b646c107260f74daf3a0ab5f91f5))
- **angular.toJson:** skip JSON.stringify for undefined
([332a3c79](https://github.com/angular/angular.js/commit/332a3c7984229a7e3a9a8a277f92942299616fdb))
<a name="1.2.0-rc1"></a>
# 1.2.0-rc1 spooky-giraffe (2013-08-13)
[Full Commit Log](https://github.com/angular/angular.js/compare/v1.1.5...master)
## Features
- **ngAnimate:** complete rewrite of animations
([81923f1e](https://github.com/angular/angular.js/commit/81923f1e41560327f7de6e8fddfda0d2612658f3))
- **$sce:** new $sce service for Strict Contextual Escaping and lots of other security enhancements
([bea9422e](https://github.com/angular/angular.js/commit/bea9422ebfc8e80ee28ad81afc62d2e432c85cbb))
- **minErr:** add error message minification and better error messages
([c8fcf3b3](https://github.com/angular/angular.js/commit/c8fcf3b369dbe866815e18e0fa4d71f3e679bc5f),
[09fa0656](https://github.com/angular/angular.js/commit/09fa0656b49321681f28453abef566d0cbe0eb22),
[b8ea7f6a](https://github.com/angular/angular.js/commit/b8ea7f6aba2e675b85826b0bee1f21ddd7b866a5))
- **$compile:**
- support animation hooks bindings to class attributes
([f2dfa891](https://github.com/angular/angular.js/commit/f2dfa8916f8ed855d55187f5400c4c2566ce9a1b))
- support multi-element directive
([e46100f7](https://github.com/angular/angular.js/commit/e46100f7097d9a8f174bdb9e15d4c6098395c3f2))
- support "Controller as" instance syntax for directives
([b3777f27](https://github.com/angular/angular.js/commit/b3777f275c6bd2bd4a88963fd03828eb7cf3aca8))
- **$http:** accept function as headers value
([a7150f12](https://github.com/angular/angular.js/commit/a7150f1256f2a97a931b3c0d16eab70f45e81cae))
- **$q:**
- add `.catch()` as shorthand for defining promise error handlers
([a207665d](https://github.com/angular/angular.js/commit/a207665dad69248139b150cd3fe8ba13059bffb4),
[#2048](https://github.com/angular/angular.js/issues/2048),
[#3476](https://github.com/angular/angular.js/issues/3476))
- added support for promise notification
([2a5c3555](https://github.com/angular/angular.js/commit/2a5c3555829da51f55abd810a828c73b420316d3))
- **$resource:**
- support an unescaped URL port in the url template
([b94ca12f](https://github.com/angular/angular.js/commit/b94ca12fa0b027d8592f5717e038b7b116c59384),
[#2778](https://github.com/angular/angular.js/issues/2778))
- expose promise as `$promise` instead of only `$then`
([05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d))
- **$route:** express style route matching (support for optional params and new wildcard syntax)
([04cebcc1](https://github.com/angular/angular.js/commit/04cebcc133c8b433a3ac5f72ed19f3631778142b))
- **jqLite:** switch bind/unbind to more recent jQuery on/off
([f1b94b4b](https://github.com/angular/angular.js/commit/f1b94b4b599ab701bc75b55bbbbb73c5ef329a93))
- **Misc:**
- add source maps to all min files
([908071af](https://github.com/angular/angular.js/commit/908071afbf32c46fe9110e4a67e104bbd4b3a56b),
[#1714](https://github.com/angular/angular.js/issues/1714))
- **Directives:**
- add `ngFocus` and `ngBlur` directives
([2bb27d49](https://github.com/angular/angular.js/commit/2bb27d4998805fd89db25192f53d26d259ae615f),
[#1277](https://github.com/angular/angular.js/issues/1277))
- **ngRepeat:** add $even and $odd props to iterator
([52b8211f](https://github.com/angular/angular.js/commit/52b8211fd0154b9d6b771a83573a161f5580d92c))
- **ngForm:** supports namespaces in form names
([8ea802a1](https://github.com/angular/angular.js/commit/8ea802a1d23ad8ecacab892a3a451a308d9c39d7))
- **ngBindHtml:** combine ng-bind-html and ng-bind-html-unsafe
([dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55))
- **ngPluralize:** add alternative mapping using attributes
([a170fc1a](https://github.com/angular/angular.js/commit/a170fc1a749effa98bfd1c2e1b30297ed47b451b),
[#2454](https://github.com/angular/angular.js/issues/2454))
- **ngMobile/ngTouch:**
- emit `swipeleft` and `swiperight` events
([ab189142](https://github.com/angular/angular.js/commit/ab189142988043d0513bb796c3b54ca7d07f242d))
- refactor swipe logic from `ngSwipe` directive to `$swipe` service.
([f4c6b2c7](https://github.com/angular/angular.js/commit/f4c6b2c7894cb2d82ac69a1500a27785360b81c3))
- **ngMock:**
- $timeout.flushNext can expect specific timeout delays
([462ed033](https://github.com/angular/angular.js/commit/462ed033d512ae94cb188efc9453de84ace4e17e))
- support delay limit for $timeout.flush
([b7fdabc4](https://github.com/angular/angular.js/commit/b7fdabc4bf2a9dd11a57f98c5229d834c4589bab))
- support a matching function for data param
([08daa779](https://github.com/angular/angular.js/commit/08daa7797bce5207916251d4a0ab3d5c93e5529a))
- **scenario:** expose jQuery for usage outside of angular scenario
([3fdbe81a](https://github.com/angular/angular.js/commit/3fdbe81a337c39027929c415e719493755cd8583))
- **ngDocs:**
- provide support for user to jump between different versions of the angularjs doc
([46dfb92a](https://github.com/angular/angular.js/commit/46dfb92afd185c93f60ca90a72653f33d7cb18e8))
- add links to source for API
([52d6a599](https://github.com/angular/angular.js/commit/52d6a5990225439ac9141398d83e0d4e6134b576))
- support popover, foldouts and foldover annotations
([ef229688](https://github.com/angular/angular.js/commit/ef22968810d555f78d3bbf7b5428757690c8cc70))
- provide documentation for the new ngRepeat repeater syntax
([b3650457](https://github.com/angular/angular.js/commit/b36504577c538b745e6270e77d86af90285e2ae6))
- provide support for inline variable hinting
([21c70729](https://github.com/angular/angular.js/commit/21c70729d9269de85df3434c431c2f18995b0f7b))
## Bug Fixes
- **$compile:**
- correct controller instantiation for async directives
([c173ca41](https://github.com/angular/angular.js/commit/c173ca412878d537b18df01f39e400ea48a4b398),
[#3493](https://github.com/angular/angular.js/issues/3493),
[#3482](https://github.com/angular/angular.js/issues/3482),
[#3537](https://github.com/angular/angular.js/issues/3537),
[#3540](https://github.com/angular/angular.js/issues/3540))
- always instantiate controllers before pre-link fns run
([5c560117](https://github.com/angular/angular.js/commit/5c560117425e7b3f7270389274476e843d6f69ec),
[#3493](https://github.com/angular/angular.js/issues/3493),
[#3482](https://github.com/angular/angular.js/issues/3482),
[#3514](https://github.com/angular/angular.js/issues/3514))
- always instantiate controllers in parent->child order
([45f9f623](https://github.com/angular/angular.js/commit/45f9f62367221b2aa097ba1d87d744e50140ddc7),
[#2738](https://github.com/angular/angular.js/issues/2738))
- don't check attr.specified on non-ie7
([f9ea69f6](https://github.com/angular/angular.js/commit/f9ea69f6567c22ff328fd1f7b07847883757bfa6),
[#3231](https://github.com/angular/angular.js/issues/3231),
[#2160](https://github.com/angular/angular.js/issues/2160))
- allow `data:` image URIs in `img[src]` bindings
([3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b))
- empty normalized href url should pass sanitation check
([fc8c9baa](https://github.com/angular/angular.js/commit/fc8c9baa399c33956133cdb6892fc7007430d299),
[#2219](https://github.com/angular/angular.js/issues/2219))
- prevent infinite loop w/ replace+transclude directives
([69f42b76](https://github.com/angular/angular.js/commit/69f42b76548d00f52b231ec91150e4f0b008c730),
[#2155](https://github.com/angular/angular.js/issues/2155))
- reject multi-expression interpolations for `src` attribute
([38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262bb43f26d47245f6c2739))
- disallow interpolations for DOM event handlers
([39841f2e](https://github.com/angular/angular.js/commit/39841f2ec9b17b3b2920fd1eb548d444251f4f56))
- sanitize values bound to `img[src]`
([1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97))
- support multi-element group over text nodes
([b28f9694](https://github.com/angular/angular.js/commit/b28f96949ac477b1fe43c81df7cedc21c7ab184c))
- correct component transclusion on compilation root.
([15e1a29c](https://github.com/angular/angular.js/commit/15e1a29cd08993b599f390e83a249ec17f753972))
- **$http:**
- allow interceptors to completely override headers
([514dc0eb](https://github.com/angular/angular.js/commit/514dc0eb16a8fe3fa7c44094d743714f73754321),
[#2770](https://github.com/angular/angular.js/issues/2770))
- treat headers as case-insensitive when overriding defaults
([53359d54](https://github.com/angular/angular.js/commit/53359d549e364759d5b382c229f7d326799bf418))
- **$location:**
- don't initialize url hash in hashbang mode unnecessarily
([d4d34aba](https://github.com/angular/angular.js/commit/d4d34aba6efbd98050235f5b264899bb788117df))
- prevent infinite digest error due to IE bug
([dca23173](https://github.com/angular/angular.js/commit/dca23173e25a32cb740245ca7f7b01a84805f43f),
[#2802](https://github.com/angular/angular.js/issues/2802))
- in html5 mode, default to / for the url base if no `base[href]`
([aef09800](https://github.com/angular/angular.js/commit/aef098006302689d2d75673be828e31903ee7c3c),
[#2762](https://github.com/angular/angular.js/issues/2762))
- fix parameter handling on search()
([705c9d95](https://github.com/angular/angular.js/commit/705c9d95bc3157547ac6008d2f0a6a0c0e0ca60a))
- **$parse:**
- unwrap promise when setting a field
([61906d35](https://github.com/angular/angular.js/commit/61906d3517428b6d52d3284b8d26d1a46e01dad7),
[#1827](https://github.com/angular/angular.js/issues/1827))
- disallow access to Function constructor
([5349b200](https://github.com/angular/angular.js/commit/5349b20097dc5cdff0216ee219ac5f6e6ef8c219))
- **$q:** call `reject()` even if `$exceptionHandler` rethrows
([664526d6](https://github.com/angular/angular.js/commit/664526d69c927370c93a06745ca38de7cd03a7be))
- **$resource:** check whether response matches action.isArray
([a644ca7b](https://github.com/angular/angular.js/commit/a644ca7b4e6ba84a467bcabed8f99386eda7fb14),
[#2255](https://github.com/angular/angular.js/issues/2255))
- **$sanitize:** match URI schemes case-insensitively
([7fef06fe](https://github.com/angular/angular.js/commit/7fef06fef9b6af4436f9fed10bd29d0a63707614),
[#3210](https://github.com/angular/angular.js/issues/3210))
- **Scope:**
- ensure that isolate scopes use the main evalAsync queue
([3967f5f7](https://github.com/angular/angular.js/commit/3967f5f7d6c8aa7b41a5352b12f457e2fbaa251a))
- watches can now be safely unregistered inside watch handlers
([8bd6619b](https://github.com/angular/angular.js/commit/8bd6619b7efa485b020fec96c76047e480469871),
[#2915](https://github.com/angular/angular.js/issues/2915))
- **jqLite:**
- properly detect unsupported calls for on()/off()
([3824e400](https://github.com/angular/angular.js/commit/3824e40011df1c0fdf5964d78776f1a12a29c144),
[4f5dfbc3](https://github.com/angular/angular.js/commit/4f5dfbc362d9683177708ebcc00c98cf594d1287),
[#3501](https://github.com/angular/angular.js/issues/3501))
- return array from multi select in val()
([306a6134](https://github.com/angular/angular.js/commit/306a613440175c7fd61d1d6eb249d1e53a46322e))
- forgive unregistration of a non-registered handler
([ab59cc6c](https://github.com/angular/angular.js/commit/ab59cc6c44705b1244a77eba999d736f9eb3c6ae))
- support space-separated events in off
([bdd4e982](https://github.com/angular/angular.js/commit/bdd4e982b7fee9811b40b545c21a74711686875c),
[#3256](https://github.com/angular/angular.js/issues/3256))
- prepend array in correct order
([fd87eb0c](https://github.com/angular/angular.js/commit/fd87eb0ca5e14f213d8b31280d444dbc29c20c50))
- allow override of jqLite.triggerHandler event object
([0cac8729](https://github.com/angular/angular.js/commit/0cac8729fb3824ebb07cee84ef78b43900c7e75d))
- added optional name arg in removeData
([e1a050e6](https://github.com/angular/angular.js/commit/e1a050e6b26aca4d0e6e7125d3f6c1c8fc1d92cb))
- correctly monkey-patch core jQuery methods
([da5f537c](https://github.com/angular/angular.js/commit/da5f537ccdb0a7b4155f13f7a70ca7981ad6f689))
- **i18n:** Do not transform arrays into objects
([b3d7a038](https://github.com/angular/angular.js/commit/b3d7a038d774d823ef861b76fb8bfa22e60a3df5))
- **ngMobile/ngTouch:**
- emit click event for touchy clicks
([fb7d891d](https://github.com/angular/angular.js/commit/fb7d891dacdcb9f799061d5fbb96cdd2dd912196),
[#3219](https://github.com/angular/angular.js/issues/3219),
[#3218](https://github.com/angular/angular.js/issues/3218),
[#3137](https://github.com/angular/angular.js/issues/3137))
- prevent ngClick when item disabled
([e0340243](https://github.com/angular/angular.js/commit/e03402433d2524fd3a74bbfce984f843794996ce),
[#3124](https://github.com/angular/angular.js/issues/3124),
[#3132](https://github.com/angular/angular.js/issues/3132))
- ngClick should prevent unwanted opening of the soft keyboard
([0bbd20f2](https://github.com/angular/angular.js/commit/0bbd20f255b2954b5c41617fe718cf6eca36a972))
- **ngMock:**
- keep withCredentials on passThrough
([3079a6f4](https://github.com/angular/angular.js/commit/3079a6f4e097a777414b8c3a8a87b8e1e20b55b5))
- keep mock.$log the api in sync with $log
([f274c0a6](https://github.com/angular/angular.js/commit/f274c0a66b28711d3b9cc7b0775e97755dd971e8),
[#2343](https://github.com/angular/angular.js/issues/2343))
- **ngScenario:** select().option(val) should prefer exact value match
([22a9b1ac](https://github.com/angular/angular.js/commit/22a9b1ac07f98d07e1e5d71ce961411b5fa9b42d),
[#2856](https://github.com/angular/angular.js/issues/2856))
- **Directives:**
- **ngRepeat:**
- handle iteration over identical obj values
([47a2a982](https://github.com/angular/angular.js/commit/47a2a9829f0a847bbee61cd142c43000d73ea98b),
[#2787](https://github.com/angular/angular.js/issues/2787),
[#2806](https://github.com/angular/angular.js/issues/2806))
- support growing over multi-element groups
([4953b497](https://github.com/angular/angular.js/commit/4953b49761a791d9ea74bcbe78769fec15d91083))
- **ngShowHide:** change the .ng-hide CSS class to use an !important flag
([246c1439](https://github.com/angular/angular.js/commit/246c1439b502b06823650505cbe4a3848b6fa5a3))
- **ngSubmit:** expose $event to ngSubmit callback
([3371fc25](https://github.com/angular/angular.js/commit/3371fc254a9698eae35bb6f8f1ee9c434ae761e2))
- **ngValue:** made ngValue to write value attribute to element
([09a1e7af](https://github.com/angular/angular.js/commit/09a1e7af129880cab89a2f709f22a7286f52371e))
- **ngView:** ensure ngView is terminal and uses its own manual transclusion system
([87405e25](https://github.com/angular/angular.js/commit/87405e25ae935eefd673e70ffd6144a5f455b662))
- **ngCloak:** hide ngCloak-ed element even when CSS 'display' is set
([3ffddad1](https://github.com/angular/angular.js/commit/3ffddad100e993403d13137387d0685466b46b2b))
- **`input[email]`:** fix the email regex to accept TLDs up to 6 characters long
([af731354](https://github.com/angular/angular.js/commit/af731354b0b600f87f15e1573e64a7f7acc70f3d))
- **form:** pick the right attribute name for ngForm
([0fcd1e3b](https://github.com/angular/angular.js/commit/0fcd1e3b1fa6244d02f08631d9ef81bf79996fab),
[#2997](https://github.com/angular/angular.js/issues/2997))
- **select:** don't support binding to `select[multiple]`
([d87fa004](https://github.com/angular/angular.js/commit/d87fa0042375b025b98c40bff05e5f42c00af114),
[#3230](https://github.com/angular/angular.js/issues/3230))
- **Filters:**
- **numberFilter:** always convert scientific notation to decimal
([a13c01a8](https://github.com/angular/angular.js/commit/a13c01a8e48ea4a0d59394eb94f1b12c50cfef61))
- **Misc:**
- detect transition/animation on older Android browsers
([ef5bc6c7](https://github.com/angular/angular.js/commit/ef5bc6c7c3336a64bae64fe9739cb1789907c906))
- handle duplicate params in parseKeyValue/toKeyValue
([80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe))
- don't crash on invalid query parameters
([8264d080](https://github.com/angular/angular.js/commit/8264d08085adc2ab57f6598b9fc9f6e263c8b4f3))
- change angular.copy to correctly clone RegExp
([f80730f4](https://github.com/angular/angular.js/commit/f80730f497cb1ecb78a814f01df79b69223ad633),
[#3473](https://github.com/angular/angular.js/issues/3473),
[#3474](https://github.com/angular/angular.js/issues/3474))
- angular.equals now supports for regular expressions
([724819e3](https://github.com/angular/angular.js/commit/724819e3cfd8aeda1f724fb527db2b57494be9b7),
[#2685](https://github.com/angular/angular.js/issues/2685))
- angular.equals should not match keys defined in the prototype chain
([7829c50f](https://github.com/angular/angular.js/commit/7829c50f9e89e779980f6d60a397aedfc7eaec61))
- angular.equals should not consider {} and [] to be equivalent
([1dcafd18](https://github.com/angular/angular.js/commit/1dcafd18afed4465ee13db91cedc8fecc3aa2c96))
- angular.bootstrap should throw an error when bootstrapping a bootstrapped element
([3ee744cc](https://github.com/angular/angular.js/commit/3ee744cc63a24b127d6a5f632934bb6ed2de275a))
- angular.toJson should skip JSON.stringify for undefined
([5a294c86](https://github.com/angular/angular.js/commit/5a294c8646452d6e49339d145faeae4f31dcd0fc))
- change css wrapping in grunt to prepend styles to the top of the head tag
([fbad068a](https://github.com/angular/angular.js/commit/fbad068aeb229fd3dd2a3004879584c728fed735))
## Breaking Changes
- **ngAnimate:** due to [81923f1e](https://github.com/angular/angular.js/commit/81923f1e41560327f7de6e8fddfda0d2612658f3),
too many things changed, we'll write up a separate doc with migration instructions and will publish it at <http://yearofmoo.com>. Please check out the [ngAnimate module docs](http://ci.angularjs.org/job/angular.js-angular-master/lastSuccessfulBuild/artifact/build/docs/api/ngAnimate) and [$animate api docs](http://ci.angularjs.org/job/angular.js-angular-master/lastSuccessfulBuild/artifact/build/docs/api/ng.$animate) in the meantime.
- **$compile:**
- due to [1adf29af](https://github.com/angular/angular.js/commit/1adf29af13890d61286840177607edd552a9df97) and [3e39ac7e](https://github.com/angular/angular.js/commit/3e39ac7e1b10d4812a44dad2f959a93361cd823b),
`img[src]` URLs are now being sanitized and a whitelist configured via `$compileProvider` can be used to configure what safe urls look like.
By default all common protocol prefixes are whitelisted including `data:` URIs with mime types `image/*`. Therefore this change is expected to have no impact on apps that don't contain malicious image links.
- due to [38deedd6](https://github.com/angular/angular.js/commit/38deedd6e3d806eb8262bb43f26d47245f6c2739),
binding more than a single expression to `*[src]` or `*[ng-src]` with the exception of `<a>` and `<img>` elements is not supported.
Concatenating expressions makes it hard to understand whether some combination of concatenated values are unsafe to use and potentially subject to XSS vulnerabilities. To simplify the task of auditing for XSS issues, we now require that a single expression be used for `*[src/ng-src]` bindings such as bindings for `iframe[src]`, `object[src]`, etc. (but not `img[src/ng-src]` since that value is sanitized).
This change ensures that the possible pool of values that are used for data-binding is easier to trace down.
To migrate your code, follow the example below:
Before:
JS:
scope.baseUrl = 'page';
scope.a = 1;
scope.b = 2;
HTML:
<!-- Are a and b properly escaped here? Is baseUrl
controlled by user? -->
<iframe src="{{baseUrl}}?a={{a}&b={{b}}">
After:
JS:
var baseUrl = "page";
scope.getIframeSrc = function() {
// There are obviously better ways to do this. The
// key point is that one will think about this and do
// it the right way.
var qs = ["a", "b"].map(function(value, name) {
return encodeURIComponent(name) + "=" +
encodeURIComponent(value);
}).join("&");
// baseUrl isn't on scope so it isn't bound to a user
// controlled value.
return baseUrl + "?" + qs;
}
HTML: <iframe src="{{getIframeSrc()}}">
- due to [39841f2e](https://github.com/angular/angular.js/commit/39841f2ec9b17b3b2920fd1eb548d444251f4f56),
Interpolations inside DOM event handlers are disallowed.
DOM event handlers execute arbitrary Javascript code. Using an interpolation for such handlers means that the interpolated value is a JS string that is evaluated. Storing or generating such strings is error prone and leads to XSS vulnerabilities. On the other hand, `ngClick` and other Angular specific event handlers evaluate Angular expressions in non-window (Scope) context which makes them much safer.
To migrate the code follow the example below:
Before:
JS: scope.foo = 'alert(1)';
HTML: <div onclick="{{foo}}">
After:
JS: scope.foo = function() { alert(1); }
HTML: <div ng-click="foo()">
- **$q:** due to [f078762d](https://github.com/angular/angular.js/commit/f078762d48d0d5d9796dcdf2cb0241198677582c),
the `always` method is now exposed as `finally`.
The reason for this change is to align `$q` with the Q promise library, despite the fact that this makes it a bit more difficult to use with non-ES5 browsers, like IE8.
`finally` also goes well together with `catch` api that was added to $q recently and is part of the DOM promises standard.
To migrate the code follow the example below:
Before:
```
$http.get('/foo').always(doSomething);
```
After:
```
$http.get('/foo').finally(doSomething);
```
or for IE8 compatible code:
```
$http.get('/foo')['finally'](doSomething);
```
- **$resource:**
- due to [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d),
resource instance does not have a `$then` function anymore. Use the `$promise.then` instead.
Before:
```
Resource.query().$then(callback);
```
After:
```
Resource.query().$promise.then(callback);
```
- due to [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d), instance methods return the promise rather than the instance itself.
Before:
```
resource.$save().chaining = true;
```
After:
```
resource.$save();
resource.chaining = true;
```
- due to [05772e15](https://github.com/angular/angular.js/commit/05772e15fbecfdc63d4977e2e8839d8b95d6a92d), on success, the resource promise is resolved with the resource instance rather than http response object.
Use interceptor api to access the http response object.
Before:
```
Resource.query().$then(function(response) {...});
```
After:
```
var Resource = $resource('/url', {}, {
get: {
method: 'get',
interceptor: {
response: function(response) {
// expose response
return response;
}
}
}
});
```
- **$route:**
- due to [04cebcc1](https://github.com/angular/angular.js/commit/04cebcc133c8b433a3ac5f72ed19f3631778142b),
the syntax for named wildcard parameters in routes has changed from `*wildcard` to `:wildcard*`
To migrate the code, follow the example below. Here, `*highlight` becomes
`:highlight*`:
Before:
```
$routeProvider.when('/Book1/:book/Chapter/:chapter/*highlight/edit',
{controller: noop, templateUrl: 'Chapter.html'});
```
After:
```
$routeProvider.when('/Book1/:book/Chapter/:chapter/:highlight*/edit',
{controller: noop, templateUrl: 'Chapter.html'});
```
- due to [5599b55b](https://github.com/angular/angular.js/commit/5599b55b04788c2e327d7551a4a699d75516dd21),
applications that use `$route` will now need to load an angular-route.js file and define a dependency on the ngRoute module.
Before:
```
...
<script src="angular.js"></script>
...
var myApp = angular.module('myApp', ['someOtherModule']);
...
```
After:
```
...
<script src="angular.js"></script>
<script src="angular-route.js"></script>
...
var myApp = angular.module('myApp', ['ngRoute', 'someOtherModule']);
...
```
- **$location:** due to [80739409](https://github.com/angular/angular.js/commit/807394095b991357225a03d5fed81fea5c9a1abe),
`$location.search` now supports multiple keys with the same value provided that the values are stored in an array in `$location.search`.
Before this change:
- `parseKeyValue` only took the last key overwriting all the previous keys;
- `toKeyValue` joined the keys together in a comma delimited string.
This was deemed buggy behavior. If your server relied on this behavior then either the server should be fixed, or a simple serialization of the array should be done on the client before passing it to $location.
- **ngBindHtml, sce:** due to [dae69473](https://github.com/angular/angular.js/commit/dae694739b9581bea5dbc53522ec00d87b26ae55),
`ngHtmlBindUnsafe` has been removed and replaced by `ngHtmlBind` (which has been moved from `ngSanitize` module to the core `ng` module). `ngBindHtml` provides `ngHtmlBindUnsafe` like behavior (evaluate an expression and innerHTML the result into the DOM) when bound to the result of `$sce.trustAsHtml(string)`. When bound to a plain string, the string is sanitized via `$sanitize` before being innerHTML'd. If the `$sanitize` service isn't available (`ngSanitize` module is not loaded) and the bound expression evaluates to a value that is not trusted an exception is thrown.
- **ngForm:** due to [8ea802a1](https://github.com/angular/angular.js/commit/8ea802a1d23ad8ecacab892a3a451a308d9c39d7),
If you have form names that will evaluate as an expression:
```
<form name="ctrl.form">
```
And if you are accessing the form from your controller:
Before:
```
function($scope) {
$scope['ctrl.form'] // form controller instance
}
```
After:
```
function($scope) {
$scope.ctrl.form // form controller instance
}
```
This makes it possible to access a form from a controller using the new "controller as" syntax. Supporting the previous behavior offers no benefit.
- **ngView:** due to [7d69d52a](https://github.com/angular/angular.js/commit/7d69d52acff8578e0f7d6fe57a6c45561a05b182),
previously ngView only updated its content, after this change ngView will recreate itself every time a new content is included. This ensures that a single rootElement for all the included contents always exists, which makes definition of css styles for animations much easier.
- **ngInclude:** due to [aa2133ad](https://github.com/angular/angular.js/commit/aa2133ad818d2e5c27cbd3933061797096356c8a),
previously ngInclude only updated its content, after this change ngInclude will recreate itself every time a new content is included. This ensures that a single rootElement for all the included contents always exists, which makes definition of css styles for animations much easier.
- **select:** due to [d87fa004](https://github.com/angular/angular.js/commit/d87fa0042375b025b98c40bff05e5f42c00af114),
binding to `select[multiple]` directly or via ngMultiple (ng-multiple) directive is not supported. This feature never worked with two-way data-binding, so it's not expected that anybody actually depends on it.
- **ngMobile:** due to [94ec84e7](https://github.com/angular/angular.js/commit/94ec84e7b9c89358dc00e4039009af9e287bbd05),
since all the code in the ngMobile module is touch related, we are renaming the module to ngTouch.
To migrate, please replace all references to "ngMobile" with "ngTouch" and "angular-mobile.js" to "angular-touch.js".
<a name="1.1.5"></a>
# 1.1.5 triangle-squarification (2013-05-22)
@@ -83,54 +738,52 @@ _Note: This release also contains all bug fixes available in [1.0.7](#1.0.7)._
([de2cdb06](https://github.com/angular/angular.js/commit/de2cdb0658b8b8cff5a59e26c5ec1c9b470efb9b))
- **$location:**
- prevent navigation when event isDefaultPrevented
([2c69a673](https://github.com/angular/angular.js/commit/2c69a6735e8af5d1b9b73fd221274d374e8efdea))
- compare against actual instead of current URL
([a348e90a](https://github.com/angular/angular.js/commit/a348e90aa141921b914f87ec930cd6ebf481a446))
- prevent navigation if already on the URL
([4bd7bedf](https://github.com/angular/angular.js/commit/4bd7bedf48c0c1ebb62f6bd8c85e8ea00f94502b))
- fix URL interception in hash-bang mode
([58ef3230](https://github.com/angular/angular.js/commit/58ef32308f45141c8f7f7cc32a6156cd328ba692),
[#1051](https://github.com/angular/angular.js/issues/1051))
- correctly rewrite Html5 urls
([77ff1085](https://github.com/angular/angular.js/commit/77ff1085554675f1a8375642996e5b1e51f9ed2d))
- prevent navigation when event isDefaultPrevented
([2c69a673](https://github.com/angular/angular.js/commit/2c69a6735e8af5d1b9b73fd221274d374e8efdea))
- compare against actual instead of current URL
([a348e90a](https://github.com/angular/angular.js/commit/a348e90aa141921b914f87ec930cd6ebf481a446))
- prevent navigation if already on the URL
([4bd7bedf](https://github.com/angular/angular.js/commit/4bd7bedf48c0c1ebb62f6bd8c85e8ea00f94502b))
- fix URL interception in hash-bang mode
([58ef3230](https://github.com/angular/angular.js/commit/58ef32308f45141c8f7f7cc32a6156cd328ba692),
[#1051](https://github.com/angular/angular.js/issues/1051))
- correctly rewrite Html5 urls
([77ff1085](https://github.com/angular/angular.js/commit/77ff1085554675f1a8375642996e5b1e51f9ed2d))
- **$resource:**
- null default param results in TypeError
([cefbcd47](https://github.com/angular/angular.js/commit/cefbcd470d4c9020cc3487b2326d45058ef831e2))
- collapse empty suffix parameters correctly
([53061363](https://github.com/angular/angular.js/commit/53061363c7aa1ab9085273d269c6f04ac2162336))
- null default param results in TypeError
([cefbcd47](https://github.com/angular/angular.js/commit/cefbcd470d4c9020cc3487b2326d45058ef831e2))
- collapse empty suffix parameters correctly
([53061363](https://github.com/angular/angular.js/commit/53061363c7aa1ab9085273d269c6f04ac2162336))
- **$rootScope:**
- ensure $watchCollection correctly handles arrayLike objects
- **$rootScope:** ensure $watchCollection correctly handles arrayLike objects
([6452707d](https://github.com/angular/angular.js/commit/6452707d4098235bdbde34e790aee05a1b091218))
- **date filter:** correctly format dates with more than 3 sub-second digits
([4f2e3606](https://github.com/angular/angular.js/commit/4f2e36068502f18814fee0abd26951124881f951))
- **jqLite:**
- pass a dummy event into triggerHandler
- **jqLite:** pass a dummy event into triggerHandler
([0401a7f5](https://github.com/angular/angular.js/commit/0401a7f598ef9a36ffe1f217e1a98961046fa551))
- **Directives:**
- **ngAnimate:**
- eval ng-animate expression on each animation
([fd21c750](https://github.com/angular/angular.js/commit/fd21c7502f0a25364a810c26ebeecb678e5783c5))
- prevent animation on initial page load
([570463a4](https://github.com/angular/angular.js/commit/570463a465fae02efc33e5a1fa963437cdc275dd))
- skip animation on first render
([1351ba26](https://github.com/angular/angular.js/commit/1351ba2632b5011ad6eaddf004a7f0411bea8453))
- **ngPattern:** allow modifiers on inline ng-pattern
([12b6deb1](https://github.com/angular/angular.js/commit/12b6deb1ce99df64e2fc91a06bf05cd7f4a3a475),
[#1437](https://github.com/angular/angular.js/issues/1437))
- **ngRepeat:**
- correctly iterate over array-like objects
([1d8e11dd](https://github.com/angular/angular.js/commit/1d8e11ddfbd6b08ff02df4331f6df125f49da3dc),
[#2546](https://github.com/angular/angular.js/issues/2546))
- prevent initial duplicates
([a0bc71e2](https://github.com/angular/angular.js/commit/a0bc71e27107c58282e71415c4e8d89e916ae99c))
- **ngView:** accidentally compiling leaving content
([9956baed](https://github.com/angular/angular.js/commit/9956baedd73d5e8d0edd04c9eed368bd3988444b))
- **ngAnimate:**
- eval ng-animate expression on each animation
([fd21c750](https://github.com/angular/angular.js/commit/fd21c7502f0a25364a810c26ebeecb678e5783c5))
- prevent animation on initial page load
([570463a4](https://github.com/angular/angular.js/commit/570463a465fae02efc33e5a1fa963437cdc275dd))
- skip animation on first render
([1351ba26](https://github.com/angular/angular.js/commit/1351ba2632b5011ad6eaddf004a7f0411bea8453))
- **ngPattern:** allow modifiers on inline ng-pattern
([12b6deb1](https://github.com/angular/angular.js/commit/12b6deb1ce99df64e2fc91a06bf05cd7f4a3a475),
[#1437](https://github.com/angular/angular.js/issues/1437))
- **ngRepeat:**
- correctly iterate over array-like objects
([1d8e11dd](https://github.com/angular/angular.js/commit/1d8e11ddfbd6b08ff02df4331f6df125f49da3dc),
[#2546](https://github.com/angular/angular.js/issues/2546))
- prevent initial duplicates
([a0bc71e2](https://github.com/angular/angular.js/commit/a0bc71e27107c58282e71415c4e8d89e916ae99c))
- **ngView:** accidentally compiling leaving content
([9956baed](https://github.com/angular/angular.js/commit/9956baedd73d5e8d0edd04c9eed368bd3988444b))
- **scenario runner:** correct bootstrap issue on IE
([ab755a25](https://github.com/angular/angular.js/commit/ab755a25f9ca3f3f000623071d8de3ddc4b1d78e))
@@ -139,11 +792,21 @@ _Note: This release also contains all bug fixes available in [1.0.7](#1.0.7)._
## Breaking Changes
- **$animator/ngAnimate:**
- **$animator/ngAnimate:** due to [11f712bc](https://github.com/angular/angular.js/commit/11f712bc3e310302eb2e8691cf6d110bdcde1810),
css transition classes changed from `foo-setup`/`foo-start` to `foo`/`foo-active`
The CSS transition classes have changed suffixes. To migrate rename
.foo-setup {...} to .foo {...}
.foo-start {...} to .foo-active {...}
or for type: enter, leave, move, show, hide
.foo-type-setup {...} to .foo-type {...}
.foo-type-start {...} to .foo-type-active {...}
- **$resource:** due to [53061363](https://github.com/angular/angular.js/commit/53061363c7aa1ab9085273d269c6f04ac2162336),
A `/` followed by a `.`, in the last segment of the URL template is now collapsed into a single `.` delimiter.
a `/` followed by a `.`, in the last segment of the URL template is now collapsed into a single `.` delimiter.
For example: `users/.json` will become `users.json`. If your server relied upon this sequence then it will no longer
work. In this case you can now escape the `/.` sequence with `/\.`
+59 -2
View File
@@ -7,6 +7,9 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-ddescribe-iit');
grunt.loadNpmTasks('grunt-merge-conflict');
grunt.loadNpmTasks('grunt-parallel');
grunt.loadTasks('lib/grunt');
var NG_VERSION = util.getVersion();
@@ -21,6 +24,20 @@ module.exports = function(grunt) {
grunt.initConfig({
NG_VERSION: NG_VERSION,
parallel: {
travis: {
options: {
stream: true,
},
tasks: [
util.parallelTask('test:modules'),
util.parallelTask('test:jquery'),
util.parallelTask('test:jqlite'),
util.parallelTask('test:e2e')
]
}
},
connect: {
devserver: {
options: {
@@ -40,7 +57,29 @@ module.exports = function(grunt) {
}
}
},
testserver: {}
testserver: {
options: {
// We use end2end task (which does not start the webserver)
// and start the webserver as a separate process (in travis_build.sh)
// to avoid https://github.com/joyent/libuv/issues/826
port: 8000,
hostname: '0.0.0.0',
middleware: function(connect, options){
return [
function(req, resp, next) {
// cache get requests to speed up tests on travis
if (req.method === 'GET') {
resp.setHeader('Cache-control', 'public, max-age=3600');
}
next();
},
connect.favicon('images/favicon.ico'),
connect.static(options.base)
];
}
}
}
},
@@ -137,6 +176,23 @@ module.exports = function(grunt) {
},
"ddescribe-iit": {
files: [
'test/**/*.js',
'!test/ngScenario/DescribeSpec.js'
]
},
"merge-conflict": {
files: [
'src/**/*',
'test/**/*',
'docs/**/*',
'css/**/*'
]
},
copy: {
i18n: {
files: [
@@ -148,7 +204,7 @@ module.exports = function(grunt) {
compress: {
build: {
options: {archive: 'build/' + dist +'.zip'},
options: {archive: 'build/' + dist +'.zip', mode: 'zip'},
src: ['**'], cwd: 'build', expand: true, dot: true, dest: dist + '/'
}
},
@@ -167,5 +223,6 @@ module.exports = function(grunt) {
grunt.registerTask('test:e2e', ['connect:testserver', 'test:end2end']);
grunt.registerTask('webserver', ['connect:devserver']);
grunt.registerTask('package', ['clean', 'buildall', 'minall', 'docs', 'copy', 'write', 'compress']);
grunt.registerTask('ci-checks', ['ddescribe-iit', 'merge-conflict']);
grunt.registerTask('default', ['package']);
};
+23
View File
@@ -0,0 +1,23 @@
Using AngularJS with the Closure Compiler
=========================================
The Closure Compiler project contains externs definitions for AngularJS
JavaScript in its `contrib/externs` directory.
The definitions contain externs for use with the Closure compiler (aka
JSCompiler). Passing these files to the --externs parameter of a compiler
pass allows using type annotations for AngularJS objects. For example,
Angular's $scope objects can be annotated as:
```js
/** @type {angular.Scope} */
var scope = $scope;
```
This allows JSCompiler to type check accesses to scope, give warnings about
missing methods or incorrect arguments, and also prevents renaming of property
accesses with advanced compilation.
The externs are incomplete and maintained on an as-needed basis, but strive to
be correct. Externs for individual modules should be added in separate files.
See https://developers.google.com/closure/compiler/
+1
View File
@@ -16,6 +16,7 @@ it makes development fun!
* API Docs: http://docs.angularjs.org/api
* Developer Guide: http://docs.angularjs.org/guide
* Contribution guidelines: http://docs.angularjs.org/misc/contribute
* Dashboard: http://dashboard.angularjs.org
Building AngularJS
---------
+19 -53
View File
@@ -94,7 +94,6 @@ angularFiles = {
'test/matchers.js',
'test/ngScenario/*.js',
'test/ngScenario/output/*.js',
'test/ngScenario/jstd-scenario-adapter/*.js',
'test/*.js',
'test/auto/*.js',
'test/bootstrap/*.js',
@@ -109,37 +108,30 @@ angularFiles = {
'test/ngMock/*.js'
],
'jstd': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'karma': [
'lib/jquery/jquery.js',
'test/jquery_remove.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'jstdExclude': [
'karmaExclude': [
'test/jquery_alias.js',
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js'
],
'jstdScenario': [
'karmaScenario': [
'build/angular-scenario.js',
'build/jstd-scenario-adapter-config.js',
'build/jstd-scenario-adapter.js',
'build/docs/docs-scenario.js'
],
"jstdModules": [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
"karmaModules": [
'build/angular.js',
'src/ngMock/angular-mocks.js',
'src/ngCookies/cookies.js',
@@ -156,39 +148,20 @@ angularFiles = {
'test/ngSanitize/filter/*.js'
],
'jstdPerf': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'@angularSrc',
'@angularSrcModules',
'src/ngMock/angular-mocks.js',
'perf/data/*.js',
'perf/testUtils.js',
'perf/*.js'
],
'jstdPerfExclude': [
'src/ng/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js'
],
'jstdJquery': [
'lib/jasmine/jasmine.js',
'lib/jasmine-jstd-adapter/JasmineAdapter.js',
'karmaJquery': [
'lib/jquery/jquery.js',
'test/jquery_alias.js',
'@angularSrc',
'src/publishExternalApis.js',
'@angularSrcModules',
'@angularScenario',
'src/ngScenario/jstd-scenario-adapter/Adapter.js',
'@angularTest',
'example/personalLog/*.js',
'example/personalLog/test/*.js'
],
'jstdJqueryExclude': [
'karmaJqueryExclude': [
'src/angular-bootstrap.js',
'src/ngScenario/angular-bootstrap.js',
'test/jquery_remove.js'
@@ -196,29 +169,22 @@ angularFiles = {
};
if (exports) {
exports.files = angularFiles
exports.mergeFiles = function mergeFiles() {
exports.files = angularFiles;
exports.mergeFilesFor = function() {
var files = [];
[].splice.call(arguments, 0).forEach(function(file) {
if (file.match(/karma/)) {
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);
}
}
});
}
Array.prototype.slice.call(arguments, 0).forEach(function(filegroup) {
angularFiles[filegroup].forEach(function(file) {
// replace @ref
var match = file.match(/^\@(.*)/);
if (match) {
files = files.concat(angularFiles[match[1]]);
} else {
files.push(file);
}
});
});
return files;
}
};
}
+1 -1
View File
@@ -192,7 +192,7 @@ var getPreviousTag = function() {
var generate = function(version, file) {
getPreviousTag().then(function(tag) {
console.log('Reading git log since', tag);
readGitLog('^fix|^feat|Breaks', tag).then(function(commits) {
readGitLog('^fix|^feat|BREAKING', tag).then(function(commits) {
console.log('Parsed', commits.length, 'commits');
console.log('Generating changelog to', file || 'stdout', '(', version, ')');
writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version);
+1 -1
View File
@@ -2,7 +2,7 @@
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],
.ng-cloak, .x-ng-cloak {
display: none;
display: none !important;
}
ng\:form {
+2 -2
View File
@@ -10,9 +10,9 @@
}
</script>
<div ng-controller="HelloCntl">
Your name: <input type="text" ng-model="name" value="World"/>
Your name: <input type="text" ng-model="name"/>
<hr/>
Hello {{name}}!
Hello {{name || "World"}}!
</div>
</doc:source>
<doc:scenario>
+13 -11
View File
@@ -7,8 +7,7 @@
This page explains the Angular initialization process and how you can manually initialize Angular
if necessary.
# Angular `<script>` Tag
## Angular `<script>` Tag
This example shows the recommended path for integrating Angular with what we call automatic
initialization.
@@ -50,7 +49,7 @@ initialization.
# Automatic Initialization
## Automatic Initialization
Angular initializes automatically upon `DOMContentLoaded` event, at which point Angular looks for
the {@link api/ng.directive:ngApp `ng-app`} directive which
@@ -77,16 +76,14 @@ will:
# Manual Initialization
## Manual Initialization
If you need to have more control over the initialization process, you can use a manual
bootstrapping method instead. Examples of when you'd need to do this include using script loaders
or the need to perform an operation before Angular compiles a page.
Here is an example of manually initializing Angular. The example is equivalent to using the {@link
api/ng.directive:ngApp ng-app} directive.
Here is an example of manually initializing Angular:
<pre>
<!doctype html>
@@ -96,17 +93,22 @@ api/ng.directive:ngApp ng-app} directive.
<script src="http://code.angularjs.org/angular.js"></script>
<script>
angular.element(document).ready(function() {
angular.bootstrap(document);
angular.module('myApp', []);
angular.bootstrap(document, ['myApp']);
});
</script>
</body>
</html>
</pre>
Note that we have provided the name of our application module to be loaded into the injector as the second
parameter of the {@link api/angular.bootstrap} function. Notice that `angular.bootstrap` will not create modules
on the fly. You must create any custom {@link guide/module modules} before you pass them as a parameter.
This is the sequence that your code should follow:
1. After the page and all of the code is loaded, find the root of the HTML template, which is
typically the root of the document.
1. After the page and all of the code is loaded, find the root element of your AngularJS
application, which is typically the root of the document.
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the template into an
2. Call {@link api/angular.bootstrap} to {@link compiler compile} the element into an
executable, bi-directionally bound application.
+11 -12
View File
@@ -6,21 +6,21 @@
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
and even create new HTML elements or attributes with custom behavior. Angular calls these behavior
extensions {@link api/ng.$compileProvider#directive directives}.
HTML has a lot of constructs for formatting the HTML for static documents in a declarative fashion.
For example if something needs to be centered, there is no need to provide instructions to the
browser how the window size needs to be divided in half so that center is found, and that this
center needs to be aligned with the text's center. Simply add `align="center"` attribute to any
browser how the window size needs to be divided in half so that the center is found, and that this
center needs to be aligned with the text's center. Simply add an `align="center"` attribute to any
element to achieve the desired behavior. Such is the power of declarative language.
But the declarative language is also limited, since it does not allow you to teach the browser new
syntax. For example there is no easy way to get the browser to align the text at 1/3 the position
instead of 1/2. What is needed is a way to teach browser new HTML syntax.
instead of 1/2. What is needed is a way to teach the browser new HTML syntax.
Angular comes pre-bundled with common directives which are useful for building any app. We also
expect that you will create directives that are specific to your app. These extension become a
expect that you will create directives that are specific to your app. These extensions become a
Domain Specific Language for building your application.
All of this compilation takes place in the web browser; no server side or pre-compilation step is
@@ -39,17 +39,16 @@ process happens in two phases.
scope model are reflected in the view, and any user interactions with the view are reflected
in the scope model. This makes the scope model the single source of truth.
Some directives such {@link api/ng.directive:ngRepeat
`ng-repeat`} clone DOM elements once for each item in collection. Having a compile and link phase
improves performance since the cloned template only needs to be compiled once, and then linked
once for each clone instance.
Some directives such as {@link api/ng.directive:ngRepeat `ng-repeat`} clone DOM elements once
for each item in a collection. Having a compile and link phase improves performance since the
cloned template only needs to be compiled once, and then linked once for each clone instance.
# Directive
A directive is a behavior which should be triggered when specific HTML constructs are encountered in
the compilation process. The directives can be placed in element names, attributes, class names, as
well as comments. Here are some equivalent examples of invoking the {@link
A directive is a behavior which should be triggered when specific HTML constructs are encountered
during the compilation process. The directives can be placed in element names, attributes, class
names, as well as comments. Here are some equivalent examples of invoking the {@link
api/ng.directive:ngBind `ng-bind`} directive.
<pre>
+1 -17
View File
@@ -45,8 +45,6 @@ This is how we get the ball rolling (refer to the diagram and example below):
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
`Hello World!`
<div class="clear">
</div>
<example>
<file name="index.html">
<p ng-init=" name='World' ">Hello {{name}}!</p>
@@ -126,8 +124,6 @@ user enters text into the text field.
the JavaScript execution context.
7. The browser re-renders the view with update text.
<div class="clear">
</div>
<example>
<file name="index.html">
<input ng-model="name">
@@ -147,8 +143,6 @@ The following example demonstrates how the `name` {@link guide/expression expres
into a different value depending on which scope it is evaluated in. The example is followed by
a diagram depicting the scope boundaries.
<div class="clear">
</div>
<div class="show-scope">
<example>
<file name="index.html">
@@ -204,8 +198,6 @@ The separation of the controller and the view is important because:
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
and testability.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-controller="MyCtrl">
@@ -239,10 +231,6 @@ to inherit from or special accessor methods for accessing or changing the model.
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
<div class="clear">
</div>
<a name="view"></a>
# View
@@ -269,9 +257,6 @@ rendering the view compared to most other templating systems.
continuously updating view which does not need template model re-merging. Your model becomes
the single source-of-truth for your view.
<div class="clear">
</div>
<example>
<file name="index.html">
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
@@ -292,7 +277,7 @@ rendering the view compared to most other templating systems.
# Directives
A directive is a behavior or DOM transformation which is triggered by the presence of a custom attribute,
element name, or a class name. A directive allows you to extend the HTML vocabulary in a
element name, class name or comment. A directive allows you to extend the HTML vocabulary in a
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
in HTML.
@@ -369,7 +354,6 @@ api/AUTO.$injector injector} asks the instance factory to create a new instance.
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
as a {@link api/AUTO.$provide provider}.
<div class='clear'></div>
<pre>
// Create a module
var myModule = angular.module('myModule', [])
+16 -12
View File
@@ -38,9 +38,9 @@ it('should filter results', function() {
});
</pre>
This scenario describes the requirements of a Buzz Client, specifically, that it should be able to
filter the stream of the user. It starts by entering a value in the 'user' input field, clicking
filter the stream of the user. It starts by entering a value in the input field with ng-model="user", clicking
the only button on the page, and then it verifies that there are 10 items listed. It then enters
'Bees' in the 'filterText' input field and verifies that the list is reduced to a single item.
'Bees' in the input field with ng-model='filterText' and verifies that the list is reduced to a single item.
The API section below lists the available commands and expectations for the Runner.
@@ -110,16 +110,16 @@ Scopes the next DSL element selection.
Returns the value of the first binding matching the given `name`.
## input(name).enter(value)
Enters the given `value` in the text field with the given `name`.
Enters the given `value` in the text field with the corresponding ng-model `name`.
## input(name).check()
Checks/unchecks the checkbox with the given `name`.
Checks/unchecks the checkbox with the corresponding ng-model `name`.
## input(name).select(value)
Selects the given `value` in the radio button with the given `name`.
Selects the given `value` in the radio button with the corresponding ng-model `name`.
## input(name).val()
Returns the current value of an input field with the given `name`.
Returns the current value of an input field with the corresponding ng-model `name`.
## repeater(selector, label).count()
Returns the number of rows in the repeater matching the given jQuery `selector`. The `label` is
@@ -134,10 +134,10 @@ Returns an array with the values in the column with the given `binding` in the r
the given jQuery `selector`. The `label` is used for test output.
## select(name).option(value)
Picks the option with the given `value` on the select with the given `name`.
Picks the option with the given `value` on the select with the given ng-model `name`.
## select(name).option(value1, value2...)
Picks the options with the given `values` on the multi select with the given `name`.
## select(name).options(value1, value2...)
Picks the options with the given `values` on the multi select with the given ng-model `name`.
## element(selector, label).count()
Returns the number of elements that match the given jQuery `selector`. The `label` is used for test
@@ -228,7 +228,7 @@ conditional assertions or element selection. Even though you should generally tr
`element(...).query(fn)`. The following code listing shows how this function can be used to delete
added entries (where an entry is some domain object) using the application's web interface.
Imagine the application to be structure into two views:
Imagine the application to be structured into two views:
1. *Overview view* which lists all the added entries in a table and
2. a *detail view* which shows the entries' details and contains a delete button. When clicking the
@@ -275,7 +275,7 @@ beforeEach(function () {
In order to understand what is happening, we should emphasize that ngScenario calls are not
immediately executed, but queued (in ngScenario terms, we would be talking about adding
future actions). If we had only one entry in our table, than the following future actions
future actions). If we had only one entry in our table, then the following future actions
would be queued:
<pre>
@@ -301,4 +301,8 @@ element('.btn-danger').click();
element('table tbody').query(function (tbody, done) { ... });
element('table tbody a');
element('.btn-danger').click();
</pre>
</pre>
# Caveats
ngScenario does not work with apps that manually bootstrap using angular.bootstrap. You must use the ng-app directive.
@@ -2,79 +2,117 @@
@name Developer Guide: About MVC in Angular: Understanding the Controller Component
@description
In Angular, a controller is a JavaScript function(type/class) that is used to augment instances of
angular {@link scope Scope}, excluding the root scope.
# Understanding Controllers
Use controllers to:
In Angular, a Controller is a JavaScript **constructor function** that is used to augment the
{@link scope Angular Scope}.
- Set up the initial state of a scope object.
- Add behavior to the scope object.
When a Controller is attached to the DOM via the {@link api/ng.directive:ngController ng-controller}
directive, Angular will instantiate a new Controller object, using the specified Controller's
**constructor function**. A new **child scope** will be available as an injectable parameter to the
Controller's constructor function as `$scope`.
# Setting up the initial state of a scope object
Use Controllers to:
Typically, when you create an application you need to set up an initial state for an Angular scope.
- Set up the initial state of the `$scope` object.
- Add behavior to the `$scope` object.
Angular applies (in the sense of JavaScript's `Function#apply`) the controller constructor function
to a new Angular scope object, which sets up an initial scope state. This means that Angular never
creates instances of the controller type (by invoking the `new` operator on the controller
constructor). Constructors are always applied to an existing scope object.
# Setting up the initial state of a `$scope` object
You set up the initial state of a scope by creating model properties. For example:
Typically, when you create an application you need to set up the initial state for the Angular
`$scope`. You set up the initial state of a scope by attaching properties to the `$scope` object.
The properties contain the **view model** (the model that will be presented by the view). All the
`$scope` properties will be available to the template at the point in the DOM where the Controller
is registered.
function GreetingCtrl($scope) {
$scope.greeting = 'Hola!';
}
The following example shows a very simple constructor function for a Controller, `GreetingCtrl`,
which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`:
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
<pre>
function GreetingCtrl($scope) {
$scope.greeting = 'Hola!';
}
</pre>
**NOTE**: Many of the examples in the documentation show the creation of functions
in the global scope. This is only for demonstration purposes - in a real
application you should use the `.controller` method of your Angular module for
your application as follows:
Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the
template:
var myApp = angular.module('myApp',[]);
<pre>
<div ng-controller="GreetingCtrl">
{{ greeting }}
</div>
</pre>
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is
not recommended. In a real application you should use the `.controller` method of your
{@link module Angular Module} for your application as follows:
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
</pre>
We have used an **inline injection annotation** to explicitly specify the dependency
of the Controller on the `$scope` service provided by Angular. See the guide on
{@link http://docs.angularjs.org/guide/di Dependency Injection} for more information.
Note also that we use the array notation to explicitly specify the dependency
of the controller on the `$scope` service provided by Angular.
# Adding Behavior to a Scope Object
Behavior on an Angular scope object is in the form of scope method properties available to the
template/view. This behavior interacts with and modifies the application model.
In order to react to events or execute computation in the view we must provide behavior to the
scope. We add behavior the scope by attaching methods to the `$scope` object. These methods are
then available to be called from the template/view.
The following example uses a Controller to add a method to the scope, which doubles a number:
<pre>
var myApp = angular.module('myApp',[]);
myApp.controller('DoubleCtrl', ['$scope', function($scope) {
$scope.double = function(value) { return value * 2; };
}]);
</pre>
Once the Controller has been attached to the DOM, the `double` method can be invoked in an Angular
expression in the template:
<pre>
<div ng-controller="DoubleCtrl">
Two times <input ng-model="num"> equals {{ double(num) }}
</div>
</pre>
As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
objects (or primitives) assigned to the scope become model properties. Any methods assigned to
the scope are available in the template/view, and can be invoked via angular expressions
and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}).
# Using Controllers Correctly
In general, a controller shouldn't try to do too much. It should contain only the business logic
In general, a Controller shouldn't try to do too much. It should contain only the business logic
needed for a single view.
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
controllers into services and then using these services in controllers via dependency injection.
The most common way to keep Controllers slim is by encapsulating work that doesn't belong to
controllers into services and then using these services in Controllers via dependency injection.
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
Services} sections of this guide.
Do not use controllers for:
Do not use Controllers for:
- Any kind of DOM manipulation — Controllers should contain only business logic. DOM
manipulationthe presentation logic of an applicationis well known for being hard to test.
Putting any presentation logic into controllers significantly affects testability of the business
manipulation (the presentation logic of an application) is well known for being hard to test.
Putting any presentation logic into Controllers significantly affects testability of the business
logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If
you have to perform your own manual DOM manipulation, encapsulate the presentation logic in
{@link guide/directive directives}.
- Input formatting — Use {@link forms angular form controls} instead.
- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead.
- To run stateless or stateful code shared across controllers — Use {@link dev_guide.services angular
- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular
services} instead.
- To instantiate or manage the life-cycle of other components (for example, to create service
instances).
- Managing the life-cycle of other components (for example, to create service instances).
# Associating Controllers with Angular Scope Objects
@@ -83,189 +121,208 @@ You can associate controllers with scope objects implicitly via the {@link api/n
directive} or {@link api/ng.$route $route service}.
## Controller Constructor and Methods Example
## Simple Spicy Controller Example
To illustrate how the controller component works in angular, let's create a little app with the
To illustrate further how Controller components work in Angular, let's create a little app with the
following components:
- A {@link dev_guide.templates template} with two buttons and a simple message
- A model consisting of a string named `spice`
- A controller with two functions that set the value of `spice`
- A Controller with two functions that set the value of `spice`
The message in our template contains a binding to the `spice` model, which by default is set to the
string "very". Depending on which button is clicked, the `spice` model is set to `chili` or
`jalapeño`, and the message is automatically updated by data-binding.
<doc:example module="spicyApp1">
<doc:source>
<div ng-app="spicyApp1" ng-controller="SpicyCtrl">
<button ng-click="chiliSpicy()">Chili</button>
<button ng-click="jalapenoSpicy()">Jalapeño</button>
<p>The food is {{spice}} spicy!</p>
</div>
<script>
var myApp = angular.module('spicyApp1', []);
## A Spicy Controller Example
<pre>
<body ng-controller="SpicyCtrl">
<button ng-click="chiliSpicy()">Chili</button>
<button ng-click="jalapenoSpicy()">Jalapeño</button>
<p>The food is {{spice}} spicy!</p>
</body>
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
}
$scope.jalapenoSpicy = function() {
$scope.spice = 'jalapeño';
}
}
</pre>
myApp.controller('SpicyCtrl', ['$scope', function($scope){
$scope.spicy = 'very';
$scope.chiliSpicy = function() {
$scope.spice = 'chili';
};
$scope.jalapenoSpicy = function() {
$scope.spice = 'jalapeño';
};
}]);
</script>
</doc:source>
</doc:example>
Things to notice in the example above:
- The `ngController` directive is used to (implicitly) create a scope for our template, and the
scope is augmented (managed) by the `SpicyCtrl` controller.
- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the
scope is augmented (managed) by the `SpicyCtrl` Controller.
- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name
starts with capital letter and ends with "Ctrl" or "Controller".
- Assigning a property to `$scope` creates or updates the model.
- Controller methods can be created through direct assignment to scope (the `chiliSpicy` method)
- Both controller methods are available in the template (for the `body` element and and its
children).
- NB: Previous versions of Angular (pre 1.0 RC) allowed you to use `this` interchangeably with
the $scope method, but this is no longer the case. Inside of methods defined on the scope
`this` and $scope are interchangeable (angular sets `this` to $scope), but not otherwise
inside your controller constructor.
- NB: Previous versions of Angular (pre 1.0 RC) added prototype methods into the scope
automatically, but this is no longer the case; all methods need to be added manually to
the scope.
- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method)
- The Controller methods and properties are available in the template (for the `<div>` element and
and its children).
## Spicy Arguments Example
Controller methods can also take arguments, as demonstrated in the following variation of the
previous example.
## Controller Method Arguments Example
<doc:example module="spicyApp2">
<doc:source>
<div ng-app="spicyApp2" ng-controller="SpicyCtrl">
<input ng-model="customSpice">
<button ng-click="spicy('chili')">Chili</button>
<button ng-click="spicy(customSpice)">Custom spice</button>
<p>The food is {{spice}} spicy!</p>
</div>
<script>
var myApp = angular.module('spicyApp2', []);
<pre>
<body ng-controller="SpicyCtrl">
<input ng-model="customSpice" value="wasabi">
<button ng-click="spicy('chili')">Chili</button>
<button ng-click="spicy(customSpice)">Custom spice</button>
<p>The food is {{spice}} spicy!</p>
</body>
myApp.controller('SpicyCtrl', ['$scope', function($scope){
$scope.customSpice = "wasabi";
$scope.spice = 'very';
$scope.spicy = function(spice){
$scope.spice = spice;
};
}]);
</script>
</doc:source>
</doc:example>
function SpicyCtrl($scope) {
$scope.spice = 'very';
$scope.spicy = function(spice) {
$scope.spice = spice;
}
}
</pre>
Notice that the `SpicyCtrl` controller now defines just one method called `spicy`, which takes one
argument called `spice`. The template then refers to this controller method and passes in a string
Notice that the `SpicyCtrl` Controller now defines just one method called `spicy`, which takes one
argument called `spice`. The template then refers to this Controller method and passes in a string
constant `'chili'` in the binding for the first button and a model property `spice` (bound to an
input box) in the second button.
## Scope Inheritance Example
## Controller Inheritance Example
It is common to attach Controllers at different levels of the DOM hierarchy. Since the
{@link api/ng.directive:ngController ng-controller} directive creates a new child scope, we get a
hierarchy of scopes that inherit from each other. The `$scope` that each Controller receives will
have access to properties and methods defined by Controllers higher up the hierarchy.
See {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes Understanding Scopes} for
more information about scope inheritance.
Controller inheritance in Angular is based on {@link api/ng.$rootScope.Scope Scope} inheritance. Let's
have a look at an example:
<doc:example module="scopeInheritance">
<doc:source>
<div ng-app="scopeInheritance" class="spicy">
<div ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<pre>
<body ng-controller="MainCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p ng-controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
</div>
</body>
<div ng-controller="ChildCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
function MainCtrl($scope) {
$scope.timeOfDay = 'morning';
$scope.name = 'Nikki';
}
<div ng-controller="BabyCtrl">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
</div>
</div>
<style>
div.spicy div {
padding: 10px;
border: solid 2px blue;
}
</style>
<script>
var myApp = angular.module('scopeInheritance', []);
myApp.controller('MainCtrl', ['$scope', function($scope){
$scope.timeOfDay = 'morning';
$scope.name = 'Nikki';
}]);
myApp.controller('ChildCtrl', ['$scope', function($scope){
$scope.name = 'Mattie';
}]);
myApp.controller('BabyCtrl', ['$scope', function($scope){
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}]);
</script>
</doc:source>
</doc:example>
function ChildCtrl($scope) {
$scope.name = 'Mattie';
}
function BabyCtrl($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbreak Baby';
}
</pre>
Notice how we nested three `ngController` directives in our template. This template construct will
result in 4 scopes being created for our view:
Notice how we nested three `ng-controller` directives in our template. This will result in four
scopes being created for our view:
- The root scope
- The `MainCtrl` scope, which contains `timeOfDay` and `name` models
- The `ChildCtrl` scope, which shadows the `name` model from the previous scope and inherits the
`timeOfDay` model
- The `BabyCtrl` scope, which shadows both the `timeOfDay` model defined in `MainCtrl` and `name`
model defined in the ChildCtrl
- The `MainCtrl` scope, which contains `timeOfDay` and `name` properties
- The `ChildCtrl` scope, which inherits the `timeOfDay` property but overrides (hides) the `name`
property from the previous
- The `BabyCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl`
and the `name` property defined in `ChildCtrl`
Inheritance works between controllers in the same way as it does with models. So in our previous
examples, all of the models could be replaced with controller methods that return string values.
Note: Standard prototypical inheritance between two controllers doesn't work as one might expect,
because as we mentioned earlier, controllers are not instantiated directly by Angular, but rather
are applied to the scope object.
Inheritance works with methods in the same way as it does with properties. So in our previous
examples, all of the properties could be replaced with methods that return string values.
## Testing Controllers
Although there are many ways to test a controller, one of the best conventions, shown below,
involves injecting the `$rootScope` and `$controller`
Although there are many ways to test a Controller, one of the best conventions, shown below,
involves injecting the {@link api/ng.$rootScope $rootScope} and {@link api/ng.$controller $controller}:
Controller Function:
**Controller Definition:**
<pre>
function myController($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
var myApp = angular.module('myApp',[]);
$scope.spice = "habanero";
}
myApp.controller('MyController', function($scope) {
$scope.spices = [{"name":"pasilla", "spiciness":"mild"},
{"name":"jalapeno", "spiceiness":"hot hot hot!"},
{"name":"habanero", "spiceness":"LAVA HOT!!"}];
$scope.spice = "habanero";
});
</pre>
Controller Test:
**Controller Test:**
<pre>
describe('myController function', function() {
describe('myController', function() {
var scope;
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
var ctrl = $controller(myController, {$scope: scope});
$scope = $rootScope.$new();
$controller('MyController', {$scope: $scope});
}));
it('should create "spices" model with 3 spices', function() {
expect(scope.spices.length).toBe(3);
expect($scope.spices.length).toBe(3);
});
it('should set the default value of spice', function() {
expect(scope.spice).toBe('habanero');
expect($scope.spice).toBe('habanero');
});
});
});
</pre>
If you need to test a nested controller you need to create the same scope hierarchy
in your test that exists in the DOM.
If you need to test a nested Controller you need to create the same scope hierarchy
in your test that exists in the DOM:
<pre>
describe('state', function() {
var mainScope, childScope, babyScope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
$controller('MainCtrl', {$scope: mainScope});
childScope = mainScope.$new();
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
babyScope = childCtrl.$new();
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
$controller('ChildCtrl', {$scope: childScope});
babyScope = childScope.$new();
$controller('BabyCtrl', {$scope: babyScope});
}));
it('should have over and selected', function() {
@@ -28,7 +28,7 @@ occurs in controllers:
* Use an {@link expression angular expression} with an assignment operator in templates:
<button ng-click="{{foo='ball'}}">Click me</button>
<button ng-click="{{foo='bar'}}">Click me</button>
* Use {@link api/ng.directive:ngInit ngInit directive} in templates (for toy/example apps
only, not recommended for real applications):
@@ -14,10 +14,10 @@ changes to $location are reflected into the browser address bar.
- Exposes the current URL in the browser address bar, so you can
- Watch and observe the URL.
- Change the URL.
- Synchronizes the URL with the browser when the user
- Changes the address bar.
- Clicks the back or forward button (or clicks a History link).
- Clicks on a link.
- Maintains synchronization between itself and the browser's URL when the user
- Changes the address in the browser's address bar.
- Clicks the back or forward button in the browser (or clicks a History link).
- Clicks on a link in the page.
- Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
@@ -121,6 +121,8 @@ All of the setter methods return the same `$location` object to allow chaining.
change multiple segments in one go, chain setters like this:
<pre>$location.path('/newValue').search({key: value});</pre>
## Replace method
There is a special `replace` method which can be used to tell the $location service that the next
time the $location service is synced with the browser, the last history record should be replaced
instead of creating a new one. This is useful when you want to implement redirection, which would
@@ -212,7 +214,7 @@ In this mode, `$location` uses Hashbang URLs in all browsers.
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix = '!';
$locationProvider.hashPrefix('!');
},
function($location) {
// open http://host.com/base/index.html#!/a
@@ -261,7 +263,7 @@ having to worry about whether the browser displaying your app supports the histo
it('should show example', inject(
function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix = '!';
$locationProvider.hashPrefix('!');
},
function($location) {
// in browser with HTML5 history support:
@@ -321,6 +323,14 @@ reload to the original link.
Example: `<a href="http://angularjs.org/">link</a>`
- Links starting with '/' that lead to a different base path when base is defined<br>
Example: `<a href="/not-my-base/link">link</a>`
When running Angular in the root of a domain, along side perhaps a normal application in the same
directory, the "otherwise" route handler will try to handle all the URLs, including ones that map
to static files.
To prevent this, you can set your base href for the app to `<base href=".">` and then prefix links
to URLs that should be handled with `.`. Now, links to locations, which are not to be routed by Angular,
are not prefixed with `.` and will not be intercepted by the `otherwise` rule in your `$routeProvider`.
### Server side
@@ -57,6 +57,7 @@ myController.$inject = ['$scope','notify'];
<p>Let's try this simple notify service, injected into the controller...</p>
<input ng-init="message='test'" ng-model="message" >
<button ng-click="callNotify(message);">NOTIFY</button>
<p>(you have to click 3 times to see an alert)</p>
</div>
</doc:source>
<doc:scenario>
@@ -98,6 +99,7 @@ function myController($scope, notify) {
<p>Let's try the notify service, that is implicitly injected into the controller...</p>
<input ng-init="message='test'" ng-model="message">
<button ng-click="callNotify(message);">NOTIFY</button>
<p>(you have to click 3 times to see an alert)</p>
</div>
</doc:source>
</doc:example>
@@ -7,9 +7,17 @@ Angular sets these CSS classes. It is up to your application to provide useful s
# CSS classes used by angular
* `ng-scope`
- **Usage:** angular applies this class to any element that where a new {@link api/ng.$rootScope.Scope scope}
is defined. (see {@link guide/scope scope} guide for more information about scopes)
* `ng-binding`
- **Usage:** angular applies this class to any element that is attached to a data binding, via `ng-bind` or
{{}} curly braces, for example. (see {@link guide/dev_guide.templates.databinding databinding} guide)
* `ng-invalid`, `ng-valid`
- **Usage:** angular applies this class to an input widget element if that element's input does
not pass validation. (see {@link api/ng.directive:input input} directive).
not pass validation. (see {@link api/ng.directive:input input} directive)
* `ng-pristine`, `ng-dirty`
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
@@ -8,7 +8,7 @@ as the first argument. Any filter arguments are passed in as additional argument
function.
The following sample filter reverses a text string. In addition, it conditionally makes the
text upper-case and assigns color.
text upper-case.
<doc:example module="MyReverseModule">
<doc:source>
+13 -24
View File
@@ -3,7 +3,7 @@
@description
JavaScript is a dynamically typed language which comes with great power of expression, but it also
comes with almost no-help from the compiler. For this reason we feel very strongly that any code
comes with almost no help from the compiler. For this reason we feel very strongly that any code
written in JavaScript needs to come with a strong set of tests. We have built many features into
Angular which makes testing your Angular applications easy. So there is no excuse for not testing.
@@ -248,10 +248,11 @@ function PasswordCtrl($scope) {
and the test is straight forward
<pre>
var pc = new PasswordCtrl();
pc.password('abc');
pc.grade();
expect(pc.strength).toEqual('weak');
var $scope = {};
var pc = $controller('PasswordCtrl', { $scope: $scope });
$scope.password = 'abc';
$scope.grade();
expect($scope.strength).toEqual('weak');
</pre>
Notice that the test is not only much shorter but it is easier to follow what is going on. We say
@@ -294,14 +295,14 @@ app.directive('aGreatEye', function () {
return {
restrict: 'E',
replace: true,
template: '<h1>lidless, wreathed in flame</h1>'
template: '<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>'
};
});
</pre>
This directive is used as a tag `<a-great-eye></a-great-eye>`. It replaces the entire tag with the
template `<h1>lidless, wreathed in flame</h1>`. Now we are going to write a jasmine unit test to
verify this functionality.
template `<h1>lidless, wreathed in flame, {{1 + 1}} times</h1>`. Now we are going to write a jasmine unit test to
verify this functionality. Note that the expression `{{1 + 1}}` times will also be evaluated in the rendered content.
<pre>
describe('Unit testing great quotes', function() {
@@ -322,30 +323,18 @@ describe('Unit testing great quotes', function() {
it('Replaces the element with the appropriate content', function() {
// Compile a piece of HTML containing the directive
var element = $compile("<a-great-eye></a-great-eye>")($rootScope);
// fire all the watches, so the scope expression {{1 + 1}} will be evaluated
$rootScope.$digest();
// Check that the compiled element contains the templated content
expect(element.html()).toContain("lidless, wreathed in flame");
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
});
});
</pre>
We inject the $compile service and $rootScope before each jasmine test. The $compile service is used
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
replaced the content and "lidless, wreathed in flame" is present.
replaced the content and "lidless, wreathed in flame, 2 times" is present.
## Mocks
oue
## Global State Isolation
oue
# Preferred way of Testing
uo
## JavaScriptTestDriver
ou
## Jasmine
ou
## Sample project
See the {@link https://github.com/angular/angular-seed angular-seed} project for an example.
+20 -16
View File
@@ -24,7 +24,7 @@ There are only three ways an object or a function can get a hold of its dependen
The first two options of creating or looking up dependencies are not optimal because they hard
code the dependency. This make it difficult, if not impossible, to modify the dependencies.
code the dependency. This makes it difficult, if not impossible, to modify the dependencies.
This is especially problematic in tests, where it is often desirable to provide mock dependencies
for test isolation.
@@ -102,20 +102,20 @@ dependency lookup responsibility to the injector by declaring the dependencies a
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
dependencies of `MyController` without the controller ever knowing about the injector. This is
the best outcome. The application code simply ask for the dependencies it needs, without having to
the best outcome. The application code simply asks for the dependencies it needs, without having to
deal with the injector. This setup does not break the Law of Demeter.
# Dependency Annotation
## Dependency Annotation
How does the injector know what service needs to be injected?
How does the injector know what service needs to be injected?
The application developer needs to provide annotation information that the injector uses in order
to resolve the dependencies. Throughout Angular certain API functions are invoked using the
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
injector, as per the API documentation. The injector needs to know what services to inject into
the function. Below are three equivalent ways of annotating your code with service name
information. These can be used interchangeably as you see fit and are equivalent.
# Inferring Dependencies
### Inferring Dependencies
The simplest way to get hold of the dependencies, is to assume that the function parameter names
are the names of the dependencies.
@@ -134,10 +134,10 @@ While straightforward, this method will not work with JavaScript minifiers/obfus
rename the method parameter names. This makes this way of annotating only useful for {@link
http://www.pretotyping.org/ pretotyping}, and demo applications.
# `$inject` Annotation
### `$inject` Annotation
To allow the minifers to rename the function parameters and still be able to inject right services
the function needs to be annotate with the `$inject` property. The `$inject` property is an array
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
<pre>
@@ -147,13 +147,15 @@ of service names to inject.
MyController.$inject = ['$scope', 'greeter'];
</pre>
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
Using above code snippet as an example, '$scope' will be injected into 'renamed$scope' and 'greeter' into 'renamedGreeter'.
Care must be taken that the `$inject` annotation is kept in sync with the actual arguments in the
function declaration.
This method of annotation is useful for controller declarations since it assigns the annotation
information with the function.
# Inline Annotation
### Inline Annotation
Sometimes using the `$inject` annotation style is not convenient such as when annotating
directives.
@@ -189,27 +191,29 @@ For this reason the third annotation style is provided as well.
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
where injection is supported.
# Where can I use DI?
## Where can I use DI?
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
## DI in controllers
### DI in controllers
Controllers are classes which are responsible for application behavior. The recommended way of
declaring controllers is:
declaring controllers is using the array notation:
<pre>
var MyController = function($scope, dep1, dep2) {
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
}
MyController.$inject = ['$scope', 'dep1', 'dep2'];
...
}]);
</pre>
This avoids the creation of global functions for controllers and also protects against minification.
## Factory methods
### Factory methods
Factory methods are responsible for creating most objects in Angular. Examples are directives,
services, and filters. The factory methods are registered with the module, and the recommended way
+14 -12
View File
@@ -27,28 +27,28 @@ attribute only.)
<!-- directive: my-dir exp -->
</pre>
Directives can be invoked in many different ways, but are equivalent in the end result as shown in
the following example.
The following demonstrates the various ways a Directive (ngBind in this case) can be referenced from within a template.
<doc:example>
<doc:source >
<script>
function Ctrl1($scope) {
$scope.name = 'angular';
$scope.name = 'Max Karl Ernst Ludwig Planck (April 23, 1858 October 4, 1947)';
}
</script>
<div ng-controller="Ctrl1">
Hello <input ng-model='name'> <hr/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span ng:bind="name"&gt; <span ng:bind="name"></span> <br/>
&lt;span ng_bind="name"&gt; <span ng_bind="name"></span> <br/>
&lt;span ng-bind="name"&gt; <span ng-bind="name"></span> <br/>
&lt;span data-ng-bind="name"&gt; <span data-ng-bind="name"></span> <br/>
&lt;span x-ng-bind="name"&gt; <span x-ng-bind="name"></span> <br/>
</div>
</doc:source>
<doc:scenario>
it('should show off bindings', function() {
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular');
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text())
.toBe('Max Karl Ernst Ludwig Planck (April 23, 1858 October 4, 1947)');
});
</doc:scenario>
</doc:example>
@@ -244,7 +244,8 @@ Here's an example directive declared with a Directive Definition Object:
transclude: false,
restrict: 'A',
scope: false,
controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
function($scope, $element, $attrs, $transclude, otherInjectables) { ... }],
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
@@ -307,8 +308,9 @@ compiler}. The attributes are:
* `priority` - When there are multiple directives defined on a single DOM element, sometimes it
is necessary to specify the order in which the directives are applied. The `priority` is used
to sort the directives before their `compile` functions get called. Higher `priority` goes
first. The order of directives within the same priority is undefined.
to sort the directives before their `compile` functions get called. Priority is defined as a
number. Directives with greater numerical `priority` are compiled first. The order of directives with
the same priority is undefined. The default priority is `0`.
* `terminal` - If set to true then the current `priority` will be the last set of directives
which will execute (any directives at the current priority will still execute
@@ -496,7 +498,7 @@ The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a
link() or compile() functions - is a way of accessing:
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized access to
the attributes.
* *directive inter-communication:* All directives share the same instance of the attributes
@@ -645,10 +647,10 @@ Following is an example of building a reusable widget.
'</div>',
// The linking function will add behavior to the template
link: function(scope, element, attrs) {
// Title element
// Title element
var title = angular.element(element.children()[0]),
// Opened / closed state
opened = true;
// Opened / closed state
opened = true;
// Clicking on title should open/close the zippy
title.bind('click', toggle);
+2 -2
View File
@@ -23,8 +23,8 @@ You can think of Angular expressions as JavaScript expressions with following di
evaluation, unlike in JavaScript where the expressions are evaluated against the global
`window`.
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript,
where such evaluations generate `NullPointerExceptions`.
* **Forgiving:** expression evaluation is forgiving to `undefined` and `null`, unlike in JavaScript,
where trying to evaluate undefined properties can generate `ReferenceError` or `TypeError`.
* **No Control Flow Statements:** you cannot do any of the following in angular expression:
conditionals, loops, or throw.
+4 -4
View File
@@ -2,8 +2,8 @@
@name Forms
@description
Controls (`input`, `select`, `textarea`) are a way for user to enter data.
Form is a collection of controls for the purpose of grouping related controls together.
Controls (`input`, `select`, `textarea`) are ways for a user to enter data.
A Form is a collection of controls for the purpose of grouping related controls together.
Form and controls provide validation services, so that the user can be notified of invalid input.
This provides a better user experience, because the user gets instant feedback on how to correct the error.
@@ -154,10 +154,10 @@ This allows us to extend the above example with these features:
<script>
function Controller($scope) {
$scope.master= {};
$scope.master = {};
$scope.update = function(user) {
$scope.master= angular.copy(user);
$scope.master = angular.copy(user);
};
$scope.reset = function() {
+4 -4
View File
@@ -56,22 +56,22 @@ locale-specific file to the end of `angular.js` or `angular.min.js` file.
For example on *nix, to create an angular.js file that contains localization rules for german
locale, you can do the following:
`cat angular.js i18n/angular-locale_de-ge.js > angular_de-ge.js`
`cat angular.js i18n/angular-locale_de-de.js > angular_de-de.js`
When the application containing `angular_de-ge.js` script instead of the generic angular.js script
When the application containing `angular_de-de.js` script instead of the generic angular.js script
starts, Angular is automatically pre-configured with localization rules for the german locale.
**2. Including locale js script in index.html page**
You can also include the locale specific js file in the index.html page. For example, if one client
requires German locale, you would serve index_de-ge.html which will look something like this:
requires German locale, you would serve index_de-de.html which will look something like this:
<pre>
<html ng-app>
<head>
….
<script src="angular.js"></script>
<script src="i18n/angular-locale_de-ge.js"></script>
<script src="i18n/angular-locale_de-de.js"></script>
….
</head>
</html>
+18
View File
@@ -191,6 +191,24 @@ scripts into a VM. There are existing projects which deal with script loading, w
with Angular. Because modules do nothing at load time they can be loaded into the VM in any order
and thus script loaders can take advantage of this property and parallelize the loading process.
## Creation versus Retrieval
Beware that using `angular.module('myModule', [])` will create the module `myModule` and overwrite any
existing module named `myModule`. Use `angular.module('myModule')` to retrieve an existing module.
<pre>
var myModule = angular.module('myModule', []);
// add some directives and services
myModule.service('myService', ...);
myModule.directive('myDirective', ...);
// overwrites both myService and myDirective by creating a new module
var myModule = angular.module('myModule', []);
// throws an error because myOtherModule has yet to be defined
var myModule = angular.module('myOtherModule');
</pre>
# Unit Testing
+21 -21
View File
@@ -8,28 +8,28 @@
AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template
language and lets you extend HTML's syntax to express your application's components clearly and
succinctly. Out of the box, it eliminates much of the code you currently write through data
binding and dependency injection. And it all happens in JavaScript within the browser making it an
ideal partner with any server technology.
binding and dependency injection. And it all happens in JavaScript within the browser, making it
an ideal partner with any server technology.
Angular is what HTML would have been had it been designed for applications. HTML is a great
declarative language for static documents. It does not contain much in the way of creating
applications, and as a result building web applications is an exercise in *what do I have to do, so
that I trick the browser in to doing what I want.*
applications, and as a result building web applications is an exercise in *what do I have to do
to trick the browser into doing what I want.*
The impedance mismatch between dynamic applications and static documents is often solved as:
The impedance mismatch between dynamic applications and static documents is often solved with:
* **library** - a collection of functions which are useful when writing web apps. Your code is
* **a library** - a collection of functions which are useful when writing web apps. Your code is
in charge and it calls into the library when it sees fit. E.g., `jQuery`.
* **frameworks** - a particular implementation of a web application, where your code fills in
the details. The framework is in charge and it calls into your code when it needs something
app specific. E.g., `knockout`, `sproutcore`, etc.
app specific. E.g., `knockout`, `ember`, etc.
Angular takes another approach. It attempts to minimize the impedance mismatch between document
centric HTML and what an application needs by creating new HTML constructs. Angular teaches the
browser new syntax through a construct we call directives. Examples include:
* Data binding as in `{{}}`.
* Data binding, as in `{{}}`.
* DOM control structures for repeating/hiding DOM fragments.
* Support for forms and form validation.
* Attaching code-behind to DOM elements.
@@ -37,13 +37,13 @@ browser new syntax through a construct we call directives. Examples include:
## End-to-end solution
## A complete client-side solution
Angular tries to be an end-to-end solution, when building a web application. This means it is
not a single piece in an overall puzzle of building a web application, but an end-to-end solution.
This makes Angular opinionated about how a CRUD application should be built. But while it is
opinionated, it also tries to make sure that its opinion is just a starting point, which you can
easily change. Angular comes with the following out-of-the-box:
Angular is not a single piece in the overall puzzle of building the client-side of a web
application. It handles all of the DOM and AJAX glue code you once wrote by hand and puts it in a
well-defined structure. This makes Angular opinionated about how a CRUD application should be
built. But while it is opinionated, it also tries to make sure that its opinion is just a
starting point you can easily change. Angular comes with the following out-of-the-box:
* Everything you need to build a CRUD app in a cohesive set: data-binding, basic templating
directives, form validation, routing, deep-linking, reusable components, dependency injection.
@@ -56,12 +56,12 @@ easily change. Angular comes with the following out-of-the-box:
Angular simplifies application development by presenting a higher level of abstraction to the
developer. Like any abstraction, it comes at a cost of flexibility. In other words not every app
is a good fit for Angular. Angular was built for the CRUD application in mind. Luckily CRUD
applications represent at least 90% of the web applications. But to understand what Angular is
applications represent the majority of web applications. But to understand what Angular is
good at one also has to understand when an app is not a good fit for Angular.
Games, and GUI editors are examples of very intensive and tricky DOM manipulation. These kinds of
apps are different from CRUD apps, and as a result are not a good fit for Angular. In these cases
using something closer to bare metal such as `jQuery` may be a better fit.
Games and GUI editors are examples of applications with intensive and tricky DOM manipulation.
These kinds of apps are different from CRUD apps, and as a result are probably not a good fit for Angular.
In these cases it may be better to use a library with a lower level of abstraction, such as `jQuery`.
# An Introductory Angular Example
@@ -134,7 +134,7 @@ These input widgets look normal enough, but consider these points:
Model-View-Controller design pattern.
* Note that the HTML widget {@link api/ng.directive:input input}
has special powers. The input invalidates itself by turning red when you enter invalid data or
leave the the input fields blank. These new widget behaviors make it easier to implement field
leave the input fields blank. These new widget behaviors make it easier to implement field
validation common in CRUD applications.
And finally, the mysterious `{{ double curly braces }}`:
@@ -151,7 +151,7 @@ into output that looks like money."
Notice that we achieved this application behavior not by calling Angular methods, nor by
implementing application specific behavior as a framework. We achieved the behavior because the
browser behaved more in line with what is needed for a dynamic web application rather then what is
browser behaved more in line with what is needed for a dynamic web application rather than what is
needed for a static document. Angular has lowered the impedance mismatch to the point where no
library/framework calls are needed.
@@ -175,7 +175,7 @@ expressing business logic.
Angular frees you from the following pain:
Angular frees you from the following pains:
* **Registering callbacks:** Registering callbacks clutters your code, making it hard to see the
forest for the trees. Removing common boilerplate code such as callbacks is a good thing. It
+7 -11
View File
@@ -247,31 +247,27 @@ To create and submit a change:
[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:
2. Create and checkout a new branch off the master branch for your changes:
git branch my-fix-branch
git checkout -b my-fix-branch master
3. Check out the branch:
3. Create your patch, make sure to have plenty of tests (that pass).
git checkout my-fix-branch
4. Create your patch, make sure to have plenty of tests (that pass).
5. Commit your changes and create a descriptive commit message (the commit message is used to generate release notes,
4. 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
6. Push your branch to Github:
5. Push your branch to Github:
git push origin my-fix-branch
7. In Github, send a pull request to `angular:master`.
6. 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
7. When the patch is reviewed and merged, delete your branch and pull yours — and other — changes
from the main (upstream) repository:
1. To delete the branch in Github, run:
+4 -9
View File
@@ -51,7 +51,7 @@ Yes. See instructions in {@link downloading}.
### What browsers does Angular work with?
We run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari). See {@link guide/ie Internet
Explorer Compatibility} for more details in supporting legacy IE browsers.
@@ -101,9 +101,9 @@ The MIT License.
### Can I download and use the Angular logo artwork?
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
Yes! You can find design files in our github repository, under "{@link https://github.com/angular/angular.js/tree/master/images/logo
angular.js/images/logo}"
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
The logo design is licensed under a "{@link http://creativecommons.org/licenses/by-sa/3.0/
Creative Commons Attribution-ShareAlike 3.0 Unported License}". If you have some other use in mind, contact us.
### How can I get some AngularJS schwag?
@@ -114,15 +114,10 @@ they'll waive the setup costs, and you can order any quantity you need.
**Stickers**
Contact Tom Witting (or anyone in sales) via email at tom@stickergiant.com, and tell him you want to order some AngularJS
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
stickers just like the ones in job #42711. You'll have to give them your own info for billing and shipping.
As long as the design stays exactly the same, {@link http://www.stickergiant.com StickerGiant} will give you a reorder discount.
**T-shirts**
Contact sales at {@link http://www.customink.com www.customink.com} and tell them you want some shirts with design name "angularjs",
just like past order #2106371. You'll have to give them your own info for billing and shipping.
As long as the design stays exactly the same, CustomInk won't charge for any set up fees, and they'll give you a reorder discount.
## Common Pitfalls
+1
View File
@@ -19,6 +19,7 @@ becoming an Angular expert.
##Watch Videos
If you havent had a chance to watch the videos from the homepage, please check out:
* {@link http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Introduction to AngularJS}
* {@link http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Creating Directives}
* {@link http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Communicating with Servers}
+87 -89
View File
@@ -1,43 +1,42 @@
@ngdoc overview
@name Tutorial
@name Tutorial: Index
@description
<div class="tutorial-page tutorial-page-no-nav">
A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
the construction of an AngularJS web app. The app you will build is a catalog that displays a list
of Android devices, lets you filter the list to see only devices that interest you, and then view
details for any device.
A great way to get introduced to AngularJS is to work through this tutorial, which walks you through
the construction of an AngularJS web app. The app you will build is a catalog that displays a list
of Android devices, lets you filter the list to see only devices that interest you, and then view
details for any device.
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413">
<img class="diagram" src="img/tutorial/catalog_screen.png" width="488" height="413">
Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
or plug-ins. As you work through the tutorial, you will:
Work through the tutorial to see how Angular makes browsers smarter — without the use of extensions
or plug-ins. As you work through the tutorial, you will:
* See examples of how to use client-side data binding and dependency injection to build dynamic
views of data that change immediately in response to user actions.
* See how Angular creates listeners on your data without the need for DOM manipulation.
* Learn a better, easier way to test your web apps.
* Learn how to use Angular services to make common web tasks, such as getting data into your app,
easier.
* See examples of how to use client-side data binding and dependency injection to build dynamic
views of data that change immediately in response to user actions.
* See how Angular creates listeners on your data without the need for DOM manipulation.
* Learn a better, easier way to test your web apps.
* Learn how to use Angular services to make common web tasks, such as getting data into your app,
easier.
And all of this works in any browser without modification to the browser!
And all of this works in any browser without modification to the browser!
When you finish the tutorial you will be able to:
When you finish the tutorial you will be able to:
* Create a dynamic application that works in any browser.
* Define the differences between Angular and common JavaScript frameworks.
* Understand how data binding works in AngularJS.
* Use the angular-seed project to quickly boot-strap your own projects.
* Create and run tests.
* Identify resources for learning more about AngularJS.
* Create a dynamic application that works in any browser.
* Define the differences between Angular and common JavaScript frameworks.
* Understand how data binding works in AngularJS.
* Use the angular-seed project to quickly boot-strap your own projects.
* Create and run tests.
* Identify resources for learning more about AngularJS.
The tutorial guides you through the entire process of building a simple application, including
writing and running unit and end-to-end tests. Experiments at the end of each step provide
suggestions for you to learn more about AngularJS and the application you are building.
The tutorial guides you through the entire process of building a simple application, including
writing and running unit and end-to-end tests. Experiments at the end of each step provide
suggestions for you to learn more about AngularJS and the application you are building.
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
{@link misc/started Getting Started} document.
You can go through the whole tutorial in a couple of hours or you may want to spend a pleasant day
really digging into it. If you're looking for a shorter introduction to AngularJS, check out the
{@link misc/started Getting Started} document.
@@ -45,73 +44,72 @@
# Working with the code
# Working with the code
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
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.
You can follow this tutorial and hack on the code in either the Mac/Linux or the Windows
environment. The tutorial relies on the use of Git versioning system for source code management.
You don't need to know anything about Git to follow the tutorial. Select one of the tabs below
and follow the instructions for setting up your computer.
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>You will need Node.js and Karma to run unit tests, so please verify that you have
<div class="tabbable" show="true">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux">
<ol>
<li><p>You will need Node.js and Karma 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://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
<pre>npm install -g karma</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>
<p>This command creates the <code>angular-phonecat</code> directory in your current
directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Node.js and Karma 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://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
don't have it already:</p>
<pre>npm install -g karma</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>
<p>This command creates the <code>angular-phonecat</code> directory in your current
directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the angular-phonecat
directory.</p></li>
<li><p>You will need an http server running on your system. Mac and Linux machines typically
have Apache pre-installed, but If you don't already have one installed, you can use <code>node</code>
to run <code>scripts/web-server.js</code>, a simple bundled http server.</p></li>
</ol>
</div>
</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 <code>angular-phonecat</code> directory in your current directory.</p></li>
<li><p>Change your current directory to <code>angular-phonecat</code>:</p>
<pre>cd angular-phonecat</pre>
<p>The tutorial instructions assume you are running all commands from the <code>angular-phonecat</code>
directory.</p>
<p>You should run all <code>git</code> commands from Git bash.</p>
<p>Other commands like <code>test.bat</code> or <code>e2e-test.bat</code> should be
executed from the Windows command line.</li>
<li><p>You need an http server running on your system, but if you don't already have one
already installed, you can use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
bundled http server.</p></li>
</ol>
</div>
<div class="tab-pane well" id="git-win" title="Git on Windows">
<ol>
<li><p>You will need Node.js and Karma 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://karma-runner.github.io/">Karma</a> if you
don't have it already:</p>
<pre>npm install -g karma</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 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 use <code>node</code> to run <code>scripts\web-server.js</code>, a simple
bundled http server.</p></li>
</ol>
</div>
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!
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!
{@link step_00 <span class="btn btn-primary">Get Started!</span>}
</div>
{@link step_00 <span class="btn btn-primary">Get Started!</span>}
+4 -4
View File
@@ -13,7 +13,7 @@ angular-seed, and run the application in the browser.
<div class="tabbable" show="true" ng-model="$cookies.platformPreference">
<div class="tab-pane well" id="git-mac" title="Git on Mac/Linux" value="gitUnix">
<ol>
<li><p>In angular-phonecat directory, run this command:</p>
<li><p>In <code>angular-phonecat</code> directory, run this command:</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
@@ -25,7 +25,7 @@ angular-seed, and run the application in the browser.
<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>
<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>
@@ -46,7 +46,7 @@ directory.</li>
<div class="tab-pane well" id="git-win" title="Git on Windows" value="gitWin">
<ol>
<li><p>Open Git bash and run this command (in angular-phonecat directory):</p>
<li><p>Open Git bash and run this command (in <code>angular-phonecat</code> 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
@@ -153,7 +153,7 @@ for most cases. In advanced cases, such as when using script loaders, you can us
There are 3 important things that happen during the app bootstrap:
1. The {@link api/AUTO.$injector injector} that will be used for dependency injection
within this app is created.
when this app is created.
2. The injector will then create the {@link api/ng.$rootScope root scope} that will
become the context for the model of our application.
+4 -4
View File
@@ -134,10 +134,10 @@ describe('PhoneCat controllers', function() {
});
</pre>
The test verifies that we have three records in the phones array and the example demonstrates how
easy it is to create a unit test for code in Angular. Since testing is such a critical part of
software development, we make it easy to create tests in Angular so that developers are encouraged
to write them.
The test instantiates our PhoneListCtrl and verifies that its phones array property contains three
records. This example demonstrates how easy it is to create a unit test for code in Angular. Since
testing is such a critical part of software development, we make it easy to create tests in Angular
so that developers are encouraged to write them.
Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
writing tests. Although Angular does not require you to use Jasmine, we wrote all of the tests in
+6 -3
View File
@@ -69,7 +69,7 @@ available as a filter input in the list repeater (`phone in phones | filter:`__`
changes to the data model cause the repeater's input to change, the repeater efficiently updates
the DOM to reflect the current state of the model.
<img class="diagram" src="img/tutorial/tutorial_03.png">
<img class="diagram" src="img/tutorial/tutorial_03.png">
* Use of the `filter` filter: The {@link api/ng.filter:filter filter} function uses the
`query` value to create a new array that contains only those records that match the `query`.
@@ -127,6 +127,9 @@ end-to-end tests! Use `./scripts/e2e-test.sh` script for that. End-to-end tests
with unit tests, Karma 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.
Note: You must ensure you've installed karma-ng-scenario prior to running the `e2e-test.sh` script.
You can do this by issuing `npm install karma-ng-scenario` into your terminal.
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.
@@ -138,12 +141,12 @@ really is that easy to set up any functional, readable, end-to-end test.
* Let's see how we can get the current value of the `query` model to appear in the HTML page title.
You might think you could just add the {{query}} to the title tag element as follows:
You might think you could just add the `{{query}}` to the title tag element as follows:
<title>Google Phone Gallery: {{query}}</title>
However, when you reload the page, you won't see the expected result. This is because the "query"
model lives in the scope defined by the body element:
model lives in the scope, defined by the `ng-controller="PhoneListCtrl"` directive, on the body element:
<body ng-controller="PhoneListCtrl">
+3 -1
View File
@@ -45,7 +45,7 @@ We made the following changes to the `index.html` template:
* First, we added a `<select>` html element named `orderProp`, so that our users can pick from the
two provided sorting options.
<img class="diagram" src="img/tutorial/tutorial_04.png">
<img class="diagram" src="img/tutorial/tutorial_04.png">
* We then chained the `filter` filter with {@link api/ng.filter:orderBy `orderBy`}
filter to further process the input into the repeater. `orderBy` is a filter that takes an input
@@ -178,6 +178,8 @@ ordering will default to unordered/natural order.
* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
text.
* Reverse the sort order by adding a `-` symbol before the sorting value: `<option value="-age">Oldest</option>`
# Summary
Now that you have added list sorting and tested the app, go to {@link step_05 step 5} to learn
+1 -3
View File
@@ -44,7 +44,7 @@ Following is a sample of the file:
We'll use angular's {@link api/ng.$http $http} service in our controller to make an HTTP
request to your web server to fetch the data in the `app/phones/phones.json` file. `$http` is just
one of several built-in {@link api/ng angular services} that handle common operations
one of several built-in {@link guide/dev_guide.services angular services} that handle common operations
in web apps. Angular injects these services for you where you need them.
Services are managed by angular's {@link guide/di DI subsystem}. Dependency injection
@@ -207,8 +207,6 @@ Finally, we verify that the default value of `orderProp` is set correctly:
it('should set the default value of orderProp model', function() {
expect(scope.orderProp).toBe('age');
});
});
});
</pre>
You should now see the following output in the Karma tab:
+1 -1
View File
@@ -53,7 +53,7 @@ When the application bootstraps, Angular creates an injector that will be used f
this app. The injector itself doesn't know anything about what `$http` or `$route` services do, in
fact it doesn't even know about the existence of these services unless it is configured with proper
module definitions. The sole responsibilities of the injector are to load specified module
definition(s), register all service providers defined in these modules and when asked inject
definition(s), register all service providers defined in these modules, and when asked, inject
a specified function with dependencies (services) that it lazily instantiates via their providers.
Providers are objects that provide (create) instances of services and expose configuration APIs
+7 -5
View File
@@ -37,8 +37,7 @@ angular.module('phonecatFilters', []).filter('checkmark', function() {
</pre>
The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
`\u2718`).
return one of the two unicode characters we have chosen to represent true (`\u2713` -> ✓) or false (`\u2718` -> ✘).
Now that our filter is ready, we need to register the `phonecatFilters` module as a dependency for
our main `phonecat` module.
@@ -95,7 +94,6 @@ describe('filter', function() {
beforeEach(module('phonecatFilters'));
describe('checkmark', function() {
it('should convert boolean values to unicode checkmark or cross',
@@ -107,8 +105,12 @@ describe('filter', function() {
});
</pre>
Note that you need to configure our test injector with the `phonecatFilters` module before any of
our filter tests execute.
We must call `beforeEach(module('phonecatFilters'))` before any of
our filter tests execute. This call loads our `phonecatFilters` module into the injector
for this test run.
Note that we call the helper function, `inject(function(checkmarkFilter) { ... })`, to get
access to the filter that we want to test. See {@link api/angular.mock.inject angular.mock.inject()}.
You should now see the following output in the Karma tab:
+1 -1
View File
@@ -104,7 +104,7 @@ __`test/e2e/scenarios.js`:__
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
http://angular.github.com/angular-phonecat/step-10/test/e2e/runner.html
Angular's server}.
# Experiments
+1 -1
View File
@@ -135,7 +135,7 @@ The {@link api/ngResource.$resource $resource} service augments the response obj
with methods for updating and deleting the resource. If we were to use the standard `toEqual`
matcher, our tests would fail because the test values would not match the responses exactly. To
solve the problem, we use a newly-defined `toEqualData` {@link
http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine matcher}. When the
https://github.com/pivotal/jasmine/wiki/Matchers Jasmine matcher}. When the
`toEqualData` matcher compares two objects, it takes only object properties into account and
ignores methods.
+12 -14
View File
@@ -2,22 +2,20 @@
@name Tutorial: The End
@description
<div class="tutorial-page tutorial-page-no-nav">
Our application is now complete. Feel free to experiment with the code further, and jump back to
previous steps using the `git checkout` command.
Our application is now complete. Feel free to experiment with the code further, and jump back to
previous steps using the `git checkout` command.
For more details and examples of the Angular concepts we touched on in this tutorial, see the
{@link guide/ Developer Guide}.
For more details and examples of the Angular concepts we touched on in this tutorial, see the
{@link guide/ Developer Guide}.
For several more examples of code, see the {@link cookbook/ Cookbook}.
For several more examples of code, see the {@link cookbook/ Cookbook}.
When you are ready to start developing a project using Angular, we recommend that you bootstrap
your development with the {@link https://github.com/angular/angular-seed angular-seed} project.
When you are ready to start developing a project using Angular, we recommend that you bootstrap
your development with the {@link https://github.com/angular/angular-seed angular-seed} project.
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
own, and that you might be interested in {@link misc/contribute contributing} to Angular.
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
own, and that you might be interested in {@link misc/contribute contributing} to Angular.
If you have questions or feedback or just want to say "hi", please post a message at {@link
https://groups.google.com/forum/#!forum/angular}.
</div>
If you have questions or feedback or just want to say "hi", please post a message at {@link
https://groups.google.com/forum/#!forum/angular}.
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
]>
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
x="0px" y="0px" width="687px" height="176px" viewBox="0 0 687 176" overflow="visible" enable-background="new 0 0 687 176"
xml:space="preserve">
<defs>
</defs>
<path fill="#FFFFFF" d="M179.011,125.328V54.527h9.158l43.322,57.035V54.527h8.666v70.801h-9.158l-43.326-57.536v57.536H179.011z
M179.011,125.328"/>
<path fill="#FFFFFF" d="M310.46,122.554c-5.708,2.182-11.864,3.269-18.467,3.269c-25.644,0-38.469-12.294-38.469-36.887
c0-23.27,12.378-34.908,37.134-34.908c7.096,0,13.7,0.994,19.802,2.976v7.921c-6.103-2.311-12.378-3.468-18.813-3.468
c-19.306,0-28.96,9.162-28.96,27.479c0,19.639,9.504,29.463,28.517,29.463c3.034,0,6.404-0.396,10.103-1.193V93.145h9.154V122.554z
M310.46,122.554"/>
<path fill="#FFFFFF" d="M325.067,97.996V54.523h9.154v43.473c0,13.598,6.768,20.4,20.303,20.4c13.531,0,20.301-6.803,20.301-20.4
V54.523h9.158v43.473c0,18.556-9.82,27.825-29.459,27.825C334.886,125.821,325.067,116.552,325.067,97.996L325.067,97.996z
M325.067,97.996"/>
<path fill="#FFFFFF" d="M409.48,54.523v63.376h37.037v7.425h-46.191V54.523H409.48z M409.48,54.523"/>
<path fill="#FFFFFF" d="M459.736,125.327h-9.504l35.201-80.146l35.199,80.146h-10.15l-9.158-22.282h-23.418l2.527-7.424h17.82
l-13.217-32.088L459.736,125.327z M459.736,125.327"/>
<path fill="#FFFFFF" d="M530.289,125.328V54.527h30.203c13.469,0,20.197,5.659,20.197,16.982c0,9.207-6.578,16.028-19.75,20.445
l24.309,33.374h-12.086l-22.521-31.835v-5.992c13.531-2.151,20.301-7.344,20.301-15.598c0-6.533-3.766-9.801-11.293-9.801h-20.201
v63.226H530.289z M530.289,125.328"/>
<path fill="#B52E31" d="M619.561,54.523v50.405c0,13.603-8.006,20.396-24.016,20.396V117.9c9.902,0,14.857-4.329,14.857-12.973
V54.523H619.561z M619.561,54.523"/>
<path fill="#B52E31" d="M635.896,122.849v-8.418c7.428,2.639,15.447,3.965,24.064,3.965c12.178,0,18.271-4.457,18.271-13.372
c0-7.584-4.492-11.385-13.469-11.385h-9.113c-14.818,0-22.234-6.435-22.234-19.31c0-13.531,9.492-20.303,28.479-20.303
c8.25,0,15.922,0.998,23.021,2.976v8.418c-7.1-2.644-14.771-3.965-23.021-3.965c-12.875,0-19.311,4.293-19.311,12.875
c0,7.588,4.352,11.385,13.066,11.385h9.113c15.08,0,22.627,6.439,22.627,19.31c0,13.864-9.141,20.796-27.43,20.796
C651.344,125.819,643.324,124.826,635.896,122.849L635.896,122.849z M635.896,122.849"/>
<path fill="#B2B2B2" d="M82.688,0L0,29.1l13.066,108.335l69.71,38.314l70.069-38.834l13.062-108.331L82.688,0z M82.688,0"/>
<path fill="#B52E31" d="M157.66,34.846L82.496,9.214v157.381l62.991-34.861L157.66,34.846z M157.66,34.846"/>
<path fill="#E23237" d="M9.279,35.308l11.196,96.889l62.019,34.398V9.211L9.279,35.308z M9.279,35.308"/>
<path fill="#F2F2F2" d="M99.918,87.493L82.632,51.396L67.415,87.493H99.918z M106.508,102.672h-45.82l-10.251,25.64l-19.067,0.352
L82.496,14.929l52.908,113.734h-17.673L106.508,102.672z M106.508,102.672"/>
<path fill="#B2B2B2" d="M82.496,14.929l0.136,36.467l17.268,36.125H82.534l-0.039,15.127l24.012,0.023l11.223,25.996l18.245,0.339
L82.496,14.929z M82.496,14.929"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+42 -28
View File
@@ -59,10 +59,10 @@ describe('ngdoc', function() {
'@param {function(number, string=)} d fn with optional arguments');
doc.parse();
expect(doc.param).toEqual([
{name:'a', description:'<p>short</p>', type:'*', optional:false, 'default':undefined},
{name:'b', description:'<p>med</p>', type:'Type', optional:false, 'default':undefined},
{name:'c', description:'<p>long\nline</p>', type:'Class', optional:true, 'default':'2'},
{name:'d', description:'<p>fn with optional arguments</p>',
{name:'a', description:'<div class="a-page"><p>short</p></div>', type:'*', optional:false, 'default':undefined},
{name:'b', description:'<div class="a-page"><p>med</p></div>', type:'Type', optional:false, 'default':undefined},
{name:'c', description:'<div class="a-page"><p>long\nline</p></div>', type:'Class', optional:true, 'default':'2'},
{name:'d', description:'<div class="a-page"><p>fn with optional arguments</p></div>',
type: 'function(number, string=)', optional: false, 'default':undefined}
]);
});
@@ -72,7 +72,7 @@ describe('ngdoc', function() {
doc.parse();
expect(doc.returns).toEqual({
type: 'Type',
description: '<p>text <em>bold</em>.</p>'
description: '<div class="a-page"><p>text <em>bold</em>.</p></div>'
});
});
@@ -138,16 +138,30 @@ describe('ngdoc', function() {
it('should not replace anything in <pre>, but escape the html escape the content', function() {
expect(new Doc().markdown('bah x\n<pre>\n<b>angular</b>.k\n</pre>\n asdf x')).
toEqual(
'<p>bah x\n' +
'<div class="docs-page"><p>bah x\n' +
'<pre class="prettyprint linenums">\n' +
'&lt;b&gt;angular&lt;/b&gt;.k\n' +
'</pre>\n' +
' asdf x</p>');
' asdf x</p></div>');
});
it('should wrap everything inside a container tag', function() {
var doc = new Doc('@name superman').parse();
var content = doc.markdown('hello');
expect(content).toMatch('<div class="superman-page"><p>hello</p></div>');
});
it('should use the content before a colon as the name prefix for the className of the tag container', function() {
var doc = new Doc('@name super: man').parse();
var content = doc.markdown('hello');
expect(content).toMatch('<div class="super-page super-man-page"><p>hello</p></div>');
});
it('should replace text between two <pre></pre> tags', function() {
expect(new Doc().markdown('<pre>x</pre>\n# One\n<pre>b</pre>')).
toMatch('</pre>\n\n<h1>One</h1>\n\n<pre');
toMatch('</pre>\n\n<h1 id="one">One</h1>\n\n<pre');
});
it('should ignore nested doc widgets', function() {
@@ -157,11 +171,11 @@ describe('ngdoc', function() {
'\ngit bla bla\n</doc:tutorial-instruction>\n' +
'</doc:tutorial-instructions>')).toEqual(
'<p>before<div class="tabbable">\n' +
'<div class="docs-page"><p>before<div class="tabbable">\n' +
'<div class="tab-pane well" id="git-mac" ng:model="Git on Mac/Linux">\n' +
'git bla bla\n' +
'</doc:tutorial-instruction>\n' +
'</doc:tutorial-instructions></p>');
'</doc:tutorial-instructions></p></div>');
});
it('should unindent text before processing based on the second line', function() {
@@ -263,7 +277,7 @@ describe('ngdoc', function() {
name : 'number',
optional: false,
'default' : undefined,
description : '<p>Number \nto format.</p>' }]);
description : '<div class="a-page"><p>Number \nto format.</p></div>' }]);
});
it('should parse with default and optional', function() {
@@ -274,7 +288,7 @@ describe('ngdoc', function() {
name : 'fractionSize',
optional: true,
'default' : '2',
description : '<p>desc</p>' }]);
description : '<div class="a-page"><p>desc</p></div>' }]);
});
});
@@ -284,8 +298,8 @@ describe('ngdoc', function() {
doc.ngdoc = 'service';
doc.parse();
expect(doc.requires).toEqual([
{name:'$service', text:'<p>for \n<code>A</code></p>'},
{name:'$another', text:'<p>for <code>B</code></p>'}]);
{name:'$service', text:'<div class="a-page"><p>for \n<code>A</code></p></div>'},
{name:'$another', text:'<div class="a-page"><p>for <code>B</code></p></div>'}]);
expect(doc.html()).toContain('<a href="api/ng.$service">$service</a>');
expect(doc.html()).toContain('<a href="api/ng.$another">$another</a>');
expect(doc.html()).toContain('<p>for \n<code>A</code></p>');
@@ -337,7 +351,7 @@ describe('ngdoc', function() {
var doc = new Doc("@name a\n@property {string} name desc rip tion");
doc.parse();
expect(doc.properties[0].name).toEqual('name');
expect(doc.properties[0].description).toEqual('<p>desc rip tion</p>');
expect(doc.properties[0].description).toEqual('<div class="a-page"><p>desc rip tion</p></div>');
});
it('should parse @property with type and description both', function() {
@@ -345,7 +359,7 @@ describe('ngdoc', function() {
doc.parse();
expect(doc.properties[0].name).toEqual('name');
expect(doc.properties[0].type).toEqual('bool');
expect(doc.properties[0].description).toEqual('<p>desc rip tion</p>');
expect(doc.properties[0].description).toEqual('<div class="a-page"><p>desc rip tion</p></div>');
});
});
@@ -368,26 +382,26 @@ describe('ngdoc', function() {
it('should parse @returns with type and description', function() {
var doc = new Doc("@name a\n@returns {string} descrip tion");
doc.parse();
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip tion</p>'});
expect(doc.returns).toEqual({type: 'string', description: '<div class="a-page"><p>descrip tion</p></div>'});
});
it('should parse @returns with complex type and description', function() {
var doc = new Doc("@name a\n@returns {function(string, number=)} description");
doc.parse();
expect(doc.returns).toEqual({type: 'function(string, number=)', description: '<p>description</p>'});
expect(doc.returns).toEqual({type: 'function(string, number=)', description: '<div class="a-page"><p>description</p></div>'});
});
it('should transform description of @returns with markdown', function() {
var doc = new Doc("@name a\n@returns {string} descrip *tion*");
doc.parse();
expect(doc.returns).toEqual({type: 'string', description: '<p>descrip <em>tion</em></p>'});
expect(doc.returns).toEqual({type: 'string', description: '<div class="a-page"><p>descrip <em>tion</em></p></div>'});
});
it('should support multiline content', function() {
var doc = new Doc("@name a\n@returns {string} description\n new line\n another line");
doc.parse();
expect(doc.returns).
toEqual({type: 'string', description: '<p>description\nnew line\nanother line</p>'});
toEqual({type: 'string', description: '<div class="a-page"><p>description\nnew line\nanother line</p></div>'});
});
});
@@ -396,18 +410,18 @@ describe('ngdoc', function() {
var doc = new Doc("@name a\n@description <pre><b>abc</b></pre>");
doc.parse();
expect(doc.description).
toBe('<pre class="prettyprint linenums">&lt;b&gt;abc&lt;/b&gt;</pre>');
toBe('<div class="a-page"><pre class="prettyprint linenums">&lt;b&gt;abc&lt;/b&gt;</pre></div>');
});
it('should support multiple pre blocks', function() {
var doc = new Doc("@name a\n@description foo \n<pre>abc</pre>\n#bah\nfoo \n<pre>cba</pre>");
doc.parse();
expect(doc.description).
toBe('<p>foo \n' +
toBe('<div class="a-page"><p>foo \n' +
'<pre class="prettyprint linenums">abc</pre>\n\n' +
'<h1>bah</h1>\n\n' +
'<h1 id="bah">bah</h1>\n\n' +
'<p>foo \n' +
'<pre class="prettyprint linenums">cba</pre>');
'<pre class="prettyprint linenums">cba</pre></div>');
});
@@ -450,7 +464,7 @@ describe('ngdoc', function() {
it('should not remove {{}}', function() {
var doc = new Doc('@name a\n@example text {{ abc }}');
doc.parse();
expect(doc.example).toEqual('<p>text {{ abc }}</p>');
expect(doc.example).toEqual('<div class="a-page"><p>text {{ abc }}</p></div>');
});
});
@@ -469,10 +483,10 @@ describe('ngdoc', function() {
doc.parse();
expect(doc.html()).toContain('<h3>Method\'s <code>this</code></h3>\n' +
'<div>' +
'<p>I am self.</p>' +
'<div class="a-page"><p>I am self.</p></div>' +
'</div>\n');
expect(doc.html()).toContain('<h3>Method\'s <code>this</code></h3>\n' +
'<div><p>I am self.</p></div>');
'<div><div class="a-page"><p>I am self.</p></div></div>');
});
});
});
@@ -483,7 +497,7 @@ describe('ngdoc', function() {
var doc = new Doc('@ngdoc overview\n@name angular\n@description\n#heading\ntext');
doc.parse();
expect(doc.html()).toContain('text');
expect(doc.html()).toContain('<h2>heading</h2>');
expect(doc.html()).toContain('<h1 id="heading">heading</h2>');
expect(doc.html()).not.toContain('Description');
});
});
+20 -1
View File
@@ -173,8 +173,27 @@ Doc.prototype = {
'</a>';
});
});
text = parts.join('');
text = new Showdown.converter({ extensions : ['table'] }).makeHtml(text);
function prepareClassName(text) {
return text.toLowerCase().replace(/[_\W]+/g, '-');
};
var pageClassName, suffix = '-page';
if(this.name) {
var split = this.name.match(/^\s*(.+?)\s*:\s*(.+)/);
if(split && split.length > 1) {
var before = prepareClassName(split[1]);
var after = prepareClassName(split[2]);
pageClassName = before + suffix + ' ' + before + '-' + after + suffix;
}
}
pageClassName = pageClassName || prepareClassName(this.name || 'docs') + suffix;
text = '<div class="' + pageClassName + '">' +
(new Showdown.converter({ extensions : ['table'] }).makeHtml(text)) +
'</div>';
text = text.replace(/(?:<p>)?(REPLACEME\d+)(?:<\/p>)?/g, function(_, id) {
return placeholderMap[id];
});
+25 -7
View File
@@ -1,8 +1,17 @@
img.AngularJS-small {
width: 95px;
height: 25px;
/* Logo */
.header .brand {
padding-top: 6px;
padding-bottom: 0px;
}
.header .brand img {
height: 25px;
width: 92px;
}
/* end: Logo */
.clear-navbar {
margin-top: 60px;
@@ -88,6 +97,11 @@ img.AngularJS-small {
.improve-docs {
float: right;
position: relative;
}
.improve-docs {
z-index:100;
}
.hint {
@@ -102,6 +116,7 @@ img.AngularJS-small {
padding: 0;
font-size: inherit;
font-family: monospace;
white-space: nowrap;
}
.content h2,
@@ -189,13 +204,16 @@ ul.events > li > h3 {
clear: both;
}
.tutorial-index-page,
.tutorial-the-end-page {
padding-top:50px;
}
.tutorial-page {
position:relative;
}
.tutorial-page-no-nav {
padding-top:50px;
}
.tutorial-page-no-nav .improve-docs {
.tutorial-page .improve-docs {
position:absolute;
top:0;
right:0;
+7 -6
View File
@@ -114,8 +114,8 @@
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="http://angularjs.org" style="padding-top: 6px; padding-bottom: 0px;">
<img class="AngularJS-small" src="http://angularjs.org/img/AngularJS-small.png">
<a class="brand" href="http://angularjs.org">
<img class="logo" src="img/angularjs-for-header-only.svg">
</a>
<ul class="nav">
<li class="divider-vertical"></li>
@@ -130,6 +130,7 @@
<li><a href="http://www.youtube.com/user/angularjs">Watch</a></li>
<li><a href="tutorial">Tutorial</a></li>
<li><a href="http://builtwith.angularjs.org/">Case Studies</a></li>
<li><a href="https://github.com/angular/angular-seed">Seed App project template</a></li>
<li><a href="misc/faq">FAQ</a></li>
</ul>
</li>
@@ -139,9 +140,9 @@
<i class="icon-book icon-white"></i> Develop <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<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="./tutorial/">Tutorial</a></li>
<li><a href="./guide/">Developer Guide</a></li>
<li><a href="./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>
@@ -203,7 +204,7 @@
<div class="dropdown search"
ng-class="{open: focused && bestMatch.rank > 0 && bestMatch.page != currentPage}">
<input type="text" ng-model="search" placeholder="search the docs"
tabindex="1" accesskey="s" class="input-medium search-query" focused="focused">
tabindex="1" accesskey="s" class="input-medium search-query" />
<ul class="dropdown-menu">
<li>
<a href="{{bestMatch.page.url}}">{{bestMatch.page.shortName}}</a>
+9 -9
View File
@@ -18,8 +18,8 @@ docsApp.directive.focused = function($timeout) {
scope.$eval(attrs.focused + '=false');
});
});
scope.$eval(attrs.focused + '=true')
}
scope.$eval(attrs.focused + '=true');
};
};
@@ -59,7 +59,7 @@ docsApp.directive.sourceEdit = function(getEmbeddedTemplate) {
openPlunkr(sources);
};
}
}
};
function read(text) {
var files = [];
@@ -127,7 +127,7 @@ docsApp.directive.docTutorialReset = function() {
'</div>\n');
}
};
}
};
docsApp.serviceFactory.angularUrls = function($document) {
@@ -141,7 +141,7 @@ docsApp.serviceFactory.angularUrls = function($document) {
});
return urls;
}
};
docsApp.serviceFactory.formPostData = function($document) {
@@ -174,7 +174,7 @@ docsApp.serviceFactory.openPlunkr = function(templateMerge, formPostData, angula
var scriptDeps = '';
angular.forEach(content.deps, function(file) {
if (file.name !== 'angular.js') {
scriptDeps += ' <script src="' + file.name + '"></script>\n'
scriptDeps += ' <script src="' + file.name + '"></script>\n';
}
});
indexProp = {
@@ -310,7 +310,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
last: this.$last,
active: page1 && this.currentPage == page1 || page2 && this.currentPage == page2
};
}
};
$scope.submitForm = function() {
$scope.bestMatch && $location.path($scope.bestMatch.page.url);
@@ -509,7 +509,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
},
types: [],
filters: []
}
};
modules.push(module);
}
return module;
@@ -560,7 +560,7 @@ docsApp.controller.DocsController = function($scope, $location, $window, $cookie
angular.element(document.getElementById('disqus_thread')).html('');
}
}
};
angular.module('docsApp', ['ngResource', 'ngCookies', 'ngSanitize', 'bootstrap', 'bootstrapPrettify']).
+5
View File
@@ -257,5 +257,10 @@ describe("serializeContent", function() {
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo());
expect((/[^\u0001-\u007f]/).test(serializedContent)).toBe(false);
});
it("should not transform arrays into objects", function() {
var serializedContent = closureI18nExtractor.serializeContent(newTestLocaleInfo().fr_CA);
var deserializedLocale = eval("(" + serializedContent + ")");
expect(deserializedLocale.DATETIME_FORMATS.MONTH.length).not.toBe(undefined);
});
});
+1 -1
View File
@@ -116,7 +116,7 @@ function canonicalizeForJsonStringify(unused_key, object) {
// 2. https://code.google.com/p/v8/issues/detail?id=164
// ECMA-262 does not specify enumeration order. The de facto standard
// is to match insertion order, which V8 also does ...
if (typeof object != "object") {
if (typeof object != "object" || Object.prototype.toString.apply(object) === '[object Array]') {
return object;
}
var result = {};
+5 -5
View File
@@ -7,8 +7,8 @@ cd $BASE_DIR
set -x # Trace commands as they're executed.
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/currency.js > closure/currencySymbols.js
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbols.js > closure/datetimeSymbols.js
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/datetimesymbolsext.js > closure/datetimeSymbolsExt.js
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/numberformatsymbols.js > closure/numberSymbols.js
curl http://closure-library.googlecode.com/svn/trunk/closure/goog/i18n/pluralrules.js > closure/pluralRules.js
curl http://google.github.io/closure-library/source/closure/goog/i18n/currency.js > closure/currencySymbols.js
curl http://google.github.io/closure-library/source/closure/goog/i18n/datetimesymbols.js > closure/datetimeSymbols.js
curl http://google.github.io/closure-library/source/closure/goog/i18n/datetimesymbolsext.js > closure/datetimeSymbolsExt.js
curl http://google.github.io/closure-library/source/closure/goog/i18n/numberformatsymbols.js > closure/numberSymbols.js
curl http://google.github.io/closure-library/source/closure/goog/i18n/pluralrules.js > closure/pluralRules.js
+40
View File
@@ -0,0 +1,40 @@
#!/bin/bash
# Enable tracing and exit on first failure
set -xe
# Define reasonable set of browsers in case we are running manually from commandline
if [[ -z "$BROWSERS" ]]
then
BROWSERS="Chrome,Firefox,Opera,/Users/jenkins/bin/safari.sh,/Users/jenkins/bin/ie8.sh,/Users/jenkins/bin/ie9.sh"
fi
if [[ -z "$BROWSERS_E2E" ]]
then
BROWSERS_E2E="Chrome,Firefox,/Users/jenkins/bin/safari.sh"
fi
# CLEAN #
rm -f angular.min.js.gzip.size
rm -f angular.js.size
# BUILD #
npm install --color false
grunt ci-checks package --no-color
# UNIT TESTS #
grunt test:unit --browsers $BROWSERS --reporters=dots,junit --no-colors --no-color
# END TO END TESTS #
grunt test:e2e --browsers $BROWSERS_E2E --reporters=dots,junit --no-colors --no-color
# CHECK SIZE #
gzip -c < build/angular.min.js > build/angular.min.js.gzip
echo "YVALUE=`ls -l build/angular.min.js | cut -d" " -f 8`" > angular.min.js.size
echo "YVALUE=`ls -l build/angular.min.js.gzip | cut -d" " -f 8`" > angular.min.js.gzip.size
+21 -16
View File
@@ -1,20 +1,25 @@
var angularFiles = require(__dirname + '/angularFiles.js');
var sharedConfig = require('./karma-shared.conf');
files = [ANGULAR_SCENARIO, ANGULAR_SCENARIO_ADAPTER, 'build/docs/docs-scenario.js'];
module.exports = function(config) {
sharedConfig(config);
autoWatch = false;
singleRun = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
config.set({
frameworks: ['ng-scenario'],
files: [
'build/docs/docs-scenario.js'
],
proxies = {
// angular.js, angular-resource.js, etc
'/angular': 'http://localhost:8000/build/angular',
'/': 'http://localhost:8000/build/docs/'
};
junitReporter = {
outputFile: 'test_out/e2e.xml',
suite: 'E2E'
proxies: {
// angular.js, angular-resource.js, etc
'/angular': 'http://localhost:8000/build/angular',
'/': 'http://localhost:8000/build/docs/'
},
junitReporter: {
outputFile: 'test_out/e2e.xml',
suite: 'E2E'
}
});
config.sauceLabs.testName = 'AngularJS: e2e';
};
+14 -10
View File
@@ -1,14 +1,18 @@
var angularFiles = require(__dirname + '/angularFiles.js');
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
files = angularFiles.mergeFiles(JASMINE, JASMINE_ADAPTER, 'jstd');
exclude = ['**/*jasmine*/**', '**/*jstd*/**'].concat(angularFiles.files.jstdExclude);
module.exports = function(config) {
sharedConfig(config);
autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
config.set({
files: angularFiles.mergeFilesFor('karma'),
exclude: angularFiles.mergeFilesFor('karmaExclude'),
junitReporter = {
outputFile: 'test_out/jqlite.xml',
suite: 'jqLite'
junitReporter: {
outputFile: 'test_out/jqlite.xml',
suite: 'jqLite'
}
});
config.sauceLabs.testName = 'AngularJS: jqLite';
};
+14 -10
View File
@@ -1,14 +1,18 @@
var angularFiles = require(__dirname + '/angularFiles.js');
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
files = angularFiles.mergeFiles(JASMINE, JASMINE_ADAPTER, 'jstdJquery');
exclude = ['**/*jasmine*/**', '**/*jstd*/**'].concat(angularFiles.files.jstdJqueryExclude);
module.exports = function(config) {
sharedConfig(config);
autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
config.set({
files: angularFiles.mergeFilesFor('karmaJquery'),
exclude: angularFiles.mergeFilesFor('karmaJqueryExclude'),
junitReporter = {
outputFile: 'test_out/jquery.xml',
suite: 'jQuery'
junitReporter: {
outputFile: 'test_out/jquery.xml',
suite: 'jQuery'
}
});
config.sauceLabs.testName = 'AngularJS: jQuery';
};
+13 -10
View File
@@ -1,14 +1,17 @@
var angularFiles = require(__dirname + '/angularFiles.js');
var angularFiles = require('./angularFiles');
var sharedConfig = require('./karma-shared.conf');
files = angularFiles.mergeFiles(JASMINE, JASMINE_ADAPTER, 'jstdModules', 'angularSrcModules');
exclude = ['**/*jasmine*/**', '**/*jstd*/**'];
module.exports = function(config) {
sharedConfig(config);
autoWatch = true;
logLevel = LOG_INFO;
logColors = true;
browsers = ['Chrome'];
config.set({
files: angularFiles.mergeFilesFor('karmaModules', 'angularSrcModules'),
junitReporter = {
outputFile: 'test_out/modules.xml',
suite: 'modules'
junitReporter: {
outputFile: 'test_out/modules.xml',
suite: 'modules'
}
});
config.sauceLabs.testName = 'AngularJS: modules';
};
+24
View File
@@ -0,0 +1,24 @@
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
autoWatch: true,
logLevel: config.LOG_INFO,
logColors: true,
browsers: ['Chrome'],
runnerPort: 0,
// config for Travis CI
sauceLabs: {
testName: 'AngularJS',
startConnect: false,
tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
},
customLaunchers: {
'SL_Chrome': {
base: 'SauceLabs',
browserName: 'chrome'
}
}
});
};
+37 -6
View File
@@ -2,22 +2,32 @@ var fs = require('fs');
var shell = require('shelljs');
var grunt = require('grunt');
var spawn = require('child_process').spawn;
var version;
module.exports = {
init: function() {
shell.exec('npm install');
if (!process.env.TRAVIS) {
shell.exec('npm install');
}
},
getVersion: function(){
if (version) return version;
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
var match = package.version.match(/^([^\-]*)(-snapshot)?$/);
// TODO(brian): change `(-|rc)` to `-` in the regex below after bower
// fixes this issue: https://github.com/bower/bower/issues/782
var match = package.version.match(/^([^\-]*)(?:(-|rc)(.+))?$/);
var semver = match[1].split('.');
var hash = shell.exec('git rev-parse --short HEAD', {silent: true}).output.replace('\n', '');
var version = {
full: (match[1] + (match[2] ? '-' + hash : '')),
var fullVersion = (match[1] + (match[2] ? '-' + hash : ''));
var numVersion = semver[0] + '.' + semver[1] + '.' + semver[2];
version = {
number: numVersion,
full: fullVersion,
major: semver[0],
minor: semver[1],
dot: semver[2],
@@ -33,11 +43,13 @@ module.exports = {
var browsers = grunt.option('browsers');
var reporters = grunt.option('reporters');
var noColor = grunt.option('no-colors');
var port = grunt.option('port');
var p = spawn('node', ['node_modules/karma/bin/karma', 'start', config,
singleRun ? '--single-run=true' : '',
reporters ? '--reporters=' + reporters : '',
browsers ? '--browsers=' + browsers : '',
noColor ? '--no-colors' : ''
noColor ? '--no-colors' : '',
port ? '--port=' + port : ''
]);
p.stdout.pipe(process.stdout);
p.stderr.pipe(process.stderr);
@@ -170,5 +182,24 @@ module.exports = {
}
next();
};
}
},
parallelTask: function(name) {
var args = [name, '--port=' + this.lastParallelTaskPort];
if (grunt.option('browsers')) {
args.push('--browsers=' + grunt.option('browsers'));
}
if (grunt.option('reporters')) {
args.push('--reporters=' + grunt.option('reporters'));
}
this.lastParallelTaskPort++;
return {grunt: true, args: args};
},
lastParallelTaskPort: 9876
};
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
# Wait for Connect to be ready before exiting
while [ ! -f $SAUCE_CONNECT_READY_FILE ]; do
sleep .5
done
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
set -e
# Setup and start Sauce Connect for your TravisCI build
# This script requires your .travis.yml to include the following two private env variables:
# SAUCE_USERNAME
# SAUCE_ACCESS_KEY
# Follow the steps at https://saucelabs.com/opensource/travis to set that up.
#
# Curl and run this script as part of your .travis.yml before_script section:
# before_script:
# - curl https://gist.github.com/santiycr/5139565/raw/sauce_connect_setup.sh | bash
CONNECT_URL="http://saucelabs.com/downloads/Sauce-Connect-latest.zip"
CONNECT_DIR="/tmp/sauce-connect-$RANDOM"
CONNECT_DOWNLOAD="Sauce_Connect.zip"
CONNECT_LOG="$CONNECT_DIR/log"
# Get Connect and start it
mkdir -p $CONNECT_DIR
cd $CONNECT_DIR
curl $CONNECT_URL > $CONNECT_DOWNLOAD 2> /dev/null
unzip $CONNECT_DOWNLOAD
rm $CONNECT_DOWNLOAD
ARGS=""
# Set tunnel-id only on Travis, to make local testing easier.
if [ ! -z "$TRAVIS_JOB_NUMBER" ]; then
ARGS="$ARGS --tunnel-identifier $TRAVIS_JOB_NUMBER"
fi
if [ ! -z "$SAUCE_CONNECT_READY_FILE" ]; then
ARGS="$ARGS --readyfile $SAUCE_CONNECT_READY_FILE"
fi
echo "Starting Sauce Connect in the background"
echo "Logging into $CONNECT_LOG"
java -jar Sauce-Connect.jar $ARGS $SAUCE_USERNAME $SAUCE_ACCESS_KEY > $CONNECT_LOG &
+24 -10
View File
@@ -1,20 +1,34 @@
{
"name": "AngularJS",
"version": "1.0.7",
"cdnVersion": "1.0.6",
"codename": "monochromatic-rainbow",
"name": "angularjs",
"version": "1.0.9-snapshot",
"cdnVersion": "1.0.7",
"codename": "marc-todo",
"repository": {
"type": "git",
"url": "https://github.com/angular/angular.js.git"
},
"devDependencies": {
"grunt": "0.4.0",
"grunt-contrib-clean": "0.4.0",
"grunt-contrib-compress": "0.4.1",
"grunt-contrib-connect": "0.1.2",
"grunt-contrib-copy": "0.4.1",
"grunt": "~0.4.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-compress": "~0.5.2",
"grunt-contrib-connect": "~0.3.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-parallel": "git://github.com/vojtajina/grunt-parallel.git#streaming-per-task",
"grunt-ddescribe-iit": "~0.0.1",
"grunt-merge-conflict": "~0.0.1",
"jasmine-node": "1.2.3",
"q": "~0.9.2",
"q-fs": "0.1.36",
"qq": "0.3.5",
"shelljs": "0.1.2",
"karma": "0.8.4",
"karma": "~0.10",
"karma-jasmine": "~0.1",
"karma-chrome-launcher": "~0.1",
"karma-firefox-launcher": "~0.1",
"karma-ng-scenario": "~0.1",
"karma-junit-reporter": "~0.1",
"karma-sauce-launcher": "~0.1",
"karma-script-launcher": "~0.1",
"yaml-js": "0.0.5",
"showdown": "0.3.1"
},
+150 -23
View File
@@ -276,7 +276,7 @@ noop.$inject = [];
*
<pre>
function transformer(transformationFn, value) {
return (transformationFn || identity)(value);
return (transformationFn || angular.identity)(value);
};
</pre>
*/
@@ -403,6 +403,18 @@ function isArray(value) {
function isFunction(value){return typeof value == 'function';}
/**
* Determines if a value is a regular expression object.
*
* @private
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `RegExp`.
*/
function isRegExp(value) {
return toString.apply(value) == '[object RegExp]';
}
/**
* Checks if `obj` is a window object.
*
@@ -430,9 +442,20 @@ function isBoolean(value) {
}
function trim(value) {
return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
}
var trim = (function() {
// native trim is way faster: http://jsperf.com/angular-trim-test
// but IE doesn't have it... :-(
// TODO: we should move this into IE/ES5 polyfill
if (!String.prototype.trim) {
return function(value) {
return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
};
}
return function(value) {
return isString(value) ? value.trim() : value;
};
})();
/**
* @ngdoc function
@@ -555,7 +578,8 @@ function isLeafNode (node) {
* * If no destination is supplied, a copy of the object or array is created.
* * If a destination is provided, all of its elements (for array) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array, `source` is returned.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
* * If `source` is identical to 'destination' an exception will be thrown.
*
* Note: this function is used to augment the Object type in Angular expressions. See
* {@link ng.$filter} for more information about Angular arrays.
@@ -565,6 +589,42 @@ function isLeafNode (node) {
* @param {(Object|Array)=} destination Destination into which the source is copied. If
* provided, must be of the same type as `source`.
* @returns {*} The copy or updated `destination`, if `destination` was specified.
*
* @example
<doc:example>
<doc:source>
<div ng-controller="Controller">
<form novalidate class="simple-form">
Name: <input type="text" ng-model="user.name" /><br />
E-mail: <input type="email" ng-model="user.email" /><br />
Gender: <input type="radio" ng-model="user.gender" value="male" />male
<input type="radio" ng-model="user.gender" value="female" />female<br />
<button ng-click="reset()">RESET</button>
<button ng-click="update(user)">SAVE</button>
</form>
<pre>form = {{user | json}}</pre>
<pre>master = {{master | json}}</pre>
</div>
<script>
function Controller($scope) {
$scope.master= {};
$scope.update = function(user) {
// Example with 1 argument
$scope.master= angular.copy(user);
};
$scope.reset = function() {
// Example with 2 arguments
angular.copy($scope.master, $scope.user);
};
$scope.reset();
}
</script>
</doc:source>
</doc:example>
*/
function copy(source, destination){
if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
@@ -575,6 +635,8 @@ function copy(source, destination){
destination = copy(source, []);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source);
} else if (isObject(source)) {
destination = copy(source, {});
}
@@ -622,7 +684,7 @@ function shallowCopy(src, dst) {
* @function
*
* @description
* Determines if two objects or two values are equivalent. Supports value types, arrays and
* Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and
* objects.
*
* Two objects or values are considered equivalent if at least one of the following is true:
@@ -630,6 +692,9 @@ function shallowCopy(src, dst) {
* * Both objects or values pass `===` comparison.
* * Both objects or values are of the same type and all of their properties pass `===` comparison.
* * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
* * Both values represent the same regular expression (In JavasScript,
* /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
* representation matches).
*
* During a property comparision, properties of `function` type and properties with names
* that begin with `$` are ignored.
@@ -648,6 +713,7 @@ function equals(o1, o2) {
if (t1 == t2) {
if (t1 == 'object') {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) == o2.length) {
for(key=0; key<length; key++) {
if (!equals(o1[key], o2[key])) return false;
@@ -656,8 +722,10 @@ function equals(o1, o2) {
}
} else if (isDate(o1)) {
return isDate(o2) && o1.getTime() == o2.getTime();
} else if (isRegExp(o1) && isRegExp(o2)) {
return o1.toString() == o2.toString();
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
keySet = {};
for(key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
@@ -695,7 +763,8 @@ function sliceArgs(args, startIndex) {
* @description
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
* known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as distinguished
* from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
*
* @param {Object} self Context which `fn` should be evaluated in.
* @param {function()} fn Function to be bound.
@@ -726,7 +795,7 @@ function bind(self, fn) {
function toJsonReplacer(key, value) {
var val = value;
if (/^\$+/.test(key)) {
if (typeof key === 'string' && key.charAt(0) === '$') {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
@@ -746,13 +815,15 @@ function toJsonReplacer(key, value) {
* @function
*
* @description
* Serializes input into a JSON-formatted string.
* Serializes input into a JSON-formatted string. Properties with leading $ characters will be
* stripped since angular uses this notation internally.
*
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
* @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
* @returns {string} Jsonified string representing `obj`.
* @returns {string|undefined} Jsonified string representing `obj`.
*/
function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined;
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
@@ -812,6 +883,23 @@ function startingTag(element) {
/////////////////////////////////////////////////
/**
* Tries to decode the URI component without throwing an exception.
*
* @private
* @param str value potential URI component to check.
* @returns {boolean} True if `value` can be decoded
* with the decodeURIComponent function.
*/
function tryDecodeURIComponent(value) {
try {
return decodeURIComponent(value);
} catch(e) {
// Ignore any invalid uri component
}
}
/**
* Parses an escaped url query string into key-value pairs.
* @returns Object.<(string|boolean)>
@@ -819,10 +907,12 @@ function startingTag(element) {
function parseKeyValue(/**string*/keyValue) {
var obj = {}, key_value, key;
forEach((keyValue || "").split('&'), function(keyValue){
if (keyValue) {
if ( keyValue ) {
key_value = keyValue.split('=');
key = decodeURIComponent(key_value[0]);
obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
key = tryDecodeURIComponent(key_value[0]);
if ( isDefined(key) ) {
obj[key] = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
}
}
});
return obj;
@@ -888,11 +978,15 @@ function encodeUriQuery(val, pctEncodeSpaces) {
* @description
*
* Use this directive to auto-bootstrap an application. Only
* one directive can be used per HTML document. The directive
* one ngApp directive can be used per HTML document. The directive
* designates the root of the application and is typically placed
* at the root of the page.
*
* In the example below if the `ngApp` directive would not be placed
* The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
* HTML document you must manually bootstrap them using {@link angular.bootstrap}.
* Applications cannot be nested.
*
* In the example below if the `ngApp` directive were not placed
* on the `html` element then the document would not be compiled
* and the `{{ 1+2 }}` would not be resolved to `3`.
*
@@ -957,12 +1051,17 @@ function angularInit(element, bootstrap) {
*
* See: {@link guide/bootstrap Bootstrap}
*
* Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
* They must use {@link api/ng.directive:ngApp ngApp}.
*
* @param {Element} element DOM element which is the root of angular application.
* @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
* Each item in the array should be the name of a predefined module or a (DI annotated)
* function that will be invoked by the injector as a run block. See: {@link angular.module modules}
* @returns {AUTO.$injector} Returns the newly created injector for this app.
*/
function bootstrap(element, modules) {
var resumeBootstrapInternal = function() {
var doBootstrap = function() {
element = jqLite(element);
modules = modules || [];
modules.unshift(['$provide', function($provide) {
@@ -984,7 +1083,7 @@ function bootstrap(element, modules) {
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
return resumeBootstrapInternal();
return doBootstrap();
}
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
@@ -992,7 +1091,7 @@ function bootstrap(element, modules) {
forEach(extraModules, function(module) {
modules.push(module);
});
resumeBootstrapInternal();
doBootstrap();
};
}
@@ -1016,9 +1115,10 @@ function bindJQuery() {
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
JQLitePatchJQueryRemove('remove', true);
JQLitePatchJQueryRemove('empty');
JQLitePatchJQueryRemove('html');
// Method signature: JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
JQLitePatchJQueryRemove('remove', true, true, false);
JQLitePatchJQueryRemove('empty', false, false, false);
JQLitePatchJQueryRemove('html', false, false, true);
} else {
jqLite = JQLite;
}
@@ -1044,3 +1144,30 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
return arg;
}
/**
* Return the value accessible from the object by path. Any undefined traversals are ignored
* @param {Object} obj starting object
* @param {string} path path to traverse
* @param {boolean=true} bindFnToScope
* @returns value as accessible by path
*/
//TODO(misko): this function needs to be removed
function getter(obj, path, bindFnToScope) {
if (!path) return obj;
var keys = path.split('.');
var key;
var lastInstance = obj;
var len = keys.length;
for (var i = 0; i < len; i++) {
key = keys[i];
if (obj) {
obj = (lastInstance = obj)[key];
}
}
if (!bindFnToScope && isFunction(obj)) {
return bind(lastInstance, obj);
}
return obj;
}
-1
View File
@@ -87,7 +87,6 @@ function publishExternalAPI(angular){
ngPluralize: ngPluralizeDirective,
ngRepeat: ngRepeatDirective,
ngShow: ngShowDirective,
ngSubmit: ngSubmitDirective,
ngStyle: ngStyleDirective,
ngSwitch: ngSwitchDirective,
ngSwitchWhen: ngSwitchWhenDirective,
+202 -49
View File
@@ -253,46 +253,37 @@ function annotate(fn) {
*
* @description
*
* Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
* The providers share the same name as the instance they create with `Provider` suffixed to them.
* The {@link AUTO.$provide $provide} service has a number of methods for registering components with
* the {@link AUTO.$injector $injector}. Many of these functions are also exposed on {@link angular.Module}.
*
* A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
* a service. The Provider can have additional methods which would allow for configuration of the provider.
* An Angular **service** is a singleton object created by a **service factory**. These **service
* factories** are functions which, in turn, are created by a **service provider**.
* The **service providers** are constructor functions. When instantiated they must contain a property
* called `$get`, which holds the **service factory** function.
*
* When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
* correct **service provider**, instantiating it and then calling its `$get` **service factory**
* function to get the instance of the **service**.
*
* Often services have no configuration options and there is no need to add methods to the service
* provider. The provider will be no more than a constructor function with a `$get` property. For
* these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
* services without specifying a provider.
*
* <pre>
* function GreetProvider() {
* var salutation = 'Hello';
* * {@link AUTO.$provide#provider provider(provider)} - registers a **service provider** with the
* {@link AUTO.$injector $injector}
* * {@link AUTO.$provide#constant constant(obj)} - registers a value/object that can be accessed by
* providers and services.
* * {@link AUTO.$provide#value value(obj)} - registers a value/object that can only be accessed by
* services, not providers.
* * {@link AUTO.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, that
* will be wrapped in a **service provider** object, whose `$get` property will contain the given
* factory function.
* * {@link AUTO.$provide#service service(class)} - registers a **constructor function**, `class` that
* will be wrapped in a **service provider** object, whose `$get` property will instantiate a new
* object using the given constructor function.
*
* this.salutation = function(text) {
* salutation = text;
* };
*
* this.$get = function() {
* return function (name) {
* return salutation + ' ' + name + '!';
* };
* };
* }
*
* describe('Greeter', function(){
*
* beforeEach(module(function($provide) {
* $provide.provider('greet', GreetProvider);
* }));
*
* it('should greet', inject(function(greet) {
* expect(greet('angular')).toEqual('Hello angular!');
* }));
*
* it('should allow configuration of salutation', function() {
* module(function(greetProvider) {
* greetProvider.salutation('Ahoj');
* });
* inject(function(greet) {
* expect(greet('angular')).toEqual('Ahoj angular!');
* });
* });
* </pre>
* See the individual methods for more information and examples.
*/
/**
@@ -301,7 +292,18 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
* Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions are
* constructor functions, whose instances are responsible for "providing" a factory for a service.
*
* Service provider names start with the name of the service they provide followed by `Provider`.
* For example, the {@link ng.$log $log} service has a provider called {@link ng.$logProvider $logProvider}.
*
* Service provider objects can have additional methods which allow configuration of the provider and
* its service. Importantly, you can configure what kind of service is created by the `$get` method,
* or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a method
* {@link ng.$logProvider#debugEnabled debugEnabled}
* which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
* console or not.
*
* @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
* @param {(Object|function())} provider If the provider is:
@@ -312,6 +314,70 @@ function annotate(fn) {
* {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
*
* @returns {Object} registered provider instance
* @example
*
* The following example shows how to create a simple event tracking service and register it using
* {@link AUTO.$provide#provider $provide.provider()}.
*
* <pre>
* // Define the eventTracker provider
* function EventTrackerProvider() {
* var trackingUrl = '/track';
*
* // A provider method for configuring where the tracked events should been saved
* this.setTrackingUrl = function(url) {
* trackingUrl = url;
* };
*
* // The service factory function
* this.$get = ['$http', function($http) {
* var trackedEvents = {};
* return {
* // Call this to track an event
* event: function(event) {
* var count = trackedEvents[event] || 0;
* count += 1;
* trackedEvents[event] = count;
* return count;
* },
* // Call this to save the tracked events to the trackingUrl
* save: function() {
* $http.post(trackingUrl, trackedEvents);
* }
* };
* }];
* }
*
* describe('eventTracker', function() {
* var postSpy;
*
* beforeEach(module(function($provide) {
* // Register the eventTracker provider
* $provide.provider('eventTracker', EventTrackerProvider);
* }));
*
* beforeEach(module(function(eventTrackerProvider) {
* // Configure eventTracker provider
* eventTrackerProvider.setTrackingUrl('/custom-track');
* }));
*
* it('tracks events', inject(function(eventTracker) {
* expect(eventTracker.event('login')).toEqual(1);
* expect(eventTracker.event('login')).toEqual(2);
* }));
*
* it('saves to the tracking url', inject(function(eventTracker, $http) {
* postSpy = spyOn($http, 'post');
* eventTracker.event('login');
* eventTracker.save();
* expect(postSpy).toHaveBeenCalled();
* expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
* expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
* expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
* }));
* });
* </pre>
*/
/**
@@ -320,12 +386,32 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* A short hand for configuring services if only `$get` method is required.
* Register a **service factory**, which will be called to return the service instance.
* This is short for registering a service where its provider consists of only a `$get` property,
* which is the given service factory function.
* You should use {@link AUTO.$provide#factory $provide.factor(getFn)} if you do not need to configure
* your service in a provider.
*
* @param {string} name The name of the instance.
* @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
* `$provide.provider(name, {$get: $getFn})`.
* @returns {Object} registered provider instance
*
* @example
* Here is an example of registering a service
* <pre>
* $provide.factory('ping', ['$http', function($http) {
* return function ping() {
* return $http.send('/ping');
* };
* }]);
* </pre>
* You would then inject and use this service like this:
* <pre>
* someModule.controller('Ctrl', ['ping', function(ping) {
* ping();
* }]);
* </pre>
*/
@@ -335,11 +421,34 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* A short hand for registering service of given class.
* Register a **service constructor**, which will be invoked with `new` to create the service instance.
* This is short for registering a service where its provider's `$get` property is the service
* constructor function that will be used to instantiate the service instance.
*
* You should use {@link AUTO.$provide#service $provide.service(class)} if you define your service
* as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}.
*
* @param {string} name The name of the instance.
* @param {Function} constructor A class (constructor function) that will be instantiated.
* @returns {Object} registered provider instance
*
* @example
* Here is an example of registering a service using {@link AUTO.$provide#service $provide.service(class)}
* that is defined as a CoffeeScript class.
* <pre>
* class Ping
* constructor: (@$http)->
* send: ()=>
* @$http.get('/ping')
*
* $provide.service('ping', ['$http', Ping])
* </pre>
* You would then inject and use this service like this:
* <pre>
* someModule.controller 'Ctrl', ['ping', (ping)->
* ping.send()
* ]
* </pre>
*/
@@ -349,11 +458,29 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* A short hand for configuring services if the `$get` method is a constant.
* Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a number,
* an array, an object or a function. This is short for registering a service where its provider's
* `$get` property is a factory function that takes no arguments and returns the **value service**.
*
* Value services are similar to constant services, except that they cannot be injected into a module
* configuration function (see {@link angular.Module#config}) but they can be overridden by an Angular
* {@link AUTO.$provide#decorator decorator}.
*
* @param {string} name The name of the instance.
* @param {*} value The value.
* @returns {Object} registered provider instance
*
* @example
* Here are some examples of creating value services.
* <pre>
* $provide.constant('ADMIN_USER', 'admin');
*
* $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
*
* $provide.constant('halfOf', function(value) {
* return value / 2;
* });
* </pre>
*/
@@ -363,13 +490,26 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
* into configuration function (other modules) and it is not interceptable by
* {@link AUTO.$provide#decorator decorator}.
* Register a **constant service**, such as a string, a number, an array, an object or a function, with
* the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be injected
* into a module configuration function (see {@link angular.Module#config}) and it cannot be
* overridden by an Angular {@link AUTO.$provide#decorator decorator}.
*
* @param {string} name The name of the constant.
* @param {*} value The constant value.
* @returns {Object} registered instance
*
* @example
* Here a some examples of creating constants:
* <pre>
* $provide.constant('SHARD_HEIGHT', 306);
*
* $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
*
* $provide.constant('double', function(value) {
* return value * 2;
* });
* </pre>
*/
@@ -379,17 +519,29 @@ function annotate(fn) {
* @methodOf AUTO.$provide
* @description
*
* Decoration of service, allows the decorator to intercept the service instance creation. The
* returned instance may be the original instance, or a new instance which delegates to the
* original instance.
* Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator
* intercepts the creation of a service, allowing it to override or modify the behaviour of the
* service. The object returned by the decorator may be the original service, or a new service object
* which replaces or wraps and delegates to the original service.
*
* @param {string} name The name of the service to decorate.
* @param {function()} decorator This function will be invoked when the service needs to be
* instantiated. The function is called using the {@link AUTO.$injector#invoke
* injector.invoke} method and is therefore fully injectable. Local injection arguments:
* instantiated and should return the decorated service instance. The function is called using
* the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
* Local injection arguments:
*
* * `$delegate` - The original service instance, which can be monkey patched, configured,
* decorated or delegated to.
*
* @example
* Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
* calls to {@link ng.$log#error $log.warn()}.
* <pre>
* $provider.decorator('$log', ['$delegate', function($delegate) {
* $delegate.warn = $delegate.error;
* return $delegate;
* }]);
* </pre>
*/
@@ -602,3 +754,4 @@ function createInjector(modulesToLoad) {
};
}
}
+13 -3
View File
@@ -183,7 +183,9 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
return {
terminal: true,
link: function(scope, element, attrs) {
var modules = [];
var modules = [],
embedRootScope,
deregisterEmbedRootScope;
modules.push(['$provide', function($provide) {
$provide.value('$templateCache', $templateCache);
@@ -209,10 +211,12 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
}
}, $delegate);
}]);
$provide.decorator('$rootScope', ['$delegate', function(embedRootScope) {
docsRootScope.$watch(function embedRootScopeDigestWatch() {
$provide.decorator('$rootScope', ['$delegate', function($delegate) {
embedRootScope = $delegate;
deregisterEmbedRootScope = docsRootScope.$watch(function embedRootScopeDigestWatch() {
embedRootScope.$digest();
});
return embedRootScope;
}]);
}]);
@@ -223,6 +227,12 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location',
event.preventDefault();
}
});
element.bind('$destroy', function() {
deregisterEmbedRootScope();
embedRootScope.$destroy();
});
angular.bootstrap(element, modules);
}
};
+40 -28
View File
@@ -26,7 +26,8 @@
* Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
* raw DOM references.
*
* ## Angular's jQuery lite provides the following methods:
* ## Angular's jqLite
* Angular's lite version of jQuery provides only the following jQuery methods:
*
* - [addClass()](http://api.jquery.com/addClass/)
* - [after()](http://api.jquery.com/after/)
@@ -59,8 +60,14 @@
* - [val()](http://api.jquery.com/val/)
* - [wrap()](http://api.jquery.com/wrap/)
*
* ## In addtion to the above, Angular provides additional methods to both jQuery and jQuery lite:
* ## jQuery/jqLite Extras
* Angular also provides the following additional methods and events to both jQuery and jqLite:
*
* ### Events
* - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
* on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
* element before it is removed.
* ### Methods
* - `controller(name)` - retrieves the controller of the current element or its parent. By default
* retrieves controller associated with the `ngController` directive. If `name` is provided as
* camelCase directive name, then the controller for this directive will be retrieved (e.g.
@@ -107,37 +114,38 @@ function camelCase(name) {
/////////////////////////////////////////////
// jQuery mutation patch
//
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
// $destroy event on all DOM nodes being removed.
//
/////////////////////////////////////////////
function JQLitePatchJQueryRemove(name, dispatchThis) {
function JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
var originalJqFn = jQuery.fn[name];
originalJqFn = originalJqFn.$original || originalJqFn;
removePatch.$original = originalJqFn;
jQuery.fn[name] = removePatch;
function removePatch() {
var list = [this],
function removePatch(param) {
var list = filterElems && param ? [this.filter(param)] : [this],
fireEvent = dispatchThis,
set, setIndex, setLength,
element, childIndex, childLength, children,
fns, events;
element, childIndex, childLength, children;
while(list.length) {
set = list.shift();
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
element = jqLite(set[setIndex]);
if (fireEvent) {
element.triggerHandler('$destroy');
} else {
fireEvent = !fireEvent;
}
for(childIndex = 0, childLength = (children = element.children()).length;
childIndex < childLength;
childIndex++) {
list.push(jQuery(children[childIndex]));
if (!getterIfNoArguments || param != null) {
while(list.length) {
set = list.shift();
for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
element = jqLite(set[setIndex]);
if (fireEvent) {
element.triggerHandler('$destroy');
} else {
fireEvent = !fireEvent;
}
for(childIndex = 0, childLength = (children = element.children()).length;
childIndex < childLength;
childIndex++) {
list.push(jQuery(children[childIndex]));
}
}
}
}
@@ -197,7 +205,7 @@ function JQLiteUnbind(element, type, fn) {
removeEventListenerFn(element, type, events[type]);
delete events[type];
} else {
arrayRemove(events[type], fn);
arrayRemove(events[type] || [], fn);
}
}
}
@@ -471,6 +479,15 @@ forEach({
val: function(element, value) {
if (isUndefined(value)) {
if (nodeName_(element) === 'SELECT' && element.multiple) {
var result = [];
forEach(element.options, function (option) {
if (option.selected) {
result.push(option.value || option.text);
}
});
return result.length === 0 ? null : result;
}
return element.value;
}
element.value = value;
@@ -688,12 +705,7 @@ forEach({
if (element.nodeType === 1) {
var index = element.firstChild;
forEach(new JQLite(node), function(child){
if (index) {
element.insertBefore(child, index);
} else {
element.appendChild(child);
index = child;
}
element.insertBefore(child, index);
});
}
},
+6 -4
View File
@@ -30,8 +30,8 @@ function setupModuleLoader(window) {
*
* # Module
*
* A module is a collocation of services, directives, filters, and configuration information. Module
* is used to configure the {@link AUTO.$injector $injector}.
* A module is a collection of services, directives, filters, and configuration information.
* `angular.module` is used to configure the {@link AUTO.$injector $injector}.
*
* <pre>
* // Create a new module
@@ -178,7 +178,8 @@ function setupModuleLoader(window) {
* @ngdoc method
* @name angular.Module#controller
* @methodOf angular.Module
* @param {string} name Controller name.
* @param {string|Object} name Controller name, or an object map of controllers where the
* keys are the names and the values are the constructors.
* @param {Function} constructor Controller constructor function.
* @description
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
@@ -189,7 +190,8 @@ function setupModuleLoader(window) {
* @ngdoc method
* @name angular.Module#directive
* @methodOf angular.Module
* @param {string} name directive name
* @param {string|Object} name Directive name, or an object map of directives where the
* keys are the names and the values are the factories.
* @param {Function} directiveFactory Factory function for creating new instance of
* directives.
* @description
+29 -1
View File
@@ -10,8 +10,36 @@
* according to rules specified in
* {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
*
* It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
* It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
* This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
*
* @example
<example>
<file name="index.html">
<div ng-controller="MainCtrl">
<a ng-click="gotoBottom()">Go to bottom</a>
<a id="bottom"></a> You're at the bottom!
</div>
</file>
<file name="script.js">
function ScrollCtrl($scope, $location, $anchorScroll) {
$scope.gotoBottom = function (){
// set the location.hash to the id of
// the element you wish to scroll to.
$location.hash('bottom');
// call $anchorScroll()
$anchorScroll();
}
}
</file>
<file name="style.css">
#bottom {
display: block;
margin-top: 2000px;
}
</file>
</example>
*/
function $AnchorScrollProvider() {
+18 -6
View File
@@ -124,7 +124,8 @@ function Browser(window, document, $log, $sniffer) {
//////////////////////////////////////////////////////////////
var lastBrowserUrl = location.href,
baseElement = document.find('base');
baseElement = document.find('base'),
replacedUrl = null;
/**
* @name ng.$browser#url
@@ -159,14 +160,21 @@ function Browser(window, document, $log, $sniffer) {
baseElement.attr('href', baseElement.attr('href'));
}
} else {
if (replace) location.replace(url);
else location.href = url;
if (replace) {
location.replace(url);
replacedUrl = url;
} else {
location.href = url;
replacedUrl = null;
}
}
return self;
// getter
} else {
// the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
return location.href.replace(/%27/g,"'");
// - the replacedUrl is a workaround for an IE8-9 issue with location.replace method that doesn't update
// location.href synchronously
// - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
return replacedUrl || location.href.replace(/%27/g,"'");
}
};
@@ -230,10 +238,14 @@ function Browser(window, document, $log, $sniffer) {
//////////////////////////////////////////////////////////////
/**
* @name ng.$browser#baseHref
* @methodOf ng.$browser
*
* @description
* Returns current <base href>
* (always relative - without domain)
*
* @returns {string=}
* @returns {string=} current <base href>
*/
self.baseHref = function() {
var href = baseElement.attr('href');
+73 -3
View File
@@ -3,7 +3,20 @@
* @name ng.$cacheFactory
*
* @description
* Factory that constructs cache objects.
* Factory that constructs cache objects and gives access to them.
*
* <pre>
*
* var cache = $cacheFactory('cacheId');
* expect($cacheFactory.get('cacheId')).toBe(cache);
* expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
*
* cache.put("key", "value");
* cache.put("another key", "another value");
*
* expect(cache.info()).toEqual({id: 'cacheId', size: 2}); // Since we've specified no options on creation
*
* </pre>
*
*
* @param {string} cacheId Name or id of the newly created cache.
@@ -135,6 +148,16 @@ function $CacheFactoryProvider() {
}
/**
* @ngdoc method
* @name ng.$cacheFactory#info
* @methodOf ng.$cacheFactory
*
* @description
* Get information about all the of the caches that have been created
*
* @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
*/
cacheFactory.info = function() {
var info = {};
forEach(caches, function(cache, cacheId) {
@@ -144,6 +167,17 @@ function $CacheFactoryProvider() {
};
/**
* @ngdoc method
* @name ng.$cacheFactory#get
* @methodOf ng.$cacheFactory
*
* @description
* Get access to a cache object by the `cacheId` used when it was created.
*
* @param {string} cacheId Name or id of a cache to access.
* @returns {object} Cache object identified by the cacheId or undefined if no such cache.
*/
cacheFactory.get = function(cacheId) {
return caches[cacheId];
};
@@ -158,8 +192,44 @@ function $CacheFactoryProvider() {
* @name ng.$templateCache
*
* @description
* Cache used for storing html templates.
*
* The first time a template is used, it is loaded in the template cache for quick retrieval. You can
* load templates directly into the cache in a `script` tag, or by consuming the `$templateCache`
* service directly.
*
* Adding via the `script` tag:
* <pre>
* <html ng-app>
* <head>
* <script type="text/ng-template" id="templateId.html">
* This is the content of the template
* </script>
* </head>
* ...
* </html>
* </pre>
*
* **Note:** the `script` tag containing the template does not need to be included in the `head` of the document, but
* it must be below the `ng-app` definition.
*
* Adding via the $templateCache service:
*
* <pre>
* var myApp = angular.module('myApp', []);
* myApp.run(function($templateCache) {
* $templateCache.put('templateId.html', 'This is the content of the template');
* });
* </pre>
*
* To retrieve the template later, simply use it in your HTML:
* <pre>
* <div ng-include=" 'templateId.html' "></div>
* </pre>
*
* or get it via Javascript:
* <pre>
* $templateCache.get('templateId.html')
* </pre>
*
* See {@link ng.$cacheFactory $cacheFactory}.
*
*/
+19 -9
View File
@@ -166,12 +166,13 @@ function $CompileProvider($provide) {
* @function
*
* @description
* Register a new directives with the compiler.
* Register a new directive with the compiler.
*
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
* <code>ng-bind</code>).
* @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
* info.
* @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
* will match as <code>ng-bind</code>), or an object map of directives where the keys are the
* names and the values are the factories.
* @param {function|Array} directiveFactory An injectable directive factory function. See
* {@link guide/directive} for more info.
* @returns {ng.$compileProvider} Self for chaining.
*/
this.directive = function registerDirective(name, directiveFactory) {
@@ -293,7 +294,7 @@ function $CompileProvider($provide) {
// href property always returns normalized absolute url, so we can match against that
normalizedVal = urlSanitizationNode.href;
if (!normalizedVal.match(urlSanitizationWhitelist)) {
if (normalizedVal !== '' && !normalizedVal.match(urlSanitizationWhitelist)) {
this[key] = value = 'unsafe:' + normalizedVal;
}
}
@@ -319,12 +320,21 @@ function $CompileProvider($provide) {
/**
* @ngdoc function
* @name ng.$compile.directive.Attributes#$observe
* @methodOf ng.$compile.directive.Attributes
* @function
*
* @description
* Observe an interpolated attribute.
* The observer will never be called, if given attribute is not interpolated.
* The interpolated value of the attribute is passed to the observer function.
*
* @param {string} key Normalized key. (ie ngAttribute) .
* @param {function(*)} fn Function that will be called whenever the attribute value changes.
* @returns {function(*)} the `fn` Function passed in.
* @param {function(interpolatedValue)} fn Function that will be called whenever
the interpolated value of the attribute changes.
* See the {@link guide/directive#Attributes Directives} guide for more info.
* @returns {function()} the `fn` parameter.
*/
$observe: function(key, fn) {
var attrs = this,
@@ -517,7 +527,7 @@ function $CompileProvider($provide) {
for (var attr, name, nName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
attr = nAttrs[j];
if (attr.specified) {
if (!msie || msie >= 8 || attr.specified) {
name = attr.name;
nName = directiveNormalize(name.toLowerCase());
attrsMap[nName] = name;
+2 -1
View File
@@ -18,7 +18,8 @@ function $ControllerProvider() {
* @ngdoc function
* @name ng.$controllerProvider#register
* @methodOf ng.$controllerProvider
* @param {string} name Controller name
* @param {string|Object} name Controller name, or an object map of controllers where the keys are
* the names and the values are the constructors.
* @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
* annotations in the array notation).
*/
+3 -3
View File
@@ -6,10 +6,10 @@
* @restrict E
*
* @description
* Modifies the default behavior of html A tag, so that the default action is prevented when href
* attribute is empty.
* Modifies the default behavior of the html A tag so that the default action is prevented when
* the href attribute is empty.
*
* The reasoning for this change is to allow easy creation of action links with `ngClick` directive
* This change permits the easy creation of action links with the `ngClick` directive
* without changing the location or causing page reloads, e.g.:
* `<a href="" ng-click="model.$save()">Save</a>`
*/
+22 -14
View File
@@ -6,13 +6,15 @@
* @restrict A
*
* @description
* Using Angular markup like {{hash}} in an href attribute makes
* the page open to a wrong URL, if the user clicks that link before
* angular has a chance to replace the {{hash}} with actual URL, the
* link will be broken and will most likely return a 404 error.
* Using Angular markup like `{{hash}}` in an href attribute will
* make the link go to the wrong URL if the user clicks it before
* Angular has a chance to replace the `{{hash}}` markup with its
* value. Until Angular replaces the markup the link will be broken
* and will most likely return a 404 error.
*
* The `ngHref` directive solves this problem.
*
* The buggy way to write it:
* The wrong way to write it:
* <pre>
* <a href="http://www.gravatar.com/avatar/{{hash}}"/>
* </pre>
@@ -26,7 +28,8 @@
* @param {template} ngHref any string which can contain `{{}}` markup.
*
* @example
* This example uses `link` variable inside `href` attribute:
* This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
* in links and their different behaviors:
<doc:example>
<doc:source>
<input ng-model="value" /><br />
@@ -119,9 +122,9 @@
* </div>
* </pre>
*
* The HTML specs do not require browsers to preserve the special attributes such as disabled.
* (The presence of them means true and absence means false)
* This prevents the angular compiler from correctly retrieving the binding expression.
* The HTML specs do not require browsers to preserve the values of special attributes
* such as disabled. (The presence of them means true and absence means false)
* This prevents the Angular compiler from correctly retrieving the binding expression.
* To solve this problem, we introduce the `ngDisabled` directive.
*
* @example
@@ -140,7 +143,8 @@
</doc:example>
*
* @element INPUT
* @param {expression} ngDisabled Angular expression that will be evaluated.
* @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
* then special attribute "disabled" will be set on the element.
*/
@@ -170,7 +174,8 @@
</doc:example>
*
* @element INPUT
* @param {expression} ngChecked Angular expression that will be evaluated.
* @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
* then special attribute "checked" will be set on the element.
*/
@@ -206,7 +211,8 @@
</doc:example>
*
* @element SELECT
* @param {expression} ngMultiple Angular expression that will be evaluated.
* @param {expression} ngMultiple If the {@link guide/expression expression} is truthy,
* then special attribute "multiple" will be set on the element.
*/
@@ -236,7 +242,8 @@
</doc:example>
*
* @element INPUT
* @param {string} expression Angular expression that will be evaluated.
* @param {string} expression If the {@link guide/expression expression} is truthy,
* then special attribute "readonly" will be set on the element.
*/
@@ -269,7 +276,8 @@
</doc:example>
*
* @element OPTION
* @param {string} expression Angular expression that will be evaluated.
* @param {string} expression If the {@link guide/expression expression} is truthy,
* then special attribute "selected" will be set on the element.
*/
+56 -10
View File
@@ -40,7 +40,7 @@ function FormController(element, attrs) {
errors = form.$error = {};
// init state
form.$name = attrs.name;
form.$name = attrs.name || attrs.ngForm;
form.$dirty = false;
form.$pristine = true;
form.$valid = true;
@@ -60,12 +60,32 @@ function FormController(element, attrs) {
addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
}
/**
* @ngdoc function
* @name ng.directive:form.FormController#$addControl
* @methodOf ng.directive:form.FormController
*
* @description
* Register a control with the form.
*
* Input elements using ngModelController do this automatically when they are linked.
*/
form.$addControl = function(control) {
if (control.$name && !form.hasOwnProperty(control.$name)) {
form[control.$name] = control;
}
};
/**
* @ngdoc function
* @name ng.directive:form.FormController#$removeControl
* @methodOf ng.directive:form.FormController
*
* @description
* Deregister a control from the form.
*
* Input elements using ngModelController do this automatically when they are destroyed.
*/
form.$removeControl = function(control) {
if (control.$name && form[control.$name] === control) {
delete form[control.$name];
@@ -75,6 +95,16 @@ function FormController(element, attrs) {
});
};
/**
* @ngdoc function
* @name ng.directive:form.FormController#$setValidity
* @methodOf ng.directive:form.FormController
*
* @description
* Sets the validity of a form control.
*
* This method will also propagate to parent forms.
*/
form.$setValidity = function(validationToken, isValid, control) {
var queue = errors[validationToken];
@@ -113,6 +143,17 @@ function FormController(element, attrs) {
}
};
/**
* @ngdoc function
* @name ng.directive:form.FormController#$setDirty
* @methodOf ng.directive:form.FormController
*
* @description
* Sets the form to a dirty state.
*
* This method can be called to add the 'ng-dirty' class and set the form to a dirty
* state (ng-dirty class). This method will also propagate to parent forms.
*/
form.$setDirty = function() {
element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
form.$dirty = true;
@@ -147,15 +188,19 @@ function FormController(element, attrs) {
* Directive that instantiates
* {@link ng.directive:form.FormController FormController}.
*
* If `name` attribute is specified, the form controller is published onto the current scope under
* If the `name` attribute is specified, the form controller is published onto the current scope under
* this name.
*
* # Alias: {@link ng.directive:ngForm `ngForm`}
*
* In angular forms can be nested. This means that the outer form is valid when all of the child
* forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
* reason angular provides {@link ng.directive:ngForm `ngForm`} alias
* which behaves identical to `<form>` but allows form nesting.
* In Angular forms can be nested. This means that the outer form is valid when all of the child
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
* using Angular validation directives in forms that are dynamically generated using the
* {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
* attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
* `ngForm` directive and nest these in an outer `form` element.
*
*
* # CSS classes
@@ -165,12 +210,12 @@ function FormController(element, attrs) {
* - `ng-dirty` Is set if the form is dirty.
*
*
* # Submitting a form and preventing default action
* # Submitting a form and preventing the default action
*
* Since the role of forms in client-side Angular applications is different than in classical
* roundtrip apps, it is desirable for the browser not to translate the form submission into a full
* page reload that sends the data to the server. Instead some javascript logic should be triggered
* to handle the form submission in application specific way.
* to handle the form submission in an application-specific way.
*
* For this reason, Angular prevents the default action (form submission to the server) unless the
* `<form>` element has an `action` attribute specified.
@@ -182,8 +227,9 @@ function FormController(element, attrs) {
* - {@link ng.directive:ngClick ngClick} directive on the first
* button or input field of type submit (input[type=submit])
*
* To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. This
* is because of the following form submission rules coming from the html spec:
* To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
* or {@link ng.directive:ngClick ngClick} directives.
* This is because of the following form submission rules in the HTML specification:
*
* - If a form has only one input field then hitting enter in this field triggers form submit
* (`ngSubmit`)
+148 -28
View File
@@ -1,7 +1,7 @@
'use strict';
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var inputType = {
@@ -112,9 +112,9 @@ var inputType = {
<form name="myForm" ng-controller="Ctrl">
Number: <input type="number" name="input" ng-model="value"
min="0" max="99" required>
<span class="error" ng-show="myForm.list.$error.required">
<span class="error" ng-show="myForm.input.$error.required">
Required!</span>
<span class="error" ng-show="myForm.list.$error.number">
<span class="error" ng-show="myForm.input.$error.number">
Not valid number!</span>
<tt>value = {{value}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
@@ -235,6 +235,8 @@ var inputType = {
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
*
* @example
<doc:example>
@@ -793,12 +795,25 @@ var VALID_CLASS = 'ng-valid',
*
* @property {string} $viewValue Actual string value in the view.
* @property {*} $modelValue The value in the model, that the control is bound to.
* @property {Array.<Function>} $parsers Whenever the control reads value from the DOM, it executes
* all of these functions to sanitize / convert the value as well as validate.
*
* @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
* these functions to convert the value as well as validate.
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
the control reads value from the DOM. Each function is called, in turn, passing the value
through to the next. Used to sanitize / convert the value as well as validation.
For validation, the parsers should update the validity state using
{@link ng.directive:ngModel.NgModelController#$setValidity $setValidity()},
and return `undefined` for invalid values.
*
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
* the model value changes. Each function is called, in turn, passing the value through to the
* next. Used to format / convert values for display in the control and validation.
* <pre>
* function formatter(value) {
* if (value) {
* return value.toUpperCase();
* }
* }
* ngModel.$formatters.push(formatter);
* </pre>
* @property {Object} $error An bject hash with all errors as keys.
*
* @property {boolean} $pristine True if user has not interacted with the control yet.
@@ -809,15 +824,19 @@ var VALID_CLASS = 'ng-valid',
* @description
*
* `NgModelController` provides API for the `ng-model` directive. The controller contains
* services for data-binding, validation, CSS update, value formatting and parsing. It
* specifically does not contain any logic which deals with DOM rendering or listening to
* DOM events. The `NgModelController` is meant to be extended by other directives where, the
* directive provides DOM manipulation and the `NgModelController` provides the data-binding.
* services for data-binding, validation, CSS updates, and value formatting and parsing. It
* purposefully does not contain any logic which deals with DOM rendering or listening to
* DOM events. Such DOM related logic should be provided by other directives which make use of
* `NgModelController` for data-binding.
*
* ## Custom Control Example
* This example shows how to use `NgModelController` with a custom control to achieve
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
* collaborate together to achieve the desired result.
*
* Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
* contents be edited in place by the user. This will not work on older browsers.
*
* <example module="customControl">
<file name="style.css">
[contenteditable] {
@@ -853,7 +872,13 @@ var VALID_CLASS = 'ng-valid',
// Write data to the model
function read() {
ngModel.$setViewValue(element.html());
var html = element.html();
// When we clear the content editable the browser leaves a <br> behind
// If strip-br attribute is provided then we strip this out
if( attrs.stripBr && html == '<br>' ) {
html = '';
}
ngModel.$setViewValue(html);
}
}
};
@@ -863,6 +888,7 @@ var VALID_CLASS = 'ng-valid',
<form name="myForm">
<div contenteditable
name="myWidget" ng-model="userContent"
strip-br="true"
required>Change me!</div>
<span ng-show="myForm.myWidget.$error.required">Required!</span>
<hr>
@@ -881,6 +907,39 @@ var VALID_CLASS = 'ng-valid',
</file>
* </example>
*
* ## Isolated Scope Pitfall
*
* Note that if you have a directive with an isolated scope, you cannot require `ngModel`
* since the model value will be looked up on the isolated scope rather than the outer scope.
* When the directive updates the model value, calling `ngModel.$setViewValue()` the property
* on the outer scope will not be updated.
*
* Here is an example of this situation. You'll notice that even though both 'input' and 'div'
* seem to be attached to the same model, they are not kept in synch.
*
* <example module="badIsolatedDirective">
<file name="script.js">
angular.module('badIsolatedDirective', []).directive('bad', function() {
return {
require: 'ngModel',
scope: { },
template: '<input ng-model="innerModel">',
link: function(scope, element, attrs, ngModel) {
scope.$watch('innerModel', function(value) {
console.log(value);
ngModel.$setViewValue(value);
});
}
};
});
</file>
<file name="index.html">
<input ng-model="someModel">
<div bad ng-model="someModel"></div>
</file>
* </example>
*
*
*/
var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
function($scope, $exceptionHandler, $attr, $element, $parse) {
@@ -985,8 +1044,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* For example {@link ng.directive:input input} or
* {@link ng.directive:select select} directives call it.
*
* It internally calls all `parsers` and if resulted value is valid, updates the model and
* calls all registered change listeners.
* It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
* Lastly it calls all registered change listeners.
*
* @param {string} value Value from the view.
*/
@@ -1051,17 +1110,26 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
* @element input
*
* @description
* Is directive that tells Angular to do two-way data binding. It works together with `input`,
* `select`, `textarea`. You can easily write your own directives to use `ngModel` as well.
* The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
* property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController},
* which is created and exposed by this directive.
*
* `ngModel` is responsible for:
*
* - binding the view into the model, which other directives such as `input`, `textarea` or `select`
* require,
* - providing validation behavior (i.e. required, number, email, url),
* - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
* - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
* - register the control with parent {@link ng.directive:form form}.
* - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
* require.
* - Providing validation behavior (i.e. required, number, email, url).
* - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
* - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`).
* - Registering the control with its parent {@link ng.directive:form form}.
*
* Note: `ngModel` will try to bind to the property given by evaluating the expression on the
* current scope. If the property doesn't already exist on this scope, it will be created
* implicitly and added to the scope.
*
* For best practices on using `ngModel`, see:
*
* - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes}
*
* For basic examples, how to use `ngModel`, see:
*
@@ -1203,8 +1271,9 @@ var requiredDirective = function() {
</script>
<form name="myForm" ng-controller="Ctrl">
List: <input name="namesInput" ng-model="names" ng-list required>
<span class="error" ng-show="myForm.list.$error.required">
<span class="error" ng-show="myForm.namesInput.$error.required">
Required!</span>
<br>
<tt>names = {{names}}</tt><br/>
<tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
<tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
@@ -1216,12 +1285,14 @@ var requiredDirective = function() {
it('should initialize to model', function() {
expect(binding('names')).toEqual('["igor","misko","vojta"]');
expect(binding('myForm.namesInput.$valid')).toEqual('true');
expect(element('span.error').css('display')).toBe('none');
});
it('should be invalid if empty', function() {
input('names').enter('');
expect(binding('names')).toEqual('[]');
expect(binding('myForm.namesInput.$valid')).toEqual('false');
expect(element('span.error').css('display')).not().toBe('none');
});
</doc:scenario>
</doc:example>
@@ -1259,19 +1330,68 @@ var ngListDirective = function() {
var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
/**
* @ngdoc directive
* @name ng.directive:ngValue
*
* @description
* Binds the given expression to the value of `input[select]` or `input[radio]`, so
* that when the element is selected, the `ngModel` of that element is set to the
* bound value.
*
* `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
* shown below.
*
* @element input
* @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
* of the `input` element
*
* @example
<doc:example>
<doc:source>
<script>
function Ctrl($scope) {
$scope.names = ['pizza', 'unicorns', 'robots'];
$scope.my = { favorite: 'unicorns' };
}
</script>
<form ng-controller="Ctrl">
<h2>Which is your favorite?</h2>
<label ng-repeat="name in names" for="{{name}}">
{{name}}
<input type="radio"
ng-model="my.favorite"
ng-value="name"
id="{{name}}"
name="favorite">
</label>
</span>
<div>You chose {{my.favorite}}</div>
</form>
</doc:source>
<doc:scenario>
it('should initialize to model', function() {
expect(binding('my.favorite')).toEqual('unicorns');
});
it('should bind the values to the inputs', function() {
input('my.favorite').select('pizza');
expect(binding('my.favorite')).toEqual('pizza');
});
</doc:scenario>
</doc:example>
*/
var ngValueDirective = function() {
return {
priority: 100,
compile: function(tpl, tplAttr) {
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
return function(scope, elm, attr) {
return function ngValueConstantLink(scope, elm, attr) {
attr.$set('value', scope.$eval(attr.ngValue));
};
} else {
return function(scope, elm, attr) {
return function ngValueLink(scope, elm, attr) {
scope.$watch(attr.ngValue, function valueWatchAction(value) {
attr.$set('value', value, false);
attr.$set('value', value);
});
};
}
+8 -8
View File
@@ -12,10 +12,9 @@
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
* `{{ expression }}` which is similar but less verbose.
*
* One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when
* it's desirable to put bindings into template that is momentarily displayed by the browser in its
* raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the
* bindings invisible to the user while the page is loading.
* It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading.
*
* An alternative solution to this problem would be using the
* {@link ng.directive:ngCloak ngCloak} directive.
@@ -61,10 +60,11 @@ var ngBindDirective = ngDirective(function(scope, element, attr) {
*
* @description
* The `ngBindTemplate` directive specifies that the element
* text should be replaced with the template in ngBindTemplate.
* Unlike ngBind the ngBindTemplate can contain multiple `{{` `}}`
* expressions. (This is required since some HTML elements
* can not have SPAN elements such as TITLE, or OPTION to name a few.)
* text content should be replaced with the interpolation of the template
* in the `ngBindTemplate` attribute.
* Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
* expressions. This directive is needed since some HTML elements
* (such as TITLE and OPTION) cannot contain SPAN elements.
*
* @element ANY
* @param {string} ngBindTemplate template of form
+5 -3
View File
@@ -62,8 +62,8 @@ function classDirective(name, selector) {
* @name ng.directive:ngClass
*
* @description
* The `ngClass` allows you to set CSS class on HTML element dynamically by databinding an
* expression that represents all classes to be added.
* The `ngClass` allows you to set CSS classes on HTML an element, dynamically, by databinding
* an expression that represents all classes to be added.
*
* The directive won't add duplicate classes if a particular class was already set.
*
@@ -73,7 +73,9 @@ function classDirective(name, selector) {
* @element ANY
* @param {expression} ngClass {@link guide/expression Expression} to eval. The result
* of the evaluation can be a string representing space delimited class
* names, an array, or a map of class names to boolean values.
* names, an array, or a map of class names to boolean values. In the case of a map, the
* names of the properties whose values are truthy will be added as css classes to the
* element.
*
* @example
<example>
+1 -1
View File
@@ -17,7 +17,7 @@
*
* <pre>
* [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
* display: none;
* display: none !important;
* }
* </pre>
*
+9 -10
View File
@@ -5,15 +5,16 @@
* @name ng.directive:ngController
*
* @description
* The `ngController` directive assigns behavior to a scope. This is a key aspect of how angular
* The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
* supports the principles behind the Model-View-Controller design pattern.
*
* MVC components in angular:
*
* * Model — The Model is data in scope properties; scopes are attached to the DOM.
* * View — The template (HTML with data bindings) is rendered into the View.
* * Controller — The `ngController` directive specifies a Controller class; the class has
* methods that typically express the business logic behind the application.
* * Model — The Model is scope properties; scopes are attached to DOM where scope properties
* are accessed through bindings.
* * View — The template (HTML with data bindings) that is rendered into the View.
* * Controller — The `ngController` directive specifies a Controller class; the class contains business
* logic behind the application to decorate the scope with functions and values
*
* Note that an alternative way to define controllers is via the {@link ng.$route $route} service.
*
@@ -25,11 +26,9 @@
*
* @example
* Here is a simple form for editing user contact information. Adding, removing, clearing, and
* greeting are methods declared on the controller (see source tab). These methods can
* easily be called from the angular markup. Notice that the scope becomes the `this` for the
* controller's instance. This allows for easy access to the view data from the controller. Also
* notice that any changes to the data are automatically reflected in the View without the need
* for a manual update.
* greeting are methods declared on the $scope by the controller (see source tab). These methods can
* easily be called from the angular markup. Notice that any changes to the data are automatically
* reflected in the View without the need for a manual update.
<doc:example>
<doc:source>
<script>
+3 -3
View File
@@ -15,12 +15,12 @@
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
* any of these restrictions.
*
* AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
* it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
* be raised.
*
* In order to use this feature put `ngCsp` directive on the root element of the application.
* In order to use this feature put the `ngCsp` directive on the root element of the application.
*
* @example
* This example shows how to apply the `ngCsp` directive to the `html` tag.
+56 -12
View File
@@ -5,8 +5,8 @@
* @name ng.directive:ngClick
*
* @description
* The ngClick allows you to specify custom behavior when
* element is clicked.
* The ngClick directive allows you to specify custom behavior when
* an element is clicked.
*
* @element ANY
* @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
@@ -37,7 +37,7 @@
*/
var ngEventDirectives = {};
forEach(
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave submit'.split(' '),
function(name) {
var directiveName = directiveNormalize('ng-' + name);
ngEventDirectives[directiveName] = ['$parse', function($parse) {
@@ -58,11 +58,11 @@ forEach(
* @name ng.directive:ngDblclick
*
* @description
* The `ngDblclick` directive allows you to specify custom behavior on dblclick event.
* The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
*
* @element ANY
* @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
* dblclick. (Event object is available as `$event`)
* a dblclick. (The Event object is available as `$event`)
*
* @example
* See {@link ng.directive:ngClick ngClick}
@@ -164,6 +164,54 @@ forEach(
*/
/**
* @ngdoc directive
* @name ng.directive:ngKeydown
*
* @description
* Specify custom behavior on keydown event.
*
* @element ANY
* @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
* keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
*
* @example
* See {@link ng.directive:ngClick ngClick}
*/
/**
* @ngdoc directive
* @name ng.directive:ngKeyup
*
* @description
* Specify custom behavior on keyup event.
*
* @element ANY
* @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
* keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
*
* @example
* See {@link ng.directive:ngClick ngClick}
*/
/**
* @ngdoc directive
* @name ng.directive:ngKeypress
*
* @description
* Specify custom behavior on keypress event.
*
* @element ANY
* @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
* keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
*
* @example
* See {@link ng.directive:ngClick ngClick}
*/
/**
* @ngdoc directive
* @name ng.directive:ngSubmit
@@ -172,10 +220,11 @@ forEach(
* Enables binding angular expressions to onsubmit events.
*
* Additionally it prevents the default action (which for form means sending the request to the
* server and reloading the current page).
* server and reloading the current page) **but only if the form does not contain an `action`
* attribute**.
*
* @element form
* @param {expression} ngSubmit {@link guide/expression Expression} to eval.
* @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
*
* @example
<doc:example>
@@ -215,8 +264,3 @@ forEach(
</doc:scenario>
</doc:example>
*/
var ngSubmitDirective = ngDirective(function(scope, element, attrs) {
element.bind('submit', function() {
scope.$apply(attrs.ngSubmit);
});
});
+4 -5
View File
@@ -8,7 +8,7 @@
* @description
* # Overview
* `ngPluralize` is a directive that displays messages according to en-US localization rules.
* These rules are bundled with angular.js and the rules can be overridden
* These rules are bundled with angular.js, but can be overridden
* (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
* by specifying the mappings between
* {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
@@ -21,8 +21,8 @@
*
* While a pural category may match many numbers (for example, in en-US locale, "other" can match
* any number that is not 1), an explicit number rule can only match one number. For example, the
* explicit number rule for "3" matches the number 3. You will see the use of plural categories
* and explicit number rules throughout later parts of this documentation.
* explicit number rule for "3" matches the number 3. There are examples of plural categories
* and explicit number rules throughout the rest of this documentation.
*
* # Configuring ngPluralize
* You configure ngPluralize by providing 2 attributes: `count` and `when`.
@@ -32,8 +32,7 @@
* Angular expression}; these are evaluated on the current scope for its bound value.
*
* The `when` attribute specifies the mappings between plural categories and the actual
* string to be displayed. The value of the attribute should be a JSON object so that Angular
* can interpret it correctly.
* string to be displayed. The value of the attribute should be a JSON object.
*
* The following example shows how to configure ngPluralize:
*
+1 -2
View File
@@ -23,8 +23,7 @@
return {
restrict: 'E',
transclude: true,
scope: 'isolate',
locals: { title:'bind' },
scope: { title:'@' },
template: '<div style="border: 1px solid black;">' +
'<div style="background-color: gray">{{title}}</div>' +
'<div ng-transclude></div>' +
+14 -4
View File
@@ -13,8 +13,8 @@
* Optionally `ngOptions` attribute can be used to dynamically generate a list of `<option>`
* elements for a `<select>` element using an array or an object obtained by evaluating the
* `ngOptions` expression.
*˝˝
* When an item in the select menu is select, the value of array element or object property
*
* When an item in the `<select>` menu is selected, the value of array element or object property
* represented by the selected option will be bound to the model identified by the `ngModel`
* directive of the parent select element.
*
@@ -384,6 +384,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
modelValue = ctrl.$modelValue,
values = valuesFn(scope) || [],
keys = keyName ? sortedKeys(values) : values,
key,
groupLength, length,
groupIndex, index,
locals = {},
@@ -399,8 +400,17 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
// We now build up the list of options we need (we merge later)
for (index = 0; length = keys.length, index < length; index++) {
locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index];
optionGroupName = groupByFn(scope, locals) || '';
key = index;
if (keyName) {
key = keys[index];
if ( key.charAt(0) === '$' ) continue;
locals[keyName] = key;
}
locals[valueName] = values[key];
optionGroupName = groupByFn(scope, locals) || '';
if (!(optionGroup = optionGroups[optionGroupName])) {
optionGroup = optionGroups[optionGroupName] = [];
optionGroupNames.push(optionGroupName);
+15 -1
View File
@@ -9,10 +9,24 @@
* Any uncaught exception in angular expressions is delegated to this service.
* The default implementation simply delegates to `$log.error` which logs it into
* the browser console.
*
*
* In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
* {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
*
* ## Example:
*
* <pre>
* angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
* return function (exception, cause) {
* exception.message += ' (caused by "' + cause + '")';
* throw exception;
* };
* });
* </pre>
*
* This example will override the normal action of `$exceptionHandler`, to make angular
* exceptions fail hard when they happen, instead of just logging to the console.
*
* @param {Error} exception Exception associated with the error.
* @param {string=} cause optional information about the context in which
* the error was thrown.
+10 -3
View File
@@ -62,7 +62,9 @@ function currencyFilter($locale) {
* If the input is not a number an empty string is returned.
*
* @param {number|string} number Number to format.
* @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
* If this is not provided then the fraction size is computed from the current locale's number
* formatting pattern. In the case of the default locale, it will be 3.
* @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
*
* @example
@@ -169,6 +171,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
}
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
} else {
if (fractionSize > 0 && number > -1 && number < 1) {
formatedText = number.toFixed(fractionSize);
}
}
parts.push(isNegative ? pattern.negPre : pattern.posPre);
@@ -292,7 +299,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
* * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
* (e.g. Friday, September 3, 2010)
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010
* * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)
* * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
* * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
* * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
@@ -300,7 +307,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
*
* `format` string can contain literal values. These need to be quoted with single quotes (e.g.
* `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
* (e.g. `"h o''clock"`).
* (e.g. `"h 'o''clock'"`).
*
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
+5 -3
View File
@@ -49,7 +49,7 @@
<table class="friend">
<tr>
<th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
(<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
(<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
<th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
<th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
</tr>
@@ -125,8 +125,10 @@ function orderByFilter($parse){
var t1 = typeof v1;
var t2 = typeof v2;
if (t1 == t2) {
if (t1 == "string") v1 = v1.toLowerCase();
if (t1 == "string") v2 = v2.toLowerCase();
if (t1 == "string") {
v1 = v1.toLowerCase();
v2 = v2.toLowerCase();
}
if (v1 === v2) return 0;
return v1 < v2 ? -1 : 1;
} else {
+59 -8
View File
@@ -185,6 +185,33 @@ function $HttpProvider() {
* will result in the success callback being called. Note that if the response is a redirect,
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
* called for such responses.
*
* # Calling $http from outside AngularJS
* The `$http` service will not actually send the request until the next `$digest()` is executed.
* Normally this is not an issue, since almost all the time your call to `$http` will be from within
* a `$apply()` block.
* If you are calling `$http` from outside Angular, then you should wrap it in a call to `$apply`
* to cause a $digest to occur and also to handle errors in the block correctly.
*
* ```
* $scope.$apply(function() {
* $http(...);
* });
* ```
*
* # Writing Unit Tests that use $http
* When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do not
* trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have been
* made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the code
* that calls the `$http()` method inside a $apply block as explained in the previous section.
*
* ```
* $httpBackend.expectGET(...);
* $scope.$apply(function() {
* $http.get(...);
* });
* $httpBackend.flush();
* ```
*
* # Shortcut methods
*
@@ -224,7 +251,7 @@ function $HttpProvider() {
* To add or overwrite these defaults, simply add or remove a property from these configuration
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
* with the lowercased HTTP method name as the key, e.g.
* `$httpProvider.defaults.headers.get['My-Header']='value'`.
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
*
* Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
* fashion.
@@ -291,6 +318,7 @@ function $HttpProvider() {
* return function(promise) {
* return promise.then(function(response) {
* // do something on success
* return response;
* }, function(response) {
* // do something on error
* if (canRecover(response)) {
@@ -482,17 +510,40 @@ function $HttpProvider() {
var reqTransformFn = config.transformRequest || $config.transformRequest,
respTransformFn = config.transformResponse || $config.transformResponse,
defHeaders = $config.headers,
reqHeaders = extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
defHeaders.common, defHeaders[lowercase(config.method)], config.headers),
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn),
reqHeaders = extend({}, config.headers),
defHeaders = extend(
{'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
$config.headers.common,
$config.headers[lowercase(config.method)]
),
reqData,
defHeaderName, lowercaseDefHeaderName, headerName,
promise;
// using for-in instead of forEach to avoid unecessary iteration after header has been found
defaultHeadersIteration:
for(defHeaderName in defHeaders) {
lowercaseDefHeaderName = lowercase(defHeaderName);
for(headerName in config.headers) {
if (lowercase(headerName) === lowercaseDefHeaderName) {
continue defaultHeadersIteration;
}
}
reqHeaders[defHeaderName] = defHeaders[defHeaderName];
}
// strip content-type if data is undefined
if (isUndefined(config.data)) {
delete reqHeaders['Content-Type'];
for(var header in reqHeaders) {
if (lowercase(header) === 'content-type') {
delete reqHeaders[header];
break;
}
}
}
reqData = transformData(config.data, headersGetter(reqHeaders), reqTransformFn);
// send request
promise = sendReq(config, reqData, reqHeaders);
@@ -682,7 +733,7 @@ function $HttpProvider() {
if (cache) {
cachedResp = cache.get(url);
if (cachedResp) {
if (isDefined(cachedResp)) {
if (cachedResp.then) {
// cached request has already been sent, but there is no response yet
cachedResp.then(removePendingReq, removePendingReq);
@@ -702,7 +753,7 @@ function $HttpProvider() {
}
// if we won't have the response in cache, send the request to the backend
if (!cachedResp) {
if (isUndefined(cachedResp)) {
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
config.withCredentials);
}
+1 -1
View File
@@ -494,7 +494,7 @@ function $LocationProvider(){
* @name ng.$locationProvider#html5Mode
* @methodOf ng.$locationProvider
* @description
* @param {string=} mode Use HTML5 strategy if available.
* @param {boolean=} mode Use HTML5 strategy if available.
* @returns {*} current value if used as getter or itself (chaining) if used as setter
*/
this.html5Mode = function(mode) {
-27
View File
@@ -663,33 +663,6 @@ function setter(obj, path, setValue) {
return setValue;
}
/**
* Return the value accesible from the object by path. Any undefined traversals are ignored
* @param {Object} obj starting object
* @param {string} path path to traverse
* @param {boolean=true} bindFnToScope
* @returns value as accesbile by path
*/
//TODO(misko): this function needs to be removed
function getter(obj, path, bindFnToScope) {
if (!path) return obj;
var keys = path.split('.');
var key;
var lastInstance = obj;
var len = keys.length;
for (var i = 0; i < len; i++) {
key = keys[i];
if (obj) {
obj = (lastInstance = obj)[key];
}
}
if (!bindFnToScope && isFunction(obj)) {
return bind(lastInstance, obj);
}
return obj;
}
var getterFnCache = {};
/**
+10 -10
View File
@@ -85,8 +85,8 @@
* **Methods**
*
* - `then(successCallback, errorCallback)` regardless of when the promise was or will be resolved
* or rejected calls one of the success or error callbacks asynchronously as soon as the result
* is available. The callbacks are called with a single argument the result or rejection reason.
* or rejected, `then` calls one of the success or error callbacks asynchronously as soon as the result
* is available. The callbacks are called with a single argument: the result or rejection reason.
*
* This method *returns a new promise* which is resolved or rejected via the return value of the
* `successCallback` or `errorCallback`.
@@ -94,7 +94,7 @@
*
* # Chaining promises
*
* Because calling `then` api of a promise returns a new derived promise, it is easily possible
* Because calling the `then` method of a promise returns a new derived promise, it is easily possible
* to create a chain of promises:
*
* <pre>
@@ -102,13 +102,13 @@
* return result + 1;
* });
*
* // promiseB will be resolved immediately after promiseA is resolved and its value will be
* // the result of promiseA incremented by 1
* // promiseB will be resolved immediately after promiseA is resolved and its value
* // will be the result of promiseA incremented by 1
* </pre>
*
* It is possible to create chains of any length and since a promise can be resolved with another
* promise (which will defer its resolution further), it is possible to pause/defer resolution of
* the promises at any point in the chain. This makes it possible to implement powerful apis like
* the promises at any point in the chain. This makes it possible to implement powerful APIs like
* $http's response interceptors.
*
*
@@ -215,8 +215,8 @@ function qFactory(nextTick, exceptionHandler) {
try {
result.resolve((callback || defaultCallback)(value));
} catch(e) {
exceptionHandler(e);
result.reject(e);
exceptionHandler(e);
}
};
@@ -224,8 +224,8 @@ function qFactory(nextTick, exceptionHandler) {
try {
result.resolve((errback || defaultErrback)(reason));
} catch(e) {
exceptionHandler(e);
result.reject(e);
exceptionHandler(e);
}
};
@@ -377,8 +377,8 @@ function qFactory(nextTick, exceptionHandler) {
* @param {Array.<Promise>} promises An array of promises.
* @returns {Promise} Returns a single promise that will be resolved with an array of values,
* each value corresponding to the promise at the same index in the `promises` array. If any of
* the promises is resolved with a rejection, this resulting promise will be resolved with the
* same rejection.
* the promises is resolved with a rejection, this resulting promise will be rejected with the
* same rejection value.
*/
function all(promises) {
var deferred = defer(),
+11 -3
View File
@@ -55,8 +55,10 @@
* @description
*
* Every application has a single root {@link ng.$rootScope.Scope scope}.
* All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
* event processing life-cycle. See {@link guide/scope developer guide on scopes}.
* All other scopes are descendant scopes of the root scope. Scopes provide separation
* between the model and the view, via a mechanism for watching the model for changes.
* They also provide an event emission/broadcast and subscription facility. See the
* {@link guide/scope developer guide on scopes}.
*/
function $RootScopeProvider(){
var TTL = 10;
@@ -393,7 +395,7 @@ function $RootScopeProvider(){
watch = watchers[length];
// Most common watches are on primitives, in which case we can short
// circuit it with === operator, only when === fails do we use .equals
if ((value = watch.get(current)) !== (last = watch.last) &&
if (watch && (value = watch.get(current)) !== (last = watch.last) &&
!(watch.eq
? equals(value, last)
: (typeof value == 'number' && typeof last == 'number'
@@ -446,6 +448,9 @@ function $RootScopeProvider(){
*
* @description
* Broadcasted when a scope and its children are being destroyed.
*
* Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
* clean up DOM bindings before an element is removed from the DOM.
*/
/**
@@ -467,6 +472,9 @@ function $RootScopeProvider(){
* Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
* Application code can register a `$destroy` event handler that will give it chance to
* perform any necessary cleanup.
*
* Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
* clean up DOM bindings before an element is removed from the DOM.
*/
$destroy: function() {
// we can't destroy the root scope or a scope that has been already destroyed
+5 -3
View File
@@ -24,8 +24,8 @@ function $RouteProvider(){
* route definition.
*
* `path` can contain named groups starting with a colon (`:name`). All characters up to the
* next slash are matched and stored in `$routeParams` under the given `name` when the route
* matches.
* next slash are matched and stored in `$routeParams` under the given `name` after the route
* is resolved.
*
* @param {Object} route Mapping information to be assigned to `$route.current` on route
* match.
@@ -50,7 +50,9 @@ function $RouteProvider(){
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
* Otherwise if function, then it is {@link api/AUTO.$injector#invoke injected}
* and the return value is treated as the dependency. If the result is a promise, it is resolved
* before its value is injected into the controller.
* before its value is injected into the controller. Be aware that `ngRoute.$routeParams` will
* still refer to the previous route within these resolve functions. Use `$route.current.params`
* to access the new route parameters, instead.
*
* - `redirectTo` {(string|function())=} value to update
* {@link ng.$location $location} path with and trigger route redirection.
+4
View File
@@ -15,6 +15,10 @@
* The service guarantees that the identity of the `$routeParams` object will remain unchanged
* (but its properties will likely change) even when a route change occurs.
*
* Note that the `$routeParams` are only updated *after* a route change completes successfully.
* This means that you cannot rely on `$routeParams` being correct in route resolve functions.
* Instead you can use `$route.current.params` to access the new route's parameters.
*
* @example
* <pre>
* // Given:
+92 -5
View File
@@ -31,6 +31,94 @@ function $TimeoutProvider() {
* will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
* promise will be resolved with is the return value of the `fn` function.
*
* @example
<doc:example module="time">
<doc:source>
<script>
function Ctrl2($scope,$timeout) {
$scope.format = 'M/d/yy h:mm:ss a';
$scope.blood_1 = 100;
$scope.blood_2 = 120;
var stop;
$scope.fight = function() {
stop = $timeout(function() {
if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
$scope.blood_1 = $scope.blood_1 - 3;
$scope.blood_2 = $scope.blood_2 - 4;
$scope.fight();
} else {
$timeout.cancel(stop);
}
}, 100);
};
$scope.stopFight = function() {
$timeout.cancel(stop);
};
$scope.resetFight = function() {
$scope.blood_1 = 100;
$scope.blood_2 = 120;
}
}
angular.module('time', [])
// Register the 'myCurrentTime' directive factory method.
// We inject $timeout and dateFilter service since the factory method is DI.
.directive('myCurrentTime', function($timeout, dateFilter) {
// return the directive link function. (compile function not needed)
return function(scope, element, attrs) {
var format, // date format
timeoutId; // timeoutId, so that we can cancel the time updates
// used to update the UI
function updateTime() {
element.text(dateFilter(new Date(), format));
}
// watch the expression, and update the UI on change.
scope.$watch(attrs.myCurrentTime, function(value) {
format = value;
updateTime();
});
// schedule update in one second
function updateLater() {
// save the timeoutId for canceling
timeoutId = $timeout(function() {
updateTime(); // update DOM
updateLater(); // schedule another update
}, 1000);
}
// listen on DOM destroy (removal) event, and cancel the next UI update
// to prevent updating time ofter the DOM element was removed.
element.bind('$destroy', function() {
$timeout.cancel(timeoutId);
});
updateLater(); // kick off the UI update process.
}
});
</script>
<div>
<div ng-controller="Ctrl2">
Date format: <input ng-model="format"> <hr/>
Current time is: <span my-current-time="format"></span>
<hr/>
Blood 1 : <font color='red'>{{blood_1}}</font>
Blood 2 : <font color='red'>{{blood_2}}</font>
<button type="button" data-ng-click="fight()">Fight</button>
<button type="button" data-ng-click="stopFight()">StopFight</button>
<button type="button" data-ng-click="resetFight()">resetFight</button>
</div>
</div>
</doc:source>
</doc:example>
*/
function timeout(fn, delay, invokeApply) {
var deferred = $q.defer(),
@@ -45,17 +133,15 @@ function $TimeoutProvider() {
deferred.reject(e);
$exceptionHandler(e);
}
finally {
delete deferreds[promise.$$timeoutId];
}
if (!skipApply) $rootScope.$apply();
}, delay);
cleanup = function() {
delete deferreds[promise.$$timeoutId];
};
promise.$$timeoutId = timeoutId;
deferreds[timeoutId] = deferred;
promise.then(cleanup, cleanup);
return promise;
}
@@ -77,6 +163,7 @@ function $TimeoutProvider() {
timeout.cancel = function(promise) {
if (promise && promise.$$timeoutId in deferreds) {
deferreds[promise.$$timeoutId].reject('canceled');
delete deferreds[promise.$$timeoutId];
return $browser.defer.cancel(promise.$$timeoutId);
}
return false;
+4 -2
View File
@@ -10,8 +10,10 @@
* it is a global variable. In angular we always refer to it through the
* `$window` service, so it may be overriden, removed or mocked for testing.
*
* All expressions are evaluated with respect to current scope so they don't
* suffer from window globality.
* Expressions, like the one defined for the `ngClick` directive in the example
* below, are evaluated with respect to the current scope. Therefore, there is
* no risk of inadvertently coding in a dependency on a global value in such an
* expression.
*
* @example
<doc:example>
+11
View File
@@ -18,6 +18,17 @@ angular.module('ngCookies', ['ng']).
* Only a simple Object is exposed and by adding or removing properties to/from
* this object, new cookies are created/deleted at the end of current $eval.
*
* # Installation
* To use $cookies make sure you have included the `angular-cookies.js` that comes in Angular
* package. You can also find this file on Google CDN, bower as well as at
* {@link http://code.angularjs.org/ code.angularjs.org}.
*
* Finally load the module in your application:
*
* angular.module('app', ['ngCookies']);
*
* and you are ready to get started!
*
* @example
<doc:example>
<doc:source>
+54 -54
View File
@@ -2,56 +2,56 @@ angular.module("ngLocale", [], ["$provide", function($provide) {
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
$provide.value("$locale", {
"DATETIME_FORMATS": {
"AMPMS": {
"0": "vm.",
"1": "nm."
},
"DAY": {
"0": "Sondag",
"1": "Maandag",
"2": "Dinsdag",
"3": "Woensdag",
"4": "Donderdag",
"5": "Vrydag",
"6": "Saterdag"
},
"MONTH": {
"0": "Januarie",
"1": "Februarie",
"2": "Maart",
"3": "April",
"4": "Mei",
"5": "Junie",
"6": "Julie",
"7": "Augustus",
"8": "September",
"9": "Oktober",
"10": "November",
"11": "Desember"
},
"SHORTDAY": {
"0": "So",
"1": "Ma",
"2": "Di",
"3": "Wo",
"4": "Do",
"5": "Vr",
"6": "Sa"
},
"SHORTMONTH": {
"0": "Jan",
"1": "Feb",
"2": "Mar",
"3": "Apr",
"4": "Mei",
"5": "Jun",
"6": "Jul",
"7": "Aug",
"8": "Sep",
"9": "Okt",
"10": "Nov",
"11": "Des"
},
"AMPMS": [
"vm.",
"nm."
],
"DAY": [
"Sondag",
"Maandag",
"Dinsdag",
"Woensdag",
"Donderdag",
"Vrydag",
"Saterdag"
],
"MONTH": [
"Januarie",
"Februarie",
"Maart",
"April",
"Mei",
"Junie",
"Julie",
"Augustus",
"September",
"Oktober",
"November",
"Desember"
],
"SHORTDAY": [
"So",
"Ma",
"Di",
"Wo",
"Do",
"Vr",
"Sa"
],
"SHORTMONTH": [
"Jan",
"Feb",
"Mar",
"Apr",
"Mei",
"Jun",
"Jul",
"Aug",
"Sep",
"Okt",
"Nov",
"Des"
],
"fullDate": "EEEE d MMMM y",
"longDate": "d MMMM y",
"medium": "d MMM y HH:mm:ss",
@@ -65,8 +65,8 @@ $provide.value("$locale", {
"CURRENCY_SYM": "R",
"DECIMAL_SEP": ",",
"GROUP_SEP": "\u00a0",
"PATTERNS": {
"0": {
"PATTERNS": [
{
"gSize": 3,
"lgSize": 3,
"macFrac": 0,
@@ -78,7 +78,7 @@ $provide.value("$locale", {
"posPre": "",
"posSuf": ""
},
"1": {
{
"gSize": 3,
"lgSize": 3,
"macFrac": 0,
@@ -90,7 +90,7 @@ $provide.value("$locale", {
"posPre": "\u00a4",
"posSuf": ""
}
}
]
},
"id": "af-na",
"pluralCat": function (n) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}

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